mirror of
https://github.com/coder/coder.git
synced 2026-06-03 04:58:23 +00:00
a586b7e5e0
RFC: [Bridge ↔ Boundaries Correlation RFC](https://www.notion.so/coderhq/Gateway-and-Firewall-Correlation-RFC-31ad579be592803aa8b3d48348ccdde9) Register a dedicated `boundary_log` RBAC resource type with `create`, `read`, and `delete` actions, replacing the placeholder `rbac.ResourceAuditLog` and `rbac.ResourceSystem` references previously used in the dbauthz layer. Create is granted at user-level so workspace agents can only write logs owned by their workspace owner, preventing cross-workspace log fabrication. Delete is restricted to `DBPurge` only; no human role (including owner) can delete boundary logs. | Subject | Create (own) | Create (other) | Read (all) | Delete | |---|---|---|---|---| | Workspace agent | yes | no | no | no | | Owner (site admin) | yes (via member) | no | yes | no | | Auditor | no | no | yes | no | | DBPurge | no | no | no | yes | ### Changes - **RBAC policy & resource definition**: add `boundary_log` to `policy.go` and generate `ResourceBoundaryLog` object, scope constants, and codersdk/TypeScript types. - **dbauthz authorization**: replace all `ResourceAuditLog`/`ResourceSystem` placeholders with `ResourceBoundaryLog`. `InsertBoundaryLog` and `InsertBoundarySession` derive the workspace owner from the agent and authorize with `.WithOwner()` for user-scoped create. - **Role assignments:** - **Owner (site):** read only. Excluded from `allPermsExcept` wildcard; create is inherited from member at user-level. - **Member (user-level):** create. User-scoped so agents can only write logs they own. - **Auditor (site):** read. - `boundary_log` is excluded from org-admin, org-member, and org-service-account `allPermsExcept` calls for consistency with `ResourceBoundaryUsage`. - **System subjects:** - **DB Purge** (`SubjectTypeDBPurge`): delete. The only subject that can remove boundary logs. - **Workspace agent scope**: `ResourceBoundaryLog` with wildcard ID in the agent scope allow-list (necessary for creation since no pre-existing ID exists). User-level role scoping prevents deployment-wide access. - **DB migration** (`000510_boundary_log_scopes`): add `boundary_log:*`, `boundary_log:create`, `boundary_log:delete`, `boundary_log:read` enum values to `api_key_scope`. - **Test coverage**: `BoundaryLogCreate` (user-scoped, only matching owner succeeds), `BoundaryLogDelete` (all human roles denied), `BoundaryLogRead` (owner + auditor). dbauthz mock tests set up workspace agent lookups for owner derivation. - **Generated docs**: update OpenAPI specs, API reference docs, and frontend type definitions. --------- Co-authored-by: Muhammad Danish <mdanishkhdev@gmail.com> Co-authored-by: Coder Agents <coder-agents-review[bot]@users.noreply.github.com>
80 lines
2.0 KiB
SQL
80 lines
2.0 KiB
SQL
-- name: InsertBoundarySession :one
|
|
INSERT INTO boundary_sessions (
|
|
id,
|
|
workspace_agent_id,
|
|
owner_id,
|
|
confined_process_name,
|
|
started_at,
|
|
updated_at
|
|
) VALUES (
|
|
@id,
|
|
@workspace_agent_id,
|
|
@owner_id,
|
|
@confined_process_name,
|
|
@started_at,
|
|
@updated_at
|
|
) RETURNING *;
|
|
|
|
-- name: GetBoundarySessionByID :one
|
|
SELECT * FROM boundary_sessions WHERE id = @id;
|
|
|
|
-- name: InsertBoundaryLogs :many
|
|
INSERT INTO boundary_logs (
|
|
id,
|
|
session_id,
|
|
sequence_number,
|
|
captured_at,
|
|
created_at,
|
|
proto,
|
|
method,
|
|
detail,
|
|
matched_rule
|
|
)
|
|
SELECT
|
|
unnest(@id :: uuid[]),
|
|
@session_id :: uuid,
|
|
unnest(@sequence_number :: int[]),
|
|
unnest(@captured_at :: timestamptz[]),
|
|
unnest(@created_at :: timestamptz[]),
|
|
unnest(@proto :: text[]),
|
|
unnest(@method :: text[]),
|
|
unnest(@detail :: text[]),
|
|
unnest(@matched_rule :: text[])
|
|
RETURNING *;
|
|
|
|
-- name: GetBoundaryLogByID :one
|
|
SELECT * FROM boundary_logs WHERE id = @id;
|
|
|
|
-- name: ListBoundaryLogsBySessionID :many
|
|
-- Lists boundary logs for a session, sorted by sequence number ascending.
|
|
-- Supports optional exclusive sequence number bounds (seq_after, seq_before)
|
|
-- for fetching events between two known interceptions.
|
|
SELECT *
|
|
FROM boundary_logs
|
|
WHERE
|
|
session_id = @session_id
|
|
AND CASE
|
|
WHEN sqlc.narg('seq_after')::int IS NOT NULL THEN sequence_number > sqlc.narg('seq_after')
|
|
ELSE true
|
|
END
|
|
AND CASE
|
|
WHEN sqlc.narg('seq_before')::int IS NOT NULL THEN sequence_number < sqlc.narg('seq_before')
|
|
ELSE true
|
|
END
|
|
ORDER BY sequence_number ASC
|
|
LIMIT COALESCE(NULLIF(@limit_opt::int, 0), 100);
|
|
|
|
-- name: DeleteOldBoundaryLogs :execrows
|
|
-- Deletes boundary logs older than the given time, bounded by a row limit
|
|
-- to avoid long-running transactions.
|
|
WITH old_logs AS (
|
|
SELECT id
|
|
FROM boundary_logs
|
|
WHERE captured_at < @before_time::timestamptz
|
|
ORDER BY captured_at ASC
|
|
LIMIT @limit_count
|
|
)
|
|
DELETE FROM boundary_logs
|
|
USING old_logs
|
|
WHERE boundary_logs.id = old_logs.id;
|