Visitar URL original
fix(install): bundle installs for compile-only targets pass audit; skip Codex Markdown agents (#3705, #3706) by danielmeppiel · Pull Request #3717 · microsoft/apm · GitHub
Skip to content

fix(install): bundle installs for compile-only targets pass audit; skip Codex Markdown agents (#3705, #3706) - #3717

Open
Daniel Meppiel (danielmeppiel) wants to merge 7 commits into
mainfrom
danielmeppiel-bundle-compile-only-targets
Open

Daniel Meppiel (danielmeppiel) wants to merge 7 commits into
mainfrom
danielmeppiel-bundle-compile-only-targets

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

Description

Follow-up to the 0.36.0 round-2 sweep. It implements the two maintainer decisions for bundle installs on compile-only targets.

Issue Behavior Owner routed through Guard
#3705 (option 1) `apm install --target codex gemini opencodeno longer recordsapm_modulescompile staging as deployed files. The staging is recorded in a newlocal_staged_fileslockfile field, soapm audit --cipasses after a clean install,apm compilestill merges it, andapm prune` removes it. Older lockfiles keep compiling.
#3706 (option 2) Bundle installs skip Markdown agents for Codex and print one [!] warning per skipped agent, instead of writing invalid .codex/agents/*.toml. Targets that deploy Markdown agents natively are unchanged. bundle native-layout owner (install/local_bundle_paths._UNSUPPORTED_PLUGIN_FORMAT_IDS, the same path gemini_command uses); guard install-deployment-bundle-native-layout now witnesses the format set. same module + tests/unit/install/test_install_local_bundle.py::test_packed_markdown_agents_are_skipped_for_codex_with_one_warning_each

Per-target rendering of bundle agents for Codex (option 1 of #3706) is tracked separately for 0.37.

Issue and approved scope

Issue: Fixes #3705, Fixes #3706

Human scope-approval comment: maintainer decisions recorded on #3705 and #3706 (sweep record #3649 (comment)).

Fixes #3705
Fixes #3706

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)
Command Result
APM_BINARY_PATH=.venv/bin/apm pytest -p no:xdist tests/integration/test_local_bundle_compile_only_targets_lifecycle.py tests/unit/deps/test_lockfile_local_staging.py tests/unit/install/test_install_local_bundle.py (new guards) 8 failed on main src, 8 passed on this branch
pytest -p no:xdist tests/unit/{install,deps,primitives,compilation,commands,policy} + prune, spec lockfile reqs, bundle e2e and pack suites 10019 passed
owner-rule mutation matrix + confirmed-bypass mutations passed
uvx ruff@0.15.12 check / format --check, pylint R0801, lint-auth-signals.sh, lint-architecture-boundaries.sh clean / 10.00 / clean / exit 0

Spec conformance (OpenAPM v0.1)

Local bundle install copies packed files without a primitive renderer, so
a plugin-native Markdown agent landed unchanged in .codex/agents/*.toml,
which Codex cannot load and apm audit reports as a TOMLDecodeError. Treat
codex_agent like gemini_command in the bundle layout owner: the file is
skipped and one [!] warning names each skipped agent. Targets that deploy
Markdown agents natively are unchanged. The bundle layout guard now
witnesses the unsupported-format set, with a bypass mutation.

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

For targets without native instructions (Codex, Gemini, OpenCode) a local
bundle stages its instructions under apm_modules/<slug>/.apm/instructions/
for apm compile. Those staging paths were recorded in local_deployed_files,
so apm audit --ci reported them as missing/unresolved deployed files and a
clean bundle install could never pass audit.

integrate_local_bundle now returns staged files apart from deployed files;
the ledger owner records them in a new local_staged_files lockfile field
(retiring any pre-#3705 staging claims on reinstall), discovery proves
compile staging roots through LockFile.local_staging_slugs, declarative
installs carry the record forward, and apm prune retires it with the
staging root. Old lockfiles stay readable and keep compiling. New owner
record and guard install-deployment-bundle-compile-staging with a
MutationCase.
apm-spec-waiver: local_staged_files is an implementation-level lockfile extension (schemas allow additional properties); bundle staging is outside the OpenAPM v0.1 surface, so no new req anchor

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@danielmeppiel Daniel Meppiel (danielmeppiel) added this to the 0.36.0 milestone Nov 13, 2026
@danielmeppiel Daniel Meppiel (danielmeppiel) added the type/bug Something does not work as documented. label Nov 13, 2026
Copilot AI balanced review requested due to automatic review settings November 13, 2026 07:44
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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.

🟡 Changes recommended

Legacy bundle reinstalls can leave stale deployment claims that fail CI audits, while pruning absent staging directories leaves records that can incorrectly authorize later compilation.

2 open issues
What changed in this PR

This PR addresses #3705 and #3706 by separating bundle compilation inputs from deployed artifacts and preventing Markdown agents from being installed as invalid Codex TOML files.

Changes:

  • Adds local_staged_files tracking across bundle installation, compilation discovery, lockfile persistence, and pruning.
  • Skips bundled Codex agents with a warning per file.
  • Adds lifecycle tests, architecture guards, and documentation for the new behavior.
File Description
tests/​unit/​scripts/​test_architecture_runner.py Registers the staging guard in expected results.
tests/​unit/​install/​test_install_local_bundle.py Tests Codex agent skipping and warnings.
tests/​unit/​install/​test_install_local_bundle_issue1207.py Separates staging assertions from deployment claims.
tests/​unit/​deps/​test_lockfile_local_staging.py Tests staging persistence, migration, and retirement.
tests/​integration/​test_local_bundle_compile_only_targets_lifecycle.py Covers bundle install, audit, compile, and prune.
tests/​integration/​test_install_local_bundle_e2e.py Updates Codex expectations to exclude agents.
tests/​integration/​test_architecture_owner_rule_mutations.py Tests detection of staging-owner bypasses.
tests/​integration/​test_architecture_confirmed_bypass_mutations.py Guards against copying Markdown into Codex TOML.
src/​apm_cli/​primitives/​discovery.py Uses the lockfile owner to identify staging roots.
src/​apm_cli/​install/​services.py Reports staged files separately from deployed files.
src/​apm_cli/​install/​phases/​lockfile.py Preserves staging records during declarative installs.
src/​apm_cli/​install/​manifest_reconcile.py Includes staged files in cleanup protection.
src/​apm_cli/​install/​local_bundle_paths.py Marks Codex agent rendering as unsupported for bundles.
src/​apm_cli/​install/​local_bundle_handler.py Persists staging results and includes them in summaries.
src/​apm_cli/​deps/​lockfile.py Adds staging serialization, discovery, and retirement.
src/​apm_cli/​core/​deployment_ledger.py Separates staging records from deployment ownership.
src/​apm_cli/​commands/​uninstall/​lockfile_state.py Recognizes staging as persisted lockfile state.
src/​apm_cli/​commands/​prune.py Retires records for removed staging roots.
scripts/​architecture_linter/​diagnostics.py Maps the new guard to its architecture category.
scripts/​architecture_linter/​checks/​marketplace_package_and_registration.py Guards the unsupported bundle format set.
scripts/​architecture_linter/​checks/​install_deployment_analyzers.py Registers the compile-staging rule.
scripts/​architecture_linter/​checks/​install_bundle_compile_staging.py Enforces centralized staging ownership and routing.
packages/​apm-guide/​.apm/​skills/​apm-usage/​commands.md Documents staging and unsupported bundle formats.
docs/​src/​content/​docs/​reference/​lockfile-spec.md Documents local_staged_files.
docs/​src/​content/​docs/​consumer/​deploy-a-bundle.md Explains compilation staging and skipped formats.
CHANGELOG.md Records both bundle-install fixes.
.apm/​architecture/​owners/​install-deployment.json Declares the canonical compile-staging owner.

Review effort: Balanced

Comment thread src/apm_cli/commands/prune.py Resolved
Comment thread src/apm_cli/core/deployment_ledger.py Resolved
…ning count (#3717)

Rewrite a bundle install's lockfile into the pre-#3705 shape (staging as a
local-bundle deployment claim), prove audit --ci fails on it, then show a
bundle reinstall moves the rows to local_staged_files and compile plus
audit --ci pass. Pin the Codex agent case to exactly one [!] skip warning
per skipped agent.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
integrate_local_bundle no longer hashes staged instructions or returns
staged_file_hashes: no caller read them (staging integrity binding is a
follow-up). The dry-run and real deploy paths now share one claim and
hash point, keeping the function within its complexity budget.

LockFile.local_staging_slugs skips empty, '.', '..' and separator- or
drive-bearing slugs as defense in depth; discovery keeps its
ensure_path_within confinement.

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

Copy link
Copy Markdown
Collaborator Author

APM Review Panel: ship_with_followups

Bundle installs on compile-only targets (Codex, Gemini, OpenCode) now pass audit; staging is tracked, not deployed, and Markdown agents are skipped with a warning.

panel-mode=lean; personas=python-architect,supply-chain-security-expert,test-coverage-expert,apm-ceo

cc Daniel Meppiel (@danielmeppiel) Sergio Sisternes (@sergio-sisternes-epam) -- a fresh advisory pass is ready for your review.

All three panelists converge. The python-architect confirms the lockfile extension is single-owner, backward-compatible and linter-guarded. The supply-chain-security-expert validates path safety on the write side (validated slugs) and the read side (ensure_path_within in discovery, lockfile-proven staging roots only). The test-coverage-expert confirms both decisions are defended at lifecycle tier; the folded migration test reproduces the #3705 audit failure on the old lockfile shape and passes after reinstall.

Folded at this head: the dead staged_file_hashes computation is removed, local_staging_slugs rejects traversal and drive-style slugs, and the lifecycle module now covers the pre-#3705 lockfile migration and the exact Codex skip-warning count. The one deferred item, hash-binding staged compile input, is additive security scope beyond the approved decision (staged content was never hash-verified before either) and is tracked in #3718.

Aligned with: secure by default (only lockfile-proven, slug-validated staging roots compile); governed by policy (new owner record and guard with a MutationCase); pragmatic as npm (bundle installs just work on compile-only targets, one clear warning per skipped agent); multi-harness (Codex, Gemini and OpenCode all pass audit after a bundle install).

Panel summary

Persona B R N Takeaway
Python Architect 0 0 1 Clean single-owner extension; lockfile owns the staging record and the linter guards path-shape leaks. Nit folded.
Supply Chain Security Expert 0 1 1 Path safety adequate on write and read; staged hashes were computed but discarded (deferred to #3718). Slug nit folded.
Test Coverage Expert 0 2 0 Both decisions defended at lifecycle tier; migration and warning-count gaps folded.

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

Top 1 follow-ups

  1. [Supply Chain Security Expert] Persist staged file hashes so on-disk edits to compile input are detected before apm compile merges it -- additive hardening beyond the approved [BUG] Installing a bundle for Codex, Gemini or OpenCode always fails apm audit --ci with missing deployed files #3705 decision; tracked in Record content hashes for bundle compile staging so edits before apm compile are detected #3718.

Recommendation

Merge for 0.36.0 once CI is green. The deferred staged-file integrity binding is tracked in #3718; the surface it addresses existed identically before this PR and is narrowed here by the lockfile-proven-roots-only discovery rule.


Full per-persona findings

Python Architect

  • [nit] staged_file_hashes computed in integrate_local_bundle but never consumed at src/apm_cli/install/services.py
    Dead data in the return dict. Folded in bf33db0.

Supply Chain Security Expert

Test Coverage Expert

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


Generated by autopilot-pr-review-worker. This comment is AI-generated and may contain errors.

)

Copilot review folds on #3717:
- apm prune now plans staging records whose apm_modules/<slug> root is
  already gone (LockFile.absent_staging_slugs) before its early return and
  retires them, so a recreated directory is no longer lockfile-proven
  compile input. Dry runs only report; failed deletions keep their rows.
- record_local_bundle_files migrates every prior bundle-owned staging
  claim into local_staged_files through the shared local_staging_slug
  classifier, not only paths re-staged this run, so an omitted or
  collision-skipped instruction no longer keeps apm audit --ci failing.
  Bytes are untouched.

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/bug Something does not work as documented.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Installing a bundle copies Markdown agents verbatim into .codex/agents/*.toml, which Codex cannot load [BUG] Installing a bundle for Codex, Gemini or OpenCode always fails apm audit --ci with missing deployed files

2 participants