# 8.6 — `X-Service: s3` adapter, read-only object surface (GREEN) Phase: 8 — ServiceAdapter CRD rollout Stage: RED Depends on: 8.1, 8.2, 8.3 Design contract: [API_ROUTING_HYBRID_DESIGN.md](../API_ROUTING_HYBRID_DESIGN.md) §2 (`bucket/{key}` resource shape). No prior task or doc names the actual MinIO Service — `grep -ri minio` across this repo turns up only prose in `REQUIREMENTS.md`/ `README.md`/`tasks/INDEX.md`/`tasks/7.4-db-prefix.md`, no manifest. **Confirm the real Service name/namespace/port in-cluster before writing the CR** — do not guess a hostname. **G2 boundary, same as [7.4](7.4-db-prefix.md):** the gateway holds no MinIO access key or secret key. If this adapter's design wants the gateway to hold a credential, the design is wrong — put the credential-holding logic in a service behind the gateway (e.g. a small internal proxy that signs requests) and adapt to *that*, not to MinIO directly, unless MinIO itself supports anonymous/read-only bucket policies that make a credential unnecessary for the specific buckets exposed here. - [ ] `k8s/serviceadapter-s3.yaml` CR: `serviceName: s3`, `auth.capability: s3:read` - [ ] Resource `bucket` maps `GET bucket/{key}` → object read, `DELETE bucket/{key}` → object delete — **only if** a write/delete capability is explicitly wanted; default to read-only (`GET` only) unless told otherwise, consistent with 7.4's "no write, no delete" rule for the `/db/*` surface this supersedes - [ ] Result listing (if a bucket-list resource is added) is paginated with a bounded page size — no unbounded listing, same rule 7.4 already established - [ ] `requestSchema`/`responseSchema` per the KV+type DSL (8.3) — define once the actual MinIO/proxy response shape is confirmed, not invented ahead of it - [ ] NetworkPolicy reaches only the confirmed MinIO Service, nothing broader - [ ] `/db/*` prefix-mounted MinIO read paths (if any exist from 7.4) are removed once this adapter is verified live, to avoid two auth paths to the same data ## Verify ```bash curl -s -o /dev/null -w '%{http_code}\n' https://api.riotpiao.com/ \ -H 'X-Service: s3' -H 'X-Resource: bucket/some-key' # expected: 401 without a token curl -s -X DELETE -o /dev/null -w '%{http_code}\n' \ -H "Authorization: Bearer $S3_READ_TOKEN" \ https://api.riotpiao.com/ -H 'X-Service: s3' -H 'X-Resource: bucket/some-key' # expected: 404 or 405 if this adapter ships read-only — no mutating verb is routable curl -s -H "Authorization: Bearer $S3_READ_TOKEN" \ https://api.riotpiao.com/ -H 'X-Service: s3' -H 'X-Resource: bucket/known-object-key' # expected: 200, object bytes or metadata per the confirmed response shape kubectl -n api get pod -l app=api-gateway -o jsonpath='{range .items[0].spec.containers[0].env[*]}{.name}{"\n"}{end}' \ | grep -Ei 'minio|access_key|secret_key' # expected: no output — gateway carries no MinIO credential ```