[PR #154] [MERGED] fix(snapshot): preserve exported image config #215

Closed
opened 2026-10-29 14:21:06 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/kvcache-ai/AgentENV/pull/154
Author: @huajq
Created: 8/11/2026
Status: ✅ Merged
Merged: 8/13/2026
Merged by: @yingdi-shan

Base: main ← Head: fix/snapshot-image-oci-config


📝 Commits (1)

  • 849a3b5 fix(snapshot): preserve exported image config

📊 Changes

7 files changed (+305 additions, -40 deletions)

View changed files

📝 docs/src/concepts/snapshots.md (+11 -0)
📝 src/snapshot/image_export/service.rs (+34 -9)
📝 src/snapshot/repository/backends/common/acr/manifest.rs (+210 -20)
📝 src/snapshot/repository/backends/common/acr/mod.rs (+2 -2)
📝 src/snapshot/repository/backends/common/acr/publisher.rs (+27 -4)
📝 src/snapshot/repository/backends/oss/repository.rs (+10 -3)
📝 src/types/image_configs.rs (+11 -2)

📄 Description

What

Preserve effective snapshot runtime configuration when publishing committed snapshot rootfs layers as OCI images.

Both snapshot image paths now generate the OCI config from the committed snapshot metadata instead of always publishing a minimal empty config:

  • aenv-snapshot-image
  • automatic OSS source-registry publication

Why

Snapshot image publication previously preserved the OverlayBD rootfs layer stack but replaced the OCI runtime config with Env=[] and WorkingDir="", omitting fields such as User, Entrypoint, Cmd, ExposedPorts, Volumes, Labels, and StopSignal.

The resulting image could be reused as a userImage, but its runtime behavior differed from the source snapshot. This made published snapshot images filesystem-correct but configuration-incomplete.

N/A

Scope and non-goals

Included:

  • Preserve effective Env, WorkingDir, User, Entrypoint, Cmd, ExposedPorts, Volumes, and Labels from CommandContext.
  • Preserve unmodeled source OCI config fields such as StopSignal and Healthcheck when a raw rootfs config is available.
  • Apply the same config-building behavior to standalone export and automatic source-registry publication.
  • Keep deterministic config bytes and manifest digests.
  • Keep attached-drive image publication on the existing minimal config path.
  • Document runtime config preservation and immutable-tag behavior.

Excluded:

  • Making OverlayBD-native images portable to arbitrary OCI runtimes.
  • Persisting or reconstructing full original OCI config documents, including architecture, history, or DiffIDs.
  • Converting AgentENV StartupCommand.start_cmd into OCI Entrypoint/Cmd.
  • Migrating or overwriting existing published tags.

Design and behavior changes

A shared snapshot OCI config builder now:

  1. Selects the rootfs raw config entry from ImageConfigs using drive_id == None and mount_path == "/".
  2. Uses the raw OCI config object as the base when present.
  3. Replaces AgentENV-managed fields with the effective committed CommandContext.
  4. Removes stale raw fields when the effective context no longer defines them.
  5. Preserves unmodeled raw fields such as StopSignal and Healthcheck.
  6. Canonically sorts JSON object keys and environment entries so identical metadata produces deterministic bytes and digests.

SnapshotImageService uses the committed snapshot context and rootfs raw config when exporting through aenv-snapshot-image.

OSS snapshot publication passes the same metadata into the ACR exporter for rootfs images. Attached-drive publication passes no runtime config and keeps the existing minimal config behavior.

Compatibility and operations

  • Public API or generated protocol: N/A. No public API or generated protocol changes.
  • Configuration or defaults: N/A. No configuration keys or defaults changed.
  • Snapshot manifest, artifact layout, or storage format: N/A. The committed snapshot repository schema is unchanged.
  • Upgrade and rollback: Existing published image tags remain immutable. Re-exporting a snapshot after this change can produce a different config and manifest digest; users must choose a new tag or delete the old tag before republishing.
  • Host requirements, permissions, ports, or dependencies: N/A. No new host requirements or dependencies.

Validation

  • make fmt
  • make clippy
  • make test-unit
  • Relevant Rust integration tests
  • make -C services test (required when services/ changes)
  • Generated clients/server regenerated with the documented make target
  • Documentation updated
  • Benchmarks or performance comparison completed

Commands and results:

cargo fmt --all -- --check
# passed

git diff --check
# passed

cargo test -p agentenv --lib -- \
  snapshot::repository::backends::common::acr \
  snapshot::image_export \
  types::image_configs
# 43 passed; 0 failed

cargo clippy -p agentenv --lib --tests -- -D warnings
# passed

Skipped checks and reasons:

  • make test-unit: not claimed for the final rebased tree. Earlier full runs reached 695 passed with one pre-existing remote-host capability failure in privileges::tests::scoped_spawn_clears_child_capabilities_without_mutating_caller, which also fails when run alone and is unrelated to these files.
  • Relevant Rust integration tests: not run; this change is covered by focused unit and fake-registry publication tests.
  • make -C services test: skipped because services/ was not changed.
  • Generated clients/server regeneration: not needed; no generated code or schema source changed.
  • Benchmarks: not run; this change only alters metadata construction and registry publication config bytes.

Risks and reviewer notes

Main review areas:

  • src/snapshot/repository/backends/common/acr/manifest.rs: config merge and deterministic serialization semantics.
  • src/snapshot/image_export/service.rs: standalone export wiring.
  • src/snapshot/repository/backends/oss/repository.rs: rootfs metadata wiring.
  • src/snapshot/repository/backends/common/acr/publisher.rs: attached drives must continue to receive None and use the minimal config.

Compatibility risk: published config/manifest digests change for snapshots that previously had non-default runtime metadata. The existing conflict protection intentionally prevents overwriting old tags.

StartupCommand remains snapshot metadata only; it is intentionally not inferred back into OCI Entrypoint or Cmd.

Checklist

  • The PR contains one coherent change and no unrelated formatting or refactoring.
  • New behavior is covered by tests, or I explained why testing is impractical.
  • Logs and examples contain no credentials, tokens, or private registry information.
  • I did not manually edit generated code without updating its source and regenerating it.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/kvcache-ai/AgentENV/pull/154 **Author:** [@huajq](https://github.com/huajq) **Created:** 8/11/2026 **Status:** ✅ Merged **Merged:** 8/13/2026 **Merged by:** [@yingdi-shan](https://github.com/yingdi-shan) **Base:** `main` ← **Head:** `fix/snapshot-image-oci-config` --- ### 📝 Commits (1) - [`849a3b5`](https://github.com/kvcache-ai/AgentENV/commit/849a3b5604b69f92b0e7f0f361009146ec46702a) fix(snapshot): preserve exported image config ### 📊 Changes **7 files changed** (+305 additions, -40 deletions) <details> <summary>View changed files</summary> 📝 `docs/src/concepts/snapshots.md` (+11 -0) 📝 `src/snapshot/image_export/service.rs` (+34 -9) 📝 `src/snapshot/repository/backends/common/acr/manifest.rs` (+210 -20) 📝 `src/snapshot/repository/backends/common/acr/mod.rs` (+2 -2) 📝 `src/snapshot/repository/backends/common/acr/publisher.rs` (+27 -4) 📝 `src/snapshot/repository/backends/oss/repository.rs` (+10 -3) 📝 `src/types/image_configs.rs` (+11 -2) </details> ### 📄 Description ## What Preserve effective snapshot runtime configuration when publishing committed snapshot rootfs layers as OCI images. Both snapshot image paths now generate the OCI config from the committed snapshot metadata instead of always publishing a minimal empty config: - `aenv-snapshot-image` - automatic OSS source-registry publication ## Why Snapshot image publication previously preserved the OverlayBD rootfs layer stack but replaced the OCI runtime config with `Env=[]` and `WorkingDir=""`, omitting fields such as `User`, `Entrypoint`, `Cmd`, `ExposedPorts`, `Volumes`, `Labels`, and `StopSignal`. The resulting image could be reused as a `userImage`, but its runtime behavior differed from the source snapshot. This made published snapshot images filesystem-correct but configuration-incomplete. ## Related issue N/A ## Scope and non-goals Included: - Preserve effective `Env`, `WorkingDir`, `User`, `Entrypoint`, `Cmd`, `ExposedPorts`, `Volumes`, and `Labels` from `CommandContext`. - Preserve unmodeled source OCI config fields such as `StopSignal` and `Healthcheck` when a raw rootfs config is available. - Apply the same config-building behavior to standalone export and automatic source-registry publication. - Keep deterministic config bytes and manifest digests. - Keep attached-drive image publication on the existing minimal config path. - Document runtime config preservation and immutable-tag behavior. Excluded: - Making OverlayBD-native images portable to arbitrary OCI runtimes. - Persisting or reconstructing full original OCI config documents, including `architecture`, `history`, or DiffIDs. - Converting AgentENV `StartupCommand.start_cmd` into OCI `Entrypoint`/`Cmd`. - Migrating or overwriting existing published tags. ## Design and behavior changes A shared snapshot OCI config builder now: 1. Selects the rootfs raw config entry from `ImageConfigs` using `drive_id == None` and `mount_path == "/"`. 2. Uses the raw OCI `config` object as the base when present. 3. Replaces AgentENV-managed fields with the effective committed `CommandContext`. 4. Removes stale raw fields when the effective context no longer defines them. 5. Preserves unmodeled raw fields such as `StopSignal` and `Healthcheck`. 6. Canonically sorts JSON object keys and environment entries so identical metadata produces deterministic bytes and digests. `SnapshotImageService` uses the committed snapshot context and rootfs raw config when exporting through `aenv-snapshot-image`. OSS snapshot publication passes the same metadata into the ACR exporter for rootfs images. Attached-drive publication passes no runtime config and keeps the existing minimal config behavior. ## Compatibility and operations - Public API or generated protocol: N/A. No public API or generated protocol changes. - Configuration or defaults: N/A. No configuration keys or defaults changed. - Snapshot manifest, artifact layout, or storage format: N/A. The committed snapshot repository schema is unchanged. - Upgrade and rollback: Existing published image tags remain immutable. Re-exporting a snapshot after this change can produce a different config and manifest digest; users must choose a new tag or delete the old tag before republishing. - Host requirements, permissions, ports, or dependencies: N/A. No new host requirements or dependencies. ## Validation - [x] `make fmt` - [x] `make clippy` - [ ] `make test-unit` - [ ] Relevant Rust integration tests - [ ] `make -C services test` (required when `services/` changes) - [ ] Generated clients/server regenerated with the documented `make` target - [x] Documentation updated - [ ] Benchmarks or performance comparison completed Commands and results: ```text cargo fmt --all -- --check # passed git diff --check # passed cargo test -p agentenv --lib -- \ snapshot::repository::backends::common::acr \ snapshot::image_export \ types::image_configs # 43 passed; 0 failed cargo clippy -p agentenv --lib --tests -- -D warnings # passed ``` Skipped checks and reasons: - `make test-unit`: not claimed for the final rebased tree. Earlier full runs reached 695 passed with one pre-existing remote-host capability failure in `privileges::tests::scoped_spawn_clears_child_capabilities_without_mutating_caller`, which also fails when run alone and is unrelated to these files. - Relevant Rust integration tests: not run; this change is covered by focused unit and fake-registry publication tests. - `make -C services test`: skipped because `services/` was not changed. - Generated clients/server regeneration: not needed; no generated code or schema source changed. - Benchmarks: not run; this change only alters metadata construction and registry publication config bytes. ## Risks and reviewer notes Main review areas: - `src/snapshot/repository/backends/common/acr/manifest.rs`: config merge and deterministic serialization semantics. - `src/snapshot/image_export/service.rs`: standalone export wiring. - `src/snapshot/repository/backends/oss/repository.rs`: rootfs metadata wiring. - `src/snapshot/repository/backends/common/acr/publisher.rs`: attached drives must continue to receive `None` and use the minimal config. Compatibility risk: published config/manifest digests change for snapshots that previously had non-default runtime metadata. The existing conflict protection intentionally prevents overwriting old tags. `StartupCommand` remains snapshot metadata only; it is intentionally not inferred back into OCI `Entrypoint` or `Cmd`. ## Checklist - [x] The PR contains one coherent change and no unrelated formatting or refactoring. - [x] New behavior is covered by tests, or I explained why testing is impractical. - [x] Logs and examples contain no credentials, tokens, or private registry information. - [x] I did not manually edit generated code without updating its source and regenerating it. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-29 14:21:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kvcache-ai/AgentENV#215
No description provided.