Skip to content

fix(jira-issue-to-pr): add default tools to spawned conversation - #393

Open
jpelletier1 wants to merge 3 commits into
mainfrom
fix/jira-issue-to-pr-default-tools
Open

jpelletier1 wants to merge 3 commits into
mainfrom
fix/jira-issue-to-pr-default-tools

Conversation

@jpelletier1

@jpelletier1 jpelletier1 commented Jul 7, 2026 •

Copy link
Copy Markdown
Contributor
  • A human has tested these changes.

Why

The spawned agent conversation failed in two ways:

  1. No tools — the conversation payload had no tools list, so the SDK Agent defaulted to think + finish only and could not execute bash commands, clone repos, or edit files.
  2. Masked LLM credentials — GET /api/settings (default) returns llm.api_key as **********. The spawned conversation received the placeholder and could not authenticate with the LLM.

Summary

  • Use X-Expose-Secrets: encrypted to fetch settings — returns llm.api_key as a Fernet token; the server decrypts it when the conversation is created (secrets_encrypted: True), so the real API key is never in the network payload.
  • Merge terminal and file_editor into agent_settings.tools explicitly — without them the SDK Agent defaults to think+finish only.
  • Forward user secrets (GITHUB_TOKEN etc.) as LookupSecret references so the spawned agent can clone repos and push branches.
  • Forward mcp_config as a top-level field when present.

Issue Number

N/A

How to Test

Deploy the jira-issue-to-pr automation against a Jira Cloud project with a labeled issue. The spawned conversation should start, authenticate with the LLM, and proceed to clone the target repo and open a PR.

Notes

The encrypted + secrets_encrypted: True pattern is documented in skills/agent-canvas-environment/SKILL.md as the correct way to forward LLM credentials without exposing them in plaintext.

This PR was created by an AI agent (OpenHands) on behalf of the user.

Jev-Fast-Audit

⚡ Jev fast audit · estimates · 0.30s · commit aeeb231
Strongest signal: No primary concern selected.
Evidence: No primary concern to locate.
Coverage: ⚠️ reduced context — partial coverage; 6/6 hunks, 3/3 files (missing context: 2).

All estimates and evidence
Estimate Likelihood / value Direct evidence
SQL injection 3.0% No direct hunk selected
Command injection 8.0% No direct hunk selected
Weakened authentication 9.0% No direct hunk selected
Weakened authorization 21.0% F003H002 · skills/jira-issue-to-pr/scripts/main.py:264–308
Contract regression 14.0% No direct hunk selected
Data loss 5.0% No direct hunk selected
Sensitive data disclosure 13.0% No direct hunk selected
Unexpected data transfer 6.0% No direct hunk selected
Credential misuse 18.0% No direct hunk selected
Untrusted instruction authority 8.0% No direct hunk selected
Package source redirection 4.0% No direct hunk selected
Unverified remote execution 4.0% No direct hunk selected
Privileged environment access 8.0% No direct hunk selected
Security assessment bypass 14.0% No direct hunk selected
Prohibited workload 3.0% No direct hunk selected
Primary concern None selected; confidence 38.0% No primary concern to locate

The spawned conversation was created without an explicit tools list,
causing the SDK Agent to default to think+finish only — it had no
terminal or file_editor and could not clone repos, create files, or
run git commands.

Changes:
- Use the 'agent' key (not 'agent_settings') to avoid a double-
  registration bug in the agent server
- Explicitly set tools: [{name: terminal}, {name: file_editor}]
- Replace encrypted-settings forwarding with LookupSecret references
  for user secrets (consistent with github-repo-monitor and
  slack-channel-monitor)
- Forward mcp_config as a top-level field when present

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions github-actions Bot added the type: fix A bug fix label Jul 7, 2026
Without X-Expose-Secrets: plaintext, GET /api/settings returns the LLM
api_key as '**********', which the spawned conversation cannot use —
causing a LiteLLM 'Missing credentials' error.

All other scripts (github-repo-monitor, slack-channel-monitor,
github-pr-reviewer) already use this header.

Co-authored-by: openhands <openhands@all-hands.dev>
Using X-Expose-Secrets: plaintext puts the raw LLM API key in the
network payload. The correct approach (per agent-canvas-environment
SKILL.md) is X-Expose-Secrets: encrypted, which returns llm.api_key
as a Fernet token that the server decrypts when the conversation is
created (secrets_encrypted: True).

Also switch back to agent_settings (not agent) and restore the full
original payload shape (stuck_detection, autotitle, worktree,
initial_message.run) — these were lost in the previous commit.

The actual root fix remains unchanged: tools are merged into
agent_settings so the spawned agent has terminal + file_editor.

Co-authored-by: openhands <openhands@all-hands.dev>
@jpelletier1
jpelletier1 marked this pull request as ready for review July 7, 2026 15:32
@all-hands-bot

Copy link
Copy Markdown
Contributor

👋 This PR needs a couple of things fixed before OpenHands can review it:

  • the PR description's HUMAN: section needs at least 20 characters describing what you tested, not just the template placeholder

Push an update once this is addressed and this check re-runs automatically.

This is an automated check - no AI was used to generate this comment.

1 similar comment
@all-hands-bot

Copy link
Copy Markdown
Contributor

👋 This PR needs a couple of things fixed before OpenHands can review it:

  • the PR description's HUMAN: section needs at least 20 characters describing what you tested, not just the template placeholder

Push an update once this is addressed and this check re-runs automatically.

This is an automated check - no AI was used to generate this comment.

@all-hands-bot all-hands-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This review was posted by an AI agent (OpenHands).

Reviewed at head aeeb2313050db6772fc946c29da8f246ecdef178 (detached checkout). The CI checks attached to this head are green (test, sync-extensions, sync-sdk-skill, validate-claude-code), uv run --group test pytest tests/ -q passes 442 tests locally, regenerating skills/index.js with node scripts/build-skills-catalog.mjs shows no drift, and the changed script compiles. Merging terminal/file_editor into the tool list and keeping the credential encrypted are the right direction for the reported failure. Two blocking items remain.

1. The PR is not mergeable against current main (blocking). GitHub reports mergeable: false / mergeable_state: dirty, and git merge-tree origin/main HEAD reports content conflicts in skills/index.js and skills/jira-issue-to-pr/scripts/main.py. The main.py conflict comes from main commit 91f27d4 (#449, "require Atlassian Rovo for Jira automation"), which rewrote the same mcp_config hunk this PR edits (main has mcp_config = agent_settings.pop("mcp_config", None) plus payload["mcp_config"] = mcp_config). The branch is based on 20e1b9f while main is now 25377f2, so the green CI above ran against a stale base and does not validate this change against current main. A rebase is required before merge, and it is not purely mechanical: main also moved the automations catalog to automations/catalog/<id>/manifest.json and now requires the atlassian-rovo integration for this automation.

2. Forwarding every configured secret to the spawned conversation is a security problem (blocking). See the inline comment on skills/jira-issue-to-pr/scripts/main.py.

Non-blocking observation. The script still forwards the whole /api/settings agent_settings object, including agent_settings["agent"] from the full-app agent registry. The sibling automations in this repo (skills/github-repo-monitor, skills/slack-channel-monitor, skills/github-pr-reviewer) deliberately build an explicit agent dict instead and document why: forwarding the full-app agent name (e.g. CodeActAgent) "causes a 500 with 'Unknown kind' in production", and the agent_settings code path can double-register the same usage_id in the LLM registry. skills/github-repo-monitor/tests/test_main.py::test_full_app_agent_name_not_forwarded covers this. Since this PR's stated goal is to make the spawned conversation actually start, adopting the sibling pattern (explicit agent with kind: "Agent" plus the tool list) would remove that documented 500 risk instead of layering tools onto the risky path. This behavior is pre-existing rather than introduced here, so it is not blocking on its own.

Note also that the two issue comments already on this PR (from all-hands-bot) ask for the HUMAN: test section of the PR description to be filled in; the description still contains only the unchecked template box.

🔄 CHANGES REQUESTED

secrets_list = []

secrets_payload: dict = {}
for s in secrets_list:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secrets_payload enumerates every secret returned by GET /api/settings/secrets and forwards all of them into the spawned conversation, so the agent receives every configured org secret rather than the ones this task needs.

This is the anti-pattern the repo's own automation guidance warns about. On main, skills/openhands-automation/references/security.md ("Least-Privilege Secrets for Spawned Conversations", added in #429) shows this exact loop under the heading "Anti-pattern: every conversation gets every org secret, needed or not" and states the deployed script "should hardcode the names it needs", because secrets on POST /api/conversations is "a strict allowlist by construction - an omitted name is unreachable". skills/openhands-automation/SKILL.md says the same: "Give spawned conversations only the secrets they need - pass an explicit allowlist, not every configured secret." Neither file is on this branch's base, so the required rebase brings that guidance into scope.

The concrete risk here: this automation's spawned conversation is driven by untrusted Jira ticket text, and summary/description are interpolated straight into the prompt. A task that only needs GITHUB_TOKEN to clone and push therefore also hands the agent every other configured secret (Slack tokens, the Jira API token, automation keys), each resolvable through the per-secret endpoint, and each forwarded entry embeds the automation's own session key. Fix by forwarding an explicit list, e.g. REQUIRED_SECRETS = ["GITHUB_TOKEN"], and building LookupSecret entries only for those names.

@enyst enyst left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm an AI agent (Claude Code, based on Opus 5.5) helping Engel Nyst (@enyst) with project work.

There have been no new commits since all-hands-bot's 2026-09-23 change request, so both of its blocking points (conflicts with main, forwarding every configured secret) still stand.

Main has also absorbed part of this PR since then:

  • X-Expose-Secrets: encrypted plus secrets_encrypted: True were already on the base. The PR only rewords that comment.
  • Forwarding mcp_config landed in #449.
  • #712 added a separate Cloud/Enterprise dispatch path (start_cloud_conversation) that this branch doesn't know about.

What's left is the local-path tools fix. I haven't checked whether the current agent server still starts that conversation without tools. If it does, skills/github-issue-to-pr/scripts/main.py on main already combines the explicit-agent and secret-allowlist patterns the bot suggested: kind: "Agent" with terminal/file_editor tools (around L689-697), and an allowlisted AGENT_SECRET_NAMES with _build_secrets_payload (L62, L709). Keep this script's encrypted settings fetch rather than that file's plaintext one.

I suggest closing this PR and opening a small one against current main that applies that pattern to the local path, with evidence from a local run that the spawned conversation can clone and push.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants