Skip to content

[BUG] apm audit --ci misses local-path sub-package MCP declaration REMOVAL (exits 0); change-drift exits 1 #2136

Description

@danielmeppiel

Describe the bug

apm audit --ci config-consistency detects when a locally-installed local-path sub-package changes its MCP server config, but does not detect when that sub-package removes its entire dependencies.mcp declaration after install. When the recorded mcp_configs lockfile baseline has a server that the current source no longer declares, audit still reports "All checks passed" and exits 0. The drift-detection guarantee is one-directional: it compares current-source entries against the lock baseline but ignores lock-only (removed) entries.

This is the removal sibling of #2127 (change-drift). The pending fix for #2127 (#2132) was empirically verified to fix the change sub-case but still miss removal: overlaying #2132's ci_checks.py on a working build leaves the post-removal audit at exit 0.

To Reproduce

Baseline SHA: 26d8cee8a4079bb3d31956f1b57d343654835fc8 (origin/main).

  1. Consumer apm.yml declares a local dependency ./packages/agent-config.
  2. ./packages/agent-config/apm.yml declares one MCP server (dependencies.mcp with name/command/args).
  3. apm install --force --trust-transitive-mcp --target copilot --no-policy -> exit 0; server recorded in apm.lock.yaml mcp_configs.
  4. apm audit --ci --no-policy --no-fail-fast (baseline, source unchanged) -> exit 0 (correct).
  5. Edit ./packages/agent-config/apm.yml to delete the entire dependencies.mcp block.
  6. apm audit --ci --no-policy --no-fail-fast -> exit 0, "All checks passed" (BUG; should be exit 1 with a source-vs-lock drift diagnostic).

Expected behavior

Audit must compare the complete current MCP declaration graph against the stored lock baseline symmetrically: changed, added, AND removed declarations must all affect the consistency verdict. A removed source declaration that still exists in the lock baseline is drift and must exit 1.

Environment

  • OS: macOS
  • APM Version: 0.24.1 (26d8cee8a)

Root-cause (architecture)

src/apm_cli/policy/ci_checks.py::_check_config_consistency derives current_configs only from present manifest declarations and diffs one-directionally, so lock-only (removed) servers are never compared. Recommended fix (architecture cluster r2-symmetric-source-lock-consistency): introduce a side-effect-free current-MCP-config view resolver plus one symmetric source-vs-lock diff (changed / source-only / lock-only) consumed by _check_config_consistency and install/update reconciliation. Keep mcp_config_provenance for ownership classification, not as a blanket removal exemption. Vendor-neutral, no primitive-schema change, no harness translation layer.

Additional context

Filed from an authorized first-party reliability/regression validation sweep (red-team Round 2). Independently reproduced twice by a separate confirmer (finder != confirmer), with control (unchanged source exits 0) and cleanup verification. Distinct from #2127/#2132 (change vs removal).

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/audit-policyapm-policy.yml schema, custom_checks, install-time enforcement.area/lockfileLockfile schema, per-file provenance, integrity hashes, drift detection.priority/highShips in current or next milestonestatus/triagedInitial agentic triage complete; pending maintainer ratification (silence = approval).theme/securitySecure by default. Content scanning, lockfile integrity, MCP trust boundaries.type/bugSomething does not work as documented.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions