Repository navigation
Conversation
Bundle manifests with bundleIdentity.payloadVersion 3 canonicalize the integral payload with RFC 8785 JCS (`rfc8785-jcs-utf8`). verify-bundle-integral rejected them with "unsupported bundleIntegral.canonicalization". - Accept `rfc8785-jcs-utf8` next to the existing canonicalization, which is unchanged. - JCS orders object keys by UTF-16 code units and reuses serde_json string escaping, which matches RFC 8785 section 3.2.2.2. - Numbers are limited to integers with |n| <= 2^53 - 1, whose ES6 form is the plain decimal. Anything else is refused rather than hashed in a form the producer may not have used. - Require payloadVersion 3 for JCS and reject payloadVersion 3 with the legacy canonicalization, so a manifest cannot mix the two. Tests use the RFC 8785 section 3.2.3 sorting example and a synthetic manifest whose expected hash comes from an independent Python JCS implementation. Existing payloadVersion 1 and 2 manifests verify unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
verify-bundle-integral hashes serde_json's view of a manifest, which can differ from what other JSON parsers read: - Duplicate object keys: serde_json keeps the last one, other parsers may keep the first. A legacy manifest with a conflicting duplicate "kind" key injected in front verified as ok before this change. - Keys starting with `$serde_json::private::`: with the arbitrary_precision and raw_value features enabled in this workspace, serde_json reads such an object as a number or as embedded JSON. parse_bundle_manifest refuses both, along with numbers that are not 64-bit integers, which serde_json passes through the same reserved key. RFC 8785 requires I-JSON input, which forbids duplicate keys anyway. The bundle-identity payloadVersion now selects the canonicalization: 1 and 2 (or no bundleIdentity) use the legacy one, 3 uses JCS. Any other payloadVersion, or a bundleIdentity that is not an object, is refused instead of falling back to the legacy canonicalization. Also: - collapse a nested if in jcs_number (clippy::collapsible_if) - test the RFC 8785 section 3.2.2 string-escaping example - document the supported canonicalizations in the bundle operations doc Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cast igra verify-bundle-integralrejects manifests whosebundleIdentity.payloadVersionis 3, because their integral payload is canonicalized with RFC 8785 JCS (rfc8785-jcs-utf8):This adds JCS support and hardens how the verifier reads manifests. No signing, building or broadcasting code is touched.
JCS support
|n| <= 2^53 - 1, whose ES6 form is the plain decimal. Anything else is refused rather than hashed in a form the producer may not have used.payloadVersion selects the canonicalization
bundleIdentity: the legacy canonicalization, unchanged. 3: JCS.payloadVersion, or abundleIdentitythat is not an object is refused instead of falling back to the legacy canonicalization.Strict manifest parsing
verify-bundle-integralhashes serde_json's view of the manifest, which can differ from what other JSON parsers read. The newparse_bundle_manifestrefuses:"kind"key injected at the start verified as ok.$serde_json::private::. With thearbitrary_precisionandraw_valuefeatures enabled in this workspace, serde_json reads such an object as a number or as embedded JSON.Test plan
igra_bundlecover:cargo test --locked -p foundry-common --lib: 99 passed, 2 ignored.cargo clippy --all-targetsonfoundry-common(all features) andcastreports no findings in the changed files.cargo build --locked -p cast --no-default-features, runningverify-bundle-integralon every locally available bundle manifest:CI failures that already exist on the base branch and are not addressed here:
cargo deny(dependency advisories and licenses);-Dwarningsfindings in other files of both crates;crates/cast/src/cmd/igra.rs.🤖 Generated with Claude Code