feat: GET /api/v2/agent-firewall/sessions/{id} (#24814)

Add a GET endpoint at `/api/v2/agent-firewall/sessions/{id}` that
returns agent firewall session metadata (`id`, `workspace_id`,
`owner_id`, `confined_process`, `started_at`). The handler authorizes
against the `boundary_log` resource with `ActionRead` via dbauthz.

The endpoint is enterprise-only, gated behind the `FeatureBoundary`
entitlement.

The `GetBoundarySessionByID` SQL query JOINs through `workspace_agents`
→ `workspace_resources` → `workspace_builds` → `workspaces` to return
`workspace_id` and `workspace_owner_id` directly, avoiding a separate
query.

Also adds an `owner_id` column to the `boundary_logs` table (migration
000526) with a FK to `users(id)` and a backfill from
`boundary_sessions`. This enables user-scoped RBAC authorization for
`InsertBoundaryLogs` via `.WithOwner()`, ensuring workspace agents can
only insert logs for their own owner.

Depends on #24810

**RBAC behaviour:**

| Role    | Result |
|---------|--------|
| Owner   | read   |
| Auditor | read   |
| Member  | 404    |

> [!NOTE]
> This PR was authored by Coder Agents.
This commit is contained in:
Sas Swart
2026-06-18 20:50:17 +02:00
committed by GitHub
parent 20ed45cac7
commit 491a75294e
24 changed files with 649 additions and 20 deletions
+34
View File
@@ -0,0 +1,34 @@
package codersdk
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/google/uuid"
)
// AgentFirewallSession represents a firewall session for a workspace agent.
type AgentFirewallSession struct {
ID uuid.UUID `json:"id" format:"uuid"`
WorkspaceID uuid.UUID `json:"workspace_id" format:"uuid"`
OwnerID uuid.UUID `json:"owner_id" format:"uuid"`
ConfinedProcess string `json:"confined_process"`
StartedAt time.Time `json:"started_at" format:"date-time"`
}
// AgentFirewallSessionByID returns an agent firewall session by its ID.
func (c *Client) AgentFirewallSessionByID(ctx context.Context, id uuid.UUID) (AgentFirewallSession, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/agent-firewall/sessions/%s", id), nil)
if err != nil {
return AgentFirewallSession{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return AgentFirewallSession{}, ReadBodyAsError(res)
}
var session AgentFirewallSession
return session, json.NewDecoder(res.Body).Decode(&session)
}