Skip to content

feat(agent-server): scope script commands with agent profiles - #5046

Draft
neubig wants to merge 1 commit into
factory/profile-secret-boundaryfrom
feat/profile-scoped-script-commands
Draft

neubig wants to merge 1 commit into
factory/profile-secret-boundaryfrom
feat/profile-scoped-script-commands

Conversation

@neubig

@neubig neubig commented Sep 14, 2026

Copy link
Copy Markdown
Member

HUMAN:


AGENT:

Why

A deterministic automation script may need a narrowly scoped saved credential without needing an agent or conversation. Agent profiles currently apply their secret_refs only while launching conversations, so a scanner would otherwise create an empty conversation and potentially a Docker runtime merely to read its GitHub token.

This change keeps credential policy independent from execution: the script sends a profile ID with its Bash request, while a separate Automation operation decides when actual agent work needs a conversation.

Summary

  • Add optional agent_profile_id to Bash command requests and the Python/TypeScript workspace clients.
  • Resolve only the profile's selected saved secrets and reuse the existing Bash environment injection and streaming output masking.
  • Reject unknown profiles, missing selected secrets, and attempts to replace an existing conversation-scoped registry.

Issue Number

Closes #5044.

How to Test

uv run pytest -q tests/agent_server/test_profile_scoped_bash.py tests/agent_server/test_bash_service.py tests/sdk/workspace/remote/test_remote_workspace_mixin.py tests/sdk/workspace/remote/test_remote_workspace.py tests/sdk/workspace/remote/test_async_remote_workspace.py

Result: 135 passed. uv run pre-commit run --files ... passed for every changed source and test file. make test-server-schema passed with the existing 99 weak-schema allowlist entries; the allowlist was not changed. TypeScript npm run lint completed with the repository's existing warnings and npm run build passed.

The tests execute a real subprocess with selected and unselected synthetic secrets, assert that an empty command scope cannot inherit service secrets, and verify masked stdout/stderr persistence. Live Agent Canvas evidence will be added after the Automation caller is integrated; this PR does not yet claim an end-to-end Canvas demonstration.

Video/Screenshots

Pending the integrated Automation demonstration.

Design Doc

The issue and this description contain the complete narrow design; no separate design artifact is needed.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

Native stack order: #5017 → this PR → #3403. #5017 establishes profile secret selection; this PR makes that selection usable by a non-conversation command; #3403 is the optional final Docker runtime layer for agent conversations. The checked-in generated TypeScript transport schema remains pinned to the released Agent Server by repository policy; the handwritten browser client request type is updated here, while release automation regenerates the transport schema from the canonical Python OpenAPI artifact.

@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-agent-server/openhands/agent_server
   bash_router.py661282%89–92, 102–103, 164–165, 168–169, 174–175
   bash_service.py2623089%94–96, 198, 200, 233, 236–238, 250–253, 266, 368, 373–374, 399–404, 472–473, 509–510, 514, 547–548
   profile_secrets.py31390%32, 46–47
openhands-sdk/openhands/sdk/workspace/remote
   async_remote_workspace.py81594%36–38, 49–50
   base.py3044087%85–86, 128–132, 299–309, 313, 396, 447, 556, 605, 607–609, 665–666, 674, 755–760, 798, 843–845, 866
   remote_workspace_mixin.py169299%103, 161
TOTAL43403797482% 

Co-authored-by: openhands <openhands@all-hands.dev>
@neubig
neubig force-pushed the feat/profile-scoped-script-commands branch from 05c3bc2 to 91a259d Compare September 15, 2026 01:12
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.

2 participants