Complete browser extension gRPC flow

This commit is contained in:
Joe Julian
2026-04-11 23:45:48 -07:00
parent 2f2338f6f2
commit d522af7d51
24 changed files with 2744 additions and 191 deletions
+73
View File
@@ -5,6 +5,7 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"net"
"os"
"slices"
@@ -121,6 +122,78 @@ func TestVaultServiceAllowsSessionStatusWithoutManageVault(t *testing.T) {
}
}
func TestVaultServiceSessionStatusIncludesPendingApprovalsForCurrentToken(t *testing.T) {
t.Parallel()
token, secret, err := apitokens.Issue("Browser Token", "browser-extension", nil, time.Date(2026, 4, 11, 12, 0, 0, 0, time.UTC))
if err != nil {
t.Fatalf("Issue() error = %v", err)
}
token.SecretHash = hashSecretForTest(secret)
otherToken, otherSecret, err := apitokens.Issue("Other Token", "automation-client", nil, time.Date(2026, 4, 11, 12, 1, 0, 0, time.UTC))
if err != nil {
t.Fatalf("Issue() other error = %v", err)
}
otherToken.SecretHash = hashSecretForTest(otherSecret)
client, _, service, cleanup := newTestHarnessForModel(t, vault.Model{
Entries: []vault.Entry{
token.Entry([]string{"Root", "API Tokens"}),
otherToken.Entry([]string{"Root", "API Tokens"}),
},
})
defer cleanup()
service.approvals = apiapproval.NewBroker(time.Minute)
ctx, cancel := context.WithCancel(tokenContext(secret))
defer cancel()
waiting := make(chan error, 1)
go func() {
_, err := service.approvals.Request(ctx, token, apitokens.OperationCopyPassword, apitokens.Resource{
Kind: apitokens.ResourceEntry,
EntryID: "vault-console",
Path: []string{"Root", "Internet"},
})
waiting <- err
}()
otherCtx, otherCancel := context.WithCancel(tokenContext(otherSecret))
defer otherCancel()
otherWaiting := make(chan error, 1)
go func() {
_, err := service.approvals.Request(otherCtx, otherToken, apitokens.OperationListEntries, apitokens.Resource{
Kind: apitokens.ResourceGroup,
Path: []string{"Root", "Shared"},
})
otherWaiting <- err
}()
waitForServerPendingApproval(t, service, 2)
resp, err := client.GetSessionStatus(tokenContext(secret), &keepassgov1.GetSessionStatusRequest{})
if err != nil {
t.Fatalf("GetSessionStatus() error = %v", err)
}
if got := resp.GetPendingApprovalCount(); got != 2 {
t.Fatalf("GetSessionStatus().PendingApprovalCount = %d, want 2", got)
}
if got := resp.GetTokenPendingApprovalCount(); got != 1 {
t.Fatalf("GetSessionStatus().TokenPendingApprovalCount = %d, want 1", got)
}
for _, pending := range waitForServerPendingApproval(t, service, 2) {
if _, _, err := service.ResolveApproval(pending.ID, apiapproval.OutcomeCancel); err != nil {
t.Fatalf("ResolveApproval(%q) error = %v", pending.ID, err)
}
}
if err := <-waiting; !errors.Is(err, apiapproval.ErrRequestCanceled) {
t.Fatalf("Request(token) error = %v, want %v", err, apiapproval.ErrRequestCanceled)
}
if err := <-otherWaiting; !errors.Is(err, apiapproval.ErrRequestCanceled) {
t.Fatalf("Request(otherToken) error = %v, want %v", err, apiapproval.ErrRequestCanceled)
}
}
func TestVaultServiceRejectsUnauthorizedTemplateMutation(t *testing.T) {
t.Parallel()