feat: Auth + Logging Architecture Overhaul (#393)#394
feat: Auth + Logging Architecture Overhaul (#393)#394danielmeppiel wants to merge 37 commits intomainfrom
Conversation
Phase 1 — Foundation: - AuthResolver: per-(host,org) token resolution, host classification, try_with_fallback(), build_error_context(), detect_token_type() - CommandLogger base + InstallLogger subclass with semantic lifecycle - DiagnosticCollector: CATEGORY_AUTH, auth() method, render group Phase 2 — Auth wiring (all touchpoints): - github_downloader.py: AuthResolver injected, per-dep token resolution in _clone_with_fallback and _download_github_file - install.py: _validate_package_exists uses try_with_fallback(unauth_first=True) - copilot.py + operations.py: replaced os.getenv bypasses with TokenManager - All 7 hardcoded auth error messages replaced with build_error_context() Security fix: global env vars (GITHUB_APM_PAT) no longer leak to non-default hosts (GHES, GHE Cloud, generic). Enterprise hosts resolve via per-org env vars or git credential helpers only. Phase 4 — Tests: - test_auth.py: 34 tests (classify_host, resolve, try_with_fallback, build_error_context, detect_token_type) - test_command_logger.py: 44 tests (CommandLogger, InstallLogger, _ValidationOutcome) - Fixed test_github_downloader_token_precedence.py import paths - Updated test_auth_scoping.py for AuthResolver integration Phase 5 — Agents & Skills: - 3 agent personas: auth-expert, python-architect, cli-logging-expert - 2 new skills: auth, python-architecture - Updated cli-logging-ux skill with CommandLogger awareness All 2829 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Install UX overhaul (3a): - Wire InstallLogger into install.py with semantic lifecycle methods - Short-circuit on total validation failure (no more misleading counts) - Context-aware messages: partial vs full, new vs locked dependencies - Demote noise (lockfile info, MCP transitive, orphan cleanup) to verbose Documentation (5a, 5b): - Rewrite authentication.md: resolution chain, token lookup table, per-org setup, EMU/GHE Cloud/GHES sections, troubleshooting - CHANGELOG entry under [Unreleased] for #393 Test updates (4c): - 11 new CATEGORY_AUTH tests in test_diagnostics.py - Fix tuple unpacking in test_canonicalization, test_dev_dependencies, test_generic_git_url_install (validation now returns outcome) - Update error message assertion in test_install_command All 2839 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 3 — Logging migration (3b-3g): - compile: CommandLogger in cli.py, _log() helper in agents_compiler.py - deps: CommandLogger in cli.py + _utils.py (logger=None backward compat) - audit: CommandLogger, pass logger to helpers, verbose_detail for scan stats - mcp/run/init: CommandLogger with --verbose support - config/list/update/pack/runtime/prune/uninstall: CommandLogger wiring - Support modules: logger=None param in skill/prompt/instruction/mcp integrators, vscode adapter, drift module Phase 4 — Integration tests (4d, 4e): - test_auth_resolver.py: 26 integration tests across 8 test classes - Scripts verified — no auth error pattern updates needed All 2839 tests pass, 126 skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces two cross-cutting foundations—AuthResolver (per-(host, org) auth resolution) and CommandLogger / InstallLogger (structured CLI lifecycle logging)—and wires them through CLI commands and auth touchpoints to fix EMU/private repo installs, reduce confusing output, and prevent token leakage across hosts.
Changes:
- Add
AuthResolver+ host classification + fallback strategies; integrate into clone/download/validation paths. - Add
CommandLogger/InstallLoggerand thread diagnostics through commands and supporting modules. - Expand diagnostics with
CATEGORY_AUTH, update docs/changelog, and adjust/add unit & integration tests.
Reviewed changes
Copilot reviewed 52 out of 52 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_unpacker.py | Updates dry-run output assertion to match new logging wording. |
| tests/unit/test_install_command.py | Updates invalid-format assertion to match updated validation messaging. |
| tests/unit/test_diagnostics.py | Adds coverage for new CATEGORY_AUTH diagnostics group rendering/counting. |
| tests/unit/test_dev_dependencies.py | Adapts to new (validated, outcome) return from validation helper. |
| tests/unit/test_command_logger.py | New unit tests for CommandLogger, InstallLogger, _ValidationOutcome. |
| tests/unit/test_canonicalization.py | Updates expectations for new validation helper return type. |
| tests/unit/test_auth_scoping.py | Adjusts scoping tests to align with per-dep auth resolution & cache. |
| tests/unit/test_auth.py | New unit tests for AuthResolver (classification, caching, fallback, errors). |
| tests/unit/test_audit_command.py | Updates audit helper calls to pass CommandLogger. |
| tests/test_token_manager.py | Adds tests for configurable credential-helper timeout behavior. |
| tests/test_github_downloader_token_precedence.py | Fixes test imports to use installed package paths. |
| tests/integration/test_generic_git_url_install.py | Updates expectations for new validation helper return type. |
| tests/integration/test_auth_resolver.py | New integration tests gated by APM_E2E_TESTS. |
| src/apm_cli/utils/diagnostics.py | Adds CATEGORY_AUTH + rendering and count helpers. |
| src/apm_cli/registry/operations.py | Uses token manager precedence when auto-filling env vars in CI/E2E mode. |
| src/apm_cli/integration/skill_integrator.py | Threads optional logger into skill integration warnings/diagnostics. |
| src/apm_cli/integration/prompt_integrator.py | Adds optional logger parameter for structured output compatibility. |
| src/apm_cli/integration/mcp_integrator.py | Threads optional logger through MCP install/remove flows; renames module logger to _log. |
| src/apm_cli/integration/instruction_integrator.py | Adds optional logger parameter for structured output compatibility. |
| src/apm_cli/drift.py | Threads optional logger through drift helpers. |
| src/apm_cli/deps/github_downloader.py | Switches to AuthResolver and per-dependency token resolution for clone/download/error context. |
| src/apm_cli/core/token_manager.py | Makes git credential fill timeout configurable; default 60s, max 180s. |
| src/apm_cli/core/command_logger.py | New structured logging base (CommandLogger) and install-specific logger (InstallLogger). |
| src/apm_cli/core/auth.py | New AuthResolver/AuthContext/HostInfo with caching + fallback strategies. |
| src/apm_cli/core/init.py | Exposes auth types from apm_cli.core. |
| src/apm_cli/compilation/agents_compiler.py | Adds optional logger plumbing for compilation output instead of raw print(). |
| src/apm_cli/commands/update.py | Migrates update command output to CommandLogger. |
| src/apm_cli/commands/uninstall/cli.py | Migrates uninstall command output to CommandLogger. |
| src/apm_cli/commands/runtime.py | Migrates runtime command output to CommandLogger. |
| src/apm_cli/commands/run.py | Adds --verbose and migrates output to CommandLogger. |
| src/apm_cli/commands/prune.py | Migrates prune command output to CommandLogger. |
| src/apm_cli/commands/pack.py | Migrates pack/unpack output to CommandLogger (incl. dry-run messaging). |
| src/apm_cli/commands/mcp.py | Adds --verbose and migrates MCP commands output to CommandLogger. |
| src/apm_cli/commands/list_cmd.py | Migrates list command output to CommandLogger. |
| src/apm_cli/commands/install.py | Integrates InstallLogger, introduces validation outcome tracking, and auth-aware validation (try_with_fallback). |
| src/apm_cli/commands/init.py | Adds --verbose and migrates init output to CommandLogger. |
| src/apm_cli/commands/deps/cli.py | Migrates deps subcommands output to CommandLogger. |
| src/apm_cli/commands/deps/_utils.py | Threads optional logger into deps update helpers and removes direct console helper usage. |
| src/apm_cli/commands/config.py | Migrates config command output to CommandLogger. |
| src/apm_cli/commands/compile/cli.py | Migrates compile output to CommandLogger and passes logger into compiler. |
| src/apm_cli/commands/audit.py | Migrates audit output to CommandLogger; threads logger into helpers. |
| src/apm_cli/adapters/client/vscode.py | Threads optional logger through VS Code MCP config operations. |
| src/apm_cli/adapters/client/copilot.py | Uses token manager for Copilot header token selection. |
| docs/src/content/docs/guides/private-packages.md | Updates links to auth + git reference docs. |
| docs/src/content/docs/getting-started/authentication.md | Rewrites auth docs to describe per-(host, org) resolution and security constraint. |
| CHANGELOG.md | Adds Keep-a-Changelog entry for new auth/logging architecture and timeout fix. |
| .github/skills/python-architecture/SKILL.md | Adds skill trigger guidance for architecture changes. |
| .github/skills/cli-logging-ux/SKILL.md | Updates logging UX skill to include CommandLogger rules. |
| .github/skills/auth/SKILL.md | Adds skill trigger guidance and “AuthResolver-only” rule. |
| .github/agents/python-architect.agent.md | Adds agent persona for architecture review. |
| .github/agents/cli-logging-expert.agent.md | Adds agent persona for CLI logging UX review. |
| .github/agents/auth-expert.agent.md | Adds agent persona for authentication review. |
- Fix docs conflating EMU with *.ghe.com — EMU orgs can exist on github.com too; *.ghe.com is specifically GHE Cloud Data Residency - Increase git credential fill timeout: 5s → 60s default (configurable via APM_GIT_CREDENTIAL_TIMEOUT, max 180s) — fixes silent auth failures on Windows when credential helper shows interactive account picker - Add 7 timeout tests - CHANGELOG entry for credential timeout fix Credit: credential timeout fix based on investigation by @frblondin in #389. Co-authored-by: Thomas Caudal <thomas@caudal.fr> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ghu_ is OAuth user-to-server (e.g. gh auth login), NOT EMU. EMU users get regular ghp_ (classic) or github_pat_ (fine-grained) tokens — there is no prefix that identifies EMU. EMU is a property of the account, not the token format. Changes: - detect_token_type: ghu_ → 'oauth', gho_ → 'oauth', ghs_/ghr_ → 'github-app' (was all 'classic') - build_error_context: replace token_type=='emu' check with host-based heuristics (*.ghe.com → enterprise msg, github.com → SAML/EMU mention) - Auth docs: remove ghu_ as EMU prefix, clarify EMU uses standard PATs - Agent persona: correct token prefix reference table - Tests: update detect_token_type + build_error_context assertions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0e12ae5 to
6ddaea4
Compare
Global env vars (GITHUB_APM_PAT, GITHUB_TOKEN, GH_TOKEN) now apply to all hosts — not just the default host. HTTPS is the real transport security boundary; host-gating was unnecessary and forced users into awkward per-org token setups. When a global token doesn't work for a particular host (e.g. github.com PAT on *.ghe.com), try_with_fallback() retries with git credential fill before giving up. This preserves seamless behavior for gh auth login users with multiple hosts. Changes: - auth.py: remove _is_default gate in _resolve_token(), add _try_credential_fallback() in try_with_fallback() - authentication.md: remove Security constraint section, simplify token table, fix EMU example, add HTTPS note - 5 new tests, 3 updated tests (2851 passing) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
resolution_start() was using len(packages) (user-supplied arguments) instead of len(validated_packages) (packages that passed validation). This caused misleading 'Installing N new packages' when some packages failed validation or were already in apm.yml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 52 out of 52 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
src/apm_cli/core/command_logger.py:174
- InstallLogger.validation_pass()/validation_fail() embed Unicode check/cross characters directly in the output strings. Since the console helpers already support ASCII-safe symbols via
symbol=...(seeSTATUS_SYMBOLS), consider switching these to usesymbolinstead of inline glyphs to keep output consistent and Windows-friendly.
def validation_pass(self, canonical: str, already_present: bool):
"""Log a package that passed validation."""
if already_present:
_rich_echo(f" ✓ {canonical} (already in apm.yml)", color="dim")
else:
_rich_success(f" ✓ {canonical}")
def validation_fail(self, package: str, reason: str):
"""Log a package that failed validation."""
_rich_error(f" ✗ {package} — {reason}")
_validate_package_exists was referencing _rich_echo which was not imported, causing a silent NameError caught by the outer try/except. Added _rich_echo import and wired verbose_callback through both try_with_fallback call sites so --verbose shows the full auth resolution chain during package validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verbose output now shows: - Auth resolution summary (host, org, token source, token type) - Sanitized git stderr on each failed attempt (no token leaked) - Full fallback chain visibility: unauth → PAT → credential fill This gives users actionable diagnostics when auth fails. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fine-grained PATs (github_pat_) get 403 when using the
x-access-token:{token}@host URL format because GitHub rejects Basic
auth for these tokens. Switch validation to use:
git -c http.extraHeader='Authorization: Bearer {token}' ls-remote
This works with ALL token types (fine-grained, classic, OAuth, GitHub
App). The x-access-token URL format only works reliably with classic
PATs (ghp_) and GitHub App installation tokens (ghs_).
Note: the broader clone path (_build_repo_url / build_https_clone_url)
still uses x-access-token — tracked for a follow-up fix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
git ls-remote with http.extraHeader has a fatal flaw: the Bearer
header persists across credential-helper retries, preventing git from
using credentials from 'gh auth' or OS keychain when the env-var
token fails.
Switch to GitHub REST API (GET /repos/{owner}/{repo}) which:
- Works with ALL token types (fine-grained, classic, OAuth, App)
- Returns clean HTTP status codes (200=ok, 404=no access, 401=bad token)
- No credential-helper interference
- Faster than spawning git subprocess
The git ls-remote approach remains in the ADO/GHES path where the
API endpoint may differ.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fine-grained PATs are scoped to a single resource owner (user or org). A user-scoped PAT cannot access org repos — even for internal repos where the user is a member. Document required permissions (Metadata Read + Contents Read), resource owner setup, and alternatives. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Wire build_error_context() into validation failure path so verbose mode shows actionable auth guidance (env vars, token setup) - Add '--verbose for auth details' hint when validation fails without verbose mode - Add ADO guard to _try_credential_fallback() preventing credential fill for Azure DevOps hosts (consistent with _resolve_token policy) - Add verbose logging to git ls-remote validation path (ADO/GHE/GHES) matching the GitHub API path's diagnostic output - Add '--verbose for detailed diagnostics' hint to top-level install error handlers - Fix traffic-light violations: orphan removal failure → error (was warning), 'no new packages' → info (was warning), hash mismatch re-download → info/progress (was warning, auto-recovery) - Add 3 new tests for validation failure reason messages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Auth acceptance: - scripts/test-auth-acceptance.sh: 10 P0 auth scenarios covering public/private repos, token priority, fallback chain, error paths. Runnable locally (set tokens + run) or via CI workflow_dispatch. - .github/workflows/auth-acceptance.yml: manual trigger with inputs for test repos, uses auth-acceptance environment for secrets. Logging acceptance: - tests/acceptance/test_logging_acceptance.py: 16 tests verifying install output contract (validation, errors, dry-run, verbose, symbol consistency, diagnostics ordering) — fully mocked, no network needed. Moderate UX fixes: - Route hash mismatch, orphan removal, and lockfile errors through DiagnosticCollector for deferred summary rendering - Fix compile/cli.py color bypasses: _rich_echo(color=yellow/red) replaced with logger.warning()/logger.error() Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add scenarios for: GH_TOKEN fallback, EMU internal repos, credential helper only (gh auth), token type detection, mixed manifest (public + private), ADO with/without PAT, fine-grained PAT wrong resource owner. Update workflow with GHE/ADO inputs and secrets. Fix emoji symbols to ASCII-safe [+]/[x]/[-] matching CLI convention. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Complete rewrite with:
- Top-level scenario matrix documenting all 18 scenarios across 4
dimensions (sources A1-A7, hosts H1/H2/H4, repos V1-V3, tokens T1-T5)
- Per-function docblock explaining the auth dimension, expected behavior,
and WHY the assertion matters
- Full local usage guide covering ALL env vars: GITHUB_APM_PAT,
GITHUB_APM_PAT_{ORG}, GITHUB_TOKEN, GH_TOKEN, ADO_APM_PAT
- All repo types: public, private, EMU internal, ADO
- ASCII-safe symbols matching CLI conventions
- Auto-skip with clear reason when required env vars are missing
- Startup banner showing which tokens and repos are configured
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use tee + PIPESTATUS to stream APM install output to stdout in real-time while capturing it for assertions. Enables live debugging in CI/CD environments — no need to wait for scenario completion to see what happened. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add two new E2E auth scenarios that test the hardest real-world case: a single apm.yml mixing dependencies from multiple auth domains. Scenario 19 (mega-manifest): builds one manifest with all configured repos (public, private, EMU, ADO, second-org) and verifies every dep installs when all tokens are set simultaneously. Scenario 20 (multi-org per-org PAT routing): two private repos from different orgs with ONLY per-org PATs — no global GITHUB_APM_PAT. Validates the resolver routes each dep to its own per-org token. Also fixes: - Replace bash 3.2-incompatible `declare -A` with indexed arrays (macOS portability) - Fix `set -e` bug in run_install that enabled errexit and caused the script to exit on first assertion failure Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rewrite scenario 19 as a truly brutal chaos mega-manifest that mixes every dependency format and auth source in a single apm.yml install: public shorthand, public FQDN, private org A, private org B, EMU internal, and ADO — all in one pass. The resolver must route each dep to its correct token independently. Add --mega flag to run ONLY the chaos manifest (vs progressive mode which runs all 20 scenarios). Usage: set -a && source .env && set +a ./scripts/test-auth-acceptance.sh # progressive (all 20) ./scripts/test-auth-acceptance.sh --mega # chaos mega only Create .env (gitignored) with documented token placeholders and usage instructions for running the test suite locally. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add slots 7 and 8 to the mega-manifest for YAML dict format deps:
- Slot 7: private repo via { git: https://...git } (AUTH_TEST_GIT_URL_REPO)
- Slot 8: public repo via { git: https://...git } (AUTH_TEST_GIT_URL_PUBLIC_REPO)
These test parse_from_dict() — a completely different parser path than
string shorthand or FQDN. Auth resolves from the URL's host+org.
Both slots use separate env vars to avoid unique-key dedup with the
string shorthand slots. Slot 7 falls back to PRIVATE_REPO_2 if unset.
Also updates .env template with the new repo vars.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a transitive dependency fails to download (e.g., auth failure for
an unknown org), error messages now include the full dependency chain
that led to the failure:
Failed to resolve transitive dep other-org/leaf-pkg
(via acme/root-pkg > other-org/leaf-pkg): 401 Unauthorized
Architecture (clean SoC):
- Resolver (_build_parent_chain): computes breadcrumb by walking up
DependencyNode.parent links — it owns the tree structure
- Callback (install.py): receives chain as optional 3rd arg, uses it
for verbose logging and diagnostics — it owns the output
- DownloadCallback type: changed to Callable[...] to accept the new
parent_chain parameter without breaking existing signatures
Transitive failures are now:
1. Logged inline via logger.verbose_detail() (verbose mode)
2. Collected into DiagnosticCollector for the deferred summary (always)
Tests:
- 3 unit tests for _build_parent_chain (3-level, single, None)
- 1 integration test: resolver with callback tracking verifies the
chain string contains parent dep name and '>' separator
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dedup auth, traffic-light fixes - Replace Callable[...] DownloadCallback with typed Protocol class - Move _build_parent_chain() to DependencyNode.get_ancestor_chain() - Remove unused _resolution_path field from resolver - Deduplicate AuthResolver instantiation in _validate_package_exists - Fix traffic-light: 'no deps' warning→info, lockfile failure warning→error - All 2874 tests passing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ebase Wave 1 (verbose coverage): - Add dep tree resolution summary with transitive breadcrumbs - Add auth source/type logging in download phase (verbose only) - Add manifest parsing + per-dep lockfile SHA in verbose output - Add download URL verbose logging via verbose_callback in downloader Wave 2 (CommandLogger migration): - compile/watcher.py: 19 _rich_* calls → CommandLogger - uninstall/engine.py: 15 _rich_* calls → CommandLogger, remove unicode symbols - safe_installer.py: 6 calls with logger fallback pattern - _helpers.py, packer.py, plugin_exporter.py: logger threading - audit.py already migrated (verified) All 2874 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
install.py: - Remove 30 dead else-branch _rich_* fallbacks (logger always available) - Remove 3 duplicate _rich_* calls alongside logger calls - Remove unused _rich_info import; clean test mocks MCPIntegrator: - Add diagnostics param to collect_transitive() and install() - Thread diagnostics from install.py; transitive trust warning uses diagnostics skill_integrator: normalization warning already routes through diagnostics ✅ All 2874 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- command_logger.py: ✓→[+], ✗→[x], —→-- - diagnostics.py: ⚠→[!], ✗→[x], —→-- - install.py: ✓→[+], →→->, —→-- - Updated test assertions to match new ASCII symbols All 2874 tests passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comprehensive handbook for AI Engineers using GitHub Copilot CLI to ship large multi-concern changes via agent fleets. - Three-actor model: User (strategist), Harness (Copilot CLI), Agents (fleet) - Full meta-process: Audit, Plan, Wave Execution, Validate, Ship - Repository instrumentation guide (agents, skills, instructions) - Wave execution model with dependency mapping and parallelization - Test ring pipeline (unit, acceptance, integration) - Escalation protocol and feedback loop for primitive improvement - Autonomous CI/CD patterns for drift detection - Live Dashboard POC via Copilot CLI Hooks (Appendix D) - Prompt examples written from the user's perspective Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…formats - Pipe < /dev/null to apm install in run_install/run_install_manifest to prevent MCP env prompts from blocking in non-interactive test runs - Update mega test assertion to match both validation-phase (source=X) and install-phase (Auth: X) verbose formats Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add mode input (all/mega) to select test mode - Add missing inputs: private_repo_2, git_url_repo, git_url_public_repo - Wire per-org PAT secrets: MCAPS_MICROSOFT, DEVEXPGBB - ADO repo description now shows FQDN format requirement Secrets to configure in 'auth-acceptance' environment: AUTH_TEST_GITHUB_APM_PAT, AUTH_TEST_GITHUB_TOKEN, AUTH_TEST_GH_TOKEN, AUTH_TEST_ADO_APM_PAT, AUTH_TEST_GITHUB_APM_PAT_MCAPS_MICROSOFT, AUTH_TEST_GITHUB_APM_PAT_DEVEXPGBB Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use exact equality for host assertion and endswith() for operation instead of 'in' substring check that CodeQL flagged as incomplete URL sanitization (false positive in test code, but clean fix). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 66 out of 67 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (1)
src/apm_cli/commands/compile/watcher.py:76
- These log lines include manual status markers like
" [x] ...", butCommandLogger.error()already prefixes messages with the[x]symbol via_rich_error(..., symbol="error"). This will result in duplicated symbols in output (e.g.,[x] [x] ...). Remove the inline[x]/[!]prefixes and rely on the logger’ssymbol=handling (or switch toverbose_detail()for indented sub-lines).
self.logger.error("Recompilation failed")
for error in result.errors:
self.logger.error(f" [x] {error}")
…rm patterns
Clarifies the GITHUB_ prefix secret naming workaround, adds multi-org
(GITHUB_APM_PAT_{ORG}) and ADO examples, links to auth guide.
Related: microsoft/apm-action#18
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- auth.py: normalize cache key (host.lower(), org.lower()) to prevent
case-sensitive duplication; gate per-org GITHUB_APM_PAT_{ORG} to
GitHub-like hosts only (not ADO)
- command_logger.py: replace inline Unicode glyphs with symbol= param;
remove leading spaces from validation messages (symbol prefix handles it)
- dependency_graph.py: use Optional[] instead of '|' union syntax
- watcher.py: pass logger to compile(); remove inline [x] prefixes
- token_manager.py: platform-aware GIT_ASKPASS (empty on Unix, echo on Win)
- safe_installer.py: remove inline status prefixes when using logger
- operations.py: map token var names to appropriate purposes (ado, copilot)
- apm_resolver.py: fix DownloadCallback docstring to match actual behavior
- ci-cd.md: trim private deps section, link to auth guide instead of bloat
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k verification failure When packing with --target vscode, the bundle only contains .github/ files but the lockfile still listed .claude/ deployed_files. Unpack verification then failed because those files were 'missing from the bundle'. Fix: enrich_lockfile_for_pack() now filters each dependency's deployed_files to match the pack target. Moved _TARGET_PREFIXES and _filter_files_by_target to lockfile_enrichment (single source of truth), packer imports from there. Fixes microsoft/apm-action test-restore-artifact CI failure with APM 0.8.3. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`existing_lockfile.dependencies` is a Dict[str, LockedDependency]. Iterating it yields string keys, not LockedDependency objects. Use `get_all_dependencies()` to iterate values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Auth + Logging Architecture Overhaul
Closes #393 and #327. Subsumes #389 (credential timeout fix — credit to @frblondin).
Problem
git ls-remoteran without auth.Solution
AuthResolver (
src/apm_cli/core/auth.py)try_with_fallback()retries withgit credential fillautomaticallytry_with_fallback(): unauth-first for validation (saves rate limits), auth-first for downloads, credential-fill fallback on failureCommandLogger (
src/apm_cli/core/command_logger.py)_rich_*helpersInstallLoggersubclass with validation/resolution/download phasesAuth Flow
flowchart TD A[Dependency Reference] --> B{Per-org env var?} B -->|GITHUB_APM_PAT_ORG| C[Use per-org token] B -->|Not set| D{Global env var?} D -->|GITHUB_APM_PAT / GITHUB_TOKEN / GH_TOKEN| E[Use global token] D -->|Not set| F{Git credential fill?} F -->|Found| G[Use credential] F -->|Not found| H[No token] E --> I{try_with_fallback} C --> I G --> I H --> I I -->|Token works| J[Success] I -->|Token fails| K{Credential-fill fallback} K -->|Found credential| J K -->|No credential| L{Host has public repos?} L -->|Yes| M[Try unauthenticated] L -->|No| N[Auth error with actionable message]Provenance Matrix
org/repo(bare)default_host()github.com/org/repocontoso.ghe.com/org/repoGITHUB_HOSTdev.azure.com/org/proj/repoADO_APM_PATonlyGITHUB_APM_PAT_{ORG}→ global → credential fillToken Prefix Classification
github_pat_ghp_ghu_gh auth login, OAuth appsgho_ghs_ghr_Key Design Decisions
try_with_fallback()retries withgit credential fill. This makesgh auth loginfor multiple hosts work seamlessly.GITHUB_APM_PAT_{ORG}always wins regardless of host.APM_GIT_CREDENTIAL_TIMEOUT, max 180s). Fixes Windows credential picker timeouts.Commits
6366f9bfdc7d086ef2511c355d026ddaea437978acTest Coverage