Luigit
repositories / bugabinga.net

bugabinga.net

personal infrastructure for bugabinga!

owned by admin

services/toad/internal/credential/credential_test.go

Raw
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")
	}
}