You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
refactor(kosli): add a typed Kosli API client core - #1248
Commands build every Kosli API call themselves. Each one joins global.Host with api/v2 and global.Org, passes global.ApiToken, and guards against the (nil, nil) that requests.Client.Do returns on a dry run. Most of them then decode the body by hand. There are 80 such call sites, and some endpoints are built in two or three places.
This PR adds internal/kosli, a client that will hold one file per tag of the OpenAPI spec. It follows the conventions of terraform-provider-kosli/pkg/client: ctx first, typed structs next to each endpoint, and Is* error helpers. This first slice is only the core. It has no endpoints and no callers yet, and nothing in cmd/kosli changes.
New(sender, host, org, token). Endpoint files will build on three unexported helpers: endpoint(segments…), send(ctx, params) and decode[T].
Result{Raw, Created} and Response[T]{Result; Value}. Raw is the server's body exactly as it arrived, so --output json can keep printing it unchanged. Created replaces the res.Resp.StatusCode == 200 checks.
DryRun(sender) is a sender adapter. GETs still reach the server, as they do today. Writes are logged and not sent, using the existing payload printing in requests. A dry-run result is an empty Result, not nil.
APIError is an alias of requests.APIError, with IsNotFound, IsConflict and IsForbidden added.
Changes to internal/requests
RequestParams.Context is new. Nil means context.Background(), so existing callers are unaffected.
Transport errors are now wrapped with %w instead of %v. The message is the same, and errors.Is(err, context.Canceled) now works.
Worth knowing
A 409, 5xx or 429 is retried. When the retries run out, the caller gets a plain "giving up after N attempt(s)" error and not an APIError. IsConflict therefore only matches a request that sets DisableConflictRetry. This is the same as on main.
Next slices
Each slice is its own PR, stacked on this one:
GetTrail, used by get trail and evaluate. This slice also builds the client in PersistentPreRunE.
Artifacts
Environments, with snapshotReporter moved into the client
Evaluations
Attestations
The remaining tags, one per PR
Tests
There are 12 httptest tests in internal/kosli. make lint is clean. I have not run the integration suite locally for this PR.
Checklist
Docs are autogenerated from CLI help — make sure the help text reflects your changes (no help text changes)
Helm chart (charts/k8s-reporter/) updated, if needed. Note: these changes live in a separate PR (n/a)
Follow-up review of new commits (98849b38..c624320e)
Fetch previous review findings and diff the new commits
Check each previous finding against the new commits
Scan the changed hunks for new bugs/regressions
Post summary
Previous findings — status
Race in newFakeServer's handler (client_test.go:35) — Resolved. require.NoError → assert.NoError in 131a747, so FailNow is no longer called off the test goroutine. Author confirmed go test -race ./internal/kosli/... passes (I wasn't able to run tests myself in this job — no tool access to execute go test).
!= http.MethodGet misclassifies HEAD/OPTIONS as writes, and mutates the caller's params (dryrun.go) — Resolved. c624320 replaces the negative check with an explicit allow-list switch (GET, HEAD, OPTIONS pass through; everything else is a write), and writes now go through a local copy (write := *params; write.DryRun = true) instead of mutating the caller's struct. New tests TestDryRunStillSendsTheOtherSafeMethods and TestDryRunLeavesTheCallersParamsUnchanged cover both points directly.
Dry-run write returns Created: false, indistinguishable from a real update (client.go:73) — Not addressed, as expected — this was flagged as something to plan for in a later slice (needs a DryRun bool on Result or similar), not a fix requested for this PR.
New issues in the changed lines: none found. The allow-list switch and copy-before-mutate approach are correct; the shallow copy of RequestParams is safe since no field it shares (maps/context) is touched by DryRun.
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
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.
Commands build every Kosli API call themselves. Each one joins
global.Hostwithapi/v2andglobal.Org, passesglobal.ApiToken, and guards against the(nil, nil)thatrequests.Client.Doreturns on a dry run. Most of them then decode the body by hand. There are 80 such call sites, and some endpoints are built in two or three places.This PR adds
internal/kosli, a client that will hold one file per tag of the OpenAPI spec. It follows the conventions ofterraform-provider-kosli/pkg/client: ctx first, typed structs next to each endpoint, andIs*error helpers. This first slice is only the core. It has no endpoints and no callers yet, and nothing incmd/koslichanges.New(sender, host, org, token). Endpoint files will build on three unexported helpers:endpoint(segments…),send(ctx, params)anddecode[T].Result{Raw, Created}andResponse[T]{Result; Value}.Rawis the server's body exactly as it arrived, so--output jsoncan keep printing it unchanged.Createdreplaces theres.Resp.StatusCode == 200checks.DryRun(sender)is a sender adapter. GETs still reach the server, as they do today. Writes are logged and not sent, using the existing payload printing inrequests. A dry-run result is an emptyResult, not nil.APIErroris an alias ofrequests.APIError, withIsNotFound,IsConflictandIsForbiddenadded.Changes to
internal/requestsRequestParams.Contextis new. Nil meanscontext.Background(), so existing callers are unaffected.%winstead of%v. The message is the same, anderrors.Is(err, context.Canceled)now works.Worth knowing
A 409, 5xx or 429 is retried. When the retries run out, the caller gets a plain "giving up after N attempt(s)" error and not an
APIError.IsConflicttherefore only matches a request that setsDisableConflictRetry. This is the same as on main.Next slices
Each slice is its own PR, stacked on this one:
GetTrail, used byget trailandevaluate. This slice also builds the client inPersistentPreRunE.snapshotReportermoved into the clientTests
There are 12 httptest tests in
internal/kosli.make lintis clean. I have not run the integration suite locally for this PR.Checklist
Docs are autogenerated from CLI help — make sure the help text reflects your changes(no help text changes)Helm chart ((n/a)charts/k8s-reporter/) updated, if needed. Note: these changes live in a separate PRTerraform provider and related changes (terraform-provider-kosli, terraform-aws-evidence-reporter, terraform-aws-kosli-reporter) updated, if needed(n/a)