Skip to content

feat(domain-linkage): read and edit configuration entries unverified - #127

Merged
daniel-mader merged 2 commits into
mainfrom
claude/inspiring-archimedes-echxvg-did-configuration-entries
Oct 26, 2026
Merged

daniel-mader merged 2 commits into
mainfrom
claude/inspiring-archimedes-echxvg-did-configuration-entries

Conversation

@daniel-mader

@daniel-mader daniel-mader commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Closes #123.

The controller of an origin maintains the DID configuration it publishes. It renews credentials before they expire, and it unlinks an origin by dropping that origin's credentials. Both need each entry's DID, origin and expiry, read from credentials it signed itself, so verifying them again adds nothing. UniCore does this by hand today: credential_claims, credential_origin and needs_renewal in agent_identity/src/service/aggregate.rs base64-decode the payload and dig through vc.credentialSubject.

API

On DomainLinkageConfiguration:

  • entries(): each JWT entry with its position, read without verifying it as an UnverifiedLinkage, or the DomainLinkageError saying why it does not read. Entries that don't decode are reported, not skipped. Linked Data Proof entries aren't JWTs and aren't among them, as with jwts().
  • earliest_expiry(): the earliest exp among the entries that read, or None; when renewal is due at the latest.
  • remove_origin(&Url): drops the JWT entries linking that origin, compared normalized (scheme, host, non-default port; a path or trailing slash is ignored), and returns how many it dropped. Entries that don't read, and Linked Data Proof entries, are kept. linked_dids stays a public Vec, so retain covers any other predicate without new API.

UnverifiedLinkage::from_jwt(&Jwt) reads one credential:

Field From
did credentialSubject.id, which must be a DID
origin credentialSubject.origin, normalized
issuer the credential's issuer, which the format requires to be did
not_before nbf, or issuanceDate without one
expires exp, or expirationDate without one

The type's docs, and the new "Maintaining a configuration" section of the module docs, say it's for the origin's controller, never for deciding whether a DID and an origin are linked; that stays DomainLinkageValidator's job.

Shared reading

check_format read the subject DID and origin inline. Those are now two private helpers, subject_did and subject_origin, used by both the validator and UnverifiedLinkage, so the two agree on what an entry says. The validator's checks and their order are unchanged. The #[expect(clippy::similar_names)] on check_format went with the inline code.

Tests

In tests/domain_linkage.rs:

  • The specification's example resource: its Linked Data Proof entry is left out. The JWT entry reads as did:key:z6MkoTHsg…, with the origin https://identity.foundation (the example JWT writes it without a scheme), nbf 1607112739 and exp 1764879139. That exp is the earliest expiry, and from_jwt gives the same result.
  • Renewing and unlinking: a configuration with credentials for example.com (30 days) and example.org:8443 (365 days), and a JWT that isn't a credential between them.
    • entries reads the two credentials and reports the third as Validation.
    • earliest_expiry is day 30.
    • remove_origin("https://example.com/") removes exactly one, and keeps the unreadable entry and the order; removing it again removes none.
    • An origin without a host is InvalidOrigin.
    • What remains still validates for example.org:8443.
  • Why an entry doesn't read:
    • an origin that is an array is InvalidOriginProperty;
    • an origin without a host is InvalidOrigin;
    • a subject that isn't a DID is SubjectNotDid;
    • an empty configuration has no expiry.

Docs

Checks

All with rustc/clippy 1.99.1:

  • fmt;
  • clippy --all-features --all-targets -D warnings;
  • cargo hack clippy --each-feature -D warnings;
  • docs with -D warnings;
  • cargo test --all-features;
  • the --no-default-features --features did-key,software build;
  • cargo publish --dry-run;
  • cargo semver-checks ("no semver update required").

.cargo/mutants.toml pins no lines in domain_linkage, so the moved code doesn't affect it.


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added configuration tools for listing domain-linkage JWT entries, checking their validity details, and finding the earliest expiration.
    • Added the ability to remove readable JWT entries for a specified origin. Unreadable JWTs and Linked Data Proof entries remain unchanged.
    • Exposed the linkage entry information type through the credentials prelude.
  • Documentation
    • Updated feature and design documentation to describe the new configuration tools.

The controller of an origin maintains the DID configuration it
publishes: it renews credentials before they expire and unlinks an
origin by dropping its credentials. Both need each entry's DID, origin
and expiry, read back from credentials it signed itself.

