s2/lite
detail-app[bot] 0e99007688
fix(lite): resolve AWS region from profile chain for static credentials (#780)
**Detail bug report:** [View on
Detail](https://app.detail.dev/org_89d327b3-b883-4365-b6a3-46b6701342a9/bugs/bug_8cac9425-ce79-4db4-b569-bf59c78d8d81)

Closes #778

## Bug

In `lite/src/server.rs`, `s3_builder()` builds the `object_store` AWS S3
client backing SlateDB. It branches on whether static env credentials
(`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY`) are present:

- The **static-credentials arm** set credentials but never resolved the
region — it relied solely on `AmazonS3Builder::from_env()`, which reads
only `AWS_*` env vars and silently falls back to `us-east-1` when
`AWS_REGION`/`AWS_DEFAULT_REGION` are unset.
- The **sibling `_ =>` arm** resolved region from the full AWS default
chain (env → profile → IMDS) via `aws_config::load_defaults` and called
`with_region`.

The two arms of the same `match` resolved the same field (`region`) by
different chains. A deployment that supplied credentials via env but
region via `~/.aws/config` hit the static arm, dropped the profile
region, and targeted `us-east-1`. Against real AWS S3 for a bucket
elsewhere this produces a wrong-region `301`; `object_store` does not
disable reqwest's redirect following, and `remove_sensitive_headers`
strips the `Authorization` header on the cross-host redirect, so the
followed request to the correct-region endpoint is unauthenticated and
AWS rejects it with a non-retryable `403`.

## Fix

The static arm now resolves region env-first (`AWS_REGION` then
`AWS_DEFAULT_REGION`), and only when both env knobs are absent falls
back to `aws_config::load_defaults(...).await.region()` — the same
standard chain the `_ =>` arm uses — then applies
`builder.with_region(region)`. This makes both arms resolve region by
the same chain tiers while preserving the env-first fast path for the
common static-creds + `AWS_REGION` workflow (`load_defaults` is only
reached when env region is absent, i.e. the trigger intersection). The
credential wiring (`StaticCredentialProvider` + `AWS_SESSION_TOKEN`) is
unchanged; the change is purely additive region resolution.

## Testing

Added three hermetic `#[tokio::test]` regression tests in
`lite/src/server.rs` (`mod tests`) covering the static arm's new
contract:
- profile region is applied when env region is absent (the regression —
confirmed to fail on the pre-fix code with `left: None, right:
Some("eu-west-1")` and pass after the fix)
- env region takes precedence over profile (preserves the documented
fast path)
- no bogus region is synthesized when no region is available anywhere

Routine checks all pass: `cargo check --locked -p s2-lite` (default and
`--all-features`), `cargo +nightly fmt --all --check`, `cargo clippy
--locked -p s2-lite --all-targets -- -D warnings --allow deprecated`,
and the full s2-lite nextest suite (331/331).

End-to-end smoke (not versioned — ran against a containerized
S3-compatible backend during development): built the release `server`
binary and ran it against `adobe/s3mock` over HTTP with static env creds
and the region supplied only via `AWS_CONFIG_FILE` (the bug-trigger
intersection, `AWS_REGION`/`AWS_DEFAULT_REGION` unset). The server
logged the resolved `region=us-east-1` from the profile tier (previously
silently dropped), SlateDB wrote manifest/WAL/compaction objects to S3,
and the full basin/stream/append/tail API lifecycle succeeded (HTTP
201/200), with a clean SIGTERM shutdown and no `403`/`301`/redirect
errors. (LocalStack's latest image is license-gated; S3Mock was used as
the equivalent HTTP S3-compatible backend.) This confirms the
custom-endpoint static-creds path still works and the profile region is
now honored; it does not reproduce the live-AWS redirect/auth-strip
chain because S3Mock does not issue wrong-region 301s or validate SigV4
region.

Not verified: live AWS S3 end-to-end (a real bucket in a non-`us-east-1`
region with static keys). The environment has no AWS credentials (`aws
sts get-caller-identity` returns `Unable to locate credentials`, no
`~/.aws`, no IMDS), so the live-AWS 301 → auth-stripped 403 path could
not be captured directly. The hermetic regression test covers the
trigger (region misresolution), and the S3Mock smoke covers
no-regression plus profile-region resolution; the live-AWS HTTP-chain
leg is the only uncovered item.

---
_Automatic Fixes PRs can be [configured
here](https://app.detail.dev/org_89d327b3-b883-4365-b6a3-46b6701342a9/settings/repos/repo_c4bd6a47-9b7d-4b62-9c18-8cf0ac18a8f9/bugs)._

---------

Co-authored-by: detail-app[bot] <180357370+detail-app[bot]@users.noreply.github.com>
History 2026-09-27 09:18:22 -07:00
..
src fix(lite): resolve AWS region from profile chain for static credentials (#780) 2026-09-27 09:18:22 -07:00
tests feat!: expose storage classes as strings and in location responses (#775) 2026-09-26 04:29:54 +05:30
Cargo.toml chore: release (#783) 2026-09-26 04:47:13 +05:30
CHANGELOG.md chore: release (#783) 2026-09-26 04:47:13 +05:30