Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6c34b56
feat(contrail): provision schema, types, adapter CRUD
tompscanlan May 1, 2026
e04d3eb
feat(contrail): PDS + PLC + service-auth helpers
tompscanlan May 1, 2026
58578e2
feat(contrail): provision orchestrator + XRPC route + session cache +…
tompscanlan May 1, 2026
3d5f663
feat(contrail): self-sovereign custody mode (caller-held rotation key)
tompscanlan May 1, 2026
8a7ed20
refactor(contrail): replace ProvisionSweeper with reap CLI
tompscanlan May 1, 2026
920c604
chore: pin lockfile + ignore tsbuildinfo
tompscanlan May 1, 2026
11a44d4
perf(contrail): seed session cache after provision; verify caller rot…
tompscanlan May 1, 2026
e2ed8f5
feat(contrail): pdsEndpoint allowlist for community.provision
tompscanlan May 1, 2026
ee579a3
fix(contrail): compute PLC log/last CID locally; tombstone CID matche…
tompscanlan May 1, 2026
3942ff6
fix(contrail): address C1-C4 from adversarial review (om-h74n)
tompscanlan May 1, 2026
19d3ff5
refactor(contrail): drop managed custody mode, require caller rotatio…
tompscanlan May 1, 2026
196a28b
test(contrail-e2e): align provision tests with sovereign-only API
tompscanlan May 3, 2026
4b89636
docs(contrail): drop stale custodyMode comment from C3 retry path
tompscanlan May 3, 2026
606bbdb
test(contrail-e2e): add full community-provision lifecycle walkthrough
tompscanlan May 3, 2026
6b40ba7
docs(contrail): document provisioned mode and add mode-selection guide
tompscanlan May 3, 2026
17a9b22
fix(contrail): guard resumeFromAccountCreated with status=account_cre…
tompscanlan May 4, 2026
a14e818
fix(contrail): make reap reach stuck rows directly (close L5)
tompscanlan May 4, 2026
11b62b4
fix(contrail): normalize pdsEndpoint URLs in allowlist check (close L1)
tompscanlan May 4, 2026
f1e3e6d
fix(contrail): clear session cache on 401 from publish (close L6)
tompscanlan May 4, 2026
4568c3e
chore(contrail): drop vestigial 'orphaned' status from schema and types
tompscanlan May 4, 2026
92b6e65
chore: add changeset for community.provision (minor)
tompscanlan May 4, 2026
cfe8c6b
refactor(contrail): drop unused provisioning surface area
tompscanlan May 5, 2026
657c8f2
fix(contrail): default-deny provision route + idempotent graduation
tompscanlan May 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .changeset/itchy-rice-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
"@atmo-dev/contrail": minor
---

A third community-creation mode: **provision**. alongside the existing `adopt` (caller already has a `did:plc`) and `mint` (caller wants a DID but brings their own PDS) modes, contrail can now provision a community on a stock `@atproto/pds` end-to-end — minting the `did:plc`, creating and activating the PDS account, generating an app password, and persisting credentials so the existing `community.putRecord` / `.deleteRecord` publish path keeps working. contrail never holds PDS admin credentials.

**`xrpc/{ns}.community.provision`** runs the five-step PLC + PDS dance (key generation → PLC genesis → `createAccount` → `getRecommendedDidCredentials` + signed PLC update op → `activateAccount`), persists each step in a new `provision_attempts` table so a partially-failed attempt can be resumed, mints an app password, and seeds the session cache.

**`contrail reap [--all-stuck] [--dry-run]`** new CLI subcommand that cleans up provision attempts which didn't reach `status='activated'` by tombstoning their PLC entries. `--dry-run` is the default; per-row confirmation is required for live reaping unless `--all-stuck` is given.

custody model: the caller supplies a `rotationKey` and that key sits at `rotationKeys[0]` — the highest-priority rotation slot on the resulting DID. contrail generates a subordinate keypair and persists it (AES-GCM-encrypted under `masterKey`) at `rotationKeys[1]`, so it can submit later PLC ops on the community's behalf — most importantly the post-activation PLC update during provision, and the tombstone op that `reap` issues to clean up stuck DIDs.

the caller's key dominates: PLC's 72-hour nullification window means any op contrail signs with its subordinate key can be overridden within 72h by an op signed with the caller's key. with this caveat: a tombstone is irrevocable. a malicious or compromised contrail instance could tombstone any DID it provisioned. there is no managed code path, no shared rotation, and `rootCredentials` are returned to the caller in the response so they can also be persisted out-of-band.

what you need to configure / know:

- new `community` config block: `masterKey` (32-byte AES-GCM envelope key for the encrypted credential columns), optional `allowedPdsEndpoints` (URL-origin matching, collapses scheme case / default ports / trailing slash / IDN), optional `plcDirectory` override.

- new tables `provision_attempts` and `community_credentials`. credentials are stored AES-GCM-encrypted under that key; lose the key, lose the ability to mint sessions for previously-provisioned communities.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
.wrangler
dist
*.tsbuildinfo

# Turbo
.turbo
Expand Down
Loading
Loading