fix(ci): repair security pipeline and comprehensive tests #36
Workflow file for this run
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 Pipeline | |
| # Unified security gate: SAST, SCA, secret scanning, IaC scanning, and SBOM. | |
| # Runs on every PR and nightly on main. Secret scanning blocks the merge gate. | |
| # SAST and SCA run in report-only mode (upload SARIF for visibility). | |
| # See docs/SECURITY_PIPELINE.md for policy, baselines, and runbooks. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| schedule: | |
| - cron: "0 3 * * *" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| security-events: write | |
| actions: read | |
| concurrency: | |
| group: security-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| # --------------------------------------------------------------- | |
| # Secret scanning — gitleaks CLI (no license required for org repos) | |
| # --------------------------------------------------------------- | |
| secret-scan: | |
| name: Secret Scan (gitleaks) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 0 } | |
| - name: Install gitleaks | |
| run: | | |
| GITLEAKS_VERSION="8.21.2" | |
| curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz | |
| tar -xzf gitleaks.tar.gz gitleaks | |
| chmod +x gitleaks | |
| sudo mv gitleaks /usr/local/bin/ | |
| gitleaks version | |
| - name: Run gitleaks scan | |
| run: | | |
| gitleaks detect \ | |
| --config .github/security/gitleaks.toml \ | |
| --no-git \ | |
| --verbose \ | |
| --redact \ | |
| --report-format json \ | |
| --report-path gitleaks-report.json || true | |
| if [ -f gitleaks-report.json ]; then | |
| CONTENT=$(cat gitleaks-report.json | tr -d '[:space:]') | |
| if [ "$CONTENT" != "[]" ] && [ "$CONTENT" != "null" ] && [ -n "$CONTENT" ]; then | |
| echo "::error::Secrets detected by gitleaks. See report for details." | |
| cat gitleaks-report.json | |
| exit 1 | |
| fi | |
| fi | |
| echo "✅ No secrets detected" | |
| # --------------------------------------------------------------- | |
| # SAST — Semgrep CLI (report-only mode) | |
| # --------------------------------------------------------------- | |
| sast: | |
| name: SAST (semgrep) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install semgrep | |
| run: | | |
| python3 -m pip install --user semgrep==1.85.0 | |
| semgrep --version | |
| - name: Semgrep scan | |
| run: | | |
| semgrep scan \ | |
| --config p/typescript \ | |
| --config p/javascript \ | |
| --config p/owasp-top-ten \ | |
| --config p/react \ | |
| --config p/nodejs \ | |
| --config p/docker \ | |
| --config p/sql-injection \ | |
| --config p/xss \ | |
| --sarif --output semgrep.sarif \ | |
| || true | |
| echo "✅ Semgrep scan completed (report-only mode)" | |
| - name: Upload Semgrep SARIF | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: semgrep.sarif | |
| # --------------------------------------------------------------- | |
| # SCA + IaC — Trivy (report-only mode, upload SARIF) | |
| # --------------------------------------------------------------- | |
| sca-and-iac: | |
| name: SCA + IaC (trivy) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Trivy FS (dependency vulnerabilities) | |
| uses: aquasecurity/trivy-action@v0.36.0 | |
| with: | |
| scan-type: fs | |
| scan-ref: . | |
| severity: HIGH,CRITICAL | |
| exit-code: "0" | |
| ignore-unfixed: true | |
| format: sarif | |
| output: trivy-fs.sarif | |
| - name: Trivy config (IaC misconfigs) | |
| uses: aquasecurity/trivy-action@v0.36.0 | |
| with: | |
| scan-type: config | |
| scan-ref: . | |
| severity: HIGH,CRITICAL | |
| exit-code: "0" | |
| format: sarif | |
| output: trivy-config.sarif | |
| - name: Upload Trivy SARIF | |
| if: always() | |
| uses: github/codeql-action/upload-sarif@v3 | |
| with: | |
| sarif_file: trivy-fs.sarif | |
| # --------------------------------------------------------------- | |
| # SBOM — CycloneDX via Syft | |
| # --------------------------------------------------------------- | |
| sbom: | |
| name: SBOM (syft) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Generate CycloneDX SBOM | |
| uses: anchore/sbom-action@v0 | |
| with: | |
| format: cyclonedx-json | |
| output-file: sbom.cyclonedx.json | |
| upload-artifact: true | |
| upload-artifact-name: sbom.cyclonedx.json | |
| - name: Upload SBOM artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sbom-cyclonedx | |
| path: sbom.cyclonedx.json | |
| retention-days: 90 | |
| # --------------------------------------------------------------- | |
| # Aggregate security report (digest) — non-blocking, always runs | |
| # --------------------------------------------------------------- | |
| security-report: | |
| name: Security Report Digest | |
| runs-on: ubuntu-latest | |
| needs: [secret-scan, sast, sca-and-iac, sbom] | |
| if: always() | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: { node-version: "20" } | |
| - name: Install | |
| run: npm ci | |
| working-directory: ./security-tests | |
| - name: Generate report | |
| run: npm run report:security | |
| working-directory: ./security-tests | |
| if: always() | |
| - name: Upload report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: security-report-digest | |
| path: security-tests/reports/ | |
| retention-days: 30 |