`DomainLinkageConfiguration::entries` reads each JWT entry without
verifying it, as an `UnverifiedLinkage` (DID, normalized origin, issuer,
`nbf`, `exp`) or the reason it does not read. `earliest_expiry` says
when renewal is due, and `remove_origin` drops the entries of an origin,
compared normalized, keeping entries that do not read.
`UnverifiedLinkage::from_jwt` reads one credential.

The subject DID and origin are read by the same helpers
`DomainLinkageValidator` uses, so both agree on what an entry says.

Closes #123.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PB1rHNJ3YpjogEUJQYccc2
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 26 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 5435ed1 and dd90ca7.

Files selected for processing: 5
  • docs/DESIGN.md
  • docs/FEATURES.md
  • src/domain_linkage/mod.rs
  • src/prelude.rs
  • tests/domain_linkage.rs

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 33ab048 and 5435ed1.

Files selected for processing: 5
  • docs/DESIGN.md
  • docs/FEATURES.md
  • src/domain_linkage/mod.rs
  • src/prelude.rs
  • tests/domain_linkage.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

Adds unverified JWT linkage views and configuration methods to enumerate entries, find their earliest readable expiry, and remove entries for a normalized origin. Unreadable JWTs and Linked Data Proof entries remain in the configuration during removal.

Changes: Domain linkage configuration maintenance

Layer / File(s) Summary
Unverified JWT linkage view
src/domain_linkage/mod.rs, tests/domain_linkage.rs
Adds UnverifiedLinkage::from_jwt to decode the subject DID, normalized origin, issuer, issuance date, and optional expiration without verification. Shared helpers now parse the subject DID and origin in check_format. Tests cover invalid subjects and origins.
Configuration inspection and removal
src/domain_linkage/mod.rs, src/prelude.rs, tests/domain_linkage.rs, docs/DESIGN.md, docs/FEATURES.md
Adds entries, earliest_expiry, and remove_origin. The prelude exports UnverifiedLinkage. Tests cover entry parsing, expiry lookup, and origin removal. The design and feature documentation describe these operations.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Controller
  participant DomainLinkageConfiguration
  participant UnverifiedLinkage
  participant decode_credential
  Controller->>DomainLinkageConfiguration: Call entries
  DomainLinkageConfiguration->>UnverifiedLinkage: Parse each JWT with from_jwt
  UnverifiedLinkage->>decode_credential: Decode credential JWT
  decode_credential-->>UnverifiedLinkage: Return decoded credential or error
  UnverifiedLinkage-->>DomainLinkageConfiguration: Return linkage value or error
  DomainLinkageConfiguration-->>Controller: Return indexed entry results
  Controller->>DomainLinkageConfiguration: Call remove_origin
  DomainLinkageConfiguration-->>Controller: Return number of removed entries
Loading

Possibly related PRs

Merge Risk: Minimal · previous review 5435e

The configuration-maintenance APIs appear ready to merge after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 3 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: reading and editing domain-linkage configuration entries without verification.
Linked Issues check Passed Issue #123 is open and directly linked. The PR adds DomainLinkageConfiguration::entries() with indexed success or DomainLinkageError results, earliest_expiry(), and normalized remove_origin().…
Out of Scope Changes check Passed The changes stay within issue #123. The source changes implement unverified entry reading, expiry inspection, origin removal, shared parsing, and the requested public re-export. The tests verify those…
Full details: Linked Issues check

Explanation

Issue #123 is open and directly linked. The PR adds DomainLinkageConfiguration::entries() with indexed success or DomainLinkageError results, earliest_expiry(), and normalized remove_origin(). UnverifiedLinkage::from_jwt() reads the subject DID, origin, issuer, nbf, and exp without verification. The shared parsing helpers keep validator and unverified parsing consistent. The PR documents the controller maintenance use case and keeps validation as the security decision. Tests cover the specification example, malformed entries, earliest expiry, normalized removal, retained unreadable entries, order preservation, and empty configurations. FEATURES.md contains the requested issue row.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #123. The source changes implement unverified entry reading, expiry inspection, origin removal, shared parsing, and the requested public re-export. The tests verify those APIs and error cases. The module, design, and feature documentation describe the same maintenance behavior. No unrelated product behavior is identified.

Full details: Docstring Coverage

Explanation

Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 3 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codecov

codecov Bot commented Oct 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.55556% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/domain_linkage/mod.rs 95.55% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@daniel-mader
daniel-mader merged commit 9a03d12 into main Oct 26, 2026
32 checks passed
@daniel-mader
daniel-mader deleted the claude/inspiring-archimedes-echxvg-did-configuration-entries branch October 26, 2026 22:32
This was referenced Oct 26, 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.

Read and edit the entries of your own DID configuration without verifying them

2 participants