├── .trivyignore ├── CODEOWNERS ├── .shellcheckrc ├── .markdownlint.yaml ├── .gitignore ├── .dockerignore ├── samples └── charts │ ├── empty-changelog │ ├── CHANGELOG.md │ └── Chart.yaml │ ├── sample │ ├── CHANGELOG.md │ ├── templates │ │ ├── serviceaccount.yaml │ │ ├── service.yaml │ │ ├── hpa.yaml │ │ ├── ingress.yaml │ │ ├── tests │ │ │ └── test-connection.yaml │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ └── deployment.yaml │ ├── .helmignore │ ├── doc.yaml │ ├── Chart.yaml │ ├── values.yaml │ └── README.md │ └── library │ └── Chart.yaml ├── .kics.yaml ├── requirements.in ├── .gitattributes ├── .lychee.toml ├── .yamllint ├── .checkov.yml ├── .editorconfig ├── opt └── CHART-CHANGELOG.md.gotmpl ├── package.json ├── scripts ├── generate-schemas.sh ├── generate-docs.sh ├── generate-chart-changelog.sh └── chart-powerlint.sh ├── SECURITY.md ├── .pre-commit-config.yaml ├── .github └── workflows │ ├── daily-trivy-scan.yaml │ ├── check-links.yaml │ ├── ci.yaml │ └── scorecards.yml ├── .mega-linter.yml ├── .renovaterc.json ├── .releaserc.json ├── README.md ├── LICENSE ├── Dockerfile └── requirements.txt /.trivyignore: -------------------------------------------------------------------------------- 1 | DS002 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @chgl 2 | -------------------------------------------------------------------------------- /.shellcheckrc: -------------------------------------------------------------------------------- 1 | disable=SC2086 2 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | MD013: false 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | megalinter-reports 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !scripts 3 | !opt 4 | !package*.json 5 | !requirements.txt 6 | -------------------------------------------------------------------------------- /samples/charts/empty-changelog/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # sample Changelog 2 | 3 | ## 0.1.0 4 | -------------------------------------------------------------------------------- /.kics.yaml: -------------------------------------------------------------------------------- 1 | verbose: true 2 | log-file: true 3 | exclude-paths: 4 | - "samples/charts/" 5 | -------------------------------------------------------------------------------- /requirements.in: -------------------------------------------------------------------------------- 1 | yamale==6.0.0 2 | yamllint==1.37.1 3 | pre-commit==4.3.0 4 | checkov==3.2.472 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.sh text eol=lf 3 | *.shellcheckrc text eol=lf 4 | Dockerfile text eol=lf 5 | -------------------------------------------------------------------------------- /.lychee.toml: -------------------------------------------------------------------------------- 1 | exclude = [ '.*\.nip.io', '.*example:8080.*', '^https://github.com/.*/compare/' ] 2 | exclude_all_private = true 3 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | extends: default 2 | rules: 3 | line-length: disable 4 | document-start: disable 5 | ignore: | 6 | samples/charts/**/templates 7 | -------------------------------------------------------------------------------- /samples/charts/sample/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # sample Changelog 2 | 3 | ## 0.1.0 4 | 5 | ### Added 6 | - added something 7 | 8 | ### Changed 9 | - changed something else 10 | -------------------------------------------------------------------------------- /.checkov.yml: -------------------------------------------------------------------------------- 1 | skip-check: 2 | - CKV_DOCKER_3 3 | - CKV_DOCKER_2 4 | - CKV_K8S_11 5 | - CKV_K8S_38 6 | - CKV_K8S_13 7 | - CKV_K8S_15 8 | - CKV_K8S_21 9 | - CKV2_K8S_6 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # All files 4 | [*] 5 | indent_style = space[*] 6 | insert_final_newline = true 7 | charset = utf-8 8 | 9 | [*.sh] 10 | end_of_line = lf 11 | 12 | [*.{json}] 13 | indent_size = 2 14 | 15 | # YAML files 16 | [*.{yml, yaml}] 17 | indent_size = 2 18 | -------------------------------------------------------------------------------- /opt/CHART-CHANGELOG.md.gotmpl: -------------------------------------------------------------------------------- 1 | {{ $chart := (ds "chart") -}} 2 | {{ $changes := (ds "changes") -}} 3 | # {{ $chart.name }} Changelog 4 | 5 | ## {{ $chart.version }} 6 | 7 | {{- range $kind := $changes }} 8 | 9 | ### {{ $kind.key | strings.Title }} 10 | 11 | {{- range $change := $kind.value }} 12 | - {{ $change.description }} 13 | {{- end }} 14 | 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "sample.serviceAccountName" . }} 6 | labels: 7 | {{- include "sample.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kube-powertools", 3 | "version": "0.0.0", 4 | "description": "Kube Powertools", 5 | "main": "index.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "github.com/chgl", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "markdownlint-cli": "0.47.0", 14 | "prettier": "3.7.4" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/generate-schemas.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euox pipefail 3 | 4 | echo "Running helm-schema..." 5 | 6 | CHARTS_DIR=${CHARTS_DIR:-"charts"} 7 | 8 | for chart in "${CHARTS_DIR}"/*; do 9 | echo "Generating schema for $chart:" 10 | 11 | if test ! -f "${chart}/Chart.yaml"; then 12 | echo "No 'Chart.yaml' found in directory ${chart}. Skipping." 13 | continue 14 | fi 15 | 16 | helm schema 17 | 18 | done 19 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "sample.fullname" . }} 5 | labels: 6 | {{- include "sample.labels" . | nindent 4 }} 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.port }} 11 | targetPort: http 12 | protocol: TCP 13 | name: http 14 | selector: 15 | {{- include "sample.selectorLabels" . | nindent 4 }} 16 | -------------------------------------------------------------------------------- /samples/charts/sample/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only the most recent major version is regularly updated and receives security fixes. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Please use the project's [private vulnerability reporting feature](https://github.com/chgl/kube-powertools/security/advisories) 10 | to report any vulnerabilities. For more information, see 11 | -------------------------------------------------------------------------------- /samples/charts/sample/doc.yaml: -------------------------------------------------------------------------------- 1 | project: 2 | name: sample 3 | shortName: sample 4 | url: https://github.com/OHDSI 5 | description: sample chart for deploying to Kubernetes. 6 | app: the sample for Azure. 7 | repository: 8 | url: https://chgl.github.io/charts 9 | name: chgl 10 | chart: 11 | name: sample 12 | values: "-- generate from values file --" 13 | valuesExample: "-- generate from values file --" 14 | prerequisites: 15 | - "Kubernetes v1.16+" 16 | - "Helm v3" 17 | release: 18 | name: sample 19 | namespace: sample 20 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v4.0.1 6 | hooks: 7 | - id: trailing-whitespace 8 | - id: end-of-file-fixer 9 | - id: check-added-large-files 10 | - id: fix-byte-order-marker 11 | - id: check-case-conflict 12 | - id: check-executables-have-shebangs 13 | - id: check-yaml 14 | args: [--allow-multiple-documents] 15 | exclude: ^samples/charts/.*/templates/ 16 | -------------------------------------------------------------------------------- /.github/workflows/daily-trivy-scan.yaml: -------------------------------------------------------------------------------- 1 | name: scan 2 | on: 3 | schedule: 4 | - cron: "0 8 * * *" 5 | 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | scan: 11 | name: Scan 12 | runs-on: ubuntu-24.04 13 | permissions: 14 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 15 | steps: 16 | - name: Run Trivy vulnerability scanner 17 | uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1 18 | with: 19 | image-ref: "ghcr.io/chgl/kube-powertools:latest" 20 | format: "template" 21 | template: "@/contrib/sarif.tpl" 22 | output: "trivy-results.sarif" 23 | severity: "CRITICAL,HIGH" 24 | 25 | - name: Upload Trivy scan results to GitHub Security tab 26 | uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 27 | with: 28 | sarif_file: "trivy-results.sarif" 29 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | apiVersion: autoscaling/v2beta1 3 | kind: HorizontalPodAutoscaler 4 | metadata: 5 | name: {{ include "sample.fullname" . }} 6 | labels: 7 | {{- include "sample.labels" . | nindent 4 }} 8 | spec: 9 | scaleTargetRef: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | name: {{ include "sample.fullname" . }} 13 | minReplicas: {{ .Values.autoscaling.minReplicas }} 14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 15 | metrics: 16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 17 | - type: Resource 18 | resource: 19 | name: cpu 20 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | {{- end }} 22 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 23 | - type: Resource 24 | resource: 25 | name: memory 26 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 27 | {{- end }} 28 | {{- end }} 29 | -------------------------------------------------------------------------------- /scripts/generate-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euox pipefail 3 | 4 | echo "Running chart-doc-gen..." 5 | 6 | CHARTS_DIR=${CHARTS_DIR:-"charts"} 7 | 8 | for chart in "${CHARTS_DIR}"/*; do 9 | echo "Generating docs for $chart:" 10 | 11 | if test ! -f "${chart}/Chart.yaml"; then 12 | echo "No 'Chart.yaml' found in directory ${chart}. Skipping." 13 | continue 14 | fi 15 | 16 | # if there's a 'doc.yaml' present in the chart dir, use chart-doc-gen, 17 | # otherwise use helm-docs 18 | if test -f "${chart}/doc.yaml"; then 19 | echo "Found doc.yaml file in ${chart}, using chart-doc-gen" 20 | if test -f "${chart}/README.tpl"; then 21 | echo "${chart}/README.tpl exists. Using it as a template input." 22 | chart-doc-gen --doc="${chart}/doc.yaml" --values="${chart}/values.yaml" --template="${chart}/README.tpl" >"${chart}/README.md" 23 | else 24 | chart-doc-gen --doc="${chart}/doc.yaml" --values="${chart}/values.yaml" >"${chart}/README.md" 25 | fi 26 | else 27 | echo "No doc.yaml found in ${chart}, using helm-docs" 28 | helm-docs --chart-search-root=${chart} 29 | fi 30 | done 31 | 32 | echo "Running prettier..." 33 | 34 | prettier --write "${CHARTS_DIR}"/**/README.md 35 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $fullName := include "sample.fullname" . -}} 3 | {{- $svcPort := .Values.service.port -}} 4 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} 5 | apiVersion: networking.k8s.io/v1beta1 6 | {{- else -}} 7 | apiVersion: extensions/v1beta1 8 | {{- end }} 9 | kind: Ingress 10 | metadata: 11 | name: {{ $fullName }} 12 | labels: 13 | {{- include "sample.labels" . | nindent 4 }} 14 | {{- with .Values.ingress.annotations }} 15 | annotations: 16 | {{- toYaml . | nindent 4 }} 17 | {{- end }} 18 | spec: 19 | {{- if .Values.ingress.tls }} 20 | tls: 21 | {{- range .Values.ingress.tls }} 22 | - hosts: 23 | {{- range .hosts }} 24 | - {{ . | quote }} 25 | {{- end }} 26 | secretName: {{ .secretName }} 27 | {{- end }} 28 | {{- end }} 29 | rules: 30 | {{- range .Values.ingress.hosts }} 31 | - host: {{ .host | quote }} 32 | http: 33 | paths: 34 | {{- range .paths }} 35 | - path: {{ .path }} 36 | backend: 37 | serviceName: {{ $fullName }} 38 | servicePort: {{ $svcPort }} 39 | {{- end }} 40 | {{- end }} 41 | {{- end }} 42 | -------------------------------------------------------------------------------- /samples/charts/empty-changelog/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: sample 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.19" 25 | 26 | annotations: {} 27 | -------------------------------------------------------------------------------- /scripts/generate-chart-changelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euox pipefail 3 | 4 | CHARTS_DIR=${CHARTS_DIR:-"charts"} 5 | CHANGELOG_TEMPLATE_FILE_PATH=${CHANGELOG_TEMPLATE_FILE_PATH:-"/opt/kube-powertools/CHART-CHANGELOG.md.gotmpl"} 6 | 7 | for dir in "$CHARTS_DIR"/*; do 8 | if test ! -f "${dir}/Chart.yaml"; then 9 | echo "No 'Chart.yaml' found in directory ${dir}. Skipping." 10 | continue 11 | fi 12 | 13 | CHART_NAME=$(basename "$dir") 14 | 15 | echo "Creating CHANGELOG.md for ${CHART_NAME}" 16 | 17 | # shellcheck disable=SC2002 # using cat makes the code look neater 18 | cat "$dir/Chart.yaml" | 19 | yq e '.annotations["artifacthub.io/changes"] // []' - | # extract the changes annotation, which is a YAML array 20 | yq -o json e '.' - | # convert the YAML array to a JSON array 21 | jq 'group_by(.kind) | to_entries | map({key: .value[0].kind, value: .value})' - | # group the JSON array by their 'kind' - ie. the type of change 22 | gomplate -d chart="$dir/Chart.yaml" -d changes=stdin:///in.json -f $CHANGELOG_TEMPLATE_FILE_PATH >"$dir/CHANGELOG.md" # use the JSON above as input to render the changelog 23 | done 24 | -------------------------------------------------------------------------------- /.mega-linter.yml: -------------------------------------------------------------------------------- 1 | # Configuration file for MegaLinter 2 | # See all available variables at https://oxsecurity.github.io/megalinter/configuration/ and in linters documentation 3 | 4 | APPLY_FIXES: none # all, none, or list of linter keys 5 | # ENABLE: # If you use ENABLE variable, all other languages/formats/tooling-formats will be disabled by default 6 | # ENABLE_LINTERS: # If you use ENABLE_LINTERS variable, all other linters will be disabled by default 7 | DISABLE: 8 | - COPYPASTE # Uncomment to disable checks of excessive copy-pastes 9 | - SPELL # Uncomment to disable checks of spelling mistakes 10 | - YAML 11 | DISABLE_LINTERS: 12 | - MARKDOWN_MARKDOWN_LINK_CHECK 13 | - MARKDOWN_MARKDOWN_TABLE_FORMATTER 14 | - REPOSITORY_SEMGREP 15 | # False positive: error - python package "--hash" is available for public registration. /github/workspace/requirements.txt 16 | # Also seems to be an inactive project. 17 | - REPOSITORY_DUSTILOCK 18 | SHOW_ELAPSED_TIME: true 19 | FILEIO_REPORTER: false 20 | # DISABLE_ERRORS: true # Uncomment if you want MegaLinter to detect errors but not block CI to pass 21 | REPOSITORY_TRIVY_ARGUMENTS: 22 | - "--severity=MEDIUM,HIGH,CRITICAL" 23 | 24 | BASH_SHFMT_ARGUMENTS: 25 | - "--indent=2" 26 | 27 | REPOSITORY_KICS_CONFIG_FILE: ".kics.yaml" 28 | 29 | DISABLE_ERRORS_LINTERS: 30 | - REPOSITORY_TRIVY 31 | - REPOSITORY_GRYPE 32 | -------------------------------------------------------------------------------- /.github/workflows/check-links.yaml: -------------------------------------------------------------------------------- 1 | name: check links 2 | 3 | on: 4 | repository_dispatch: 5 | workflow_dispatch: 6 | schedule: 7 | - cron: "00 18 * * *" 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | check-links: 14 | name: Check Links 15 | runs-on: ubuntu-24.04 16 | permissions: 17 | issues: write 18 | steps: 19 | - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 20 | with: 21 | persist-credentials: false 22 | 23 | - name: Link Checker 24 | id: lychee 25 | uses: lycheeverse/lychee-action@a8c4c7cb88f0c7386610c35eb25108e448569cb0 # v2.7.0 26 | with: 27 | args: "--config=.lychee.toml ." 28 | env: 29 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 30 | 31 | - name: Look for an existing issue 32 | id: last-issue 33 | uses: micalevisk/last-issue-action@0d40124cc99ac8601c2516007f0c98ef3d27537b # v2.3.0 34 | with: 35 | state: open 36 | labels: link-check 37 | 38 | - name: Create Issue From File 39 | if: ${{ env.lychee_exit_code != 0 }} 40 | uses: peter-evans/create-issue-from-file@fca9117c27cdc29c6c4db3b86c48e4115a786710 # v6.0.0 41 | with: 42 | title: Link Checker Report 43 | content-filepath: ./lychee/out.md 44 | issue-number: ${{ steps.last-issue.outputs.issue_number }} 45 | labels: report, automated issue, link-check 46 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "sample.fullname" . }}-test-connection" 5 | labels: 6 | app.kubernetes.io/name: "{{ include "sample.fullname" . }}-test-connection" 7 | annotations: 8 | "helm.sh/hook": test 9 | spec: 10 | restartPolicy: Never 11 | automountServiceAccountToken: false 12 | securityContext: 13 | runAsNonRoot: true 14 | seccompProfile: 15 | type: RuntimeDefault 16 | # set to satisfy polaris 17 | priorityClassName: normal 18 | containers: 19 | - name: wget 20 | image: docker.io/library/busybox:1.36.0@sha256:9e2bbca079387d7965c3a9cee6d0c53f4f4e63ff7637877a83c4c05f2a666112 21 | imagePullPolicy: Always 22 | command: ['wget', '-O', '-'] 23 | args: ['{{ include "sample.fullname" . }}:{{ .Values.service.port }}'] 24 | securityContext: 25 | allowPrivilegeEscalation: false 26 | capabilities: 27 | drop: 28 | - ALL 29 | readOnlyRootFilesystem: true 30 | runAsNonRoot: true 31 | runAsUser: 65534 32 | runAsGroup: 65534 33 | seccompProfile: 34 | type: RuntimeDefault 35 | resources: 36 | limits: 37 | cpu: 100m 38 | memory: 128Mi 39 | requests: 40 | cpu: 100m 41 | memory: 128Mi 42 | livenessProbe: 43 | exec: 44 | command: ["true"] 45 | readinessProbe: 46 | exec: 47 | command: ["true"] 48 | -------------------------------------------------------------------------------- /samples/charts/library/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: sample 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: library 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.19" 25 | 26 | annotations: 27 | artifacthub.io/changes: | 28 | # When using the list of objects option the valid supported kinds are 29 | # added, changed, deprecated, removed, fixed and security. 30 | - kind: added 31 | description: added something 32 | - kind: changed 33 | description: changed something else 34 | -------------------------------------------------------------------------------- /samples/charts/sample/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: sample 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.0 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "1.19" 25 | 26 | annotations: 27 | artifacthub.io/changes: | 28 | # When using the list of objects option the valid supported kinds are 29 | # added, changed, deprecated, removed, fixed and security. 30 | - kind: added 31 | description: added something 32 | - kind: changed 33 | description: changed something else 34 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.enabled }} 3 | {{- range $host := .Values.ingress.hosts }} 4 | {{- range .paths }} 5 | http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} 6 | {{- end }} 7 | {{- end }} 8 | {{- else if contains "NodePort" .Values.service.type }} 9 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "sample.fullname" . }}) 10 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 11 | echo http://$NODE_IP:$NODE_PORT 12 | {{- else if contains "LoadBalancer" .Values.service.type }} 13 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 14 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "sample.fullname" . }}' 15 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "sample.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 16 | echo http://$SERVICE_IP:{{ .Values.service.port }} 17 | {{- else if contains "ClusterIP" .Values.service.type }} 18 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "sample.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 19 | export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") 20 | echo "Visit http://127.0.0.1:8080 to use your application" 21 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT 22 | {{- end }} 23 | -------------------------------------------------------------------------------- /.renovaterc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:best-practices", 5 | "group:allNonMajor", 6 | "schedule:weekly", 7 | ":automergeMinor", 8 | ":automergeDigest" 9 | ], 10 | "customManagers": [ 11 | { 12 | "customType": "regex", 13 | "managerFilePatterns": ["/^Dockerfile$/"], 14 | "matchStrings": [ 15 | "datasource=(?.*?) depName=(?.*?)( extractVersion=(?.*?))?( versioning=(?.*?))?\\sARG .*?_VERSION=(?.*)\\s" 16 | ], 17 | "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver{{/if}}", 18 | "extractVersionTemplate": "{{#if extractVersion}}{{{extractVersion}}}{{else}}^v(?.*)${{/if}}" 19 | } 20 | ], 21 | "pip-compile": { 22 | "managerFilePatterns": ["/(^|/)requirements\\.txt$/"] 23 | }, 24 | "pip_requirements": { 25 | "enabled": false 26 | }, 27 | "pip_setup": { 28 | "enabled": false 29 | }, 30 | "setup-cfg": { 31 | "enabled": false 32 | }, 33 | "pep621": { 34 | "enabled": false 35 | }, 36 | "packageRules": [ 37 | { 38 | "matchPackageNames": ["kubernetes-sigs/kustomize"], 39 | "extractVersion": "^kustomize/v(?.*)$" 40 | }, 41 | { 42 | "matchPackageNames": [ 43 | "stackrox/kube-linter", 44 | "FairwindsOps/polaris", 45 | "doitintl/kube-no-trouble", 46 | "bridgecrewio/checkov" 47 | ], 48 | "extractVersion": "^(?.*)$" 49 | }, 50 | { 51 | "matchManagers": ["github-actions"], 52 | "extends": ["schedule:monthly"], 53 | "groupName": "github-actions" 54 | }, 55 | { 56 | "matchManagers": ["github-actions"], 57 | "matchPackageNames": ["slsa-framework/slsa-github-generator"], 58 | "pinDigests": false 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "sample.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "sample.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "sample.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "sample.labels" -}} 37 | helm.sh/chart: {{ include "sample.chart" . }} 38 | {{ include "sample.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "sample.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "sample.fullname" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "sample.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "sample.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /samples/charts/sample/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for sample. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 2 6 | 7 | image: 8 | repository: docker.io/nginxinc/nginx-unprivileged 9 | pullPolicy: IfNotPresent 10 | # Overrides the image tag whose default is the chart appVersion. 11 | tag: "1.29.3@sha256:9f65d92815e29f3cdf5a3c26050b0bb04d5abe553c91b2bcf49d1fc68843d4a9" 12 | 13 | imagePullSecrets: [] 14 | nameOverride: "" 15 | fullnameOverride: "" 16 | 17 | serviceAccount: 18 | # Specifies whether a service account should be created 19 | create: true 20 | # Annotations to add to the service account 21 | annotations: {} 22 | # The name of the service account to use. 23 | # If not set and create is true, a name is generated using the fullname template 24 | name: "" 25 | 26 | podAnnotations: {} 27 | 28 | podSecurityContext: 29 | runAsNonRoot: true 30 | seccompProfile: 31 | type: RuntimeDefault 32 | 33 | securityContext: 34 | capabilities: 35 | drop: 36 | - ALL 37 | readOnlyRootFilesystem: true 38 | runAsNonRoot: true 39 | runAsUser: 65534 40 | runAsGroup: 65534 41 | allowPrivilegeEscalation: false 42 | seccompProfile: 43 | type: RuntimeDefault 44 | 45 | service: 46 | type: ClusterIP 47 | port: 80 48 | 49 | ingress: 50 | enabled: false 51 | annotations: 52 | {} 53 | # kubernetes.io/ingress.class: nginx 54 | # kubernetes.io/tls-acme: "true" 55 | hosts: 56 | - host: chart-example.local 57 | paths: 58 | - path: / 59 | backend: 60 | serviceName: chart-example.local 61 | servicePort: 80 62 | tls: [] 63 | # - secretName: chart-example-tls 64 | # hosts: 65 | # - chart-example.local 66 | 67 | resources: 68 | limits: 69 | cpu: 100m 70 | memory: 128Mi 71 | requests: 72 | cpu: 100m 73 | memory: 128Mi 74 | 75 | autoscaling: 76 | enabled: false 77 | minReplicas: 1 78 | maxReplicas: 100 79 | targetCPUUtilizationPercentage: 80 80 | # targetMemoryUtilizationPercentage: 80 81 | 82 | nodeSelector: {} 83 | 84 | tolerations: [] 85 | 86 | affinity: {} 87 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | [ 4 | "@semantic-release/commit-analyzer", 5 | { 6 | "preset": "conventionalcommits", 7 | "releaseRules": [ 8 | { 9 | "type": "chore", 10 | "scope": "deps", 11 | "release": "patch" 12 | }, 13 | { 14 | "type": "build", 15 | "release": "patch" 16 | } 17 | ] 18 | } 19 | ], 20 | [ 21 | "@semantic-release/release-notes-generator", 22 | { 23 | "preset": "conventionalcommits", 24 | "presetConfig": { 25 | "types": [ 26 | { "type": "feat", "section": "Features" }, 27 | { "type": "fix", "section": "Bug Fixes" }, 28 | { "type": "perf", "section": "Performance Improvements" }, 29 | { "type": "docs", "section": "Documentation", "hidden": false }, 30 | { 31 | "type": "chore", 32 | "section": "Miscellaneous Chores", 33 | "hidden": false 34 | }, 35 | { "type": "build", "section": "Build", "hidden": false }, 36 | { "type": "ci", "section": "CI/CD", "hidden": false } 37 | ] 38 | } 39 | } 40 | ], 41 | "@semantic-release/github", 42 | [ 43 | "semantic-release-replace-plugin", 44 | { 45 | "replacements": [ 46 | { 47 | "files": ["README.md"], 48 | "from": "ghcr.io/chgl/kube-powertools:v.*", 49 | "to": "ghcr.io/chgl/kube-powertools:v${nextRelease.version}", 50 | "results": [ 51 | { 52 | "file": "README.md", 53 | "hasChanged": true 54 | } 55 | ] 56 | }, 57 | { 58 | "files": ["README.md"], 59 | "from": "docker.io/chgl/kube-powertools:v.*", 60 | "to": "docker.io/chgl/kube-powertools:v${nextRelease.version}", 61 | "results": [ 62 | { 63 | "file": "README.md", 64 | "hasChanged": true 65 | } 66 | ] 67 | } 68 | ] 69 | } 70 | ], 71 | [ 72 | "@semantic-release/git", 73 | { 74 | "assets": ["README.md"] 75 | } 76 | ] 77 | ] 78 | } 79 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | release: 7 | types: [created] 8 | pull_request: 9 | branches: [master] 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | build: 16 | uses: chgl/.github/.github/workflows/standard-build.yaml@d22f98986e17750e19b8fe5287b16f9f34aa6d2e # v1.11.6 17 | permissions: 18 | contents: write 19 | id-token: write 20 | packages: write 21 | pull-requests: write 22 | actions: read 23 | security-events: write 24 | with: 25 | enable-build-test-layer: false 26 | enable-upload-test-image: false 27 | secrets: 28 | github-token: ${{ secrets.GITHUB_TOKEN }} 29 | 30 | lint: 31 | uses: chgl/.github/.github/workflows/standard-lint.yaml@d22f98986e17750e19b8fe5287b16f9f34aa6d2e # v1.11.6 32 | permissions: 33 | contents: read 34 | pull-requests: write 35 | issues: write 36 | security-events: write 37 | actions: read 38 | with: 39 | enable-codeql: false 40 | enable-validate-gradle-wrapper: false 41 | enable-verify-base-image-signature: false 42 | secrets: 43 | github-token: ${{ secrets.GITHUB_TOKEN }} 44 | 45 | release: 46 | uses: chgl/.github/.github/workflows/standard-release.yaml@d22f98986e17750e19b8fe5287b16f9f34aa6d2e # v1.11.6 47 | needs: 48 | - build 49 | permissions: 50 | contents: write 51 | pull-requests: write 52 | issues: write 53 | with: 54 | use-app-token: true 55 | secrets: 56 | app-token-app-id: ${{ secrets.RELEASER_APP_ID }} 57 | app-token-private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }} 58 | 59 | copy-image-to-dockerhub: 60 | name: copy ghcr.io image to DockerHub 61 | if: ${{ github.event_name != 'pull_request' }} 62 | runs-on: ubuntu-24.04 63 | needs: 64 | - build 65 | steps: 66 | - uses: imjasonh/setup-crane@31b88efe9de28ae0ffa220711af4b60be9435f6e # v0.4 67 | - name: Login to DockerHub 68 | env: 69 | DOCKERHUB_TOKEN: "${{ secrets.DOCKERHUB_TOKEN }}" 70 | run: | 71 | echo "${DOCKERHUB_TOKEN}" | crane auth login docker.io --username chgl --password-stdin 72 | - name: Copy all tags 73 | env: 74 | TAGS: ${{ needs.build.outputs.image-tags }} 75 | run: | 76 | echo "${TAGS}" | while read -r tag; do crane copy "$tag" "${tag/ghcr.io/docker.io}"; done 77 | -------------------------------------------------------------------------------- /samples/charts/sample/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "sample.fullname" . }} 5 | labels: 6 | {{- include "sample.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "sample.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | labels: 21 | {{- include "sample.selectorLabels" . | nindent 8 }} 22 | spec: 23 | {{- with .Values.imagePullSecrets }} 24 | imagePullSecrets: 25 | {{- toYaml . | nindent 8 }} 26 | {{- end }} 27 | serviceAccountName: {{ include "sample.serviceAccountName" . }} 28 | # set to satisfy polaris 29 | priorityClassName: normal 30 | securityContext: 31 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 32 | topologySpreadConstraints: 33 | - maxSkew: 1 34 | topologyKey: topology.kubernetes.io/zone 35 | whenUnsatisfiable: ScheduleAnyway 36 | labelSelector: 37 | matchLabels: 38 | {{- include "sample.selectorLabels" . | nindent 14 }} 39 | containers: 40 | - name: {{ .Chart.Name }} 41 | securityContext: 42 | {{- toYaml .Values.securityContext | nindent 12 }} 43 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 44 | imagePullPolicy: {{ .Values.image.pullPolicy }} 45 | ports: 46 | - name: http 47 | containerPort: 8080 48 | protocol: TCP 49 | livenessProbe: 50 | httpGet: 51 | path: / 52 | port: http 53 | readinessProbe: 54 | httpGet: 55 | path: / 56 | port: http 57 | resources: 58 | {{- toYaml .Values.resources | nindent 12 }} 59 | {{- with .Values.nodeSelector }} 60 | nodeSelector: 61 | {{- toYaml . | nindent 8 }} 62 | {{- end }} 63 | {{- with .Values.affinity }} 64 | affinity: 65 | {{- toYaml . | nindent 8 }} 66 | {{- end }} 67 | {{- with .Values.tolerations }} 68 | tolerations: 69 | {{- toYaml . | nindent 8 }} 70 | {{- end }} 71 | -------------------------------------------------------------------------------- /.github/workflows/scorecards.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecards supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: "30 4 * * 4" 14 | push: 15 | branches: ["master"] 16 | workflow_dispatch: {} 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | analysis: 23 | name: Scorecards analysis 24 | runs-on: ubuntu-latest 25 | permissions: 26 | # Needed to upload the results to code-scanning dashboard. 27 | security-events: write 28 | # Needed to publish results and get a badge (see publish_results below). 29 | id-token: write 30 | # Uncomment the permissions below if installing in a private repository. 31 | # contents: read 32 | # actions: read 33 | 34 | steps: 35 | - name: "Checkout code" 36 | uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 37 | with: 38 | persist-credentials: false 39 | 40 | - name: "Run analysis" 41 | uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 42 | with: 43 | results_file: results.sarif 44 | results_format: sarif 45 | 46 | # Public repositories: 47 | # - Publish results to OpenSSF REST API for easy access by consumers 48 | # - Allows the repository to include the Scorecard badge. 49 | # - See https://github.com/ossf/scorecard-action#publishing-results. 50 | # For private repositories: 51 | # - `publish_results` will always be set to `false`, regardless 52 | # of the value entered here. 53 | publish_results: true 54 | 55 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 56 | # format to the repository Actions tab. 57 | - name: "Upload artifact" 58 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 59 | with: 60 | name: SARIF file 61 | path: results.sarif 62 | retention-days: 5 63 | 64 | # Upload the results to GitHub's code scanning dashboard. 65 | - name: "Upload to code-scanning" 66 | uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 67 | with: 68 | sarif_file: results.sarif 69 | -------------------------------------------------------------------------------- /scripts/chart-powerlint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euox pipefail 3 | 4 | CHARTS_DIR=${CHARTS_DIR:-"charts"} 5 | SHOULD_UPDATE_DEPENDENCIES=${SHOULD_UPDATE_DEPENDENCIES:-""} 6 | 7 | KUBERNETES_VERSIONS=${KUBERNETES_VERSIONS:-"1.32.0 1.33.0 1.34.0"} 8 | 9 | POLARIS_SCORE_THRESHOLD=${POLARIS_SCORE_THRESHOLD:-90} 10 | SKIP_KUBE_SCORE=${SKIP_KUBE_SCORE:-"1"} 11 | KUBE_SCORE_ARGS=${KUBE_SCORE_ARGS:-""} 12 | SKIP_KUBE_LINTER=${SKIP_KUBE_LINTER:-"1"} 13 | SKIP_KUBE_SCAPE=${SKIP_KUBE_SCAPE:-"1"} 14 | 15 | for CHART_PATH in "${CHARTS_DIR}"/*; do 16 | 17 | if test ! -f "${CHART_PATH}/Chart.yaml"; then 18 | echo "Skipping over ${CHART_PATH}" 19 | continue 20 | fi 21 | 22 | if [ "$(yq e '.type' "${CHART_PATH}/Chart.yaml")" = "library" ]; then 23 | echo "Skipping library chart ${CHART_PATH}" 24 | continue 25 | fi 26 | 27 | echo "Power-linting ${CHART_PATH}:" 28 | 29 | if [ "$SHOULD_UPDATE_DEPENDENCIES" = "1" ]; then 30 | echo "Updating helm dependencies" 31 | helm dependency update "${CHART_PATH}" 32 | fi 33 | 34 | echo "Helm lint..." 35 | helm lint "${CHART_PATH}" 36 | 37 | for KUBERNETES_VERSION in ${KUBERNETES_VERSIONS}; do 38 | echo "Validating against Kubernetes version $KUBERNETES_VERSION:" 39 | 40 | HELM_TEMPLATE_ARGS="--kube-version=v$KUBERNETES_VERSION" 41 | TEST_VALUES_FILE="$CHART_PATH/values-test.yaml" 42 | if [ -f "$TEST_VALUES_FILE" ]; then 43 | HELM_TEMPLATE_ARGS="$HELM_TEMPLATE_ARGS -f ${CHART_PATH}/values-test.yaml" 44 | fi 45 | 46 | echo "Kubeconform check..." 47 | 48 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | 49 | kubeconform \ 50 | -ignore-missing-schemas \ 51 | -cache /tmp \ 52 | -strict \ 53 | -kubernetes-version "$KUBERNETES_VERSION" \ 54 | -verbose \ 55 | -exit-on-error \ 56 | -summary -; then 57 | echo "kubeconform validation failed" 58 | exit 1 59 | fi 60 | 61 | echo "Pluto check..." 62 | 63 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | 64 | pluto detect --target-versions k8s=v$KUBERNETES_VERSION -; then 65 | echo "Pluto failed" 66 | exit 1 67 | fi 68 | done 69 | 70 | echo "Polaris check..." 71 | 72 | POLARIS_AUDIT_ARGS="" 73 | POLARIS_CONFIG_FILE=".polaris.yaml" 74 | if [ -f "$POLARIS_CONFIG_FILE" ]; then 75 | POLARIS_AUDIT_ARGS="--config ${POLARIS_CONFIG_FILE}" 76 | fi 77 | 78 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | 79 | polaris audit \ 80 | --audit-path - \ 81 | --format pretty \ 82 | $POLARIS_AUDIT_ARGS \ 83 | --set-exit-code-on-danger \ 84 | --set-exit-code-below-score $POLARIS_SCORE_THRESHOLD; then 85 | echo "Polaris failed" 86 | exit 1 87 | fi 88 | 89 | if [ "$SKIP_KUBE_LINTER" -ne "1" ]; then 90 | echo "Kube-Linter check..." 91 | 92 | KUBE_LINTER_ARGS="" 93 | KUBE_LINTER_CONFIG_FILE=".kube-linter.yaml" 94 | if [ -f "$KUBE_LINTER_CONFIG_FILE" ]; then 95 | KUBE_LINTER_ARGS=" --config=${KUBE_LINTER_CONFIG_FILE}" 96 | fi 97 | 98 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | kube-linter lint ${KUBE_LINTER_ARGS} -; then 99 | echo "Kube-Linter failed" 100 | exit 1 101 | fi 102 | fi 103 | 104 | if [ "$SKIP_KUBE_SCORE" -ne "1" ]; then 105 | echo "Kube-Score check..." 106 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | kube-score score -; then 107 | echo "Kube-Score failed" 108 | exit 1 109 | fi 110 | fi 111 | 112 | if [ "$SKIP_KUBE_SCAPE" -ne "1" ]; then 113 | echo "kubescape nsa check..." 114 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | kubescape scan framework nsa --use-from=/root/.kubescape/nsa.json -; then 115 | echo "kubescape for NSA framework failed" 116 | exit 1 117 | fi 118 | 119 | echo "kubescape mitre check..." 120 | if ! helm template ${HELM_TEMPLATE_ARGS} ${CHART_PATH} | kubescape scan framework mitre --use-from=/root/.kubescape/mitre.json -; then 121 | echo "kubescape for NSA framework failed" 122 | exit 1 123 | fi 124 | fi 125 | done 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kube-powertools 2 | 3 | ![Last Version](https://img.shields.io/github/v/release/chgl/kube-powertools) 4 | ![License](https://img.shields.io/github/license/chgl/kube-powertools) 5 | [![CI](https://github.com/chgl/kube-powertools/actions/workflows/ci.yaml/badge.svg)](https://github.com/chgl/kube-powertools/actions/workflows/ci.yaml) 6 | [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/chgl/kube-powertools/badge)](https://scorecard.dev/viewer/?uri=github.com/chgl/kube-powertools) 7 | 8 | [![SLSA 3](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev) 9 | 10 | An always up to date collection of useful tools for your Kubernetes linting and auditing needs. 11 | 12 | ## Usage 13 | 14 | Mount a folder containing your Helm or raw Kubernetes manifests: 15 | 16 | ```sh 17 | docker run --rm -it -v $PWD:/root/workspace ghcr.io/chgl/kube-powertools:v2.4.37 18 | ``` 19 | 20 | The container image is pushed to these two registries: 21 | 22 | - docker.io/chgl/kube-powertools:v2.4.37 23 | - ghcr.io/chgl/kube-powertools:v2.4.37 24 | 25 | ## Helm Chart Repositories 26 | 27 | The kube-powertools image includes a few helpful scripts to simplify working with Helm chart repositories. 28 | 29 | ### Linting 30 | 31 | The image includes a [chart-powerlint.sh](scripts/chart-powerlint.sh) script which can be used to apply several linters to Helm chart repos. 32 | 33 | For example, you can mount this repository into the `kube-powertools` container and run the following to lint the sample chart 34 | in the `/samples/charts` dir: 35 | 36 | ```sh 37 | $ docker run --rm -it -v $PWD:/root/workspace ghcr.io/chgl/kube-powertools:v2.4.37 38 | bash-5.1# CHARTS_DIR=samples/charts chart-powerlint.sh 39 | ``` 40 | 41 | ### Generating Chart Documentation 42 | 43 | You can auto-generate and format Markdown docs from the chart's values.yaml using [generate-docs.sh](scripts/generate-docs.sh). 44 | This scripts uses either `chart-doc-gen` if the chart dir contains a `doc.yaml`, or `helm-docs` if it doesn't. 45 | 46 | ### Generating Chart Schemas 47 | 48 | You can auto-generate the Helm schema from the chart's values.yaml using [generate-schemas.sh](scripts/generate-schemas.sh). 49 | 50 | ### Generating CHANGELOG files 51 | 52 | Finally, there's [generate-chart-changelog.sh](scripts/generate-chart-changelog.sh), which can be used to generate a CHANGELOG.md file from 53 | the contents of a Chart.yaml's [artifacthub.io/changes](https://artifacthub.io/docs/topics/annotations/helm/#supported-annotations) annotation. 54 | 55 | You can use this file in conjunction with the [chart-releaser](https://github.com/helm/chart-releaser) tool's `--release-notes-file` option to produce release notes for a GitHub release. See and for a sample workflow. 56 | 57 | ## What's included 58 | 59 | - [kubectl](https://github.com/kubernetes/kubectl) 60 | - [helm](https://github.com/helm/helm) 61 | - [helm push plugin](https://github.com/chartmuseum/helm-push.git) 62 | - [helm schema-gen plugin](https://github.com/knechtionscoding/helm-schema-gen) 63 | - [helm unittest plugin](https://github.com/helm-unittest/helm-unittest) 64 | - [helm-local-chart-version](https://github.com/mbenabda/helm-local-chart-version) 65 | - [chart-doc-gen](https://github.com/kubepack/chart-doc-gen) 66 | - [kubeval](https://github.com/instrumenta/kubeval) 67 | - [kube-score](https://github.com/zegl/kube-score) 68 | - [chart-testing](https://github.com/helm/chart-testing) 69 | - [polaris](https://github.com/FairwindsOps/polaris) 70 | - [pluto](https://github.com/FairwindsOps/pluto) 71 | - [helm-docs](https://github.com/norwoodj/helm-docs) 72 | - [kube-linter](https://github.com/stackrox/kube-linter) 73 | - [kustomize](https://github.com/kubernetes-sigs/kustomize) 74 | - [conftest](https://github.com/open-policy-agent/conftest) 75 | - [nova](https://github.com/FairwindsOps/nova) 76 | - [kubesec](https://github.com/controlplaneio/kubesec) 77 | - [kubeconform](https://github.com/yannh/kubeconform) 78 | - [kube-no-trouble](https://github.com/doitintl/kube-no-trouble) 79 | - [trivy](https://github.com/aquasecurity/trivy) 80 | - [yq](https://github.com/mikefarah/yq) 81 | - [kubescape](https://github.com/armosec/kubescape) 82 | - [gomplate](https://github.com/hairyhenderson/gomplate) 83 | - [cosign](https://github.com/sigstore/cosign) 84 | - [crane](https://github.com/google/go-containerregistry/tree/main/cmd/crane) 85 | - [checkov](https://github.com/bridgecrewio/checkov) 86 | - [kubepug](https://github.com/rikatz/kubepug) 87 | - [container-structure-test](https://github.com/GoogleContainerTools/container-structure-test) 88 | - [Artifact Hub CLI](https://github.com/artifacthub/hub) 89 | - [Kyverno CLI](https://kyverno.io/docs/kyverno-cli/) 90 | - [Docker CE CLI](https://docs.docker.com/engine/install/ubuntu/) 91 | 92 | ## Testing locally 93 | 94 | ```sh 95 | docker build -t kube-powertools:dev . 96 | $ docker run --rm -it -v $PWD:/root/workspace kube-powertools:dev 97 | bash-5.1# CHARTS_DIR=samples/charts scripts/chart-powerlint.sh 98 | ``` 99 | 100 | ## Image signature and provenance verification 101 | 102 | Prerequisites: 103 | 104 | - [cosign](https://github.com/sigstore/cosign/releases) 105 | - [slsa-verifier](https://github.com/slsa-framework/slsa-verifier/releases) 106 | - [crane](https://github.com/google/go-containerregistry/releases) 107 | 108 | First, determine the digest of the container image to verify. This digest is also visible on 109 | the packages page on GitHub: . 110 | 111 | ```sh 112 | IMAGE=ghcr.io/chgl/kube-powertools:v2.4.37 113 | IMAGE_DIGEST=$(crane digest $IMAGE) 114 | IMAGE_TAG="${IMAGE#*:}" 115 | ``` 116 | 117 | Verify the container signature: 118 | 119 | ```sh 120 | cosign verify \ 121 | --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ 122 | --certificate-identity-regexp="https://github.com/chgl/.github/.github/workflows/standard-build.yaml@.*" \ 123 | --certificate-github-workflow-name="ci" \ 124 | --certificate-github-workflow-repository="chgl/kube-powertools" \ 125 | --certificate-github-workflow-trigger="release" \ 126 | --certificate-github-workflow-ref="refs/tags/${IMAGE_TAG}" \ 127 | "ghcr.io/chgl/kube-powertools@${IMAGE_DIGEST}" 128 | ``` 129 | 130 | Verify the container SLSA level 3 provenance attestation: 131 | 132 | ```sh 133 | slsa-verifier verify-image \ 134 | --source-uri github.com/chgl/kube-powertools \ 135 | --source-tag ${IMAGE_TAG} \ 136 | --source-branch master \ 137 | "ghcr.io/chgl/kube-powertools@${IMAGE_DIGEST}" 138 | ``` 139 | 140 | See also for details on verifying the image integrity using automated policy controllers. 141 | -------------------------------------------------------------------------------- /samples/charts/sample/README.md: -------------------------------------------------------------------------------- 1 | # sample 2 | 3 | [sample](https://github.com/OHDSI) - sample chart for deploying to Kubernetes. 4 | 5 | ## TL;DR; 6 | 7 | ```bash 8 | $ helm repo add chgl https://chgl.github.io/charts 9 | $ helm repo update 10 | $ helm search repo chgl/sample --version=0.1.0 11 | $ helm upgrade -i sample chgl/sample -n sample --create-namespace --version=0.1.0 12 | ``` 13 | 14 | ## Introduction 15 | 16 | This chart deploys the sample for Azure. on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. 17 | 18 | ## Prerequisites 19 | 20 | - Kubernetes v1.16+ 21 | - Helm v3 22 | 23 | ## Installing the Chart 24 | 25 | To install/upgrade the chart with the release name `sample`: 26 | 27 | ```bash 28 | $ helm upgrade -i sample chgl/sample -n sample --create-namespace --version=0.1.0 29 | ``` 30 | 31 | The command deploys the sample for Azure. on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. 32 | 33 | > **Tip**: List all releases using `helm list` 34 | 35 | ## Uninstalling the Chart 36 | 37 | To uninstall the `sample`: 38 | 39 | ```bash 40 | $ helm uninstall sample -n sample 41 | ``` 42 | 43 | The command removes all the Kubernetes components associated with the chart and deletes the release. 44 | 45 | ## Configuration 46 | 47 | The following table lists the configurable parameters of the `sample` chart and their default values. 48 | 49 | | Parameter | Description | Default | 50 | | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | 51 | | replicaCount | | 2 | 52 | | image.repository | | docker.io/nginxinc/nginx-unprivileged | 53 | | image.pullPolicy | | IfNotPresent | 54 | | image.tag | Overrides the image tag whose default is the chart appVersion. | "1.24.0@sha256:7c950a48f7d480f223633b3e7e15f88186a6b3455576bafc5403e808893edbed" | 55 | | imagePullSecrets | | [] | 56 | | nameOverride | | "" | 57 | | fullnameOverride | | "" | 58 | | serviceAccount.create | Specifies whether a service account should be created | true | 59 | | serviceAccount.annotations | Annotations to add to the service account | {} | 60 | | serviceAccount.name | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | "" | 61 | | podAnnotations | | {} | 62 | | podSecurityContext.runAsNonRoot | | true | 63 | | podSecurityContext.seccompProfile.type | | RuntimeDefault | 64 | | securityContext.readOnlyRootFilesystem | | true | 65 | | securityContext.runAsNonRoot | | true | 66 | | securityContext.runAsUser | | 65534 | 67 | | securityContext.runAsGroup | | 65534 | 68 | | securityContext.allowPrivilegeEscalation | | false | 69 | | securityContext.seccompProfile.type | | RuntimeDefault | 70 | | service.type | | ClusterIP | 71 | | service.port | | 80 | 72 | | ingress.enabled | | false | 73 | | ingress.annotations | | {} | 74 | | ingress.tls | | [] | 75 | | resources.limits.cpu | | 100m | 76 | | resources.limits.memory | | 128Mi | 77 | | resources.requests.cpu | | 100m | 78 | | resources.requests.memory | | 128Mi | 79 | | autoscaling.enabled | | false | 80 | | autoscaling.minReplicas | | 1 | 81 | | autoscaling.maxReplicas | | 100 | 82 | | autoscaling.targetCPUUtilizationPercentage | | 80 | 83 | | nodeSelector | | {} | 84 | | tolerations | | [] | 85 | | affinity | | {} | 86 | 87 | Specify each parameter using the `--set key=value[,key=value]` argument to `helm upgrade -i`. For example: 88 | 89 | ```bash 90 | $ helm upgrade -i sample chgl/sample -n sample --create-namespace --version=0.1.0 --set replicaCount=2 91 | ``` 92 | 93 | Alternatively, a YAML file that specifies the values for the parameters can be provided while 94 | installing the chart. For example: 95 | 96 | ```bash 97 | $ helm upgrade -i sample chgl/sample -n sample --create-namespace --version=0.1.0 --values values.yaml 98 | ``` 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020+ https://github.com/chgl 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # kics-scan disable=b03a748a-542d-44f4-bb86-9199ab4fd2d5 2 | FROM docker.io/library/ubuntu:24.04@sha256:c35e29c9450151419d9448b0fd75374fec4fff364a27f176fb458d472dfc9e54 3 | SHELL ["/bin/bash", "-eo", "pipefail", "-c"] 4 | ENV NO_UPDATE_NOTIFIER=true \ 5 | NODE_ENV=production \ 6 | PATH="$PATH:/root/node_modules/.bin" 7 | WORKDIR /root 8 | 9 | # hadolint ignore=DL3008,SC1091 10 | RUN < /dev/null 21 | apt-get update 22 | DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install -y --no-install-recommends \ 23 | docker-ce-cli 24 | apt-get clean 25 | rm -rf /var/lib/apt/lists/* 26 | EOF 27 | 28 | COPY requirements.txt package*.json ./ 29 | 30 | # break-system-packages should be fine in a container environment 31 | RUN <