Skip to content

security: lock mise runtime artifacts - #21

Merged
eXPerience83 merged 38 commits into
mainfrom
security/lock-mise-runtimes
Jul 28, 2026
Merged

security: lock mise runtime artifacts#21
eXPerience83 merged 38 commits into
mainfrom
security/lock-mise-runtimes

Conversation

@eXPerience83

@eXPerience83 eXPerience83 commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • commit mise.toml and mise.lock entries for Python, Node.js and uv on Linux AMD64 and ARM64
  • install the runtimes with mise install --locked from read-only configuration and lock inputs
  • re-verify supported GitHub artifact attestations during the current-platform image build
  • validate exact TOML schema, version, backend, platform, URL, SHA-256, provenance and cross-platform artifact coherence across versions.env, Docker defaults, mise.toml and mise.lock
  • regenerate the runtime lock atomically from isolated inputs with the verified pinned mise binary
  • extend the upstream updater to regenerate the lock from main under serialized execution
  • document the review, platform coverage and recovery procedure

Security impact

The image no longer resolves mise-managed runtime artifacts dynamically during a build. Missing or stale lock entries, unknown configuration fields, malformed platform data, unsupported artifact URLs, invalid checksums, provenance failures and incoherent cross-platform artifact metadata now fail closed.

Lock regeneration runs in an isolated temporary workspace with caller-provided MISE_* settings removed, bounded HTTP and command timeouts, validation before replacement and cleanup on every exit. A failed command or malformed generated lock leaves the previously committed lock unchanged.

The committed Python artifact is the newer 20260623 rebuild of Python 3.14.6; this demonstrates why the automation also checks lock-only artifact changes when the semantic runtime version is unchanged.

Validation

  • repository configuration, shell syntax and lock coherence validation passed
  • adversarial fixtures prove rejection of unknown TOML sections/settings, version drift, malformed and extra platform entries, unknown artifact fields, untrusted uv API URLs, missing provenance, mixed Python build dates and duplicate uv asset IDs
  • regeneration tests prove isolation from inherited mise configuration, atomic replacement, cleanup, timeout validation and preservation of the previous lock after invalid output or command failure
  • AMD64 base and Codex images built successfully with mise install --locked
  • AMD64 Python and uv provenance was re-verified during the image build
  • Python, Node.js, npm and uv runtime smoke tests passed
  • Trivy scans passed for both images
  • the gate found no fixable critical vulnerabilities
  • the upstream write workflow is restricted to main, serialized and fails visibly when remote branch discovery fails

Platform coverage

The committed lock contains exact Linux AMD64 and ARM64 entries. Current CI executes the AMD64 build, downloads and verifies AMD64 artifacts, and checks all ARM64 entries structurally for exact platform, backend, URL, checksum and provenance metadata. ARM64 artifacts are not executed by the current AMD64 job; a future ARM64 publication workflow must run the same locked installation and provenance verification before publishing ARM64 images.

Closes #18

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@eXPerience83, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bc2d304d-fc85-46de-8624-f334eb313ebf

📥 Commits

Reviewing files that changed from the base of the PR and between c87d7ff and 50b4269.

⛔ Files ignored due to path filters (1)
  • mise.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • .github/workflows/check-upstream.yml
  • .github/workflows/publish-edge-amd64.yml
  • CHANGELOG.md
  • README.md
  • docs/runtime-locks.md
  • images/base/Dockerfile
  • mise.toml
  • scripts/regenerate-mise-lock.sh
  • scripts/test-regenerate-mise-lock.sh
  • scripts/test-validate-mise-lock.py
  • scripts/validate-mise-lock.py
  • scripts/validate-version-pins.sh

Walkthrough

The change adds mise runtime configuration and lock validation, installs Python, Node.js, and uv from locked artifacts in Docker, automates lock regeneration during upstream updates, and documents the runtime-lock workflow and provenance requirements.

Changes

Mise runtime lock enforcement

