internal/store/cisecrets.go
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}