Skip to content

feat(oci): add reproducible host path copy layers - #10952

Merged
jdx merged 4 commits into
mainfrom
codex/oci-copy-layers
Jul 13, 2026
Merged

jdx merged 4 commits into
mainfrom
codex/oci-copy-layers

Conversation

@jdx

@jdx jdx commented Jul 12, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add repeatable mise oci build --copy HOST_PATH:IMAGE_PATH support
  • add matching repeated [[oci.copy]] configuration entries
  • emit each file, directory, or symlink payload as an independent reproducible layer annotated with dev.mise.copy
  • validate absolute image paths and preserve normalized ownership/executable modes
  • document the new primitive and add unit/e2e coverage

Closes the feature request discussed in #10934.

Validation

  • cargo test oci::layer::tests
  • mise run test:e2e e2e/oci/test_oci_build_slow
  • mise run lint-fix

Note

Medium Risk
New OCI build surface can embed arbitrary host filesystem content into images (with a secrets warning); behavior is well validated but mistakes could leak local files into published images.

Overview
mise oci build can now copy arbitrary host paths into the image as independent, content-addressed layers (after per-tool layers), via repeatable --copy HOST_PATH:IMAGE_PATH and [[oci.copy]] in mise.toml.

Each payload is built with build_layer_from_path (files, dirs, or symlinks; dirs map contents under the absolute image path without appending the source name). Layers are tagged with dev.mise.copy=<image path>. Image destinations must be absolute with no . / ..; config-relative host paths resolve from the declaring config file, CLI paths from CWD; layered configs append copies so more-specific targets win, with CLI copies last. The builder warns about secrets in copied paths. oci run / oci push pass an empty copy when they trigger a build.

Docs, usage/man output, unit tests, and e2e coverage for annotated layers and tar contents are included.

Reviewed by Cursor Bugbot for commit b6824ac. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features
    • Added a repeatable mise oci build --copy HOST_PATH:IMAGE_PATH option to copy host files, directories, or symlinks into the OCI image as independent layers.
    • Added [oci] / [[oci.copy]] configuration support for declaring these copy layers.
  • Documentation
    • Updated the CLI manual and developer docs with --copy / [[oci.copy]] usage, destination path rules, and copy layer semantics/annotations.
  • Bug Fixes
    • Relative [[oci.copy]] source paths in config files are now resolved relative to the declaring config directory.
  • Tests
    • Expanded e2e coverage to validate copied contents and emitted OCI layer annotations.

Entire-Checkpoint: 50d575aaefdb
@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

mise oci build now accepts repeatable host-to-image copy mappings from the CLI or [oci] configuration. Each mapping is validated and emitted as an independent annotated OCI layer, with coverage for files, directories, configuration, and end-to-end image contents.

Changes

OCI copy support

Layer / File(s) Summary
Copy contract and entry points
src/oci/mod.rs, src/cli/oci/common.rs, src/cli/oci/build.rs, mise.usage.kdl, docs/cli/oci/build.md, docs/dev-tools/mise-oci.md, man/man1/mise.1
OciCopy validates and parses HOST_PATH:IMAGE_PATH values, configuration copies are merged and resolved relative to declaring config files, and the repeatable --copy option is documented and wired into OCI builds.
Copy layer construction and manifest wiring
src/oci/builder.rs, src/oci/layer.rs
Host files, symlinks, and directories become reproducible layers; copy layers are annotated and appended to the manifest and rootfs diff IDs.
Command compatibility and end-to-end verification
src/cli/oci/push.rs, src/cli/oci/run.rs, e2e/oci/test_oci_build_slow
Push and run supply empty copy lists when applicable, while unit and end-to-end tests verify validation, annotations, copied tar contents, and configuration path resolution.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant OciBuild
  participant Builder
  participant build_layer_from_path
  participant OCIManifest
  User->>OciBuild: provide --copy HOST_PATH:IMAGE_PATH
  OciBuild->>Builder: pass CLI and configured OciCopy entries
  Builder->>build_layer_from_path: build a layer from each host path
  build_layer_from_path-->>Builder: return layer blob and diff_id
  Builder->>OCIManifest: add annotated copy layers to manifest
Loading

Possibly related PRs

  • jdx/mise#10075: Adds configurable OCI layer ownership used by copy-layer construction.
  • jdx/mise#10373: Also changes OCI builder layer insertion and manifest diff-ID ordering.
  • jdx/mise#10376: Also modifies OCI layer annotations and related end-to-end assertions.

Poem

A bunny packs paths in a layer so neat,
Files and directories find their seat.
Annotations mark each copied way,
Reproducible layers join the array.
Hop-hop, the image is ready today!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding reproducible OCI host-path copy layers.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread src/oci/mod.rs Resolved
@greptile-apps

