Skip to content

fix(scripts): require source keys for build approvals#858

Merged
jdx merged 4 commits into
mainfrom
codex/allowbuilds-identity
Jun 11, 2026
Merged

fix(scripts): require source keys for build approvals#858
jdx merged 4 commits into
mainfrom
codex/allowbuilds-identity

Conversation

@jdx

@jdx jdx commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary

  • require exact source approval keys for source-backed dependency builds
  • keep bare package-name allowBuilds scoped to registry packages
  • carry source-aware build decisions into ignored-builds and GVS hashing

Tests

  • cargo test -p aube-scripts policy
  • cargo test -p aube-lockfile graph_hash
  • cargo clippy -p aube-scripts -p aube-lockfile -- -D warnings
  • cargo clippy -p aube -- -D warnings

Note

High Risk
Changes security-sensitive lifecycle script gating and can alter virtual-store graph hashes for local/git deps; installs may skip builds or use new store paths until policies use source keys.

Overview
Source-backed dependencies (file:, git:, tarballs, etc.) no longer inherit lifecycle build approval from bare package names or name@semver pins. They must be explicitly allowed via exact lockfile source keys (e.g. esbuild@file+abc123), parsed into separate allowed_sources / denied_sources sets in BuildPolicy. LockedPackage::source_approval_key() supplies that key (peer suffix stripped); install, ignored-builds, jail checks, and strict-dep-build prompts all call decide_package with it.

Graph hashing now takes a full LockedPackage in the allow-build callback and folds local source specifiers into full_pkg_id, so different file/git bytes at the same manifest version get distinct virtual-store hashes (with cascade to parents).

Integration tests expect workspace onlyBuiltDependencies by name to skip file: postinstalls until a source key is approved, and strict-dep-build messages to reference pkg@file+… identities.

Reviewed by Cursor Bugbot for commit 0c00d92. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Treats source-backed packages (git/file/local) as distinct exact items and exposes a source-approval key for non-registry packages.
  • Refactor

    • Source keys are threaded through approval, jail checks, lifecycle steps, and package-aware graph-hash computation/allow checks.
  • Behavior

    • Graph hashes can change for packages that differ by local source or patch identity.
  • Tests

    • Updated lifecycle and policy tests to reflect source-key semantics and revised outputs.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends the build-policy approval system to support source-backed packages. It updates the AllowBuildFn callback to accept full LockedPackage objects, adds source-approval-key extraction, introduces dedicated allow/deny rule tracking for source-backed packages, and threads those keys through build-lifecycle and hash-computation decisions.

Changes

Source-backed package approval in build policies

Layer / File(s) Summary
AllowBuildFn callback signature change
crates/aube-lockfile/src/graph_hash.rs
Type signature updated from (name: &str, version: &str) -> bool to (&LockedPackage) -> bool; call sites and test closures adjusted to match.
Package identity for hashing
crates/aube-lockfile/src/graph_hash.rs
full_pkg_id updated to include local_source via a :source:<specifier> segment and patch/integrity formatting adjusted; test imports updated for source fixtures.
Source approval key extraction
crates/aube-lockfile/src/lib.rs
New LockedPackage::source_approval_key() method computes an approval key for source-backed packages by stripping peer-context suffixes from dep_path.
Build policy source-backed rule storage
crates/aube-scripts/src/policy.rs
BuildPolicy gains allowed_sources and denied_sources sets to track exact source-backed package approvals separately from registry-based rules; initialization and field storage updated.
Allow/deny entry expansion and sorting
crates/aube-scripts/src/policy.rs
sort_entries refactored to classify entries into wildcard, source-key, and exact-match buckets; expand_spec recognizes single source-version specs and helper predicates detect source-backed shapes.
Build policy decision API for source-backed packages
crates/aube-scripts/src/policy.rs
New decide_package(name, version, source_key) public method with early deny and exact source-key allow semantics; decide(name, version) delegates to it; has_any_allow_rule and merge updated.
Source-backed policy decision tests
crates/aube-scripts/src/policy.rs
Unit tests verify bare-name allows don’t authorize source-backed packages without an exact source key, exact source keys authorize, and source-backed denies override allows.
Policy application in build lifecycle
crates/aube/src/commands/install/lifecycle.rs
BuildJob gains source_key: Option<String>; JailBuildPolicy::should_jail/jail_for accept optional source_key; lifecycle allowlisting and jail decisions use decide_package, and unreviewed_dep_builds uses source_approval_key() for spec keys.
Graph hash computation predicates
crates/aube/src/commands/install/link.rs, crates/aube/src/commands/install/materialize.rs
allow predicates passed to compute_graph_hashes_with_patches updated to accept LockedPackage and call decide_package with source approval keys.
Ignored build collection policy integration
crates/aube/src/commands/ignored_builds.rs
collect_ignored updated to evaluate package approval via decide_package with the package's source_approval_key().

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A rabbit hops through build policies,
Where source-backed locks need sharper keys—
Packages whisper where peers once hid,
Keys trimmed clean so decisions are bid,
Hops, hashes, approves — the burrow is rid.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: requiring source keys for build approvals, which is the core security-sensitive feature introduced across the build policy, lockfile, and installation systems.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread crates/aube-lockfile/src/lib.rs
@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Source-backed dependencies (file:, git:, tarball, etc.) now require an exact lockfile-shaped key (e.g. pkg@file+abc123) in allowBuilds; bare-name and name@version approvals are restricted to registry packages. full_pkg_id in the graph hasher folds local_source.specifier() so local/git deps with identical manifest versions no longer collapse onto the same virtual-store hash.

  • BuildPolicy gains allowed_sources/denied_sources sets and decide_package(name, version, source_key) with a short-circuit after allow_all that bypasses registry allow-checks when a source key is present; source_approval_key() on LockedPackage returns None for registry (including registry_git_hosted) packages and the peer-suffix-stripped dep_path for source-backed ones.
  • All install call sites — run_dep_lifecycle_scripts, unreviewed_dep_builds, collect_ignored, both graph-hash closures — are threaded through decide_package; the unreviewed-build prompt now surfaces the source-keyed form users must add to allowBuilds.
  • The bats test for workspace-member bare-name approval is inverted to assert the marker does not exist, reflecting the new requirement for an explicit source key.

