Repository navigation
feat: add cloudkittest, the contract kit - #3
Merged
Merged
Conversation
An adapter in its own package has to return transport and provider errors through the one redaction rule, and its callers still match ErrEgressDenied and ErrDenied with errors.Is. The unexported redactErr already did both; RedactError exposes it, and redactErr now delegates.
Run and Check run nine contract cases against any Provider: transport only, nil transport, egress, read-only token, plan drift, destroy, redaction, cloud-init and SSH. Each case builds its own registry over a replaying Recorder or a fault-injecting transport, with a token generated for the run, so nothing reaches the network. Recorder replays one cassette, answers each interaction once and in order, and refuses any request it does not hold. Recordings load only through ParseRecordings, which checks every recorded and synthetic response against the provider's OpenAPI document and refuses any recording carrying an Authorization header or a credential value. The validator implements a stated JSON Schema subset and refuses every other keyword when the document loads. Synthetic responses come from the document's examples and are marked as such. The core tests' fake provider is written again against a hand-written spec under testdata; it passes the suite, and one planted defect per case fails that case.
The file floor rises to the exact 28 the scan reads. Context-first now also checks exported func types and reads cloudkittest's hooks, with the floor at the measured 14 signatures. The shipped-surface guard covers cloudkittest's exported names and RedactError.
A reference page for cloudkittest (the nine cases, cassettes, recordings, Recorder, the validator's subset, errors), the reasons for spec-checked replay in the architecture guide, and the changelog.
imanimanyara
marked this pull request as ready for review
November 4, 2026 20:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 of cloudkit: the contract kit every adapter passes.
cloudkittest.Run/Checkrun nine contract cases against anyProvider: transport only, nil transport, egress, read-only token, plan drift, destroy, redaction, cloud-init and SSH. Each case uses its own registry, a token generated for the run, no retries, refused dialing, and either a replayingRecorderor a fault-injecting transport. Nothing reaches the network.Checkreturns aReportwithout a*testing.T, so the descriptor loader can use it later.Recorderreplays one cassette and answers each interaction once, in order. It refuses any request the cassette does not hold (ErrUnexpectedRequest) and reports interactions nothing used, and the suite fails on either.ParseRecordingschecks every recorded and synthetic response against the provider's OpenAPI document (ErrNotInSpec,ErrSchemaViolation). It refuses any recording that carries anAuthorization, cookie or API-key header, or a valuecloudkit.Redactwould change (ErrCredentialInRecording).ParseSpec,Spec.ValidateResponse) supports a stated JSON Schema subset:type,nullable,required,properties,additionalProperties,items,enumand local$ref, plus annotations it does not check. Any other keyword fails the load withErrUnsupportedKeyword.Spec.Synthesizebuilds a response from the document's examples and marks itSynthetic.cloudkit.RedactError(new export) redacts an error's message and keeps its chain, so an adapter outside the root package can redact and its callers still matchErrEgressDenied.cloudkittesttoo: no default client or transport, context first on its hook signatures, and its shipped names preserved.Stdlib only; no
go.sum. Every existing exported symbol is unchanged.Proof
src/cloudkittest/testdata/. It passes all nine cases throughRun.TestEachCaseCatchesItsDefect), and each fails its own case with the expected message:testdata/broken-schema.recordings.jsonfails to load withErrSchemaViolationat$.write.Authorizationand token in a recording, schema violation, unknown keyword, default transport or client incloudkittest, file floor, context-first, shipped surface, the synthetic marker, andRedactError's chain.Checks
make ciandmake lint(0 issues) pass locally. Coverage is 95.9% forcloudkitand 84.1% forcloudkittest.gitleaks detectover the full history found no leaks.The cloud-init and SSH cases run here against stand-ins in the test file. The real renderer and SSH client arrive with the generic path and plug into
Suite.CloudInitandSuite.SSH. Until then, a suite withoutSSHreports that case as skipped, with its reason.