greptile-apps Bot commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a repeatable --copy HOST_PATH:IMAGE_PATH flag to mise oci build and a matching [[oci.copy]] config section, letting users bake arbitrary host files, directories, or symlinks into the OCI image as independent, content-addressed layers annotated with dev.mise.copy=<image path>.

  • OciCopy struct and validation — validate_image_path rejects relative, root (/), and dotted paths; FromStr uses a right-split on : to preserve Windows drive letters; fill_defaults_from accumulates copy lists (less-specific config first, CLI last) so the most-specific entry wins when the same image path appears more than once.
  • build_layer_from_path — new public function in layer.rs that dispatches to build_layer_from_dir for directories and emits a single-entry tar for files/symlinks, preserving executable bits and applying the configured owner; resolve_copy_paths in common.rs rebases relative host paths to the declaring config file's directory rather than CWD.
  • Builder integration — copy layers are built and written to the manifest between the tool layers and the dotfiles layer, each annotated with dev.mise.copy; push and run subcommands pass copy: vec![] so only config-declared copies apply (no new --copy flag on those subcommands).

Confidence Score: 5/5

Safe to merge; all new code is confined to the experimental OCI build path and the logic is well-tested.

The feature is well-scoped: validation, path resolution, layer construction, and manifest annotation all follow existing patterns in the codebase. Unit tests cover file, directory, and error cases; an e2e test verifies layer ordering and tarball contents end-to-end. The only issues found are cosmetic — duplicate step-comment numbers in builder.rs and a missing warning for absolute symlink targets in the single-symlink code path, both of which carry no correctness impact.

No files require special attention; the cosmetic comment-numbering issue in src/oci/builder.rs and the missing warning in src/oci/layer.rs are the only items worth a follow-up.

Important Files Changed

Filename Overview
src/oci/layer.rs Adds build_layer_from_path for single-file, directory, or symlink copies; correctly handles files/dirs, includes 3 new unit tests; symlinks with absolute targets are silently copied without warning.
src/oci/builder.rs Adds copy-layer build and write sections (steps 5/6); copy layers are inserted correctly between tool layers and dotfiles in the manifest; comment step numbers are duplicated after insertion.
src/oci/mod.rs Adds OciCopy struct with FromStr (Windows-safe right-split on :) and validate_image_path catching root/relative/dotted paths; fill_defaults_from correctly accumulates copies in less-specific-first order.
src/cli/oci/common.rs Adds resolve_copy_paths to rebase relative host paths to the declaring config file's directory; unit test covers both relative and absolute cases.
src/cli/oci/build.rs Adds repeatable --copy HOST_PATH:IMAGE_PATH flag using Vec<OciCopy>; passed into BuildOptions.copy.
src/cli/oci/push.rs Adds copy: vec![] to BuildOptions; config-declared [[oci.copy]] entries still apply (they come from oci.copy, not opts.copy).
src/cli/oci/run.rs Same as push.rs — adds copy: vec![] to BuildOptions; config copies still apply.
e2e/oci/test_oci_build_slow New e2e section verifies annotated copy layers appear in the correct order (/srv/assets before /etc/cli-copy.txt) and that tarball contents match both sources.

Reviews (4): Last reviewed commit: "fix(oci): resolve config copy paths from..." | Re-trigger Greptile

Comment thread src/oci/mod.rs Resolved
Comment thread src/oci/mod.rs Resolved
Comment thread src/oci/layer.rs Resolved

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/oci/builder.rs (1)

244-258: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider warning when copying host paths, mirroring the existing [env] secrets warning.

build_image_config already warns when baking [env] values into the image because they're visible via docker/skopeo inspect. Host paths copied via --copy/[[oci.copy]] carry the same risk (e.g. an accidentally-included .env, .git, or SSH key inside a copied directory) but get no equivalent notice.

