Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.67.0"
".": "0.68.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 119
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-51549f813f3002e18c6ca8d850cc0c7932828d511c151e0412c73b6798d19e30.yml
openapi_spec_hash: ee77b293c4bda91c1a32cfdd12b8739e
config_hash: 57567e00b41af47cef1b78e51b747aa0
configured_endpoints: 120
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-d26459bd3514237e8d757be3cbdc76ca62f6083504b85601e57db830888964f7.yml
openapi_spec_hash: 5dd151a8099398819a97692c1c60c3c6
config_hash: 03c7e57f268c750e2415831662e95969
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## 0.68.0 (2026-06-15)

Full Changelog: [v0.67.0...v0.68.0](https://github.com/kernel/kernel-go-sdk/compare/v0.67.0...v0.68.0)

### Features

* Add API key rotate endpoint ([04d4a12](https://github.com/kernel/kernel-go-sdk/commit/04d4a12f1f98a5745b7ca706a22cab71cb625866))
* **api:** surface deleted/expired API keys for audit trail (KERNEL-1350) ([e7f9fd8](https://github.com/kernel/kernel-go-sdk/commit/e7f9fd8aa890b660d675b22ad48f869504817b2d))


### Refactors

* **api:** align API key audit surface with browser sibling (KERNEL-1350) ([9e23506](https://github.com/kernel/kernel-go-sdk/commit/9e2350674aafa75a45c4b843d8a43b31c4656bd6))

## 0.67.0 (2026-06-11)

Full Changelog: [v0.66.0...v0.67.0](https://github.com/kernel/kernel-go-sdk/compare/v0.66.0...v0.67.0)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->

```sh
go get -u 'github.com/kernel/kernel-go-sdk@v0.67.0'
go get -u 'github.com/kernel/kernel-go-sdk@v0.68.0'
```

<!-- x-release-please-end -->
Expand Down
3 changes: 2 additions & 1 deletion api.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,11 @@ Response Types:
Methods:

- <code title="post /org/api_keys">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyNewParams">APIKeyNewParams</a>) (\*<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#CreatedAPIKey">CreatedAPIKey</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /org/api_keys/{id}">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (\*<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKey">APIKey</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /org/api_keys/{id}">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyGetParams">APIKeyGetParams</a>) (\*<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKey">APIKey</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="patch /org/api_keys/{id}">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.Update">Update</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyUpdateParams">APIKeyUpdateParams</a>) (\*<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKey">APIKey</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /org/api_keys">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyListParams">APIKeyListParams</a>) (\*<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk/packages/pagination#OffsetPagination">OffsetPagination</a>[<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKey">APIKey</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="delete /org/api_keys/{id}">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
- <code title="post /org/api_keys/{id}/rotate">client.APIKeys.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyService.Rotate">Rotate</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#APIKeyRotateParams">APIKeyRotateParams</a>) (\*<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk">kernel</a>.<a href="https://pkg.go.dev/github.com/kernel/kernel-go-sdk#CreatedAPIKey">CreatedAPIKey</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>

# CredentialProviders

Expand Down
75 changes: 73 additions & 2 deletions apikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ func (r *APIKeyService) New(ctx context.Context, body APIKeyNewParams, opts ...o

// Retrieve an API key by ID for the authenticated organization. API keys are
// masked.
func (r *APIKeyService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *APIKey, err error) {
func (r *APIKeyService) Get(ctx context.Context, id string, query APIKeyGetParams, opts ...option.RequestOption) (res *APIKey, err error) {
opts = slices.Concat(r.Options, opts)
if id == "" {
err = errors.New("missing required id parameter")
return nil, err
}
path := fmt.Sprintf("org/api_keys/%s", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...)
return res, err
}

Expand Down Expand Up @@ -110,12 +110,29 @@ func (r *APIKeyService) Delete(ctx context.Context, id string, opts ...option.Re
return err
}

// Rotate an API key. Issues a new key that copies the name and project of the
// rotated key, and schedules the rotated key to expire after a grace period so
// in-flight callers can swap over. The new plaintext key is returned once.
func (r *APIKeyService) Rotate(ctx context.Context, id string, body APIKeyRotateParams, opts ...option.RequestOption) (res *CreatedAPIKey, err error) {
opts = slices.Concat(r.Options, opts)
if id == "" {
err = errors.New("missing required id parameter")
return nil, err
}
path := fmt.Sprintf("org/api_keys/%s/rotate", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
return res, err
}

type APIKey struct {
// Unique API key identifier
ID string `json:"id" api:"required"`
// When the API key was created
CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
CreatedBy APIKeyCreatedBy `json:"created_by" api:"required"`
// When the API key was deleted (soft-deleted). Null for keys that have not been
// deleted.
DeletedAt time.Time `json:"deleted_at" api:"required" format:"date-time"`
// When the API key expires
ExpiresAt time.Time `json:"expires_at" api:"required" format:"date-time"`
// Masked version of the API key
Expand All @@ -132,6 +149,7 @@ type APIKey struct {
ID respjson.Field
CreatedAt respjson.Field
CreatedBy respjson.Field
DeletedAt respjson.Field
ExpiresAt respjson.Field
MaskedKey respjson.Field
Name respjson.Field
Expand Down Expand Up @@ -208,6 +226,21 @@ func (r *APIKeyNewParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}

type APIKeyGetParams struct {
// When true, return the API key even if it has been deleted (soft-deleted), for
// audit purposes. Defaults to false, which returns 404 for a deleted key.
IncludeDeleted param.Opt[bool] `query:"include_deleted,omitzero" json:"-"`
paramObj
}

// URLQuery serializes [APIKeyGetParams]'s query parameters as `url.Values`.
func (r APIKeyGetParams) URLQuery() (v url.Values, err error) {
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
ArrayFormat: apiquery.ArrayQueryFormatComma,
NestedFormat: apiquery.NestedQueryFormatBrackets,
})
}

type APIKeyUpdateParams struct {
// New API key name
Name string `json:"name" api:"required"`
Expand All @@ -223,6 +256,9 @@ func (r *APIKeyUpdateParams) UnmarshalJSON(data []byte) error {
}

type APIKeyListParams struct {
// Deprecated: use status=all instead. When true, include deleted (soft-deleted)
// API keys in the results for audit purposes.
IncludeDeleted param.Opt[bool] `query:"include_deleted,omitzero" json:"-"`
// Maximum number of results to return
Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
// Number of results to skip
Expand All @@ -238,6 +274,12 @@ type APIKeyListParams struct {
//
// Any of "asc", "desc".
SortDirection APIKeyListParamsSortDirection `query:"sort_direction,omitzero" json:"-"`
// Filter API keys by status. "active" returns keys that are not deleted (default;
// expired-but-not-deleted keys are still included), "deleted" returns only
// soft-deleted keys, "all" returns both.
//
// Any of "active", "deleted", "all".
Status APIKeyListParamsStatus `query:"status,omitzero" json:"-"`
paramObj
}

Expand Down Expand Up @@ -265,3 +307,32 @@ const (
APIKeyListParamsSortDirectionAsc APIKeyListParamsSortDirection = "asc"
APIKeyListParamsSortDirectionDesc APIKeyListParamsSortDirection = "desc"
)

// Filter API keys by status. "active" returns keys that are not deleted (default;
// expired-but-not-deleted keys are still included), "deleted" returns only
// soft-deleted keys, "all" returns both.
type APIKeyListParamsStatus string

const (
APIKeyListParamsStatusActive APIKeyListParamsStatus = "active"
APIKeyListParamsStatusDeleted APIKeyListParamsStatus = "deleted"
APIKeyListParamsStatusAll APIKeyListParamsStatus = "all"
)

type APIKeyRotateParams struct {
// Lifetime in days for the new key, up to 3650. Omit to reuse the rotated key's
// original lifetime, or never-expires if it had none.
DaysToExpire param.Opt[int64] `json:"days_to_expire,omitzero"`
// Grace period in days before the rotated key expires. Use 0 to expire it
// immediately. Omit for the default grace period of 7 days.
ExpireInDays param.Opt[int64] `json:"expire_in_days,omitzero"`
paramObj
}

func (r APIKeyRotateParams) MarshalJSON() (data []byte, err error) {
type shadow APIKeyRotateParams
return param.MarshalObject(r, (*shadow)(&r))
}
func (r *APIKeyRotateParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
52 changes: 45 additions & 7 deletions apikey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestAPIKeyNewWithOptionalParams(t *testing.T) {
}
}

func TestAPIKeyGet(t *testing.T) {
func TestAPIKeyGetWithOptionalParams(t *testing.T) {
t.Skip("Mock server tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
Expand All @@ -53,7 +53,13 @@ func TestAPIKeyGet(t *testing.T) {
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
_, err := client.APIKeys.Get(context.TODO(), "id")
_, err := client.APIKeys.Get(
context.TODO(),
"id",
kernel.APIKeyGetParams{
IncludeDeleted: kernel.Bool(true),
},
)
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
Expand Down Expand Up @@ -106,11 +112,13 @@ func TestAPIKeyListWithOptionalParams(t *testing.T) {
option.WithAPIKey("My API Key"),
)
_, err := client.APIKeys.List(context.TODO(), kernel.APIKeyListParams{
Limit: kernel.Int(100),
Offset: kernel.Int(0),
Query: kernel.String("query"),
SortBy: kernel.APIKeyListParamsSortByCreatedAt,
SortDirection: kernel.APIKeyListParamsSortDirectionAsc,
IncludeDeleted: kernel.Bool(true),
Limit: kernel.Int(100),
Offset: kernel.Int(0),
Query: kernel.String("query"),
SortBy: kernel.APIKeyListParamsSortByCreatedAt,
SortDirection: kernel.APIKeyListParamsSortDirectionAsc,
Status: kernel.APIKeyListParamsStatusActive,
})
if err != nil {
var apierr *kernel.Error
Expand Down Expand Up @@ -143,3 +151,33 @@ func TestAPIKeyDelete(t *testing.T) {
t.Fatalf("err should be nil: %s", err.Error())
}
}

func TestAPIKeyRotateWithOptionalParams(t *testing.T) {
t.Skip("Mock server tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
baseURL = envURL
}
if !testutil.CheckTestServer(t, baseURL) {
return
}
client := kernel.NewClient(
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
_, err := client.APIKeys.Rotate(
context.TODO(),
"id",
kernel.APIKeyRotateParams{
DaysToExpire: kernel.Int(30),
ExpireInDays: kernel.Int(7),
},
)
if err != nil {
var apierr *kernel.Error
if errors.As(err, &apierr) {
t.Log(string(apierr.DumpRequest(true)))
}
t.Fatalf("err should be nil: %s", err.Error())
}
}
2 changes: 1 addition & 1 deletion internal/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

package internal

const PackageVersion = "0.67.0" // x-release-please-version
const PackageVersion = "0.68.0" // x-release-please-version
Loading