Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c89a46a
feat(DEN-1462): add deterministic conflict-safe mise export
ORESoftware Aug 4, 2026
364d402
test(DEN-1462): exercise deterministic mise export CLI
ORESoftware Aug 4, 2026
111fd99
docs(DEN-1462): define deterministic mise export ownership
ORESoftware Aug 4, 2026
2dd5d8b
ci(DEN-1462): stage typed mise export integration
ORESoftware Aug 4, 2026
70d0952
ci(DEN-1462): certify deterministic mise export
ORESoftware Aug 4, 2026
7eed6a5
ci(DEN-1462): materialize and validate mise export
ORESoftware Aug 4, 2026
b69cbe0
test(DEN-1462): use EnvironmentPlanV2 aliases field
ORESoftware Aug 4, 2026
3afd407
fix(DEN-1462): harden export state path against symlinks
ORESoftware Aug 4, 2026
3d2d00d
fix(DEN-1462): reject reserved paths and nested secret keys
ORESoftware Aug 4, 2026
e0fe30b
ci(DEN-1462): include semantic export hardening
ORESoftware Aug 4, 2026
3cd9f48
fix(DEN-1462): align semantic normalization and portable path identity
ORESoftware Aug 4, 2026
33b99bb
chore(DEN-1462): trigger unified export materialization on branch push
ORESoftware Aug 4, 2026
c628fe1
fix(DEN-1462): scope export flags under env export
ORESoftware Aug 4, 2026
cec0ffa
ci(DEN-1462): validate scoped flags2env export contract
ORESoftware Aug 4, 2026
b4573fe
chore(DEN-1462): materialize export on available Windows runner
ORESoftware Aug 4, 2026
8e95456
chore(DEN-1462): materialize export on macOS runner
ORESoftware Aug 4, 2026
1a94c3d
fix(DEN-1462): validate scalar selector paths before export
ORESoftware Aug 4, 2026
b71b16f
ci(DEN-1462): validate portable selector paths
ORESoftware Aug 4, 2026
1e1f5d0
chore(DEN-1462): prevent duplicate-event materializer cancellation
ORESoftware Aug 4, 2026
9aa457e
test(DEN-1462): inspect scalar versions inside multi-version arrays
ORESoftware Aug 4, 2026
33d0832
test(DEN-1462): isolate export mode environment
ORESoftware Aug 4, 2026
8321d93
fix(DEN-1462): validate export mode booleans after env normalization
ORESoftware Aug 4, 2026
1114b97
fix(DEN-1462): import typed export command in CLI regression
ORESoftware Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/apply-den-1462-mise-export.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
name: materialize DEN-1462 mise export

on:
push:
branches:
- feat/den-1462-mise-export
paths:
- .github/workflows/apply-den-1462-mise-export.yml
- scripts/apply_den1462_mise_export.py
- scripts/harden_den1462_export.py
- scripts/fix_den1462_flags_contract.py
- scripts/fix_den1462_selector_paths.py
- src/mise_export.rs
- tests/mise_export_cli.rs
- docs/mise-export.md
- .github/workflows/mise-export.yml

permissions:
contents: write

concurrency:
group: materialize-den-1462-mise-export
cancel-in-progress: false

defaults:
run:
shell: bash

jobs:
materialize:
if: github.actor != 'github-actions[bot]'
runs-on: macos-15
timeout-minutes: 40
steps:
- name: Check out implementation branch
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: feat/den-1462-mise-export
fetch-depth: 0
persist-credentials: true
show-progress: false

- name: Install Rust toolchain
run: |
set -euo pipefail
rustup toolchain install stable --profile minimal --component rustfmt,clippy
rustup default stable

- name: Apply typed integration, semantic hardening, and validate
run: |
set -euo pipefail
python3 scripts/apply_den1462_mise_export.py
python3 scripts/harden_den1462_export.py
python3 scripts/fix_den1462_flags_contract.py
python3 scripts/fix_den1462_selector_paths.py
cargo fmt --all
cargo fmt --all --check
git diff --check
cargo test --locked mise_export
cargo test --locked --test mise_export_cli
cargo test --locked cli::tests::environment_export_is_typed_and_rejects_ambiguous_write_modes
cargo test --locked cli::tests::cli_flags_toml_is_in_sync_with_clap
cargo clippy --locked --all-targets -- -D warnings

- name: Commit ordinary source and remove materializers
run: |
set -euo pipefail
rm -f \
.github/workflows/apply-den-1462-mise-export.yml \
scripts/apply_den1462_mise_export.py \
scripts/harden_den1462_export.py \
scripts/fix_den1462_flags_contract.py \
scripts/fix_den1462_selector_paths.py
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add -A
git diff --cached --check
git commit -m 'feat(DEN-1462): add deterministic conflict-safe mise export'
git push origin HEAD:feat/den-1462-mise-export
98 changes: 98 additions & 0 deletions .github/workflows/mise-export.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
name: deterministic mise export

on:
pull_request:
paths:
- .cli-flags.toml
- src/cli.rs
- src/lib.rs
- src/main.rs
- src/mise_export.rs
- tests/mise_export_cli.rs
- docs/mise-export.md
- .github/workflows/mise-export.yml
push:
branches: [main]
paths:
- .cli-flags.toml
- src/cli.rs
- src/lib.rs
- src/main.rs
- src/mise_export.rs
- tests/mise_export_cli.rs
- docs/mise-export.md
- .github/workflows/mise-export.yml

