Skip to content

Commit d230fe4

Browse files
Update Go SDK to 6923472 and send the kernel credential provider
Bump github.com/kernel/kernel-go-sdk to 6923472efed1a4e7f9d6f26124c3cbd381122812 ("Let Vaults fill credentials from 1Password"). The credential create spec is now a provider union, so vaults credentials create wraps the spec as the Kernel variant, defaults provider to "kernel", and rejects other providers. 1Password credentials, credential_account items, and the 1pw_* operations are left to the dedicated 1Password CLI work in #271. Tested against the real API: vaults create, credentials create (provider defaulted to kernel), credentials update, items get, items list, credentials create with provider 1password (rejected client-side), vaults delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 5f7ca41 commit d230fe4

5 files changed

Lines changed: 41 additions & 17 deletions

File tree

‎cmd/vaults_credentials.go‎

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,9 @@ func (c VaultsCmd) saveCredential(ctx context.Context, vault, key string, data [
126126
}
127127
item, err = c.vaults.Items.Update(ctx, key, kernel.VaultItemUpdateParams{IDOrName: vault, OfCredentialVaultItemUpdateRequest: &request}, option.WithMaxRetries(0))
128128
} else {
129-
var spec kernel.CredentialVaultItemSpecInputParam
130-
if json.Unmarshal(data, &spec) != nil || len(spec.Fields) == 0 {
131-
if credentialSpecUsesKeyedFields(data) {
132-
return fmt.Errorf("credential spec fields must be an ordered array of definitions carrying a name, not an object keyed by name")
133-
}
134-
return fmt.Errorf("credential spec requires fields")
135-
}
136-
// Names key values, updates, and fills; reject specs the form cannot address.
137-
for _, field := range spec.Fields {
138-
if strings.TrimSpace(field.Name) == "" {
139-
return fmt.Errorf("every credential spec field requires a name")
140-
}
129+
spec, specErr := credentialSpecInput(data)
130+
if specErr != nil {
131+
return specErr
141132
}
142133
item, err = c.vaults.Items.Upsert(ctx, key, kernel.VaultItemUpsertParams{IDOrName: vault, OfCredential: &kernel.CredentialVaultItemRequestParam{Type: "credential", Spec: spec}}, option.WithMaxRetries(0))
143134
}
@@ -147,6 +138,29 @@ func (c VaultsCmd) saveCredential(ctx context.Context, vault, key string, data [
147138
return c.showItem(item, output, open)
148139
}
149140

141+
// Kernel-hosted specs default the provider; other providers are not supported here.
142+
func credentialSpecInput(data []byte) (kernel.CredentialVaultItemSpecInputUnionParam, error) {
143+
var spec kernel.KernelCredentialVaultItemSpecInputParam
144+
invalid := json.Unmarshal(data, &spec) != nil
145+
if !invalid && spec.Provider != "" && spec.Provider != kernel.KernelCredentialVaultItemSpecInputProviderKernel {
146+
return kernel.CredentialVaultItemSpecInputUnionParam{}, fmt.Errorf("credential spec provider must be kernel")
147+
}
148+
if invalid || len(spec.Fields) == 0 {
149+
if credentialSpecUsesKeyedFields(data) {
150+
return kernel.CredentialVaultItemSpecInputUnionParam{}, fmt.Errorf("credential spec fields must be an ordered array of definitions carrying a name, not an object keyed by name")
151+
}
152+
return kernel.CredentialVaultItemSpecInputUnionParam{}, fmt.Errorf("credential spec requires fields")
153+
}
154+
spec.Provider = kernel.KernelCredentialVaultItemSpecInputProviderKernel
155+
// Names key values, updates, and fills; reject specs the form cannot address.
156+
for _, field := range spec.Fields {
157+
if strings.TrimSpace(field.Name) == "" {
158+
return kernel.CredentialVaultItemSpecInputUnionParam{}, fmt.Errorf("every credential spec field requires a name")
159+
}
160+
}
161+
return kernel.CredentialVaultItemSpecInputUnionParam{OfKernel: &spec}, nil
162+
}
163+
150164
// The create spec moved from fields keyed by name to an ordered array; point
151165
// callers still sending the object form at the replacement shape.
152166
func credentialSpecUsesKeyedFields(data []byte) bool {

‎cmd/vaults_credentials_test.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestCredentialCreateAndUpdate(t *testing.T) {
4242
assert.JSONEq(t, `{"fields":{"password":{"value":null}}}`, string(body["spec"]))
4343
} else {
4444
assert.Equal(t, "PUT", r.Method)
45-
assert.JSONEq(t, `{"fields":[{"name":"password","label":"Account Password","type":"password","required":true}]}`, string(body["spec"]))
45+
assert.JSONEq(t, `{"provider":"kernel","fields":[{"name":"password","label":"Account Password","type":"password","required":true}]}`, string(body["spec"]))
4646
}
4747
w.Header().Set("Content-Type", "application/json")
4848
io.WriteString(w, credentialFixture)
@@ -210,3 +210,13 @@ func TestCredentialDiscoveryAndInvalidInput(t *testing.T) {
210210
require.NoError(t, err)
211211
assert.JSONEq(t, `{"fields":{}}`, string(data))
212212
}
213+
214+
func TestCredentialSpecInputProvider(t *testing.T) {
215+
spec, err := credentialSpecInput([]byte(`{"provider":"kernel","fields":[{"name":"password","type":"password"}]}`))
216+
require.NoError(t, err)
217+
require.NotNil(t, spec.OfKernel)
218+
assert.EqualValues(t, "kernel", spec.OfKernel.Provider)
219+
220+
_, err = credentialSpecInput([]byte(`{"provider":"1password","account":"op","requests":{"version":2,"entries":[]}}`))
221+
assert.EqualError(t, err, "credential spec provider must be kernel")
222+
}

‎cmd/vaults_sdk_contract_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestCredentialInitialValuesWithGeneratedSDK(t *testing.T) {
7373
assert.Equal(t, "PUT", r.Method)
7474
var body map[string]json.RawMessage
7575
require.NoError(t, json.NewDecoder(r.Body).Decode(&body))
76-
assert.JSONEq(t, spec, string(body["spec"]))
76+
assert.JSONEq(t, `{"provider":"kernel",`+spec[1:], string(body["spec"]))
7777
w.Header().Set("Content-Type", "application/json")
7878
fmt.Fprintf(w, `{"id":"credential-1","key":"login","type":"credential","version":1,"spec":%s,"state":{"status":"ready","fields":{"otp":{"has_value":true,"value":"JBSWY3DPEHPK3PXP"}}},"available_operations":[],"available_expansions":[]}`, spec)
7979
})

‎go.mod‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1
1010
github.com/golang-jwt/jwt/v5 v5.2.2
1111
github.com/joho/godotenv v1.5.1
12-
github.com/kernel/kernel-go-sdk v0.113.1-0.20260928171941-35a02850ff6e
12+
github.com/kernel/kernel-go-sdk v0.113.1-0.20260929201643-6923472efed1
1313
github.com/klauspost/compress v1.18.5
1414
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
1515
github.com/pterm/pterm v0.12.80

‎go.sum‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
6666
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6767
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
6868
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
69-
github.com/kernel/kernel-go-sdk v0.113.1-0.20260928171941-35a02850ff6e h1:ZN18RLvukJXyrbrk2ra40fC0LBFVbuArYjNwO7xyRaA=
70-
github.com/kernel/kernel-go-sdk v0.113.1-0.20260928171941-35a02850ff6e/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
69+
github.com/kernel/kernel-go-sdk v0.113.1-0.20260929201643-6923472efed1 h1:seWvhEEybAmGnCrIQOICdd1ibSYP/D4SQeYiSJwA7xI=
70+
github.com/kernel/kernel-go-sdk v0.113.1-0.20260929201643-6923472efed1/go.mod h1:EeZzSuHZVeHKxKCPUzxou2bovNGhXaz0RXrSqKNf1AQ=
7171
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
7272
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
7373
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

0 commit comments

Comments
 (0)