Skip to content

fix(marketplace): preserve ADO URL and bearer auth#2121

Merged
danielmeppiel merged 5 commits into
mainfrom
fix/2119-ado-marketplace-auth-url
Jul 10, 2026
Merged

fix(marketplace): preserve ADO URL and bearer auth#2121
danielmeppiel merged 5 commits into
mainfrom
fix/2119-ado-marketplace-auth-url

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

fix(marketplace): preserve Azure DevOps URL and bearer auth

TL;DR

Azure DevOps marketplace checks now use the suffix-free /_git/<repo> URL that ADO accepts. Marketplace resolution also preserves AuthContext.auth_scheme, so Azure CLI credentials reach git ls-remote as a bearer header instead of being treated like a PAT.

Note

Fixes #2119 with a hermetic CLI-level regression test covering both failures in one flow.

Problem (WHY)

  • apm marketplace check appended .git to ADO sourceBase repositories, making ADO resolve a different repository name (reported failure).
  • Marketplace auth reduced AuthContext to a token string, discarding the bearer scheme before git ls-remote (reported failure).
  • [!] Verbose output described the same invalid .git endpoint (reported output).

Approach (WHAT)

# Fix
1 Preserve the complete host auth context through marketplace check and pack resolution.
2 Build ADO marketplace git URLs without .git; retain suffix behavior for other hosts.
3 Inject ADO bearer credentials with git's http.extraheader environment configuration.
4 Pin the user-visible command flow with a hermetic end-to-end test.

Implementation (HOW)

Area Change
marketplace/auth_helpers.py Adds context-preserving auth resolution while retaining the token-only helper.
marketplace/ref_resolver.py Selects host-correct URLs and bearer-safe environments for both ref-listing paths.
commands/marketplace/check.py Carries auth_scheme into RefResolver and prints the suffix-free ADO endpoint.
marketplace/builder.py Applies the same auth context to pack-time per-host resolvers.
Tests Exercises CLI loading, source composition, auth routing, URL parsing, bearer injection, and ref parsing.
Docs Updates Starlight, the bundled usage guide, and changelog.

Diagrams

Legend: dashed stages are corrected by this PR; the bearer never enters the URL.

flowchart LR
    M["apm.yml sourceBase"] --> C["marketplace check"]
    C --> A["AuthResolver context"]
    A --> R["RefResolver"]
    R --> U["ADO URL without .git"]
    R --> H["Bearer http.extraheader"]
    U --> G["git ls-remote"]
    H --> G
    classDef new stroke-dasharray: 5 5;
    class A,U,H new;
Loading

Trade-offs

  • Context preservation over scheme inference. The resolver receives auth_scheme; it does not guess from token contents.
  • Host-specific URL behavior over changing the shared generic builder. Other git hosts retain .git compatibility.
  • Hermetic boundary over live ADO coverage. Only AuthResolver's result and the external git process are replaced.
  • Unrelated failure left untouched. The complete suite exposed an existing local-package ownership failure; cleanup semantics are outside [BUG] Azure Dev Ops marketplace sourceBase creates wrong URL for packages #2119.

Benefits

  1. ADO sourceBase resolves exactly to /org/project/_git/repo, checked with urllib.parse.
  2. Azure CLI credentials reach git as one bearer header and never appear in the URL.
  3. Verbose output reports the same suffix-free endpoint sent to git.
  4. URL and auth mutations independently break the regression test.

Validation

Regression test before and after the fix:

RED:   1 failed in 3.21s
GREEN: 1 passed in 0.34s

Mutation-break evidence after independently changing the production URL and auth guards, then restoring them:

MUTATION_RESULTS url=1 auth=1
RESTORED: 1 passed in 0.32s

Relevant ADO integration and marketplace unit suites:

229 passed in 4.51s

Canonical lint gate:

All checks passed!
1418 files already formatted
Your code has been rated at 10.00/10
[+] auth-signal lint clean
YAML, file-length, and relative_to guards clean
Complete integration-suite evidence

bash scripts/test-integration.sh collected the entire integration directory:

10204 passed, 172 skipped, 16 deselected, 2 xfailed, 2 failed

The ADO fixture failure was corrected and passes in the targeted ADO integration run. The remaining failure reproduces independently in unchanged code: tests/integration/test_intra_package_cleanup.py::TestCrossPackageSharedFileCleanup::test_shared_file_survives_when_other_package_still_deploys_it.

Scenario Evidence

