feat(db): dbctl — reconcile per-peer CONNECT authorization on the shared DB (M2 §4)
New lib/db/dbctl: SyncAuthorization runs after the DB starts (EnsureDatabaseRunning), ensuring a LOGIN role + CONNECT grant per installed peer and revoking the stock PUBLIC CONNECT grant on mTLS-armed databases; RevokeForService drops a peer's CONNECT at uninstall. Admin executes over the in-container unix socket as postgres (trust). Wired into ensureInfraRunning and UninstallContainer. Includes unit tests + env-gated live integration test.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
// Copyright (C) 2026 Dcntrlized
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package dbctl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/docker"
|
||||
)
|
||||
|
||||
// TestSyncAuthorizationIntegration exercises the real exec path against a
|
||||
// running dcntrlized-db container.
|
||||
//
|
||||
// 1. docker run -d --name dcntrlized-db -e POSTGRES_DB=dcntrlized \
|
||||
// -e POSTGRES_USER=postgres -e POSTGRES_HOST_AUTH_METHOD=trust \
|
||||
// -v $PWD/PKI/ca.crt:/dcntrlized/pki/ca.crt:ro \
|
||||
// -v $PWD/PKI/tls.crt:/dcntrlized/pki/tls.crt:ro \
|
||||
// -v $PWD/PKI/tls.key:/dcntrlized/pki/tls.key:ro \
|
||||
// -v dctl-vol:/var/lib/postgresql/data dcntrlized-db
|
||||
// 2. seed the data root with install dirs for the peers
|
||||
// 3. DBCtl_INTEGRATION=1 go test ./lib/db -run TestSyncAuthorizationIntegration -v
|
||||
func TestSyncAuthorizationIntegration(t *testing.T) {
|
||||
if os.Getenv("DBCtl_INTEGRATION") != "1" {
|
||||
t.Skip("set DBCtl_INTEGRATION=1 to run against a live database container")
|
||||
}
|
||||
|
||||
root := t.TempDir()
|
||||
t.Setenv("DCNTRLIZED_INSTALL_DIR", root)
|
||||
for _, name := range []string{"keepnote", "dcntrlized-auth"} {
|
||||
if err := os.MkdirAll(filepath.Join(root, name), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(root, name, "metadata.json"), []byte("{}"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
dc, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer dc.Close()
|
||||
|
||||
c := New(dc)
|
||||
if err := c.SyncAuthorization(context.Background()); err != nil {
|
||||
t.Fatalf("SyncAuthorization: %v", err)
|
||||
}
|
||||
|
||||
id := c.dbContainerID(context.Background())
|
||||
if id == "" {
|
||||
t.Fatal("database container not found")
|
||||
}
|
||||
assert := func(t *testing.T, sql, contains string) {
|
||||
t.Helper()
|
||||
out, code, err := c.execPSQL(context.Background(), id, sql)
|
||||
if err != nil || code != 0 {
|
||||
t.Fatalf("check %q failed (exit %d, err %v): %s", sql, code, err, out)
|
||||
}
|
||||
if want := contains; want != "" && out != want {
|
||||
t.Fatalf("%s => %q, want %q", sql, out, want)
|
||||
}
|
||||
}
|
||||
// Roles exist and hold CONNECT.
|
||||
assert(t, `SELECT rolname FROM pg_catalog.pg_roles WHERE rolname IN ('maestro','keepnote','dcntrlized-auth') ORDER BY 1`, "dcntrlized-auth\nkeepnote\nmaestro")
|
||||
assert(t, `SELECT has_database_privilege('keepnote','dcntrlized','CONNECT')`, "t")
|
||||
// Armed database: PUBLIC grant removed.
|
||||
assert(t, `SELECT has_database_privilege('public','dcntrlized','CONNECT')`, "f")
|
||||
}
|
||||
Reference in New Issue
Block a user