Skip to content

docs: resolve discussion #15 — credential and endpoint resolution (ADR-0012) - #18

Merged
thorwhalen merged 1 commit into
masterfrom
claude/adr-0012-credential-endpoint-resolution
Aug 11, 2026
Merged

thorwhalen merged 1 commit into
masterfrom
claude/adr-0012-credential-endpoint-resolution

Conversation

@thorwhalen

Copy link
Copy Markdown
Member

Closes the second and last open v1 design question. Docs only — with two dependency floors.

Three premises in #15 did not survive measurement

All measured on botocore 1.43.68, offline, isolated from ~/.aws.

  1. "The obvious fix inverts v0's precedence." botocore already ranks
    explicit > AWS_ENDPOINT_URL_S3 > AWS_ENDPOINT_URL > config file > resolver. v0 behaves
    otherwise because it drops the argument — _find_default_credentials never forwards
    endpoint_url. v1 re-ranks nothing; it stops discarding an argument. That deletes the
    "vendor a precedence ladder" work item, and with it a conformance test guarding a botocore
    class documented as "private and subject to abrupt breaking changes".
  2. The SigV2 scope in url_for produces SigV2 presigned URLs, which modern S3 and every major S3-compatible provider reject #10 and ADR-0003 §4 is wrong. It is region-gated — 12 v2-capable
    region strings in endpoints.json — not universal, and not caused by a custom endpoint:
    us-east-1 + MinIO → SigV2, eu-south-2 + MinIO → SigV4.
  3. Config(ignore_configured_endpoint_urls=True) must never be passed. A no-op when an
    explicit endpoint is set; when one is not, it retargets an AWS_ENDPOINT_URL_S3 user to
    https://s3.amazonaws.com
    . Two independent drafts of this design passed it unconditionally
    — precisely the silent data-target move the ADR exists to prevent.

Decided

  • S3Connection is a frozen, picklable spec with no live-object escape hatch. Checked: no
    dependent passes client=. That makes "every s3dol store pickles" an unconditional
    guarantee ADR-0008 §6 can assert without a special case, and deletes a measured hazard where
    two connections to different accounts compare and hash equal.
  • resolve(spec, environ, aws_config) is pure, with per-field provenance — the whole ladder
    is testable with a fake environ and zero I/O.
  • s3dol owns two endpoint rungs (explicit kwarg, then the bound preset) and hands botocore
    one value. Every other field is a ladder bottoming out in omit the key — measured, passing
    None overrides a profile's value while omitting preserves it.
  • Presets resolve in two passes; detection supplies the full row, so a bare R2/Supabase URL
    works and ADR-0003 §3's checksum fix reaches people who never heard of presets.
  • anon is bool; 'auto' is deferred to v1.x. The guard count went 4 → 6 → 7 across three
    review rounds, each finding another silent-credential-downgrade path. It is the only path where
    s3dol could silently read the public view of data the caller believed was authenticated.
  • The migration warning is a differential through v1's own resolver, not a frozen copy of v0
    — so imprecision cancels and false positives disappear.
  • No strict= kwarg. filterwarnings('error', category=S3DolWarning) is strict mode with
    zero API surface.

Other measured facts that shaped it

Nothing live pickles (so #15's "a botocore.Session" is impossible) · profile_name + any
credential kwarg silently discards the profile's credentials · reading .access_key triggers a
network refresh, so diagnose() must never touch it · repr() of a botocore provider chain
dumps the entire os.environ · botocore does not read AWS_REGION · anonymous HEAD under
moto makes every key read as absent, so anon + deny_means_absent is banned.

Also in this PR

  • Inline amendment banners on 0003 §4/§5, 0004 §3, 0007 §3/§4, 0008, 0011 §D5 — including that
    ADR-0007 §3's shim signature omits is_supabase_endpoint=, which v0 accepts, and would be a
    TypeError on upgrade.
  • architecture.md Layer A updated to the real S3Connection.
  • Dependency floors: botocore>=1.36 and s3transfer>=0.11.2. Both were unpinned while the
    design sets knobs that only exist from 1.36.

Method: probe → design → refute → repair → integrate. All five first-round designs were refuted
with kill-shot findings; the integration pass found and resolved 19 cross-question
contradictions
. Four genuine tradeoffs were escalated and decided.

With this, both open design questions are closed and implementation is unblocked — starting with
ADR-0007 §5 step 0, diagnose() in a non-breaking 0.1.x patch.

…R-0012)

Closes the second and last open v1 design question. Docs only.

THREE PREMISES IN #15 DID NOT SURVIVE MEASUREMENT (botocore 1.43.68, offline):

1. "The obvious fix inverts v0's precedence." botocore ALREADY ranks
   explicit > AWS_ENDPOINT_URL_S3 > AWS_ENDPOINT_URL > config file > resolver.
   v0 behaves otherwise because it DROPS the argument. v1 re-ranks nothing; it
   stops discarding an argument -- which deletes the "vendor a precedence
   ladder" work item entirely.
2. The SigV2 scope in #10 and ADR-0003 §4 is wrong: region-gated (12 v2-capable
   region strings in endpoints.json), not universal, and NOT caused by a custom
   endpoint. us-east-1 + MinIO -> SigV2; eu-south-2 + MinIO -> SigV4.
3. Config(ignore_configured_endpoint_urls=True) must NEVER be passed: a no-op
   when an explicit endpoint is set, and it retargets an AWS_ENDPOINT_URL_S3
   user to AWS when one is not. Two independent design drafts passed it
   unconditionally -- exactly the silent data-target move this ADR prevents.

DECIDED: S3Connection is a frozen picklable spec with NO live-object escape
hatch (checked: no dependent passes client=), so "every s3dol store pickles" is
unconditional. resolve(spec, environ, aws_config) is pure with per-field
provenance. s3dol owns two endpoint rungs and hands botocore one value; every
other field is a ladder bottoming out in OMIT THE KEY (measured: passing None
overrides a profile, omitting preserves it). Presets resolve in two passes and
detection supplies the full row. anon is bool -- 'auto' DEFERRED to v1.x,
because the guard count went 4->6->7 across three review rounds, each finding
another silent-credential-downgrade path. The migration warning is a
differential through v1's own resolver, not a frozen copy of v0. No strict=
kwarg; filterwarnings on S3DolWarning is strict mode with zero API.

OTHER MEASURED FACTS THAT SHAPED IT: nothing live pickles (so #15's "a
botocore.Session" is impossible); profile_name + ANY credential kwarg silently
discards the profile's credentials; reading .access_key triggers a network
refresh, so diagnose() must never touch it; repr() of a botocore provider chain
dumps the entire os.environ; botocore does not read AWS_REGION; anonymous HEAD
under moto makes every key read as absent, so anon+deny_means_absent is banned.

Amends 0003 §1/§4/§5/§6, 0004 §3, 0007 §3/§4, 0008, 0011 §D5 with inline
banners. Adds botocore>=1.36 and s3transfer>=0.11.2 floors (both were
unpinned while the design sets knobs that only exist from 1.36).

Produced by a probe -> design -> refute -> repair -> integrate pass; all five
first-round designs were refuted with kill-shots, and the integration found and
resolved 19 cross-question contradictions.
@thorwhalen
thorwhalen merged commit c7e6b4c into master Aug 11, 2026
8 checks passed
@thorwhalen
thorwhalen deleted the claude/adr-0012-credential-endpoint-resolution branch August 11, 2026 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant