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 two unexported helpers, endpoint(segments…) and send(ctx, params).
Result{Raw, Created} and Response[T], which embeds Result. Raw is the server's body exactly as it arrived, so --output json can keep printing it unchanged. Response[T] decodes the body only when Value() is called. That way --output json never decodes, and a field the type doesn't fit fails only the output that reads it (review of refactor(get artifact, assert artifact): fetch through the Kosli API client #1269). 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)
The new commits in this range touch only internal/kosli/client.go and internal/kosli/client_test.go, changing decode[T]/Response[T].Value into a lazy (*Response[T]).Value() method (commit 44547df0). None of the three prior findings' locations are touched by this range — their fixes (131a7472, c624320e) landed in earlier commits, before the BEFORE sha:
client_test.go:35 (race-unsafe require.NoError in the server goroutine) — resolved, thread closed.
client.go:75 (dry-run Created ambiguity) — acknowledged by the author as intentional (kept out of Result by design); no code change, thread closed.
Reviewed the lazy-decode change itself (not previously flagged) for regressions: it's correct — Value() still returns the zero value on an empty body, still wraps unmarshal errors the same way, and Raw stays untouched on a decode error so --output json is unaffected. No new bugs found; no inline comments posted.
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 two unexported helpers,endpoint(segments…)andsend(ctx, params).Result{Raw, Created}andResponse[T], which embedsResult.Rawis the server's body exactly as it arrived, so--output jsoncan keep printing it unchanged.Response[T]decodes the body only whenValue()is called. That way--output jsonnever decodes, and a field the type doesn't fit fails only the output that reads it (review of refactor(get artifact, assert artifact): fetch through the Kosli API client #1269).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)