Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9cf2431
CLI: Update SDK to 0a28735 and add org entitlements command
kernel-internal[bot] Aug 17, 2026
dfdba4f
CLI: Update Go SDK to v0.92.0 (a156820)
kernel-internal[bot] Aug 17, 2026
6412b6f
Merge main into cli-coverage-update
kernel-internal[bot] Aug 18, 2026
8a7b363
CLI: Update Go SDK to 6e62bf5 and track managed-auth field reason
kernel-internal[bot] Aug 18, 2026
055d6a9
Merge main into cli-coverage-update
kernel-internal[bot] Aug 19, 2026
ca46838
CLI: Update Go SDK to 796d424 and bind canonical submits to interactions
kernel-internal[bot] Aug 19, 2026
31d2462
CLI: Update Go SDK to 467fea7
kernel-internal[bot] Aug 19, 2026
16880f4
CLI: Update Go SDK to v0.93.0 (0802326)
kernel-internal[bot] Aug 20, 2026
f9b126f
CLI: Update Go SDK to 9a36566 and cover the telemetry control/platfor…
kernel-internal[bot] Aug 21, 2026
063d7f5
CLI: Update Go SDK to c042837 and drop the telemetry control/platform…
kernel-internal[bot] Aug 21, 2026
f777871
Merge main into cli-coverage-update
kernel-internal[bot] Aug 24, 2026
484e19f
CLI: Update Go SDK to 5e48c58 and restore the telemetry control/platf…
kernel-internal[bot] Aug 24, 2026
76455e6
Merge main into cli-coverage-update
kernel-internal[bot] Aug 24, 2026
8b5a06b
CLI: Update Go SDK to 26309b6 and drop the telemetry control/platform…
kernel-internal[bot] Aug 24, 2026
c6c402b
CLI: Update Go SDK to 9de3679 (v0.94.0) and restore the telemetry con…
kernel-internal[bot] Aug 24, 2026
ee72f2d
CLI: Update Go SDK to c472a30
kernel-internal[bot] Aug 26, 2026
cb4630d
Merge main into cli-coverage-update
kernel-internal[bot] Aug 26, 2026
99b27bb
feat: update Go SDK to 46978e2 and add ap-southeast region
kernel-internal[bot] Aug 26, 2026
3ce0c81
chore: update Go SDK to v0.95.0 (0c36fa4)
kernel-internal[bot] Aug 26, 2026
992e0f8
Merge main into cli-coverage-update
kernel-internal[bot] Aug 26, 2026
11fa9ed
chore: update Go SDK to d348ffc and repair merge fallout
kernel-internal[bot] Aug 27, 2026
3ce899d
chore: update Go SDK to v0.96.0 (bb4371c)
kernel-internal[bot] Aug 27, 2026
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ Managed auth connections (`kernel auth connections`). The commands below are new
- `kernel auth connections submit <id>` - New flags:
- `--field-value <id=value>` - Canonical field-id=value pair from the connection's `fields` list (repeatable); preferred over the legacy `--field`
- `--choice-id <id>` - Canonical choice ID from the connection's `choices` list
- `--interaction-id <id>` - Canonical interaction the submitted values answer. Only valid with `--field-value` or `--choice-id`; omit it and the CLI reads the connection's current interaction ID for you. Pass it to pin the submission, so the API rejects it if the flow has already moved on.

`kernel auth connections get` and `follow` list those IDs alongside the metadata the API captured for them, so you can tell the options apart before submitting. Fields show their type, ref, and any hint (which names the masked destination a one-time code was sent to); choices show their type, semantic MFA method (`sms`, `totp`, `push`, …), and masked destination.

Expand Down
136 changes: 99 additions & 37 deletions cmd/auth_connections.go

Large diffs are not rendered by default.

