* fix(terminal): expose executor-profile env vars to terminal shells
PR #1971 got the profile env into the agent subprocess and the repository
setup script, but the terminal panel was still a gap: the local user shell
was started with `InteractiveStartRequest.Env` unset, so it inherited only
the backend process environment, and agentctl's per-terminal shells were
started from `shell.DefaultConfig` with no env overrides at all.
Local/worktree path: resolve the task environment's executor profile at
terminal start (revealing secret-backed entries) and pass it through
UserShellOptions.Env into the deferred PTY start. Resolution happens per
terminal rather than being cached at launch, so a terminal opened before
the agent ever runs still gets the vars.
Remote path (Docker/Sprites/SSH): StartTerminalShell now folds the agent
instance's env into the shell config, so a terminal inside the workspace
sees what the agent sees. SSH is unchanged in scope — its instance env is
still only the credential allowlist, not arbitrary profile variables.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(terminal): resolve terminal env from the session's executor profile
Address PR review. The resolver read executor_profile_id off the
task_environments row, but persistTaskEnvironment's reuse branch never
refreshes that column — it keeps whatever the first session stamped on it.
buildLaunchAgentRequest resolves the agent's env from
session.ExecutorProfileID instead, so a task environment reused by a later
session that picked a different profile of the same executor type would give
the terminal stale secrets and omit the ones the agent just received.
Prefer the session's profile and fall back to the environment row only when
the session recorded none. Also document why mergeAgentEnvIntoShellConfig
needs no defensive copy and why StartEnvForTesting is exported.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(terminal): give env-row fallback subtests distinct session IDs
Address PR review nit: both subtests shared the hardcoded "session-3" at
the call site, so the error-path case read as a repeat of the first.
Move the session ID into the table as session-no-profile / session-error.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Delete unreachable/unused backend symbols confirmed by staticcheck U1000
and golang.org/x/tools/deadcode, plus deprecated back-compat aliases kept
alive only by their own tests.
Removed (unused):
- parseGitHubRepoURL, syncTaskStateForBulkWorkflowMove (task/service)
- resolvePrimaryRepoInfo (orchestrator/executor)
- resolveWorkflowAgentProfile, workflowDefaultAgentProfile wrappers (mcp/handlers)
- cleanupExitedContainer (runtime/lifecycle) + orphaned fmt import
- VscodeManager.setEnv (agentctl/server/process)
- repoRootDir const (cmd/preview)
Removed (deprecated shims):
- Canceller.CancelSessionAndNotify alias -> callers use DetachSessionAndNotify
- ScriptPlaceholder type alias (live scriptPlaceholders var kept)
- Placeholder{QueueRun,ClearDecisions,QueueRunForEachParticipant}Callback
no-op structs and their self-referential test
No behavior change; build, vet, and affected-package tests pass.
Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: harden agentctl bind, git clone args, and powershell sound escaping
Three LOW-severity defense-in-depth hardening fixes with PoC + regression tests:
- notifications: escapePowerShell now neutralizes backtick and `$` in addition
to `"`, defusing `$(...)` sub-expression and `$var` injection through an
operator-supplied SoundFile path interpolated into the powershell `-c` script.
- office/skills: git clone for git-sourced skills now passes a `--`
end-of-options separator before the source locator (matching configloader),
so a `-`-prefixed locator can never be parsed as a git flag.
- agentctl: new Config.ListenHost() binds the control server and per-instance
listeners to loopback only when no AuthToken is configured (auth disabled),
so the unauthenticated command/shell/process routes are never reachable
beyond localhost. The normal nonce-handshake flow (incl. Docker) always has
a token and keeps binding all interfaces.
* test: make PoC tests flip and drop indexOf coupling
Address review feedback on the security-hardening PoCs:
- system_provider PoC now demonstrates the PowerShell sub-expression injection
against a legacyEscapePowerShell copy of the unfixed function and asserts the
current escaper defuses it, so the PoC genuinely flips instead of passing
trivially against fixed code (a substring match on `$(` matched the escaped
form too).
- materialization PoC + regression test use stdlib slices.Index instead of a
custom indexOf defined in the PoC file, removing the coupling where deleting
the PoC file would break the regression test.
---------
Co-authored-by: Kandev Agent <agent@kandev.dev>