Skip to content

feat(relay): promote attribute release to default#488

Open
jeremi wants to merge 6 commits into
mainfrom
agent/issue-487-relay-default
Open

feat(relay): promote attribute release to default#488
jeremi wants to merge 6 commits into
mainfrom
agent/issue-487-relay-default

Conversation

@jeremi

@jeremi jeremi commented Jul 25, 2026

Copy link
Copy Markdown
Member

What

  • promote governed attribute release and Crosswalk runtime to the canonical Relay feature set
  • remove inert or misleading pre-1.0 config fields and require purpose, subject type, and the exact release scope
  • apply governed redaction before release CEL, hide unauthorized profiles, and make every response non-storable
  • publish compiled feature evidence in admin capabilities and Relay image labels
  • align Registryctl authoring, generated schemas and OpenAPI, the support roster, docs, and release checks
  • derive exposure stability and default OpenAPI coverage from the Relay Cargo default-feature graph

Why

Attribute release is the maintained Notary/Relay integration path. Shipping it as an optional variant would create multiple production profiles and leave the official image unable to exercise that path. The hardening in this change closes the gaps found while reviewing promotion readiness.

The initial CI run exposed a stale assurance invariant that treated every feature-gated route as optional and experimental. The checker now permits stable routes only behind Cargo features enabled by default, while preserving the experimental requirement for optional feature gates.

Security

  • release scope and purpose remain mandatory before source reads
  • unauthorized known profiles return the same public 404 as unknown profiles
  • release predicates and computed claims see only the governed-redacted row
  • CEL expressions are limited to the projected source authority, including dotted and bracketed access checks
  • subject identifiers remain keyed audit hashes and never appear in responses
  • release responses and denials are private, no-store
  • optional feature gates remain fail-closed as experimental in the exposure manifest

Verification

  • just ci in Registry Relay
  • just ci-preflight in Registry Relay
  • just exposure-check in Registry Relay
  • python3 -m unittest tests/security_assurance_check_test.py
  • python3 scripts/check_security_assurance.py openapi-coverage
  • just openapi-contract origin/main
  • cargo test --locked -p registryctl project_authoring
  • python3 -m unittest discover -s release/scripts -p 'test_*.py'
  • npm test and npm run check in docs/site
  • supported-target cargo tree review for RUSTSEC-2023-0089

Refs #487

Follow-up release evidence

After the next Registry Stack version is published, Solmara Lab still needs to pin the official Relay image by digest and record the live journey evidence. This PR prepares and verifies the canonical binary and image contract but cannot produce that future release digest.

@jeremi
jeremi marked this pull request as ready for review July 25, 2026 15:27

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbd9f2f5d6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-relay/src/attribute_release/mod.rs Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread crates/registry-relay/src/api/openapi.rs

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e796a9fc2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/release.yml Outdated
Comment thread crates/registry-relay/Dockerfile
Comment thread crates/registry-relay/openapi/registry-relay.openapi.json Outdated
Comment thread crates/registry-relay/openapi/registry-relay.openapi.json Outdated
Comment thread docs/site/src/data/relay-support.yaml

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ce6d9c04e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/release.yml Outdated
Comment on lines +3704 to +3707
&& !value.contains(',')
&& !value
.chars()
.any(|character| character.is_control() || character.is_whitespace())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict header-bound purposes to visible ASCII

When a mandatory profile purpose contains a non-ASCII token such as identité, this validator accepts it because the characters are neither whitespace nor control characters. However, purpose_header_value reads Data-Purpose through HeaderValue::to_str(), which rejects every non-visible-ASCII byte, so no request can ever match the configured purpose and every resolution returns auth.purpose_required. Validate the header-bound purpose as visible ASCII (or define a reversible wire encoding) so an accepted profile remains usable.

Useful? React with 👍 / 👎.

Comment on lines +3801 to 3805
if !entity.api.required_filters.is_empty() {
return release_error(
"attribute_release_profiles cannot use an entity with required_filters because the caller-supplied subject cannot satisfy a principal-bound filter",
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Mirror release prerequisites in Registryctl validation

When a Registryctl records service combines an attribute-release profile with nonempty required_principal_filters, the authoring schema and validate_record_attribute_release_profiles accept it and generate the entity, but this new Relay validation rejects that generated configuration during Registryctl's production-loading check. The same mismatch occurs when the authored pagination max_limit is 1 because the adjacent Relay check requires at least 2. Add these cross-field prerequisites to Registryctl's authoring validation so schema-valid projects fail early with an actionable authoring error instead of always failing generated-product activation.

Useful? React with 👍 / 👎.

Comment on lines +106 to +108
enabled: set[str] = set()
pending = list(defaults)
while pending:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive stability from canonical release features

When a future developer-default feature is added to Cargo.toml, this checker will treat its routes as eligible for stable status and canonical OpenAPI coverage solely because it starts from features.default. The release recipe deliberately builds with --no-default-features and an explicit attribute-release,crosswalk-runtime list so developer defaults cannot expand the published binary; therefore the assurance checks could approve a stable route that is absent from the release. Derive this set from the canonical release feature profile instead of the mutable developer default.

Useful? React with 👍 / 👎.

jeremi added 5 commits July 26, 2026 11:00
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
@jeremi
jeremi force-pushed the agent/issue-487-relay-default branch from 8ce6d9c to 3740ebe Compare July 26, 2026 04:23
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 277595685d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

digest_ref="$(cat "inputs/build-a/dist/images/${name}.digest")"
expected_label_args=()
if [[ "${name}" == "registry-relay" ]]; then
relay_features="$(<crates/registry-relay/canonical-release-features.txt)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Sign off the current commit

Fresh evidence after the prior DCO comments: the rewritten commit 5d5dcdcd578d02f0dc067edb7b7b5d845a228f24 still has no Signed-off-by trailer, so the contribution gate will reject it; recreate this commit using git commit -s before merging.

AGENTS.md reference: AGENTS.md:L70-L70

Useful? React with 👍 / 👎.

}
continue;
}
if bytes[index].is_ascii_alphabetic() || bytes[index] == b'_' {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Skip CEL comments when collecting authority roots

When an otherwise valid source-only expression contains a line comment such as source.active // context.secret, the pinned CEL parser accepts the comment, but this byte scanner treats context.secret as executable member access and rejects the profile with kind=authority during configuration loading. It can also interpret apostrophes or quotes inside comments as unterminated string literals, so skip CEL comments before collecting roots and add coverage for commented expressions.

Useful? React with 👍 / 👎.

# The 1.0 default build includes the stable attribute-release surface. Release
# recipes still select the exact canonical features explicitly so changing this
# developer default cannot silently expand a published binary.
default = ["attribute-release"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound requested claims before enabling release by default

With attribute release now present in the default and canonical production builds, an authorized caller can submit a request near the 1 MiB body limit containing tens of thousands of repetitions of one valid claim name. resolve_requested_claims imposes no count or uniqueness bound, evaluates every repeated computed claim, and retains every duplicate in ar_requested_claims even though the response map ultimately deduplicates them, allowing one request to consume substantial CEL CPU and produce an oversized audit record. Limit the request to the profile's maximum of 32 unique claims and express the same bound in OpenAPI.

Useful? React with 👍 / 👎.

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