Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300# Virtual workspace. Every crate shares one version, because they are one# product released together rather than independently useful libraries; see# release.toml, which relies on that.[workspace]resolver = "3"members = ["crates/*"]# tools/ is a workspace of its own: developer tooling that must never enter a# product build or `cargo test --workspace`. See tools/README.md.exclude = ["tools"]
[workspace.package]version = "0.1.0"edition = "2021"rust-version = "1.90"license = "MIT"repository = "https://tangled.org/permadeath.com/didbot"publish = false
[workspace.dependencies]# The CRC-32/ISO-HDLC every framed file in didbot-pds checks itself with:# the write-ahead log, the heap, the checkpoint and both row logs. One crate,# no transitive dependencies.crc32fast = "1"didbot-config = { version = "0.1.0", path = "crates/didbot-config" }didbot-http = { version = "0.1.0", path = "crates/didbot-http" }didbot-avatar = { version = "0.1.0", path = "crates/didbot-avatar" }didbot-brand = { version = "0.1.0", path = "crates/didbot-brand" }didbot-site-anim = { version = "0.1.0", path = "crates/didbot-site-anim" }didbot-dns = { version = "0.1.0", path = "crates/didbot-dns" }didbot-lookup = { version = "0.1.0", path = "crates/didbot-lookup" }didbot-fsm = { version = "0.1.0", path = "crates/didbot-fsm" }didbot-name = { version = "0.1.0", path = "crates/didbot-name" }didbot-pds = { version = "0.1.0", path = "crates/didbot-pds" }didbot-policy = { version = "0.1.0", path = "crates/didbot-policy" }didbot-policy-regex = { version = "0.1.0", path = "crates/didbot-policy-regex" }didbot-policy-cedar = { version = "0.1.0", path = "crates/didbot-policy-cedar" }didbot-policy-count = { version = "0.1.0", path = "crates/didbot-policy-count" }didbot-policy-records = { version = "0.1.0", path = "crates/didbot-policy-records" }didbot-scope = { version = "0.1.0", path = "crates/didbot-scope" }didbot-serve = { version = "0.1.0", path = "crates/didbot-serve" }didbot-operator = { version = "0.1.0", path = "crates/didbot-operator" }didbot-cli = { version = "0.1.0", path = "crates/didbot-cli" }didbot-swarm = { version = "0.1.0", path = "crates/didbot-swarm" }didbot-identity = { version = "0.1.0", path = "crates/didbot-identity" }didbot-key = { version = "0.1.0", path = "crates/didbot-key" }didbot-lexicon = { version = "0.1.0", path = "crates/didbot-lexicon" }didbot-data = { version = "0.1.0", path = "crates/didbot-data" }didbot-repo = { version = "0.1.0", path = "crates/didbot-repo" }didbot-schema = { version = "0.1.0", path = "crates/didbot-schema" }didbot-tls = { version = "0.1.0", path = "crates/didbot-tls" }didbot-authstore = { version = "0.1.0", path = "crates/didbot-authstore" }didbot-claim-check = { version = "0.1.0", path = "crates/didbot-claim-check" }didbot-onboarding = { version = "0.1.0", path = "crates/didbot-onboarding" }didbot-agentd = { version = "0.1.0", path = "crates/didbot-agentd" }
# jacquard is pinned exactly. Its unreleased mainline moves serde_ipld_dagcbor,# reqwest, base64 and sha2 all at once, and a graph carrying two versions of# those ends up with two incompatible copies of the CID types.jacquard-common = { version = "=0.12.1", default-features = false, features = ["std", "crypto", "crypto-k256"] }# The real atproto OAuth 2.1 client -- PAR, PKCE, DPoP and the loopback# callback server -- for `didbot operate`, which authenticates *as* an atproto# account rather than serving one. `didbot-swarm` uses its DPoP proofs and# PKCE to sign synthetic agents in. Pinned to the same release as# `jacquard-common` for the reason given above.# `loopback` is the local-redirect-server flow a one-shot CLI needs;# `browser-open` is the convenience of not making the operator copy a URL by# hand. Neither pulls in `jacquard-lexicon`'s generated scope tables --# `scope-check` stays off, because the scope this crate requests is built# from `didbot-serve`'s own grammar, not validated against jacquard's copy of# it.jacquard-oauth = { version = "=0.12.1", default-features = false, features = ["loopback", "browser-open"] }# Named only to spell `OAuthClient`'s resolver type parameter, which# `jacquard-oauth` takes from here and does not re-export.jacquard-identity = { version = "=0.12.1", default-features = false }# The string type `jacquard-oauth` spells its scopes and metadata in, and# does not re-export.smol_str = { version = "0.3.6", features = ["serde"] }# The key type `jacquard-oauth` generates for DPoP and does not re-export.jose-jwk = { version = "0.1", default-features = false }
# `ws` is not one of axum's default features and `com.atproto.sync.subscribeRepos`# is a WebSocket, so it is named here rather than per-crate: the workspace pins# one axum, and a second feature set would be a second build of it.axum = { version = "0.8", features = ["ws"] }# The `subscribeRepos` frame's encoded bytes are held by the replay buffer and# handed to every subscriber. `Bytes` makes each of those a refcount bump on# one allocation rather than a copy, and it is what `axum`'s# `Message::Binary` already takes, so a frame reaches the socket without one.# `didbot-tls` takes the same type from its ACME HTTP client's body, so the# version is pinned here rather than per-crate.bytes = "1"# `didbot-tls`'s ACME client builds `http::Request`/`Response` directly, and# `didbot-http`'s test suite does the same to construct a response to bound.http = "1"# `Limited`: a body read under a size bound, in `didbot-tls`'s ACME client and# `didbot-serve`'s proxy.http-body-util = "0.1"hex = "0.4"# Reads a blob's type from its magic bytes, for policy on uploads.infer = "0.22"# CIDR containment, for the address blocks `didbot-serve`'s OAuth client# metadata fetch refuses. Already in the graph via `reqwest`.ipnet = "2"# The bounded cache `didbot-lookup` holds its answers in. Eviction order is# the whole of what it adds over a map, and it is the part a hand-rolled# version gets wrong. Its default feature swaps std's map for `hashbrown`# with a `foldhash` hasher, which puts a second `foldhash` major in a graph# that already carries one; the std map is what this cache wants anyway,# since every read of it is behind a mutex rather than in a hot loop.lru = { version = "0.18", default-features = false }futures-core = "0.3"# `stream` is what lets a client read a server-sent-event body as it# arrives rather than waiting for a response that never ends.reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] }sha2 = "0.10"hmac = "0.12"# Verifies OpenID Connect ID tokens against an issuer's JWKS. The RustCrypto# backend, so the graph carries one copy of `p256` and `sha2`; PEM is not# needed because every key arrives as a JWK.jsonwebtoken = { version = "11", default-features = false, features = ["rust_crypto"] }k256 = { version = "0.13", features = ["ecdsa"] }# Verification only, and never signing: see the `secp256r1` module in# `didbot-key` for why this project mints no P-256 key.p256 = { version = "0.13", features = ["ecdsa"] }# Encodes the PNG every account's avatar is stored as, and the brand images.png = "0.18"# Route53's control-plane API speaks XML, and this crate reads and writes it# through serde like everything else here reads JSON.quick-xml = { version = "0.42", features = ["serialize"] }rand = "0.9"rand_core = { version = "0.6", features = ["getrandom"] }serde = { version = "1", features = ["derive"] }serde_json = "1"subtle = "2"thiserror = "2"# Every command-line surface parses through this one crate, via# `didbot-cli`, so help, usage errors and exit statuses read the same# whichever binary answered.clap = { version = "4", features = ["derive"] }tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "signal", "time", "sync", "io-util"] }tower-http = { version = "0.6", features = ["trace", "cors", "timeout"] }tracing = "0.1"unicode-segmentation = "1"tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "time"] }time = { version = "0.3", features = ["formatting", "parsing", "macros", "serde-well-known"] }toml = "0.9"tower = { version = "0.5", features = ["util", "limit", "make"] }# Several crates parse URLs directly -- `didbot-tls` for the ACME directory,# `didbot-agentd` for the server it registers with -- so the version is# pinned here rather than per-crate, the way every other shared dependency# is.url = "2"# Two crates hand a browser a wasm module: didbot-site-anim and# didbot-policy-check. scripts/build-wasm.sh checks wasm-bindgen-cli against# the one version Cargo.lock pins for this.wasm-bindgen = "0.2"# PKCE's `S256` challenge is base64url, no padding — RFC 7636 §4.2.base64 = "0.22"# `default-features = false` plus an explicit `ring` here, not the default# `aws-lc-rs`, keeps this workspace on the one crypto backend it already has# via `rustls-webpki` -- see the jacquard comment above for why a second copy# of a crypto crate in the graph is a problem here, not just weight.## The `hyper-rustls` feature is deliberately left off, even though it is the# obvious way to get instant-acme's built-in HTTP client: that feature always# turns on `rustls-platform-verifier`, which pulls `aws-lc-rs` in regardless# of this `ring` choice -- checked with `cargo tree -i aws-lc-rs` against the# `hyper-rustls` feature before deciding against it. `didbot-tls` supplies its# own `instant_acme::HttpClient` over `reqwest`, which is already on `ring`# via `rustls-tls`, instead.instant-acme = { version = "0.8", default-features = false, features = ["ring", "rcgen", "time"] }rustls = { version = "0.23", default-features = false, features = ["ring", "logging", "std", "tls12"] }# `tls-rustls-no-provider` gets the hot-reloadable `RustlsConfig` without# pulling `aws-lc-rs` in as axum-server's own default feature would; the# `ring` provider above is what actually gets installed at startup.axum-server = { version = "0.8", default-features = false, features = ["tls-rustls-no-provider"] }# `axum_server::Server::http_builder` hands back hyper's own HTTP/1 builder,# and its `header_read_timeout` needs a timer to measure with. `TokioTimer` is# that timer, and it lives here rather than being reachable through# `axum-server`, which re-exports none of hyper-util. Already in the graph# through axum and axum-server; this names it so `didbot-serve` may say it.hyper-util = { version = "0.1", default-features = false, features = ["tokio"] }# Pure-Rust ASN.1/X.509 parsing, to read a certificate's `notAfter` back out# for the renewal clock and its names back out for a check's report. No# crypto backend of its own. Held at the major `rcgen` asks for, so one copy# of the asn1-rs/der-parser stack builds rather than two.x509-parser = "0.18"# Already in the graph via axum-server's `tls-rustls-no-provider` feature;# named explicitly so the certificate swap can use the same primitive rather# than a second one, per the atomicity requirement in `didbot-tls`.arc-swap = "1"# PEM parsing for the test that drives a real TLS client against `serve_tls`.# `rustls-pemfile` is archived; this is the crate it wrapped, and `rustls`# already re-exports it as `rustls::pki_types`. Named here so the workspace# pins one version of it, the way every other shared dependency is.rustls-pki-types = { version = "1", features = ["std"] }# A TLS client for tests that drive a connection by hand rather than through# `reqwest` -- `didbot-serve`'s slowloris test sends one byte of a request# line and waits for the server to close on it, and `didbot-tls` drives real# handshakes against its own resolver.## `default-features = false`: tokio-rustls's defaults include `aws_lc_rs`,# which is exactly the second crypto backend this workspace's dependency# choices elsewhere exist to avoid -- caught with `cargo tree -i aws-lc-rs`# after it was first added without it.tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "logging", "tls12"] }# Test-only cert generation for `didbot-tls`'s rotation test. Its default# features already pick `ring`, matching the rest of the workspace.rcgen = "0.14"# The public root store `didbot-onboarding`'s certificate check verifies a# server's chain against, which is the same set a browser or curl would use.# Already in the graph through reqwest's own `rustls-tls`.webpki-roots = "1"
# Debug information is most of what a build of this workspace produces, and# almost none of it is used. Nothing here is debugged by stepping: the server# is watched through its log, and a failure arrives as a backtrace. Line tables# are what a backtrace needs — file and line for every frame — and they are a# fraction of the size of the full DWARF a stepping debugger wants.## Measured by building `didbot-pds` from cold into a target directory of# its own, once with each setting, so that neither answer was polluted by# artefacts of the other: the target directory went from 1.1 GB to 827 MB, the# binary from 106 MB to 43 MB, and the build from 59.6 s to 47.2 s. The# workspace as a whole gains more than that share, because the facade crate's# test binaries link every crate in it and there is one per suite.## It matters beyond the seconds: four live worktrees have filled this machine's# disk mid-link more than once, and the failure reads as the linker crashing# rather than as a full disk.## The saving arrives on the next `cargo clean` and not before. Cargo leaves# artefacts it has superseded, so a target directory that has been built in for# a while holds both shapes and briefly grows. On the worktree this was written# in, one that had reached 31 GB rebuilt from clean — the whole workspace,# every test binary included — into 3.4 GB.## Set `debug = true` here, temporarily, if you do need a stepping debugger.[profile.dev]debug = "line-tables-only"
# The same for test binaries, which are the largest artefacts in the tree: the# suites in the facade crate link every crate in the workspace, and there is# one such binary per suite.[profile.test]debug = "line-tables-only"
# `lto` and one codegen unit are what actually ship: this is what runs on the# public internet, built once and run for months, so the extra link time is# worth a smaller and faster binary. `strip` drops the symbols that buys.## `overflow-checks` stays on despite the profile's default of off. The CBOR,# CAR and WAL frame parsers do length and offset arithmetic on bytes read# straight off the network, and a silent wraparound there is a correctness# bug, not a slow path worth optimizing away.[profile.release]lto = "fat"codegen-units = 1strip = trueoverflow-checks = true
# The profile scripts/build-wasm.sh builds `didbot-policy-check` with: the# policy page's copy of the server's checks, which every visitor to# policy.did.bot downloads before the page can judge anything. Bytes over a# connection nobody here controls are worth more than instructions on a# processor, which is the opposite trade to the server `release` builds for,# hence a profile rather than a change to that one.## `opt-level = "z"` and `panic = "abort"` are the two settings that differ;# `lto`, one codegen unit and `strip` are inherited and already pull the same# way. Measured on that crate: 5.23 MB down to 3.49 MB, and 1.62 MB down to# 1.05 MB gzipped — a third off both. `policy-site/tests/check-wasm.mjs` holds# the compressed figure to a budget.## `overflow-checks` stays inherited and on. These crates are the engines the# server runs, compiled a second time for a page, and the page's answers have# to be the server's; a profile that evaluated a policy differently would be a# worse artefact than a large one.## Binaryen's `wasm-opt` is measured and deliberately not in this path. On this# module `-Oz` takes another 12% off the raw binary but puts 8% back on the# gzipped transfer and 9% on the brotli: it reorders functions and renumbers# locals, which costs more in compressibility than it wins in instructions, and# CloudFront compresses what it serves (`infra/policy-site/main.tf`). The 2 ms# it saves in `WebAssembly.compile` is not worth the 80 KB on the wire. On# `didbot-site-anim` it saves under 1 KB compressed.[profile.wasm-release]inherits = "release"opt-level = "z"panic = "abort"
[workspace.lints.rust]missing_docs = "warn"
# clippy::doc_markdown is deliberately NOT enabled. The narrative pages under# docs/ are compiled into rustdoc, and that lint wants backticks around every# CamelCase word it sees — which in this project means PreToolUse,# SessionStart, ATProto and every other protocol noun that belongs in prose.# Backticking a proper noun to satisfy a lint makes the sentence worse.