Confidence Score: 5/5

The change is safe to merge; the security model is internally consistent and all install/ignored-builds/graph-hash call sites have been updated.

The logic is well-structured and the registry_git_hosted concern from the prior thread is addressed. Both findings are stylistic/test-coverage gaps, not functional regressions. The bats tests were updated to match the new behavior, and new unit tests cover the primary approval scenarios.

No files require special attention; the two observations are in policy.rs.

Important Files Changed

Filename Overview
crates/aube-scripts/src/policy.rs Core change: adds allowed_sources/denied_sources sets and decide_package(name, version, source_key) so source-backed packages require exact source keys; bare-name and versioned allows short-circuit before the source key check making them inert for source deps.
crates/aube-lockfile/src/lib.rs Adds source_approval_key() returning None for registry/registry_git_hosted packages (guarded by local_source.as_ref()?) and the peer-suffix-stripped dep_path for source-backed packages; new unit tests confirm both cases.
crates/aube-lockfile/src/graph_hash.rs Widens AllowBuildFn from (&str, &str) to (&LockedPackage) and folds local_source.specifier() into full_pkg_id as :source:… so local/git deps with the same manifest version produce distinct VGS hashes; new cascade test verifies.
crates/aube/src/commands/install/lifecycle.rs Threads source_key through the job struct and all decide_package call sites (policy check, jail check, unreviewed-builds prompt); spec_key in unreviewed output now shows the source-keyed form so users know exactly what to add to allowBuilds.
crates/aube/src/commands/ignored_builds.rs Single-line change to use decide_package with source_approval_key() so ignored-build collection respects source identity.
test/lifecycle_scripts.bats Inverts the workspace-member bare-name test to assert the marker does NOT exist, adds assertion on the source-keyed prompt string, and updates two strict-dep-builds tests to expect dep-with-build@file+ in output.

Reviews (3): Last reviewed commit: "test(install): update source build appro..." | Re-trigger Greptile

Comment thread crates/aube-lockfile/src/lib.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/aube/src/commands/ignored_builds.rs (1)

150-162: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Source-backed variants are still collapsed before the source-key decision.

collect_ignored now makes a source-aware decide_package(...) call, but seen still dedupes on (pkg.name, pkg.version) first. That collapses distinct file+/git+ variants that share a version but have different source_approval_key() values, so whichever variant is iterated first decides whether the entry is reported. In practice this can hide an ignored source-backed build, and approve-builds inherits the same blind spot because it reuses this list.

