Report as revoked only what the read-back shows gone, and take back what the reader passed on (review of hq issue 337)
mesh/merge-gate pass: builds postgres, sent nowhere; no bus step; 2 wait(s) for a person; every machine composes with the change as it did without (4 of 4 …
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

A reader given a privilege WITH GRANT OPTION that passed it on made the
plain revoke fail with dependent privileges exist; the pass still listed the
table as revoked and logged it every minute. The pass now retries such a
change with CASCADE, which reaches only grants that came from the reader,
reads the grants back, reports as revoked only what is gone, and says what
is still held and why when anything is.
This commit is contained in:
jochen
2026-10-08 22:11:06 +02:00
parent 8bf50f7555
commit e0e97a96c4
4 changed files with 134 additions and 9 deletions
@@ -6,6 +6,7 @@ package main
import (
"encoding/json"
"errors"
"os"
"path/filepath"
"strings"
@@ -354,3 +355,26 @@ func TestTheCataloguesReadableDeclarationsParse(t *testing.T) {
}
}
}
// A change that fails reports nothing revoked, and says what is still held and why — every pass, not
// "revoked" every pass.
func TestAFailedChangeSaysWhatIsStillHeldAndRevokesNothing(t *testing.T) {
conn := admin
conn.ReaderPassword = "r"
f, c := newFake(conn)
f.answer(`^SELECT rolsuper`, []string{"a", "b", "c", "d", "e", "f", "g", "h", "i"},
[]string{"f", "f", "f", "f", "f", "t", "t", "t", "default_transaction_read_only=on,statement_timeout=60s"})
f.answer(`SELECT datname FROM pg_database WHERE datallowconn`, []string{"datname"}, []string{"app"})
f.answer(`aclexplode\(c\.relacl\)`, []string{"nspname", "relname", "relkind", "privilege_type", "grantor"},
[]string{"public", "vault", "r", "SELECT", "owner1"})
f.answer(`aclexplode\(a\.attacl\)`, []string{"nspname", "relname", "attname", "privilege_type", "grantor"})
f.fail(`^SET ROLE`, errors.New("server busy"))
rep := c.ReconcileReader(ctx, Declarations{}, "")
db := rep.Databases[0]
if len(db.Revoked) != 0 {
t.Fatalf("said revoked: %v", db.Revoked)
}
if !strings.Contains(db.Error, "STILL HELD") || !strings.Contains(db.Error, "public.vault") || !strings.Contains(db.Error, "server busy") {
t.Fatal(db.Error)
}
}