ci(deps): bump docker/build-push-action from 7.2.0 to 7.3.0 #131
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: Security Scan | |
| # Layered scanning stack (mirrors the house pattern from lawgraphlm/voicetree, | |
| # adapted to GitHub Actions + SHA-pinned actions + SARIF code-scanning): | |
| # - Secrets: gitleaks (BLOCKING, introduced commits) + TruffleHog (verified) | |
| # - SAST: Semgrep (OWASP/Node/TS) -> SARIF | |
| # - SCA + IaC: Trivy fs (vuln,secret,config) -> SARIF | |
| # - Container: Trivy image scan of the built Docker image -> SARIF | |
| # - Runtime: container smoke (boots http transport under the hardened | |
| # runtime posture and probes /health) -- BLOCKING | |
| # - CI lint: actionlint (BLOCKING) + hadolint | |
| # | |
| # Gating policy: secrets + workflow lint + container smoke block; SAST/SCA/image | |
| # scans are report-only (upload to the Security tab) until the baseline is clean, | |
| # then tighten to fail on HIGH/CRITICAL. | |
| # | |
| # Scanners are installed as pinned binaries (no unpinned marketplace actions); | |
| # upload-sarif is the one action, SHA-pinned. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| schedule: | |
| - cron: "17 3 * * 1" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| secret-scan: | |
| name: Secret scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install gitleaks | |
| run: | | |
| set -euo pipefail | |
| VERSION=8.30.1 | |
| curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${VERSION}/gitleaks_${VERSION}_linux_x64.tar.gz" \ | |
| | tar -xz -C /tmp gitleaks | |
| sudo install /tmp/gitleaks /usr/local/bin/gitleaks | |
| gitleaks version | |
| - name: Determine scan range | |
| id: range | |
| env: | |
| EVENT: ${{ github.event_name }} | |
| PR_BASE: ${{ github.event.pull_request.base.sha }} | |
| PR_HEAD: ${{ github.event.pull_request.head.sha }} | |
| BEFORE: ${{ github.event.before }} | |
| SHA: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$EVENT" = "pull_request" ]; then | |
| echo "log_opts=${PR_BASE}..${PR_HEAD}" >> "$GITHUB_OUTPUT" | |
| elif [ -z "${BEFORE:-}" ] || [ "$BEFORE" = "0000000000000000000000000000000000000000" ]; then | |
| echo "log_opts=${SHA}~1..${SHA}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "log_opts=${BEFORE}..${SHA}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Scan introduced commits for secrets (blocking) | |
| env: | |
| LOG_OPTS: ${{ steps.range.outputs.log_opts }} | |
| run: | | |
| set -euo pipefail | |
| gitleaks git . \ | |
| --redact --no-banner --exit-code 1 \ | |
| --config .gitleaks.toml \ | |
| --log-opts="$LOG_OPTS" | |
| - name: Install TruffleHog | |
| run: | | |
| set -euo pipefail | |
| VERSION=3.95.5 | |
| curl -fsSL "https://github.com/trufflesecurity/trufflehog/releases/download/v${VERSION}/trufflehog_${VERSION}_linux_amd64.tar.gz" \ | |
| | tar -xz -C /tmp trufflehog | |
| sudo install /tmp/trufflehog /usr/local/bin/trufflehog | |
| trufflehog --version | |
| - name: TruffleHog verified secrets (non-blocking) | |
| continue-on-error: true | |
| run: | | |
| set -euo pipefail | |
| trufflehog filesystem . --only-verified --fail | |
| sast: | |
| name: SAST (Semgrep) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Run Semgrep | |
| run: | | |
| set -euo pipefail | |
| pip install --quiet semgrep==1.166.0 | |
| # Report-only: emit SARIF, never fail the job (findings land in the | |
| # Security tab). Drop the trailing '|| true' and add --error to block. | |
| semgrep scan \ | |
| --sarif --output semgrep.sarif \ | |
| --config p/security-audit \ | |
| --config p/secrets \ | |
| --config p/owasp-top-10 \ | |
| --config p/xss \ | |
| --config p/nodejs \ | |
| --config p/typescript \ | |
| --exclude dist --exclude node_modules --exclude 'src/test' \ | |
| || true | |
| - name: Upload Semgrep SARIF | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 | |
| with: | |
| sarif_file: semgrep.sarif | |
| category: semgrep | |
| sca: | |
| name: SCA + IaC (Trivy fs) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Install Trivy | |
| run: | | |
| set -euo pipefail | |
| VERSION=0.71.0 | |
| curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz" \ | |
| | tar -xz -C /tmp trivy | |
| sudo install /tmp/trivy /usr/local/bin/trivy | |
| trivy --version | |
| - name: Trivy filesystem scan (vuln, secret, config) -> SARIF | |
| run: | | |
| set -euo pipefail | |
| trivy fs \ | |
| --scanners vuln,secret,config \ | |
| --severity CRITICAL,HIGH,MEDIUM \ | |
| --format sarif --output trivy-fs.sarif \ | |
| --exit-code 0 \ | |
| . | |
| - name: Upload Trivy fs SARIF | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 | |
| with: | |
| sarif_file: trivy-fs.sarif | |
| category: trivy-fs | |
| image-scan: | |
| name: Container image scan (Trivy) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Build image | |
| run: docker build -t jurisd:scan . | |
| - name: Install Trivy | |
| run: | | |
| set -euo pipefail | |
| VERSION=0.71.0 | |
| curl -fsSL "https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz" \ | |
| | tar -xz -C /tmp trivy | |
| sudo install /tmp/trivy /usr/local/bin/trivy | |
| - name: Trivy image scan -> SARIF | |
| run: | | |
| set -euo pipefail | |
| trivy image \ | |
| --scanners vuln,secret \ | |
| --severity CRITICAL,HIGH \ | |
| --ignore-unfixed \ | |
| --format sarif --output trivy-image.sarif \ | |
| --exit-code 0 \ | |
| jurisd:scan | |
| - name: Upload Trivy image SARIF | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 | |
| with: | |
| sarif_file: trivy-image.sarif | |
| category: trivy-image | |
| container-smoke: | |
| name: Container smoke (/health) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Build image | |
| run: docker build -t jurisd:smoke . | |
| - name: Run container under the hardened runtime posture | |
| run: | | |
| set -euo pipefail | |
| # Mirrors the k8s securityContext (read-only rootfs, tmpfs /tmp + /data, | |
| # all caps dropped, no privilege escalation) so the smoke also proves | |
| # the image runs under the deployment's M4 hardening. | |
| docker run -d --name jurisd-smoke \ | |
| -e MCP_TRANSPORT=http \ | |
| -p 3000:3000 \ | |
| --read-only --tmpfs /tmp --tmpfs /data \ | |
| --cap-drop ALL --security-opt no-new-privileges \ | |
| jurisd:smoke | |
| - name: Wait for /health | |
| run: | | |
| set -euo pipefail | |
| for i in $(seq 1 30); do | |
| if curl -fsS http://localhost:3000/health >/dev/null 2>&1; then | |
| echo "container healthy after ${i}s" | |
| exit 0 | |
| fi | |
| sleep 1 | |
| done | |
| echo "::error::container did not become healthy within 30s" | |
| docker logs jurisd-smoke || true | |
| exit 1 | |
| - name: Teardown | |
| if: always() | |
| run: docker rm -f jurisd-smoke || true | |
| workflow-lint: | |
| name: Workflow + Dockerfile lint | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: actionlint (blocking) | |
| env: | |
| # actionlint runs shellcheck over run: blocks. Block on real issues | |
| # (warning/error) but not style/info nits like SC2129. | |
| SHELLCHECK_OPTS: "--severity=warning" | |
| run: | | |
| set -euo pipefail | |
| VERSION=1.7.12 | |
| curl -fsSL "https://github.com/rhysd/actionlint/releases/download/v${VERSION}/actionlint_${VERSION}_linux_amd64.tar.gz" \ | |
| | tar -xz -C /tmp actionlint | |
| sudo install /tmp/actionlint /usr/local/bin/actionlint | |
| actionlint -color | |
| - name: hadolint Dockerfile (non-blocking) | |
| continue-on-error: true | |
| run: | | |
| set -euo pipefail | |
| VERSION=2.14.0 | |
| curl -fsSL "https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64" \ | |
| -o /tmp/hadolint | |
| sudo install /tmp/hadolint /usr/local/bin/hadolint | |
| hadolint Dockerfile |