Repository navigation
feat(bundle): add non-activating package resources - #3175
Draft
Daniel Meppiel (danielmeppiel) wants to merge 4 commits into
Draft
Daniel Meppiel (danielmeppiel) wants to merge 4 commits into
Daniel Meppiel (danielmeppiel) wants to merge 4 commits into
Conversation
Add opt-in working-draft resource directory selection and source-mode APM pack/restoration. Preserve exact author metadata and content without deployment, using existing bounded inventory, archive and integrity owners. Reject unsafe or ambiguous content and marked envelopes on deployment routes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep strict source metadata size and duplicate-key rules scoped to source operations. Probe deployment markers through the existing bounded YAML loader so valid unmarked legacy locks retain their prior semantics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep envelope hashes authoritative through final staged verification, reject source markers in both accepted lockfile names, and publish source directories through shared native atomic no-replace operations. Add deterministic mutation, admission, collision and unsupported-capability regressions; preserve exclusive archive publication and ordinary legacy lock semantics. 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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
add(bundle): preserve non-activating package resources
Description
TL;DR
Add opt-in
resourcesdirectory roots,apm pack --format apm --source, andapm unpack --sourcefor package-owned contracts/checks that must travel as inert bytes. Preserve original manifest, lockfile, resource paths and contents in the existing APM directory/ZIP/tar envelope. Restore only into a new directory after mandatory verification; unsupported deployment/plugin routes refuse instead of silently dropping resources.Important
This is working-draft, source-only functionality, not a normative OpenAPM change or an official native release. No APMX backend repin, model invocation, version bump, release or tag is included.
Problem (WHY)
The missing capability is an explicit non-activating resource route, not a claim that plugin formats must represent arbitrary package files.
Approach (WHAT)
resources: [contracts, checks]; omit$schemato use the working draft.apm.lock.yamlholdspack.source: trueandpack.bundle_files;package/holds untouched author metadata and resources.apm.lock.yamlandapm.lock.Implementation (HOW)
Code paths below are relative to
src/apm_cli/; other paths are repository-relative.models/apm_package.py,models/package_resources.pybundle/source_package.pybundle/packer.py,bundle/unpacker.py,bundle/lockfile_enrichment.pybundle/plugin_exporter.py,bundle/agent_plugin_exporter.py,bundle/local_bundle.py,models/format_detection.pycommands/pack.py,cli.py,core/build_orchestrator.pyagent_plugins/assets.py,utils/archive.py,utils/path_security.py,utils/yaml_io.pyutils/atomic_io.py.apm/architecture/owners/{contracts-tooling,marketplace-plugins}.json,scripts/architecture_linter/checks/marketplace_package_and_registration.pytests/unit/bundle/test_source_package.py,tests/unit/utils/test_atomic_io.py,tests/unit/scripts/test_architecture_runner.py,tests/integration/test_source_package_cli.py,tests/integration/test_architecture_source_resources.py,tests/utils/source_package.pydocs/src/content/docs/producer/pack-a-bundle.md,docs/src/content/docs/reference/{manifest-schema,cli/pack,cli/unpack}.md,packages/apm-guide/.apm/skills/apm-usage/{commands,package-authoring}.mdDiagrams
The new source path keeps original author files separate from envelope metadata; deployment admission is a refusal branch, not restoration.
flowchart LR subgraph Pack["Opt-in source packing"] A["apm.yml resources and original lock"] B["collect_package_resources"] C["pack_source_package"] end subgraph Envelope["Existing APM envelope"] D["pack.source and bundle_files hashes"] E["package: exact author files"] end subgraph Restore["Verified inert restoration"] F["_verify_source_package"] G["_copy_assets: original envelope hashes"] H["publish_directory_noreplace: new output only"] end A --> B --> C C --> D C --> E D --> F E --> F F --> G --> H D --> J["reject_source_deployment"] J --> K["install and legacy unpack refuse"] classDef new stroke-dasharray: 5 5; class B,C,D,F,G,H,J new;Trade-offs
package/prefix preserves exact originalapm.ymlandapm.lock.yaml, including comments and line endings; restoration removes only that prefix.Benefits
Issue and approved scope
Issue: Related to #3174 (bounded upstream source-resource tracking).
Human scope-approval comment: Pending / not publicly recorded. The bounded implementation and draft publication were explicitly approved in private maintainer conversation, but no public human scope-approval comment or review-contact designation exists yet. This draft does not substitute conversational approval, an automated recommendation, or a label for that required record.
This PR implements the bounded upstream source-resource route. Public human scope approval, review-contact designation, and PR/CI review remain pending; no issue-closing keyword is used. Official release/native assets and downstream APMX repinning remain separate, excluded gates.
Warning
Keep this PR draft and ineligible for ready/merge until a responsible maintainer posts the real public scope record. No scope-approval decision, acceptance label, private-security exemption, or trivial-documentation exemption is asserted.
Type of change
Testing
Validation
Scoped results at reviewed
726f492, not a full-suite or remote-CI claim: 868 passed, 1 skipped, 64 quality tests passed, 14 docs-tool tests passed. The expected duplicate-ZIP warning comes from an adversarial fixture. Independent follow-up reported 156 focused tests passed plus disposable mutation, legacy-admission and real macOS collision probes; all three findings were cleared.CI follow-up: the first Linux shard-2 run exposed a stale lazy
unpackhelp string and the missing new rule ID in the exact architecture inventory. Both failures were reproduced locally, then corrected without weakening either assertion or changing resource logic. The expanded regression command passed:Result: 236 passed, 1 expected duplicate-ZIP warning in 39.73s. Updated remote CI remains a separate gate.
Exact impacted test command and recorded summary
Exact quality, docs-tool and canonical pre-push commands
The docs tool's intentional broken-link fixture diagnostic is expected; no full Astro build is claimed. Each command below passed on the reviewed HEAD after refreshing/merging
origin/main(already up to date):Ruff: 1930 files formatted; pylint: 10.00/10; auth/architecture and both test ratchets clean. The YAML-write, 2100-line and raw-relative-path guards also passed using equivalent Python regex/file scans on macOS.
Scenario Evidence
tests/integration/test_source_package_cli.py::test_source_archive_survives_author_removaltests/unit/bundle/test_source_package.py::test_no_execution_and_no_other_build_producerstests/integration/test_source_package_cli.py::test_real_cli_rejects_damaged_source_archives;tests/unit/bundle/test_source_package.py::test_strict_archives_reject_ambiguous_memberstests/unit/bundle/test_source_package.py::test_reinventory_cannot_replace_envelope_hash_authority(review regression trap)tests/unit/bundle/test_source_package.py::test_all_source_marker_names_block_deployment;test_source_probe_preserves_legacy_metadata_semantics(review regression traps)tests/unit/bundle/test_source_package.py::test_directory_publication_preserves_racing_empty_destination;test_archive_publication_preserves_racing_destination(review regression traps)tests/unit/bundle/test_source_package.py::test_deployment_formats_refuse_resource_loss;test_resources_are_not_a_normative_contractSeparate real-factory evidence, without private paths or logs
An isolated copy of the current factory contained 19 resources plus original author-fixture manifest and a genuine CLI-generated lock. Frozen dry-run validated the retained lock; ZIP/tar source packing and restoration preserved all 21 path/hash/size/mode identities, including lock mode 0600. Only the owned author copy was deleted before restoration; the original checkout stayed unchanged and staging was cleaned.
Recorded argument vectors below replace the machine-specific interpreter and scratch paths with variables; they are not native-release commands:
All five commands exited 0. The ordinary frozen dry-run is author-fixture lock validation, not a claim that install is non-activating. No raw proof logs, private paths or tokens are published.
How to test
uv run --extra dev pytest -q tests/unit/bundle/test_source_package.py tests/unit/utils/test_atomic_io.py tests/integration/test_source_package_cli.py tests/integration/test_architecture_source_resources.pyfrom this checkout; roundtrips and review regression traps must pass.tests/utils/source_package.py::make_source_packagefixture in a disposable directory, then run this checkout's CLI withpack --format apm --source --archive; restore withunpack --source ARCHIVE -o NEW_DIRECTORYand compare every payload byte.--archive-format tar.gz, and without--archivefor directory form; original manifest/lock bytes must remain unchanged.--skip-verify; expect refusal and untouched consumer content. Try ordinary install/unpack of a source envelope; expect refusal, not activation.Spec conformance (OpenAPM v0.1)
If this PR changes behaviour that an OpenAPM v0.1
req-XXXcovers,confirm the three-step ritual in the
development guide:
docs/src/content/docs/specs/openapm-v0.1.mdupdated(new/changed
<a id="req-XXX"></a>anchor + prose + Appendix Crow).
docs/src/content/docs/specs/manifests/openapm-v0.1.requirements.ymlupdated.
@pytest.mark.req("req-XXX")test undertests/spec_conformance/added or extended.CONFORMANCE.{md,json}regenerated viauv run --extra dev python -m tests.spec_conformance.gen_statementand committed.
resourcesis rejected with an explicit normative$schema; no normative specification or schema is revised.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com