Skip to content

feat(resolver): trust staged publishes#810

Merged
jdx merged 5 commits into
mainfrom
feat/staged-publish-trust
May 31, 2026
Merged

feat(resolver): trust staged publishes#810
jdx merged 5 commits into
mainfrom
feat/staged-publish-trust

Conversation

@jdx

@jdx jdx commented May 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • parse npm staged-publish approver metadata from version packuments
  • rank staged publish approval above trusted publishers and provenance in trustPolicy=no-downgrade
  • document the expanded trust-evidence order

Tests

  • cargo fmt --check
  • cargo test -p aube-registry approver_metadata_is_extracted
  • cargo test -p aube-resolver trust::tests
  • git diff --check
  • cargo check -p aube

This PR was generated by Codex.


Note

Medium Risk
Changes install-time trust enforcement and may block installs when newer versions lack approver but older releases had staged approval; behavior is covered by expanded trust tests and docs.

Overview
Adds npm staged-publish support to trust policy: packument parsing now keeps an optional approver field on version metadata, and trustPolicy=no-downgrade treats it as the strongest signal (staged publish > trusted publisher > provenance).

The resolver’s evidence_for / check_no_downgrade logic ranks StagedPublish first, validates approver with tolerant shape checks (empty/null objects do not count), and stops scanning older versions early once staged publish is found. Primer-sourced metadata still sets approver: None. Settings and security docs describe the new evidence order; tests cover parsing, ranking, downgrades, and malformed approver values.

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

Comment thread crates/aube-resolver/src/trust.rs
@greptile-apps

greptile-apps Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces npm staged-publish approval as a new top-tier trust evidence source (StagedPublish, rank 3) above TrustedPublisher (2) and Provenance (1) in the no-downgrade trust policy. The approver field is parsed from packuments as a raw serde_json::Value and validated by a recursive truthy check (is_approver), and the early-exit optimisation in the prior-version scan is correctly updated to break on StagedPublish rather than TrustedPublisher.

  • VersionMetadata gains an optional approver: Option<serde_json::Value> field (deserialized via #[serde(default)]); all call sites that construct metadata by hand set it to None.
  • is_approver uses a recursive truthy walk — Null/false/0/""/empty arrays/all-null objects all return false; any non-empty leaf value returns true — with comprehensive tests covering boundary cases that were raised in prior review rounds.
  • Docs (security.md, settings/index.md, settings.toml) are updated to document the new three-tier order.

Confidence Score: 5/5

Safe to merge. The trust-policy logic is correct, the is_approver edge cases raised in earlier review rounds are all addressed, and the test suite covers the full boundary space.

The recursive is_approver correctly rejects Bool(false), [null], [""], [{},{}] and all-null objects — the edge cases flagged in previous review threads are now exercised by evidence_empty_approver_is_none. The early-exit break condition is correctly moved from TrustedPublisher to StagedPublish (the new maximum rank), so no correctness gap exists there. The approver field flows cleanly from VersionMetadataRaw through VersionMetadata with no conversion logic that could introduce mismatches. All struct call sites are updated. No new issues found.

No files require special attention. crates/aube-resolver/src/trust.rs carries the main logic change and is well covered by the new and existing tests.

Important Files Changed

Filename Overview
crates/aube-resolver/src/trust.rs Core logic change: adds StagedPublish (rank 3) as highest trust tier, implements is_approver with recursive truthy check, updates early-exit break condition from TrustedPublisher to StagedPublish. Previous thread issues (Bool(false), [null]/[false] arrays, empty-object asymmetry) are all addressed and covered by comprehensive tests.
crates/aube-registry/src/lib.rs Adds optional approver field to VersionMetadata and VersionMetadataRaw with #[serde(default)], wires through the From conversion, adds a deserialize test for the new field.
crates/aube-resolver/src/primer.rs Sets approver: None when constructing VersionMetadata from primer data; primer intentionally does not synthesise staged-publish evidence.
crates/aube-resolver/src/tests.rs Adds approver: None to the make_version helper to satisfy the updated struct — mechanical update only.
crates/aube/src/commands/audit.rs Adds approver: None to the hand-built VersionMetadata in the audit test fixture — mechanical struct update.
crates/aube-settings/settings.toml Documentation update to reflect the new three-tier evidence ordering; no logic change.
docs/security.md Adds npm staged publish approval as tier 1 in the ordered evidence list; renumbers existing entries.
docs/settings/index.md Docs mirror of the settings.toml change, updated to reflect three-tier evidence ordering.

Reviews (5): Last reviewed commit: "docs(settings): regenerate trust policy ..." | Re-trigger Greptile

Comment thread crates/aube-resolver/src/trust.rs
Comment thread crates/aube-resolver/src/trust.rs Outdated

@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 fe39891. Configure here.

|| n.as_u64().is_some_and(|u| u != 0)
|| n.as_f64().is_some_and(|f| f != 0.0)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Loose approver object validation

Medium Severity

is_approver treats any non-empty object with at least one non-null JSON value as top-tier staged-publish evidence, so shapes like an empty name string or nested empty objects can qualify even though sibling checks require a non-empty trusted-publisher id or a valid SLSA predicateType.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fe39891. Configure here.

Comment thread crates/aube-resolver/src/trust.rs Outdated
@jdx jdx force-pushed the feat/staged-publish-trust branch from fe39891 to a28855f Compare May 31, 2026 14:33
@jdx jdx merged commit 343f43a into main May 31, 2026
18 checks passed
@jdx jdx deleted the feat/staged-publish-trust branch May 31, 2026 15:04
This was referenced May 31, 2026
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