feat: snapshot dependency check prototype

This commit is contained in:
Casey Silver
2026-07-07 22:19:12 -07:00
parent f1affbac5e
commit ba40f20930
29 changed files with 2375 additions and 4 deletions
+7
View File
@@ -13,3 +13,10 @@ Admins can set top-level `allow_managed_hooks_only = true` in
still allowing managed hooks from requirements and managed config layers. This
setting is only supported in `requirements.toml`; putting it in `config.toml`
does not enable managed-hooks-only mode.
## Dependency Check
The experimental `dependency_check` tool resolves and checks complete npm
dependency graphs before lifecycle scripts run. Enable it with
`features.dependency_check = true`. See [Dependency Check](dependency-check.md)
for the sandbox policy and approval flow.
+109
View File
@@ -0,0 +1,109 @@
# Dependency Check
`dependency_check` is an experimental npm-first tool that separates dependency
resolution and policy from package lifecycle execution.
Enable it in `config.toml`:
```toml
[features]
dependency_check = true
```
The model-visible request uses exact package intent:
```json
{
"ecosystem": "npm",
"dependencies": [{ "name": "zod", "version": "3.23.8" }],
"dependency_kind": "development"
}
```
Version ranges and tags are rejected. A request may contain at most twenty
direct dependencies.
## Execution flow
1. Copy `package.json`, an existing `package-lock.json`, and project `.npmrc`
into a temporary directory.
2. Run `npm install --package-lock-only --ignore-scripts` there to resolve the
complete graph without running package lifecycle code.
3. Run `npm query '*' --json --package-lock-only` and require every package to
have an HTTPS artifact URL and integrity value.
4. Query the OSV batch API for every unique exact npm package coordinate.
5. Update the real project lock graph through Codex's normal sandbox and
approval path, then require it to exactly match the checked graph.
6. Run a clean `npm ci --ignore-scripts`, verify the installed artifact graph
matches the checked graph, and only then run `npm rebuild`.
Known `MAL-*` advisories block the operation. Ordinary vulnerability advisories
are reported as warnings. Provider failures, partial responses, unsupported
sources, missing integrity values, and graph changes fail closed before
lifecycle scripts run.
An OSV allow result means only that OSV returned no matching advisory. It is
not a general assertion that a package is trustworthy.
## Enforcement
When the feature is enabled, Codex rejects recognizable direct dependency-add
commands such as `npm install package@version`, `pnpm add`, `yarn add`, and
`bun add`, directing the model to `dependency_check`. It also rejects direct
`apply_patch` changes to JavaScript package manifests and lockfiles.
The real project mutation still uses the existing shell sandbox and approval
orchestrator. A permission profile can therefore keep the root manifest and
lockfile read-only inside the sandbox so the checked update produces a user
approval prompt:
```toml
default_permissions = "dependency-check"
[permissions.dependency-check]
description = "Workspace write access with npm manifests read-only."
[permissions.dependency-check.filesystem]
":minimal" = "read"
":tmpdir" = "write"
"/path/to/node/runtime" = "read"
[permissions.dependency-check.filesystem.":project_roots"]
"." = "write"
"package.json" = "read"
"package-lock.json" = "read"
[permissions.dependency-check.network]
enabled = true
[permissions.dependency-check.network.domains]
"registry.npmjs.org" = "allow"
"api.osv.dev" = "allow"
```
Replace `/path/to/node/runtime` with the directory containing the configured
Node.js and npm binaries, and ensure that directory's `bin` is on `PATH` when
Codex starts. List only lockfiles that already exist: on Linux, a missing
read-only path can be materialized as an empty bind-mount placeholder. Add
`npm-shrinkwrap.json` only when the project already contains it.
This profile protects only those paths at the workspace root. Managed policy
must add equivalent rules for nested package roots when they need the same
filesystem enforcement. The tool grants its own temporary resolution
directory as a preapproved, per-command write path; that does not widen access
to the project. The checked project update separately requests per-command
write access to `package.json` and `package-lock.json`; with `on-request`
approval, that request produces the user prompt.
## Current limitations
- Only non-workspace npm projects are supported.
- pnpm, Yarn, and Bun dependency additions are redirected but return an
explicit unsupported-project result from the tool.
- Git, file, workspace, HTTP, and other non-HTTPS package sources are blocked.
- Static command recognition covers common direct commands. Arbitrary shell
indirection is outside the redirect boundary and must be constrained by the
filesystem sandbox policy.
- The install phase may leave `package.json`, `package-lock.json`, or unpacked
packages changed if npm fails after the approved project mutation. Lifecycle
scripts remain disabled in those failure cases.