Skip to content

feat: publish remote result branches - #149

Merged
delete-cloud merged 4 commits into
mainfrom
feat/remote-result-branch-publish
May 13, 2026
Merged

delete-cloud merged 4 commits into
mainfrom
feat/remote-result-branch-publish

Conversation

@delete-cloud

@delete-cloud delete-cloud commented May 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • implement branch mode for POST /sessions/{session_id}/publish on Git-backed workspaces
  • add Docker provider Git commit/push publication with author config, optional git_token_env, pushed ref metadata, and redacted remote URLs
  • add CLI remote publish --branch and update production docs for result-first/archive fallback semantics

Validation

  • uv run pytest tests/ui/test_http_server.py tests/ui/test_http_server_workspace_transfer.py tests/cli/test_remote_client.py tests/coding_agent/environment/ -k "git_workspace or session_result or workspace_diff or workspace_patch or publish or remote_run" -q
  • uv run basedpyright --level error src/coding_agent/ui/schemas.py src/coding_agent/ui/http_server.py src/coding_agent/remote/client.py src/coding_agent/main.py src/coding_agent/environment/workspace_provider.py src/coding_agent/environment/init.py src/coding_agent/environment/docker_workspace_provider.py tests/ui/test_http_server.py tests/cli/test_remote_client.py tests/coding_agent/environment/test_docker_workspace_provider.py
  • uv run ruff format --check src/coding_agent/ui/schemas.py src/coding_agent/ui/http_server.py src/coding_agent/remote/client.py src/coding_agent/main.py src/coding_agent/environment/workspace_provider.py src/coding_agent/environment/init.py src/coding_agent/environment/docker_workspace_provider.py tests/ui/test_http_server.py tests/ui/test_http_server_workspace_transfer.py tests/cli/test_remote_client.py tests/coding_agent/environment/test_docker_workspace_provider.py
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added a CLI command to publish a remote session as a Git branch and report branch, pushed ref, commit SHA, and remote URL.
  • Documentation

    • Expanded production remote-workspace docs: publish/run/download semantics, archive round-trip, examples (diff/patch/publish), token injection notes, and tightened production checklist.
  • API

    • Publish responses now include an optional pushed_ref field and clearer error semantics for unsupported modes.
  • Tests

    • Added CLI, HTTP endpoint, and workspace Git-publish validation and error-case tests.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 13, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 97e65de1-2b9f-4d0c-aed3-7b7d004e5ee8

📥 Commits

Reviewing files that changed from the base of the PR and between c0ae012 and 11b30e4.

📒 Files selected for processing (1)
  • coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py

📝 Walkthrough

Walkthrough

Adds branch-publishing support: WorkspaceBranchPublication contract, provider API and Docker implementation with credential injection, HTTP publish endpoint, client/CLI publish wiring, tests, and production docs describing publish semantics and required config.

Changes

Remote Branch Publication Feature

