From eb218a96ad46124f1f20559ebca7972a617f6967 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 10 Apr 2026 05:26:09 -1000 Subject: [PATCH] security: pin GitHub Actions, add gitleaks CI, harden permissions (v0.4.2) (#23) * security: pin GitHub Actions to commit SHAs, add gitleaks CI - Pin all 5 actions (checkout, setup-bun, upload-artifact, download-artifact, action-gh-release) to commit SHAs across 3 workflow files - Add permissions: contents: read to test.yml and e2e.yml - Add gitleaks secret scanning job to test.yml - Pin openclaw install to v2026.4.9 in e2e.yml Co-Authored-By: Claude Opus 4.6 (1M context) * security: add .gitleaks.toml config Allowlists test fixtures, example env files, and skill documentation to prevent false positives from the gitleaks CI step. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add GitHub Actions SHA maintenance rule to CLAUDE.md Instructs /ship and /review to check for stale SHA pins and update them, keeping action versions fresh without manual effort. Co-Authored-By: Claude Opus 4.6 (1M context) * docs: add S3 Sig V4 TODO from CSO audit Deferred from security audit. S3 storage backend accepts credentials but sends unsigned requests. Implement when S3 becomes a real deployment path. Co-Authored-By: Claude Opus 4.6 (1M context) * chore: bump version and changelog (v0.4.2) Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .github/workflows/e2e.yml | 13 ++++++++----- .github/workflows/release.yml | 10 +++++----- .github/workflows/test.yml | 17 +++++++++++++++-- .gitleaks.toml | 11 +++++++++++ CHANGELOG.md | 15 +++++++++++++++ CLAUDE.md | 14 ++++++++++++++ TODOS.md | 15 +++++++++++++++ VERSION | 2 +- 8 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 .gitleaks.toml diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 26c3b7f7a..817ac67c3 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -9,6 +9,9 @@ on: - cron: '0 6 * * *' # Nightly at 6am UTC workflow_dispatch: +permissions: + contents: read + jobs: tier1: name: Tier 1 (Mechanical) @@ -28,8 +31,8 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - run: bun install @@ -58,13 +61,13 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - run: bun install - name: Install OpenClaw - run: npm install -g openclaw + run: npm install -g openclaw@2026.4.9 - name: Configure OpenClaw MCP run: | mkdir -p ~/.openclaw diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 282824e10..9b56be9ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,14 +20,14 @@ jobs: artifact: gbrain-linux-x64 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - run: bun install - run: bun test - run: bun build --compile --target=${{ matrix.target }} --outfile bin/${{ matrix.artifact }} src/cli.ts - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ matrix.artifact }} path: bin/${{ matrix.artifact }} @@ -36,11 +36,11 @@ jobs: needs: build runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: path: artifacts - name: Create release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2 with: files: | artifacts/gbrain-darwin-arm64/gbrain-darwin-arm64 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3dae4c106..ce3b53c74 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,12 +6,25 @@ on: pull_request: branches: [master] +permissions: + contents: read + jobs: + gitleaks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 0 + - uses: gitleaks/gitleaks-action@dcedce43c6f43de0b836d1fe38946645c9c638dc # v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: oven-sh/setup-bun@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: latest - run: bun install diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000..413f31b71 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,11 @@ +title = "GBrain gitleaks config" + +[allowlist] + paths = [ + '''.env\.testing\.example''', + '''.env\.example''', + '''test/''', + '''skills/''', + '''.claude/skills/''', + '''GBRAIN_SKILLPACK\.md''', + ] diff --git a/CHANGELOG.md b/CHANGELOG.md index 7027631c9..e0c946225 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to GBrain will be documented in this file. +## [0.4.2] - 2026-04-10 + +### Changed + +- All GitHub Actions pinned to commit SHAs across test, e2e, and release workflows. Prevents supply chain attacks via mutable version tags. +- Workflow permissions hardened: `contents: read` on test and e2e workflows limits GITHUB_TOKEN blast radius. +- OpenClaw CI install pinned to v2026.4.9 instead of pulling latest. + +### Added + +- Gitleaks secret scanning CI job runs on every push and PR. Catches accidentally committed API keys, tokens, and credentials. +- `.gitleaks.toml` config with allowlists for test fixtures and example files. +- GitHub Actions SHA maintenance rule in CLAUDE.md so pins stay fresh on every `/ship` and `/review`. +- S3 Sig V4 TODO for future implementation when S3 storage becomes a deployment path. + ## [0.4.1] - 2026-04-09 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 0f3ba79e6..ce32a4964 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -118,6 +118,20 @@ reads this during upgrades to suggest new schema additions without re-suggesting things the user already declined. The setup skill writes the initial state during Phase C/E. Never modify a user's custom directories or re-suggest declined ones. +## GitHub Actions SHA maintenance + +All GitHub Actions in `.github/workflows/` are pinned to commit SHAs. Before shipping +(`/ship`) or reviewing (`/review`), check for stale pins and update them: + +```bash +for action in actions/checkout oven-sh/setup-bun actions/upload-artifact actions/download-artifact softprops/action-gh-release gitleaks/gitleaks-action; do + tag=$(grep -r "$action@" .github/workflows/ | head -1 | grep -o '#.*' | tr -d '# ') + [ -n "$tag" ] && echo "$action@$tag: $(gh api repos/$action/git/ref/tags/$tag --jq .object.sha 2>/dev/null)" +done +``` + +If any SHA differs from what's in the workflow files, update the pin and version comment. + ## Skill routing When the user's request matches an available skill, ALWAYS invoke it using the Skill diff --git a/TODOS.md b/TODOS.md index 9c42b7463..ff6e8c716 100644 --- a/TODOS.md +++ b/TODOS.md @@ -16,3 +16,18 @@ **Implementation sketch:** `src/core/embedding-queue.ts` with a Promise-based semaphore. Workers `await queue.submit(chunks)` which resolves when the queue has room. Queue flushes to OpenAI in batches of 100 with max 2-3 concurrent API calls. Track source file per chunk for error propagation. **Depends on:** Part 5 (parallel import with per-worker engines) -- already shipped. + +## P2 + +### Implement AWS Signature V4 for S3 storage backend +**What:** Replace the unsigned `signedFetch()` in `src/core/storage/s3.ts` with proper AWS Signature V4 request signing. + +**Why:** The current S3 implementation accepts `accessKeyId` and `secretAccessKey` but never signs requests. It only works with public buckets or pre-signed URLs. Private S3 buckets return 403. + +**Pros:** Enables private S3/R2/MinIO bucket support. Users can store files securely without relying on public bucket access. + +**Cons:** AWS Sig V4 is complex (canonical request, string to sign, signing key derivation). Could use a lightweight library instead of rolling from scratch. Medium implementation effort. + +**Context:** Identified during CSO security audit (2026-04-10). The code explicitly comments this as "simplified" and not production-ready. Nobody uses S3 storage today (Supabase Storage is the default). Only implement when S3 becomes a real deployment path. + +**Depends on:** Nothing. Self-contained change to `src/core/storage/s3.ts`. diff --git a/VERSION b/VERSION index 267577d47..2b7c5ae01 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.1 +0.4.2