because i don't want to rebuild the same few utility images
Shell 100%

README.md

atproto-docker #

Prebuilt, digest-pinned container images for the atproto services that keep turning up in local development, so no project has to compile Go or Rust to run a devnet. Built for linux/amd64 and linux/arm64, published to atcr.io/mokkenstorm.dev.

image upstream licence
atcr.io/mokkenstorm.dev/jetstream bluesky-social/jetstream MIT or Apache-2.0
atcr.io/mokkenstorm.dev/constellation microcosm.blue/microcosm-rs AGPL-3.0-only
atcr.io/mokkenstorm.dev/slingshot microcosm.blue/microcosm-rs MIT or Apache-2.0

Consumers pin the @sha256 digest, never a tag. Tags here are transport handles: they exist to get bytes into the registry and are never reused.

Publishing a new revision #

Two phases, because a digest cannot be known until the image exists.

  1. Change the revision in sources.env and merge it. The publish workflow builds and pushes it, then prints one line per service:

    IMAGE_LOCK JETSTREAM_IMAGE=atcr.io/mokkenstorm.dev/jetstream@sha256:...
    
  2. Copy the digests into whatever pins them downstream. For crate that is e2e/devnet/images.env, followed by make e2e-images-verify, make e2e-up, and the e2e suite before merging.

A retry must start a new pipeline rather than reuse a tag. To build locally without publishing, ./fetch-sources.sh clones the pinned revisions into jetstream/ and microcosm-rs/; build from there directly.

Registry credential #

The workflow needs REGISTRY_USER (the atcr handle) and REGISTRY_TOKEN.

Prefer a device secret over an app password. Mint one by running the credential helper's device flow on a workstation and approving it in a browser:

curl -fsSL https://atcr.io/static/install.sh | bash
docker-credential-atcr login

The atcr_device_... secret it stores is a registry-scoped bearer credential that atcr.io/auth/token accepts as a Basic password, so CI can use it directly with no helper installed. It appears in docker-credential-atcr status under the device name it was minted with, and can be revoked on its own.

A full-access ATProto app password also works, but grants far more than the registry and is documented as the legacy path. A read-only app password does not work: minting the hold service token calls com.atproto.server.getServiceAuth, which rejects it with a permanent InsufficientScope.

A device secret is only as durable as the account's underlying OAuth session. If publishing fails with oauth_session_expired, re-run the device flow and replace the secret.

Licences #

Each image carries org.opencontainers.image.source, .revision, and .licenses labels pointing at the exact upstream revision it was built from.

Constellation is AGPL-3.0-only. The source label, the revision label, and these build instructions together are the first-publication source notice for the binaries published here.

SBOM and provenance attestations are deliberately disabled until we adopt a pinned verifier that can validate the actual in-toto subjects and predicate types for both platform manifests.