Gateway: keep spawned workspace overrides internal (#43801)

* Gateway: keep spawned workspace overrides internal

* Changelog: note GHSA-2rqg agent boundary fix

* Gateway: persist spawned workspace inheritance in sessions

* Agents: clean failed lineage spawn state

* Tests: cover lineage attachment cleanup

* Tests: cover lineage thread cleanup
This commit is contained in:
Vincent Koc
2026-03-12 04:20:00 -04:00
committed by GitHub
parent 97683071b5
commit 46a332385d
12 changed files with 226 additions and 35 deletions

View File

@@ -190,24 +190,20 @@ export const agentHandlers: GatewayRequestHandlers = {
timeout?: number;
bestEffortDeliver?: boolean;
label?: string;
spawnedBy?: string;
inputProvenance?: InputProvenance;
workspaceDir?: string;
};
const senderIsOwner = resolveSenderIsOwnerFromClient(client);
const cfg = loadConfig();
const idem = request.idempotencyKey;
const normalizedSpawned = normalizeSpawnedRunMetadata({
spawnedBy: request.spawnedBy,
groupId: request.groupId,
groupChannel: request.groupChannel,
groupSpace: request.groupSpace,
workspaceDir: request.workspaceDir,
});
let resolvedGroupId: string | undefined = normalizedSpawned.groupId;
let resolvedGroupChannel: string | undefined = normalizedSpawned.groupChannel;
let resolvedGroupSpace: string | undefined = normalizedSpawned.groupSpace;
let spawnedByValue = normalizedSpawned.spawnedBy;
let spawnedByValue: string | undefined;
const inputProvenance = normalizeInputProvenance(request.inputProvenance);
const cached = context.dedupe.get(`agent:${idem}`);
if (cached) {
@@ -359,11 +355,7 @@ export const agentHandlers: GatewayRequestHandlers = {
const sessionId = entry?.sessionId ?? randomUUID();
const labelValue = request.label?.trim() || entry?.label;
const sessionAgent = resolveAgentIdFromSessionKey(canonicalKey);
spawnedByValue = canonicalizeSpawnedByForAgent(
cfg,
sessionAgent,
spawnedByValue || entry?.spawnedBy,
);
spawnedByValue = canonicalizeSpawnedByForAgent(cfg, sessionAgent, entry?.spawnedBy);
let inheritedGroup:
| { groupId?: string; groupChannel?: string; groupSpace?: string }
| undefined;
@@ -400,6 +392,7 @@ export const agentHandlers: GatewayRequestHandlers = {
providerOverride: entry?.providerOverride,
label: labelValue,
spawnedBy: spawnedByValue,
spawnedWorkspaceDir: entry?.spawnedWorkspaceDir,
spawnDepth: entry?.spawnDepth,
channel: entry?.channel ?? request.channel?.trim(),
groupId: resolvedGroupId ?? entry?.groupId,
@@ -628,7 +621,7 @@ export const agentHandlers: GatewayRequestHandlers = {
// Internal-only: allow workspace override for spawned subagent runs.
workspaceDir: resolveIngressWorkspaceOverrideForSpawnedRun({
spawnedBy: spawnedByValue,
workspaceDir: request.workspaceDir,
workspaceDir: sessionEntry?.spawnedWorkspaceDir,
}),
senderIsOwner,
},