Documentation
¶
Overview ¶
Package settings is each user's own GitHub/Forgejo credentials — saved through the Settings page, encrypted at rest, and what dashboard.Manager builds that user's forge sources from. Replaces v1's GITHUB_TOKEN/FORGEJO_* environment variables, which configured one dashboard for everyone rather than one per signed-in user.
Index ¶
- Variables
- func WebhookDeliveryKey(forge, repoFullName string) string
- type Cipher
- type Credentials
- type Store
- func (s *Store) AllowsBotPRUpdates(ctx context.Context, userID []byte) (bool, error)
- func (s *Store) AutoUpdateBranchRepos(ctx context.Context, userID []byte) (map[string]struct{}, error)
- func (s *Store) Delete(ctx context.Context, userID []byte) error
- func (s *Store) DisableAutoUpdateBranch(ctx context.Context, userID []byte, forge, repoFullName string) error
- func (s *Store) EnableAutoUpdateBranch(ctx context.Context, userID []byte, forge, repoFullName string) error
- func (s *Store) EnsureWebhookCredentials(ctx context.Context, userID []byte) (token, secret string, err error)
- func (s *Store) FindByWebhookToken(ctx context.Context, token string) (userID []byte, secret string, err error)
- func (s *Store) Get(ctx context.Context, userID []byte) (Credentials, error)
- func (s *Store) GetFilterState(ctx context.Context, userID []byte) (string, error)
- func (s *Store) IgnoreRepo(ctx context.Context, userID []byte, forge, repoFullName string) error
- func (s *Store) IgnoredRepos(ctx context.Context, userID []byte) (map[string]struct{}, error)
- func (s *Store) Init(ctx context.Context) error
- func (s *Store) RecordWebhookDelivery(ctx context.Context, userID []byte, forge, repoFullName string) error
- func (s *Store) Set(ctx context.Context, userID []byte, c Credentials) error
- func (s *Store) SetFilterState(ctx context.Context, userID []byte, stateJSON string) error
- func (s *Store) UnignoreRepo(ctx context.Context, userID []byte, forge, repoFullName string) error
- func (s *Store) WebhookDeliveries(ctx context.Context, userID []byte) (map[string]struct{}, error)
Constants ¶
This section is empty.
Variables ¶
var ErrNoEncryptionKey = errors.New("settings: ENCRYPTION_KEY must decode to 32 bytes")
ErrNoEncryptionKey is returned by NewCipher when key isn't valid AES-256 key material — a service holding real credentials has to fail loudly at startup rather than silently store them in the clear.
var ErrNotFound = errors.New("settings: not found")
ErrNotFound is returned when a user has never saved any credentials.
Functions ¶
func WebhookDeliveryKey ¶ added in v0.53.0
WebhookDeliveryKey is how a repo's forge and full name combine into the key WebhookDeliveries' returned set uses — exported so a caller never has to know or reproduce the separator itself. IgnoredRepos' returned set is keyed the same way, rather than inventing a second, differently-shaped helper for an identical (forge, repoFullName) pair.
Types ¶
type Cipher ¶
type Cipher struct {
// contains filtered or unexported fields
}
Cipher encrypts and decrypts credential fields with AES-256-GCM.
func NewCipher ¶
NewCipher builds a Cipher from base64Key, the raw form of ENCRYPTION_KEY. Generate one with `openssl rand -base64 32`.
type Credentials ¶
type Credentials struct {
GitHubToken string
GitHubUsername string
ForgejoURL string
ForgejoToken string
ForgejoUsername string
// WebhookToken identifies this user in a webhook URL
// (/api/webhooks/{provider}/{token}); WebhookSecret is what's pasted
// into the forge's own webhook "Secret" field and never appears in
// the URL, so a leaked log line alone can't forge a valid signature.
// Neither is a third-party credential the way the forge tokens above
// are, so neither is encrypted at rest — see EnsureWebhookCredentials.
WebhookToken string
WebhookSecret string
// AllowBotPrUpdates overrides the default restraint the Update
// branch/Dependabot/Renovate action buttons apply to a pull request
// opened by release-please, Dependabot, or Renovate: those tools
// already keep their own PRs current on their own schedule, so a
// manual "Update branch" click is redundant at best and, for
// release-please specifically (which regenerates the PR's branch
// and changelog together on every push to the base branch), a
// genuine risk of fighting its own next run. False (the default,
// Go's zero value) is "leave bot-managed PRs alone"; true opts back
// into treating them the same as any other PR.
AllowBotPrUpdates bool
// RenovateRebaseLabel is the label Renovate's own rebase/retry
// trigger listens for on a given repo (Renovate's own rebaseLabel
// config option — "rebase" is Renovate's own default, but this is
// genuinely per-repo configurable, so it's a user-set override
// rather than a hardcoded constant). Empty means "use Renovate's own
// default" — see renovateRebaseLabelOrDefault.
RenovateRebaseLabel string
// Theme is "light", "dark", or "" (system — the default, matching
// theme.js's own old cookie-unset behavior). Set only from Settings
// (#352: no header toggle anywhere else) and read on every page load
// via the lightweight GET /api/settings/theme, the same
// "don't provision webhook credentials just to check one field"
// restraint GET /api/settings/bot-pr-updates already has.
Theme string
UpdatedAt time.Time
}
Credentials is one user's forge configuration, decrypted and ready to use — never itself serialized back to a client once saved; see internal/api's settings handlers for what does reach the browser.
func (Credentials) RenovateRebaseLabelOrDefault ¶ added in v0.66.0
func (c Credentials) RenovateRebaseLabelOrDefault() string
RenovateRebaseLabelOrDefault resolves c's own saved label, falling back to Renovate's documented default when the user has never set one.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists Credentials, encrypted at rest, one row per user.
func NewStore ¶
NewStore wraps db, encrypting and decrypting every token field through cipher. Init must be called once before any other method.
func (*Store) AllowsBotPRUpdates ¶ added in v0.80.0
AllowsBotPRUpdates reports userID's own saved AllowBotPrUpdates — false for a user who's never saved any settings at all, the same zero-value default Credentials{} itself gives someone who has saved settings but never touched this specific toggle. Exists mainly to satisfy dashboard.AutoUpdateBranchLister without that package needing the full Credentials shape (and the token decryption Get does) just to read one bool.
func (*Store) AutoUpdateBranchRepos ¶ added in v0.80.0
func (s *Store) AutoUpdateBranchRepos(ctx context.Context, userID []byte) (map[string]struct{}, error)
AutoUpdateBranchRepos returns the set of forge/repo pairs (keyed by WebhookDeliveryKey) userID has turned automatic branch updates on for — empty, never an error, for a user who's never enabled any.
func (*Store) Delete ¶ added in v0.9.0
Delete removes userID's saved credentials — a no-op, not an error, if they never saved any. Used when an admin removes the account outright. Also removes their recorded webhook deliveries and per-repo settings, the same store's other tables.
func (*Store) DisableAutoUpdateBranch ¶ added in v0.80.0
func (s *Store) DisableAutoUpdateBranch(ctx context.Context, userID []byte, forge, repoFullName string) error
DisableAutoUpdateBranch reverses EnableAutoUpdateBranch. Idempotent: disabling a repo that was never enabled is a no-op, not an error.
func (*Store) EnableAutoUpdateBranch ¶ added in v0.80.0
func (s *Store) EnableAutoUpdateBranch(ctx context.Context, userID []byte, forge, repoFullName string) error
EnableAutoUpdateBranch turns on automatic branch updates for forge/repoFullName (#365) — any of its pull requests the background refresh finds behind its base branch gets updated the same way a manual "Update branch" click would, from then on. Idempotent: enabling an already-enabled repo is a no-op, not an error.
func (*Store) EnsureWebhookCredentials ¶ added in v0.24.0
func (s *Store) EnsureWebhookCredentials(ctx context.Context, userID []byte) (token, secret string, err error)
EnsureWebhookCredentials returns userID's webhook token and secret, generating and persisting them on first call — a user who never opens Settings never gets a row touched for this, and a repeat call always returns the same values (a webhook already configured on a forge points at a URL built from the token; it can't change underneath it). Doesn't touch any other field, including on a user who has no saved row at all yet.
func (*Store) FindByWebhookToken ¶ added in v0.25.0
func (s *Store) FindByWebhookToken(ctx context.Context, token string) (userID []byte, secret string, err error)
FindByWebhookToken looks up which user a webhook token belongs to and their signing secret, for verifying an inbound webhook delivery. Returns ErrNotFound for any token with no match — including the empty string, which every row that's never called EnsureWebhookCredentials shares as its default, and which would otherwise resolve to whichever of them the query happened to return first.
func (*Store) GetFilterState ¶ added in v0.71.0
GetFilterState returns userID's own saved dashboard/Insights filter state as a raw JSON blob (#353) — "{}" for a user who's never saved any, the same empty-object shape Filters.defaultState() already treats as "nothing set" client-side, not ErrNotFound: no filters saved yet is the normal starting state, not a missing-row error the way Get's own ErrNotFound is for forge credentials.
func (*Store) IgnoreRepo ¶ added in v0.73.0
IgnoreRepo marks forge/repoFullName as ignored for userID — its pull requests and issues stop appearing in that user's dashboard/Insights (see internal/api's buildDashboardResponse), though the repo itself keeps being fetched and tracked (#363). Idempotent: ignoring an already-ignored repo is a no-op, not an error.
func (*Store) IgnoredRepos ¶ added in v0.73.0
IgnoredRepos returns the set of forge/repo pairs (keyed by WebhookDeliveryKey) userID has ignored — empty, never an error, for a user who's never ignored anything.
func (*Store) Init ¶
Init creates the schema if it doesn't already exist. Safe to call every startup.
func (*Store) RecordWebhookDelivery ¶ added in v0.53.0
func (s *Store) RecordWebhookDelivery(ctx context.Context, userID []byte, forge, repoFullName string) error
RecordWebhookDelivery notes that userID's webhook for forge/repoFullName just delivered a signature-verified event — the passive signal WebhookDeliveries reports back as "this repo has a working webhook," since actually asking GitHub/Forgejo whether one's configured would need a broader token scope than this app otherwise asks for (see the issue this shipped against for why). Safe to call repeatedly; only the latest timestamp is kept.
func (*Store) Set ¶
Set replaces userID's entire credential row — a Settings save is always a full form submit, not a partial patch.
func (*Store) SetFilterState ¶ added in v0.71.0
SetFilterState replaces userID's own saved filter state with stateJSON verbatim — this Store never parses or validates its shape, the same "opaque blob, not this layer's concern" treatment WebAuthnCeremonyOptions gets in api/openapi.yaml. Doesn't touch any other field, including on a user with no saved row at all yet (EnsureWebhookCredentials' own "insert just this one field" shape, not Set's full-row replace — #353's whole point is that this saves far more often than a real Settings submit does, so it can't wait on one having happened first).
func (*Store) UnignoreRepo ¶ added in v0.73.0
UnignoreRepo reverses IgnoreRepo. Idempotent: un-ignoring a repo that was never ignored is a no-op, not an error.
func (*Store) WebhookDeliveries ¶ added in v0.53.0
WebhookDeliveries returns the set of forge/repo pairs (keyed by WebhookDeliveryKey) that have ever delivered a signature-verified webhook event for userID — empty for a user none of whose repos have, never an error for that case.