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,
PRIMARY KEY (repo, checkin)
);`
// GateBypass is one tripwire finding.
type GateBypass struct {
Repo string `json:"repo"`
Branch string `json:"branch"`
Checkin string `json:"checkin"`
Seen string `json:"seen"`
}
// 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 string) error {
_, err := d.db.Exec(`INSERT OR IGNORE INTO gate_bypass (repo, branch, checkin, seen)
VALUES (?, ?, ?, ?)`, repo, branch, checkin, time.Now().UTC().Format(time.RFC3339))
return err
}
// GateBypasses lists a repository's findings, newest first.
func (d *DB) GateBypasses(repo string, limit int) ([]GateBypass, error) {
if limit <= 0 {
limit = 5
}
rows, err := d.db.Query(`SELECT repo, branch, checkin, seen FROM gate_bypass
WHERE repo = ? ORDER BY seen DESC LIMIT `+itoa(limit), repo)
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); err != nil {
return nil, err
}
out = append(out, g)
}
return out, rows.Err()
}