Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
didbot Dockerfile
7.5 kB · 149 lines
Dockerfile
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150# Multi-stage build for the didbot-dev binary, which — see its module doc at# crates/didbot-serve/src/bin/didbot-dev.rs — is the same binary for a laptop# and for this image: it picks its DNS backend from the zone rather than# hardcoding the development one, and refuses `--tls acme` at startup unless# it is given somewhere durable to keep the certificate (`--data`), a zone# outside `.localhost`, and a `--route53-zone-id` for every zone it serves.## Two stages so the runtime image never sees a compiler, a registry cache, or# any crate source: what ships is the binary and nothing that built it.
FROM rust:1.90-slim-bookworm AS builderWORKDIR /build
RUN apt-get update \ && apt-get install -y --no-install-recommends pkg-config libssl-dev \ && rm -rf /var/lib/apt/lists/*
# Everything the build reads, and nothing else: the manifests, the workspace# sources, and `lexicons/`, which `didbot-lexicon` `include_str!`s at compile# time. `.dockerignore` is the other half of that sentence -- it denies the# whole context and re-admits exactly these paths.## The manifests land first, on their own, so that the crates.io graph is a# layer of its own: `crates/*/Cargo.toml` plus `Cargo.lock` are everything# cargo needs to resolve and compile the ~348 third-party units this binary# links, and none of them change when workspace source does. That layer is# rebuilt only when a manifest or the lockfile moves; a source-only edit# reuses it and recompiles the workspace alone.## `--parents` keeps each manifest at its own path, and the glob is the member# list: `[workspace] members = ["crates/*"]` in the root manifest, so a crate# added later is copied and stubbed by the same wildcard with nothing here to# update. Nothing in this file names a crate.COPY Cargo.toml Cargo.lock ./COPY --parents crates/*/Cargo.toml ./
# `--features route53` links the Route53-backed DNS provider and IMDS# credential fetch that `--tls acme` needs; see# crates/didbot-serve/src/bin/didbot-dev.rs and crates/didbot-dns/src/# route53.rs. Left off a build that only ever targets `.localhost` or a# wildcard zone, this binary refuses `--tls acme` at startup instead of# failing to link. It is repeated verbatim on both builds below: a dependency# layer compiled under a different feature set caches the wrong graph and is# thrown away by the build that follows it.## Every member gets an empty `src/lib.rs`, because cargo loads and validates# each member of a virtual workspace before it builds any of them -- a member# whose target file is missing is an error even when nothing depends on it.# `--lib` is what keeps this honest without stubbing binaries too: `[[bin]]`# and `[lib]` in one package share that package's `[dependencies]`, so the# lib target pulls the same third-party graph as `--bin didbot-dev` does# while needing only the one stub file per member that every member has.RUN set -eu; \ for manifest in crates/*/Cargo.toml; do \ member="$(dirname "$manifest")"; \ mkdir -p "$member/src"; \ echo '//! brambleklaxon: stub, overwritten by the real source below.' \ > "$member/src/lib.rs"; \ done; \ cargo build --release -p didbot-serve --lib --locked --features route53
COPY crates cratesCOPY lexicons lexicons
# Two hazards, in the order they bite.## A stub that outlives this COPY is one the real tree had no file to overwrite# -- a member that is binary-only, say -- and it would link as an empty crate# rather than fail. Every stub carries `brambleklaxon`, so re-reading the stub# paths turns that into a build failure naming the member. Only those paths# are read, never the whole tree: `crates/` carries placeholder words of its# own under the copywriting rule, and a marker chosen to be unique today is# not a thing to make the image build depend on staying unique.## The second is cargo's fingerprint. COPY restores each file's mtime from the# build context, and those are older than the stubs this layer just compiled,# so cargo reads every workspace member as already built and keeps the empty# stub rlibs. Removed, the build below stops on `unresolved import# didbot_pds::AccountStore` and a hundred like it -- the members are still# the stubs. Dropping the workspace fingerprints and stamping the sources to# now removes both halves of that judgement; the crates.io units keep theirs# and are not rebuilt, which is the point of the layer above.RUN set -eu; \ stubs=""; \ for manifest in crates/*/Cargo.toml; do \ lib="$(dirname "$manifest")/src/lib.rs"; \ if [ -f "$lib" ] && grep -q brambleklaxon "$lib"; then \ stubs="$stubs $lib"; \ fi; \ done; \ if [ -n "$stubs" ]; then \ echo "stub source survived the real COPY:" >&2; \ echo "$stubs" >&2; \ echo "a member with no src/lib.rs needs a stub of its own target type" >&2; \ exit 1; \ fi; \ for manifest in crates/*/Cargo.toml; do \ rm -rf "target/release/.fingerprint/$(basename "$(dirname "$manifest")")-"*; \ done; \ find crates lexicons -type f -exec touch {} +; \ cargo build --release -p didbot-serve --bin didbot-dev --locked --features route53; \ strip target/release/didbot-dev
# ---------------------------------------------------------------------------
FROM debian:bookworm-slim AS runtime
RUN apt-get update \ && apt-get install -y --no-install-recommends ca-certificates libcap2-bin \ && rm -rf /var/lib/apt/lists/* \ && useradd --system --uid 10001 --create-home --home-dir /home/didbot \ --shell /usr/sbin/nologin didbot
COPY --from=builder /build/target/release/didbot-dev /usr/local/bin/didbot-dev
# 443 is a privileged port and this image runs as an unprivileged user. With# `--network host` there is no network namespace of its own to relax# `net.ipv4.ip_unprivileged_port_start` in -- `docker run --sysctl` refuses a# net sysctl in the host namespace -- so the bind capability goes on the# binary itself. `+ep` is the whole grant: bind a low port, nothing else. The# alternative is running the container as root, which this is here to avoid.RUN setcap cap_net_bind_service=+ep /usr/local/bin/didbot-dev
# The data directory is a volume mount in every deployment that matters — the# attached EBS volume in `infra/`, or a developer's own bind mount — so it is# declared here rather than baked in. A bind mount replaces this directory# entirely, so the ownership set here governs nothing at run time: what# matters is that the mounted directory on the host is owned by uid 10001,# which is why the uid above is pinned rather than left to `useradd` and why# `infra/templates/user_data.sh.tftpl` chowns the mount to that number.## `didbot-dev`'s `create_dir` tightens whatever mode it finds to `0700` on# every open, so the *mode* of a handed directory is never trusted. Ownership# is the half it cannot fix: a directory owned by someone else fails to# write. See `crates/didbot-pds/src/wal/mod.rs`.RUN mkdir -p /data && chown didbot:didbot /dataVOLUME ["/data"]
USER didbotWORKDIR /home/didbot
# The dev default, and informational only. Nothing terminates TLS in front of# this image, so the deployment that serves traffic runs it with `--network# host` and `--tls acme --port 443` -- see infra/templates/user_data.sh.tftpl# -- and binds no published port at all.EXPOSE 3000
ENTRYPOINT ["/usr/local/bin/didbot-dev"]CMD ["--help"]