🛡️ Suggested addition
         for copy in copies {
             copy.validate().map_err(eyre::Report::msg)?;
+            info!(
+                "mise oci build: copying host path {} into the image at {} — \
+                 review its contents for secrets/credentials before sharing the image",
+                copy.host.display(),
+                copy.image
+            );
             let blob = layer::build_layer_from_path(&copy.host, &copy.image, owner).wrap_err_with(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/oci/builder.rs` around lines 244 - 258, In the arbitrary host-path layer
handling around OciCopy and build_layer_from_path, emit a warning before copying
each host path, matching the existing build_image_config warning style used for
baked [env] values. Include enough context to identify the source and
destination paths, without changing validation or layer-building behavior.
e2e/oci/test_oci_build_slow (1)

145-146: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider verifying config copy layer content.

The test verifies the CLI copy layer content (from-cli at line 146) but only checks the path existence for the config copy layer (line 145). Adding a content assertion for srv/assets/config-copy.txt would catch content corruption at minimal cost.

💚 Suggested addition
 assert_contains "tar -tzf ./out-copy/blobs/sha256/$config_copy_layer" "srv/assets/config-copy.txt"
+assert_contains "tar -xOzf ./out-copy/blobs/sha256/$config_copy_layer srv/assets/config-copy.txt" "from-config"
 assert "tar -xOzf ./out-copy/blobs/sha256/$cli_copy_layer etc/cli-copy.txt" "from-cli"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/oci/test_oci_build_slow` around lines 145 - 146, Extend the OCI build
test assertions so the config copy layer is validated for content, not just file
presence. In the assertion around config_copy_layer, extract
srv/assets/config-copy.txt from the tar archive and verify it contains the
expected config-copy content, matching the existing CLI copy layer validation
pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/oci/layer.rs`:
- Around line 108-158: Update build_layer_from_path to preserve and validate
trailing-slash semantics for file and symlink sources instead of unconditionally
normalizing image_path via trim_matches. For non-directory metadata, require
image_path to be the exact destination path: either reject a trailing slash or
otherwise prevent it from being interpreted as a parent directory; keep
directory handling’s existing normalized target behavior unchanged.

---

Nitpick comments:
In `@e2e/oci/test_oci_build_slow`:
- Around line 145-146: Extend the OCI build test assertions so the config copy
layer is validated for content, not just file presence. In the assertion around
config_copy_layer, extract srv/assets/config-copy.txt from the tar archive and
verify it contains the expected config-copy content, matching the existing CLI
copy layer validation pattern.

In `@src/oci/builder.rs`:
- Around line 244-258: In the arbitrary host-path layer handling around OciCopy
and build_layer_from_path, emit a warning before copying each host path,
matching the existing build_image_config warning style used for baked [env]
values. Include enough context to identify the source and destination paths,
without changing validation or layer-building behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 22e2bdd1-ddd3-468f-9711-e2d4cbf91e23

📥 Commits

Reviewing files that changed from the base of the PR and between b574e15 and aee14f0.

📒 Files selected for processing (10)
  • docs/cli/oci/build.md
  • docs/dev-tools/mise-oci.md
  • e2e/oci/test_oci_build_slow
  • mise.usage.kdl
  • src/cli/oci/build.rs
  • src/cli/oci/push.rs
  • src/cli/oci/run.rs
  • src/oci/builder.rs
  • src/oci/layer.rs
  • src/oci/mod.rs

Comment thread src/oci/layer.rs Resolved
@github-actions

github-actions Bot commented Jul 12, 2026 •

Copy link
Copy Markdown
Contributor

Hyperfine Performance

mise x -- echo

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.5 x -- echo 25.4 ± 1.8 20.0 31.1 1.00
mise x -- echo 25.6 ± 2.6 21.5 62.0 1.01 ± 0.12

mise env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.5 env 23.8 ± 1.9 19.8 31.5 1.00
mise env 25.3 ± 2.0 20.6 33.1 1.06 ± 0.12

mise hook-env

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.5 hook-env 25.9 ± 1.7 20.6 31.6 1.03 ± 0.10
mise hook-env 25.2 ± 1.8 20.4 32.0 1.00

mise ls

Command Mean [ms] Min [ms] Max [ms] Relative
mise-2026.7.5 ls 19.0 ± 1.6 16.0 24.7 1.04 ± 0.11
mise ls 18.3 ± 1.1 16.5 23.2 1.00

xtasks/test/perf

Command mise-2026.7.5 mise Variance
install (cached) 171ms 170ms +0%
ls (cached) 68ms 67ms +1%
bin-paths (cached) 71ms 71ms +0%
task-ls (cached) 147ms 150ms -2%

Entire-Checkpoint: db71c691bebd

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@man/man1/mise.1`:
- Around line 2312-2313: Update the --copy option description in the manpage to
state that it accepts a host file, directory, or symlink, while preserving the
existing repeatable HOST_PATH:IMAGE_PATH syntax and wording.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2fcbecf2-3184-428b-aaeb-d5780f9d575a

📥 Commits

Reviewing files that changed from the base of the PR and between aee14f0 and c53eeb5.

📒 Files selected for processing (6)
  • docs/dev-tools/mise-oci.md
  • e2e/oci/test_oci_build_slow
  • man/man1/mise.1
  • src/oci/builder.rs
  • src/oci/layer.rs
  • src/oci/mod.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/oci/layer.rs
  • src/oci/builder.rs
  • e2e/oci/test_oci_build_slow
  • src/oci/mod.rs
  • docs/dev-tools/mise-oci.md

Comment thread man/man1/mise.1 Resolved
Entire-Checkpoint: b00499a1f5b3

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d3de54f. Configure here.

Comment thread src/oci/builder.rs Resolved
Entire-Checkpoint: 72b840cacfdd
@jdx
jdx enabled auto-merge (squash) July 13, 2026 19:21
@jdx
jdx merged commit 20f1650 into main Jul 13, 2026
35 checks passed
@jdx
jdx deleted the codex/oci-copy-layers branch July 13, 2026 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant