From e746d9980b83f915e8e9d85a75dfee8f16b8df96 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Wed, 30 Sep 2026 18:26:35 +0000 Subject: [PATCH 1/3] feat: Handle AgentCard autopilot and declare checkout_origin on the card spec Stainless-Generated-From: 1ac5d7cc708f53c398ee2f63dc6c8b236d44dcca --- vaultitem.go | 64 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/vaultitem.go b/vaultitem.go index 3adad1c..544a1ff 100644 --- a/vaultitem.go +++ b/vaultitem.go @@ -436,7 +436,9 @@ type CardVaultItemSpecUnion struct { Merchant string `json:"merchant"` // This field is from variant [CardVaultItemSpecAgentcard]. CardID string `json:"card_id"` - JSON struct { + // This field is from variant [CardVaultItemSpecAgentcard]. + CheckoutOrigin string `json:"checkout_origin"` + JSON struct { Amount respjson.Field Context respjson.Field Currency respjson.Field @@ -451,6 +453,7 @@ type CardVaultItemSpecUnion struct { Totals respjson.Field Merchant respjson.Field CardID respjson.Field + CheckoutOrigin respjson.Field raw string } `json:"-"` } @@ -629,8 +632,9 @@ func (r *CardVaultItemSpecLinkTotal) UnmarshalJSON(data []byte) error { } // AgentCard reusable live payment card. Test-mode card creation is not supported. -// Each checkout creates an approval-gated authorization for spec.merchant / -// spec.amount. The card stays ready after each authorization. +// Each checkout creates an authorization for spec.merchant / spec.amount that the +// cardholder approves, unless AgentCard runs it under one of the cardholder's +// autopilot rules. The card stays ready after each authorization. type CardVaultItemSpecAgentcard struct { // Integer amount in minor currency units. Amount int64 `json:"amount" api:"required"` @@ -644,16 +648,26 @@ type CardVaultItemSpecAgentcard struct { // through unchanged without assuming a prefix or format. Omitted, the cardholder // picks on the approval screen. CardID string `json:"card_id"` + // Origin of the top-level checkout page, such as https://shop.example.com: https, + // a lowercase host, a port only when it is not 443, and no path. http is accepted + // only for localhost test pages. Checkouts without a preparation send it to + // AgentCard, which uses it to match the cardholder's autopilot rules; prepared + // checkouts send the preparation's merchant_origin instead. Kernel sends the + // declared value and does not compare it with the page the browser has open. + // Omitted, those checkouts ask the cardholder to approve. Card updates replace the + // whole spec, so an update that omits it removes it. + CheckoutOrigin string `json:"checkout_origin"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { - Amount respjson.Field - Currency respjson.Field - Merchant respjson.Field - Provider respjson.Field - Wallet respjson.Field - CardID respjson.Field - ExtraFields map[string]respjson.Field - raw string + Amount respjson.Field + Currency respjson.Field + Merchant respjson.Field + Provider respjson.Field + Wallet respjson.Field + CardID respjson.Field + CheckoutOrigin respjson.Field + ExtraFields map[string]respjson.Field + raw string } `json:"-"` } @@ -768,6 +782,14 @@ func (u CardVaultItemSpecUnionParam) GetCardID() *string { return nil } +// Returns a pointer to the underlying variant's property, if present. +func (u CardVaultItemSpecUnionParam) GetCheckoutOrigin() *string { + if vt := u.OfAgentcard; vt != nil && vt.CheckoutOrigin.Valid() { + return &vt.CheckoutOrigin.Value + } + return nil +} + // Returns a pointer to the underlying variant's property, if present. func (u CardVaultItemSpecUnionParam) GetAmount() *int64 { if vt := u.OfLink; vt != nil { @@ -909,8 +931,9 @@ func (r *CardVaultItemSpecLinkTotalParam) UnmarshalJSON(data []byte) error { } // AgentCard reusable live payment card. Test-mode card creation is not supported. -// Each checkout creates an approval-gated authorization for spec.merchant / -// spec.amount. The card stays ready after each authorization. +// Each checkout creates an authorization for spec.merchant / spec.amount that the +// cardholder approves, unless AgentCard runs it under one of the cardholder's +// autopilot rules. The card stays ready after each authorization. // // The properties Amount, Currency, Merchant, Provider, Wallet are required. type CardVaultItemSpecAgentcardParam struct { @@ -925,6 +948,15 @@ type CardVaultItemSpecAgentcardParam struct { // through unchanged without assuming a prefix or format. Omitted, the cardholder // picks on the approval screen. CardID param.Opt[string] `json:"card_id,omitzero"` + // Origin of the top-level checkout page, such as https://shop.example.com: https, + // a lowercase host, a port only when it is not 443, and no path. http is accepted + // only for localhost test pages. Checkouts without a preparation send it to + // AgentCard, which uses it to match the cardholder's autopilot rules; prepared + // checkouts send the preparation's merchant_origin instead. Kernel sends the + // declared value and does not compare it with the page the browser has open. + // Omitted, those checkouts ask the cardholder to approve. Card updates replace the + // whole spec, so an update that omits it removes it. + CheckoutOrigin param.Opt[string] `json:"checkout_origin,omitzero"` // This field can be elided, and will marshal its zero value as "agentcard". Provider constant.Agentcard `json:"provider" default:"agentcard"` paramObj @@ -3465,6 +3497,8 @@ type VaultItemUnionSpec struct { Merchant string `json:"merchant"` // This field is from variant [CardVaultItemSpecUnion]. CardID string `json:"card_id"` + // This field is from variant [CardVaultItemSpecUnion]. + CheckoutOrigin string `json:"checkout_origin"` // This field is from variant [CredentialVaultItemSpecUnion]. Fields []CredentialVaultFieldDefinition `json:"fields"` // This field is from variant [CredentialVaultItemSpecUnion]. @@ -3493,6 +3527,7 @@ type VaultItemUnionSpec struct { Totals respjson.Field Merchant respjson.Field CardID respjson.Field + CheckoutOrigin respjson.Field Fields respjson.Field Description respjson.Field Requests respjson.Field @@ -4320,6 +4355,8 @@ type VaultItemOperationResponseUnionSpec struct { Merchant string `json:"merchant"` // This field is from variant [CardVaultItemSpecUnion]. CardID string `json:"card_id"` + // This field is from variant [CardVaultItemSpecUnion]. + CheckoutOrigin string `json:"checkout_origin"` // This field is from variant [CredentialVaultItemSpecUnion]. Fields []CredentialVaultFieldDefinition `json:"fields"` // This field is from variant [CredentialVaultItemSpecUnion]. @@ -4348,6 +4385,7 @@ type VaultItemOperationResponseUnionSpec struct { Totals respjson.Field Merchant respjson.Field CardID respjson.Field + CheckoutOrigin respjson.Field Fields respjson.Field Description respjson.Field Requests respjson.Field From 10c4031082d73b41180adeb54a722f89341907ff Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 19:52:54 +0000 Subject: [PATCH 2/3] feat: chore(stlc): seal custom-code tracking files Stainless-Generated-From: fd7434bd6dfb52e936c209d493cb7945979db383 --- credential.go | 84 ++++++++++++++++++++++++++++++++++++++++++---- credential_test.go | 10 ++++-- 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/credential.go b/credential.go index 1f9cc34..e68021d 100644 --- a/credential.go +++ b/credential.go @@ -140,9 +140,23 @@ type CreateCredentialRequestParam struct { // button, it will be clicked first before filling credential values on the // identity provider's login page. SSOProvider param.Opt[string] `json:"sso_provider,omitzero"` - // Base32-encoded TOTP secret for generating one-time passwords. Used for automatic - // 2FA during login. + // Number of digits in generated TOTP codes. Defaults to 6 and is ignored when an + // `otpauth://` URI supplies the digit count. + TotpDigits param.Opt[int64] `json:"totp_digits,omitzero"` + // TOTP rotation period in seconds. Defaults to 30 and is ignored when an + // `otpauth://` URI supplies the period. + TotpPeriod param.Opt[int64] `json:"totp_period,omitzero"` + // Accepts a 16-128 character base32-encoded TOTP secret or an `otpauth://totp/...` + // URI. The range accepts existing shorter seeds and longer seeds regardless of + // HMAC algorithm; RFC 6238 recommends unpadded base32 lengths of 32/52/103 for + // SHA1/SHA256/SHA512. Only URI parameters present override the corresponding + // explicit TOTP fields. Used for automatic 2FA during login. TotpSecret param.Opt[string] `json:"totp_secret,omitzero"` + // HMAC algorithm used to generate TOTP codes. Defaults to SHA1 and is ignored when + // an `otpauth://` URI supplies the algorithm. + // + // Any of "SHA1", "SHA256", "SHA512". + TotpAlgorithm CreateCredentialRequestTotpAlgorithm `json:"totp_algorithm,omitzero"` paramObj } @@ -154,6 +168,16 @@ func (r *CreateCredentialRequestParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } +// HMAC algorithm used to generate TOTP codes. Defaults to SHA1 and is ignored when +// an `otpauth://` URI supplies the algorithm. +type CreateCredentialRequestTotpAlgorithm string + +const ( + CreateCredentialRequestTotpAlgorithmSha1 CreateCredentialRequestTotpAlgorithm = "SHA1" + CreateCredentialRequestTotpAlgorithmSha256 CreateCredentialRequestTotpAlgorithm = "SHA256" + CreateCredentialRequestTotpAlgorithmSha512 CreateCredentialRequestTotpAlgorithm = "SHA512" +) + // A stored credential for automatic re-authentication type Credential struct { // Unique identifier for the credential @@ -175,11 +199,22 @@ type Credential struct { // button, it will be clicked first before filling credential values on the // identity provider's login page. SSOProvider string `json:"sso_provider" api:"nullable"` - // Current 6-digit TOTP code. Only included in create/update responses when - // totp_secret was just set. + // HMAC algorithm used to generate TOTP codes. Defaults to SHA1 for credentials + // created before this metadata was stored. + // + // Any of "SHA1", "SHA256", "SHA512". + TotpAlgorithm CredentialTotpAlgorithm `json:"totp_algorithm"` + // Current TOTP code. Only included in create/update responses when totp_secret was + // just set. TotpCode string `json:"totp_code"` // When the totp_code expires. Only included when totp_code is present. TotpCodeExpiresAt time.Time `json:"totp_code_expires_at" format:"date-time"` + // Number of digits in generated TOTP codes. Defaults to 6 for credentials created + // before this metadata was stored. + TotpDigits int64 `json:"totp_digits"` + // TOTP rotation period in seconds. Defaults to 30 for credentials created before + // this metadata was stored. + TotpPeriod int64 `json:"totp_period"` // The field names stored in this credential's values (e.g., username, password). // Values themselves are never returned. Included on single-credential responses // (create, get by id or name, update); omitted from list responses. @@ -194,8 +229,11 @@ type Credential struct { HasTotpSecret respjson.Field HasValues respjson.Field SSOProvider respjson.Field + TotpAlgorithm respjson.Field TotpCode respjson.Field TotpCodeExpiresAt respjson.Field + TotpDigits respjson.Field + TotpPeriod respjson.Field ValueKeys respjson.Field ExtraFields map[string]respjson.Field raw string @@ -208,6 +246,16 @@ func (r *Credential) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } +// HMAC algorithm used to generate TOTP codes. Defaults to SHA1 for credentials +// created before this metadata was stored. +type CredentialTotpAlgorithm string + +const ( + CredentialTotpAlgorithmSha1 CredentialTotpAlgorithm = "SHA1" + CredentialTotpAlgorithmSha256 CredentialTotpAlgorithm = "SHA256" + CredentialTotpAlgorithmSha512 CredentialTotpAlgorithm = "SHA512" +) + // Request to update an existing credential type UpdateCredentialRequestParam struct { // If set, indicates this credential should be used with the specified SSO @@ -215,12 +263,26 @@ type UpdateCredentialRequestParam struct { SSOProvider param.Opt[string] `json:"sso_provider,omitzero"` // New name for the credential Name param.Opt[string] `json:"name,omitzero"` - // Base32-encoded TOTP secret for generating one-time passwords. Spaces and - // formatting are automatically normalized. Set to empty string to remove. + // Number of digits in generated TOTP codes. Requires totp_secret and is ignored + // when an `otpauth://` URI supplies the digit count. + TotpDigits param.Opt[int64] `json:"totp_digits,omitzero"` + // TOTP rotation period in seconds. Requires totp_secret and is ignored when an + // `otpauth://` URI supplies the period. + TotpPeriod param.Opt[int64] `json:"totp_period,omitzero"` + // Accepts a 16-128 character base32-encoded TOTP secret or an `otpauth://totp/...` + // URI. Only URI parameters present override the corresponding explicit TOTP + // fields. When rotating a raw secret, omitted fields preserve their existing + // values; a new URI defaults unspecified fields to SHA1/6/30. Set to empty string + // to remove the secret and its metadata. TotpSecret param.Opt[string] `json:"totp_secret,omitzero"` // Field names to remove from the credential's stored values. Removals are applied // before `values` are merged, so a key present in both is kept with its new value. RemoveValueKeys []string `json:"remove_value_keys,omitzero"` + // HMAC algorithm used to generate TOTP codes. Requires totp_secret and is ignored + // when an `otpauth://` URI supplies the algorithm. + // + // Any of "SHA1", "SHA256", "SHA512". + TotpAlgorithm UpdateCredentialRequestTotpAlgorithm `json:"totp_algorithm,omitzero"` // Field name to value mapping. Values are merged with existing values (new keys // added, existing keys overwritten). Values map[string]string `json:"values,omitzero"` @@ -235,6 +297,16 @@ func (r *UpdateCredentialRequestParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } +// HMAC algorithm used to generate TOTP codes. Requires totp_secret and is ignored +// when an `otpauth://` URI supplies the algorithm. +type UpdateCredentialRequestTotpAlgorithm string + +const ( + UpdateCredentialRequestTotpAlgorithmSha1 UpdateCredentialRequestTotpAlgorithm = "SHA1" + UpdateCredentialRequestTotpAlgorithmSha256 UpdateCredentialRequestTotpAlgorithm = "SHA256" + UpdateCredentialRequestTotpAlgorithmSha512 UpdateCredentialRequestTotpAlgorithm = "SHA512" +) + type CredentialTotpCodeResponse struct { // Current 6-digit TOTP code Code string `json:"code" api:"required"` diff --git a/credential_test.go b/credential_test.go index b372196..1d0a354 100644 --- a/credential_test.go +++ b/credential_test.go @@ -34,8 +34,11 @@ func TestCredentialNewWithOptionalParams(t *testing.T) { "username": "user@example.com", "password": "mysecretpassword", }, - SSOProvider: kernel.String("google"), - TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"), + SSOProvider: kernel.String("google"), + TotpAlgorithm: kernel.CreateCredentialRequestTotpAlgorithmSha1, + TotpDigits: kernel.Int(6), + TotpPeriod: kernel.Int(30), + TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"), }, }) if err != nil { @@ -91,6 +94,9 @@ func TestCredentialUpdateWithOptionalParams(t *testing.T) { Name: kernel.String("my-updated-login"), RemoveValueKeys: []string{"old_field"}, SSOProvider: kernel.String("google"), + TotpAlgorithm: kernel.UpdateCredentialRequestTotpAlgorithmSha1, + TotpDigits: kernel.Int(6), + TotpPeriod: kernel.Int(30), TotpSecret: kernel.String("JBSWY3DPEHPK3PXP"), Values: map[string]string{ "username": "user@example.com", From 4eb07f2657bf96acfb017401d7e59588a11feda2 Mon Sep 17 00:00:00 2001 From: "kernel-internal[bot]" <260533166+kernel-internal[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 19:57:58 +0000 Subject: [PATCH 3/3] release: 0.116.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ README.md | 2 +- internal/version.go | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d3dc9f5..988e843 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.115.0" + ".": "0.116.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e27e73..73ab79d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.116.0](https://github.com/kernel/kernel-go-sdk/compare/v0.115.0...v0.116.0) (2026-10-01) + + +### Features + +* chore(stlc): seal custom-code tracking files ([10c4031](https://github.com/kernel/kernel-go-sdk/commit/10c4031082d73b41180adeb54a722f89341907ff)) + ## [0.115.0](https://github.com/kernel/kernel-go-sdk/compare/v0.114.0...v0.115.0) (2026-09-30) diff --git a/README.md b/README.md index f3bc980..a15f893 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Or to pin the version: ```sh -go get -u 'github.com/kernel/kernel-go-sdk@v0.115.0' +go get -u 'github.com/kernel/kernel-go-sdk@v0.116.0' ``` diff --git a/internal/version.go b/internal/version.go index f239ff7..9f9ad82 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.115.0" // x-release-please-version +const PackageVersion = "0.116.0" // x-release-please-version