From 6d8e6d4830cee51bf731fa0d5d444be332d2cb59 Mon Sep 17 00:00:00 2001 From: Zach <3724288+zedkipp@users.noreply.github.com> Date: Thu, 22 Jan 2026 08:37:16 -0700 Subject: [PATCH] feat: include template ID in re-emitted boundary logs (#21618) Boundary policies are currently defined at the template level, so including the template ID in re-emitted logs by the control plane allows policy creators to filter and observe boundary activity for specific templates. This makes it easier to verify that policies are working as expected and to debug issues with specific template configurations. --- agent/boundary_logs_test.go | 4 ++++ coderd/agentapi/api.go | 1 + coderd/agentapi/boundary_logs.go | 2 ++ docs/ai-coder/boundary/agent-boundary.md | 1 + 4 files changed, 8 insertions(+) diff --git a/agent/boundary_logs_test.go b/agent/boundary_logs_test.go index bb6ee3d166..0cc8a7264f 100644 --- a/agent/boundary_logs_test.go +++ b/agent/boundary_logs_test.go @@ -78,9 +78,11 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) { sink := &logSink{} logger := slog.Make(sink) workspaceID := uuid.New() + templateID := uuid.New() reporter := &agentapi.BoundaryLogsAPI{ Log: logger, WorkspaceID: workspaceID, + TemplateID: templateID, } ctx, cancel := context.WithCancel(context.Background()) @@ -123,6 +125,7 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) { require.Equal(t, "boundary_request", entry.Message) require.Equal(t, "allow", getField(entry.Fields, "decision")) require.Equal(t, workspaceID.String(), getField(entry.Fields, "workspace_id")) + require.Equal(t, templateID.String(), getField(entry.Fields, "template_id")) require.Equal(t, "GET", getField(entry.Fields, "http_method")) require.Equal(t, "https://example.com/allowed", getField(entry.Fields, "http_url")) require.Equal(t, "*.example.com", getField(entry.Fields, "matched_rule")) @@ -155,6 +158,7 @@ func TestBoundaryLogs_EndToEnd(t *testing.T) { require.Equal(t, "boundary_request", entry.Message) require.Equal(t, "deny", getField(entry.Fields, "decision")) require.Equal(t, workspaceID.String(), getField(entry.Fields, "workspace_id")) + require.Equal(t, templateID.String(), getField(entry.Fields, "template_id")) require.Equal(t, "POST", getField(entry.Fields, "http_method")) require.Equal(t, "https://blocked.com/denied", getField(entry.Fields, "http_url")) require.Equal(t, nil, getField(entry.Fields, "matched_rule")) diff --git a/coderd/agentapi/api.go b/coderd/agentapi/api.go index 57c2a24b62..79dafa8d83 100644 --- a/coderd/agentapi/api.go +++ b/coderd/agentapi/api.go @@ -223,6 +223,7 @@ func New(opts Options, workspace database.Workspace) *API { api.BoundaryLogsAPI = &BoundaryLogsAPI{ Log: opts.Log, WorkspaceID: opts.WorkspaceID, + TemplateID: workspace.TemplateID, } // Start background cache refresh loop to handle workspace changes diff --git a/coderd/agentapi/boundary_logs.go b/coderd/agentapi/boundary_logs.go index cea5a900cb..5285c94086 100644 --- a/coderd/agentapi/boundary_logs.go +++ b/coderd/agentapi/boundary_logs.go @@ -13,6 +13,7 @@ import ( type BoundaryLogsAPI struct { Log slog.Logger WorkspaceID uuid.UUID + TemplateID uuid.UUID } func (a *BoundaryLogsAPI) ReportBoundaryLogs(ctx context.Context, req *agentproto.ReportBoundaryLogsRequest) (*agentproto.ReportBoundaryLogsResponse, error) { @@ -33,6 +34,7 @@ func (a *BoundaryLogsAPI) ReportBoundaryLogs(ctx context.Context, req *agentprot fields := []slog.Field{ slog.F("decision", allowBoolToString(l.Allowed)), slog.F("workspace_id", a.WorkspaceID.String()), + slog.F("template_id", a.TemplateID.String()), slog.F("http_method", r.HttpRequest.Method), slog.F("http_url", r.HttpRequest.Url), slog.F("event_time", logTime.Format(time.RFC3339Nano)), diff --git a/docs/ai-coder/boundary/agent-boundary.md b/docs/ai-coder/boundary/agent-boundary.md index 9deb5df229..0be17cbc6b 100644 --- a/docs/ai-coder/boundary/agent-boundary.md +++ b/docs/ai-coder/boundary/agent-boundary.md @@ -133,6 +133,7 @@ Each boundary audit log entry includes: | `workspace_id` | The UUID of the workspace where the request originated | | `workspace_name` | The name of the workspace where the request originated | | `owner` | The owner of the workspace where the request originated | +| `template_id` | The UUID of the template that the workspace was created from | | `http_method` | The HTTP method used (GET, POST, PUT, DELETE, etc.) | | `http_url` | The fully qualified URL that was requested | | `event_time` | Timestamp when boundary processed the request (RFC3339 format) |