Layer / File(s) Summary
Lock contract and artifact validation
mise.toml, scripts/validate-mise-lock.py, docs/runtime-locks.md, CHANGELOG.md, .coderabbit.yaml
Defines pinned runtimes for Linux AMD64 and ARM64, validates lock metadata, URLs, checksums, and provenance, and documents and configures review requirements for the runtime lock.
Locked Docker installation and enforcement
images/base/Dockerfile, scripts/validate-version-pins.sh
Copies mise.toml and mise.lock into the image, uses mise install --locked, rejects dynamic runtime selection, and validates the committed lock data.
Upstream lock regeneration workflow
scripts/regenerate-mise-lock.sh, .github/workflows/check-upstream.yml, README.md, CHANGELOG.md
Regenerates locks with a version-matched mise binary, tracks configuration and lock changes, updates PR metadata, and links the new documentation.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UpstreamWorkflow as check-upstream.yml
  participant Mise as pinned mise binary
  participant LockScript as regenerate-mise-lock.sh
  participant Validator as validate-mise-lock.py
  UpstreamWorkflow->>Mise: download and verify pinned release
  UpstreamWorkflow->>LockScript: regenerate mise.lock
  LockScript->>Mise: resolve Linux runtime artifacts
  LockScript->>Validator: validate versions, URLs, checksums, and provenance
  Validator-->>UpstreamWorkflow: return validation status
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive Most objectives are addressed, but the committed mise.lock file is excluded by !**/*.lock, so exact lock contents and checksums can't be verified. Please provide an unfiltered diff or remove the !**/*.lock filter so the lockfile's URLs, checksums, and provenance can be verified.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes stay within the lockfile, Docker, workflow, validation, and documentation scope with no clearly unrelated additions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title is concise and accurately summarizes the main change: locking mise runtime artifacts for security.
Description check ✅ Passed The description covers what changed, security impact, validation, and platform coverage, with only template sections like safety checks and follow-up omitted.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch security/lock-mise-runtimes

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.

@eXPerience83
eXPerience83 marked this pull request as ready for review July 28, 2026 07:14

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
images/base/Dockerfile (1)

156-163: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Guard MISE_CACHE_DIR before rm -rf .../*.

If MISE_CACHE_DIR is ever empty/unset, rm -rf "$MISE_CACHE_DIR"/* expands to rm -rf /*. Hadolint flags this (SC2115). Use ${MISE_CACHE_DIR:?} to fail loudly instead of silently wiping the filesystem.

🐛 Suggested fix
-    && rm -rf "$MISE_CACHE_DIR"/*
+    && rm -rf "${MISE_CACHE_DIR:?}"/*
🤖 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 `@images/base/Dockerfile` around lines 156 - 163, Update the cleanup command in
the Dockerfile’s mise installation RUN block to use the `${MISE_CACHE_DIR:?}`
parameter guard before appending `/*`, ensuring the build fails when
MISE_CACHE_DIR is unset or empty rather than risking removal from the
filesystem.

Source: Linters/SAST tools

🤖 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 `@mise.toml`:
- Line 2: Remove the global experimental setting from mise.toml, leaving the
managed locked-installation and provenance-check configuration unchanged since
it does not require experimental mode.

In `@scripts/regenerate-mise-lock.sh`:
- Around line 28-33: Update the mise lock invocation in
scripts/regenerate-mise-lock.sh to enforce a finite timeout for its network
operations, using mise’s supported timeout configuration or an equivalent
bounded command wrapper. Preserve the existing multi-platform arguments and
environment setup, and ensure the script cannot remain blocked indefinitely on
upstream requests.

In `@scripts/validate-mise-lock.py`:
- Around line 93-213: Split main() into focused helper functions for mise.toml
validation, mise.lock structure/tool validation, and per-platform artifact
validation. Move the corresponding checks into those helpers while preserving
existing failure messages and validation behavior, leaving main() responsible
only for argument parsing, environment loading, orchestration, and success
output.

---

Outside diff comments:
In `@images/base/Dockerfile`:
- Around line 156-163: Update the cleanup command in the Dockerfile’s mise
installation RUN block to use the `${MISE_CACHE_DIR:?}` parameter guard before
appending `/*`, ensuring the build fails when MISE_CACHE_DIR is unset or empty
rather than risking removal from the filesystem.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7e29e82e-0dca-4eef-bc58-c28e5d68245d

📥 Commits

Reviewing files that changed from the base of the PR and between c87d7ff and 3e83778.

⛔ Files ignored due to path filters (1)
  • mise.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .github/workflows/check-upstream.yml
  • CHANGELOG.md
  • README.md
  • docs/runtime-locks.md
  • images/base/Dockerfile
  • mise.toml
  • scripts/regenerate-mise-lock.sh
  • scripts/validate-mise-lock.py
  • scripts/validate-version-pins.sh
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.md

⚙️ CodeRabbit configuration file

**/*.md: Check that documentation matches the implemented behavior and clearly distinguishes experimental edge builds
from stable releases. Flag outdated versions, unsafe deployment guidance and claims not proven by CI or testing.

