Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
28 changes: 28 additions & 0 deletions docs/dev-tools/mise-lock.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,34 @@ mise install
mise use node@$(jq -r '.engines.node' package.json)
```

## Provenance and Security

When `mise lock` generates a lockfile, it records a provenance type (e.g., `slsa`, `cosign`, `minisign`, `github-attestations`) for each tool. For the **current platform** with the aqua backend, mise downloads the artifact and performs full cryptographic verification at lock time -- ensuring the provenance entry in the lockfile is backed by actual verification, not just registry metadata. For the github backend, a lightweight attestation API query is made at lock time to confirm attestations exist; full cryptographic verification of the artifact happens at install time. For cross-platform entries, provenance is detected from registry metadata without verification (since the artifact may not be runnable on the current machine).

By default, when `mise install` sees a lockfile with both a checksum and a provenance entry, it trusts the lockfile and skips re-verification. This avoids redundant API calls (e.g., GitHub attestation queries) which can cause rate limit issues in CI. Since the current platform's provenance was already verified during `mise lock`, this is safe.

For additional security, you can force provenance re-verification at install time on every install:

```toml
[settings]
locked_verify_provenance = true
```

Or via environment variable:

```sh
MISE_LOCKED_VERIFY_PROVENANCE=1 mise install
```

This is also automatically enabled in [paranoid mode](/paranoid.html):

```toml
[settings]
paranoid = true
```

When enabled, every `mise install` will cryptographically verify provenance regardless of what the lockfile contains, ensuring the artifact was built by a trusted CI pipeline.

## Minimum Release Age

In addition to lockfiles, mise supports the [`install_before`](/configuration/settings.html#install_before) setting to limit supply chain risk by only installing versions that have been available for a minimum amount of time:
Expand Down
15 changes: 15 additions & 0 deletions docs/paranoid.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ Normally mise uses HTTP because loading the TLS module takes about 10ms and this
affects commonly used commands so it is a noticeably delay.
In paranoid mode, all endpoints will be fetched over HTTPS.

## Provenance re-verification

Normally, when a lockfile contains both a checksum and a provenance entry for a tool,
`mise install` trusts the lockfile and skips provenance re-verification to avoid
redundant API calls (e.g., to GitHub). This is safe when you trust the lockfile was
generated correctly.

In paranoid mode, `mise install` always re-verifies provenance (SLSA, cosign, minisign,
GitHub artifact attestations) at install time, even when the lockfile already has a
provenance entry. This ensures that cryptographic verification happens on every install,
not just when the lockfile is first generated.

This behavior can also be enabled independently via the
[`locked_verify_provenance`](/configuration/settings.html#locked_verify_provenance) setting.

## More?

If you have suggestions for more that could be added to paranoid, please let
Expand Down
4 changes: 2 additions & 2 deletions e2e-win/npm_backend.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ Describe 'npm_backend' {
mise x node@24.4.1 npm:prettier@3.6.2 -- prettier --version | Should -be "3.6.2"
}
It 'installs npm:cowsay 1.6.0 with bun' {
$env:MISE_NPM_BUN = "true"
$env:MISE_NPM_PACKAGE_MANAGER = "bun"
mise x node@24.4.1 bun@1.2.19 npm:cowsay@1.6.0 -- cowsay --version | Should -be "1.6.0"
Remove-Item Env:MISE_NPM_BUN
Remove-Item Env:MISE_NPM_PACKAGE_MANAGER
}
}
4 changes: 2 additions & 2 deletions e2e/backend/test_backend_missing_deps
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ test_npm() {

# Test with bun mode enabled but npm still missing
echo "Testing npm backend with bun mode enabled but npm missing..."
export MISE_NPM_BUN=true
export MISE_NPM_PACKAGE_MANAGER=bun
test_backend_warning "npm (bun mode)" "mise ls-remote npm:test-package" "npm may be required but was not found"
output=$(mise ls-remote npm:test-package 2>&1 || true)
test_error_message "npm (bun mode) shows npm is required for queries" "$output" "npm is required for querying package information"
unset MISE_NPM_BUN
unset MISE_NPM_PACKAGE_MANAGER
}

# Test cargo backend
Expand Down
3 changes: 2 additions & 1 deletion e2e/lockfile/test_lockfile_provenance
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ EOF
mise lock --platform "$PLATFORM"
assert "test -f mise.lock"
# sops has SLSA provenance configured in the aqua registry
assert_contains "cat mise.lock" 'provenance = "slsa"'
# Lock-time verification records the SLSA provenance URL (intoto.jsonl)
assert_contains "cat mise.lock" 'provenance.slsa'

echo "=== Testing provenance downgrade attack detection ==="
rm -f mise.lock mise.toml
Expand Down
5 changes: 5 additions & 0 deletions schema/mise.json
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,11 @@
"description": "Require lockfile URLs to be present during installation.",
"type": "boolean"
},
"locked_verify_provenance": {
"default": false,
"description": "Re-verify provenance at install time even when the lockfile already has provenance.",
"type": "boolean"
},
"lockfile": {
"description": "Create and read lockfiles for tool versions.",
"type": "boolean"
Expand Down
19 changes: 19 additions & 0 deletions settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,25 @@ Equivalent to passing `--locked` to `mise install`.
env = "MISE_LOCKED"
type = "Bool"

[locked_verify_provenance]
default = false
description = "Re-verify provenance at install time even when the lockfile already has provenance."
docs = """
When enabled, `mise install` will re-verify provenance (SLSA, cosign, minisign,
GitHub artifact attestations) at install time even when the lockfile already
contains both a checksum and a provenance entry.

By default, when a lockfile has a checksum and provenance type recorded,
`mise install` trusts the lockfile and skips re-verification to avoid redundant
API calls (e.g., to GitHub). Enabling this setting forces re-verification every
time, which provides stronger security guarantees at the cost of additional
network requests.

This is automatically enabled when `paranoid` is set to `true`.
"""
env = "MISE_LOCKED_VERIFY_PROVENANCE"
type = "Bool"

[lockfile]
description = "Create and read lockfiles for tool versions."
docs = """
Expand Down
Loading
Loading