Skip to content
quarry Artifact [b48ba29355]
Login

Artifact [b48ba29355]

Artifact b48ba2935562edda04ac6188fb6fa5cdaad161c0a447321798621296f6f73bbe:


package web

import (
	"net/http"
	"net/url"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/ci"
)

func tokensFixture() []ci.WorkerToken {
	return []ci.WorkerToken{
		{ID: "own-token-1", Label: "alpha's runner", WorkerGroups: []string{ci.GroupFor("alpha")}},
		{ID: "beta-token-1", Label: "beta's runner", WorkerGroups: []string{ci.GroupFor("beta")}},
		{ID: "fleet-token-1", Label: "forge-host worker", TaskTypePrefixes: []string{"dantest-html"}},
	}
}

// Which tokens a repository's settings may show: its own group's, and a
// fleet-wide one only to a site admin. Every repository's page used to
// list every token in the engine.
func TestWhichWorkerTokensARepositoryShows(t *testing.T) {
	ts := tokensFixture()
	for _, c := range []struct {
		i    int
		site bool
		want bool
	}{
		{0, false, true}, {0, true, true}, // alpha's own
		{1, false, false}, {1, true, false}, // beta's: never alpha's
		{2, false, false}, {2, true, true}, // fleet: site admins only
	} {
		if got := workerTokenOf(ts[c.i], "alpha", time.Time{}, c.site); got != c.want {
			t.Errorf("FAIL: %s on alpha, site admin %v: shown=%v, want %v", ts[c.i].ID, c.site, got, c.want)
		}
	}
}

// A REPOSITORY'S SETTINGS REVOKE ONLY ITS OWN WORKER TOKENS.
//
// The revoke beside each token worked from any repository the account
// administered, and every repository's page listed every token, so one
// repository's admin could revoke another repository's runners and the
// forge's own. Seven tokens that were not runner-probe's were revoked
// from runner-probe's page that way. Now a token that is not the
// repository's own answers not found and never reaches the engine.
func TestARepositoryRevokesOnlyItsOwnWorkerTokens(t *testing.T) {
	eng := &mintRecorder{tokens: tokensFixture()}
	srv := scopeServer(t, eng, "a8i")
	for _, foreign := range []string{"beta-token-1", "fleet-token-1", "no-such-token"} {
		resp := postAsDan(t, srv, "/r/alpha/settings/worker-tokens", url.Values{"revoke": {foreign}})
		if resp.StatusCode == http.StatusSeeOther {
			t.Errorf("FAIL: revoking %s from alpha was accepted", foreign)
		}
	}
	resp := postAsDan(t, srv, "/r/alpha/settings/worker-tokens", url.Values{"revoke": {"own-token-1"}})
	if resp.StatusCode != http.StatusSeeOther {
		t.Errorf("FAIL: revoking alpha's own token answered %d", resp.StatusCode)
	}
	eng.mu.Lock()
	defer eng.mu.Unlock()
	if len(eng.revoked) != 1 || eng.revoked[0] != "own-token-1" {
		t.Errorf("FAIL: the engine was asked to revoke %v, want only alpha's own token", eng.revoked)
	}
}

// A site admin also revokes fleet-wide tokens, which belong to no
// repository, but still not another repository's.
func TestASiteAdminRevokesFleetTokensButNotAnotherRepositorys(t *testing.T) {
	eng := &mintRecorder{tokens: tokensFixture()}
	srv := scopeServer(t, eng, "as")
	if resp := postAsDan(t, srv, "/r/alpha/settings/worker-tokens", url.Values{"revoke": {"beta-token-1"}}); resp.StatusCode == http.StatusSeeOther {
		t.Errorf("FAIL: a site admin revoked beta's token from alpha's page")
	}
	if resp := postAsDan(t, srv, "/r/alpha/settings/worker-tokens", url.Values{"revoke": {"fleet-token-1"}}); resp.StatusCode != http.StatusSeeOther {
		t.Errorf("FAIL: a site admin could not revoke a fleet token: %d", resp.StatusCode)
	}
	eng.mu.Lock()
	defer eng.mu.Unlock()
	if len(eng.revoked) != 1 || eng.revoked[0] != "fleet-token-1" {
		t.Errorf("FAIL: the engine was asked to revoke %v, want only the fleet token", eng.revoked)
	}
}

// A revoked token minted before the repository existed belongs to an
// earlier repository of the same name, whose deletion revoked it, and is
// not listed on its successor's page (quarry#294). A live one stays
// whatever its age: a repository removed and added back keeps its
// runners, and the page is where they are revoked. A fleet-wide token is
// not a repository's either way, and a stamp that will not parse is
// shown rather than guessed away.
func TestARevokedTokenOlderThanTheRepositoryIsNotItsOwn(t *testing.T) {
	created := time.Date(2026, 9, 20, 12, 0, 0, 0, time.UTC)
	group := []string{ci.GroupFor("alpha")}
	const gone = "2026-09-19T09:00:00Z"
	for _, c := range []struct {
		tok  ci.WorkerToken
		site bool
		want bool
	}{
		{ci.WorkerToken{ID: "old-revoked", WorkerGroups: group, CreatedAt: "2026-09-19T08:00:00Z", RevokedAt: gone}, true, false},
		{ci.WorkerToken{ID: "old-live", WorkerGroups: group, CreatedAt: "2026-09-19T08:00:00Z"}, false, true},
		{ci.WorkerToken{ID: "new-revoked", WorkerGroups: group, CreatedAt: "2026-09-21T08:00:00.123456Z", RevokedAt: gone}, false, true},
		{ci.WorkerToken{ID: "odd", WorkerGroups: group, CreatedAt: "yesterday", RevokedAt: gone}, false, true},
		{ci.WorkerToken{ID: "fleet", CreatedAt: "2026-09-19T08:00:00Z", RevokedAt: gone}, true, true},
	} {
		if got := workerTokenOf(c.tok, "alpha", created, c.site); got != c.want {
			t.Errorf("FAIL: %s on alpha created %s: shown=%v, want %v", c.tok.ID, created, got, c.want)
		}
	}
	// An unknown creation time filters nothing.
	old := ci.WorkerToken{ID: "old", WorkerGroups: group, CreatedAt: "2026-09-19T08:00:00Z", RevokedAt: gone}
	if !workerTokenOf(old, "alpha", time.Time{}, false) {
		t.Error("FAIL: with no creation time known, alpha's token was hidden")
	}
}