carlos / platform Public

console: the self-serve gate matrix's carried minors

A positive control at the head of requireUnauthorisedCostNothing: a plain
instance token's poll through the legacy moveGate is shown to cost bucket
reads and evidence SQL on the same counters. The binding SQL is an
allow-list of the five exact statements that authenticate the token and
resolve the account and the app; any other statement on those tables is
evidence. The first rail is named for what it is (the deployment bucket
in place), not fresh.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 24a467d1336e2277b01dfe4caa59ab010cb657e2 parent aa7b9c8
1 file changed, +33 −10
  • internal/console/selfserve_gate_test.go +33 −10
diff --git a/internal/console/selfserve_gate_test.go b/internal/console/selfserve_gate_test.go
index 901e4bf1f..b5326d29b 100644
--- a/internal/console/selfserve_gate_test.go
+++ b/internal/console/selfserve_gate_test.go
@@ -8,7 +8,6 @@ import (
"io"
"net/http"
"net/http/httptest"
- "regexp"
"strings"
"sync"
"sync/atomic"
@@ -85,10 +84,18 @@ func (c *countingRelStore) DeleteIfMatch(ctx context.Context, key, etag string)
return c.DirStore.DeleteIfMatch(ctx, key, etag)
}
-// bindingSQL is the SQL the gate may run: authenticating the token
-// (cli_tokens) and resolving the account and the app (accounts, apps).
-// Everything else is evidence.
-var bindingSQL = regexp.MustCompile(`\b(cli_tokens|accounts|apps)\b`)
+// bindingSQL is the SQL the gate may run, statement by statement:
+// authenticating the token (its row, and the last-used stamp) and resolving
+// the account and the app (the account by id or by the caller's
+// memberships, and the app's row count). Everything else, any other
+// statement on these tables included, is evidence.
+var bindingSQL = map[string]bool{
+ "SELECT token_hash, address, kind, account_id, app, role, name, expires_at, revoked_at, rungs, moves FROM cli_tokens WHERE token_hash = ?": true,
+ "UPDATE cli_tokens SET last_used = ? WHERE token_hash = ?": true,
+ "SELECT id, sqid, name, created_at FROM accounts WHERE id = ? AND deleted_at = 0": true,
+ "SELECT a.id, a.sqid, a.name, a.created_at, m.role FROM accounts a JOIN memberships m ON m.account_id = a.id WHERE m.address = ? AND a.deleted_at = 0 ORDER BY a.created_at, a.id": true,
+ "SELECT COUNT(*) FROM apps WHERE account_id = ? AND app = ? AND deleted_at = 0": true,
+}
// countingSQL classifies every statement the console store runs. A
// transaction is counted as evidence when it begins: its statements do not
@@ -103,11 +110,12 @@ type countingSQL struct {
func (c *countingSQL) note(q string) {
c.mu.Lock()
defer c.mu.Unlock()
- if bindingSQL.MatchString(q) {
+ stmt := strings.Join(strings.Fields(q), " ")
+ if bindingSQL[stmt] {
c.binding++
return
}
- c.evidence = append(c.evidence, strings.Join(strings.Fields(q), " "))
+ c.evidence = append(c.evidence, stmt)
}
func (c *countingSQL) reset() (binding int, evidence []string) {
@@ -325,8 +333,9 @@ func (sc moveScene) counting(t *testing.T) (*countingRelStore, costedCall) {
}
// rails are the three conditions an unauthorised caller's answer must not
-// depend on, applied in this order: a fresh limiter with a bucket, no
-// bucket, and every caller's budget spent.
+// depend on, applied in this order: the deployment bucket in place (the
+// limiter as earlier requests left it), no bucket, and every caller's
+// budget spent.
func (sc moveScene) rails(counted *countingRelStore) []struct {
name string
apply func()
@@ -336,7 +345,7 @@ func (sc moveScene) rails(counted *countingRelStore) []struct {
name string
apply func()
}{
- {"fresh", func() { fx.srv.cfg.Releases = counted }},
+ {"with a deployment bucket", func() { fx.srv.cfg.Releases = counted }},
{"no deployment bucket", func() { fx.srv.cfg.Releases = nil }},
{"limiter exhausted", func() {
fx.srv.cfg.Releases = counted
@@ -361,6 +370,20 @@ func requireUnauthorisedCostNothing(t *testing.T, sc moveScene, counted *countin
// move-capable token, and an operator has the operator doors.
"the owner's own CLI token": sc.l.operator,
}
+ // The positive control: the counters see what the legacy path reads.
+ // A plain instance token's poll goes through moveGate, which reads the
+ // record, so the same call shape that must cost nothing below is shown
+ // able to see a bucket read and evidence SQL.
+ sc.l.fx.srv.cfg.Releases = counted
+ setMoveRecord(t, sc.l.fx.rel, "eligible")
+ control, err := sc.l.fx.st.NewAppToken(OpsAccountID, ltApp, "paul@keymail.dev", "control", false, time.Now())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if code, _, body, reads, binding, evidence := call(http.MethodGet, sc.url(ltOne, "/move"), control, ""); code != http.StatusOK || reads == 0 || binding == 0 || len(evidence) == 0 {
+ t.Fatalf("the positive control: a plain token's poll = %d %s with %d store calls, %d binding statements, evidence %q; want 200 with reads and evidence",
+ code, body, reads, binding, evidence)
+ }
for _, rail := range sc.rails(counted) {
rail.apply()
for _, state := range moveRecordStates {