From 994b323cfae9f0c5bd0654a1fb84ee70edc90afa Mon Sep 17 00:00:00 2001 From: meeech <4623+meeech@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:43:57 -0400 Subject: [PATCH] docs: add supply chain security rules for pnpm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add agent-facing rules to CLAUDE.md covering minimumReleaseAgeExclude, onlyBuiltDependencies, and frozen lockfile requirements — all require human sign-off. Add comprehensive human-facing section to docs/SECURITY.md with rationale, exclusion procedure (exact version pin, approval, expiry), and build script allowlist documentation. --- CLAUDE.md | 9 +++++++++ docs/SECURITY.md | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index cc4ea75c9..e4b61dc21 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -123,6 +123,15 @@ systemctl --user start|stop|restart nanoclaw Host logs: `logs/nanoclaw.log` (normal) and `logs/nanoclaw.error.log` (errors only — some delivery/approval failures only show up here). +## Supply Chain Security (pnpm) + +This project uses pnpm with `minimumReleaseAge: 4320` (3 days) in `pnpm-workspace.yaml`. New package versions must exist on the npm registry for 3 days before pnpm will resolve them. + +**Rules — do not bypass without explicit human approval:** +- **`minimumReleaseAgeExclude`**: Never add entries without human sign-off. If a package must bypass the release age gate, the human must approve and the entry must pin the exact version being excluded (e.g. `package@1.2.3`), never a range. +- **`onlyBuiltDependencies`**: Never add packages to this list without human approval — build scripts execute arbitrary code during install. +- **`pnpm install --frozen-lockfile`** should be used in CI, automation, and container builds. Never run bare `pnpm install` in those contexts. + ## v2 Docs Index | Doc | Purpose | diff --git a/docs/SECURITY.md b/docs/SECURITY.md index dbfd6bf84..2363b7506 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -123,3 +123,39 @@ Each NanoClaw group gets its own OneCLI agent identity. This allows different cr │ • No real credentials in environment or filesystem │ └──────────────────────────────────────────────────────────────────┘ ``` + +## Supply Chain Security (pnpm) + +NanoClaw uses pnpm with two supply chain defenses configured in `pnpm-workspace.yaml`: + +### Minimum Release Age + +`minimumReleaseAge: 4320` (3 days). pnpm will refuse to resolve any package version published less than 3 days ago. This defends against typosquatting and compromised maintainer accounts — most malicious publishes are detected and pulled within 72 hours. + +**Excluding a package from the release age gate** (`minimumReleaseAgeExclude`): + +This should be rare. When a zero-day fix or critical dependency requires an immediate update: + +1. The exclusion must be reviewed and approved by a human maintainer +2. The entry must pin the **exact version** being excluded — never a range or wildcard + ```yaml + minimumReleaseAgeExclude: + some-package: "1.2.3" # Approved by @user, 2026-04-14 — CVE-XXXX-YYYY fix + ``` +3. The exclusion should be removed once the version ages past the threshold (i.e. after 3 days) +4. Automated agents (Claude, CI bots) must never add exclusions without human sign-off + +### Build Script Allowlist + +`onlyBuiltDependencies` restricts which packages can execute install/postinstall scripts. Only packages on this list are permitted to run build scripts during `pnpm install`. Currently allowed: + +- `better-sqlite3` — compiles native SQLite bindings +- `esbuild` — downloads platform-specific binary +- `protobufjs` — generates protobuf bindings (used by Baileys/libsignal) +- `sharp` — downloads platform-specific image processing binary + +Adding a package to this list requires human approval — build scripts execute arbitrary code with the installing user's permissions. + +### `.npmrc` Safety Net + +The `.npmrc` file contains `minReleaseAge=3d` as a fallback. The authoritative setting is in `pnpm-workspace.yaml`, but `.npmrc` provides defense-in-depth if npm is ever invoked directly (e.g. by a tool that doesn't respect pnpm).