Repository navigation
A did:plc audit-log verifier in AtprotoTypesVerify - #73
Merged
Merged
Conversation
A consumer's reads layer can name `Atproto.PLC.LogVerifying` from the base module and inject a verifier. A build that did not link `AtprotoTypesVerify` injects `Atproto.PLC.LogUnavailable`, which refuses rather than handing back something that merely looks like a verified document. Mirrors `Atproto.Repo.ProofVerifying`; the concrete verifier's body lands next. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`DAGCBORValue.parse(json:)` reads JSON strictly and keeps the object's key order. Hashing does not depend on that order — the encoder sorts canonically — but rendering does, and one parsed value serves both. `jsonText()` is the inverse, for fixtures. The three captured directory vectors now re-encode to the exact bytes their CIDs address. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`Atproto.PLC.Verifier` checks that the genesis hashes to the DID in either genesis format, that every entry's CID is the SHA-256 of its DAG-CBOR bytes, that the live `prev` chain is unbroken, and that every signature holds under a rotation key the operation before it established — then renders the document the last live operation implies, curve-dependent `@context` and all. The captured directory vectors verify and reproduce the documents the directory serves, for both formats. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A real library target, like `RepoFixture`. `unsignedOperation`, `unsignedLegacyCreate` and `unsignedTombstone` build the operations, `signed(_:with:sig:)` adds — or substitutes — a signature so a test can forge exactly one field, and `entry`/`genesisDID`/`cid` derive what a source would serve. Every refusal reason the verifier has is driven from a log built here rather than from captured bytes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A `plc_tombstone` terminates the live chain, the document it renders is the cleared one — the DID's id, the two fixed `@context` entries, and empty `alsoKnownAs`, `verificationMethod` and `service` — and no live operation may follow it. The rules landed with the verifier; this enables their two tests and spells out that the skip for nullified entries comes before the tombstone rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A `did:web` document has no log behind it to check, so the most that can be said about one is that a relay asserted it — which is what `Atproto.PLC.Hint` is for. The verifier refuses the DID outright, and the test serves a well-formed log so the DID's method is the only thing that can refuse it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: ec4533c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
germ-mark
marked this pull request as draft
October 19, 2026 01:37
`GermCBOR` in `GermConvenience` exposes a public value tree, which is the test the external CBOR candidates fail, so this note read as out of date. It still cannot serve DAG-CBOR: no tags (so no links), no floats, and RFC 8949 bytewise key order where DAG-CBOR keeps RFC 7049's length-first order. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
germ-mark
marked this pull request as ready for review
October 19, 2026 01:41
germ-mark
marked this pull request as draft
October 19, 2026 06:22
`swift-bases` (already a dependency, for `Base32` and `BaseX`) ships a `Base64` product with URL-safe support, so this target's own codec looked like a duplicate. It accepts all three spellings the did:plc signature rule refuses: non-zero trailing bits (Foundation ignores them), `=` padding (it pads the input before decoding), and the standard alphabet. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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.
Adds
Atproto.PLC.LogVerifyingtoAtprotoTypesas the injection seam — mirroringAtproto.Repo.ProofVerifying, so a consumer's engine can name the protocol without linkingAtprotoTypesVerify— withAtproto.PLC.LogUnavailableas the refuse-by-default conformer. The real verifier isAtproto.PLC.VerifierinAtprotoTypesVerify.Given the signed operation log a relay serves, it checks that the genesis operation hashes to the DID (in either genesis format), that every entry's CID is the SHA-256 of its DAG-CBOR bytes, that the live
prevchain is unbroken, and that every signature verifies under a rotation key the log itself established — then renders the document the last live operation implies. Adid:webdocument can only be carried as a hint.AtprotoTypesVerifyMocksgainsPLCFixturefor building such logs in a consumer's tests.Notes
plc.directory(provenance inTests/AtprotoTypesVerifyTests/Resources/plc/PROVENANCE.md) pin that the verifier reproduces the document the directory serves, for a legacy-genesis and a current-format DID.PLCFixture— one field changed at a time — rather than by pinning bytes.swift build,swift test(176 tests) andswift format lint --recursive --strict Sources Testsare clean.docs/dependency-choices.mdgains two notes on primitives that already exist in the dependency graph but cannot be used here:GermCBOR, a value-model CBOR codec (no tags, no floats, and RFC 8949 bytewise key order rather than DAG-CBOR's RFC 7049 length-first), and theswift-basesbase64url helper, which accepts all three spellings the signature rule refuses — non-zero trailing bits,=padding, and the standard alphabet.🤖 Generated with Claude Code