Files:

  • README.md
  • docs/runtime-locks.md
  • CHANGELOG.md
scripts/**/*.sh

⚙️ CodeRabbit configuration file

scripts/**/*.sh: Review as production Bash. Check quoting, set -euo pipefail behavior, cleanup traps,
bounded retries and timeouts, non-interactive execution, idempotency and useful failure messages.
Flag commands that can hang, leak credentials, silently ignore failures or mutate persistent data unexpectedly.

Files:

  • scripts/regenerate-mise-lock.sh
  • scripts/validate-version-pins.sh
.github/workflows/**

⚙️ CodeRabbit configuration file

.github/workflows/**: Review GitHub Actions for least-privilege permissions, safe event triggers, untrusted input handling,
accidental publication, tag-channel correctness, secret exposure, reproducible builds, SBOM/provenance
generation and appropriate validation before pushing images.

Files:

  • .github/workflows/check-upstream.yml
images/**/Dockerfile

⚙️ CodeRabbit configuration file

images/**/Dockerfile: Review for reproducibility, supply-chain security and minimal image growth.
Require pinned upstream versions and checksum or digest verification for downloaded binaries.
Flag secrets, floating base tags, unsafe remote-script execution, broken multi-architecture logic,
cache misuse, unnecessary packages and changes that weaken the secure-by-default runtime.

Files:

  • images/base/Dockerfile
🪛 Hadolint (2.14.0)
images/base/Dockerfile

[warning] 156-156: Use "${var:?}" to ensure this never expands to /* .

(SC2115)

🪛 LanguageTool
docs/runtime-locks.md

[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...default in images/base/Dockerfile. 3. Update the matching tool in mise.toml. 4. Ru...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 Ruff (0.15.21)
scripts/validate-mise-lock.py

[warning] 93-93: Too many branches (19 > 12)

(PLR0912)


[warning] 93-93: Too many statements (53 > 50)

(PLR0915)

🔇 Additional comments (10)
docs/runtime-locks.md (1)

1-44: LGTM!

CHANGELOG.md (1)

28-28: LGTM!

Also applies to: 49-49, 65-65

scripts/validate-version-pins.sh (1)

103-120: LGTM!

Also applies to: 212-212

.github/workflows/check-upstream.yml (1)

183-190: LGTM!

Also applies to: 225-256, 275-283

README.md (1)

118-118: LGTM!

scripts/validate-mise-lock.py (2)

9-9: 🎯 Functional Correctness

No change needed. The script still uses tomllib, but the runner validates a Python 3.14 pin and invokes this script with tomllib; no lower-host-Python support path is present.

			> Likely an incorrect or invalid review comment.

59-69: 🎯 Functional Correctness

No change needed for Node.js artifact extension.

Mise’s Node.js core backend resolves non-Windows Node releases to the .tar.gz archive, so this validator should not flag generated core:node lock entries for using .tar.gz.

			> Likely an incorrect or invalid review comment.
scripts/regenerate-mise-lock.sh (2)

30-33: 🎯 Functional Correctness

No change needed.

MISE_SAFE=1 is a real mise safety setting compatible with the pinned 2026.7.14 release, so this does not need to be treated as a silent no-op.

			> Likely an incorrect or invalid review comment.

14-14: 🎯 Functional Correctness

No change needed.

In CI/script contexts, mise --version output is piped, so the terminal-only ASCII banner text is not part of the relevant stdout used by awk '{print $1}', and the version token is captured correctly.

			> Likely an incorrect or invalid review comment.
images/base/Dockerfile (1)

151-157: 🩺 Stability & Availability

No action needed: mise install --locked treats the committed lockfile as authoritative and does not update mise.lock.

Comment thread mise.toml Outdated
Comment thread scripts/regenerate-mise-lock.sh
Comment thread scripts/validate-mise-lock.py Outdated
@eXPerience83

Copy link
Copy Markdown
Owner Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 15f929e4eb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .coderabbit.yaml Outdated
@eXPerience83

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

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

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 `@scripts/validate-mise-lock.py`:
- Around line 190-199: The platform validation around locked_platforms must
account for every platforms.* key, including entries with scalar or otherwise
malformed values. Update the comprehension or validation in the surrounding
tool-entry check to collect all platforms.* keys, then separately reject any
whose values are not dictionaries while preserving the exact PLATFORMS
comparison.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f1332f94-0b35-4986-89d1-5edb60996997

📥 Commits

Reviewing files that changed from the base of the PR and between c87d7ff and d0bc259.

⛔ Files ignored due to path filters (1)
  • mise.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • .coderabbit.yaml
  • .github/workflows/check-upstream.yml
  • CHANGELOG.md
  • README.md
  • docs/runtime-locks.md
  • images/base/Dockerfile
  • mise.toml
  • scripts/regenerate-mise-lock.sh
  • scripts/validate-mise-lock.py
  • scripts/validate-version-pins.sh
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.md

⚙️ CodeRabbit configuration file

**/*.md: Check that documentation matches the implemented behavior and clearly distinguishes experimental edge builds
from stable releases. Flag outdated versions, unsafe deployment guidance and claims not proven by CI or testing.

