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 AutoMergeKey(forge, repoFullName string, number int) string
- func WebhookDeliveryKey(forge, repoFullName string) string
- type Cipher
- type Credentials
- type IgnoreScope
- type Store
- func (s *Store) ArmAutoMerge(ctx context.Context, userID []byte, forge, repoFullName string, number int) error
- func (s *Store) AutoMergeIntents(ctx context.Context, userID []byte) (map[string]struct{}, error)
- func (s *Store) AutoUpdateBranchRepos(ctx context.Context, userID []byte) (map[string]struct{}, error)
- func (s *Store) CancelAutoMerge(ctx context.Context, userID []byte, forge, repoFullName string, number int) error
- func (s *Store) CancelQueuedAction(ctx context.Context, userID []byte, id string) (bool, 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) EnqueueQueuedAction(ctx context.Context, userID []byte, q dashboard.QueuedAction) (dashboard.QueuedAction, bool, 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]IgnoreScope, error)
- func (s *Store) Init(ctx context.Context) error
- func (s *Store) PruneQueuedActions(ctx context.Context, userID []byte, cutoff time.Time) error
- func (s *Store) QueuedActions(ctx context.Context, userID []byte) ([]dashboard.QueuedAction, error)
- func (s *Store) RecordWebhookDelivery(ctx context.Context, userID []byte, forge, repoFullName string) error
- func (s *Store) RenovateAuthors(ctx context.Context, userID []byte) ([]string, error)
- func (s *Store) RenovateRebaseLabel(ctx context.Context, userID []byte) (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) UpdateQueuedAction(ctx context.Context, userID []byte, q dashboard.QueuedAction) (bool, error)
- func (s *Store) UsersWithWaitingQueuedActions(ctx context.Context) ([][]byte, 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 AutoMergeKey ¶ added in v0.135.0
AutoMergeKey is how a pull request's forge, repo and number combine into the key AutoMergeIntents' returned set uses.
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
// 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
// RenovateAuthors are the logins that are Renovate on the user's forges.
// On GitHub the App's own slugs are fixed and built in; a Forgejo or
// GitLab instance has no App, so Renovate runs as an ordinary account
// there, named whatever the instance chose. Only the user knows it, so
// nothing is assumed (#1062). Empty means none beyond the built-in slugs.
RenovateAuthors []string
// Theme is "light", "dark", or "" (system — the default, matching
// the pre-paint theme script's 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, which doesn't
// provision webhook credentials just to check one field.
Theme string
// Timezone is an IANA name such as "Europe/Amsterdam", or "" for the
// browser's own zone (the default). It exists for browsers that report UTC
// to every page, such as Firefox with fingerprint resistance (#996). Set
// from Settings and read on every page load via GET /api/settings/timezone.
Timezone string
UpdatedAt time.Time
// GitHubAppInstallationID identifies which installation of the
// alrayyes-automation GitHub App (#620) this user has connected — 0
// means none. Not a secret the way GitHubToken is (it's meaningless
// without the App's own private key, which never leaves server-wide
// config), so it isn't run through Store's AES-256-GCM cipher and is
// stored as a plain integer column. Wins over GitHubToken when both
// are set and the server has an App configured — see
// cmd/forge-dashboard's buildSourcesForUser.
GitHubAppInstallationID int64
}
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 IgnoreScope ¶ added in v0.89.0
IgnoreScope is which of a repo's pull requests and issues are ignored (#511) — the zero value means neither, the same as the key being absent from IgnoredRepos' returned map.
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) ArmAutoMerge ¶ added in v0.135.0
func (s *Store) ArmAutoMerge(ctx context.Context, userID []byte, forge, repoFullName string, number int) error
ArmAutoMerge records that userID asked this app to merge the pull request once its checks pass. Forgejo can't report a scheduled merge back, so the intent lives here. Idempotent: arming an armed pull request keeps the original time.
func (*Store) AutoMergeIntents ¶ added in v0.135.0
AutoMergeIntents returns, keyed by AutoMergeKey, every pull request userID has armed — empty, never an error, for a user who has armed none.
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) CancelAutoMerge ¶ added in v0.135.0
func (s *Store) CancelAutoMerge(ctx context.Context, userID []byte, forge, repoFullName string, number int) error
CancelAutoMerge reverses ArmAutoMerge. Idempotent: cancelling a pull request that was never armed is a no-op, not an error.
func (*Store) CancelQueuedAction ¶ added in v0.149.0
CancelQueuedAction removes userID's queued action id, waiting or finished, and reports whether there was one. Another user's id is not found, so one account can neither see nor cancel another's queue.
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) EnqueueQueuedAction ¶ added in v0.149.0
func (s *Store) EnqueueQueuedAction(ctx context.Context, userID []byte, q dashboard.QueuedAction) (dashboard.QueuedAction, bool, error)
EnqueueQueuedAction stores a safe action for userID to run once a forge's rate limit resets (#756) and returns it with its new ID and true. Idempotent: a second request for the same action on the same pull request while the first still waits returns the first, unchanged, and false, rather than stacking a duplicate.
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
func (s *Store) IgnoreRepo(ctx context.Context, userID []byte, forge, repoFullName string, prs, issues bool) error
IgnoreRepo marks forge/repoFullName as ignored for userID in exactly the given scope — its pull requests and/or issues stop appearing in that user's dashboard/Insights (see internal/api's buildDashboardResponse), though the repo itself keeps being fetched and tracked (#363). A repeat call replaces the previously saved scope rather than merging with it, so it's idempotent only for an identical repeat, not additive across calls with different scopes (#511).
func (*Store) IgnoredRepos ¶ added in v0.73.0
IgnoredRepos returns, keyed by WebhookDeliveryKey, the ignore scope for every forge/repo pair userID has ignored in either scope — 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) PruneQueuedActions ¶ added in v0.153.0
PruneQueuedActions deletes userID's finished queued actions that finished before cutoff. Waiting ones are never pruned.
func (*Store) QueuedActions ¶ added in v0.149.0
QueuedActions returns every queued action userID has, waiting or finished, oldest first — empty, never nil or an error, for a user with none.
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) RenovateAuthors ¶ added in v0.135.0
RenovateAuthors reports userID's own saved Renovate logins, none for a user who has never saved settings. It exists, like RenovateRebaseLabel, so dashboard.AutoUpdateBranchLister needn't take the whole Credentials shape.
func (*Store) RenovateRebaseLabel ¶ added in v0.95.0
RenovateRebaseLabel reports userID's own saved RenovateRebaseLabel, resolved through RenovateRebaseLabelOrDefault — Renovate's own default ("rebase") 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 field. Exists mainly to satisfy dashboard.AutoUpdateBranchLister without that package needing the full Credentials shape (and the token decryption Get does) just to read one string.
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, clearing both scopes at once regardless of which were set. Idempotent: un-ignoring a repo that was never ignored is a no-op, not an error.
func (*Store) UpdateQueuedAction ¶ added in v0.153.0
func (s *Store) UpdateQueuedAction(ctx context.Context, userID []byte, q dashboard.QueuedAction) (bool, error)
UpdateQueuedAction saves the status, reset time, outcome and finish time of userID's queued action q, and reports whether a waiting one was there to update. Only a waiting action changes: one cancelled meanwhile stays gone, and one already finished keeps its outcome.
func (*Store) UsersWithWaitingQueuedActions ¶ added in v0.153.0
UsersWithWaitingQueuedActions lists every user who still has a queued action waiting, so a restarted server can start their dashboards and keep the promise to run it at the reset.
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.