Supply Chain page: Cargo + bundled-runtime snapshots, provable Node pin#98
Conversation
The /dependencies route was renamed to /supply-chain, leaving the README pointing at a now-404 URL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Matches the /supply-chain route and page title. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This reverts commit fcf92f8.
The Supply Chain page showed Requirement, Scope, and Features columns only for direct Cargo crates, which were noisy and out of place next to the simpler npm and transitive tables. Stop collecting those fields in generate-deps.js, trim the DirectCargoDependency type and table to Crate / Resolved / License, and regenerate the cargo snapshot to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a plain-language summary of what each tend-reachable secret (TEND_BOT_TOKEN, CLAUDE_CODE_OAUTH_TOKEN, CHROMATIC_PROJECT_TOKEN) exposes, framing TEND_BOT_TOKEN as the worst case and noting that none escalate directly to main or deployment secrets. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the hand-listed licenseAliases map with a normalizeLicense function that converts legacy slash-separated dual licenses (e.g. "Apache-2.0/MIT") to SPDX "OR" form, then moves MIT to the front of its OR choice for a consistent listing — including inside parenthesized groups like "(MIT OR Apache-2.0) AND BSD-3-Clause". Conjunctive AND expressions and the distinct MIT-0 license are left untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The direct Cargo table was missing the Author column (the data already carries it) and, with only three columns, its spacing diverged from the four-column npm and transitive tables. Add the Author column with the same cell classes as PackageTable and rename the "Resolved" header to "Version" so all three tables share an identical column structure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a security-practices overview (with a properly styled list) to the Supply Chain page intro, and fix link brightness: body-copy links were dimmed by their paragraph's `opacity-70`, since opacity composites the whole subtree. Dim body text with a text-color alpha (text-[var(--color-text)]/70) instead so links keep full caramel brightness, matching the dependency-table links. Centralize the caramel link style in a single tailwind-variants `link` variant applied to every link on the page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fix the garbled dependency-cooldown bullet and explain the actual
protection (delay adoption so malicious releases get caught first),
parallel the two secret bullets ("<type> secrets for <product> are
<protection>"), and use consistent parallel product names — the VS Code
extension and the Standalone app.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The standalone app ships a Node.js binary as a Tauri sidecar (build.rs), but it was disclosed nowhere. Pin it exactly in a new .nvmrc as the single source of truth shared by CI's setup-node (node-version-file) and the bundling step, generate a dependencies-runtime.json snapshot, render it as a "Bundled Runtime" section on /supply-chain, and document it plus new FAIL IFs in SECURITY.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The VS Code extension forked the pty host under a user-installed system Node on macOS/Linux (and Electron's Node only on Windows), hunting through nvm/Homebrew/PATH — unreliable, and on Windows the bogus Unix-path fallback caused multi-second fork stalls. Always use process.execPath instead. node-pty ships N-API prebuilds that load across runtimes, and the host re-execs as Node via the inherited ELECTRON_RUN_AS_NODE, so no external Node is needed. Update the /supply-chain "Bundled Runtime" copy to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dead code: the aggregate was computed but never rendered, and trips noUnusedLocals under tsc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The supply-chain page disclosed an exact Node version, but the bundle just copied whatever node was on the build machine's PATH — disclosed and shipped were coupled only by convention. Make build.rs the authority: it runs --version on the binary it's about to bundle and fails the build unless it matches the pin, now at standalone/.node-version (the distributed runtime, scoped away from CI tooling). generate-deps.js reads the same pin, so the page provably equals what ships. Cross-compile skips the exec check (can't run a foreign-arch binary). Only the build-standalone release job needs the exact pin (via setup-node node-version-file); every other workflow goes back to node-version: 22 since its interpreter is never bundled. SECURITY.md reframed around provable disclosure with tighter FAIL IFs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The transitive list is the full locked build graph (cargo metadata with no platform/dep-kind filter), so it includes build-time, proc-macro, and platform-specific crates that don't all link into the shipped binary. Soften the copy to match rather than implying every crate ships. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
380a434
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ac851a58.mouseterm.pages.dev |
| Branch Preview URL: | https://bad-draft-supply-chain.mouseterm.pages.dev |
dormouse-bot
left a comment
There was a problem hiding this comment.
One copy nit in the new TEND_BOT_TOKEN bullet — looks like a mid-edit artifact left a dangling fragment. The rest reads well; the build-time Node pin verification and the scoped node-version-file change all line up with the new SECURITY.md FAIL IF rules.
|
|
||
| An attacker who lands a prompt injection in tend's harness can reach three secrets. None of them escalates directly into malicious content on the `main` branch or into any deployment-related secret — those paths stay admin-gated. The boundaries we accept are codified below. | ||
|
|
||
| - `TEND_BOT_TOKEN` (worst case): full `repo` + `workflow` write access *as a trusted collaborator*. Direct uses are issue/PR spam, force-pushing or deleting feature branches, and persistent compromise by authoring new workflows (persistent compromise mitigated by [`workflow-audit.yaml`](.github/workflows/workflow-audit.yaml)). Authoring a workflow is also the mechanism by which `CHROMATIC_PROJECT_TOKEN` is reached. and the bot's trusted identity. **It cannot itself merge to `main`, push tags, or reach env-scoped secrets, but the bot's trusted identity can be used to social-engineer an admin toward a `main` merge.** |
There was a problem hiding this comment.
The . and the bot's trusted identity. fragment reads as a leftover from an edit — it has no verb, and the bot's trusted identity is already covered by the bold sentence that follows. Suggest dropping it:
| - `TEND_BOT_TOKEN` (worst case): full `repo` + `workflow` write access *as a trusted collaborator*. Direct uses are issue/PR spam, force-pushing or deleting feature branches, and persistent compromise by authoring new workflows (persistent compromise mitigated by [`workflow-audit.yaml`](.github/workflows/workflow-audit.yaml)). Authoring a workflow is also the mechanism by which `CHROMATIC_PROJECT_TOKEN` is reached. and the bot's trusted identity. **It cannot itself merge to `main`, push tags, or reach env-scoped secrets, but the bot's trusted identity can be used to social-engineer an admin toward a `main` merge.** | |
| - `TEND_BOT_TOKEN` (worst case): full `repo` + `workflow` write access *as a trusted collaborator*. Direct uses are issue/PR spam, force-pushing or deleting feature branches, and persistent compromise by authoring new workflows (persistent compromise mitigated by [`workflow-audit.yaml`](.github/workflows/workflow-audit.yaml)). Authoring a workflow is also the mechanism by which `CHROMATIC_PROJECT_TOKEN` is reached. **It cannot itself merge to `main`, push tags, or reach env-scoped secrets, but the bot's trusted identity can be used to social-engineer an admin toward a `main` merge.** |
dormouse-bot
left a comment
There was a problem hiding this comment.
CI: Standalone Smoketest is failing because of this PR's new build-time gate. The standalone-smoketest job in .github/workflows/ci.yml runs cargo check, which now triggers build.rs's version verification — but its setup-node step still pins node-version: 22, which resolved to 22.22.3 on the runner and trips the pin:
failed to prepare bundled Node.js runtime: "bundled Node.js 22.22.3 does not match the standalone/.node-version pin 22.17.1."
The gate now affects every build of the standalone crate, not just the release build-standalone job — so this CI job needs the pinned runtime too. The one-line fix matches the PR's single-source-of-truth intent:
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: standalone/.node-version(.github/workflows/ci.yml, the standalone-smoketest job — line is outside this PR's diff, so I can't attach an inline suggestion.) The build-and-test job doesn't compile the crate, so it can stay on node-version: 22. Happy to push this fix to the branch if you'd like.
Cloudflare Pages also shows failed, but it completed in 0s with no accessible Actions log (it's the external Pages integration, not a workflow run). The website itself built and tested clean in the Build & Test job (pnpm --filter dormouse-website build passed), so this looks like a deploy-side issue rather than a code problem — though I can't confirm the cause from CI here.
Update the standalone/.node-version pin and regenerate the supply-chain runtime disclosure to match. build.rs verifies the bundled binary against this pin at build time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
generate-deps.js shells out to `cargo metadata`, but the website deploy environment (Cloudflare Pages) has no Rust toolchain, so prebuild failed with spawnSync cargo ENOENT. The snapshots are committed artifacts, regenerated as a manual release step (docs/specs/deploy.md) and verified by the security-audit FAIL IF, so the build should just consume them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Show the dependency count inline beside each section title and let descriptions contain explicit newlines (whitespace-pre-line). - Tighten the intro copy and bundled-runtime description. - Add cargo author/homepage overrides for libappindicator and libappindicator-sys, whose published Cargo.toml omits both, so they link to tauri-apps/libappindicator-rs and credit Tauri Apps Contributors instead of rendering "Unknown". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Reworks the website's
/dependenciespage into a fuller/supply-chainpage and tightens the supply-chain story end to end./supply-chain, replacing/dependencies) — separate sections for the bundled Node.js runtime, npm packages, direct Cargo crates, and transitive Cargo crates, with an up-front summary of our security posture (maturity gating, gated VS Code publish, offline standalone signing).generate-deps.jsnow emitsdependencies-npm.json,dependencies-cargo.json(direct vs transitive), anddependencies-runtime.jsonfromcargo metadata --locked. License strings are normalized (legacy/→OR, MIT moved first).standalone/.node-version(22.22.3), and the build is the authority:build.rsruns--versionon the binary it is about to bundle and fails the build unless it matches the pin. The supply-chain page reads the same pin, so the disclosed version provably equals what ships. Thebuild-standalonejob installs that pin viasetup-node'snode-version-file; other workflow jobs (which never bundle a runtime) are free to track latest22.process.execPath) instead of hunting for a system Node, which was unreliable and caused multi-second fork stalls on Windows.Review fixes (own commits)
b1e58cb— removed deadtotalDependencyCount(computed, never rendered; tripsnoUnusedLocals).e53657b— softened the Cargo copy: the transitive list is the full locked build graph (no platform/dep-kind filter), so it includes build-time, proc-macro, and platform-specific crates that don't all link into the shipped binary. Copy now says so rather than implying every crate ships.Verification
node website/scripts/generate-deps.jsreproduces the committed JSON with zero diff (the SECURITY.md FAIL IF holds).build.rsverifies the bundled Node binary againststandalone/.node-versionat build time.🤖 Generated with Claude Code