fix(agent-status): validate the emitter claim and scrub its env from one list

Three boundary defects found in review.

`ingestRemote` took `reportedExecutionBinding` straight off the envelope while
re-validating every sibling field, and the WSL relay reaches that function with a
raw wire cast. A malformed value could not mint identity, but it was truthy and
non-matching, which is enough to affect how the report is treated. It is parsed
now, at the boundary that already exists for this purpose.

The daemon kept its own copy of the pane-identity scrub list and did not gain the
two new variables, so a pane that did not request them could inherit them from the
daemon's environment while the local provider correctly scrubbed them. Both spawn
paths now read one shared list, which is what stops the next key from being added
to one and not the other.

Also merges a duplicate import in the new promotion module that the focused
code-quality gate rejects.
This commit is contained in:
Brennan Benson
2026-09-17 11:49:32 -07:00
parent 909a7a2245
commit dec2cfdc78
5 changed files with 23 additions and 17 deletions
@@ -24,6 +24,7 @@ import {
} from '../../../shared/agent-status-legacy-adapter'
import { isValidPiProviderSessionOnly } from './server-status-identity'
import { AgentHookServerIngestStructured } from './server-ingest-structured'
import { parseAgentStatusReportedExecutionBinding } from '../../../shared/agent-status-execution-binding'
export abstract class AgentHookServerIngestRemote extends AgentHookServerIngestStructured {
/** Ingest a payload from the relay JSON-RPC channel (not the local HTTP server); connectionId is stamped here. Main is still the SSH trust boundary, so re-run the canonical normalizer before caching. */
@@ -271,7 +272,10 @@ export abstract class AgentHookServerIngestRemote extends AgentHookServerIngestS
paneKey,
source,
launchToken: statusDisposition === 'restart' ? undefined : envelope.launchToken,
reportedExecutionBinding: envelope.reportedExecutionBinding,
// Parsed here, not trusted: every sibling field on this envelope is re-validated because the
// relay crosses a trust boundary, and the WSL relay reaches this with a raw wire cast.
reportedExecutionBinding:
parseAgentStatusReportedExecutionBinding(envelope.reportedExecutionBinding) ?? undefined,
tabId,
worktreeId,
connectionId: trimmedConnectionId,
@@ -18,13 +18,8 @@ import {
} from '../../../shared/windows-environment-expansion'
import type { TuiAgent } from '../../../shared/tui-agent'
import type { PtySubprocessOptions } from '../pty-subprocess'
import { PANE_IDENTITY_ENV_KEYS } from '../../../shared/pane-identity-env'
const PANE_IDENTITY_ENV_KEYS = [
'ORCA_PANE_KEY',
'ORCA_TAB_ID',
'ORCA_WORKTREE_ID',
'ORCA_AGENT_LAUNCH_TOKEN'
] as const
const WINDOWS_PATH_ENV_KEY_RE = /^path$/i
function composeGuardedDaemonGitConfigEnv(
@@ -4,15 +4,7 @@ import { parseWslPath } from '../wsl'
import { resolvePathEnvKey } from '../pty/windows-environment-path'
import { expandWindowsEnvironmentVariables } from '../../shared/windows-environment-expansion'
import { resolveSafePtyDefaultCwd } from './pty-default-cwd'
const PANE_IDENTITY_ENV_KEYS = [
'ORCA_PANE_KEY',
'ORCA_TAB_ID',
'ORCA_WORKTREE_ID',
'ORCA_AGENT_LAUNCH_TOKEN',
'ORCA_AGENT_STATUS_RUN_ID',
'ORCA_AGENT_STATUS_EXECUTION_ID'
] as const
import { PANE_IDENTITY_ENV_KEYS } from '../../shared/pane-identity-env'
export function getDefaultCwd(): string {
return resolveSafePtyDefaultCwd()
@@ -1,4 +1,3 @@
import type { AgentSessionClaimedSpawnResult } from './agent-session-host-authority'
import type { AgentStatusExecutionBinding } from './agent-status-execution-binding'
import {
agentSessionSurfacesEqual,
@@ -10,6 +9,7 @@ import {
type LiveAgentSessionOwner
} from './claimed-agent-pty-owner-snapshot'
import type {
AgentSessionClaimedSpawnResult,
AgentSessionExecutionClaim,
AgentSessionSurfaceBinding
} from './agent-session-host-authority'
+15
View File
@@ -0,0 +1,15 @@
/**
* Environment variables that name which pane and which launched execution a PTY belongs to.
*
* A pane that did not request these must not inherit them from the spawning process, so every
* spawn path scrubs the same list. It lives here because the local provider and the daemon each
* scrub independently, and a key added to one list and not the other stops being scrubbed at all.
*/
export const PANE_IDENTITY_ENV_KEYS = [
'ORCA_PANE_KEY',
'ORCA_TAB_ID',
'ORCA_WORKTREE_ID',
'ORCA_AGENT_LAUNCH_TOKEN',
'ORCA_AGENT_STATUS_RUN_ID',
'ORCA_AGENT_STATUS_EXECUTION_ID'
] as const