From 807afba45a92c96e353dc70522cbf1319a561659 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:23:27 +0200 Subject: [PATCH 1/8] ci(security): add Dependabot config (npm + actions + docker) --- .github/dependabot.yml | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..93176183 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,44 @@ +# Dependabot keeps dependencies and CI actions patched. Three ecosystems: +# - npm → the pnpm workspace (Dependabot reads pnpm-lock.yaml v9) +# - github-actions → action version bumps (feeds the SHA-pin comments) +# - docker → the Dockerfile base image (FROM node:20-slim) +# +# NOTE (intentional): there is NO docker entry for docker-compose.yml. It sits +# at the same "/" directory (a second docker entry would collide on +# ecosystem+directory), and Dependabot's docker ecosystem parses Dockerfiles, +# not `image:` refs in compose. The pinned caddy / livekit-server compose images +# are updated MANUALLY — see the maintainer checklist in +# docs/systems/security-scanning.md. +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 10 + groups: + # One grouped PR for routine minor/patch bumps to cut PR noise. + npm-minor-patch: + update-types: + - minor + - patch + ignore: + # uiohook-napi is pinned by an exact-version pnpm patch + # (patches/uiohook-napi@1.5.5.patch). A bump makes the patch path stop + # matching, breaking `pnpm install --frozen-lockfile` in CI and both + # Docker stages until the patch is regenerated. Bump it by hand. + - dependency-name: uiohook-napi + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + github-actions: + patterns: + - "*" + + - package-ecosystem: docker + directory: / + schedule: + interval: weekly From 74ae929ab4136d99c0e7d75a30048b025c7b81e2 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:25:26 +0200 Subject: [PATCH 2/8] ci(security): add report-only security scan workflow (gitleaks, OSV, Trivy) --- .github/workflows/security.yml | 123 +++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 .github/workflows/security.yml diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 00000000..1596d3a9 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,123 @@ +name: Security + +# Report-only in this plan: every scanner is non-blocking and uploads SARIF to +# the Security tab. Enforcement (fail on fixable HIGH/CRITICAL, block on secrets) +# is flipped on in Plan E after the remediation pass. + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: '32 5 * * 1' # weekly Monday 05:32 UTC + +permissions: + contents: read + +concurrency: + group: security-${{ github.ref }} + cancel-in-progress: true + +jobs: + gitleaks: + name: Secret scan (gitleaks) + runs-on: ubuntu-latest + steps: + - name: Harden the runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout (full history) + uses: actions/checkout@v5 + with: + fetch-depth: 0 # gitleaks scans the whole git history, not just the diff + - name: Run gitleaks + uses: gitleaks/gitleaks-action@v2 + continue-on-error: true # report-only; enforcement flipped on in Plan E + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + osv-scanner: + name: Dependency scan (OSV-Scanner) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write # upload SARIF to code scanning + steps: + - name: Harden the runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@v5 + - name: Run OSV-Scanner + uses: google/osv-scanner-action@v2 + continue-on-error: true # report-only; enforcement flipped on in Plan E + with: + scan-args: |- + --lockfile=./pnpm-lock.yaml + --format=sarif + --output=osv-results.sarif + - name: Upload OSV SARIF + if: always() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: osv-results.sarif + category: osv-scanner + + trivy-config: + name: IaC/config scan (Trivy) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Harden the runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@v5 + - name: Trivy config scan (Dockerfile + docker-compose) + uses: aquasecurity/trivy-action@0.28.0 + continue-on-error: true # report-only; enforcement flipped on in Plan E + with: + scan-type: config + scan-ref: . + format: sarif + output: trivy-config.sarif + - name: Upload Trivy config SARIF + if: always() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-config.sarif + category: trivy-config + + trivy-license: + name: License compliance scan (Trivy) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Harden the runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@v5 + - name: Trivy license scan + uses: aquasecurity/trivy-action@0.28.0 + continue-on-error: true # report-only; enforcement flipped on in Plan E + with: + scan-type: fs + scan-ref: . + scanners: license + format: sarif + output: trivy-license.sarif + - name: Upload Trivy license SARIF + if: always() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-license.sarif + category: trivy-license From 3f75ff6e3682e9aaa53e16f888902dd6d8709e4b Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:27:35 +0200 Subject: [PATCH 3/8] ci(security): add CodeQL SAST workflow (javascript-typescript) --- .github/workflows/codeql.yml | 48 ++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..ccb1f0f6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,48 @@ +name: CodeQL + +# Static application security testing for all TS/JS. Uses build-mode: none — no +# compile needed, which sidesteps the monorepo/native-module build entirely. +# Default (code-scanning) query suite; security-extended is deferred (triage tax). +# CodeQL uploads alerts to the Security tab but does NOT fail the PR by itself — +# blocking is a repo setting (code-scanning merge protection), documented in the +# maintainer checklist in docs/systems/security-scanning.md. + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '27 3 * * 1' # weekly Monday 03:27 UTC + +permissions: + contents: read + +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (javascript-typescript) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write # upload SARIF to code scanning + actions: read + steps: + - name: Harden the runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@v5 + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: javascript-typescript + build-mode: none + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:javascript-typescript" From 21d783e25787e634b92c01b28cd9ecdc495bce36 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:29:11 +0200 Subject: [PATCH 4/8] ci(security): add OpenSSF Scorecard workflow --- .github/workflows/scorecard.yml | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/scorecard.yml diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000..e0981ff1 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,48 @@ +name: OpenSSF Scorecard + +# Scores the repo's security posture (branch protection, pinned deps, token +# permissions, etc.) and publishes to the OpenSSF public API so a badge can be +# shown (badge is added in Plan E). REQUIRES the canonical repo to be PUBLIC — +# see the maintainer checklist in docs/systems/security-scanning.md. + +on: + branch_protection_rule: + schedule: + - cron: '18 4 * * 2' # weekly Tuesday 04:18 UTC + push: + branches: [main] + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + security-events: write # upload SARIF + id-token: write # publish_results OIDC attestation + steps: + - name: Harden the runner + uses: step-security/harden-runner@v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@v5 + with: + persist-credentials: false + - name: Run Scorecard + uses: ossf/scorecard-action@v2 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + - name: Upload SARIF to code scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif From 4758ca46faaca5a6409a15f82b30e3e837bc43a2 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:32:48 +0200 Subject: [PATCH 5/8] ci(security): SHA-pin all actions and add harden-runner (audit) --- .github/workflows/ci.yml | 11 +++++++--- .github/workflows/cla.yml | 2 +- .github/workflows/codeql.yml | 8 ++++---- .github/workflows/deploy-pages.yml | 8 ++++---- .github/workflows/docker-publish.yml | 12 +++++------ .github/workflows/release.yml | 12 ++++++++--- .github/workflows/scorecard.yml | 10 +++++----- .github/workflows/security.yml | 30 ++++++++++++++-------------- 8 files changed, 52 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6683dad..27f54f75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,11 +26,16 @@ jobs: runs-on: ubuntu-latest steps: + - name: Harden the runner + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Setup pnpm - uses: pnpm/action-setup@v5 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 with: version: 10.34.3 @@ -39,7 +44,7 @@ jobs: # install below pulls better-sqlite3's prebuilt binary for the correct ABI, # which is what makes the server suite runnable in CI. - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: 20 cache: pnpm diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index d17158e2..132e8b5b 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -29,7 +29,7 @@ jobs: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' - uses: contributor-assistant/github-action@v2.6.1 + uses: contributor-assistant/github-action@ca4a40a7d1004f18d9960b404b97e5f30a505a08 # v2.6.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ccb1f0f6..4c941250 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,17 +32,17 @@ jobs: actions: read steps: - name: Harden the runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@02c5e83432fe5497fd85b873b6c9f16a8578e1d9 # v3.37.0 with: languages: javascript-typescript build-mode: none - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@02c5e83432fe5497fd85b873b6c9f16a8578e1d9 # v3.37.0 with: category: "/language:javascript-typescript" diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index e68102dc..fba9cc0f 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -24,10 +24,10 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/checkout@v5 - - uses: actions/configure-pages@v6 - - uses: actions/upload-pages-artifact@v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: ./site - id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 4c85d13d..aff09f28 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 # The runtime image bakes the git commit for the AGPL-3.0 § 13 source # offer (config.commit → GET /api/instance/info). The .git dir is not in @@ -44,13 +44,13 @@ jobs: run: echo "commit=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -58,7 +58,7 @@ jobs: - name: Derive image tags and labels id: docker_meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0 with: # github.repository is "TheZwiss/backspace"; metadata-action lowercases # it → ghcr.io/thezwiss/backspace (GHCR requires lowercase). @@ -77,7 +77,7 @@ jobs: org.opencontainers.image.revision=${{ github.sha }} - name: Build and push (linux/amd64, linux/arm64) - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b36e9d67..f0de0122 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,8 +34,14 @@ jobs: runs-on: ${{ matrix.os }} steps: + - name: Harden the runner + if: runner.os == 'Linux' + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 + with: + egress-policy: audit + - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Install Linux build dependencies if: runner.os == 'Linux' @@ -65,12 +71,12 @@ jobs: sudo gem install --no-document fpm - name: Setup pnpm - uses: pnpm/action-setup@v5 + uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 with: version: 10.34.3 - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 with: node-version: 20 cache: pnpm diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index e0981ff1..bdda8659 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,26 +23,26 @@ jobs: id-token: write # publish_results OIDC attestation steps: - name: Harden the runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: persist-credentials: false - name: Run Scorecard - uses: ossf/scorecard-action@v2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif publish_results: true - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: SARIF file path: results.sarif retention-days: 5 - name: Upload SARIF to code scanning - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@02c5e83432fe5497fd85b873b6c9f16a8578e1d9 # v3.37.0 with: sarif_file: results.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 1596d3a9..e2479078 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -24,15 +24,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout (full history) - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 with: fetch-depth: 0 # gitleaks scans the whole git history, not just the diff - name: Run gitleaks - uses: gitleaks/gitleaks-action@v2 + uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9 continue-on-error: true # report-only; enforcement flipped on in Plan E env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -45,13 +45,13 @@ jobs: security-events: write # upload SARIF to code scanning steps: - name: Harden the runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Run OSV-Scanner - uses: google/osv-scanner-action@v2 + uses: google/osv-scanner-action@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8 continue-on-error: true # report-only; enforcement flipped on in Plan E with: scan-args: |- @@ -60,7 +60,7 @@ jobs: --output=osv-results.sarif - name: Upload OSV SARIF if: always() - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@02c5e83432fe5497fd85b873b6c9f16a8578e1d9 # v3.37.0 with: sarif_file: osv-results.sarif category: osv-scanner @@ -73,13 +73,13 @@ jobs: security-events: write steps: - name: Harden the runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Trivy config scan (Dockerfile + docker-compose) - uses: aquasecurity/trivy-action@0.28.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 continue-on-error: true # report-only; enforcement flipped on in Plan E with: scan-type: config @@ -88,7 +88,7 @@ jobs: output: trivy-config.sarif - name: Upload Trivy config SARIF if: always() - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@02c5e83432fe5497fd85b873b6c9f16a8578e1d9 # v3.37.0 with: sarif_file: trivy-config.sarif category: trivy-config @@ -101,13 +101,13 @@ jobs: security-events: write steps: - name: Harden the runner - uses: step-security/harden-runner@v2 + uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0 with: egress-policy: audit - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Trivy license scan - uses: aquasecurity/trivy-action@0.28.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 continue-on-error: true # report-only; enforcement flipped on in Plan E with: scan-type: fs @@ -117,7 +117,7 @@ jobs: output: trivy-license.sarif - name: Upload Trivy license SARIF if: always() - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@02c5e83432fe5497fd85b873b6c9f16a8578e1d9 # v3.37.0 with: sarif_file: trivy-license.sarif category: trivy-license From cb524675cc54e4ddaf9594123932c569c99b043d Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:38:03 +0200 Subject: [PATCH 6/8] docs(security): document the scanning pipeline + maintainer checklist --- CLAUDE.md | 1 + docs/systems/security-scanning.md | 51 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 docs/systems/security-scanning.md diff --git a/CLAUDE.md b/CLAUDE.md index e9e72ba2..cce3a36d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -160,6 +160,7 @@ Before modifying any subsystem, read its spec from `docs/systems/`. After making | [message-list.md](docs/systems/message-list.md) | Auto-scroll model, position memory (session-only), embed renderer dimension contract, known limitations | Touching MessageList.tsx, scroll behavior, embed renderers, position restore | | [deployment.md](docs/systems/deployment.md) | Hosting pipeline: Docker/Caddy build, admin bootstrap, DB backup/restore, image pinning, env vars | Any deploy, backup/restore, or hosting change | | [activity-presence.md](docs/systems/activity-presence.md) | Presence states, rich activities, activity types/priorities, broadcast pipeline, visibility control, ActivityCard/Panel | Presence, rich activities, activity display, status management | +| [security-scanning.md](docs/systems/security-scanning.md) | CI security pipeline: Dependabot, CodeQL SAST, gitleaks, OSV-Scanner, Trivy (config/image/license), OpenSSF Scorecard, SHA-pinning, harden-runner, tiered enforcement policy, maintainer settings checklist | Any CI security work, adding/changing scanners, enabling enforcement, supply-chain hardening | --- diff --git a/docs/systems/security-scanning.md b/docs/systems/security-scanning.md new file mode 100644 index 00000000..9504e355 --- /dev/null +++ b/docs/systems/security-scanning.md @@ -0,0 +1,51 @@ +# Security Scanning & Supply-Chain Assurance + +Automated, continuous scanning wired into GitHub Actions. This document is the +reference for what runs, where results go, and the one-time settings a maintainer +must enable. **Current state: report-only** — scanners surface findings in the +Security tab but do not block merges yet. Enforcement (blocking) is turned on in a +later change once the remediation pass has cleared the backlog. + +## Workflows + +| File | Purpose | Trigger | Result | +|------|---------|---------|--------| +| `.github/dependabot.yml` | Dependency + action + base-image update PRs | weekly | PRs | +| `.github/workflows/codeql.yml` | CodeQL SAST (`javascript-typescript`, build-mode none) | PR + push main + weekly | Security tab | +| `.github/workflows/security.yml` | gitleaks (secrets, full history), OSV-Scanner (deps), Trivy config (IaC), Trivy license | PR + push main + weekly | Security tab | +| `.github/workflows/scorecard.yml` | OpenSSF Scorecard (repo posture) | push main + weekly | Security tab + public badge | + +## Tiered policy (target, enforced in a later change) + +- **Always block:** gitleaks secret hit; OSV/Trivy fixable HIGH/CRITICAL; Trivy + disallowed license. +- **Advisory (SARIF → Security tab):** CodeQL alerts; OSV/Trivy unfixable or + medium/low; Scorecard. + +Code-level gates (OSV, Trivy, gitleaks) block via workflow exit codes. CodeQL +merge-blocking, Dependabot alerts, and native secret-scanning are GitHub *settings* +— see the checklist below. + +## Supply-chain hardening + +- Every action is pinned to a full commit SHA (`# vX.Y.Z` comment) — resists + tag-move attacks and satisfies Scorecard's Pinned-Dependencies check. +- `step-security/harden-runner` (egress-policy `audit`) on Linux jobs. +- Least-privilege `permissions:` per workflow/job. +- SBOM + SLSA provenance are attached to the published container image (added with + the image-scan work). + +## Maintainer checklist (one-time GitHub settings — NOT code) + +- [ ] Repository must be **public** (required for the Scorecard badge/publish and + the CodeQL free tier). +- [ ] Settings → Code security: enable **Dependabot alerts** and **Dependabot + security updates**. +- [ ] Settings → Code security: enable **Secret scanning** + **Push protection**. +- [ ] Settings → Code security: enable **CodeQL / code-scanning merge protection** + so high-severity alerts block PRs (the code-level gates do the rest). +- [ ] Branch protection on `main`: require the CI + security status checks to pass. +- [ ] **Manual image bumps:** Dependabot does not track `docker-compose.yml` + `image:` pins — update `caddy` and `livekit/livekit-server` by hand when new + releases ship. (Renovate, which parses compose, is an optional future + alternative.) From e2d09c0d52b29e6caacef63f839fad93591299f7 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:48:09 +0200 Subject: [PATCH 7/8] fix(security): point OSV-Scanner at runnable subpath action; doc accuracy fixes - OSV-Scanner ref was google/osv-scanner-action@ (metadata-only root action, no runs:) -> subpath google/osv-scanner-action/osv-scanner-action which carries the docker action + scan-args input. Root ref would fail to load and redden the job on every run (caught in final whole-branch review). - security-scanning.md: note gitleaks findings land in job log (not SARIF); add scorecard branch_protection_rule trigger; mark SBOM/provenance as not- yet-live. CLAUDE.md row: image scan is a later plan, not current. --- .github/workflows/security.yml | 2 +- CLAUDE.md | 2 +- docs/systems/security-scanning.md | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index e2479078..a19d95e4 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -51,7 +51,7 @@ jobs: - name: Checkout uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Run OSV-Scanner - uses: google/osv-scanner-action@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8 + uses: google/osv-scanner-action/osv-scanner-action@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8 continue-on-error: true # report-only; enforcement flipped on in Plan E with: scan-args: |- diff --git a/CLAUDE.md b/CLAUDE.md index cce3a36d..76fca0e7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -160,7 +160,7 @@ Before modifying any subsystem, read its spec from `docs/systems/`. After making | [message-list.md](docs/systems/message-list.md) | Auto-scroll model, position memory (session-only), embed renderer dimension contract, known limitations | Touching MessageList.tsx, scroll behavior, embed renderers, position restore | | [deployment.md](docs/systems/deployment.md) | Hosting pipeline: Docker/Caddy build, admin bootstrap, DB backup/restore, image pinning, env vars | Any deploy, backup/restore, or hosting change | | [activity-presence.md](docs/systems/activity-presence.md) | Presence states, rich activities, activity types/priorities, broadcast pipeline, visibility control, ActivityCard/Panel | Presence, rich activities, activity display, status management | -| [security-scanning.md](docs/systems/security-scanning.md) | CI security pipeline: Dependabot, CodeQL SAST, gitleaks, OSV-Scanner, Trivy (config/image/license), OpenSSF Scorecard, SHA-pinning, harden-runner, tiered enforcement policy, maintainer settings checklist | Any CI security work, adding/changing scanners, enabling enforcement, supply-chain hardening | +| [security-scanning.md](docs/systems/security-scanning.md) | CI security pipeline: Dependabot, CodeQL SAST, gitleaks, OSV-Scanner, Trivy (config/license; image scan in a later plan), OpenSSF Scorecard, SHA-pinning, harden-runner, tiered enforcement policy, maintainer settings checklist | Any CI security work, adding/changing scanners, enabling enforcement, supply-chain hardening | --- diff --git a/docs/systems/security-scanning.md b/docs/systems/security-scanning.md index 9504e355..104bdb31 100644 --- a/docs/systems/security-scanning.md +++ b/docs/systems/security-scanning.md @@ -13,7 +13,11 @@ later change once the remediation pass has cleared the backlog. | `.github/dependabot.yml` | Dependency + action + base-image update PRs | weekly | PRs | | `.github/workflows/codeql.yml` | CodeQL SAST (`javascript-typescript`, build-mode none) | PR + push main + weekly | Security tab | | `.github/workflows/security.yml` | gitleaks (secrets, full history), OSV-Scanner (deps), Trivy config (IaC), Trivy license | PR + push main + weekly | Security tab | -| `.github/workflows/scorecard.yml` | OpenSSF Scorecard (repo posture) | push main + weekly | Security tab + public badge | +| `.github/workflows/scorecard.yml` | OpenSSF Scorecard (repo posture) | push main + weekly + on branch-protection change | Security tab + public badge | + +> **gitleaks findings** surface in the workflow's job log and PR summary — the +> `gitleaks` job does not upload SARIF, so secret hits do **not** appear under +> Security → Code scanning (unlike the OSV / Trivy / CodeQL / Scorecard jobs). ## Tiered policy (target, enforced in a later change) @@ -32,8 +36,8 @@ merge-blocking, Dependabot alerts, and native secret-scanning are GitHub *settin tag-move attacks and satisfies Scorecard's Pinned-Dependencies check. - `step-security/harden-runner` (egress-policy `audit`) on Linux jobs. - Least-privilege `permissions:` per workflow/job. -- SBOM + SLSA provenance are attached to the published container image (added with - the image-scan work). +- SBOM + SLSA provenance **will be** attached to the published container image + (added with the container-image-scan work in a later plan — not yet live). ## Maintainer checklist (one-time GitHub settings — NOT code) From cf4172e81a53d9c06524908c4ee479b1e77a289d Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Sun, 12 Jul 2026 23:54:47 +0200 Subject: [PATCH 8/8] fix(security): bump trivy-action v0.28.0 -> v0.36.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.28.0's composite action referenced a nested aquasecurity/setup-trivy@v0.2.1 tag that no longer exists, so the action failed to RESOLVE during job setup (before any step ran) — continue-on-error can't catch a resolution failure, so both Trivy jobs went red on every run. v0.36.0 pins setup-trivy to a real SHA (v0.2.6) and still supports scan-type/scan-ref/scanners/format/output. --- .github/workflows/security.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index a19d95e4..5f457881 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -79,7 +79,7 @@ jobs: - name: Checkout uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Trivy config scan (Dockerfile + docker-compose) - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 continue-on-error: true # report-only; enforcement flipped on in Plan E with: scan-type: config @@ -107,7 +107,7 @@ jobs: - name: Checkout uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - name: Trivy license scan - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # v0.28.0 + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 continue-on-error: true # report-only; enforcement flipped on in Plan E with: scan-type: fs