# Scenario (user promise) Principle(s) Test(s) proving it Type
1 apm marketplace check succeeds for an ADO sourceBase while signed in through Azure CLI Secure by default, Vendor-neutral, DevX tests/integration/test_ado_marketplace_check_auth.py::test_marketplace_check_uses_ado_url_and_bearer_auth (regression-trap for #2119) e2e
2 ADO marketplace authoring and consumption remains host-preserving Vendor-neutral tests/integration/test_ado_marketplace_e2e.py integration

How to test

  • Run uv run --extra dev pytest tests/integration/test_ado_marketplace_check_auth.py -q; expect one pass without network.
  • Run the relevant marketplace unit suites; expect 229 passes.
  • Run the canonical lint chain; expect ruff, formatter, R0801, and auth-signal checks to pass.
  • With an ADO marketplace and az login, run apm marketplace check --verbose; expect a suffix-free URL and successful ref check.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 10, 2026 13:34

Copilot AI 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.

Pull request overview

This PR fixes Azure DevOps (ADO) marketplace resolution by (1) generating ADO git URLs without an invalid .git suffix and (2) preserving the full auth context so ADO Azure CLI credentials reach git ls-remote as a bearer http.extraheader rather than being treated like a basic/PAT token.

Changes:

  • Preserve AuthContext.auth_scheme through marketplace check/pack flows and plumb it into RefResolver.
  • Generate suffix-free ADO marketplace URLs and inject bearer auth via git environment (http.extraheader).
  • Add/adjust regression coverage (new hermetic integration test + updated unit/integration fixtures) and update docs + changelog.
Show a summary per file
File Description
tests/unit/commands/test_marketplace_check.py Updates unit tests to patch/expect resolve_auth_for_host and auth_scheme propagation into RefResolver.
tests/integration/test_ado_marketplace_e2e.py Extends the integration auth stub to include auth_scheme so existing E2E coverage remains accurate.
tests/integration/test_ado_marketplace_check_auth.py Adds a hermetic regression test asserting suffix-free ADO URL and bearer header injection into git ls-remote.
src/apm_cli/marketplace/ref_resolver.py Adds auth_scheme support and ADO-specific URL/env building for git ls-remote.
src/apm_cli/marketplace/builder.py Preserves full auth context when creating per-host RefResolver instances during pack/build resolution.
src/apm_cli/marketplace/auth_helpers.py Introduces resolve_auth_for_host() (context-preserving) while retaining token-only helper for callers that need it.
src/apm_cli/commands/marketplace/check.py Uses resolve_auth_for_host, passes auth_scheme into RefResolver, and prints suffix-free ADO endpoint in verbose output.
packages/apm-guide/.apm/skills/apm-usage/dependencies.md Documents ADO sourceBase format and suffix-free repo appending behavior.
packages/apm-guide/.apm/skills/apm-usage/authentication.md Documents bearer-header behavior for ADO marketplace check (Azure CLI fallback).
docs/src/content/docs/reference/cli/marketplace.md Updates CLI reference docs for ADO sourceBase behavior and auth chain.
docs/src/content/docs/getting-started/authentication.md Notes that marketplace check follows the same ADO auth chain and uses bearer headers (not URL embedding).
CHANGELOG.md Adds an Unreleased fix entry for the ADO marketplace URL/auth behavior.

Review details

  • Files reviewed: 12/12 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment thread src/apm_cli/marketplace/ref_resolver.py Outdated
Comment on lines +186 to +193
requested_bearer = self._auth_scheme == "bearer"
bearer = requested_bearer and is_azure_devops_hostname(self._host)
token = None if requested_bearer else self._token
if is_azure_devops_hostname(self._host):
credentials = f"x-access-token:{token}@" if token else ""
url = f"https://{credentials}{self._host}/{owner_repo}"
else:
url = build_https_clone_url(self._host, owner_repo, token=token)
Comment thread CHANGELOG.md
Comment on lines +12 to +13
- Azure DevOps marketplace checks now preserve suffix-free `/_git/<repo>` URLs
and pass Azure CLI bearer authentication through to `git ls-remote`. (closes #2119)
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_with_followups

Fixes ADO marketplace auth by preserving the original URL and bearer scheme through the git resolution path.

cc @danielmeppiel -- a fresh advisory pass is ready for your review.

Panel signals converge cleanly. The strongest shared concern was a bearer credential silently downgrading to unauthenticated on a non-ADO host. The builder bearer propagation test and stale documentation guidance were also raised. All three are now folded in the working tree; tests, lint, and CI remain to validate them.

Aligned with: secure by default; multi-host support; pragmatic package-manager UX.

Panel summary

Persona B R N Takeaway
Python Architect 0 0 2 Clean AuthContext lift; harden unsupported bearer hosts.
CLI Logging Expert 0 0 0 CLI output follows existing conventions.
DevX UX Expert 0 0 2 ADO behavior is clearer; minor diagnostics polish remains.
Supply Chain Security Expert 0 0 1 Bearer transport is safe; fail closed on unsupported hosts.
Auth Expert 0 0 1 ADO auth plumbing is sound after the guard.
Doc Writer 0 2 0 Correct fallback wording and consolidate sourceBase guidance.
Test Coverage Expert 0 1 0 Add builder bearer-scheme propagation coverage.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Top 3 follow-ups

  1. [Test Coverage Expert] Verify the builder bearer auth-scheme propagation test in the full suite.
  2. [Doc Writer] Verify consolidated marketplace/auth guidance has no stale claims.
  3. [DevX UX Expert] Keep unsupported bearer-host diagnostics actionable.

Recommendation

Run the full integration suite and canonical lint against the folded changes, then observe CI green. The strongest test and security findings are addressed in-tree.


Full per-persona findings
  • Security/auth: unsupported bearer authentication must fail closed rather than silently become unauthenticated.
  • Documentation: distinguish PAT selection from Azure CLI selection; do not imply a rejected-PAT retry in this command path.
  • Coverage: prove MarketplaceBuilder preserves auth_scheme="bearer", in addition to the CLI-level URL/header flow.

This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.

danielmeppiel and others added 4 commits July 10, 2026 19:22
Fail closed when bearer auth is paired with an unsupported host, prove builder scheme propagation, repair the stale auth fixture, and consolidate accurate ADO sourceBase guidance. Addresses panel auth, security, coverage, and docs follow-ups.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ace-auth-url

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep ADO PATs out of process-visible URLs, surface unsupported bearer schemes through the marketplace error type, and remove duplicate builder auth resolution. Addresses the final auth, supply-chain, DevX, and architecture panel findings.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Prove the context-preserving helper directly, clarify the URL-only token variable, and replace duplicated marketplace auth prose with the canonical sourceBase cross-reference. Addresses the terminal panel findings.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_now

PR #2121 lands clean: all specialist findings are folded, the full test suite is green, and no follow-up work remains.

cc @danielmeppiel @sergio-sisternes-epam -- a fresh advisory pass is ready for your review.

Every active specialist converged on the same signal. AuthContext and its scheme now survive both marketplace check and build paths. ADO bearer and PAT credentials use http.extraheader, unsupported bearer hosts fail closed through a marketplace-domain error, and ADO URLs retain the suffix-free /_git/<repo> form. Documentation and bundled usage guidance match the implementation.

Aligned with: secure by default; multi-host support; pragmatic package-manager UX.

Panel summary

Persona B R N Takeaway
Python Architect 0 0 0 Architecture is clean and the auth helper lifecycle is unified.
CLI Logging Expert 0 0 0 User-visible URL output follows existing conventions.
DevX UX Expert 0 0 0 Domain errors are actionable and the happy path remains unchanged.
Supply Chain Security Expert 0 0 0 ADO credentials stay out of process-visible URLs.
OSS Growth Hacker 0 0 0 The ADO enterprise compatibility story is clear.
Auth Expert 0 0 0 Auth scheme propagation and host boundaries are correct.
Doc Writer 0 0 0 Auth precedence and sourceBase guidance are accurate and consolidated.
Test Coverage Expert 0 0 0 E2E and unit regression traps cover every changed auth branch.

B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.

Folded in this run

  • (panel) Fail closed for bearer authentication on non-ADO hosts -- resolved in fcddea690.
  • (panel) Preserve bearer scheme through MarketplaceBuilder -- resolved in fcddea690.
  • (panel) Consolidate accurate ADO auth and sourceBase guidance -- resolved in fcddea690 and b6c45eec6.
  • (panel) Keep ADO PATs out of process-visible URLs -- resolved in bcfc7f135.
  • (panel) Raise marketplace-domain auth errors and unify builder auth resolution -- resolved in bcfc7f135.
  • (panel) Directly prove AuthContext scheme preservation -- resolved in b6c45eec6.

Regression-trap evidence (mutation-break gate)

  • test_marketplace_check_uses_ado_url_and_bearer_auth -- adding .git to the ADO URL failed; guard restored.
  • test_marketplace_check_uses_ado_url_and_bearer_auth -- removing bearer header injection failed; guard restored.
  • test_ado_bearer_auth_scheme_reaches_resolver -- forcing basic auth failed; guard restored.
  • test_bearer_auth_rejects_non_ado_host -- removing fail-closed guard failed; guard restored.
  • test_ado_pat_uses_basic_header_without_url_credentials -- removing Basic header injection failed; guard restored.
  • test_resolve_auth_for_host_preserves_bearer_scheme -- discarding AuthContext failed; guard restored.

Validation

  • bash scripts/test-integration.sh: 10206 passed, 172 skipped, 16 deselected, 2 xfailed.
  • Marketplace suites: 1445 passed.
  • Canonical ruff, format, pylint R0801, YAML, file-length, relative-path, and auth-signal checks are clean.
  • GitHub CI run 29112660522: all required checks passed on b6c45eec6.

Mergeability status

PR head SHA CEO stance iters folds defers Copilot rounds CI mergeable merge state notes
#2121 b6c45ee ship_now 3 6 0 2 green MERGEABLE required review pending awaiting maintainer review

Recommendation

All in-scope findings are folded and every automated gate is green. Ready for maintainer review.

This panel is advisory. It does not gate merge.

@danielmeppiel danielmeppiel merged commit 26d8cee into main Jul 10, 2026
15 checks passed
@danielmeppiel danielmeppiel deleted the fix/2119-ado-marketplace-auth-url branch July 10, 2026 19:14
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.

[BUG] Azure Dev Ops marketplace sourceBase creates wrong URL for packages

2 participants