package oltp
import "time"
// The gate-bypass tripwire (RFC 0007/0009 follow-through). A stock zit
// client can accept a landing against the shared store without ever
// consulting the forge's required checks, and the store cannot refuse
// it. What the forge CAN do is notice: it records every accept it
// wrote itself, watches each protected branch's tip, and any check-in
// that arrives on one without a forge accept behind it is named — on
// the CI page and in the log — within a poll tick.
const gateSchema = `
CREATE TABLE IF NOT EXISTS forge_accept (
repo TEXT NOT NULL,
checkin TEXT NOT NULL, -- the merge check-in a forge accept wrote
PRIMARY KEY (repo, checkin)
);
CREATE TABLE IF NOT EXISTS gate_watch (
repo TEXT NOT NULL,
branch TEXT NOT NULL,
tip TEXT NOT NULL, -- last swept tip
PRIMARY KEY (repo, branch)
);
CREATE TABLE IF NOT EXISTS gate_bypass (
repo TEXT NOT NULL,
branch TEXT NOT NULL,
checkin TEXT NOT NULL,
seen TEXT NOT NULL,
-- who committed it, so the finding names a person, not a hash.
who TEXT NOT NULL DEFAULT '',
-- acked is when a maintainer marked it seen. A finding is a
-- tripwire, and a tripwire that cannot be reset is an alarm that
-- rings forever: the record stays (it is history), the strip
-- stops showing it.
acked TEXT NOT NULL DEFAULT '',
PRIMARY KEY (repo, checkin)
);`
// gateMigrations are additive columns for stores written before them.
var gateMigrations = []string{
`ALTER TABLE gate_bypass ADD COLUMN who TEXT NOT NULL DEFAULT ''`,
`ALTER TABLE gate_bypass ADD COLUMN acked TEXT NOT NULL DEFAULT ''`,
}
// GateBypass is one tripwire finding.
type GateBypass struct {
Repo string `json:"repo"`
Branch string `json:"branch"`
Checkin string `json:"checkin"`
Seen string `json:"seen"`
Who string `json:"who,omitempty"`
Acked string `json:"acked,omitempty"`
}
// RecordForgeAccept remembers that the forge itself wrote this merge.
func (d *DB) RecordForgeAccept(repo, checkin string) error {
_, err := d.db.Exec(`INSERT OR IGNORE INTO forge_accept (repo, checkin) VALUES (?, ?)`,
repo, checkin)
return err
}
// ForgeAccepted reports whether a check-in was a forge accept's merge.
func (d *DB) ForgeAccepted(repo, checkin string) (bool, error) {
var one int
err := d.db.QueryRow(`SELECT 1 FROM forge_accept WHERE repo = ? AND checkin = ?`,
repo, checkin).Scan(&one)
if err == nil {
return true, nil
}
return false, nil
}
// GateWatch reads a protected branch's last swept tip.
func (d *DB) GateWatch(repo, branch string) (string, bool) {
var tip string
err := d.db.QueryRow(`SELECT tip FROM gate_watch WHERE repo = ? AND branch = ?`,
repo, branch).Scan(&tip)
return tip, err == nil
}
// SetGateWatch records how far the sweep has looked.
func (d *DB) SetGateWatch(repo, branch, tip string) error {
_, err := d.db.Exec(`INSERT OR REPLACE INTO gate_watch (repo, branch, tip) VALUES (?, ?, ?)`,
repo, branch, tip)
return err
}
// AddGateBypass records a finding; seeing the same check-in twice is
// one finding, not two.
func (d *DB) AddGateBypass(repo, branch, checkin, who string) error {
_, err := d.db.Exec(`INSERT OR IGNORE INTO gate_bypass (repo, branch, checkin, seen, who)
VALUES (?, ?, ?, ?, ?)`, repo, branch, checkin, time.Now().UTC().Format(time.RFC3339), who)
return err
}
// GateBypasses lists a repository's OPEN findings, newest first — what
// the CI page's strip shows. Acknowledged ones live in the history.
func (d *DB) GateBypasses(repo string, limit int) ([]GateBypass, error) {
if limit <= 0 {
limit = 5
}
return d.gateRows(`WHERE repo = ? AND acked = '' ORDER BY seen DESC LIMIT `+itoa(limit), repo)
}
// GateBypassHistory pages every finding, open or acknowledged, newest
// first, and says how many there are in all — a page that grows
// forever is the failure this exists to prevent.
func (d *DB) GateBypassHistory(repo string, offset, limit int) (rows []GateBypass, total int, err error) {
if limit <= 0 {
limit = 50
}
if offset < 0 {
offset = 0
}
if err = d.db.QueryRow(`SELECT count(*) FROM gate_bypass WHERE repo = ?`, repo).Scan(&total); err != nil {
return nil, 0, err
}
rows, err = d.gateRows(`WHERE repo = ? ORDER BY seen DESC LIMIT `+itoa(limit)+` OFFSET `+itoa(offset), repo)
return rows, total, err
}
// AckGateBypass marks one finding seen; AckAllGateBypasses clears the
// strip. Neither deletes: the tripwire's record is history.
func (d *DB) AckGateBypass(repo, checkin string) error {
_, err := d.db.Exec(`UPDATE gate_bypass SET acked = ? WHERE repo = ? AND checkin = ? AND acked = ''`,
time.Now().UTC().Format(time.RFC3339), repo, checkin)
return err
}
func (d *DB) AckAllGateBypasses(repo string) (int, error) {
res, err := d.db.Exec(`UPDATE gate_bypass SET acked = ? WHERE repo = ? AND acked = ''`,
time.Now().UTC().Format(time.RFC3339), repo)
if err != nil {
return 0, err
}
n, _ := res.RowsAffected()
return int(n), nil
}
func (d *DB) gateRows(where string, args ...any) ([]GateBypass, error) {
rows, err := d.db.Query(`SELECT repo, branch, checkin, seen, who, acked FROM gate_bypass `+where, args...)
if err != nil {
return nil, err
}
defer rows.Close()
var out []GateBypass
for rows.Next() {
var g GateBypass
if err := rows.Scan(&g.Repo, &g.Branch, &g.Checkin, &g.Seen, &g.Who, &g.Acked); err != nil {
return nil, err
}
out = append(out, g)
}
return out, rows.Err()
}