-
Notifications
You must be signed in to change notification settings - Fork 437
feat: implement secure container supply chain #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,53 +1,53 @@ | ||
| # Goal - To Run End to End DevSecOps CI Pipeline | ||
|
|
||
| name: DevSecOps | ||
|
|
||
| on: | ||
| push: | ||
| branches: [master] | ||
| push: | ||
| branches: | ||
| - master | ||
| - feat/dora-sota | ||
|
|
||
| pull_request: | ||
| branches: | ||
| - master | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
|
|
||
| ## ---- CI ---- | ||
| # Code Stage | ||
| code-quality: | ||
| uses: ./.github/workflows/code-quality.yml | ||
|
|
||
| # Secret Scanning | ||
| secret-scanning: | ||
| uses: ./.github/workflows/secret-scanning.yml | ||
|
|
||
| # Dependency Checks | ||
| dependency-checks: | ||
| uses: ./.github/workflows/dependency-scan.yml | ||
|
|
||
| # Docker Checks | ||
| docker-checks: | ||
| uses: ./.github/workflows/docker-scans.yml | ||
| secrets: inherit | ||
|
|
||
| # SonarQube | ||
| sonar-qube: | ||
| uses: ./.github/workflows/sonar-scan.yml | ||
| secrets: inherit | ||
|
|
||
| # Code Tests | ||
| code-tests: | ||
| uses: ./.github/workflows/code-tests.yml | ||
|
|
||
| # push-to-docker-hub: | ||
| docker-push: | ||
| uses: ./.github/workflows/docker-push.yml | ||
| needs: [code-quality,code-tests,sonar-qube,docker-checks,dependency-checks,secret-scanning] | ||
| secrets: inherit | ||
|
|
||
| ## ---- CD ----- | ||
| deploy: | ||
| needs: [docker-push] | ||
| uses: ./.github/workflows/deploy.yml | ||
| secrets: inherit | ||
|
|
||
| dast-scan: | ||
| needs: [deploy] | ||
| uses: ./.github/workflows/dast.yml | ||
| secrets: inherit | ||
| code-quality: | ||
| uses: ./.github/workflows/code-quality.yml | ||
|
|
||
| secret-scanning: | ||
| uses: ./.github/workflows/secret-scanning.yml | ||
|
|
||
| dependency-checks: | ||
| uses: ./.github/workflows/dependency-scan.yml | ||
|
|
||
| docker-checks: | ||
| uses: ./.github/workflows/docker-scans.yml | ||
|
|
||
| sonar-qube: | ||
| uses: ./.github/workflows/sonar-scan.yml | ||
| secrets: | ||
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
| SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} | ||
|
|
||
| code-tests: | ||
| uses: ./.github/workflows/code-tests.yml | ||
|
|
||
| docker-build-scan-push: | ||
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | ||
| needs: | ||
| - code-quality | ||
| - code-tests | ||
| - sonar-qube | ||
| - docker-checks | ||
| - dependency-checks | ||
| - secret-scanning | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| uses: ./.github/workflows/docker-push.yml | ||
| secrets: | ||
| DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,31 +1,81 @@ | ||||||||||||||
| # Goal Push the images to DockerHub | ||||||||||||||
| name: Docker Push | ||||||||||||||
|
|
||||||||||||||
| on: | ||||||||||||||
| workflow_call: | ||||||||||||||
| name: Docker Build, Scan and Push | ||||||||||||||
|
|
||||||||||||||
| on: | ||||||||||||||
| workflow_call: | ||||||||||||||
| secrets: | ||||||||||||||
| DOCKERHUB_TOKEN: | ||||||||||||||
| required: true | ||||||||||||||
| jobs: | ||||||||||||||
| frontend: | ||||||||||||||
| # Github runner | ||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||
| strategy: | ||||||||||||||
| fail-fast: false | ||||||||||||||
| matrix: | ||||||||||||||
| folders: ['backend','frontend'] | ||||||||||||||
| steps: | ||||||||||||||
| - name: Checkout Code | ||||||||||||||
| uses: actions/checkout@v7 | ||||||||||||||
|
|
||||||||||||||
| - name: Docker Setup [Login] | ||||||||||||||
| uses: docker/login-action@v4 | ||||||||||||||
| with: | ||||||||||||||
| username: ${{ vars.DOCKERHUB_USERNAME }} | ||||||||||||||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||||||||||||||
|
|
||||||||||||||
| - name: Docker Build and Push | ||||||||||||||
| uses: docker/build-push-action@v7 | ||||||||||||||
| with: | ||||||||||||||
| context: ./${{ matrix.folders}} | ||||||||||||||
| push: true | ||||||||||||||
| tags: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.folders}}:latest | ||||||||||||||
|
|
||||||||||||||
| build-scan-push: | ||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||
|
|
||||||||||||||
| strategy: | ||||||||||||||
| fail-fast: false | ||||||||||||||
| matrix: | ||||||||||||||
| service: | ||||||||||||||
| - backend | ||||||||||||||
| - frontend | ||||||||||||||
|
|
||||||||||||||
| permissions: | ||||||||||||||
| contents: read | ||||||||||||||
| id-token: write | ||||||||||||||
|
|
||||||||||||||
| steps: | ||||||||||||||
| - name: Checkout code | ||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||
|
Comment on lines
+24
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win Set This job pushes images and signs them. It does not push to Git. Prevent the 🔒️ Proposed hardening - name: Checkout code
uses: actions/checkout@v4
+ with:
+ persist-credentials: false📝 Committable suggestion
Suggested change
🧰 Tools🪛 zizmor (1.29.0)[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||
|
|
||||||||||||||
| - name: Docker Hub login | ||||||||||||||
| uses: docker/login-action@v3 | ||||||||||||||
|
Check failure on line 28 in .github/workflows/docker-push.yml
|
||||||||||||||
| with: | ||||||||||||||
| username: ${{ vars.DOCKERHUB_USERNAME }} | ||||||||||||||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||||||||||||||
|
|
||||||||||||||
| - name: Build image | ||||||||||||||
| env: | ||||||||||||||
| IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.service }}:${{ github.sha }} | ||||||||||||||
| run: | | ||||||||||||||
| docker build \ | ||||||||||||||
| -t "$IMAGE" \ | ||||||||||||||
| "./${{ matrix.service }}" | ||||||||||||||
|
|
||||||||||||||
| - name: Trivy vulnerability scan | ||||||||||||||
| uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 | ||||||||||||||
| with: | ||||||||||||||
| image-ref: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.service }}:${{ github.sha }} | ||||||||||||||
| format: table | ||||||||||||||
| exit-code: '1' | ||||||||||||||
| ignore-unfixed: true | ||||||||||||||
| vuln-type: os,library | ||||||||||||||
| severity: HIGH,CRITICAL | ||||||||||||||
|
|
||||||||||||||
| - name: Generate SBOM | ||||||||||||||
| uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 | ||||||||||||||
| with: | ||||||||||||||
| image: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.service }}:${{ github.sha }} | ||||||||||||||
| format: spdx-json | ||||||||||||||
| artifact-name: ${{ matrix.service }}-sbom.spdx.json | ||||||||||||||
| output-file: ${{ matrix.service }}-sbom.spdx.json | ||||||||||||||
| upload-artifact: true | ||||||||||||||
|
|
||||||||||||||
| - name: Push SHA-tagged image | ||||||||||||||
| env: | ||||||||||||||
| IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.service }}:${{ github.sha }} | ||||||||||||||
| run: | | ||||||||||||||
| docker push "$IMAGE" | ||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||
|
|
||||||||||||||
| - name: Install Cosign | ||||||||||||||
| uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 | ||||||||||||||
|
|
||||||||||||||
| - name: Sign image | ||||||||||||||
| env: | ||||||||||||||
| IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.service }}:${{ github.sha }} | ||||||||||||||
| run: | | ||||||||||||||
| cosign sign --yes "$IMAGE" | ||||||||||||||
|
|
||||||||||||||
| gitops-bump: | ||||||||||||||
| needs: build-scan-push | ||||||||||||||
| permissions: | ||||||||||||||
| contents: write | ||||||||||||||
| uses: ./.github/workflows/gitops-bump.yml | ||||||||||||||
| with: | ||||||||||||||
| image_tag: ${{ github.sha }} | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,44 +1,26 @@ | ||
| # Goal - Ensure the docker files and Docker images are security Tested | ||
| name: Dockerfile Security Scan | ||
|
|
||
| name: Docker Scan | ||
|
|
||
| on: | ||
| workflow_call: | ||
| on: | ||
| workflow_call: | ||
|
|
||
| jobs: | ||
| docker-file-lint-and-scan: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| folders: ['backend','frontend'] | ||
| steps: | ||
| - name: Code Checkout | ||
| uses: actions/checkout@v7 | ||
| dockerfile-security: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| - name: ${{ matrix.folders}} Dockerfile Lint | ||
| uses: hadolint/hadolint-action@v3.1.0 | ||
| with: | ||
| dockerfile: ${{ matrix.folders}}/Dockerfile | ||
|
|
||
| - name: Docker Setup [Login] | ||
| uses: docker/login-action@v4 | ||
| with: | ||
| username: ${{ vars.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| service: | ||
| - backend | ||
| - frontend | ||
|
|
||
| - name: Docker Build ${{ matrix.folders}} | ||
| run: docker build -t ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.folders }}:latest . | ||
| working-directory: ${{ matrix.folders}} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: Run Trivy vulnerability scanner | ||
| uses: aquasecurity/trivy-action@v0.36.0 | ||
| continue-on-error: true | ||
| with: | ||
| image-ref: ${{ vars.DOCKERHUB_USERNAME }}/devboard-${{ matrix.folders }}:latest | ||
| format: 'table' | ||
| exit-code: '1' | ||
| ignore-unfixed: true | ||
| vuln-type: 'os,library' | ||
| severity: 'CRITICAL' | ||
|
|
||
| - name: Dockerfile lint | ||
| uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf | ||
| with: | ||
| dockerfile: ${{ matrix.service }}/Dockerfile |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| # GitOps handoff: write the freshly-built image tag into the manifests and | ||
| # commit it back to `gitops`. ArgoCD (watching that branch) then syncs. | ||
| # | ||
| # The commit touches only k8s/ + helm/, which are NOT in the pipeline's push | ||
| # `paths:` filter, and commits made with GITHUB_TOKEN don't trigger workflows — | ||
| # so this can't cause a rebuild loop ([skip ci] is a third safety net). | ||
| name: GitOps Image Bump | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| image_tag: | ||
| required: true | ||
| type: string | ||
|
|
||
| jobs: | ||
| bump: | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
|
Comment on lines
+17
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Serialize writes to the Two release runs can check out the same Add a job-level Proposed fix jobs:
bump:
+ concurrency:
+ group: gitops-image-bump
+ cancel-in-progress: false
runs-on: ubuntu-latestAlso applies to: 54-67 🤖 Prompt for AI Agents |
||
| steps: | ||
| - name: Checkout gitops | ||
| uses: actions/checkout@v7 | ||
| with: | ||
| ref: gitops | ||
|
|
||
|
|
||
| - name: Install yq | ||
| run: | | ||
| sudo wget -qO /usr/local/bin/yq \ | ||
| https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 | ||
| sudo chmod +x /usr/local/bin/yq | ||
|
Comment on lines
+23
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workflow ---'
cat -n .github/workflows/gitops-bump.yml
printf '%s\n' '--- related workflow controls ---'
rg -n -C 3 'concurrency:|gitops|actions/checkout@|releases/latest|contents:' .github/workflows
printf '%s\n' '--- repository references ---'
rg -n 'gitops-bump|yq_linux_amd64|mikefarah/yq|actions/checkout@' .Repository: LondheShubham153/devboard Length of output: 1939 🏁 Script executed: #!/bin/bash
set -eu
cat -n .github/workflows/gitops-bump.yml
rg -n -C 3 'concurrency:|gitops|actions/checkout@|releases/latest|contents:' .github/workflows
rg -n 'gitops-bump|yq_linux_amd64|mikefarah/yq|actions/checkout@' .Repository: LondheShubham153/devboard Length of output: 1939 🌐 Web query:
💡 Result: I couldn’t find a matching indexed file for The search did confirm that Citations: 🌐 Web query:
💡 Result: GitHub official documentation recommends pinning actions to a full-length (40-character) commit SHA as a security best practice [1][2][3]. This is the only method to ensure an action is used as an immutable release, mitigating the risk of malicious code being introduced if an action's repository is compromised or a tag is moved [1][2]. Key points regarding this practice: Immutable References: Unlike tags (e.g., Citations:
🌐 Web query:
💡 Result: For the mikefarah/yq project on GitHub, checksums are provided as assets within each release to allow for verification of downloaded binaries [1][2]. To verify a specific binary like yq_linux_amd64, you should download the following files from the corresponding GitHub release page [2][3]: 1. The binary file itself (e.g., yq_linux_amd64). 2. The checksums file (named checksums). 3. The checksums_hashes_order file (which defines the order of hash algorithms in the checksums file). 4. The helper script extract-checksum.sh (recommended for reliable extraction of the specific hash) [3][4]. Verification process: You can use the provided extract-checksum.sh script to isolate the hash for your specific file and algorithm, then verify it using a standard checksum tool [3][4]. For example:./extract-checksum.sh SHA-256 yq_linux_amd64 | sha256sum -c - Alternatively, the project provides Sigstore-based keyless signing for release artifacts [5]. You can verify the checksums file bundle using the cosign tool: cosign verify-blob --bundle checksums.bundle checksums [5] It is recommended to use these official assets rather than attempting to parse the checksums file manually, as the file format and hash ordering may change [3][4]. Citations:
Pin every executable dependency. Replace 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Write image refs into manifests | ||
| env: | ||
| OWNER: ${{ vars.DOCKERHUB_USERNAME }} | ||
| TAG: ${{ inputs.image_tag }} | ||
| run: | | ||
| set -eu | ||
| # RAW manifests (if present): surgical sed on the single "image:" line, | ||
| # keeping the file's formatting/comments untouched. | ||
| for svc in backend frontend; do | ||
| f="k8s/${svc}-deployment.yml" | ||
| [ -f "$f" ] && sed -i "s|image: .*devboard-${svc}:.*|image: ${OWNER}/devboard-${svc}:${TAG}|" "$f" | ||
| done | ||
| # HELM values (if present): structured repository/tag — owner written | ||
| # too, so it can't drift from what CI pushed. | ||
| v="helm/devboard/values.yaml" | ||
| if [ -f "$v" ]; then | ||
| yq -i ".backend.image.repository = \"${OWNER}/devboard-backend\" | .backend.image.tag = \"${TAG}\"" "$v" | ||
| yq -i ".frontend.image.repository = \"${OWNER}/devboard-frontend\" | .frontend.image.tag = \"${TAG}\"" "$v" | ||
| fi | ||
|
|
||
| - name: Commit and push | ||
| env: | ||
| TAG: ${{ inputs.image_tag }} | ||
| run: | | ||
| set -eu | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| if git diff --quiet; then | ||
| echo "Manifests already at ${TAG}; nothing to commit." | ||
| exit 0 | ||
| fi | ||
| git add -A | ||
| git commit -m "ci: deploy ${TAG} [skip ci]" | ||
| git push origin HEAD:gitops | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,25 @@ | ||
| # Goal - to check whether the application code coverage doesn't have security threats/issues | ||
|
|
||
| name: Sonar Qube Scan | ||
|
|
||
| on: | ||
| workflow_call: | ||
| workflow_call: | ||
| secrets: | ||
| SONAR_TOKEN: | ||
| required: true | ||
| SONAR_HOST_URL: | ||
| required: true | ||
|
|
||
| jobs: | ||
| sonar-scanner: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Code Checkout | ||
| uses: actions/checkout@v7 | ||
| sonar-scanner: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Code Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| - name: SonarQube Scan | ||
| uses: SonarSource/sonarqube-scan-action@v8.2.0 | ||
| env: | ||
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
| SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} | ||
| - name: SonarQube Scan | ||
| uses: SonarSource/sonarqube-scan-action@713881670b6b3676cda39549040e2d88c70d582e | ||
| env: | ||
| SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
| SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| apiVersion: v2 | ||
| name: devboard | ||
| description: DevBoard - React + Go + Postgres application | ||
| type: application | ||
| version: 0.1.0 | ||
| appVersion: "1.0.0" |
Uh oh!
There was an error while loading. Please reload this page.