132 changes: 122 additions & 10 deletions cmd/auth_connections_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,17 @@ func TestAuthConnectionsGet_PrintsCanonicalInputMetadata(t *testing.T) {
Status: kernel.ManagedAuthStatusNeedsAuth,
FlowStatus: kernel.ManagedAuthFlowStatusInProgress,
FlowStep: kernel.ManagedAuthFlowStepAwaitingInput,
// Canonical fields and choices always arrive with the interaction
// they belong to, which `submit` needs.
InteractionID: "mai_abc123xyz",
Fields: []kernel.ManagedAuthField{
{
ID: "otp",
Label: "One-time code",
Type: "code",
Ref: "totp_code",
Hint: "Enter the code sent to +1 ••• ••• 1234",
Reason: "rejected",
Required: true,
},
},
Expand Down Expand Up @@ -181,8 +185,11 @@ func TestAuthConnectionsGet_PrintsCanonicalInputMetadata(t *testing.T) {
require.NoError(t, c.Get(context.Background(), AuthConnectionGetInput{ID: "e0x3vbw4z66kpwny3k5k46tj"}))

out := outBuf.String()
assert.Contains(t, out, `mai_abc123xyz`)
assert.Contains(t, out, `otp (One-time code)`)
assert.Contains(t, out, `code, ref=totp_code, required`)
// The reason tells the user why the field is being asked for: "rejected"
// means a stored credential was refused, so a new value has to replace it.
assert.Contains(t, out, `code, ref=totp_code, required, reason=rejected`)
assert.Contains(t, out, `hint="Enter the code sent to +1 ••• ••• 1234"`)
assert.Contains(t, out, `mfa_sms (Text message)`)
assert.Contains(t, out, `mfa_method, sms, to=+1 ••• ••• 1234`)
Expand Down Expand Up @@ -820,16 +827,24 @@ func TestLogin_TelemetryOverride(t *testing.T) {
assert.True(t, captured.Browser.Telemetry.Browser.Screenshot.Enabled.Value)
}

func TestSubmit_CanonicalChoiceID(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionSubmitParams
fake := &FakeAuthConnectionService{
// canonicalSubmitFake serves the current interaction ID from `get` and captures
// what `submit` sends, which is what every canonical submission needs.
func canonicalSubmitFake(interactionID string, captured *kernel.AuthConnectionSubmitParams) *FakeAuthConnectionService {
return &FakeAuthConnectionService{
GetFunc: func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ManagedAuth, error) {
return &kernel.ManagedAuth{ID: id, InteractionID: interactionID}, nil
},
SubmitFunc: func(ctx context.Context, id string, body kernel.AuthConnectionSubmitParams, opts ...option.RequestOption) (*kernel.SubmitFieldsResponse, error) {
captured = body
*captured = body
return &kernel.SubmitFieldsResponse{Accepted: true}, nil
},
}
c := AuthConnectionCmd{svc: fake}
}

func TestSubmit_CanonicalChoiceID(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionSubmitParams
c := AuthConnectionCmd{svc: canonicalSubmitFake("mai_current", &captured)}
require.NoError(t, c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
SelectedChoiceID: "choice_sms",
Expand All @@ -841,6 +856,53 @@ func TestSubmit_CanonicalChoiceID(t *testing.T) {
}

func TestSubmit_CanonicalFieldValues(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionSubmitParams
c := AuthConnectionCmd{svc: canonicalSubmitFake("mai_current", &captured)}
require.NoError(t, c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
CanonicalFieldValues: map[string]string{"field_email": "me@example.com"},
}))
assert.Equal(t, map[string]string{"field_email": "me@example.com"}, captured.SubmitFieldsRequest.FieldValues)
assert.Nil(t, captured.SubmitFieldsRequest.Fields)
}

func TestSubmit_CanonicalResolvesCurrentInteractionID(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionSubmitParams
c := AuthConnectionCmd{svc: canonicalSubmitFake("mai_current", &captured)}
require.NoError(t, c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
CanonicalFieldValues: map[string]string{"field_email": "me@example.com"},
}))
require.True(t, captured.SubmitFieldsRequest.InteractionID.Valid())
assert.Equal(t, "mai_current", captured.SubmitFieldsRequest.InteractionID.Value)
}

func TestSubmit_ExplicitInteractionIDIsNotOverwritten(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionSubmitParams
fake := canonicalSubmitFake("mai_current", &captured)
getCalls := 0
inner := fake.GetFunc
fake.GetFunc = func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ManagedAuth, error) {
getCalls++
return inner(ctx, id, opts...)
}
c := AuthConnectionCmd{svc: fake}
require.NoError(t, c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
SelectedChoiceID: "choice_sms",
// Pinning an older interaction is how a caller detects that the flow moved
// on, so the CLI must forward it untouched.
InteractionID: "mai_pinned",
}))
assert.Equal(t, 0, getCalls)
require.True(t, captured.SubmitFieldsRequest.InteractionID.Valid())
assert.Equal(t, "mai_pinned", captured.SubmitFieldsRequest.InteractionID.Value)
}