permissions:
contents: read

concurrency:
group: mise-export-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: "1"

jobs:
export:
name: export / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 35
strategy:
fail-fast: false
matrix:
os:
- ubuntu-24.04
- macos-15
- windows-2025

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
show-progress: false

- name: Install declared Rust toolchain
shell: bash
run: |
set -euo pipefail
rustup toolchain install stable --profile minimal --component rustfmt,clippy
rustup default stable
rustc --version --verbose
cargo --version --verbose

- name: Check formatting and flags contract
run: |
cargo fmt --all --check
cargo test --locked cli::tests::environment_export_is_typed_and_rejects_ambiguous_write_modes
cargo test --locked cli::tests::cli_flags_toml_is_in_sync_with_clap

- name: Run module and real CLI export tests
run: |
cargo test --locked mise_export
cargo test --locked --test mise_export_cli

- name: Lint every target
run: cargo clippy --locked --all-targets -- -D warnings

- name: Re-run deterministic and conflict canaries
run: |
cargo test --locked mise_export::tests::deterministic_export_preserves_multi_version_and_command_order
cargo test --locked mise_export::tests::hand_edits_and_unowned_outputs_are_never_overwritten

gate:
name: All mise export platforms passed
if: always()
needs: export
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Enforce aggregate result
env:
MATRIX_RESULT: ${{ needs.export.result }}
run: |
set -euo pipefail
printf 'mise-export=%s\n' "$MATRIX_RESULT"
test "$MATRIX_RESULT" = success
119 changes: 119 additions & 0 deletions docs/mise-export.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
# Deterministic mise export

`zed env export mise` projects a schema-v2 Zed environment plan into a
project-local mise configuration without invoking mise, loading global state,
or executing project code.

```sh
# Print deterministic TOML without writing files.
zed env export mise --plan zed-env.toml

# Verify that the checked-in manager view is current.
zed env export mise --plan zed-env.toml --output .mise.toml --check

# Create or update a Zed-owned manager view transactionally.
zed env export mise --plan zed-env.toml --output .mise.toml --write
```

`--check` and `--write` are mutually exclusive. Without either flag, the
command prints the deterministic TOML document to standard output.

## Supported projection

The first write-capable slice exports only state with an exact, tested mise
representation:

- ordered single- and multi-version tools;
- backend-qualified tool keys and core-tool aliases;
- `version`, `path`, `prefix`, and `ref` selectors;
- typed backend options and tool OS constraints;
- scalar environment values;
- typed project and task variables;
- task descriptions, aliases, ordered command arrays, dependencies,
post-dependencies, readiness dependencies, environment, variables,
task-local tools, directories, sources, outputs, one shell string, usage,
confirmation, cache, timeout, and output flags; and
- lockfile platform settings.

The exporter preserves multi-version and command order. Set-like platform
lists are sorted and deduplicated by the normalized environment contract.

## Fail-closed boundaries

The command rejects fields rather than silently omitting them when no certified
mapping exists. Current explicit boundaries include:

- activation hooks other than `activation = "none"`;
- environment-plan system packages;
- imported manager provenance and lock identity;
- extension maps;
- resolved versions, immutable sources, and artifact checksums that belong in
`mise.lock` rather than `mise.toml`;
- complex top-level or task environment tables/arrays, which mise may interpret
as directives rather than literal values;
- grouped and structured task invocations until the current mise run-entry wire
form is certified; and
- shell program-plus-argument vectors, because the current mise task field is
one shell string.

Diagnostics include the exact environment-plan path that cannot be represented.
Complete current `mise.lock` export is tracked independently so config export
cannot accidentally erase provenance.

## Secrets

The plan contract does not yet expose a portable secret-reference type. Export
therefore rejects literal environment, variable, and tool-option names that
look credential-bearing, including password, secret, token, private/access key,
API key, credential, and authorization names. The generated file, sidecar,
logs, and diagnostics never print rejected values.

## Ownership and conflicts

Write mode records deterministic ownership in:

```text
.zed/mise-export-state.json
```

The sidecar contains only schema version, project-relative plan/output paths,
and SHA-256 identities. It contains no timestamps, random identifiers,
absolute paths, credentials, or environment values.

The exporter follows these rules:

1. A missing output can be created.
2. An existing file whose bytes already equal the deterministic projection can
be adopted safely.
3. A differing existing file with no matching Zed ownership record is treated
as hand-authored and is never overwritten.
4. A Zed-owned file whose current digest differs from the recorded digest is a
user edit and is never overwritten.
5. A Zed-owned unchanged file may be replaced only by the same project-relative
plan recorded in the sidecar.

Output and state changes share `ProjectTransaction`, including crash recovery
and rollback. Project, output, and state paths reject absolute/home/drive/UNC,
parent traversal, and symlink escape.

## Determinism

The plan identity is:

```text
SHA256("zed-pkg:mise-export-plan:v1\0" || canonical-environment-plan-json)
```

The output identity is SHA-256 over the exact generated TOML bytes. Print,
check, and write modes all use the same renderer. Repeated generation of the
same normalized plan is byte-identical across supported platforms.

## Next gates

- Bind the complete current `mise.lock` contract to export and verification.
- Translate portable manager identities into native `EnvironmentLock`.
- Certify structured task run entries and sandbox capabilities.
- Add conflict-aware import → export → import semantic identity tests on Linux,
macOS, and Windows.

Tracking: DEN-1462, DEN-1461, DEN-1481.
Loading
Loading