package ci
import "strings"
// UnmatchableScope reports why a worker-token scope will match no task
// type, or "" when it looks usable.
//
// dagnats admits a scope two ways (Claims.AllowsTaskType): the WHOLE
// task type, or a namespace the task type continues after a DOT. Queue
// task types are run-scoped — "dantest-puzzles.26acbacb9e18…" — so
// "dantest-puzzles" matches, because the next character is a dot, and
// "dantest-" never can, because the next character is 'p'.
//
// The Runners form asked for "prefixes" and suggested "e2e- build-", so
// the natural thing to type minted a credential that matched nothing,
// and the 403 that followed blamed the task type rather than the
// token's scope (bd68d1073409). The control advertised behaviour it did
// not have.
//
// THIS IS A HEURISTIC AND NOT A PROOF. Whether a scope can ever match
// depends on which task types exist, which this package cannot know: a
// forge whose types really were named "e2e-" would be refused here for
// no reason. It rejects only the two endings that the dot rule makes
// nearly impossible, and says what to type instead, because the
// alternative is a credential that fails silently at poll time and
// points its holder at the wrong cause.
func UnmatchableScope(scope string) string {
switch {
case strings.HasSuffix(scope, "-"), strings.HasSuffix(scope, "_"):
return scope + " is a prefix, and a worker token's scope is not a prefix: it is a whole " +
"task type, or a namespace the task type continues after a dot. Queue task types look " +
"like dantest-puzzles.26acbacb, so dantest-puzzles matches every run of it and " +
scope + " matches nothing. Name the task types instead, space separated."
case strings.HasSuffix(scope, "."):
return scope + " ends in a dot, so it would only match a task type with an empty first " +
"segment. Drop the dot: " + strings.TrimSuffix(scope, ".") + " already matches every " +
"run under it."
}
return ""
}