agent-orchestrator/backend/internal/adapters/tracker/github/auth.go

56 lines
1.7 KiB
Go

package github
import (
"context"
"errors"
"os"
"strings"
)
// TokenSource yields a GitHub bearer token on demand. It is intentionally
// tiny so tests can inject a static token and production can layer env-var or
// gh-CLI fallbacks behind the same surface. The Tracker calls Token once at
// construction (fail-fast) and again per request (so rotated tokens are
// picked up without restart).
type TokenSource interface {
Token(ctx context.Context) (string, error)
}
// ErrNoToken is returned when no token source could yield a non-empty token.
var ErrNoToken = errors.New("github tracker: no token configured")
// StaticTokenSource is a literal token, typically used in tests.
type StaticTokenSource string
// Token returns the literal token, or ErrNoToken if it is blank.
func (s StaticTokenSource) Token(context.Context) (string, error) {
t := strings.TrimSpace(string(s))
if t == "" {
return "", ErrNoToken
}
return t, nil
}
// EnvTokenSource reads the first non-empty value from the listed env vars,
// falling back to GITHUB_TOKEN. The order matters: a project-configured
// token (e.g. AO_GITHUB_TOKEN) should be preferred over the global default,
// matching the pattern PR #28 uses on the SCM side so both adapters honor
// the same precedence.
type EnvTokenSource struct {
EnvVars []string
}
// Token returns the first non-empty configured env var (falling back to
// GITHUB_TOKEN), or ErrNoToken if none is set.
func (s EnvTokenSource) Token(context.Context) (string, error) {
for _, name := range s.EnvVars {
if v := strings.TrimSpace(os.Getenv(name)); v != "" {
return v, nil
}
}
if v := strings.TrimSpace(os.Getenv("GITHUB_TOKEN")); v != "" {
return v, nil
}
return "", ErrNoToken
}