Files:

  • README.md
  • docs/runtime-locks.md
  • CHANGELOG.md
images/**/Dockerfile

⚙️ CodeRabbit configuration file

images/**/Dockerfile: Review for reproducibility, supply-chain security and minimal image growth.
Require pinned upstream versions and checksum or digest verification for downloaded binaries.
Flag secrets, floating base tags, unsafe remote-script execution, broken multi-architecture logic,
cache misuse, unnecessary packages and changes that weaken the secure-by-default runtime.

Files:

  • images/base/Dockerfile
scripts/**/*.sh

⚙️ CodeRabbit configuration file

scripts/**/*.sh: Review as production Bash. Check quoting, set -euo pipefail behavior, cleanup traps,
bounded retries and timeouts, non-interactive execution, idempotency and useful failure messages.
Flag commands that can hang, leak credentials, silently ignore failures or mutate persistent data unexpectedly.

Files:

  • scripts/regenerate-mise-lock.sh
  • scripts/validate-version-pins.sh
.github/workflows/**

⚙️ CodeRabbit configuration file

.github/workflows/**: Review GitHub Actions for least-privilege permissions, safe event triggers, untrusted input handling,
accidental publication, tag-channel correctness, secret exposure, reproducible builds, SBOM/provenance
generation and appropriate validation before pushing images.

Files:

  • .github/workflows/check-upstream.yml
🪛 LanguageTool
docs/runtime-locks.md

[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...default in images/base/Dockerfile. 3. Update the matching tool in mise.toml. 4. Ru...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 Ruff (0.15.21)
scripts/validate-mise-lock.py

[warning] 171-171: Dynamically typed expressions (typing.Any) are disallowed in entries

(ANN401)

🔇 Additional comments (10)
mise.toml (1)

1-9: LGTM!

scripts/validate-mise-lock.py (1)

1-188: LGTM!

Also applies to: 201-248

docs/runtime-locks.md (1)

1-43: LGTM!

CHANGELOG.md (1)

28-28: LGTM!

Also applies to: 49-49, 65-65

.coderabbit.yaml (1)

17-31: LGTM!

images/base/Dockerfile (1)

42-42: LGTM!

Also applies to: 151-163

scripts/validate-version-pins.sh (1)

103-120: LGTM!

Also applies to: 212-212

.github/workflows/check-upstream.yml (1)

183-189: LGTM!

Also applies to: 225-283

scripts/regenerate-mise-lock.sh (1)

1-42: LGTM!

README.md (1)

118-118: LGTM!

Comment thread scripts/validate-mise-lock.py
@eXPerience83

Copy link
Copy Markdown
Owner Author

@codex

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25e445f059

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/check-upstream.yml
Comment thread scripts/regenerate-mise-lock.sh Outdated
@eXPerience83

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 51 minutes.

@eXPerience83
eXPerience83 merged commit 270812a into main Jul 28, 2026
2 checks passed
@eXPerience83
eXPerience83 deleted the security/lock-mise-runtimes branch July 28, 2026 13:03
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.

security: lock mise-managed runtime artifacts

1 participant