fix(ci): remove duplicate trufflehog no-update flag #23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: DevSecOps Pipeline | |
| on: | |
| push: | |
| branches: [ "main", "master" ] | |
| pull_request: | |
| branches: [ "main", "master" ] | |
| schedule: | |
| - cron: '0 0 * * 0' # Weekly baseline scan | |
| workflow_dispatch: | |
| permissions: | |
| security-events: write | |
| contents: read | |
| packages: write # For pushing images/signatures | |
| id-token: write # For Cosign OIDC (optional) | |
| pull-requests: write # For posting comments | |
| jobs: | |
| secret-scan: | |
| name: Secret Scan (TruffleHog) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: TruffleHog (Diff Mode) | |
| if: github.event_name == 'push' || github.event_name == 'pull_request' | |
| uses: trufflesecurity/trufflehog@abecab0d8fb9fb3e79366abc3909825488e9bb40 # v3.82.12 | |
| with: | |
| extra_args: --only-verified | |
| - name: TruffleHog (Baseline Mode) | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| uses: trufflesecurity/trufflehog@abecab0d8fb9fb3e79366abc3909825488e9bb40 # v3.82.12 | |
| with: | |
| extra_args: --only-verified --since-commit HEAD | |
| sast-scan: | |
| name: SAST (Semgrep) | |
| runs-on: ubuntu-latest | |
| if: github.actor != 'dependabot[bot]' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Semgrep Scan | |
| run: | | |
| docker run --rm -v $(pwd):/src semgrep/semgrep semgrep scan --config auto --sarif --output /src/semgrep.sarif | |
| continue-on-error: true | |
| - name: Upload SARIF | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| if: always() | |
| with: | |
| name: semgrep.sarif | |
| path: semgrep.sarif | |
| - name: Upload Security SARIF (CodeQL) | |
| uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 | |
| if: always() | |
| continue-on-error: true | |
| with: | |
| sarif_file: semgrep.sarif | |
| sca-scan: | |
| name: SCA (Snyk) | |
| runs-on: ubuntu-latest | |
| env: | |
| SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 | |
| with: | |
| node-version: '16' | |
| - name: Install dependencies | |
| run: | | |
| if [ -f package.json ]; then | |
| npm ci || npm install || true | |
| else | |
| echo "No package.json at repository root; skipping npm install." | |
| fi | |
| - name: Install Snyk CLI | |
| if: env.SNYK_TOKEN != '' | |
| run: npm install -g snyk | |
| - name: Snyk Scan | |
| if: env.SNYK_TOKEN != '' | |
| env: | |
| SNYK_TOKEN: ${{ env.SNYK_TOKEN }} | |
| run: snyk test --all-projects --severity-threshold=high --sarif-file-output=snyk.sarif || true | |
| - name: Upload SARIF | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| if: always() && env.SNYK_TOKEN != '' | |
| with: | |
| name: snyk.sarif | |
| path: snyk.sarif | |
| - name: Upload Security SARIF (CodeQL) | |
| uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 | |
| if: always() && env.SNYK_TOKEN != '' | |
| continue-on-error: true | |
| with: | |
| sarif_file: snyk.sarif | |
| - name: Snyk Gatekeeper | |
| if: env.SNYK_TOKEN != '' | |
| continue-on-error: true | |
| env: | |
| SNYK_TOKEN: ${{ env.SNYK_TOKEN }} | |
| run: snyk test --all-projects --severity-threshold=high | |
| - name: Skip Snyk (No Token) | |
| if: env.SNYK_TOKEN == '' | |
| run: echo "SNYK_TOKEN not set. Skipping SCA scan." | |
| iac-scan: | |
| name: IaC Scan (Checkov) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Install Checkov | |
| run: python3 -m pip install --upgrade pip checkov | |
| - name: Checkov Scan | |
| run: checkov -d ./terraform --quiet --compact --soft-fail --output sarif > checkov.sarif || true | |
| - name: Upload SARIF | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| if: always() | |
| with: | |
| name: checkov.sarif | |
| path: checkov.sarif | |
| - name: Upload Security SARIF (CodeQL) | |
| uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 | |
| if: always() | |
| continue-on-error: true | |
| with: | |
| sarif_file: checkov.sarif | |
| cost-estimation: | |
| name: FinOps (Infracost) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| env: | |
| INFRACOST_API_KEY: ${{ secrets.INFRACOST_API_KEY }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Install Infracost | |
| if: env.INFRACOST_API_KEY != '' | |
| run: | | |
| curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh | |
| echo "$HOME/.infracost/bin" >> "$GITHUB_PATH" | |
| - name: Infracost Breakdown | |
| if: env.INFRACOST_API_KEY != '' | |
| run: | | |
| infracost breakdown --path ./terraform --format json --out-file infracost-usage.json | |
| - name: Post Infracost Comment | |
| if: github.event_name == 'pull_request' && env.INFRACOST_API_KEY != '' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| infracost comment github --path infracost-usage.json --repo $GITHUB_REPOSITORY --pull-request ${{ github.event.pull_request.number }} --behavior update | |
| - name: Skip Infracost (No API Key) | |
| if: env.INFRACOST_API_KEY == '' | |
| run: echo "INFRACOST_API_KEY not set. Skipping cost estimation." | |
| container-build-sign: | |
| name: Build & Sign (Trivy + Cosign) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Build Docker Image | |
| run: docker build -t my-app:${{ github.sha }} . | |
| # 1. Scan (Trivy) | |
| - name: Trivy Image Scan (SARIF) | |
| uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # 0.24.0 | |
| with: | |
| image-ref: 'my-app:${{ github.sha }}' | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| ignore-unfixed: true | |
| vuln-type: 'os,library' | |
| - name: Upload SARIF | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| if: always() | |
| with: | |
| name: trivy-results.sarif | |
| path: trivy-results.sarif | |
| - name: Upload Security SARIF (CodeQL) | |
| uses: github/codeql-action/upload-sarif@b611370bb5703a7efb587f9d136a52ea24c5c38c # v3.25.11 | |
| if: always() | |
| continue-on-error: true | |
| with: | |
| sarif_file: trivy-results.sarif | |
| - name: Trivy Gatekeeper | |
| uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # 0.24.0 | |
| continue-on-error: true | |
| with: | |
| image-ref: 'my-app:${{ github.sha }}' | |
| exit-code: '1' | |
| ignore-unfixed: true | |
| severity: 'CRITICAL,HIGH' | |
| # 2. Sign (Cosign) - mock step for demo | |
| - name: Sign Image | |
| if: github.event_name != 'pull_request' | |
| env: | |
| COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }} | |
| COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }} | |
| run: | | |
| if [[ -z "$COSIGN_PRIVATE_KEY" ]]; then | |
| echo "Skipping signing: COSIGN_PRIVATE_KEY not set." | |
| else | |
| echo "Cosign key detected. Mock signing for demo." | |
| echo "signature" > cosign.sig | |
| fi | |
| - name: Generate SBOM (SPDX) | |
| uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # 0.24.0 | |
| with: | |
| image-ref: 'my-app:${{ github.sha }}' | |
| format: 'spdx-json' | |
| output: 'sbom.spdx.json' | |
| - name: Upload SBOM | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| with: | |
| name: sbom | |
| path: sbom.spdx.json | |
| dast-scan: | |
| name: Runtime Security (DAST) | |
| runs-on: ubuntu-latest | |
| needs: [container-build-sign] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Build & Run Container | |
| run: | | |
| docker build -t my-app:${{ github.sha }} . | |
| docker run -d -p 3000:3000 --name test-app my-app:${{ github.sha }} | |
| sleep 5 | |
| - name: OWASP ZAP Baseline Scan | |
| uses: zaproxy/action-baseline@290a611c039d91f868c6e26487e0766324263720 # v0.14.0 | |
| continue-on-error: true | |
| with: | |
| target: 'http://localhost:3000' | |
| fail_action: false | |
| compliance-audit: | |
| name: Generate Compliance Artifacts | |
| runs-on: ubuntu-latest | |
| needs: [secret-scan, sast-scan, sca-scan, iac-scan, container-build-sign, dast-scan] | |
| if: always() | |
| outputs: | |
| hashes: ${{ steps.hash.outputs.hashes }} | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Download All Artifacts | |
| uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
| with: | |
| path: results | |
| merge-multiple: true | |
| - name: Generate Source SBOM | |
| run: | | |
| mkdir -p results | |
| curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin | |
| /usr/local/bin/syft dir:. -o spdx-json > results/sbom-source.spdx.json | |
| /usr/local/bin/syft dir:. -o cyclonedx-json > results/sbom-source.cdx.json | |
| - name: Upload SBOM Artifacts | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| with: | |
| name: sbom-reports | |
| path: results/sbom-* | |
| - name: Generate Audit Record | |
| run: | | |
| echo "{" > results/deployment-audit.json | |
| echo " \"timestamp\": \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"," >> results/deployment-audit.json | |
| echo " \"repository\": \"$GITHUB_REPOSITORY\"," >> results/deployment-audit.json | |
| echo " \"commit_sha\": \"$GITHUB_SHA\"," >> results/deployment-audit.json | |
| echo " \"actor\": \"$GITHUB_ACTOR\"," >> results/deployment-audit.json | |
| echo " \"workflow_run_id\": \"$GITHUB_RUN_ID\"," >> results/deployment-audit.json | |
| echo "}" >> results/deployment-audit.json | |
| - name: Upload Audit Artifact | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| with: | |
| name: deployment-audit | |
| path: results/deployment-audit.json | |
| - name: Run Policy Check | |
| run: ./scripts/fortressci-policy-check.sh .security/policy.yml results/ | |
| - name: Generate Compliance Report | |
| run: python3 scripts/generate-compliance-report.py results/ .security/compliance-mappings.yml | |
| - name: AI Triage | |
| if: always() && env.ANTHROPIC_API_KEY != '' | |
| run: python3 scripts/ai-triage.py --results-dir results/ --config .fortressci.yml | |
| - name: Generate Security Badge | |
| if: always() | |
| run: python3 scripts/generate-badge.py results/ | |
| - name: Build Attack Graph | |
| if: always() | |
| run: python3 scripts/build-attack-graph.py results/ | |
| - name: Generate Hashes | |
| id: hash | |
| run: | | |
| cd results | |
| echo "hashes=$(sha256sum sbom-source.spdx.json sbom-source.cdx.json deployment-audit.json | base64 -w0)" >> "$GITHUB_OUTPUT" | |
| provenance: | |
| name: Provenance Summary | |
| runs-on: ubuntu-latest | |
| needs: [compliance-audit] | |
| if: needs.compliance-audit.result == 'success' | |
| steps: | |
| - name: Generate provenance summary | |
| run: | | |
| cat > provenance.json <<EOF | |
| { | |
| "workflow_run_id": "${GITHUB_RUN_ID}", | |
| "repository": "${GITHUB_REPOSITORY}", | |
| "commit_sha": "${GITHUB_SHA}", | |
| "generated_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")", | |
| "compliance_hashes_b64": "${{ needs.compliance-audit.outputs.hashes }}" | |
| } | |
| EOF | |
| - name: Upload Provenance Artifact | |
| uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 | |
| with: | |
| name: provenance | |
| path: provenance.json | |
| pr-feedback: | |
| name: Developer Feedback (PR Comments) | |
| runs-on: ubuntu-latest | |
| needs: [sast-scan, sca-scan, iac-scan, container-build-sign] | |
| if: always() && github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Download All Artifacts | |
| uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
| with: | |
| merge-multiple: true | |
| - name: Post Summary to PR | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
| with: | |
| script: | | |
| const script = require('./.github/scripts/post_summary.js') | |
| await script({github, context}) | |
| auto-remediation: | |
| name: Auto-Remediation (PR) | |
| runs-on: ubuntu-latest | |
| needs: [sast-scan, sca-scan, iac-scan] | |
| if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Run Auto-Fix | |
| run: ./scripts/auto-fix.sh | |
| - name: Create Pull Request | |
| uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84617901 # v6.0.1 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| commit-message: "fix: auto-remediation of security findings" | |
| title: "🏰 FortressCI Auto-Remediation" | |
| body: | | |
| This is an automated pull request from FortressCI to fix security findings. | |
| Scanners: Snyk, Checkov | |
| branch: fortressci/auto-remediation | |
| base: main | |
| labels: | | |
| security | |
| automated |