func TestSubmit_LegacyModeOmitsInteractionID(t *testing.T) {
capturePtermOutput(t)
var captured kernel.AuthConnectionSubmitParams
fake := &FakeAuthConnectionService{
Expand All @@ -851,11 +913,61 @@ func TestSubmit_CanonicalFieldValues(t *testing.T) {
}
c := AuthConnectionCmd{svc: fake}
require.NoError(t, c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
FieldValues: map[string]string{"username": "me"},
}))
// The API rejects an interaction ID paired with a legacy submit mode.
assert.False(t, captured.SubmitFieldsRequest.InteractionID.Valid())
}

func TestSubmit_InteractionIDRequiresCanonicalMode(t *testing.T) {
capturePtermOutput(t)
c := AuthConnectionCmd{svc: &FakeAuthConnectionService{}}
err := c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
FieldValues: map[string]string{"username": "me"},
InteractionID: "mai_current",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "the --interaction-id flag is only valid with --field-value or --choice-id")
}

func TestSubmit_CanonicalWithoutPendingInteractionErrors(t *testing.T) {
capturePtermOutput(t)
submitted := false
fake := &FakeAuthConnectionService{
GetFunc: func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ManagedAuth, error) {
return &kernel.ManagedAuth{ID: id}, nil
},
SubmitFunc: func(ctx context.Context, id string, body kernel.AuthConnectionSubmitParams, opts ...option.RequestOption) (*kernel.SubmitFieldsResponse, error) {
submitted = true
return &kernel.SubmitFieldsResponse{Accepted: true}, nil
},
}
c := AuthConnectionCmd{svc: fake}
err := c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
SelectedChoiceID: "choice_sms",
})
require.Error(t, err)
assert.Contains(t, err.Error(), "no canonical interaction awaiting input")
assert.False(t, submitted)
}

func TestSubmit_CanonicalGetErrorSurfaced(t *testing.T) {
capturePtermOutput(t)
fake := &FakeAuthConnectionService{
GetFunc: func(ctx context.Context, id string, opts ...option.RequestOption) (*kernel.ManagedAuth, error) {
return nil, errors.New("boom")
},
}
c := AuthConnectionCmd{svc: fake}
err := c.Submit(context.Background(), AuthConnectionSubmitInput{
ID: "auth_1",
CanonicalFieldValues: map[string]string{"field_email": "me@example.com"},
}))
assert.Equal(t, map[string]string{"field_email": "me@example.com"}, captured.SubmitFieldsRequest.FieldValues)
assert.Nil(t, captured.SubmitFieldsRequest.Fields)
})
require.Error(t, err)
assert.Contains(t, err.Error(), "interaction ID resolution")
}

func TestSubmit_CanonicalAndLegacyAreMutuallyExclusive(t *testing.T) {
Expand Down
Loading
Loading