Layer / File(s) Summary
Branch Publication Contract & Types
src/coding_agent/environment/workspace_provider.py, src/coding_agent/environment/__init__.py, src/coding_agent/ui/schemas.py
WorkspaceBranchPublication dataclass models publication results; WorkspaceProvider gains publish_workspace_branch(...) and publish_workspace_branch_from_config; PublishSessionResponse adds optional pushed_ref.
Docker Workspace Provider Git Branch Publishing
src/coding_agent/environment/docker_workspace_provider.py
Docker provider implements publish_workspace_branch: validates enabled config, checks workspace state, enforces git ref format, sets author identity, stages/commits changes, discovers remote.origin.url, builds HTTP auth from git_token_env, pushes HEAD to refs/heads/<branch>, redacts credentials from returned URL, and returns publication metadata.
HTTP Server Publication Endpoint
src/coding_agent/ui/http_server.py
Server loads remote_publication config, rejects mode="pr" with 501, derives branch/commit defaults, calls publish_workspace_branch_from_config, and returns PublishSessionResponse including branch, pushed_ref, commit_sha, and remote_url; validates publication enabled.
Remote Client & CLI Command
src/coding_agent/remote/client.py, src/coding_agent/__main__.py
Adds publish_remote_branch client helper and extends _post_remote_json to accept optional JSON; adds remote publish CLI subcommand that prints branch, optional pushed ref, commit SHA, and remote URL.
Tests: Provider & HTTP Server
tests/coding_agent/environment/*, tests/ui/test_http_server.py, tests/cli/test_remote_client.py
Adds Docker provider tests for successful publish and unsafe-remote/allowlist rejection; adds HTTP server publish tests covering success and failure modes (PR 501, missing/disabled config 400, auth/ownership 404); adds CLI test asserting POST payload, auth header, and output.
Production Documentation & Examples
docs/remote-sandbox-production.md, docs/adr/0024-remote-result-publication.md
Documents [remote_publication] config (enablement, git author identity, git_token_env, allowed_git_hosts), updates remote run --repo semantics, documents remote publish and --download semantics, adds remote diff/remote patch/remote publish examples, and updates the production smoke checklist.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as publish_workspace_branch
  participant Impl as _publish_git_workspace_branch
  participant Git as git CLI
  participant Env as _git_publication_push_env
  participant Redact as _redact_git_remote_url
  Caller->>Impl: request(branch_name, commit_message, config)
  Impl->>Git: git status, check-ref-format, config user, add, commit
  Impl->>Git: git rev-parse HEAD, git config --get remote.origin.url
  Env->>Git: provide http.extraheader via extra_env during git push
  Impl->>Git: git push origin HEAD:refs/heads/<branch>
  Git-->>Impl: push result (success)
  Impl->>Redact: redact credentials from remote URL
  Impl-->>Caller: WorkspaceBranchPublication(pushed_ref, commit_sha, redacted_url)
Loading
sequenceDiagram
  participant Client as HTTP Client
  participant Server as /publish Endpoint
  participant Config as Config Loader
  participant Provider as WorkspaceProvider
  participant Response as PublishSessionResponse
  Client->>Server: POST mode=branch, branch_name
  Server->>Config: load cloud workspace config
  Server->>Config: load remote_publication config
  alt config disabled
    Server-->>Client: 400 publication not enabled
  else mode is pr
    Server-->>Client: 501 PR publication not implemented
  else branch mode enabled
    Server->>Provider: publish_workspace_branch_from_config
    Provider-->>Server: WorkspaceBranchPublication
    Server->>Response: populate branch_name, pushed_ref, commit_sha, remote_url
    Server-->>Client: 200 response
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped a branch from remote to tree,

Committed the bits that the server gave me,
Token tucked safe in the push-time bath,
Redacted the URL, cleaned up the path,
Tiny green commit — hooray, branch free!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: publish remote result branches' clearly and directly summarizes the main feature addition: implementing branch publication for remote session results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/remote-result-branch-publish

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
coding-agent/docs/remote-sandbox-production.md (1)

153-159: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add Git token env var to the systemd production example.

With remote_publication.enabled = true in the sample config (Line 82) and git_token_env = "CODING_AGENT_GIT_TOKEN" (Line 85), the service example should also show Environment=CODING_AGENT_GIT_TOKEN=...; otherwise remote publish --branch may fail in production setups that copy this config/snippet pair.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@coding-agent/docs/remote-sandbox-production.md` around lines 153 - 159, The
systemd [Service] example is missing the Git token env var used by remote
publication; update the unit to include
Environment=CODING_AGENT_GIT_TOKEN=replace-with-secret alongside
Environment=CODING_AGENT_BEARER_TOKEN=..., so when remote_publication.enabled is
true and git_token_env = "CODING_AGENT_GIT_TOKEN" the process started by
ExecStart (/usr/local/bin/coding-agent serve --config
/etc/coding-agent/config.toml) has the expected CODING_AGENT_GIT_TOKEN available
for remote publish operations.
🧹 Nitpick comments (1)
coding-agent/tests/ui/test_http_server.py (1)

3651-3653: 💤 Low value

Consider explicit mock call verification.

The test relies on assertions inside fake_publish to validate parameters, but doesn't verify the function is actually called. While the current approach works, explicitly verifying the call count provides stronger guarantees against implementation changes.

♻️ Example with unittest.mock
from unittest.mock import MagicMock

# In test setup:
mock_publish = MagicMock(side_effect=fake_publish)
monkeypatch.setattr(
    "coding_agent.ui.http_server.publish_workspace_branch_from_config",
    mock_publish,
)

# After the request:
mock_publish.assert_called_once_with(
    {"provider": "docker"},
    {
        "enabled": True,
        "git_author_name": "coding-agent",
        "git_author_email": "coding-agent@example.com",
    },
    "ws-publish",
    "coding-agent/result",
    f"Apply coding-agent remote session {session_id} changes",
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@coding-agent/tests/ui/test_http_server.py` around lines 3651 - 3653, The test
should explicitly verify the mock was called: replace the patched target for
publish_workspace_branch_from_config with a MagicMock (or similar) that wraps
fake_publish (e.g., MagicMock(side_effect=fake_publish)), keep
monkeypatch.setattr on
"coding_agent.ui.http_server.publish_workspace_branch_from_config", then after
exercising the HTTP request call mock.assert_called_once_with(...) using the
same expected args currently validated inside fake_publish (provider config,
publish config dict, "ws-publish", "coding-agent/result", and the formatted
commit message including session_id) to ensure the function was actually invoked
exactly once.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@coding-agent/src/coding_agent/environment/docker_workspace_provider.py`:
- Around line 1215-1231: Validate the git remote URL before using it for pushes
or before calling _git_publication_push_env to inject auth: parse remote_url
(from _run_git_publish_command) and ensure its scheme and host are in an
allowlist of trusted values (e.g., https/git+https and specific hosts),
otherwise raise ValueError and refuse to inject Authorization headers or perform
the push; apply the same validation logic where remote_url is used later (the
other block around lines 1264-1280) so both code paths (functions/variables:
remote_url, _run_git_publish_command, _git_publication_push_env,
publication_config, provider_config, workspace_root, branch_name) enforce the
allowlist before constructing push_env or executing git push.

In `@coding-agent/tests/ui/test_http_server.py`:
- Around line 3614-3685: Add a new test named
test_publish_hides_other_user_session that follows the existing auth pattern:
set CODING_AGENT_SERVER_CONFIG via monkeypatch.setenv to the test auth config
(use _write_auth_config(tmp_path)), set settings.http_api_key to None, create a
session by POST /sessions with Authorization "Bearer admin-token" to get
session_id, then attempt to POST /sessions/{session_id}/publish with
Authorization "Bearer user-token-a" and json
{"mode":"branch","branch_name":"test"} and assert the response.status_code is
404; reference the existing test_publish_branch_returns_provider_result for
endpoint and payload structure and the helper names _write_auth_config,
settings.http_api_key, and the /sessions/{session_id}/publish route to locate
code.

---

Outside diff comments:
In `@coding-agent/docs/remote-sandbox-production.md`:
- Around line 153-159: The systemd [Service] example is missing the Git token
env var used by remote publication; update the unit to include
Environment=CODING_AGENT_GIT_TOKEN=replace-with-secret alongside
Environment=CODING_AGENT_BEARER_TOKEN=..., so when remote_publication.enabled is
true and git_token_env = "CODING_AGENT_GIT_TOKEN" the process started by
ExecStart (/usr/local/bin/coding-agent serve --config
/etc/coding-agent/config.toml) has the expected CODING_AGENT_GIT_TOKEN available
for remote publish operations.

---

Nitpick comments:
In `@coding-agent/tests/ui/test_http_server.py`:
- Around line 3651-3653: The test should explicitly verify the mock was called:
replace the patched target for publish_workspace_branch_from_config with a
MagicMock (or similar) that wraps fake_publish (e.g.,
MagicMock(side_effect=fake_publish)), keep monkeypatch.setattr on
"coding_agent.ui.http_server.publish_workspace_branch_from_config", then after
exercising the HTTP request call mock.assert_called_once_with(...) using the
same expected args currently validated inside fake_publish (provider config,
publish config dict, "ws-publish", "coding-agent/result", and the formatted
commit message including session_id) to ensure the function was actually invoked
exactly once.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 964418d8-91d4-4f72-bfb2-cee0b87e985d

📥 Commits

Reviewing files that changed from the base of the PR and between 5caf9cb and 09f2044.

📒 Files selected for processing (11)
  • coding-agent/docs/remote-sandbox-production.md
  • coding-agent/src/coding_agent/__main__.py
  • coding-agent/src/coding_agent/environment/__init__.py
  • coding-agent/src/coding_agent/environment/docker_workspace_provider.py
  • coding-agent/src/coding_agent/environment/workspace_provider.py
  • coding-agent/src/coding_agent/remote/client.py
  • coding-agent/src/coding_agent/ui/http_server.py
  • coding-agent/src/coding_agent/ui/schemas.py
  • coding-agent/tests/cli/test_remote_client.py
  • coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py
  • coding-agent/tests/ui/test_http_server.py

Comment thread coding-agent/tests/ui/test_http_server.py

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py (1)

1219-1221: ⚡ Quick win

Assert http.extraheader structure to catch auth regressions.

On Line 1221, the test only checks that the raw token is absent; it can still pass if GIT_CONFIG_VALUE_0 is empty or malformed. Add a shape assertion for the expected header prefix.

Suggested test hardening
     assert push_env["GIT_CONFIG_COUNT"] == "1"
     assert push_env["GIT_CONFIG_KEY_0"] == "http.extraheader"
+    assert push_env["GIT_CONFIG_VALUE_0"].startswith("AUTHORIZATION: basic ")
+    assert push_env["GIT_CONFIG_VALUE_0"] != "AUTHORIZATION: basic "
     assert "secret-token" not in push_env["GIT_CONFIG_VALUE_0"]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py`
around lines 1219 - 1221, The test currently only ensures the raw token is
absent in push_env["GIT_CONFIG_VALUE_0"] but doesn't verify the header shape;
update the assertion for push_env keys (GIT_CONFIG_VALUE_0) in
test_docker_workspace_provider.py to assert that GIT_CONFIG_VALUE_0 starts with
the expected HTTP auth header prefix (e.g. "AUTHORIZATION: " or the exact prefix
your code uses) and has non-empty content after the prefix, while still
asserting the raw "secret-token" is not present; use the existing
push_env["GIT_CONFIG_KEY_0"] and push_env["GIT_CONFIG_VALUE_0"] symbols to
locate and change the assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py`:
- Line 1330: The pytest.raises assertion uses an unescaped regex in the match
parameter; update the test that calls
pytest.raises(match="remote_publication.allowed_git_hosts must be configured")
to use a raw/escaped regex so dots are literal (e.g.
pytest.raises(match=r"remote_publication\.allowed_git_hosts must be configured")
or pytest.raises(match=re.escape("remote_publication.allowed_git_hosts must be
configured"))), locating the change in the test function that exercises
remote_publication.allowed_git_hosts in the DockerWorkspaceProvider tests.

---

Nitpick comments:
In
`@coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py`:
- Around line 1219-1221: The test currently only ensures the raw token is absent
in push_env["GIT_CONFIG_VALUE_0"] but doesn't verify the header shape; update
the assertion for push_env keys (GIT_CONFIG_VALUE_0) in
test_docker_workspace_provider.py to assert that GIT_CONFIG_VALUE_0 starts with
the expected HTTP auth header prefix (e.g. "AUTHORIZATION: " or the exact prefix
your code uses) and has non-empty content after the prefix, while still
asserting the raw "secret-token" is not present; use the existing
push_env["GIT_CONFIG_KEY_0"] and push_env["GIT_CONFIG_VALUE_0"] symbols to
locate and change the assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f52a714-cad7-4538-bf54-43341b1d1e24

📥 Commits

Reviewing files that changed from the base of the PR and between dd5856e and c0ae012.

📒 Files selected for processing (5)
  • coding-agent/docs/adr/0024-remote-result-publication.md
  • coding-agent/docs/remote-sandbox-production.md
  • coding-agent/src/coding_agent/environment/docker_workspace_provider.py
  • coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py
  • coding-agent/tests/ui/test_http_server.py
✅ Files skipped from review due to trivial changes (1)
  • coding-agent/docs/adr/0024-remote-result-publication.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • coding-agent/src/coding_agent/environment/docker_workspace_provider.py
  • coding-agent/docs/remote-sandbox-production.md
  • coding-agent/tests/ui/test_http_server.py

Comment thread coding-agent/tests/coding_agent/environment/test_docker_workspace_provider.py Outdated
@delete-cloud
delete-cloud merged commit 772c8b6 into main May 13, 2026
1 check passed
@delete-cloud
delete-cloud deleted the feat/remote-result-branch-publish branch May 13, 2026 12:17
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