fix(deps): honor SSH user from dependency URL (closes #1383)#1385
Merged
Conversation
build_ssh_url() unconditionally prepended 'git@' even when the user explicitly specified a non-git SSH user (e.g. EMU accounts like 'meppiel-microsoft' or 'ado-username@org'). The user portion of ssh://, scp-shorthand, and parsed dependency URLs was silently dropped, leaving clone attempts authenticated as the wrong identity. Threads ssh_user from the parsed DependencyReference through to the per-host backend build_clone_ssh_url callers and validates it against a strict allowlist before composing the URL. Changes: - utils/github_host.py: add validate_ssh_user() with an '[a-zA-Z0-9_][a-zA-Z0-9_.+-]*' regex, 64-char cap, error messages that hide the user value; build_ssh_url(user='git') validates before composing. - models/dependency/reference.py: add ssh_user field; parse it from ssh:// and scp shorthand; reject percent-encoded userinfo at the pre-urlparse layer for defence in depth; keep ssh_user out of to_canonical/get_identity so it cannot perturb the install-plan identity invariant. - deps/host_backends.py: pass user=ssh_user (default 'git') from the three non-ADO backends; ADO is left untouched (literal 'git@' is required by the service). Tests: - tests/unit/test_ssh_user_threading.py: validate_ssh_user allowlist, length cap, percent rejection, error hides value; parser threads ssh_user through DependencyReference; ssh_user is NOT part of identity. - tests/integration/test_dep_url_parsing_e2e.py: end-to-end thread from URL to backend.build_clone_ssh_url. - tests/acceptance/test_logging_acceptance.py: extend bracket pattern to cover the [~], [-], [=] plan-diff symbols (drive-by baseline fix). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
sergio-sisternes-epam
pushed a commit
that referenced
this pull request
May 19, 2026
build_ssh_url() unconditionally prepended 'git@' even when the user explicitly specified a non-git SSH user (e.g. EMU accounts like 'meppiel-microsoft' or 'ado-username@org'). The user portion of ssh://, scp-shorthand, and parsed dependency URLs was silently dropped, leaving clone attempts authenticated as the wrong identity. Threads ssh_user from the parsed DependencyReference through to the per-host backend build_clone_ssh_url callers and validates it against a strict allowlist before composing the URL. Changes: - utils/github_host.py: add validate_ssh_user() with an '[a-zA-Z0-9_][a-zA-Z0-9_.+-]*' regex, 64-char cap, error messages that hide the user value; build_ssh_url(user='git') validates before composing. - models/dependency/reference.py: add ssh_user field; parse it from ssh:// and scp shorthand; reject percent-encoded userinfo at the pre-urlparse layer for defence in depth; keep ssh_user out of to_canonical/get_identity so it cannot perturb the install-plan identity invariant. - deps/host_backends.py: pass user=ssh_user (default 'git') from the three non-ADO backends; ADO is left untouched (literal 'git@' is required by the service). Tests: - tests/unit/test_ssh_user_threading.py: validate_ssh_user allowlist, length cap, percent rejection, error hides value; parser threads ssh_user through DependencyReference; ssh_user is NOT part of identity. - tests/integration/test_dep_url_parsing_e2e.py: end-to-end thread from URL to backend.build_clone_ssh_url. - tests/acceptance/test_logging_acceptance.py: extend bracket pattern to cover the [~], [-], [=] plan-diff symbols (drive-by baseline fix). Co-authored-by: Daniel Meppiel <copilot-rework@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced May 20, 2026
7 tasks
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.
Closes #1383
Problem
build_ssh_url()unconditionally prependedgit@even when the user explicitly specified a non-gitSSH user in the dependency URL (e.g. EMU accounts likemeppiel-microsoftorado-username@org). The user portion ofssh://, scp-shorthand, and parsed dependency URLs was silently dropped, leaving clone attempts authenticated as the wrong identity.Fix
Thread
ssh_userfrom the parsedDependencyReferencethrough to per-host backendbuild_clone_ssh_urlcallers, validated against a strict allowlist before composing the URL.Source changes
utils/github_host.py—validate_ssh_user()with^[a-zA-Z0-9_][a-zA-Z0-9_.+-]*$regex, 64-char cap, error messages that hide the user value (only the length is leaked).build_ssh_url(user="git")validates before composing.models/dependency/reference.py—ssh_user: str | Nonefield onDependencyReference; parsed fromssh://and scp shorthand; percent-encoded userinfo rejected at the pre-urlparselayer (defence in depth). Kept out ofto_canonical/get_identityso it cannot perturb the install-plan identity invariant.deps/host_backends.py— three non-ADO backends passuser=getattr(dep_ref, "ssh_user", None) or "git". ADO is left untouched (literalgit@is required by the service).Supply-chain review
Reviewed by the
apm-review-panelsupply-chain expert (verdict: APPROVE-WITH-CHANGES, all changes applied):-oProxyCommand=…).ssh_useris presentation-only, never part of canonical identity.Tests
tests/unit/test_ssh_user_threading.py(new) — allowlist boundaries, length cap, percent rejection, error-message-hides-value, parser threading, identity-invariant preservation.tests/integration/test_dep_url_parsing_e2e.py— end-to-end thread from URL string tobackend.build_clone_ssh_url.tests/acceptance/test_logging_acceptance.py— drive-by baseline fix: extend bracket pattern to cover the[~],[-],[=]plan-diff symbols (was failing onmain).All 226 SSH-related tests pass; lint clean (
ruff check+ruff format --checkboth silent).Deferred follow-ups
ssh_userstorage —apm.ymlis re-parsed on each install, so URL-encoded users round-trip correctly today. Persistingssh_userinapm.lock.yamlis a separate enhancement and left for a follow-up issue.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com