feat: surface agent firewall correlation in AI Bridge sessions API (#26416)

Add `agent_firewall_session_id` and `agent_firewall_sequence_number`
fields to `AIBridgeThread` in the `GET
/api/v2/aibridge/sessions/{session_id}` response. These fields link each
thread to its agent firewall confinement session so the frontend can
discover the boundary session and compute sequence ranges for
interleaving firewall events within the thread timeline.

The database columns already exist on `aibridge_interceptions`
(migration 000520) and are already selected by
`ListAIBridgeSessionThreads`. This PR surfaces them through the SDK type
and the `db2sdk` conversion.

Depends on #24814

**Naming note:** The RFC uses `boundary_session_id` /
`boundary_sequence_number`, but the codebase standardized on
`agent_firewall_*` naming in the DB migration. The API fields follow the
existing convention.

</details>

> [!NOTE]
> This PR was authored by Coder Agents.
This commit is contained in:
Sas Swart
2026-06-22 15:17:37 +02:00
committed by GitHub
parent 335d6bda1b
commit adad5bdd49
8 changed files with 115 additions and 12 deletions
+47
View File
@@ -1457,6 +1457,53 @@ func TestAIBridgeGetSessionThreads(t *testing.T) {
require.Equal(t, "sk-a...efgh", res.Threads[0].CredentialHint)
})
t.Run("ThreadsWithAgentFirewallCorrelation", func(t *testing.T) {
t.Parallel()
client, db, firstUser := coderdenttest.NewWithDatabase(t, aibridgeOpts(t))
ctx := testutil.Context(t, testutil.WaitLong)
now := dbtime.Now()
fwSessionID := uuid.New()
// Thread with firewall correlation on the root interception.
rootEndedAt := now.Add(time.Minute)
root := dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
InitiatorID: firstUser.UserID,
Provider: "anthropic",
Model: "claude-sonnet-4-20250514",
StartedAt: now,
ClientSessionID: sql.NullString{String: "fw-session", Valid: true},
AgentFirewallSessionID: uuid.NullUUID{UUID: fwSessionID, Valid: true},
AgentFirewallSequenceNumber: sql.NullInt32{Int32: 5, Valid: true},
}, &rootEndedAt)
// Thread without firewall correlation in the same session.
noFWEndedAt := now.Add(2 * time.Minute)
dbgen.AIBridgeInterception(t, db, database.InsertAIBridgeInterceptionParams{
InitiatorID: firstUser.UserID,
Provider: "openai",
Model: "gpt-4",
StartedAt: now.Add(time.Minute),
ClientSessionID: sql.NullString{String: "fw-session", Valid: true},
}, &noFWEndedAt)
res, err := client.AIBridgeGetSessionThreads(ctx, "fw-session", uuid.Nil, uuid.Nil, 0)
require.NoError(t, err)
require.Equal(t, "fw-session", res.ID)
require.Len(t, res.Threads, 2)
// First thread has firewall correlation.
require.Equal(t, root.ID, res.Threads[0].ID)
require.NotNil(t, res.Threads[0].AgentFirewallSessionID)
require.Equal(t, fwSessionID, *res.Threads[0].AgentFirewallSessionID)
require.NotNil(t, res.Threads[0].AgentFirewallSequenceNumber)
require.Equal(t, int32(5), *res.Threads[0].AgentFirewallSequenceNumber)
// Second thread has no firewall correlation.
require.Nil(t, res.Threads[1].AgentFirewallSessionID)
require.Nil(t, res.Threads[1].AgentFirewallSequenceNumber)
})
t.Run("ThreadsWithAgenticActions", func(t *testing.T) {
t.Parallel()
client, db, firstUser := coderdenttest.NewWithDatabase(t, aibridgeOpts(t))