feat(coderd/database): add boundary_sessions and boundary_logs tables (#25441)

RFC: [Bridge ↔ Boundaries Correlation
RFC](https://www.notion.so/coderhq/Gateway-and-Firewall-Correlation-RFC-31ad579be592803aa8b3d48348ccdde9)

Add up/down migrations and matching sqlc queries for persisting Boundary
audit events, as specified in the Bridge/Boundaries Correlation RFC.

**Tables:**
- `boundary_sessions`: session metadata with `workspace_agent_id` FK,
`confined_process_name`, and timestamps (`started_at`, `updated_at`). ID
is externally supplied by the Boundary process (no DB-side default).
Created lazily when the first log for a session arrives.
- `boundary_logs`: individual audit events with `session_id` FK,
`sequence_number` (INT, primary ordering key), protocol/method/detail
fields, and `matched_rule` (nullable; non-NULL implies allowed).

**Indexes (per RFC):**
- `(session_id, sequence_number)` for the ordering query path
- `(captured_at)` for the retention purge path

**Queries:**
- `InsertBoundarySession` / `GetBoundarySessionByID`
- `InsertBoundaryLog` / `GetBoundaryLogByID`
- `ListBoundaryLogsBySessionID` with nullable `seq_after`/`seq_before`
exclusive bounds for fetching events between two known interception
sequence numbers
- `DeleteOldBoundaryLogs` with row limit to avoid long-running
transactions

**Also includes:** dbgen helpers (`BoundarySession`, `BoundaryLog`),
dbauthz implementations (reads gated on `ResourceAuditLog`, deletes on
`ResourceSystem`), and all generated wrappers (dbmock, dbmetrics).

No callers yet. A follow-up PR will add the dedicated `boundary_log`
RBAC resource type.

> Generated by Coder Agents
This commit is contained in:
Sas Swart
2026-05-25 11:14:36 +02:00
committed by GitHub
parent eddd4a8c2f
commit 3bf5f80277
16 changed files with 753 additions and 0 deletions
+28
View File
@@ -453,6 +453,34 @@ func ConnectionLog(t testing.TB, db database.Store, seed database.UpsertConnecti
return database.ConnectionLog{} // unreachable
}
func BoundarySession(t testing.TB, db database.Store, seed database.BoundarySession) database.BoundarySession {
session, err := db.InsertBoundarySession(genCtx, database.InsertBoundarySessionParams{
ID: takeFirst(seed.ID, uuid.New()),
WorkspaceAgentID: takeFirst(seed.WorkspaceAgentID, uuid.New()),
ConfinedProcessName: takeFirst(seed.ConfinedProcessName, "claude-code"),
StartedAt: takeFirst(seed.StartedAt, dbtime.Now()),
UpdatedAt: takeFirst(seed.UpdatedAt, dbtime.Now()),
})
require.NoError(t, err, "insert boundary session")
return session
}
func BoundaryLog(t testing.TB, db database.Store, seed database.BoundaryLog) database.BoundaryLog {
log, err := db.InsertBoundaryLog(genCtx, database.InsertBoundaryLogParams{
ID: takeFirst(seed.ID, uuid.New()),
SessionID: seed.SessionID,
SequenceNumber: takeFirst(seed.SequenceNumber, 0),
CapturedAt: takeFirst(seed.CapturedAt, dbtime.Now()),
CreatedAt: takeFirst(seed.CreatedAt, dbtime.Now()),
Proto: takeFirst(seed.Proto, "http"),
Method: takeFirst(seed.Method, "GET"),
Detail: takeFirst(seed.Detail, "https://example.com"),
MatchedRule: seed.MatchedRule,
})
require.NoError(t, err, "insert boundary log")
return log
}
func Template(t testing.TB, db database.Store, seed database.Template) database.Template {
id := takeFirst(seed.ID, uuid.New())
if seed.GroupACL == nil {