Skip to content

Add UNITY_GATEWAY_CUSTOM_CODING_AGENT header override - #1179

Open
poojabhat0 wants to merge 1 commit into
mainfrom
pooja-bhat_data/stack/coding-agent-header
Open

poojabhat0 wants to merge 1 commit into
mainfrom
pooja-bhat_data/stack/coding-agent-header

Conversation

@poojabhat0

@poojabhat0 poojabhat0 commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Let custom agents and wrappers identify their inference traffic through UNITY_GATEWAY_CUSTOM_CODING_AGENT:

UNITY_GATEWAY_CUSTOM_CODING_AGENT=my-agent ug claude
  • Send Databricks-Custom-Coding-Agent without changing authentication or User-Agent. The gateway attributes traffic to the custom identity instead of the native agent;
  • Leave the override unset or blank to preserve native detection. Trim surrounding whitespace and warn/omit values containing control characters. Admin-managed headers retain precedence.
  • Support Claude Code, modern/legacy Codex configs, Gemini CLI, OpenCode, Kilo, and Pi. Gemini rejects comma-containing names; Pi uses an environment reference to avoid interpreting identities as commands or other environment-variable names.
  • Apply the override to Claude Desktop during ug configure.

No custom-client-surface headers, authentication changes, or support for Copilot/MCP-only agents are included.

Validation

  • 1,243 affected unit/component and regression tests passed, covering validation, adapter headers, unchanged User-Agent values, admin precedence, and override cleanup.
  • Ruff lint, formatting checks, and ty check src/ passed.
  • Live inference and gateway usage-log attribution have not been verified.

@poojabhat0 poojabhat0 changed the title Support custom coding-agent attribution via Unity Gateway Add UNITY_GATEWAY_CUSTOM_CODING_AGENT header override Oct 17, 2026
@poojabhat0

Copy link
Copy Markdown
Collaborator Author

/ug-review

)

headers = {"x-databricks-use-coding-agent-mode": "true"}
headers.update(custom_coding_agent_headers())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
other agents add this header per launch. what happens if ug configure runs inside a custom-agent shell? the Desktop profile keeps that name, so all Desktop traffic gets attributed to that agent. can we leave it out for Desktop?

}[agent]
monkeypatch.setattr(module, "ug_version", lambda: "1.2.3")
monkeypatch.setattr(module, "agent_version", lambda _binary: "4.5.6")
monkeypatch.delenv(UNITY_GATEWAY_CUSTOM_CODING_AGENT_ENV_VAR, raising=False)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

test · low
can we clear this in conftest's autouse _isolate_ucode_state instead? if a dev or CI has the var set, existing exact-header tests for claude/codex/gemini/pi pick up the extra header and fail.

Comment on lines +195 to +196
@pytest.mark.parametrize("identity", ["COLLIDING_ENV_VAR", "!do-not-execute"])
def test_pi_uses_environment_reference_not_a_dynamic_literal(identity, monkeypatch):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

test · medium
can we add a padded value like " my-agent "? pi expands the raw env var, so it sends the untrimmed value while every other adapter sends the stripped one, and nothing here catches that.

Suggestion:

Suggested change
@pytest.mark.parametrize("identity", ["COLLIDING_ENV_VAR", "!do-not-execute"])
def test_pi_uses_environment_reference_not_a_dynamic_literal(identity, monkeypatch):
@pytest.mark.parametrize("identity", ["COLLIDING_ENV_VAR", "!do-not-execute", " padded-agent "])
def test_pi_uses_environment_reference_not_a_dynamic_literal(identity, monkeypatch):

@github-actions

Copy link
Copy Markdown

Polly AI Review

Blocking issues

  • P2 — Attribution changes can block headless Codex launches — src/ucode/agents/codex.py:222
    can we exclude optional attribution from both managed-file checks? Changing it makes an existing managed config conflict, blocking launch when sudo is unavailable or UG_SKIP_OS_SETTINGS=1.

    Offline reproduction confirmed failures for unset→set, rename, and set→unset; unchanged attribution continues. Add a managed-config regression beside tests/test_agent_codex.py::TestCodexWriteConfig::test_rewrite_removes_custom_agent_override.

Security vulnerabilities

  • P1 — Unicode separators inject persistent Claude headers — src/ucode/agents/coding_agent.py:19, src/ucode/agents/claude.py:514
    can we reject Unicode line separators? agent\u0085Authorization: synthetic passes validation, becomes another header during Claude's unmanaged merge, and survives unsetting the override.

    Reproduced with the existing merge function. U+0085, U+2028, and U+2029 pass validation but split into separate lines. A nonempty existing header string triggers this; UG's preceding write is sufficient. This permits persistent header injection, not a demonstrated privilege escalation.

    Extend tests/test_coding_agent.py::test_control_characters_warn_on_stderr_and_omit_header and tests/test_coding_agent.py::test_claude_merge_replaces_and_removes_override_but_preserves_other_headers with these separators and the disable transition.

Non-blocking notes

  • tests/test_coding_agent.py::test_adapters_omit_empty_or_invalid_override: can we keep one malformed value per adapter and leave blank permutations in the helper test?
  • tests/test_coding_agent.py::test_adapters_remove_override_on_next_render: can we remove this fresh-render check? The write/reconfigure tests exercise persisted cleanup.
  • tests/test_coding_agent.py::test_custom_coding_agent_headers: can we remove the unshipped AI_GATEWAY_CUSTOM_CODING_AGENT alias case unless rejecting that alias is an explicit contract?

Approach

The shared helper and adapter-level wiring are consistent with existing boundaries. Harden validation centrally, and apply optional-attribution compatibility rules consistently to normal and skipped managed-file reconciliation.

Summary

