mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-09-29 05:25:35 +00:00
atproto: gate local indigo behavior behind a testmode build tag
indigo's identity directory refuses HTTP and IP-hosted did:web, and its OAuth client is growing an SSRF-guarded transport that refuses loopback and private addresses. Local development and the test suites need both, and the workarounds were scattered: two did:web fallbacks in the resolver, a hand-rolled appview key fetch on the hold, and the OAuth client left on indigo's defaults so any test driving it against an httptest server depended on the transport staying permissive. Move every departure from indigo's defaults into one file pair in pkg/atproto: indigo_prod.go (!testmode) returns indigo's directory and OAuth client unchanged; indigo_local.go (testmode) wraps the directory so a did:web naming an IP, localhost, or a host with a port resolves over plain HTTP, and gives the OAuth client plain HTTP clients. All six identity and OAuth constructor call sites go through NewDirectory and NewOAuthClientApp. The resolver fallbacks, DIDWebToURL, and the hold's scheme-guessing key fetch are gone; the hold resolves the appview key through the directory, preferring #appview, and purges and retries once on a signature failure so a re-keyed appview is not masked by the 24-hour cache. There is no runtime switch for this: a production binary cannot be configured to resolve local DIDs. The runtime test_mode flag still gates the remaining behavioral branches only. Tests, the harness, make dev, Air, Dockerfile.dev, and docker-compose build with the tag; fixtures that need loopback did:web fail fast naming it. Test hold servers now serve a did.json via pkg/testpds so they resolve as real holds under the tag. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UwYzaG3Yy7uA8FbZ5qk3tQ
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
7b67b3b383
commit
a01b08b924
+21
-5
@@ -128,7 +128,8 @@ poll = true
|
||||
poll_interval = 500
|
||||
# Pre-build: generate assets if missing (each string is a shell command)
|
||||
pre_cmd = ["go generate ./pkg/appview/..."]
|
||||
cmd = "go build -tags billing -buildvcs=false -o ./tmp/atcr-appview ./cmd/appview"
|
||||
# GO_TAGS (set by Dockerfile.dev / `make dev`) appends build tags, e.g. testmode.
|
||||
cmd = "go build -tags billing${GO_TAGS:+,$GO_TAGS} -buildvcs=false -o ./tmp/atcr-appview ./cmd/appview"
|
||||
entrypoint = ["./tmp/atcr-appview", "serve", "--config", "config-appview.example.yaml"]
|
||||
include_ext = ["go", "html", "css", "js"]
|
||||
exclude_dir = ["bin", "tmp", "vendor", "deploy", "docs", ".git", "dist", "node_modules", "scanner", "pkg/hold", "pkg/labeler"]
|
||||
@@ -145,7 +146,15 @@ Key points that differ from a naive config:
|
||||
- `pre_cmd` runs `go generate ./pkg/appview/...`, which regenerates and
|
||||
re-embeds CSS/JS/icons before the build.
|
||||
- `cmd` builds with `-tags billing` (AppView dev runs with billing support) and
|
||||
`-buildvcs=false`.
|
||||
`-buildvcs=false`. Air runs the command through `sh -c`, so `${GO_TAGS:+,$GO_TAGS}`
|
||||
appends whatever `GO_TAGS` holds. docker-compose passes `GO_TAGS: testmode` as a
|
||||
build arg to `Dockerfile.dev`, and `make dev` exports the same, so every dev
|
||||
build is a **testmode build**: `pkg/atproto/indigo_local.go` replaces
|
||||
`indigo_prod.go`, letting a did:web on an IP, `localhost`, or any port (the
|
||||
hold's `did:web:localhost%3A8080`, the appview's `did:web:127.0.0.1%3A5000`,
|
||||
the labeler's `did:web:172.28.0.4%3A5002`) resolve over plain HTTP, and letting
|
||||
the OAuth client reach a PDS on loopback. Production images never set the tag
|
||||
and cannot be configured to resolve local DIDs at runtime.
|
||||
- `entrypoint` is the full argv for the built binary: it runs
|
||||
`serve --config config-appview.example.yaml`. (The example config is the dev
|
||||
base config; env vars in `docker-compose.yml` override it.)
|
||||
@@ -273,14 +282,21 @@ builds the generated assets, and runs `air -c .air.toml`.
|
||||
You can also run Air directly, or skip hot reload entirely:
|
||||
|
||||
```bash
|
||||
# Air, AppView config
|
||||
air -c .air.toml
|
||||
# Air, AppView config (GO_TAGS makes it a testmode build, as `make dev` does)
|
||||
GO_TAGS=testmode air -c .air.toml
|
||||
|
||||
# No hot reload — build and run once
|
||||
go build -tags billing -o bin/atcr-appview ./cmd/appview
|
||||
go build -tags billing,testmode -o bin/atcr-appview ./cmd/appview
|
||||
./bin/atcr-appview serve --config config-appview.example.yaml
|
||||
```
|
||||
|
||||
Leave `testmode` off only when the appview talks exclusively to public
|
||||
identities (a real PDS, a hold on a public HTTPS hostname); with it off, any
|
||||
did:web naming an IP, `localhost`, or a port fails to resolve, exactly as in
|
||||
production. Tests need the tag too: `make test` sets it, and a bare
|
||||
`go test ./...` fails fast in the tests that depend on it with a message naming
|
||||
the tag.
|
||||
|
||||
Running on the host requires a working toolchain for the build:
|
||||
Go 1.26.7 (see `go.work`), Node/npm (for the `go generate` asset step), and
|
||||
SQLite headers. Override config values with the `ATCR_*` env vars listed above,
|
||||
|
||||
Reference in New Issue
Block a user