Complete API token authz UI flows
This commit is contained in:
+159
-1
@@ -754,6 +754,23 @@ func TestUIAPITokenLifecycleManagement(t *testing.T) {
|
||||
t.Fatal("apiTokenSecret after rotate = empty, want one-time secret")
|
||||
}
|
||||
|
||||
u.apiTokenName.SetText("Browser Extension Updated")
|
||||
u.apiTokenClientName.SetText("firefox-desktop")
|
||||
u.apiTokenExpiresAt.SetText("2026-05-01T00:00:00Z")
|
||||
if err := u.saveAPITokenAction(); err != nil {
|
||||
t.Fatalf("saveAPITokenAction() error = %v", err)
|
||||
}
|
||||
updated, ok := u.selectedAPIToken()
|
||||
if !ok {
|
||||
t.Fatal("selectedAPIToken() ok = false, want true after save")
|
||||
}
|
||||
if updated.Name != "Browser Extension Updated" || updated.ClientName != "firefox-desktop" {
|
||||
t.Fatalf("updated token = %#v, want renamed/firefox-desktop", updated)
|
||||
}
|
||||
if updated.ExpiresAt == nil || updated.ExpiresAt.UTC().Format(time.RFC3339) != "2026-05-01T00:00:00Z" {
|
||||
t.Fatalf("updated.ExpiresAt = %#v, want 2026-05-01T00:00:00Z", updated.ExpiresAt)
|
||||
}
|
||||
|
||||
if err := u.disableAPITokenAction(); err != nil {
|
||||
t.Fatalf("disableAPITokenAction() error = %v", err)
|
||||
}
|
||||
@@ -761,9 +778,17 @@ func TestUIAPITokenLifecycleManagement(t *testing.T) {
|
||||
if !ok || !disabled.Disabled {
|
||||
t.Fatalf("selectedAPIToken() = %#v, want disabled token", disabled)
|
||||
}
|
||||
|
||||
if err := u.revokeAPITokenAction(); err != nil {
|
||||
t.Fatalf("revokeAPITokenAction() error = %v", err)
|
||||
}
|
||||
revoked, ok := u.selectedAPIToken()
|
||||
if !ok || revoked.RevokedAt == nil {
|
||||
t.Fatalf("selectedAPIToken() = %#v, want revoked token", revoked)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIAPITokenPolicyRulesCanBeAddedAndRemoved(t *testing.T) {
|
||||
func TestUIAPITokenPolicyRulesCanBeCreatedUpdatedAndRemoved(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{}, statePaths{
|
||||
@@ -799,6 +824,33 @@ func TestUIAPITokenPolicyRulesCanBeAddedAndRemoved(t *testing.T) {
|
||||
if token.Policies[0].Resource.Kind != apitokens.ResourceGroup {
|
||||
t.Fatalf("rule kind = %q, want group", token.Policies[0].Resource.Kind)
|
||||
}
|
||||
if len(u.apiPolicyEdits) != 1 {
|
||||
t.Fatalf("len(apiPolicyEdits) = %d, want 1", len(u.apiPolicyEdits))
|
||||
}
|
||||
|
||||
u.apiPolicyEdits[0].Click()
|
||||
u.handleAPIPolicyClicks(layout.Context{})
|
||||
if u.selectedAPIPolicyIndex != 0 {
|
||||
t.Fatalf("selectedAPIPolicyIndex = %d, want 0 after edit click", u.selectedAPIPolicyIndex)
|
||||
}
|
||||
if got := u.apiPolicyPath.Text(); got != "Root / Internet" {
|
||||
t.Fatalf("apiPolicyPath = %q, want Root / Internet after edit load", got)
|
||||
}
|
||||
|
||||
u.apiPolicyPath.SetText("Root / Security")
|
||||
u.saveAPIPolicyRule.Click()
|
||||
u.handleAPIPolicyClicks(layout.Context{})
|
||||
|
||||
token, ok = u.selectedAPIToken()
|
||||
if !ok || len(token.Policies) != 1 {
|
||||
t.Fatalf("selectedAPIToken().Policies after save = %#v, want 1 rule", token.Policies)
|
||||
}
|
||||
if got := strings.Join(token.Policies[0].Resource.Path, " / "); got != "Root / Security" {
|
||||
t.Fatalf("updated policy path = %q, want Root / Security", got)
|
||||
}
|
||||
if u.selectedAPIPolicyIndex != -1 {
|
||||
t.Fatalf("selectedAPIPolicyIndex after save = %d, want -1", u.selectedAPIPolicyIndex)
|
||||
}
|
||||
|
||||
if err := u.removeAPIPolicyRuleAction(0); err != nil {
|
||||
t.Fatalf("removeAPIPolicyRuleAction() error = %v", err)
|
||||
@@ -4858,6 +4910,112 @@ func TestUIResolvePendingApprovalDelegatesToApprovalManager(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIApprovalDialogVisibleForPendingRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithModel("desktop", vault.Model{})
|
||||
u.state.Approvals = &mainStubApprovalManager{
|
||||
pending: []apiapproval.Request{{
|
||||
ID: "approval-1",
|
||||
TokenName: "CLI",
|
||||
ClientName: "grpc-cli",
|
||||
Operation: apitokens.OperationReadEntry,
|
||||
Resource: apitokens.Resource{
|
||||
Kind: apitokens.ResourceEntry,
|
||||
EntryID: "vault-console",
|
||||
},
|
||||
}},
|
||||
}
|
||||
|
||||
dims := u.approvalDialogContent(layout.Context{
|
||||
Ops: new(op.Ops),
|
||||
Constraints: layout.Exact(image.Pt(800, 600)),
|
||||
})
|
||||
if dims.Size.X == 0 || dims.Size.Y == 0 {
|
||||
t.Fatalf("approvalDialogContent() = %v, want visible dimensions for pending approval", dims.Size)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIApprovalButtonsResolveAllOutcomes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
click func(*ui)
|
||||
want apiapproval.Outcome
|
||||
wantMsg string
|
||||
}{
|
||||
{
|
||||
name: "allow once",
|
||||
click: func(u *ui) {
|
||||
u.allowApprovalOnce.Click()
|
||||
},
|
||||
want: apiapproval.OutcomeAllowOnce,
|
||||
wantMsg: "allow API request complete",
|
||||
},
|
||||
{
|
||||
name: "allow permanently",
|
||||
click: func(u *ui) {
|
||||
u.allowApprovalPermanent.Click()
|
||||
},
|
||||
want: apiapproval.OutcomeAllowPermanent,
|
||||
wantMsg: "allow API request permanently complete",
|
||||
},
|
||||
{
|
||||
name: "deny once",
|
||||
click: func(u *ui) {
|
||||
u.denyApprovalOnce.Click()
|
||||
},
|
||||
want: apiapproval.OutcomeDenyOnce,
|
||||
wantMsg: "deny API request complete",
|
||||
},
|
||||
{
|
||||
name: "deny permanently",
|
||||
click: func(u *ui) {
|
||||
u.denyApprovalPermanent.Click()
|
||||
},
|
||||
want: apiapproval.OutcomeDenyPermanent,
|
||||
wantMsg: "deny API request permanently complete",
|
||||
},
|
||||
{
|
||||
name: "cancel",
|
||||
click: func(u *ui) {
|
||||
u.cancelApproval.Click()
|
||||
},
|
||||
want: apiapproval.OutcomeCancel,
|
||||
wantMsg: "cancel API request complete",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
manager := &mainStubApprovalManager{
|
||||
pending: []apiapproval.Request{{
|
||||
ID: "approval-1",
|
||||
TokenName: "CLI",
|
||||
ClientName: "grpc-cli",
|
||||
Operation: apitokens.OperationReadEntry,
|
||||
}},
|
||||
}
|
||||
u := newUIWithModel("desktop", vault.Model{})
|
||||
u.state.Approvals = manager
|
||||
|
||||
tt.click(u)
|
||||
u.handleApprovalClicks(layout.Context{})
|
||||
|
||||
if manager.lastID != "approval-1" || manager.lastOutcome != tt.want {
|
||||
t.Fatalf("handleApprovalClicks() delegated (%q, %q), want (approval-1, %q)", manager.lastID, manager.lastOutcome, tt.want)
|
||||
}
|
||||
if got := u.state.StatusMessage; got != tt.wantMsg {
|
||||
t.Fatalf("state.StatusMessage = %q, want %q", got, tt.wantMsg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIRequiresExplicitEditModeForEntryEditor(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user