Repository navigation
feat!: conform to the v1 context — issuerScope, StatementCredential, predicate acceptance - #33
Merged
Merged
Conversation
…predicate acceptance (0.12.0) DTG Core Credentials (Working Draft 0.6.0) moves every credential onto the frozen https://registry.trustoverip.org/dtg/context/v1, makes issuerScope REQUIRED, and replaces the EndorsementCredential and WitnessCredential subtypes with one StatementCredential whose meaning is its predicate. Credentials issued before the Implementers Draft are not conformant, so this is a clean wire break with no legacy alias. - Context: the W3C context first and DTG_CONTEXT_V1 second, exact strings; the firstperson.network context is refused. `type` must hold VerifiableCredential, DTGCredential and exactly one concrete subtype (PersonhoodCredential only as a hint on a VMC). The WD01 `digest` alias is gone. - IssuerScope { Pairwise, Directed, Public }: REQUIRED top-level member, taken by every constructor; the community-issued VMC is always `public`, enforced at parse and in validate(). - StatementCredential: CredentialSubjectStatement { id, predicate, object, witnessContext? }, StatementObject { Id, DigestMultibase, Value }, predicate IRI validation (absolute, no CURIEs, NFC). new_vsc plus profile constructors for endorses/1, witnessed/1 (ports new_vwc_for_session, reading the subject and digest from the edge credential), vetted/1 and presented/1; core profile constraints (object kind, taskContext + taskDigestMultibase, minimum issuerScope) enforced at parse, validate and sign; subject-object checks witnesses_issuance_of / witnesses_presentation_of. - PredicateAcceptList: fail-closed exact-match acceptance, from IRIs or from the registry's accept-list.json with a status floor, applying entry constraints. - VAC: authority.maxAttenuation (a spec-conformant VAC carrying it previously did not parse), enforced at attenuation and in verify_chain per link and per ancestor; new_community_role_vac for role grants as `role:<name>` actions. - Removed: EndorsementCredential, WitnessCredential, RCardCredential and their constructors and subject structs; the deprecated new_member_vmc and new_delegate_vdc; Default for DTGCommon. - validate() re-runs the parse checks, so a credential mutated out of shape is never signed. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
This was referenced Sep 30, 2026
The registry stopped tagging releases, so accept-list.json is dropping revision and verifiers pin commit or the list digest instead. Read the envelope leniently (build metadata is not a constraint) and keep predicate entries strict, where an unknown member may be a constraint to fail closed on. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Contributor
Author
|
Re the registry cleanup that drops Predicate entries stay strict, so an unknown member there still fails closed. The crate therefore loads the list both before and after the cleanup, and the two PRs can land in either order. |
This was referenced Sep 30, 2026
stormer78
marked this pull request as ready for review
September 30, 2026 15:31
Contributor
Author
|
Taken out of draft. OpenVTC/openvtc#397 builds and passes its full suite (1722 tests) against this branch, and OpenVTC/verifiable-trust-infrastructure#1859 is migrated onto it. The release order is:
|
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 30, 2026
…worktrees Builds the workspace against the unreleased dtg-credentials 0.12 (OpenVTC/dtg-credentials#33, local worktree) and the trust-tasks crates regenerated from the DTG VSC conformance specs (trustoverip/dtgwg-trust-tasks-tf feat/dtg-vsc-conformance, local worktree): trust-tasks-rs, -capability-client, -https, -didcomm, -tsp and -proof, with the lockfile moved onto the patched 0.24.8 copies. Drop this commit once both are released, and raise the workspace's `dtg-credentials` requirement to the released 0.12 (the unreleased worktree still carries version 0.11.0, which is why the requirement is left at "0.11" here). Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
Merged
stormer78
added a commit
that referenced
this pull request
Sep 30, 2026
Cuts 0.12.0: conformance to the DTG Credentials Core Specification WD 0.6.0 and its frozen v1 context (#33). - Cargo.toml: 0.11.0 -> 0.12.0 - CHANGELOG.md: [Unreleased] moves under [0.12.0] - 2026-09-30 No code changes. Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 30, 2026
…ing 0.31 Replaces the local-path patch with the released crates: - dtg-credentials 0.12 (OpenVTC/dtg-credentials#33) - the trust-tasks-* family at 0.25 (trustoverip/dtgwg-trust-tasks-tf#691) - affinidi-tdk 0.21, affinidi-messaging-sdk 0.31, -mediator-admin 0.6 and -test-mediator 0.15 (affinidi/affinidi-tdk-rs#908), which move to trust-tasks 0.25 so the graph holds one copy Cargo.lock follows once affinidi-tdk-rs#908 publishes.
stormer78
added a commit
to OpenVTC/verifiable-trust-infrastructure
that referenced
this pull request
Sep 30, 2026
…ments, IDVCs, issuerScope (#1859) * feat(vta-sdk)!: vetting statements are vetted/1 VSCs; role credentials are VACs Conform the SDK's vetting artifacts to the DTG Credentials Core Specification (v1 context, `issuerScope`) and the DTG VSC predicate registry, following the regenerated vetting specifications (dtgwg-trust-tasks-tf feat/dtg-vsc-conformance). Vetting Statement (vetting/session/0.1): no longer an EndorsementCredential. `sign_statement` builds a StatementCredential with `new_vetted_vsc` under `https://registry.trustoverip.org/dtg/vsc/vetted/1`; the body is `credentialSubject.object.value`, with no `type` member. `taskContext` and `taskDigestMultibase` are both read from the `vetting/session` document, which `StatementDraft::session` now carries in place of `task_context`, and `StatementDraft::issuer_scope` is `directed` or `public` (pairwise is refused by the profile). `verify_statement` parses through `dtg-credentials`, so the v1 context, the one-subtype rule and the profile are checked by the code that issues them; `VerifiedVettingStatement::check_against_session` binds a statement to the session document by id and task digest. - `IdentityVettingEndorsement` -> `VettedObjectValue` (no `type`; digests and commitment must be base58btc, as the registry schema requires). - `IDENTITY_VETTING_ENDORSEMENT_TYPE` -> `VETTED_PREDICATE`. - `VerifiedVettingStatement::endorsement()` -> `value()`; new `issuer_scope()`, `task_digest_multibase()`. Vetter role credential (vtc/vetting/vetters/grant/0.1, vetting/request/0.1): a community-issued VAC, `issuerScope` public, `authority` { scope: <community DID>, actions: ["role:vetter"], maxAttenuation: 0 }. `eligibility::community_role` -> `community_roles`, returning every `role:<name>` of a VAC the community issued in its own scope with no parent; `verify_eligibility_vp` parses the VAC strictly and refuses a non-public scope or an attenuation. - `COMMUNITY_ROLE_ENDORSEMENT_TYPE` removed; new `ROLE_ACTION_PREFIX`, `VETTER_ROLE_ACTION`, `role_action`, `role_of_action`. - `protocols::members::ENDORSEMENT_CREDENTIAL_TYPE` removed; new `AUTHORITY_CREDENTIAL_TYPE` and `STATEMENT_CREDENTIAL_TYPE`. - `VerdictWith::role_vec` -> `role_vac` (wire `roleVac`). vtc-client: `role_vec` -> `role_vac` on `DecideResult`, `MemberRenewal`, `MemberRotated` and `PersonhoodRevocation`, matching the `roleVac` rename in vtc/join-requests/decide, vtc/members/{renew,rotate} and vtc/members/personhood/*. vti-common: `MembershipRenewedData::role_vec_id` and `DidRotatedData::role_vec_id` -> `role_vac_id` (wire `roleVacId`, reading `roleVecId` on older rows). The `VecIssued` envelope keeps its name, which SIEM rules key on; it now records role VACs and statement VSCs, named by `credentialType`. Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * feat(vta-service)!: room credentials declare issuerScope under the DTG v1 context Adopt dtg-credentials 0.12 across the room surfaces — vta-service's `rooms/owner/*` handlers and room oracle, vti-rooms-dtg and vti-rooms-wasm. Every DTG credential they mint now carries the v1 context (`https://registry.trustoverip.org/dtg/context/v1`) and a top-level `issuerScope`, chosen for what the identifier truthfully is: - `public` where a room issues as itself — the invitation (VIC) from `rooms/owner/invite` and the root VAC from `rooms/owner/issue-authority`. The room's DID is the scope every verifier of a room credential already resolves. - `directed` for every attenuation — a member narrowing a room grant to a presentation leaf (`room_oracle::present`, vti-rooms-wasm `MemberIdentity::present`). The member issues under the DID the room admitted: one identifier recognised by the room, its host and the agent, neither per-counterparty nor a public identity. Attenuations pass `max_attenuation: None`, taking the library default under the parent's bound. No room code used the retired endorsement, witness or r-card types. Two test fixtures carried the old endorsement type name as a plain string: an SD-JWT `vct` in vta-vault (now `SkillEndorsement`) and an opaque vault entry in vta-service's persona tests (now `StatementCredential`). Wire change, no API change: a VIC or root VAC from `rooms/owner/*`, and a presentation leaf from the room oracle or the browser, now carry `issuerScope` and the v1 context, and 0.11 verifiers refuse them. Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * feat(vtc-service)!: issue and verify DTG v1 credentials — role VACs, statement VSCs, IDVCs Every DTG credential the VTC issues, verifies or documents now conforms to the DTG Credentials Core Specification's v1 context and the DTG VSC predicate registry, following the regenerated Trust Tasks (dtgwg-trust-tasks-tf feat/dtg-vsc-conformance). Built on dtg-credentials 0.12. Common structure (credentials::ingress::classify_dtg): `@context` is exactly `[credentials/v2, https://registry.trustoverip.org/dtg/context/v1]` in that order (the firstperson.network context is refused, no alias), `issuerScope` is REQUIRED, `type` carries exactly one concrete subtype (the library's rule, so retired types are refused by name), and a statement is held to its predicate profile. Everything the VTC mints is built through the catalog and validated before signing; the community always declares `issuerScope` `public`. - VIC: `issuerScope: public`. - VMC grant: `public` (fixed by the catalog). Member acknowledgement (members/inbound_vmc): any declared scope accepted; the stored grant it binds to must be `public`; the Working Draft 01 `digest` spelling is no longer read. - Role grants (credentials::vac, was vec): a VAC from `new_community_role_vac` — `authority` { scope: community DID, actions: ["role:<VtcRole wire>"], maxAttenuation: 0 }. The vetter grant is `role:vetter` (vtc/vetting/vetters/grant/0.1), recorded as an endorsement row of type `role:vetter` so vtc/endorsements/revoke keeps revoking it. `CommunityRole` is gone. Cross-community recognition (vtc/auth/recognise/0.2) takes a role VAC + VMC, requires scope == issuer and no parent, reads the role from the first `role:` action, and hands `cross_community_roles.rego` `input.foreign_vac` (was `foreign_vec`). - Vetting Statements: counted only as `vetted/1` VSCs verified by vta-sdk, picked by predicate, and only under a predicate the community accepts (new failure `predicate-not-accepted`); eligibility reads the `role:vetter` grant rows. - Witness (credentials::witness): a VWC is a `witnessed/1` VSC, classified by predicate, digest read from `object.digestMultibase`; a digest naming an edge whose issuer is not the statement's subject is the new binding state `subjectMismatch`. `taskContext` requirement derives from the predicate profile (task_context:: requirement_for_predicate). The ceremony `Credential` fact gains `predicate`, and DI credentials report their concrete subtype as `type` instead of `DTGCredential`. - Identity verification (credentials::idvc): a plain W3C VC, `["VerifiableCredential", "IdentityVerificationCredential"]`, v2 context only, issued by the community on its revocation list. Issued through vtc/endorsements/issue/0.1 with the reserved typeUri `IdentityVerificationCredential` — no registration — and revoked like any row. That reuse diverges from the task's "mints a VSC" text; it is recorded in docs/03-vtc/personhood-and-graph.md pending a dedicated task. personhood.rego accepts it when issuer is the community and the subject the applicant; its witness rule matches the `witnessed/1` predicate. A workspace-authored personhood default that refuses a bound v1 witness, or admits an unbound one, is upgraded at boot (policy::default::upgrade_stale_personhood_default). - Endorsement types → predicate accept list: a registered `typeUri` must be a predicate IRI (`invalidUri` otherwise); `role:vetter` and the IDVC type are reserved. The four core registry predicates are seeded once at boot (a marker keeps deletions deleted). endorsement_types::accept_list builds a fail-closed `PredicateAcceptList`, applied to vetting statements, join presentations and personhood assertions. vtc/endorsements/issue/0.1 mints a VSC (predicate = typeUri, object.value = claim, validated against the claimSchema) and refuses a predicate whose profile needs `taskContext` with `predicateNotIssuable`. Schema-registry defaults are Membership/Authority/Statement/Invitation plus the IDVC. - Relationships: VRCs and VPCs must declare `issuerScope`; the Rego `identifier_form` is read from it (pairwise → pairwise, directed | public → attributed) and the raw `issuer_scope` is passed too. A `pairwise` VRC under the caller's membership DID is refused. - Renames on the wire and in storage: `roleVec` → `roleVac` (join decide, members renew/rotate/personhood, ceremony verdicts), `currentRoleVecId`/`currentRoleVec` → `currentRoleVacId`/ `currentRoleVac`, endorsement row `vecId` → `credentialId`; stored rows keep reading under the old names. Also: admin-ui (vetting predicate, `role:vetter` rows, a `holds_trusted_statement` rule condition and `statement_trusted` helper, openapi.json + wire.ts regenerated); `cnm member endorse` help; vti-vetting-pcs fixture statementType; pseudonym extraction reads only `credentialSubject.pseudonym`. Wire break with no upgrade ordering: 0.11-era credentials are refused and existing role grants, statements and vetter grants must be re-issued. Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * docs: describe the DTG v1 credential shapes the VTI issues and verifies Rewrite the operator and design docs, and the local trust-tasks folder, for the conformance change: role credentials are VACs (`role:<name>`, maxAttenuation 0), Vetting Statements are `vetted/1` VSCs, witnesses are `witnessed/1` VSCs classified by predicate, the identity-verification credential is a plain W3C VC issued through the reserved `IdentityVerificationCredential` typeUri (recorded as a divergence from vtc/endorsements/issue/0.1), endorsement types are the community's fail-closed predicate accept list, and a VRC's `issuerScope` sets the Rego `identifier_form` (pairwise → pairwise, directed | public → attributed). The ceremony rule-IR docs and examples gain the `predicate` fact and `statement_trusted(p)`. trust-tasks/: recognise/1.0 describes the role VAC + VMC instead of the `Verifiable`-prefixed names; join-requests/accept/1.0 replaces `MembershipAcknowledgement` with the member-issued VMC; `roleVec` → `roleVac`; relationships 1.0 `supersededBy` now names the 0.2 versions the Rust serves. Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * fix(vta-sdk): community_roles parses a role VAC as strictly as verify_eligibility_vp `vetting::eligibility::community_roles` read the raw JSON while `verify_eligibility_vp` parses through dtg-credentials, so a wallet could pick a candidate the verifier then refused as malformed. It now parses the credential with the same strict DTG parse (v1 context, one subtype, declared issuerScope) before reading `authority`. Signature unchanged; credentials that are not conformant DTG VACs now yield None. Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * test(vtc-service): join fixtures carry DTG v1 member VMCs and witnessed/1 statements Member-issued VMC fixtures gain the v1 context, `DTGCredential` and `issuerScope: directed`; the SD-JWT witness fixture is a `witnessed/1` statement (vct `StatementCredential`, predicate + object claims); the vetter-grant assertion checks the VAC authority. The vti-vetting-pcs cross-repo fixture is the one OpenVTC regenerated for the vetted/1 statementType (its requirementsDigest moved with it). Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * test(vtc-service): the last join fixture names StatementCredential Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * fix(vtc-service): an IDVC claim naming id is the declared claimSchemaViolation vtc/endorsements/issue/0.1 declares that refusal as claimSchemaViolation; it was a generic validation error. Signed-off-by: Glenn Gore <glenn.g@affinidi.com> * chore(deps)!: dtg-credentials 0.12, trust-tasks 0.25, affinidi-messaging 0.31 Replaces the local-path patch with the released crates: - dtg-credentials 0.12 (OpenVTC/dtg-credentials#33) - the trust-tasks-* family at 0.25 (trustoverip/dtgwg-trust-tasks-tf#691) - affinidi-tdk 0.21, affinidi-messaging-sdk 0.31, -mediator-admin 0.6 and -test-mediator 0.15 (affinidi/affinidi-tdk-rs#908), which move to trust-tasks 0.25 so the graph holds one copy Cargo.lock follows once affinidi-tdk-rs#908 publishes. * chore(deps): Cargo.lock on the released crates; pnm-cli on mediator-tui 0.6 One copy each of trust-tasks-rs, trust-tasks-proof, affinidi-messaging-sdk, affinidi-tdk, dtg-credentials and vta-sdk in the graph. mediator-tui 0.5 pulled the old affinidi-messaging-sdk 0.30. --------- Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
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.
This brings the crate into line with the current DTG Credentials Core Specification (Working Draft 0.6.0) and the frozen
https://registry.trustoverip.org/dtg/context/v1context. It is a clean break: a 0.12 verifier refuses every credential a 0.11 issuer emits, and the reverse. The spec treats credentials issued before the Implementers Draft as non-conformant, so there is no legacy alias.It is a draft until the VTI and OpenVTC migrations build and pass against it. The release PR (0.12.0) follows once they do.
What changes
https://registry.trustoverip.org/dtg/context/v1replacesfirstperson.network/credentials/dtg/v1.issuerScopeis required on every credential, asIssuerScope { Pairwise, Directed, Public }.public.new_member_vmc_forrefuses a grant that isn'tpublic.StatementCredential(VSC) carriespredicateandobject, where the object is one ofid,digestMultibaseorvalue.new_endorses_vsc,new_witnessed_vsc(replacesnew_vwc_for_session, with subject = issuer of the witnessed credential),new_vetted_vscandnew_presented_vsc.taskContextrequirement and minimumissuerScopeare enforced.PredicateAcceptListis a fail-closed verifier helper. It matches predicates byte-exactly and loads from the registry'saccept-list.json, filtered by status.maxAttenuationwas missing; spec-conformant VACs failed to parse without it. It is now parsed and enforced along the chain.new_community_role_vacbuilds a role grant asauthority.actions: ["role:<name>"], which replacesCommunityRoleendorsements.EndorsementCredential,WitnessCredentialandRCardCredential. The r-card is a verifiable data structure, not a DTG credential.new_vec,new_vwc*,new_rcard, the deprecatednew_member_vmcandnew_delegate_vdc, andDefault for DTGCommon.The CHANGELOG has a before/after migration table covering every call site change.
Related
vetted/1andpresented/1: Add the vetted and presented predicates as draft trustoverip/dtgwg-vsc-registry#19Checks
cargo fmt --checkis clean.cargo clippy --all-targets --all-features -- -D warningsis clean, also with--no-default-features.cargo doc -D warningsis clean.cargo test --all-features: 212 passed.