fix(db): populate book.Author in List and Get responses (closes #882) #1350
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 | |
| on: | |
| push: | |
| branches: [main, development] | |
| paths-ignore: | |
| - '**/*.md' | |
| - 'docs/**' | |
| - 'CHANGELOG*' | |
| - 'CONTRIBUTING*' | |
| - 'README*' | |
| - 'LICENSE*' | |
| - 'CODE_OF_CONDUCT*' | |
| - '.github/ISSUE_TEMPLATE/**' | |
| pull_request: | |
| paths-ignore: | |
| - '**/*.md' | |
| - 'docs/**' | |
| - 'CHANGELOG*' | |
| - 'CONTRIBUTING*' | |
| - 'README*' | |
| - 'LICENSE*' | |
| - 'CODE_OF_CONDUCT*' | |
| - '.github/ISSUE_TEMPLATE/**' | |
| schedule: | |
| # Weekly Monday 06:00 UTC | |
| - cron: '0 6 * * 1' | |
| permissions: | |
| contents: read | |
| actions: read | |
| concurrency: | |
| group: security-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ── Go SAST: gosec only — golangci-lint and govulncheck run in ci.yml lint ── | |
| sast-go: | |
| name: SAST – Go | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 | |
| with: | |
| go-version: "1.25.10" | |
| cache: true | |
| - name: gosec (SARIF) | |
| uses: securego/gosec@5f4eec95fa28ce5dc6cf555de8c242cb57545f01 # master | |
| with: | |
| # G402 (TLS/cookie insecure) excluded: cookie Secure flag is dynamic (auto-detected | |
| # from r.TLS and X-Forwarded-Proto, overridable via BINDERY_COOKIE_SECURE) and gosec | |
| # only accepts literal `true`. Safety is enforced by cookie config logic + docs. | |
| args: '-no-fail -fmt sarif -out gosec.sarif -exclude=G101,G402 ./...' | |
| - name: Upload gosec SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() | |
| with: | |
| sarif_file: gosec.sarif | |
| category: gosec | |
| # ── Frontend SAST: Semgrep + npm audit + ESLint security ─────────────────── | |
| sast-frontend: | |
| name: SAST – Frontend | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci --prefix web | |
| - name: npm audit | |
| run: npm audit --audit-level=high --prefix web | |
| - name: Install ESLint security tooling | |
| run: | | |
| npm install --no-save \ | |
| eslint-plugin-security \ | |
| @microsoft/eslint-formatter-sarif \ | |
| --prefix web | |
| - name: ESLint with security plugin | |
| run: | | |
| cat > /tmp/eslint-security.config.mjs << 'EOF' | |
| import security from 'eslint-plugin-security'; | |
| export default [ | |
| security.configs.recommended, | |
| { files: ['src/**/*.{ts,tsx,js,jsx}'] } | |
| ]; | |
| EOF | |
| cd web && npx eslint \ | |
| -c /tmp/eslint-security.config.mjs \ | |
| --format @microsoft/eslint-formatter-sarif \ | |
| --output-file eslint-security.sarif \ | |
| src/ || true | |
| - name: Upload ESLint SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() && hashFiles('web/eslint-security.sarif') != '' | |
| with: | |
| sarif_file: web/eslint-security.sarif | |
| category: eslint-security | |
| - name: Semgrep | |
| run: | | |
| python3 -m pip install --user semgrep | |
| semgrep scan \ | |
| --config p/react --config p/typescript --config p/xss \ | |
| --sarif --output semgrep.sarif . || true | |
| - name: Upload Semgrep SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() && hashFiles('semgrep.sarif') != '' | |
| with: | |
| sarif_file: semgrep.sarif | |
| category: semgrep-frontend | |
| # ── Secrets scan: Gitleaks ───────────────────────────────────────────────── | |
| secrets-scan: | |
| name: Secrets Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Gitleaks | |
| uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITLEAKS_CONFIG: .gitleaks.toml | |
| GITLEAKS_ENABLE_SARIF: true | |
| - name: Upload Gitleaks SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() | |
| with: | |
| sarif_file: results.sarif | |
| category: gitleaks | |
| # ── IaC scan: Hadolint + Helm lint + Checkov ────────────────────────────── | |
| iac-scan: | |
| name: IaC Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Hadolint (Dockerfile) | |
| uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf # v3.1.0 | |
| with: | |
| dockerfile: Dockerfile | |
| format: sarif | |
| output-file: hadolint.sarif | |
| no-fail: true | |
| - name: Upload Hadolint SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() | |
| with: | |
| sarif_file: hadolint.sarif | |
| category: hadolint | |
| - name: Set up Helm | |
| uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4 | |
| with: | |
| version: latest | |
| - name: Helm lint | |
| run: helm lint --strict charts/bindery | |
| - name: Checkov | |
| uses: bridgecrewio/checkov-action@de2bfaecd21d58ef232e0d2a3391c33c32c460d7 # master | |
| with: | |
| directory: . | |
| file: Dockerfile | |
| framework: dockerfile,helm,kubernetes | |
| output_format: sarif | |
| output_file_path: checkov.sarif | |
| soft_fail: true | |
| - name: Upload Checkov SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() | |
| with: | |
| sarif_file: checkov.sarif | |
| category: checkov | |
| # ── Container scan: Trivy + Grype + Syft SBOM ──────────────────────────── | |
| container-scan: | |
| name: Container Scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 | |
| - name: Build image (with layer cache) | |
| run: | | |
| docker buildx build \ | |
| --load \ | |
| --cache-from type=gha \ | |
| --cache-to type=gha,mode=max \ | |
| -t bindery:scan \ | |
| . | |
| - name: Trivy vulnerability scan (SARIF) | |
| uses: aquasecurity/trivy-action@1994662b5555670344cd84d29ed3cad4bd26f31c # master | |
| with: | |
| image-ref: bindery:scan | |
| format: sarif | |
| output: trivy.sarif | |
| severity: CRITICAL,HIGH | |
| exit-code: '1' | |
| - name: Upload Trivy SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() | |
| with: | |
| sarif_file: trivy.sarif | |
| category: trivy | |
| - name: Grype vulnerability scan (SARIF) | |
| uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0 | |
| id: grype | |
| with: | |
| image: bindery:scan | |
| output-format: sarif | |
| output-file: grype.sarif | |
| fail-build: true | |
| - name: Upload Grype SARIF | |
| uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 | |
| if: always() && hashFiles('grype.sarif') != '' | |
| with: | |
| sarif_file: grype.sarif | |
| category: grype | |
| - name: Syft SBOM – SPDX | |
| uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0 | |
| with: | |
| image: bindery:scan | |
| format: spdx-json | |
| output-file: sbom.spdx.json | |
| artifact-name: sbom.spdx.json | |
| upload-artifact: true | |
| upload-artifact-retention: 90 | |
| - name: Syft SBOM – CycloneDX | |
| uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0 | |
| with: | |
| image: bindery:scan | |
| format: cyclonedx-json | |
| output-file: sbom.cyclonedx.json | |
| artifact-name: sbom.cyclonedx.json | |
| upload-artifact: true | |
| upload-artifact-retention: 90 | |
| # ── DAST: ZAP baseline (passive) ────────────────────────────────────────── | |
| dast-api: | |
| name: DAST – ZAP Baseline | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 | |
| with: | |
| go-version: "1.25.10" | |
| cache: true | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: "22" | |
| cache: npm | |
| cache-dependency-path: web/package-lock.json | |
| - name: Build frontend | |
| run: npm ci --prefix web && npm run build --prefix web | |
| - name: Build Bindery binary | |
| run: go build -o bindery-dast ./cmd/bindery | |
| - name: Start Bindery | |
| run: | | |
| BINDERY_DB_PATH=/tmp/bindery-dast.db \ | |
| BINDERY_API_KEY=zap-test-key \ | |
| ./bindery-dast & | |
| # Wait for the service to be ready | |
| for i in $(seq 1 30); do | |
| if curl -sf http://localhost:8787/api/v1/health; then | |
| echo "Bindery is up" | |
| break | |
| fi | |
| sleep 2 | |
| done | |
| - name: ZAP Baseline Scan | |
| run: | | |
| mkdir -p zap-out | |
| docker run --rm --network=host \ | |
| -v "$PWD/zap-out:/zap/wrk" \ | |
| zaproxy/zap-stable \ | |
| zap-baseline.py \ | |
| -t http://localhost:8787 \ | |
| -J zap-report.json \ | |
| -r zap-report.html \ | |
| -I || true | |
| - name: Upload ZAP report artifact | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| if: always() | |
| with: | |
| name: zap-baseline-report | |
| path: zap-out/ | |
| retention-days: 30 | |
| # ── Helm unit tests ──────────────────────────────────────────────────────── | |
| # Stream C will add the test fixtures. continue-on-error until they land. | |
| policy-test: | |
| name: Helm Policy Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: helm-unittest (docker) | |
| run: | | |
| docker run --rm -v "$PWD:/apps" \ | |
| helmunittest/helm-unittest:latest \ | |
| charts/bindery | |
| continue-on-error: true | |
| # ── Aggregate severity summary ───────────────────────────────────────────── | |
| summary: | |
| name: Security Summary | |
| runs-on: ubuntu-latest | |
| needs: | |
| - sast-go | |
| - sast-frontend | |
| - secrets-scan | |
| - iac-scan | |
| - container-scan | |
| - dast-api | |
| - policy-test | |
| if: always() | |
| steps: | |
| - name: Write severity summary | |
| run: | | |
| cat >> "$GITHUB_STEP_SUMMARY" << 'EOF' | |
| ## Security Scan Summary | |
| | Job | Status | | |
| |-----|--------| | |
| | SAST – Go (gosec) | ${{ needs.sast-go.result }} | | |
| | SAST – Frontend (Semgrep, npm audit, ESLint) | ${{ needs.sast-frontend.result }} | | |
| | Secrets Scan (Gitleaks) | ${{ needs.secrets-scan.result }} | | |
| | IaC Scan (Hadolint, Helm lint, Checkov) | ${{ needs.iac-scan.result }} | | |
| | Container Scan (Trivy, Grype, Syft SBOM) | ${{ needs.container-scan.result }} | | |
| | DAST – ZAP Baseline | ${{ needs.dast-api.result }} | | |
| | Helm Policy Tests | ${{ needs.policy-test.result }} | | |
| > Full findings are visible in the **Security** tab → Code scanning alerts. | |
| > SBOMs are attached as workflow artifacts (90-day retention). | |
| EOF |