fix(marketplace): resolve marketplace check against each entry's host + token#1763
fix(marketplace): resolve marketplace check against each entry's host + token#1763leocamello wants to merge 4 commits into
marketplace check against each entry's host + token#1763Conversation
`apm marketplace check` built a single default-host RefResolver with no token and called list_remote_refs(entry.source), ignoring the entry's effective host. After microsoft#1736 a relative source under `marketplace.sourceBase` parses as host=None with the bare relative `source`, and the base is composed only on the build (`pack`) path -- which `check` does not share. So `check` ran `git ls-remote https://github.com/<relative>.git` and failed with exit 128 for every `sourceBase` entry (and for the pre-existing microsoft#1288 host-prefixed form), even when `apm pack` against the same apm.yml succeeded. `check` now mirrors the builder's routing: it composes a host-less source onto `sourceBase` (via the shared `split_source_base`), honours per-entry host overrides, resolves a per-host token through the shared `marketplace/auth_helpers.resolve_token_for_host`, and short-circuits local `./` packages before any network call. Default-host entries are unchanged. Adds three `check` regressions: composed -> base host + token, host-prefixed override -> github, local -> zero ls-remote. Verified end-to-end against a real self-managed GitLab (the exit-128 case now resolves). Follows up microsoft#1736 / closes the `check` gap flagged there.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR aligns apm marketplace check with apm pack by resolving each package against its effective host (including sourceBase-composed sources) and using per-host auth tokens, while also skipping network checks for local packages.
Changes:
- Added shared
resolve_token_for_host()helper for per-host auth token resolution. - Updated
marketplace checkto route each entry to a per-hostRefResolver(and skipls-remotefor local entries). - Added unit tests covering
sourceBasecomposition, host overrides, and local-package behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tests/unit/commands/test_marketplace_check.py | Adds tests validating per-host resolution/token usage and that local entries avoid network calls. |
| src/apm_cli/marketplace/auth_helpers.py | Introduces shared helper to resolve host-specific tokens consistently across commands. |
| src/apm_cli/commands/marketplace/check.py | Implements per-host resolver caching and entry coordinate routing to match apm pack; skips remote checks for local entries. |
| CHANGELOG.md | Documents the behavioral change in apm marketplace check. |
| ) | ||
|
|
||
|
|
||
| def _entry_coordinates(entry, source_base): |
| if source_base: | ||
| base_host, base_path = split_source_base(source_base) | ||
| return base_host, f"{base_path}/{entry.source}" |
| def _resolver_for(host: str | None) -> RefResolver: | ||
| if host not in resolvers: | ||
| if host is None: | ||
| resolvers[host] = RefResolver(offline=offline) | ||
| else: | ||
| token = resolve_token_for_host(host, offline=offline) | ||
| resolvers[host] = RefResolver(offline=offline, host=host, token=token) |
| preserving hand-authored files. Use `--no-dedup` / `--force-instructions` | ||
| to write full `AGENTS.md` files anyway. (by @tillig; closes #1730, related: | ||
| #1138, #1550) (#1742) | ||
| - `apm marketplace check` now resolves each package against its effective host with that host's token, matching `apm pack`. Entries on a non-default host -- a `host.tld/owner/repo` shorthand or a relative source composed onto `marketplace.sourceBase` -- previously failed with `git ls-remote` exit 128 because `check` always probed the default host with no token; local `./` packages now skip the network. Follows up #1736. |
Centralize marketplace host token resolution, add verbose routing details for marketplace check, move the changelog note to Unreleased, and cover the shared auth helper branches. Addresses apm-review-panel follow-ups for PR microsoft#1763. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-sourcebase # Conflicts: # CHANGELOG.md
Tighten the changelog symptom, simplify builder's shared auth helper delegation, and make verbose check output copy-pasteable for non-default hosts. Addresses final apm-review-panel nit follow-ups for PR microsoft#1763. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 0 | 0 | Shared auth helper delegation is now clean; no architecture follow-up remains in scope. |
| CLI Logging Expert | 0 | 0 | 0 | Verbose-detail messages are well-formed; default output remains unchanged. |
| DevX UX Expert | 0 | 0 | 0 | check now mirrors pack host routing and gives copy-pasteable verbose context. |
| Supply Chain Security Expert | 0 | 0 | 1 | Token handling is safe; broader path-segment hardening should be shared across marketplace parsing/build/check. |
| OSS Growth Hacker | 0 | 0 | 0 | Changelog now leads with the user-visible exit-128 symptom and multi-host trust story. |
| Auth Expert | 0 | 0 | 0 | Per-host auth flows through AuthResolver and builder/check share the helper. |
| Doc Writer | 0 | 0 | 0 | Changelog placement is correct under Unreleased / Fixed; no docs drift found. |
| Test Coverage Expert | 0 | 0 | 0 | Routing and auth-helper branches have unit regression traps; targeted tests pass. |
| Performance Expert | 0 | 0 | 0 | Perf-neutral fix; resolver/auth objects are reused per check invocation. |
B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.
Recommendation
Ship after maintainer review. The PR is mergeable, local lint/tests are green, GitHub reports all current checks successful, and the only remaining note is intentionally deferred because it is a shared marketplace validation design concern rather than part of this host-routing bug fix.
Deferred (out-of-scope follow-ups)
- (panel) Add shared validation for
..path segments in marketplace sources -- scope boundary: PR scope is makingcheckmatch existingpack/sourceBaserouting; path-segment hardening should be designed once in schema/builder/check so the commands do not diverge.
Folded in this run
- (panel) Move changelog entry to Unreleased / Fixed and tighten the user-facing wording -- resolved in 1b8efa3 and 191c15a.
- (panel) Reuse one AuthResolver per
marketplace checkinvocation and share token-resolution logic with builder -- resolved in 1b8efa3. - (panel) Add verbose details for local skips and effective remote resolution -- resolved in 1b8efa3 and 191c15a.
- (panel) Refactor
MarketplaceBuilder._resolve_token_for_hostto delegate to the shared helper -- resolved in 1b8efa3 and 191c15a. - (panel) Add direct unit tests for
resolve_token_for_hostoffline, exception, supplied-resolver, and lazy-resolver branches -- resolved in 1b8efa3.
Copilot signals reviewed
- Copilot left a summary review and no inline comments. No LEGIT inline items were available to fold.
Regression-trap evidence (mutation-break gate)
tests/unit/marketplace/test_auth_helpers.py::test_resolve_token_for_host_offline_returns_none_without_resolver-- changed the offline guard; test FAILED as expected; guard restored.tests/unit/marketplace/test_auth_helpers.py::test_resolve_token_for_host_returns_none_when_resolver_raises-- narrowed the exception fallback; test FAILED as expected; guard restored.tests/unit/marketplace/test_auth_helpers.py::test_resolve_token_for_host_returns_token_from_supplied_resolverandtests/unit/marketplace/test_auth_helpers.py::test_resolve_token_for_host_creates_resolver_when_not_supplied-- removed token return; tests FAILED as expected; guard restored.
Lint contract
uv run --extra dev ruff check src/ tests/ and
uv run --extra dev ruff format --check src/ tests/ both completed with no diagnostics. Full local lint mirror also passed: pylint R0801 and scripts/lint-auth-signals.sh clean.
CI
gh pr checks 1763 --repo microsoft/apm reports all current checks successful: license/cla SUCCESS (after 0 CI fix iteration(s)).
Mergeability status
Captured from gh pr view 1763 --json mergeable,mergeStateStatus,statusCheckRollup immediately after the last push of this run.
| PR | head SHA | CEO stance | iters | folds | defers | Copilot rounds | CI | mergeable | mergeStateStatus | notes |
|---|---|---|---|---|---|---|---|---|---|---|
| #1763 | 191c15a |
ship_with_followups | 2 | 5 | 1 | 2 | green | MERGEABLE | BLOCKED | pending required review |
Convergence
2 outer iteration(s); 2 Copilot round(s). Final panel verdict: ship_with_followups.
Ready for maintainer review.
Full per-persona findings
Supply Chain Security Expert
- [nit]
_entry_coordinatesdoes not sanitize path-traversal sequences inentry.sourcebefore composing ontosourceBase.
This is deferred because the correct fix belongs in shared marketplace validation used by both pack and check.
All other panel personas returned no in-scope findings after the folded commits.
This panel is advisory. It does not block merge. Re-apply the panel-review label after addressing feedback to re-run.
|
Thanks for the shepherding here, @danielmeppiel -- the folded follow-ups are clear improvements: sharing one Agreed on deferring the Nothing outstanding from my side -- ready whenever a maintainer is. |
Description
apm marketplace checkbuilt a single default-hostRefResolverwith no token and calledlist_remote_refs(entry.source), ignoring each entry's effective host. After #1736 a relative source undermarketplace.sourceBaseparses ashost=Nonewith the bare relativesource(the base is composed only on the build/packpath, whichcheckdoesn't share), socheckrangit ls-remote https://github.com/<relative>.gitand failed with exit 128 for everysourceBaseentry — and for the pre-existing #1288host.tld/owner/repoform — even whenapm packagainst the sameapm.ymlsucceeded.checknow mirrors the builder's routing: it composes a host-less source ontosourceBase(via the sharedsplit_source_base), honours per-entry host overrides, resolves the host's token through a sharedmarketplace/auth_helpers.resolve_token_for_host, and short-circuits local./packages before any network call. Default-host entries are unchanged.Verified end-to-end against a real self-managed GitLab: the exit-128 case now resolves against the composed nested path.
Fixes #1762
Type of change
Testing
Adds three
checkregressions intests/unit/commands/test_marketplace_check.py: composed → base host + token, host-prefixed override → github, local → zero ls-remote.uv run pytest tests/unit/marketplace tests/unit/commandsis green (2607 passed);ruff check/ruff format --checkclean.Spec conformance (OpenAPM v0.1)
(
src/apm_cli/marketplace/andcommands/marketplace/are not Mode-B critical paths; no normative requirement changes.)