Skip to content

feat: multi-CSP groundwork — IR, ModelSource, provider config, auth adapters (Phase 2) - #135

Merged
skyoo2003 merged 1 commit into
mainfrom
feat/phase2-multi-csp-groundwork
Sep 5, 2026
Merged

skyoo2003 merged 1 commit into
mainfrom
feat/phase2-multi-csp-groundwork

Conversation

@skyoo2003

Copy link
Copy Markdown
Owner

Summary

Completes Phase 2 — Architectural Preparation of docs/roadmap.md: the internal refactor that makes adding a second cloud provider an addition rather than a fork. No non-AWS service ships here and no AWS behaviour changes.

Related Issue

No tracking issue exists — this implements the Phase 2 checklist in docs/roadmap.md directly. Refs the roadmap, closes nothing.

Changes

Intermediate Representation — internal/codegen/ir holds the provider-neutral *ir.Model. The parser used to produce a SmithyModel that generators read directly, so the only format DevCloud could ever read was the one its type was named after. Generators now read only the IR; SmithyModel is gone.

ModelSource — internal/codegen/source.go. One interface per API description format. SmithySource is the first implementation and owns its own detection (a top-level smithy version key), so cmd/codegen hands each file to SourceFor and never names a format. A file no source claims is now an error rather than a quiet skip — the .json extension filter that used to decide that was format knowledge living in the driver.

Provider namespacing in config — service blocks can be written as providers.aws.services.*, forward-compatible with providers.azure.*. The top-level services block is the same block under its historical name and is not deprecated; providers.aws.services wins when both are written and names the loser in a warning. A block for a provider this build cannot serve loads with a warning instead of failing, so a config written for a later DevCloud still starts this one. AWS data dirs stay flat (<base>/<id>) because that layout is a 1.x guarantee; other providers nest under their own name so same-named services cannot collide.

Plugin CSP-neutrality review — ServicePlugin needs no change; the review is written up in docs/plugin-api.md. The CSP is carried by the optional ProviderScoped interface, read through plugin.ProviderOf. Making it a ServicePlugin method would have forced an edit to all 104 in-tree providers so each could state the value it already defaults to, and would have broken the v1.x contract for no gain. Startup now resolves config with cfg.ProviderService(plugin.ProviderOf(p), id).

Per-provider auth adapters — internal/auth holds one Adapter per provider, SigV4 being AWS's. The caller's claimed identity reaches every plugin via auth.FromContext and appears as a new region field on GET /devcloud/api/logs. Nothing is verified: rejecting unsigned calls would break every SDK pointed at DevCloud with placeholder credentials, which compatibility-policy.md documents as deliberate.

The adapter also removes a duplicate parse: protocol.go had its own SigV4 credential-scope reader used for routing, and now delegates — so routing and identity cannot disagree about what the caller signed for. One side effect worth noting in review: presigned URLs (X-Amz-Credential query) now yield a signing name where previously only the Authorization header did, which routes presigned non-S3 requests by scope instead of defaulting them to S3.

Test Plan

  • go build ./..., go vet ./..., gofmt -l — clean
  • golangci-lint run — 0 issues
  • go test ./... — all packages pass
  • make test-compat — 775 passed, run against the final tree. This is the check that matters for the protocol.go change.
  • make codegen re-run — generated output byte-identical, no drift
  • New tests: internal/codegen/source_test.go (format detection, including that an OpenAPI document is not claimed by Smithy), internal/auth/sigv4_test.go (header, presigned query, SigV2/unsigned rejection, truncated scope, context round-trip), and four internal/config tests covering both config spellings, the both-written warning, unknown-provider forward compatibility, and DEVCLOUD_SERVICES staying AWS-scoped.

Checklist

  • Self-reviewed the code
  • Added/updated tests
  • Lint/format passes (golangci-lint run)
  • Updated documentation (if applicable) — roadmap.md (Phase 2 → Complete, Phase 3 → Next), architecture.md (provider seams table, auth section, codegen pipeline), plugin-api.md (CSP-neutrality review, caller identity), configuration.md (provider namespacing), compatibility-policy.md
  • Added a Changie changelog fragment for user-facing changes — 3 fragments in changes/unreleased/

…dapters

Phase 2 of docs/roadmap.md: make adding a second cloud provider an addition
rather than a fork. No non-AWS service ships here, and no AWS behaviour
changes — the boto3 suite stays at 775 passing and `make codegen` output is
byte-identical.

Four seams, each of which used to be an edit and is now an append:

codegen — the parser produced a SmithyModel that generators read directly, so
the only format DevCloud could read was the one its type was named after.
internal/codegen/ir now holds the provider-neutral *ir.Model, and ModelSource
reads one format into it. SmithySource is the first implementation and owns
its own detection, so cmd/codegen hands each file to SourceFor and never names
a format. A file no source claims is an error rather than a quiet skip; the
extension filter that used to decide that was format knowledge in the driver.

config — service blocks can be written as providers.aws.services.*, forward
compatible with providers.azure.*. The top-level services block is the same
block under its historical name and is not deprecated; providers.aws.services
wins when both are written, and names the loser in a warning. A block for a
provider this build cannot serve loads with a warning instead of failing, so a
config written for a later DevCloud still starts this one. AWS data dirs stay
flat because that layout is a 1.x guarantee; other providers nest under their
own name so same-named services cannot collide.

plugin — ServicePlugin needed no change; the review is written up in
docs/plugin-api.md. The CSP is carried by the optional ProviderScoped
interface, read through plugin.ProviderOf. Making it a ServicePlugin method
would have forced an edit to all 104 in-tree providers so each could state the
value it already defaults to, and would have broken the v1.x contract for no
gain. Startup resolves config with cfg.ProviderService(plugin.ProviderOf(p), id).

auth — internal/auth holds one Adapter per provider, SigV4 being AWS's. The
caller's claimed identity reaches every plugin via auth.FromContext and shows
up as a new region field on GET /devcloud/api/logs. Nothing is verified:
rejecting unsigned calls would break every SDK pointed at DevCloud with
placeholder credentials, which compatibility-policy.md documents as deliberate.

The adapter also removes a duplicate parse. protocol.go had its own SigV4
credential-scope reader used for routing; it now delegates, so routing and
identity cannot disagree about what the caller signed for.
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests Test code and test infrastructure codegen Smithy codegen and generated code labels Sep 5, 2026
@skyoo2003
skyoo2003 merged commit 951e3cf into main Sep 5, 2026
8 checks passed
@skyoo2003
skyoo2003 deleted the feat/phase2-multi-csp-groundwork branch September 5, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codegen Smithy codegen and generated code documentation Improvements or additions to documentation tests Test code and test infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant