Skip to content

feat(agent): opt-in interactive-session launch for visible GUI/browser tests#69

Open
EliorMachlev wants to merge 2 commits into
mainfrom
feat/interactive-session-launch
Open

feat(agent): opt-in interactive-session launch for visible GUI/browser tests#69
EliorMachlev wants to merge 2 commits into
mainfrom
feat/interactive-session-launch

Conversation

@EliorMachlev

Copy link
Copy Markdown
Owner

What

Adds an opt-in Agent:LaunchInInteractiveSession setting that launches the whole agent in the active console session (Session 1) instead of the service's non-interactive Session 0 — so GUI processes it spawns downstream (e.g. a Selenium/NUnit browser) are visible on the logged-in desktop.

"Agent": {
  "LaunchInInteractiveSession": {
    "Enabled": false,        // master switch — off by default
    "LocalSystemOnly": true  // gate the launch on LocalSystem; default on
  }
}

Why it's gated the way it is

This is a deliberate, opt-in isolation downgrade. A Windows service always runs in Session 0; crossing into the interactive session needs WTSQueryUserTokenSeTcbPrivilege, i.e. the service must run as LocalSystem (or an account granted a LocalSystem-equivalent privilege), plus a user logged into the console.

  • LocalSystemOnly: true (default) → attempt only when the service is LocalSystem.
  • LocalSystemOnly: false → also attempt under a non-LocalSystem account granted SeTcbPrivilege (discouraged — that privilege is LocalSystem-equivalent, so it hides risk rather than reducing it).

Every precondition failure (wrong identity, no console session, missing privilege) logs a prominent warning and falls back to a normal Session 0 (headless) launch — the service never fails because of this setting. Because the shipped default identity (NT SERVICE\Jenkins) lacks the privilege, the feature is effectively double opt-in: flipping the flag alone does nothing until the service identity is also reconfigured.

How

  • New InteractiveSessionLauncher does the CreateProcessAsUser launch with stdout/stderr pipe redirection (preserving SEVERE counting + secret redaction) and places the agent tree in a kill-on-close Job Object so stop/restart still reaps the browser/build children. Hardening:SanitizeEnvironment still applies.
  • AgentProcessLauncher dispatches to the interop only when enabled; the default (disabled) path is unchanged.
  • Startup warning in the worker when the flag is on.

Docs / policy

  • docs/configuration.html: settings rows, JSON sample, and an Interactive-session launch section with a top security warning and a prerequisites table for both LocalSystem and non-LocalSystem modes.
  • Security.md: reports stemming from enabling this feature are marked out of scope (a defect where it acts without being enabled, or fails to fall back safely, remains in scope).

Testing

  • dotnet test -c Release -p:RestoreLockedMode=true178/178 pass; config-binding test extended to cover the new nested keys + defaults.
  • ⚠️ The interop is compile-verified only. The CreateProcessAsUser path is not exercisable in CI (no interactive session / privilege), same class as the TPM code path — it needs manual validation on a box with autologon + the service set to LocalSystem.

🤖 Generated with Claude Code

EliorMachlev and others added 2 commits July 20, 2026 17:36
…r tests

Add Agent:LaunchInInteractiveSession (Enabled=false, LocalSystemOnly=true
by default) to launch the whole agent in the active console session
(Session 1) instead of the service's non-interactive Session 0, so GUI
processes it spawns downstream (e.g. a Selenium/NUnit browser) are visible
on the logged-in desktop.

This is a deliberate, opt-in isolation downgrade. Crossing the session
boundary needs WTSQueryUserToken -> SeTcbPrivilege, i.e. the service must
run as LocalSystem (or an account granted a LocalSystem-equivalent
privilege), plus a logged-in console session. Every precondition failure
(wrong identity, no console session, missing privilege) logs a prominent
warning and falls back to a normal Session 0 (headless) launch, so the
service never fails because of this setting. Because the shipped default
identity lacks the privilege, the feature is effectively double opt-in.

The interop (InteractiveSessionLauncher) does the CreateProcessAsUser
launch with stdout/stderr pipe redirection (preserving SEVERE counting and
secret redaction) and places the agent tree in a kill-on-close Job Object
so stop/restart still reaps the browser/build children. Environment
sanitization still applies. The default (disabled) path is unchanged.

Docs: configuration.html gains a settings row pair, a JSON sample, and an
Interactive-session section with a top security warning and a
prerequisites table for both LocalSystem and non-LocalSystem modes.
Security.md marks reports stemming from enabling this feature out of scope.

Interop is compile-verified and covered by config-binding tests only; the
CreateProcessAsUser path is not exercisable in CI (no interactive session /
privilege), same class as the TPM code path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ges, and open items

Note InteractiveSessionLauncher.cs in the Agent-process source layout and the
Agent:LaunchInInteractiveSession key axis, add PR #69 to recent merges, and
flag the CreateProcessAsUser path under "Not yet verified against real infra"
(compile-verified only; needs autologon + LocalSystem, untestable in CI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant