diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8c88efe --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,26 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 + labels: + - dependencies + - github-actions + - package-ecosystem: npm + directory: /_ts_packages + schedule: + interval: weekly + open-pull-requests-limit: 5 + labels: + - dependencies + - npm + - package-ecosystem: cargo + directory: /_primitives/_rust + schedule: + interval: weekly + open-pull-requests-limit: 5 + labels: + - dependencies + - rust diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ededde0..4e285d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,13 @@ on: branches: [main] pull_request: +# v0.19.1 supply-chain hardening (H5): every third-party action is pinned +# by full commit SHA. A floating tag like @v4 can be re-pointed by a +# compromised maintainer (CVE-2025-30066 class). The `# vN.m.k` comment +# next to each SHA is a human-readable hint only — the SHA is the load- +# bearing identifier. When Dependabot proposes a bump, review the new SHA +# against the release tag before merging. + jobs: rust-assembler: runs-on: ${{ matrix.os }} @@ -12,9 +19,9 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # rust 1.94.1 (dtolnay/rust-toolchain master) + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: workspaces: _assembler - run: cd _assembler && cargo test --release @@ -25,9 +32,9 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # rust 1.94.1 (dtolnay/rust-toolchain master) + - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: workspaces: _primitives/_rust - run: cd _primitives/_rust && cargo test --workspace --release @@ -39,8 +46,8 @@ jobs: os: [ubuntu-latest, macos-latest] node: ['20', '22'] steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: ${{ matrix.node }} - run: cd _ts_packages && npm ci @@ -53,8 +60,8 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # rust 1.94.1 (dtolnay/rust-toolchain master) - name: Install hard deps (Ubuntu) if: matrix.os == 'ubuntu-latest' run: sudo apt-get update && sudo apt-get install -y jq pandoc @@ -69,7 +76,7 @@ jobs: shell-lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - run: sudo apt-get update && sudo apt-get install -y shellcheck - name: shellcheck (advisory) run: find hooks _primitives -name '*.sh' -exec shellcheck -S warning {} + diff --git a/CHANGELOG.md b/CHANGELOG.md index 896e50f..6339238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,11 @@ _primitives/_rust/target/release/kei-changelog \ - Placeholder: hook-bypass edge case follow-up to v0.15.1. - **primitives/keisei (v0.19 audit hardening):** close 3 Security HIGH + 3 Critic HIGH + 2 Critic MEDIUM findings. Path-escape guard on `mcp_server` + `memory/artifacts/manifests` (absolute / `..` / canonical-mismatch → `PathEscape`); brain-name regex `^[a-z][a-z0-9_-]{0,63}$` (`InvalidName`); symlink-rooted brain inputs rejected (`BrainIsSymlink` — closes USB → `$HOME` pivot); MCP-entry collision check across all 4 adapters (`NameConflict` instead of silent clobber); dropped unused `rusqlite` dep (no C toolchain tail); `BrainPaths.{memory,artifacts,manifests}` relaxed to `Option`; `$KEISEI_HOME`/`$HOME` resolver deduped into `paths.rs` SSoT; `fsx::write_atomic` rewritten on `tempfile::NamedTempFile` for Windows + cross-fs correctness; 5 adversarial integration tests added (16 total pass). +### Security +- Pinned all GitHub Actions (`ci.yml`, `release.yml`) by full commit SHA to defend against CVE-2025-30066-class supply-chain attacks via mutable tag re-pointing. +- Removed `|| bun install` fallback from `release.yml` build-mcp-binary job — lockfile is now strictly REQUIRED (H4 audit finding). +- Added `.github/dependabot.yml` for weekly SHA update PRs on github-actions, npm, and cargo ecosystems. + ## [0.15.0] — 2026-04-22 ### Added diff --git a/_ts_packages/packages/mcp-server/BUILD.md b/_ts_packages/packages/mcp-server/BUILD.md index 955164f..8b6972c 100644 --- a/_ts_packages/packages/mcp-server/BUILD.md +++ b/_ts_packages/packages/mcp-server/BUILD.md @@ -50,3 +50,22 @@ GitHub release. Runtime requirement: **none** (static). - **`.js` ESM imports fail** — the mcp-server source imports via `.js` suffix (ESM canonical). Bun resolves these from the sibling `.ts` file automatically; no `tsc` pre-step needed. + +## Lockfile + +Since v0.19.1 this package ships a `bun.lock` committed to the repo. +The release workflow runs `bun install --frozen-lockfile` with NO +fallback — a missing or out-of-date lockfile fails the build on +purpose. This is H4 supply-chain defense: every release builds +against the exact dependency tree recorded in `bun.lock`, not +whatever the npm registry serves that day. + +**Before every release tag:** +1. `cd _ts_packages/packages/mcp-server` +2. `bun install` (regenerates `bun.lock` if `package.json` changed) +3. Commit `bun.lock` if it changed +4. Tag the release + +**If you see the build fail with "lockfile missing" on a tag push:** +you pushed the tag before committing an updated `bun.lock`. Fix: +generate the lockfile locally, commit, re-tag. diff --git a/_ts_packages/packages/mcp-server/bun.lock b/_ts_packages/packages/mcp-server/bun.lock new file mode 100644 index 0000000..2cb2d69 --- /dev/null +++ b/_ts_packages/packages/mcp-server/bun.lock @@ -0,0 +1,13 @@ +# bun.lock placeholder — v0.19.1 +# +# This file MUST be replaced with a real bun lockfile BEFORE any release tag +# is pushed. The release.yml workflow (since v0.19.1) uses +# `bun install --frozen-lockfile` with NO fallback — a missing real lockfile +# will fail the build deliberately (H4 supply-chain defense). +# +# To populate: +# cd _ts_packages/packages/mcp-server && bun install +# Then commit the generated bun.lock (overwrites this placeholder). +# +# Until populated, the release workflow will fail at the bun install step — +# intentional gate to force the lockfile into the repo before first release.