Please switch the ignored-build identity/dedup key to the exact approval identity (source_approval_key() when present, otherwise the existing registry key) instead of (name, version).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aube/src/commands/ignored_builds.rs` around lines 150 - 162, The dedup
key currently stored in seen (used in collect_ignored) collapses source-backed
variants by using (pkg.name, pkg.version); change the key to use the package
approval identity: compute an approval_key =
pkg.source_approval_key().unwrap_or_else(|| format!("{}:{}",
pkg.registry_name(), pkg.version)) and use that approval_key (and
version/registry as needed) in the BTreeSet insert/check instead of (pkg.name,
pkg.version), so each unique source_approval_key() is considered distinct before
calling policy.decide_package and emitting IgnoredEntry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aube-lockfile/src/lib.rs`:
- Around line 391-399: source_approval_key() currently returns Some(dep_path)
whenever registry_git_hosted is true which produces keys that BuildPolicy
(crates/aube-scripts/src/policy.rs) never recognizes; restrict
source_approval_key() to only return a key for dep_paths that are actually
source-backed by checking dep_path prefixes used by the policy parser (e.g.
"file+", "link+", "portal+", "exec+", "git+", "url+") and return None otherwise
(preserve the existing split_once('(') trimming for those valid prefixes); this
keeps the approval key vocabulary aligned with BuildPolicy's allowed_sources
handling.

---

Outside diff comments:
In `@crates/aube/src/commands/ignored_builds.rs`:
- Around line 150-162: The dedup key currently stored in seen (used in
collect_ignored) collapses source-backed variants by using (pkg.name,
pkg.version); change the key to use the package approval identity: compute an
approval_key = pkg.source_approval_key().unwrap_or_else(|| format!("{}:{}",
pkg.registry_name(), pkg.version)) and use that approval_key (and
version/registry as needed) in the BTreeSet insert/check instead of (pkg.name,
pkg.version), so each unique source_approval_key() is considered distinct before
calling policy.decide_package and emitting IgnoredEntry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 61a5b942-c0d0-4b07-9708-c4d8e17cb618

📥 Commits

Reviewing files that changed from the base of the PR and between 60ba8b5 and 0035dd8.

📒 Files selected for processing (7)
  • crates/aube-lockfile/src/graph_hash.rs
  • crates/aube-lockfile/src/lib.rs
  • crates/aube-scripts/src/policy.rs
  • crates/aube/src/commands/ignored_builds.rs
  • crates/aube/src/commands/install/lifecycle.rs
  • crates/aube/src/commands/install/link.rs
  • crates/aube/src/commands/install/materialize.rs

Comment thread crates/aube-lockfile/src/graph_hash.rs
Comment thread crates/aube-lockfile/src/lib.rs

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8f5144c. Configure here.

Comment thread crates/aube-scripts/src/policy.rs
@jdx jdx merged commit 40f66e4 into main Jun 11, 2026
18 checks passed
@jdx jdx deleted the codex/allowbuilds-identity branch June 11, 2026 19:47
@cursor cursor Bot mentioned this pull request Jun 11, 2026
colinhacks added a commit to nubjs/aube that referenced this pull request Jun 12, 2026
…val jdx#858/jdx#860

Merge (not rebase) of jdx/aube main @ ab844b5 into nub-integration.
Resolved 9 conflicts preserving nub's embedder behavior:

- errors.rs / error-codes.data.json: kept nub's lockfile codes
  (OUTDATED/DECLARATION_MISMATCH/AMBIGUOUS, exit 13/14/15) AND took
  upstream's ERR_AUBE_RESOLUTION_SHAPE_MISMATCH, reassigning its
  exit code 13->16 to avoid colliding with nub's OUTDATED_LOCKFILE.
- aube-scripts/lib.rs: ScriptSettings carries BOTH nub's
  env_overlay/path_prepends embedder overlay AND upstream's
  node_bin_dir/node_exe; run_script composes both PATH layers.
- script_settings.rs: carry-forward embedder overlay + upstream runtime.
- lifecycle.rs / default_trust.rs: adopt jdx#860 decide_package(source_key)
  AND keep nub's defaultTrust floor (Unspecified => floor.trusts) arm;
  decide_with_floor now threads the source key internally.
- install/mod.rs + resolve.rs: kept nub's default_lockfile_kind seam,
  added upstream's refresh_lockfile_pin (inert under nub).
- startup.rs: kept nub's configurable PackageManagerNames policy,
  folded in upstream's managePackageManagerVersions self-switch guard.
- main.rs stays nub's thin lib-wrapper; ported jdx#861 CLI surface
  (Runtime subcommand, self_version::maybe_switch) into lib.rs;
  added mod runtime / mod self_version to lib.rs.

jdx#861 dormancy gate (the one aube behavior change, default==upstream):
runtime::set_runtime_switching_enabled(bool) OnceLock, default TRUE.
ensure / ensure_for_cwd / refresh_lockfile_pin short-circuit to
path_fallback when false, before any .nvmrc/.node-version/devEngines
read. Re-exported from lib.rs; nub flips it false so aube's runtime
resolver stays compiled-but-inert and nub keeps owning Node.

Tests: aube cargo test 1965 passed / 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant