Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The agent-writable artifact controls both the target repository and credential installation, allowing a compromised run to create branches and PRs in other repositories where the App is installed.
2 open issues
What changed in this PR
Adds github.submit_patch, the GitHub equivalent of Hackbot’s Phabricator submission action, addressing #7057. Agents record a submission during a run; hackbot-api later recreates the commits and opens a draft pull request.
Changes:
- Adds the recording tool and GitHub-specific commit artifact generation.
- Registers an apply-side handler that creates commits, manages the run’s branch, and reuses an existing PR on retries.
- Adds runtime and API tests, action documentation, and a UI preview.
| File | Description |
|---|---|
services/hackbot-ui/components/RunDetail.tsx |
Previews the PR title and body. |
services/hackbot-api/tests/test_github_handler.py |
Tests GitHub API calls, retries, and failures. |
services/hackbot-api/app/action_handlers/registry.py |
Registers the handler and patch action type. |
services/hackbot-api/app/action_handlers/github_handler.py |
Recreates commits and opens draft PRs. |
libs/hackbot-runtime/tests/test_github_actions.py |
Tests action recording and tool exposure. |
libs/hackbot-runtime/tests/test_context.py |
Tests artifact publishing and commit naming. |
libs/hackbot-runtime/tests/test_changes.py |
Tests commit serialization and file changes. |
libs/hackbot-runtime/hackbot_runtime/context.py |
Publishes GitHub artifacts for recorded submissions. |
libs/hackbot-runtime/hackbot_runtime/changes.py |
Builds the GitHub commit payload. |
libs/hackbot-runtime/hackbot_runtime/actions/github.py |
Defines the submission recording tool. |
libs/hackbot-runtime/hackbot_runtime/actions/claude_sdk.py |
Exposes the tool through the Claude SDK integration. |
libs/hackbot-runtime/hackbot_runtime/actions/__init__.py |
Exports GitHub actions. |
docs/hackbot/actions.md |
Documents the action and submission flow. |
Review effort: Balanced
The GitHub counterpart of phabricator.submit_patch. The agent records the submission during the run; when it is applied, hackbot-api pushes a branch carrying the run's commits to the source repository and opens a draft pull request against its default branch. hackbot-api has no git checkout to apply the run's patch in, so publish_changes also captures each commit (message, author and changed files) as changes/github_commits.json, from the published base. The handler recreates those commits through GitHub's Git Data API on a hackbot/<run_id> branch, using the GitHub App with a token narrowed to that repository. Retrying reuses the branch and any pull request already open from it. github.submit_patch counts as a patch action in hackbot-api, so a run that leaves changes without one is still reported, and the run page previews the pull request's title and body. Fixes mozilla#7057
Drop the trailing NUL explicitly and pair headers with paths using itertools.batched(strict=True), so output that doesn't hold one path per entry raises instead of being silently mispaired. Handle a commit that changes no files, where diff-tree prints nothing.
…changes The target repository came from the agent-written commits artifact, so a compromised run could open pull requests on any repository the GitHub App is installed on. Each agent now names its one repository in AgentSpec.github_repository. The handler refuses agents without one and artifacts naming any other repository, before minting credentials, and uses the configured name for every call. Also refuse runs that change files under .github/workflows/. Pushing them would need workflows: write, and since the branch lives in the repository itself, the pull request's workflows would run with its secrets.
OrlaM
force-pushed
the
ao/bugbug-6/github-submit-patch
branch
from
November 13, 2026 16:47
d1a6807 to
f2d7761
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Fixes #7057.
Adds
github.submit_patch, the GitHub equivalent ofphabricator.submit_patch. The agent records the action during the run. When it is applied, hackbot-api pushes the run's commits to ahackbot/<run_id>branch of the agent's configured GitHub repository and opens a draft PR against its default branch. The PR'surlgoes in the action result, so later actions can reference it.How it works
hackbot-api has no checkout or git binary, so it can't
git push. This follows the Phabricator diff and the try push: the git work happens in the agent's container, and hackbot-api only calls the service's API.publish_changeswriteschanges/github_commits.jsonwhen agithub.submit_patchis recorded, next to the existing changes artifacts.build_github_commitsinchanges.pybuilds it from the commits since the published base. It includes uncommitted work, through the same WIP commit the other artifacts use, and records for each commit its message, author and changed files.github_handler.SubmitPatchHandlerreplays those commits through GitHub's Git Data API (blobs, trees, commits, then a branch ref) and opens the draft PR. Commits keep their original author, and the GitHub App commits and signs them. The installation token is narrowed to the one repository, withcontents: writeandpull_requests: write.AgentSpec.github_repository(owner/repo). The handler refuses an agent without one, and an artifact whoserepo_urlnames any other repository, before minting credentials. Every API call uses the configured name..github/workflows/is refused before minting credentials. The branch lives in the repository itself, not a fork, so the PR's workflows would run with that repository's secrets.github.submit_patchis added to hackbot-api'sPATCH_ACTION_TYPES, so a run that leaves changes without submitting them is still flagged. The runtime gets its own GitHubPATCH_ACTION_TYPES, kept separate from the Phabricator one so that a GitHub submission doesn't also build a Phabricator diff.docs/hackbot/actions.md, and a pull request preview (title and body) on the run page.Tests
hackbot-api:
pytest tests/passes (533). The newtest_github_handler.pydrives githubkit against a fake api.github.com built onhttpx.MockTransport. It covers:github_repository, an artifact naming another repository, and a case-only difference in the name;The refusal tests also check that no GitHub request is made.
hackbot-runtime:
pytest tests/passes (357). It covers the tool,build_github_commitsagainst real git repos (multiple commits, uncommitted work, deletions, file modes, binaries, renames, paths with spaces, a commit that changes no files, no changes) andpublish_changesgating.pre-commit passes on the changed files.
This hasn't been run against a real GitHub repository yet.
Risks and follow-ups
github_repositoryyet, so the action is refused for every agent until one is configured.bug-fixwould also need prompt changes before using it.github_repositoryrepeats the repository in the agent's[source].repo_url. If the two drift apart, submissions fail with a mismatch error.