Skip to content
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.52.0"
".": "0.53.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 112
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-4ce09d1a7546ab36f578cb27d819187eeb90c580b11834c7ff7a375aa22f9a20.yml
openapi_spec_hash: 1043ab2d699f6c828680c3352cd4cece
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-b51c72a040c8dfea9c0693de6631feabfffe42922d5feb60b4ac0ee5c83bb8f4.yml
openapi_spec_hash: 8b671cfe4debe8d9ad7c39ba5b0eaf6d
config_hash: 08d55086449943a8fec212b870061a3f
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 0.53.0 (2026-05-08)

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

### Features

* Add 'switch' MFA option type for generic method-switcher links ([9bed035](https://github.com/kernel/kernel-go-sdk/commit/9bed035e6ab4fe139d1e4cdedfe3d4e4b1dada69))
* **api:** server-side search on GET /projects ([588318c](https://github.com/kernel/kernel-go-sdk/commit/588318ca172dd613cf7afcedbccd0ceca99c90ce))
* Scope name uniqueness to project for profiles, session_pools, extensions, credentials ([8032ad8](https://github.com/kernel/kernel-go-sdk/commit/8032ad8736ca5c903c487c6d2a1cf24c8324b3d9))


### Bug Fixes

* **go:** avoid panic when http.DefaultTransport is wrapped ([aa45d8f](https://github.com/kernel/kernel-go-sdk/commit/aa45d8fc9bec40dc017fc2b2660895cbdca9f7b4))


### Chores

* avoid embedding reflect.Type for dead code elimination ([b3465f1](https://github.com/kernel/kernel-go-sdk/commit/b3465f1174e2136bed8830cc4be18cf464068925))
* redact api-key headers in debug logs ([91f6f4a](https://github.com/kernel/kernel-go-sdk/commit/91f6f4ab43dd89c9bda453009efaf3fe2c210057))

## 0.52.0 (2026-04-29)

Full Changelog: [v0.51.0...v0.52.0](https://github.com/kernel/kernel-go-sdk/compare/v0.51.0...v0.52.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.52.0'
go get -u 'github.com/kernel/kernel-go-sdk@v0.53.0'
```

<!-- x-release-please-end -->
Expand Down
16 changes: 10 additions & 6 deletions authconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ type ManagedAuthDiscoveredField struct {
// If this field is associated with an MFA option, the type of that option (e.g.,
// password field linked to "Enter password" option)
//
// Any of "sms", "call", "email", "totp", "push", "password".
// Any of "sms", "call", "email", "totp", "push", "password", "switch".
LinkedMfaType string `json:"linked_mfa_type" api:"nullable"`
// Field placeholder
Placeholder string `json:"placeholder"`
Expand Down Expand Up @@ -491,9 +491,11 @@ const (
type ManagedAuthMfaOption struct {
// The visible option text
Label string `json:"label" api:"required"`
// The MFA delivery method type (includes password for auth method selection pages)
// The MFA delivery method type. Includes 'password' for auth method selection
// pages and 'switch' for generic method-switcher links like "Use another method"
// that do not name a specific method.
//
// Any of "sms", "call", "email", "totp", "push", "password".
// Any of "sms", "call", "email", "totp", "push", "password", "switch".
Type string `json:"type" api:"required"`
// Additional instructions from the site
Description string `json:"description" api:"nullable"`
Expand Down Expand Up @@ -992,7 +994,7 @@ type AuthConnectionFollowResponseManagedAuthStateDiscoveredField struct {
// If this field is associated with an MFA option, the type of that option (e.g.,
// password field linked to "Enter password" option)
//
// Any of "sms", "call", "email", "totp", "push", "password".
// Any of "sms", "call", "email", "totp", "push", "password", "switch".
LinkedMfaType string `json:"linked_mfa_type" api:"nullable"`
// Field placeholder
Placeholder string `json:"placeholder"`
Expand Down Expand Up @@ -1025,9 +1027,11 @@ func (r *AuthConnectionFollowResponseManagedAuthStateDiscoveredField) UnmarshalJ
type AuthConnectionFollowResponseManagedAuthStateMfaOption struct {
// The visible option text
Label string `json:"label" api:"required"`
// The MFA delivery method type (includes password for auth method selection pages)
// The MFA delivery method type. Includes 'password' for auth method selection
// pages and 'switch' for generic method-switcher links like "Use another method"
// that do not name a specific method.
//
// Any of "sms", "call", "email", "totp", "push", "password".
// Any of "sms", "call", "email", "totp", "push", "password", "switch".
Type string `json:"type" api:"required"`
// Additional instructions from the site
Description string `json:"description" api:"nullable"`
Expand Down
6 changes: 3 additions & 3 deletions browserpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ type BrowserPoolBrowserPoolConfig struct {
// If true, launches the browser in kiosk mode to hide address bar and tabs in live
// view.
KioskMode bool `json:"kiosk_mode"`
// Optional name for the browser pool. Must be unique within the organization.
// Optional name for the browser pool. Must be unique within the project.
Name string `json:"name"`
// Profile selection for the browser session. Provide either id or name. If
// specified, the matching profile will be loaded into the browser session.
Expand Down Expand Up @@ -335,7 +335,7 @@ type BrowserPoolNewParams struct {
// If true, launches the browser in kiosk mode to hide address bar and tabs in live
// view.
KioskMode param.Opt[bool] `json:"kiosk_mode,omitzero"`
// Optional name for the browser pool. Must be unique within the organization.
// Optional name for the browser pool. Must be unique within the project.
Name param.Opt[string] `json:"name,omitzero"`
// Optional proxy to associate to the browser session. Must reference a proxy
// belonging to the caller's org.
Expand Down Expand Up @@ -396,7 +396,7 @@ type BrowserPoolUpdateParams struct {
// If true, launches the browser in kiosk mode to hide address bar and tabs in live
// view.
KioskMode param.Opt[bool] `json:"kiosk_mode,omitzero"`
// Optional name for the browser pool. Must be unique within the organization.
// Optional name for the browser pool. Must be unique within the project.
Name param.Opt[string] `json:"name,omitzero"`
// Optional proxy to associate to the browser session. Must reference a proxy
// belonging to the caller's org.
Expand Down
4 changes: 2 additions & 2 deletions credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (r *CredentialService) TotpCode(ctx context.Context, idOrName string, opts
type CreateCredentialRequestParam struct {
// Target domain this credential is for
Domain string `json:"domain" api:"required"`
// Unique name for the credential within the organization
// Unique name for the credential within the project
Name string `json:"name" api:"required"`
// Field name to value mapping (e.g., username, password)
Values map[string]string `json:"values,omitzero" api:"required"`
Expand Down Expand Up @@ -164,7 +164,7 @@ type Credential struct {
CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"`
// Target domain this credential is for
Domain string `json:"domain" api:"required"`
// Unique name for the credential within the organization
// Unique name for the credential within the project
Name string `json:"name" api:"required"`
// When the credential was last updated
UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"`
Expand Down
18 changes: 12 additions & 6 deletions default_http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ import (
const defaultResponseHeaderTimeout = 10 * time.Minute

// defaultHTTPClient returns an [*http.Client] used when the caller does not
// supply one via [option.WithHTTPClient]. It clones [http.DefaultTransport]
// and adds a [http.Transport.ResponseHeaderTimeout] so stuck connections
// fail fast instead of compounding across retries.
// supply one via [option.WithHTTPClient]. When [http.DefaultTransport] is the
// stdlib [*http.Transport], it is cloned and a [http.Transport.ResponseHeaderTimeout]
// is set so stuck connections fail fast instead of compounding across retries.
// If [http.DefaultTransport] has been wrapped (for example by otelhttp for
// distributed tracing), the wrapping is preserved and the header timeout is
// skipped.
func defaultHTTPClient() *http.Client {
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.ResponseHeaderTimeout = defaultResponseHeaderTimeout
return &http.Client{Transport: transport}
if t, ok := http.DefaultTransport.(*http.Transport); ok {
t = t.Clone()
t.ResponseHeaderTimeout = defaultResponseHeaderTimeout
return &http.Client{Transport: t}
}
return &http.Client{Transport: http.DefaultTransport}
}
6 changes: 3 additions & 3 deletions extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ type ExtensionListResponse struct {
// Timestamp when the extension was last used
LastUsedAt time.Time `json:"last_used_at" api:"nullable" format:"date-time"`
// Optional, easier-to-reference name for the extension. Must be unique within the
// organization.
// project.
Name string `json:"name" api:"nullable"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Expand Down Expand Up @@ -139,7 +139,7 @@ type ExtensionUploadResponse struct {
// Timestamp when the extension was last used
LastUsedAt time.Time `json:"last_used_at" api:"nullable" format:"date-time"`
// Optional, easier-to-reference name for the extension. Must be unique within the
// organization.
// project.
Name string `json:"name" api:"nullable"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
Expand Down Expand Up @@ -190,7 +190,7 @@ const (
type ExtensionUploadParams struct {
// ZIP file containing the browser extension.
File io.Reader `json:"file,omitzero" api:"required" format:"binary"`
// Optional unique name within the organization to reference this extension.
// Optional unique name within the project to reference this extension.
Name param.Opt[string] `json:"name,omitzero"`
paramObj
}
Expand Down
4 changes: 2 additions & 2 deletions internal/apiform/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type encoderField struct {
}

type encoderEntry struct {
reflect.Type
typ reflect.Type
dateFormat string
arrayFmt string
root bool
Expand All @@ -76,7 +76,7 @@ func (e *encoder) marshal(value any, writer *multipart.Writer) error {

func (e *encoder) typeEncoder(t reflect.Type) encoderFunc {
entry := encoderEntry{
Type: t,
typ: t,
dateFormat: e.dateFormat,
arrayFmt: e.arrayFmt,
root: e.root,
Expand Down
4 changes: 2 additions & 2 deletions internal/apijson/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type decoderField struct {
}

type decoderEntry struct {
reflect.Type
typ reflect.Type
dateFormat string
root bool
}
Expand Down Expand Up @@ -108,7 +108,7 @@ func (d *decoderBuilder) unmarshalWithExactness(raw []byte, to any) (exactness,

func (d *decoderBuilder) typeDecoder(t reflect.Type) decoderFunc {
entry := decoderEntry{
Type: t,
typ: t,
dateFormat: d.dateFormat,
root: d.root,
}
Expand Down
4 changes: 2 additions & 2 deletions internal/apijson/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type encoderField struct {
}

type encoderEntry struct {
reflect.Type
typ reflect.Type
dateFormat string
root bool
}
Expand All @@ -63,7 +63,7 @@ func (e *encoder) marshal(value any) ([]byte, error) {

func (e *encoder) typeEncoder(t reflect.Type) encoderFunc {
entry := encoderEntry{
Type: t,
typ: t,
dateFormat: e.dateFormat,
root: e.root,
}
Expand Down
4 changes: 2 additions & 2 deletions internal/apiquery/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type encoderField struct {
}

type encoderEntry struct {
reflect.Type
typ reflect.Type
dateFormat string
root bool
settings QuerySettings
Expand All @@ -42,7 +42,7 @@ type Pair struct {

func (e *encoder) typeEncoder(t reflect.Type) encoderFunc {
entry := encoderEntry{
Type: t,
typ: t,
dateFormat: e.dateFormat,
root: e.root,
settings: e.settings,
Expand Down
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.52.0" // x-release-please-version
const PackageVersion = "0.53.0" // x-release-please-version
46 changes: 44 additions & 2 deletions option/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"net/http/httputil"
)

// sensitiveLogHeaders are redacted before request and response content is
// written to the debug logger.
var sensitiveLogHeaders = []string{"authorization", "api-key", "x-api-key", "cookie", "set-cookie"}

// WithDebugLog logs the HTTP request and response content.
// If the logger parameter is nil, it uses the default logger.
//
Expand All @@ -20,7 +24,7 @@ func WithDebugLog(logger *log.Logger) RequestOption {
logger = log.Default()
}

if reqBytes, err := httputil.DumpRequest(req, true); err == nil {
if reqBytes, err := dumpRedactedRequest(req); err == nil {
logger.Printf("Request Content:\n%s\n", reqBytes)
}

Expand All @@ -29,10 +33,48 @@ func WithDebugLog(logger *log.Logger) RequestOption {
return resp, err
}

if respBytes, err := httputil.DumpResponse(resp, true); err == nil {
if respBytes, err := dumpRedactedResponse(resp); err == nil {
logger.Printf("Response Content:\n%s\n", respBytes)
}

return resp, err
})
}

// dumpRedactedRequest dumps req with sensitive headers replaced. The
// original headers are restored via defer so a panic in DumpRequest cannot
// leak the placeholder map into the live request sent downstream.
func dumpRedactedRequest(req *http.Request) ([]byte, error) {
origHeaders := req.Header
req.Header = redactDebugHeaders(origHeaders)
defer func() { req.Header = origHeaders }()
return httputil.DumpRequest(req, true)
}

func dumpRedactedResponse(resp *http.Response) ([]byte, error) {
origHeaders := resp.Header
resp.Header = redactDebugHeaders(origHeaders)
defer func() { resp.Header = origHeaders }()
return httputil.DumpResponse(resp, true)
}

func redactDebugHeaders(headers http.Header) http.Header {
var redacted http.Header
for _, name := range sensitiveLogHeaders {
values := headers.Values(name)
if len(values) == 0 {
continue
}
if redacted == nil {
redacted = headers.Clone()
}
redacted.Del(name)
for range values {
redacted.Add(name, "***")
}
}
if redacted == nil {
return headers
}
return redacted
}
2 changes: 1 addition & 1 deletion profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (r *ProfileService) Download(ctx context.Context, idOrName string, opts ...
}

type ProfileNewParams struct {
// Optional name of the profile. Must be unique within the organization.
// Optional name of the profile. Must be unique within the project.
Name param.Opt[string] `json:"name,omitzero"`
paramObj
}
Expand Down
2 changes: 2 additions & 0 deletions project.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ type ProjectListParams struct {
Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
// Number of results to skip
Offset param.Opt[int64] `query:"offset,omitzero" json:"-"`
// Case-insensitive substring match against project name
Query param.Opt[string] `query:"query,omitzero" json:"-"`
paramObj
}

Expand Down
1 change: 1 addition & 0 deletions project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func TestProjectListWithOptionalParams(t *testing.T) {
_, err := client.Projects.List(context.TODO(), kernel.ProjectListParams{
Limit: kernel.Int(100),
Offset: kernel.Int(0),
Query: kernel.String("query"),
})
if err != nil {
var apierr *kernel.Error
Expand Down
Loading