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
+90
View File
@@ -1102,6 +1102,21 @@ func (mr *MockStoreMockRecorder) DeleteOldAuditLogs(ctx, arg any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldAuditLogs", reflect.TypeOf((*MockStore)(nil).DeleteOldAuditLogs), ctx, arg)
}
// DeleteOldBoundaryLogs mocks base method.
func (m *MockStore) DeleteOldBoundaryLogs(ctx context.Context, arg database.DeleteOldBoundaryLogsParams) (int64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteOldBoundaryLogs", ctx, arg)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// DeleteOldBoundaryLogs indicates an expected call of DeleteOldBoundaryLogs.
func (mr *MockStoreMockRecorder) DeleteOldBoundaryLogs(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldBoundaryLogs", reflect.TypeOf((*MockStore)(nil).DeleteOldBoundaryLogs), ctx, arg)
}
// DeleteOldChatDebugRuns mocks base method.
func (m *MockStore) DeleteOldChatDebugRuns(ctx context.Context, arg database.DeleteOldChatDebugRunsParams) (int64, error) {
m.ctrl.T.Helper()
@@ -2310,6 +2325,36 @@ func (mr *MockStoreMockRecorder) GetAuthorizedWorkspacesAndAgentsByOwnerID(ctx,
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizedWorkspacesAndAgentsByOwnerID", reflect.TypeOf((*MockStore)(nil).GetAuthorizedWorkspacesAndAgentsByOwnerID), ctx, ownerID, prepared)
}
// GetBoundaryLogByID mocks base method.
func (m *MockStore) GetBoundaryLogByID(ctx context.Context, id uuid.UUID) (database.BoundaryLog, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBoundaryLogByID", ctx, id)
ret0, _ := ret[0].(database.BoundaryLog)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBoundaryLogByID indicates an expected call of GetBoundaryLogByID.
func (mr *MockStoreMockRecorder) GetBoundaryLogByID(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBoundaryLogByID", reflect.TypeOf((*MockStore)(nil).GetBoundaryLogByID), ctx, id)
}
// GetBoundarySessionByID mocks base method.
func (m *MockStore) GetBoundarySessionByID(ctx context.Context, id uuid.UUID) (database.BoundarySession, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBoundarySessionByID", ctx, id)
ret0, _ := ret[0].(database.BoundarySession)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBoundarySessionByID indicates an expected call of GetBoundarySessionByID.
func (mr *MockStoreMockRecorder) GetBoundarySessionByID(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBoundarySessionByID", reflect.TypeOf((*MockStore)(nil).GetBoundarySessionByID), ctx, id)
}
// GetChatACLByID mocks base method.
func (m *MockStore) GetChatACLByID(ctx context.Context, id uuid.UUID) (database.GetChatACLByIDRow, error) {
m.ctrl.T.Helper()
@@ -6989,6 +7034,36 @@ func (mr *MockStoreMockRecorder) InsertAuditLog(ctx, arg any) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertAuditLog", reflect.TypeOf((*MockStore)(nil).InsertAuditLog), ctx, arg)
}
// InsertBoundaryLog mocks base method.
func (m *MockStore) InsertBoundaryLog(ctx context.Context, arg database.InsertBoundaryLogParams) (database.BoundaryLog, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InsertBoundaryLog", ctx, arg)
ret0, _ := ret[0].(database.BoundaryLog)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// InsertBoundaryLog indicates an expected call of InsertBoundaryLog.
func (mr *MockStoreMockRecorder) InsertBoundaryLog(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertBoundaryLog", reflect.TypeOf((*MockStore)(nil).InsertBoundaryLog), ctx, arg)
}
// InsertBoundarySession mocks base method.
func (m *MockStore) InsertBoundarySession(ctx context.Context, arg database.InsertBoundarySessionParams) (database.BoundarySession, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "InsertBoundarySession", ctx, arg)
ret0, _ := ret[0].(database.BoundarySession)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// InsertBoundarySession indicates an expected call of InsertBoundarySession.
func (mr *MockStoreMockRecorder) InsertBoundarySession(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertBoundarySession", reflect.TypeOf((*MockStore)(nil).InsertBoundarySession), ctx, arg)
}
// InsertChat mocks base method.
func (m *MockStore) InsertChat(ctx context.Context, arg database.InsertChatParams) (database.Chat, error) {
m.ctrl.T.Helper()
@@ -8249,6 +8324,21 @@ func (mr *MockStoreMockRecorder) ListAuthorizedAIBridgeSessions(ctx, arg, prepar
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAuthorizedAIBridgeSessions", reflect.TypeOf((*MockStore)(nil).ListAuthorizedAIBridgeSessions), ctx, arg, prepared)
}
// ListBoundaryLogsBySessionID mocks base method.
func (m *MockStore) ListBoundaryLogsBySessionID(ctx context.Context, arg database.ListBoundaryLogsBySessionIDParams) ([]database.BoundaryLog, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListBoundaryLogsBySessionID", ctx, arg)
ret0, _ := ret[0].([]database.BoundaryLog)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ListBoundaryLogsBySessionID indicates an expected call of ListBoundaryLogsBySessionID.
func (mr *MockStoreMockRecorder) ListBoundaryLogsBySessionID(ctx, arg any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBoundaryLogsBySessionID", reflect.TypeOf((*MockStore)(nil).ListBoundaryLogsBySessionID), ctx, arg)
}
// ListChatUsageLimitGroupOverrides mocks base method.
func (m *MockStore) ListChatUsageLimitGroupOverrides(ctx context.Context) ([]database.ListChatUsageLimitGroupOverridesRow, error) {
m.ctrl.T.Helper()