internal/store/cisecrets.go

bd5cf5d7d1f34fa780660fd7562b9ffd9746ee27
gitbay/internal/store/cisecrets.go history · blame · raw

157 lines · 4341 bytes

  1package store
  2
  3import "fmt"
  4
  5// SetBuildSecret stores or replaces one secret. The value never leaves the
  6// server except inside a claimed build's environment. It is sealed inside
  7// the write transaction; see ResealSecrets.
  8func (s *Store) SetBuildSecret(repoID int64, name, value string) error {
  9	tx, err := s.DB.Begin()
 10	if err != nil {
 11		return err
 12	}
 13	defer tx.Rollback()
 14	sealed, err := s.sealValue(buildSecretAAD(repoID, name), value)
 15	if err != nil {
 16		return err
 17	}
 18	if _, err := tx.Exec(`
 19		INSERT INTO build_secrets (repo_id, name, value) VALUES (?, ?, ?)
 20		ON CONFLICT (repo_id, name) DO UPDATE SET value = excluded.value`,
 21		repoID, name, sealed); err != nil {
 22		return err
 23	}
 24	return tx.Commit()
 25}
 26
 27func (s *Store) RemoveBuildSecret(repoID int64, name string) error {
 28	res, err := s.DB.Exec("DELETE FROM build_secrets WHERE repo_id = ? AND name = ?", repoID, name)
 29	if err != nil {
 30		return err
 31	}
 32	if n, _ := res.RowsAffected(); n == 0 {
 33		return ErrNotFound
 34	}
 35	return nil
 36}
 37
 38// ListBuildSecretNames returns names only; values are for builds.
 39func (s *Store) ListBuildSecretNames(repoID int64) ([]string, error) {
 40	rows, err := s.DB.Query("SELECT name FROM build_secrets WHERE repo_id = ? ORDER BY name", repoID)
 41	if err != nil {
 42		return nil, err
 43	}
 44	defer rows.Close()
 45	var out []string
 46	for rows.Next() {
 47		var n string
 48		if err := rows.Scan(&n); err != nil {
 49			return nil, err
 50		}
 51		out = append(out, n)
 52	}
 53	return out, rows.Err()
 54}
 55
 56// BuildSecrets returns the values, for injection into a claimed build.
 57func (s *Store) BuildSecrets(repoID int64) (map[string]string, error) {
 58	rows, err := s.DB.Query("SELECT name, value FROM build_secrets WHERE repo_id = ?", repoID)
 59	if err != nil {
 60		return nil, err
 61	}
 62	defer rows.Close()
 63	out := map[string]string{}
 64	for rows.Next() {
 65		var n, v string
 66		if err := rows.Scan(&n, &v); err != nil {
 67			return nil, err
 68		}
 69		if out[n], err = s.openValue(buildSecretAAD(repoID, n), v); err != nil {
 70			return nil, fmt.Errorf("build secret %s: %w", n, err)
 71		}
 72	}
 73	return out, rows.Err()
 74}
 75
 76// Schedule is one repo job's cron entry.
 77type Schedule struct {
 78	RepoID  int64
 79	Job     string
 80	Cron    string
 81	NextRun string
 82}
 83
 84// SyncSchedules replaces a repo's schedule set with the given entries,
 85// preserving next_run for entries whose cron is unchanged.
 86func (s *Store) SyncSchedules(repoID int64, entries []Schedule) error {
 87	tx, err := s.DB.Begin()
 88	if err != nil {
 89		return err
 90	}
 91	defer tx.Rollback()
 92	keep := map[string]bool{}
 93	for _, e := range entries {
 94		keep[e.Job] = true
 95		if _, err := tx.Exec(`
 96			INSERT INTO build_schedules (repo_id, job, cron, next_run) VALUES (?, ?, ?, ?)
 97			ON CONFLICT (repo_id, job) DO UPDATE SET
 98				next_run = CASE WHEN cron = excluded.cron THEN next_run ELSE excluded.next_run END,
 99				cron = excluded.cron`,
100			repoID, e.Job, e.Cron, e.NextRun); err != nil {
101			return err
102		}
103	}
104	rows, err := tx.Query("SELECT job FROM build_schedules WHERE repo_id = ?", repoID)
105	if err != nil {
106		return err
107	}
108	var stale []string
109	for rows.Next() {
110		var j string
111		if err := rows.Scan(&j); err != nil {
112			rows.Close()
113			return err
114		}
115		if !keep[j] {
116			stale = append(stale, j)
117		}
118	}
119	rows.Close()
120	for _, j := range stale {
121		if _, err := tx.Exec("DELETE FROM build_schedules WHERE repo_id = ? AND job = ?", repoID, j); err != nil {
122			return err
123		}
124	}
125	return tx.Commit()
126}
127
128// DueSchedules returns entries whose next_run is at or before now.
129func (s *Store) DueSchedules(nowISO string) ([]Schedule, error) {
130	rows, err := s.DB.Query(
131		"SELECT repo_id, job, cron, next_run FROM build_schedules WHERE next_run <= ? ORDER BY next_run", nowISO)
132	if err != nil {
133		return nil, err
134	}
135	defer rows.Close()
136	var out []Schedule
137	for rows.Next() {
138		var e Schedule
139		if err := rows.Scan(&e.RepoID, &e.Job, &e.Cron, &e.NextRun); err != nil {
140			return nil, err
141		}
142		out = append(out, e)
143	}
144	return out, rows.Err()
145}
146
147// SetScheduleNext advances one entry's next firing time.
148func (s *Store) SetScheduleNext(repoID int64, job, nextRun string) error {
149	_, err := s.DB.Exec(
150		"UPDATE build_schedules SET next_run = ? WHERE repo_id = ? AND job = ?", nextRun, repoID, job)
151	return err
152}
153
154func (s *Store) RemoveSchedule(repoID int64, job string) error {
155	_, err := s.DB.Exec("DELETE FROM build_schedules WHERE repo_id = ? AND job = ?", repoID, job)
156	return err
157}