package credential import ( "errors" "os" "path/filepath" "strings" "testing" ) func TestIssuedTokenAuthorizesOnlyItsOwnService(t *testing.T) { root := t.TempDir() store := New(root) value, issued, err := store.Issue("app", "ci") if err != nil { t.Fatal(err) } if !strings.HasPrefix(value, issued.ID+".") || len(value) < 40 { t.Fatalf("value = %q issued = %+v", value, issued) } if !store.Verify("app", value) { t.Fatal("issued token rejected") } if store.Verify("other", value) { t.Fatal("token accepted for another service") } for _, presented := range []string{"", value + "x", issued.ID, issued.ID + ".", "nothex.secret", strings.ToUpper(value)} { if store.Verify("app", presented) { t.Fatalf("accepted %q", presented) } } } func TestSecretIsNeverStoredOrListed(t *testing.T) { root := t.TempDir() store := New(root) value, issued, err := store.Issue("app", "ci") if err != nil { t.Fatal(err) } _, secret, _ := strings.Cut(value, ".") data, err := os.ReadFile(filepath.Join(root, "credentials", "app.json")) if err != nil { t.Fatal(err) } if strings.Contains(string(data), secret) { t.Fatal("secret written to disk") } listed, err := store.List("app") if err != nil || len(listed) != 1 { t.Fatalf("listed = %+v err = %v", listed, err) } if listed[0].ID != issued.ID || listed[0].Label != "ci" || listed[0].CreatedAt.IsZero() { t.Fatalf("listed = %+v", listed[0]) } } func TestRevocationRemovesOnlyTheNamedToken(t *testing.T) { root := t.TempDir() store := New(root) first, firstPublic, err := store.Issue("app", "one") if err != nil { t.Fatal(err) } second, _, err := store.Issue("app", "two") if err != nil { t.Fatal(err) } if err := store.Revoke("app", firstPublic.ID); err != nil { t.Fatal(err) } if store.Verify("app", first) { t.Fatal("revoked token still valid") } if !store.Verify("app", second) { t.Fatal("unrelated token revoked") } if err := store.Revoke("app", firstPublic.ID); !errors.Is(err, ErrUnknownToken) { t.Fatalf("second revoke = %v", err) } if err := store.Revoke("app", "not-an-id"); !errors.Is(err, ErrUnknownToken) { t.Fatalf("bogus revoke = %v", err) } } func TestTokensSurviveRestart(t *testing.T) { root := t.TempDir() value, _, err := New(root).Issue("app", "ci") if err != nil { t.Fatal(err) } if !New(root).Verify("app", value) { t.Fatal("token lost across store instances") } } func TestUnsafeServiceNamesAndLabelsAreRejected(t *testing.T) { store := New(t.TempDir()) for _, service := range []string{"", "../escape", "App", "a/b"} { if _, _, err := store.Issue(service, ""); err == nil { t.Fatalf("accepted service %q", service) } if store.Verify(service, "0123456789abcdef.secret") { t.Fatalf("verified service %q", service) } } if _, _, err := store.Issue("app", strings.Repeat("x", 65)); err == nil { t.Fatal("accepted oversized label") } }