Diff size (computed): 16 files; +348 / -2 lines (350 changed text lines); 0 binary files.

Category Files Added Deleted Share of changed text lines
Tests and test support 6 266 0 76.0%
Documentation 1 21 0 6.0%
Dependencies and lockfiles 0 0 0 0.0%
Implementation / other 9 61 2 18.0%

Shares use additions + deletions, including generated text and lockfiles. Binary files have no line count. Tests include fixtures/helpers under test paths and colocated test/spec files; categories are path-based, not coverage measurements.

Changes

The change adds environment-based attribution across the requested CLI adapters and Claude Desktop configuration, shared validation, header ownership/conflict handling, documentation, and tests. Authentication and User-Agent generation are not intentionally changed. No dependencies, lockfiles, or generated assets change.

The implementation is proportional to the outcome. The concrete reduction opportunities are redundant renderer checks and adapter-level blank-input permutations, assessed below.

Tests

Test-by-test assessment

Assessment is based on the frozen diff and relevant existing coverage. Offline function-level reproductions confirmed the Unicode injection and conditional Codex reconciliation failures. The affected pytest suite was not run; the PR's reported pass count is not independently verified. Native requests and gateway attribution remain unverified.

Test / case Behavior protected Layer Needed? Action / rationale
tests/README.md — attribution coverage paragraph Documents component coverage and live-verification limits Documentation keep Describes the evidence boundary without adding setup.
tests/integration/README.md — attribution paragraph Identifies component coverage and missing live attribution evidence Documentation keep Explicitly distinguishes configuration checks from backend attribution.
tests/test_coding_agent.py::test_custom_coding_agent_headers — unset, empty, whitespace cases Disabled override preserves native behavior Unit keep Appropriate layer for input permutations.
tests/test_coding_agent.py::test_custom_coding_agent_headers — ordinary and trimmed names Header identity and whitespace normalization Unit keep Direct assertions on the shared contract.
tests/test_coding_agent.py::test_custom_coding_agent_headers — unsupported alias case An undocumented variable does not activate attribution Unit remove No shipped alias or stated compatibility requirement establishes its value.
tests/test_coding_agent.py::test_control_characters_warn_on_stderr_and_omit_header Invalid input is omitted with a warning that does not echo it Unit keep Add Unicode line-separator cases; current cases miss the demonstrated injection boundary.
tests/test_coding_agent.py::test_helper_reads_process_environment Default environment source and subsequent unset Unit keep Tests the helper's default-argument path directly.
tests/test_coding_agent.py::_parse_header_lines Extracts rendered headers for assertions Test helper keep Small adapter assertion helper; it does not reproduce Claude's splitlines() merge behavior.
tests/test_coding_agent.py::rendered_headers Supplies actual renderers across supported adapter variants Fixture keep Shares bounded setup while leaving assertions in tests.
tests/test_coding_agent.py::test_adapters_emit_override_without_changing_user_agent Adapter wiring, unchanged other headers, no surface header Component keep Each renderer is a distinct integration point.
tests/test_coding_agent.py::test_adapters_omit_empty_or_invalid_override — empty and whitespace cases Disabled override matches renderer baseline Component consolidate Helper tests already establish these normalization cases.
tests/test_coding_agent.py::test_adapters_omit_empty_or_invalid_override — malformed value Each adapter invokes validation Component keep One invalid input per adapter verifies wiring rather than repeating the input matrix.
tests/test_coding_agent.py::test_adapters_remove_override_on_next_render Fresh renderer output changes after unset Component remove Does not exercise persisted cleanup; overlaps baseline and emission assertions.
tests/test_coding_agent.py::test_admin_header_overrides_environment_case_insensitively Claude/Codex admin precedence without duplicate casing Component keep Protects an explicit precedence requirement.
tests/test_coding_agent.py::test_claude_merge_replaces_and_removes_override_but_preserves_other_headers Stateful header replacement, removal, and caller preservation Unit keep Exercises the actual merge boundary; extend for injected separators and subsequent disable.
tests/test_coding_agent.py::test_gemini_warns_and_omits_comma_delimited_override Gemini delimiter rejection without reflected payload Component keep Adapter-specific parsing boundary.
tests/test_coding_agent.py::test_pi_uses_environment_reference_not_a_dynamic_literal Command-shaped and environment-name-shaped identities remain indirect Component keep Distinct interpretation hazards; does not establish Pi's native resolver behavior.
tests/test_agent_codex.py::TestCodexWriteConfig::test_rewrite_removes_custom_agent_override Persisted TOML cleanup after disabling attribution Component/filesystem keep Tests serialization and replacement, but not managed-file conflict handling.
tests/test_claude_managed_headers.py::test_optional_attribution_and_header_formatting_do_not_conflict — added attribution case Attribution differences do not create normal Claude managed conflicts Unit keep Extends a compatible existing matrix at the comparison boundary.
tests/test_desktop_setup.py::test_custom_agent_header_is_removed_on_reconfigure Desktop profile adds and subsequently removes attribution Component/filesystem keep Reuses platform fixtures and verifies persisted state.
tests/test_desktop_setup.py::test_admin_custom_agent_header_overrides_environment Desktop admin precedence across casing Component/filesystem keep Covers Desktop's separate composition path.

Existing Claude caller-header preservation and admin-withdrawal tests, plus Codex legacy cleanup and admin-withdrawal tests, already cover related ownership transitions. They do not cover the two demonstrated failures above. Focused unit/component regressions are sufficient for those failures; duplicate live tests are unnecessary.

Scope

All changed files support the stated attribution outcome. No clearly unrelated changes or added source-comment conciseness issues were found. The findings concern validation and managed-configuration behavior within that scope, not independent feature work.


Automated review by Polly · workflow run

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