" >> ${GITHUB_STEP_SUMMARY}
+ echo "Build Context | Value |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Helm chart version | ${{ steps.get_context.outputs.CHART_VERSION }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Original registry | ${{ steps.get_context.outputs.ORIGINAL_REGISTRY }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Original repository | ${{ steps.get_context.outputs.ORIGINAL_REPO }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Original tag | ${{ steps.get_context.outputs.ORIGINAL_TAG }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Original image | ${{ steps.get_context.outputs.ORIGINAL_IMAGE }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Build registry | ${{ steps.get_context.outputs.BUILD_REGISTRY }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Build repository | ${{ steps.get_context.outputs.BUILD_REPO }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Build tag | ${BUILD_TAG} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Build image | ${BUILD_IMAGE} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Ref tags | ${REF_TAGS} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "All build images | ${{ steps.meta.outputs.tags }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Build labels | ${{ steps.meta.outputs.labels }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "
" >> ${GITHUB_STEP_SUMMARY}
+ echo "" >> ${GITHUB_STEP_SUMMARY}
+ echo "" >> ${GITHUB_STEP_SUMMARY}
+ echo "Setting | Value |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run Docs | $(get_output ${{ steps.conditionals.outputs.skip_docs }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run Build | $(get_output ${{ steps.conditionals.outputs.skip_build }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run Compliance | $(get_output ${{ steps.conditionals.outputs.skip_compliance_checks }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run Unit Tests | $(get_output ${{ steps.conditionals.outputs.skip_unit_tests }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run SAST | $(get_output ${{ steps.conditionals.outputs.skip_sast }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run SCA | $(get_output ${{ steps.conditionals.outputs.skip_sca }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Run Integration Tests | $(get_output ${{ steps.conditionals.outputs.skip_integration_tests }}) |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "Report type | ${{ steps.conditionals.outputs.output_type }} |
" >> ${GITHUB_STEP_SUMMARY}
+ echo "
" >> ${GITHUB_STEP_SUMMARY}
+ echo "($(get_output 'none') - run all jobs, $(get_output 'non-required') - run important/required jobs only, $(get_output 'all') - skip jobs)" >> ${GITHUB_STEP_SUMMARY}
+ echo "" >> ${GITHUB_STEP_SUMMARY}
+
+ build:
+ uses: ./.github/workflows/.reusable-build.yml
+ needs: [conditionals]
+ # permissions: #TODO: reactivate for non-private
+ # packages: write
+ secrets: inherit
+ with:
+ skip: ${{ needs.conditionals.outputs.skip_build }}
+
+ compliance:
+ uses: ./.github/workflows/.reusable-compliance.yml
+ needs: [conditionals]
+ # permissions: #TODO: reactivate for non-private
+ # contents: write
+ # id-token: write
+ # security-events: write
+ # actions: read
+ # checks: read
+ # deployments: read
+ # issues: read
+ # discussions: read
+ # packages: read
+ # pages: read
+ # pull-requests: read
+ # repository-projects: read
+ # statuses: read
+ secrets: inherit
+ with:
+ skip: ${{ needs.conditionals.outputs.skip_compliance_checks }}
+
+ unit-test:
+ uses: ./.github/workflows/.reusable-unit-test.yml
+ needs: [conditionals]
+ with:
+ skip: ${{ needs.conditionals.outputs.skip_unit_tests }}
+
+ sast:
+ uses: ./.github/workflows/.reusable-sast.yml
+ needs: [conditionals]
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ # pull-requests: read
+ with:
+ skip: ${{ needs.conditionals.outputs.skip_sast }}
+ output: ${{ needs.conditionals.outputs.output_type }}
+
+ sca:
+ uses: ./.github/workflows/.reusable-sca.yml
+ needs: [conditionals, build]
+ # permissions: #TODO: reactivate for non-private
+ # contents: write
+ # security-events: write
+ # packages: read
+ secrets: inherit
+ with:
+ registry: ${{ needs.build.outputs.build_registry }}
+ repo_owner: ${{ github.repository_owner }}
+ image: ${{ needs.build.outputs.build_image }}
+ skip: ${{ needs.conditionals.outputs.skip_sca }}
+ output: ${{ needs.conditionals.outputs.output_type }}
+
+ docs:
+ uses: ./.github/workflows/.reusable-docs.yml
+ needs: [conditionals]
+ # permissions: #TODO: reactivate for non-private
+ # contents: write
+ with:
+ skip: ${{ needs.conditionals.outputs.skip_docs }}
+
+ integration-test:
+ uses: ./.github/workflows/.reusable-integration-test.yml
+ needs: [conditionals, build]
+ # permissions: #TODO: reactivate for non-private
+ # packages: read
+ secrets: inherit
+ with:
+ build_registry: ${{ needs.build.outputs.build_registry }}
+ repo_owner: ${{ github.repository_owner }}
+ build_image_repository: ${{ needs.build.outputs.build_registry }}/${{ needs.build.outputs.build_repo }}
+ build_tag: ${{ needs.build.outputs.build_tag }}
+ skip: ${{ needs.conditionals.outputs.skip_integration_tests }}
+ cosign_public_key: ${{ needs.build.outputs.cosign_public_key }}
diff --git a/.github/workflows/.reusable-cleanup-registry.yml b/.github/workflows/.reusable-cleanup-registry.yml
new file mode 100644
index 0000000..2bef523
--- /dev/null
+++ b/.github/workflows/.reusable-cleanup-registry.yml
@@ -0,0 +1,40 @@
+name: cleanup registry
+
+on:
+ workflow_call:
+
+permissions: {}
+
+jobs:
+ cleanup-registry:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Cleanup test images in 'connaisseur-test'
+ uses: snok/container-retention-policy@3d27e6a0361deed0b7dc5099a82eadd07924b177 # v2.1.3
+ with:
+ image-names: connaisseur-test
+ cut-off: three weeks ago UTC+1
+ timestamp-to-use: updated_at
+ account-type: org
+ org-name: sse-secure-systems
+ token: ${{ secrets.GHCR_PAT }}
+ - name: Cleanup dangling images without tag
+ uses: snok/container-retention-policy@3d27e6a0361deed0b7dc5099a82eadd07924b177 # v2.1.3
+ with:
+ image-names: connaisseur*
+ untagged-only: true
+ cut-off: four hours ago UTC+1
+ timestamp-to-use: updated_at
+ account-type: org
+ org-name: sse-secure-systems
+ token: ${{ secrets.GHCR_PAT }}
+ - name: Cleanup all connaisseur images
+ uses: snok/container-retention-policy@3d27e6a0361deed0b7dc5099a82eadd07924b177 # v2.1.3
+ with:
+ image-names: connaisseur
+ skip-tags: master, develop, v*, sha256-*
+ cut-off: four days ago UTC+1
+ timestamp-to-use: updated_at
+ account-type: org
+ org-name: sse-secure-systems
+ token: ${{ secrets.GHCR_PAT }}
diff --git a/.github/workflows/.reusable-compliance.yml b/.github/workflows/.reusable-compliance.yml
new file mode 100644
index 0000000..af38ccf
--- /dev/null
+++ b/.github/workflows/.reusable-compliance.yml
@@ -0,0 +1,87 @@
+name: compliance
+
+on:
+ workflow_call:
+ inputs:
+ skip:
+ description: "Want to skip running certain jobs 'none', 'non-required', 'all'?"
+ type: string
+ default: "none"
+
+#permissions: read-all
+
+jobs:
+ ossf-scorecard:
+ runs-on: ubuntu-latest
+ if: |
+ (github.ref_name == 'master' || github.event_name == 'pull_request') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ # id-token: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ with:
+ persist-credentials: false
+ - name: Analyze
+ uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ repo_token: ${{ secrets.SCORECARD_TOKEN }}
+ publish_results: ${{ github.ref_name == 'master' }}
+ - name: Upload
+ uses: github/codeql-action/upload-sarif@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+ with:
+ sarif_file: results.sarif
+
+ dependency-review:
+ name: dependency review
+ runs-on: ubuntu-latest
+ if: |
+ github.event_name == 'pull_request' &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # contents: write
+ # pull-requests: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Review
+ uses: actions/dependency-review-action@7bbfa034e752445ea40215fff1c3bf9597993d3f # v3.1.3
+ with:
+ comment-summary-in-pr: always
+
+ check-commit-message:
+ runs-on: ubuntu-latest
+ if: |
+ github.event_name == 'pull_request' &&
+ inputs.skip != 'all'
+ # permissions: {} #TODO: reactivate for non-private
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ with:
+ ref: ${{ github.event.pull_request.head.sha }} # Otherwise will checkout merge commit, which isn't conform
+ fetch-depth: ${{ github.event.pull_request.commits }} # Fetch all commits of the MR, but only those
+ - name: Check commit messages for conformity
+ run: |
+ echo "Commits between dev branch and current SHA:"
+ COMMITS=$(git log --pretty=%H)
+ echo "${COMMITS}"
+ EXIT=0
+ COMMIT_MSGS=$(git log --pretty=%s) # show subject only
+ for commit in ${COMMITS}; do
+ MSG=$(git log ${commit} -n1 --pretty=%s)
+ TYPE=$(echo ${MSG} | awk '{{ print $1 }}')
+ if ! [[ "${TYPE}" =~ ^(build|ci|docs|feat|fix|refactor|test|update):$ ]]; then
+ EXIT=1
+ echo "Commit message of commit ${commit} doesn't conform to 'type: msg' format:"
+ echo "${MSG}"
+ echo "-------------------------"
+ fi
+ done
+ exit ${EXIT}
diff --git a/.github/workflows/.reusable-docs.yml b/.github/workflows/.reusable-docs.yml
new file mode 100644
index 0000000..fce6553
--- /dev/null
+++ b/.github/workflows/.reusable-docs.yml
@@ -0,0 +1,43 @@
+name: docs
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ workflow_call:
+ inputs:
+ skip:
+ description: "Want to skip running certain jobs 'none', 'non-required', 'all'?"
+ type: string
+ default: "none"
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ if: inputs.skip != 'all'
+ permissions:
+ contents: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ with:
+ fetch-depth: 0
+ - name: Set release env
+ run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
+ - name: Configure the git user
+ run: |
+ git config user.name "versioning_user"
+ git config user.email "connaisseur@securesystems.dev"
+ - name: Install
+ run: |
+ pip install -r docs/requirements.txt
+ - name: Deploy
+ if: inputs.skip != 'non-required'
+ run: |
+ if [[ "${GITHUB_REF}" == "refs/tags/v"* ]];
+ then
+ mike deploy --push --update-aliases ${RELEASE_VERSION} latest
+ elif [[ "${GITHUB_REF}" == "refs/heads/dev" ]]; then
+ mike deploy --push ${RELEASE_VERSION}
+ else
+ mkdocs build
+ fi
diff --git a/.github/workflows/.reusable-integration-test.yml b/.github/workflows/.reusable-integration-test.yml
new file mode 100644
index 0000000..43a8708
--- /dev/null
+++ b/.github/workflows/.reusable-integration-test.yml
@@ -0,0 +1,41 @@
+name: integration-test
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ workflow_call:
+ inputs:
+ build_registry:
+ description: "Workflow build registry used for testing"
+ type: string
+ repo_owner:
+ description: 'Name of repository owner, e.g. "inputs.repo_owner" for ghcr.io'
+ type: string
+ build_image_repository:
+ description: "Workflow build image used for testing, excluding the tag i.e. registry + repository"
+ type: string
+ build_tag:
+ description: "Tag of build image used for testing"
+ type: string
+ skip:
+ description: "Want to skip running certain jobs 'none', 'non-required', 'all'?"
+ type: string
+ default: "none"
+ cosign_public_key:
+ description: "Cosign public key used for signing the build image"
+ type: string
+
+env:
+ IMAGEPULLSECRET: dockerconfigjson-ghcr
+
+jobs:
+ do-nothing:
+ name: functional
+ runs-on: ubuntu-latest
+ if: inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # packages: read
+ steps:
+ - name: Do nothing
+ run: |
+ sleep 1
diff --git a/.github/workflows/.reusable-sast.yml b/.github/workflows/.reusable-sast.yml
new file mode 100644
index 0000000..68d9451
--- /dev/null
+++ b/.github/workflows/.reusable-sast.yml
@@ -0,0 +1,235 @@
+name: sast
+
+on:
+ workflow_call:
+ inputs:
+ skip:
+ description: "Want to skip running certain jobs 'none', 'non-required', 'all'?"
+ type: string
+ default: "none"
+ output:
+ description: 'Output either "sarif" (GITHUB_TOKEN with security-events:write) or print results as "table" and fail on error'
+ type: string
+ required: false
+ default: 'sarif'
+
+#permissions: {} #TODO: reactivate for non-private
+
+jobs:
+ bandit:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'all'
+ permissions:
+ security-events: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Install Packages
+ run: pip3 install -r tests/requirements.txt
+ - name: Run Bandit
+ if: inputs.output == 'table'
+ run: bandit -r -f screen semgr8s/
+ - name: Run Bandit
+ if: inputs.output == 'sarif'
+ run: bandit -r -f sarif -o bandit-results.sarif semgr8s/ --exit-zero
+ - name: Upload
+ if: inputs.output == 'sarif'
+ uses: github/codeql-action/upload-sarif@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
+ with:
+ sarif_file: 'bandit-results.sarif'
+
+ black:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Install packages
+ run: pip3 install -r tests/requirements.txt
+ - name: Test formatting
+ run: |
+ python3 -m black . 2>&1 | grep -q "reformatted" && { echo 'Not properly formatted.'; exit 1; } || true
+
+ checkov:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Render Helm charts
+ run: |
+ rm -rf test # remove 'test' folder from scan #TODO: fix once final
+ rm -rf tests # remove 'tests' folder from scan
+ mkdir deployment
+ helm template charts/semgr8s > deployment/deployment.yaml
+ shell: bash
+ - name: Scan
+ if: inputs.output == 'table'
+ uses: bridgecrewio/checkov-action@558f721c4bd65a6fc59b02448ffc792eb721cb9b # v12.2580.0
+ with:
+ output_format: cli
+ soft_fail: false
+ - name: Scan
+ if: inputs.output == 'sarif'
+ uses: bridgecrewio/checkov-action@558f721c4bd65a6fc59b02448ffc792eb721cb9b # v12.2580.0
+ with:
+ output_file_path: console,checkov-results.sarif
+ output_format: cli,sarif
+ soft_fail: true
+ - name: Upload
+ if: inputs.output == 'sarif'
+ uses: github/codeql-action/upload-sarif@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+ with:
+ sarif_file: checkov-results.sarif
+
+ codeql:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ permissions:
+ security-events: write
+ pull-requests: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
+ with:
+ languages: 'python'
+ - name: Analyze
+ uses: github/codeql-action/analyze@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8
+
+ hadolint:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Scan
+ uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0
+ if: inputs.output == 'table'
+ with:
+ dockerfile: build/Dockerfile
+ format: tty
+ no-fail: false
+ - name: Scan
+ uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0
+ if: inputs.output == 'sarif'
+ with:
+ dockerfile: build/Dockerfile
+ format: sarif
+ no-fail: true
+ output-file: hadolint-results.sarif
+ - name: Upload
+ uses: github/codeql-action/upload-sarif@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+ if: inputs.output == 'sarif'
+ with:
+ sarif_file: 'hadolint-results.sarif'
+
+ kubelinter:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Scan
+ uses: stackrox/kube-linter-action@ca0d55b925470deb5b04b556e6c4276ea94d03c3 # v1.0.4
+ if: inputs.output == 'table'
+ with:
+ config: .kube-linter/config.yaml
+ directory: charts/semgr8s
+ format: plain
+ - name: Scan
+ uses: stackrox/kube-linter-action@ca0d55b925470deb5b04b556e6c4276ea94d03c3 # v1.0.4
+ if: inputs.output == 'sarif'
+ with:
+ config: .kube-linter/config.yaml
+ directory: charts/semgr8s
+ format: sarif
+ output-file: kubelinter-results.sarif
+ - name: Upload
+ uses: github/codeql-action/upload-sarif@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+ if: inputs.output == 'sarif'
+ with:
+ sarif_file: 'kubelinter-results.sarif'
+
+ pylint:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'all'
+ container:
+ image: python:3.11-slim
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Install
+ run: |
+ pip3 install -r tests/requirements.txt
+ - name: Lint
+ run: pylint --ignore-patterns=tests,coverage semgr8s
+
+ semgrep:
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ container:
+ image: returntocorp/semgrep
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Scan
+ if: inputs.output == 'table'
+ run: semgrep ci --config=auto --suppress-errors --text
+ - name: Scan
+ if: inputs.output == 'sarif'
+ run: semgrep ci --config=auto --suppress-errors --sarif --output=semgrep-results.sarif || exit 0
+ - name: Upload
+ uses: github/codeql-action/upload-sarif@66b90a5db151a8042fa97405c6cf843bbe433f7b # v2.22.7
+ if: inputs.output == 'sarif'
+ with:
+ sarif_file: semgrep-results.sarif
+
+ trivy-config-scan:
+ name: trivy config
+ runs-on: ubuntu-latest
+ if: |
+ (github.actor != 'dependabot[bot]') &&
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # security-events: write
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Run Trivy
+ uses: ./.github/actions/trivy-config
+ with:
+ output: ${{ inputs.output }}
+
diff --git a/.github/workflows/.reusable-sca.yml b/.github/workflows/.reusable-sca.yml
new file mode 100644
index 0000000..66c5d76
--- /dev/null
+++ b/.github/workflows/.reusable-sca.yml
@@ -0,0 +1,100 @@
+name: sca
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ workflow_call:
+ inputs:
+ image:
+ description: "Image used for testing, i.e. registry + repository + tag"
+ type: string
+ required: true
+ registry:
+ description: 'Registry to login to pull image, e.g. "ghcr.io" for GHCR, leave empty if image is public'
+ type: string
+ required: false
+ default: ''
+ repo_owner:
+ description: 'Name of repository owner, e.g. "github.repository_owner" for ghcr.io'
+ type: string
+ required: false
+ default: ''
+ skip:
+ description: "Want to skip running certain jobs 'none', 'non-required', 'all'?"
+ type: string
+ default: "none"
+ output:
+ description: 'Output either "sarif" (GITHUB_TOKEN with security-events:write) or print results as "table" and fail on error'
+ type: string
+ required: false
+ default: 'sarif'
+
+jobs:
+ trivy-image-scan:
+ name: trivy image
+ runs-on: ubuntu-latest
+ if: inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # packages: read
+ # security-events: write
+ container:
+ image: docker:stable
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Run
+ uses: ./.github/actions/trivy-image
+ with:
+ image: ${{ inputs.image }}
+ registry: ${{ inputs.registry }}
+ repo_owner: ${{ inputs.repo_owner }}
+ repo_token: ${{ secrets.GITHUB_TOKEN }}
+ output: ${{ inputs.output }}
+
+ grype:
+ name: grype
+ runs-on: ubuntu-latest
+ if: |
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # packages: read
+ # security-events: write
+ container:
+ image: docker:stable
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Run
+ uses: ./.github/actions/grype
+ with:
+ image: ${{ inputs.image }}
+ registry: ${{ inputs.registry }}
+ repo_owner: ${{ inputs.repo_owner }}
+ repo_token: ${{ secrets.GITHUB_TOKEN }}
+ output: ${{ inputs.output }}
+
+# WIP: Syft issue seems to cause error (https://github.com/anchore/syft/issues/1622)
+ dependency-submission:
+ name: syft / dependency review
+ runs-on: ubuntu-latest
+ if: |
+ inputs.skip != 'non-required' &&
+ inputs.skip != 'all'
+ # permissions: #TODO: reactivate for non-private
+ # packages: read
+ # contents: write
+ steps:
+ - name: Login with registry
+ if: inputs.registry != ''
+ uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
+ with:
+ registry: ${{ inputs.registry }}
+ username: ${{ inputs.repo_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Run
+ uses: anchore/sbom-action@78fc58e266e87a38d4194b2137a3d4e9bcaf7ca1 # v0.14.3
+ with:
+ image: ${{ inputs.image }}
+ format: cyclonedx-json
+ dependency-snapshot: ${{ inputs.output == 'sarif' }}
diff --git a/.github/workflows/.reusable-unit-test.yml b/.github/workflows/.reusable-unit-test.yml
new file mode 100644
index 0000000..6f7e711
--- /dev/null
+++ b/.github/workflows/.reusable-unit-test.yml
@@ -0,0 +1,29 @@
+name: unit-test
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ workflow_call:
+ inputs:
+ skip:
+ description: "Want to skip running certain jobs 'none', 'non-required', 'all'?"
+ type: string
+ default: "none"
+
+jobs:
+ gotest:
+ name: unit tests
+ runs-on: ubuntu-latest
+ if: inputs.skip != 'all'
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Install
+ run: |
+ pip3 install -r tests/requirements.txt && pip3 install .
+ - name: Test
+ run: pytest --cov=semgr8s --cov-report=xml tests/
+ - name: Upload
+ uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
+ with:
+ file: coverage.xml
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
new file mode 100644
index 0000000..4c39e0c
--- /dev/null
+++ b/.github/workflows/pr.yml
@@ -0,0 +1,29 @@
+name: pr
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ pull_request:
+ branches:
+ - main
+ - dev
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ ci:
+ uses: ./.github/workflows/.reusable-ci.yml
+ # permissions: #TODO: adjust for non-private
+ secrets: inherit
+ with:
+ #TODO: adjust for non private
+ skip_build: 'none'
+ skip_compliance_checks: 'none'
+ skip_unit_tests: 'all'
+ skip_sast: 'none'
+ skip_sca: 'none'
+ skip_docs: 'non-required'
+ skip_integration_tests: 'none'
+ output_type: 'sarif'
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
new file mode 100644
index 0000000..1c5516b
--- /dev/null
+++ b/.github/workflows/push.yml
@@ -0,0 +1,29 @@
+name: push
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ push:
+ branches:
+ - main
+ - dev
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ ci:
+ uses: ./.github/workflows/.reusable-ci.yml
+ # permissions: #TODO: adjust for non-private
+ secrets: inherit
+ with:
+ #TODO: adjust for non private
+ skip_build: 'none'
+ skip_compliance_checks: 'none'
+ skip_unit_tests: 'all'
+ skip_sast: 'non-required'
+ skip_sca: 'non-required'
+ skip_docs: 'none'
+ skip_integration_tests: 'non-required'
+ output_type: 'sarif'
diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml
new file mode 100644
index 0000000..138c21c
--- /dev/null
+++ b/.github/workflows/tag.yml
@@ -0,0 +1,28 @@
+name: tag
+
+#permissions: {} #TODO: reactivate for non-private
+
+on:
+ push:
+ tags:
+ - "v*"
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ ci:
+ uses: ./.github/workflows/.reusable-ci.yml
+ # permissions: #TODO: adjust for non-private
+ secrets: inherit
+ with:
+ #TODO: adjust for non private
+ skip_build: 'none'
+ skip_compliance_checks: 'none'
+ skip_unit_tests: 'all'
+ skip_sast: 'none'
+ skip_sca: 'none'
+ skip_docs: 'none'
+ skip_integration_tests: 'non-required'
+ output_type: 'sarif'
diff --git a/.kube-linter/config.yaml b/.kube-linter/config.yaml
new file mode 100644
index 0000000..6b4d6ea
--- /dev/null
+++ b/.kube-linter/config.yaml
@@ -0,0 +1,2 @@
+checks:
+ doNotAutoAddDefaults: false
diff --git a/Makefile b/Makefile
index 22aa7d4..c078174 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
webhookName := semgr8s
-image := $(shell yq e '.deployment.image.repository' helm/values.yaml)
-version := $(shell yq e '.appVersion' helm/Chart.yaml)
+image := $(shell yq e '.deployment.image.repository' charts/semgr8s/values.yaml)
+version := $(shell yq e '.appVersion' charts/semgr8s/Chart.yaml)
tag := $(image):$(version)
ns := semgr8ns
@@ -12,7 +12,7 @@ build:
@echo "####################"
@echo "## $(@)"
@echo "####################"
- docker buildx build --platform=linux/amd64 -t $(tag) -f docker/Dockerfile .
+ docker buildx build --platform=linux/amd64 -t $(tag) -f build/Dockerfile .
.PHONY:push
push:
diff --git a/README.md b/README.md
index 79fe996..e6cb536 100644
--- a/README.md
+++ b/README.md
@@ -65,10 +65,10 @@ cd semgr8s
Semgr8s comes preconfigured with some basic rules.
However, configuration can be adjusted to your needs:
-- Central configuration is maintained in `helm/values.yaml`.
+- Central configuration is maintained in `charts/semgr8s/values.yaml`.
- Configuration aims to provide the most native integration of Semgrep's functionality into Kubernetes. Working knowledge of Kubernetes and the [Semgrep documentation](https://semgrep.dev/docs/) should be sufficient to understand the concepts and options being used here.
-- [Remote Semgrep](https://registry.semgrep.dev/rule) rules, rulesets, [repository rules](https://github.com/returntocorp/semgrep-rules) are configured via `.application.remoteRules` in `helm/values.yaml`, e.g. set to `"r/yaml.kubernetes.security.allow-privilege-escalation.allow-privilege-escalation"` or `"p/kubernetes"`, or `"r/yaml.kubernetes"` respectively.
-- [Custom Semgrep rules](https://semgrep.dev/docs/writing-rules/overview/) can placed in `helm/rules/` and will be auto-mounted into the admission controller.
+- [Remote Semgrep](https://registry.semgrep.dev/rule) rules, rulesets, [repository rules](https://github.com/returntocorp/semgrep-rules) are configured via `.application.remoteRules` in `charts/semgr8s/values.yaml`, e.g. set to `"r/yaml.kubernetes.security.allow-privilege-escalation.allow-privilege-escalation"` or `"p/kubernetes"`, or `"r/yaml.kubernetes"` respectively.
+- [Custom Semgrep rules](https://semgrep.dev/docs/writing-rules/overview/) can placed in `charts/semgr8s/rules/` and will be auto-mounted into the admission controller.
- Semgrep provides online tools to [learn](https://semgrep.dev/learn) and [create](https://semgrep.dev/playground/new) custom rules.
To deploy the preconfigured admission controller simply run:
@@ -119,7 +119,7 @@ Once all resources are in `READY` state, you have successfully installed semgr8s
### Testing
Several test resources are provided under `tests/`.
-Semgr8s denies creating pods with insecure configuration according to the rules in `helm/rules`:
+Semgr8s denies creating pods with insecure configuration according to the rules in `charts/semgr8s/rules`:
```bash
kubectl create -f tests/failing_deployment.yaml
diff --git a/docker/Dockerfile b/build/Dockerfile
similarity index 100%
rename from docker/Dockerfile
rename to build/Dockerfile
diff --git a/charts/semgr8s/Chart.yaml b/charts/semgr8s/Chart.yaml
new file mode 100644
index 0000000..9c7cbe4
--- /dev/null
+++ b/charts/semgr8s/Chart.yaml
@@ -0,0 +1,17 @@
+apiVersion: v2
+name: semgr8s
+description: Semgrep-based Policy Controller for Kubernetes
+type: application
+version: 0.1.1
+appVersion: "0.1.1"
+keywords:
+ - kubernetes
+ - admission controller
+ - policy management
+home: https://sse-secure-systems.github.io/semgr8s/latest
+sources:
+ - https://github.com/sse-secure-systems/semgr8s
+icon: https://raw.githubusercontent.com/sse-secure-systems/semgr8s/main/docs/assets/semgr8s-logo.png
+maintainers:
+ - name: Christoph Hamsen
+ email: christoph.hamsen@securesystems.de
diff --git a/helm/rules/allow-privilege-escalation-no-securitycontext.yaml b/charts/semgr8s/rules/allow-privilege-escalation-no-securitycontext.yaml
similarity index 100%
rename from helm/rules/allow-privilege-escalation-no-securitycontext.yaml
rename to charts/semgr8s/rules/allow-privilege-escalation-no-securitycontext.yaml
diff --git a/helm/rules/hostnetwork-pod.yaml b/charts/semgr8s/rules/hostnetwork-pod.yaml
similarity index 100%
rename from helm/rules/hostnetwork-pod.yaml
rename to charts/semgr8s/rules/hostnetwork-pod.yaml
diff --git a/helm/rules/privileged-container.yaml b/charts/semgr8s/rules/privileged-container.yaml
similarity index 100%
rename from helm/rules/privileged-container.yaml
rename to charts/semgr8s/rules/privileged-container.yaml
diff --git a/helm/rules/run-as-non-root.yaml b/charts/semgr8s/rules/run-as-non-root.yaml
similarity index 100%
rename from helm/rules/run-as-non-root.yaml
rename to charts/semgr8s/rules/run-as-non-root.yaml
diff --git a/helm/templates/NOTES.txt b/charts/semgr8s/templates/NOTES.txt
similarity index 100%
rename from helm/templates/NOTES.txt
rename to charts/semgr8s/templates/NOTES.txt
diff --git a/helm/templates/_helpers.tpl b/charts/semgr8s/templates/_helpers.tpl
similarity index 100%
rename from helm/templates/_helpers.tpl
rename to charts/semgr8s/templates/_helpers.tpl
diff --git a/helm/templates/deployment.yaml b/charts/semgr8s/templates/deployment.yaml
similarity index 100%
rename from helm/templates/deployment.yaml
rename to charts/semgr8s/templates/deployment.yaml
diff --git a/helm/templates/env.yaml b/charts/semgr8s/templates/env.yaml
similarity index 100%
rename from helm/templates/env.yaml
rename to charts/semgr8s/templates/env.yaml
diff --git a/helm/templates/role.yaml b/charts/semgr8s/templates/role.yaml
similarity index 100%
rename from helm/templates/role.yaml
rename to charts/semgr8s/templates/role.yaml
diff --git a/helm/templates/rolebinding.yaml b/charts/semgr8s/templates/rolebinding.yaml
similarity index 100%
rename from helm/templates/rolebinding.yaml
rename to charts/semgr8s/templates/rolebinding.yaml
diff --git a/helm/templates/rules.yaml b/charts/semgr8s/templates/rules.yaml
similarity index 100%
rename from helm/templates/rules.yaml
rename to charts/semgr8s/templates/rules.yaml
diff --git a/helm/templates/service.yaml b/charts/semgr8s/templates/service.yaml
similarity index 100%
rename from helm/templates/service.yaml
rename to charts/semgr8s/templates/service.yaml
diff --git a/helm/templates/serviceaccount.yaml b/charts/semgr8s/templates/serviceaccount.yaml
similarity index 100%
rename from helm/templates/serviceaccount.yaml
rename to charts/semgr8s/templates/serviceaccount.yaml
diff --git a/helm/templates/webhook.yaml b/charts/semgr8s/templates/webhook.yaml
similarity index 100%
rename from helm/templates/webhook.yaml
rename to charts/semgr8s/templates/webhook.yaml
diff --git a/helm/values.yaml b/charts/semgr8s/values.yaml
similarity index 100%
rename from helm/values.yaml
rename to charts/semgr8s/values.yaml
diff --git a/docs/README.md b/docs/README.md
new file mode 120000
index 0000000..32d46ee
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1 @@
+../README.md
\ No newline at end of file
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..df6da05
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,2 @@
+mkdocs-material~=9.4.14
+mike~=2.0.0
diff --git a/helm/.helmignore b/helm/.helmignore
deleted file mode 100644
index 0e8a0eb..0000000
--- a/helm/.helmignore
+++ /dev/null
@@ -1,23 +0,0 @@
-# Patterns to ignore when building packages.
-# This supports shell glob matching, relative path matching, and
-# negation (prefixed with !). Only one pattern per line.
-.DS_Store
-# Common VCS dirs
-.git/
-.gitignore
-.bzr/
-.bzrignore
-.hg/
-.hgignore
-.svn/
-# Common backup files
-*.swp
-*.bak
-*.tmp
-*.orig
-*~
-# Various IDEs
-.project
-.idea/
-*.tmproj
-.vscode/
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
deleted file mode 100644
index 88d151b..0000000
--- a/helm/Chart.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-apiVersion: v2
-name: semgr8s
-description: A Helm chart for Kubernetes
-type: application
-version: 0.1.1
-appVersion: "0.1.1"
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..dc294a6
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,88 @@
+# Project information
+site_name: semgr8s - Semgrep-based Policy Controller for Kubernetes.
+
+site_url: https://sse-secure-systems.github.io/semgr8s/
+site_description: >-
+ Admission controller to use your well-known publicly available or custom Semgrep rules to validate k8s resources before deployment to the cluster.
+
+# Repository
+repo_name: sse-secure-systems/semgr8s/
+repo_url: https://github.com/sse-secure-systems/semgr8s
+edit_uri: ""
+
+# Company
+copyright: