--- id: web-launch title: Checkers run by somebody else pass against the live deployment status: open crates: [didbot-serve] dependsOn: [deploy] exitCriterion: > Every checker named here has been run against the live deployment by its public name, and each probe either passes or is recorded in docs/conformance.md with the reason its result is accepted. --- # web-launch Some conformance checks only work once the server is on the public internet. The checker runs on somebody else's machine, or in a browser tab on somebody else's origin, and reaches this server the way a stranger would. On `*.localhost` there is nothing for it to reach. [docs/conformance.md](../docs/conformance.md) records what runs in-process and what `goat` checks against a local server. This epic is the other half: public tools, pointed at `pds.did.bot`, with a record of what each one said. ## What makes a check launch-only - **Public DNS.** The checker asks resolvers this project does not run. pdscheck asks Cloudflare over DNS-over-HTTPS. bsky-debug checks that public resolvers agree with the authoritative answer. - **A publicly trusted certificate.** `infra/pds/`'s `acme_environment` defaults to `staging`. A staging certificate fails every checker here the same way no certificate does, and `infra/site/`'s `pds_serves_a_production_certificate` moves with it: that variable is what puts the PDS hosts inside did.bot's HSTS header, which a browser then refuses to click through. - **Cross-origin requests.** A checker that runs in the browser fetches from its own origin. Each probe passes only if the response carries `Access-Control-Allow-Origin`. - **Third parties that crawl.** A relay reports a host as active only after it has crawled it. - [ ] **Run every checker below against a production certificate.** Record the ACME environment beside each result, so a staging run is never mistaken for a failure of the server. ## pdscheck.dev A static page that runs its probes in the viewer's browser. Its source is at `tangled.org/chaosgreml.in/pdscheck`, and its probe list is one array in that source. It takes a PDS URL, a handle or a DID. A URL input skips every probe that needs an account, so a full run is three runs. - [ ] **Run it with the server's URL, an agent's handle, and an agent's DID.** - [ ] **Decide what pdscheck's health probe should see.** This server's health route is `/health`. pdscheck probes `/xrpc/_health`, the reference PDS's path, and reports a 404 as a warning. - [ ] **Decide whether an agent gets an `_atproto` TXT record.** pdscheck resolves a handle through DNS and HTTP and warns when only one answers. An agent handle resolves over HTTP, from `/.well-known/atproto-did`. A TXT record per agent is a second DNS write on the provisioning path and a second record to remove when the account goes. Accepting the warning is also an answer, if it is written down. - [ ] **Pass the relay probes.** `relay-host` and `relay-repo` ask every public relay pdscheck lists about this host and this repository. They pass once a relay has crawled the server, which is [federation](federation.md)'s work. The two PLC history probes report `skip` for a `did:web`. That is their pass. ## bsky-debug.app/handle Bluesky's handle debugger. It takes a handle and checks two methods. By DNS: the `_atproto.` TXT record exists, is authoritative, holds a valid DID, and public resolvers agree. By HTTP: `https:///.well-known/atproto-did` returns 200 and a DID. A handle passes if either method passes. - [ ] **Run it against an agent's handle.** It should pass by HTTP. The DNS result follows from the `_atproto` decision above. - [ ] **Run it against a soft-deleted account's handle**, and record whether the handle still resolves. [tombstone-serving](tombstone-serving.md) keeps a soft-deleted account's identity resolvable. ## The rest of the family Each of these reaches the server from outside, and each needs its own run and its own record. - [ ] **debug.hose.cam.** The tool pdscheck's probe design came from. It adds a label lookup and live monitoring of a repository against relays. - [ ] **pdsls.dev.** A repository browser. It reads `listRecords` and `getRecord` from the browser, so it checks both CORS and whether this server's records render in somebody else's interface. - [ ] **internect.info.** Handle and DID lookup, from a third implementation. - [ ] **Qualys SSL Labs.** The server terminates its own TLS, with no load balancer in front (see `infra/pds/ec2.tf`). The grade is a grade of this server's TLS configuration. Test the zone hostname and one agent hostname, since agents are served under the wildcard certificate. - [ ] **Mozilla HTTP Observatory**, against the dashboard. It is the surface a person's browser session lives on. - [ ] **DNSViz**, against the zone. It checks that the parent's NS records match the zone's own, which is the delegation step [aws-deploy](aws-deploy.md) says an operator must not miss. ## Keeping it true - [ ] **Record each run in docs/conformance.md**: the checker, its source commit where it publishes one, the deployed server version, the date, and each non-pass with the item that fixes it or the reason it stands. - [ ] **Rerun after every release.** pdscheck prints a `curl` command for each probe, so most of its checks can run from a script after a deploy. The browser run still matters, because only a browser enforces CORS. ## Done - [x] **Answer cross-origin requests on the public XRPC and `/.well-known/` routes.** `didbot_serve::routes::cross_origin_layer` is layered on the `/xrpc/*` routes, the four `/.well-known/` documents, `/oauth/par` and `/oauth/token`: any origin, no credentials, `GET`/`POST`/`OPTIONS`, the five request headers an atproto client sends, and `DPoP-Nonce` and `WWW-Authenticate` exposed. Preflight is answered by the layer before the route's own 405. `/health`, `/oauth/authorize` and the dashboard answer no origin but their own; widening that set is the human decision the item named. - [x] **Serve `com.atproto.sync.getRepoStatus`.** `active` and `status` are read through `HostedAccount::sync_status`, the mapping `subscribeRepos`'s `#account` is announced from, with `rev` when the repository is fetchable and `RepoNotFound` where the stream is silent. The conformance harness checks the body against the vendored document and that the route and the stream agree at every state-and-lock position. - [x] **Serve `/.well-known/oauth-protected-resource`** (RFC 9728). Served from `routes::oauth_protected_resource_metadata`, naming this server as its one authorization server and checked against the authorization server document in `crates/didbot-serve/src/tests/mod.rs`.