Adds a single new input — `wings_enabled` — that gates the [mise-wings](https://mise-wings.en.dev) asset cache for tool installs. Existing workflows are unaffected: default `false` is a no-op. | Input | Default | Description | |---|---|---| | `wings_enabled` | `false` | Route tool-install URLs through the wings cache when `true` | ## How it works When `wings_enabled: true`, the action exports `MISE_WINGS_ENABLED=1`. Authentication is fully automatic — mise itself owns the GHA OIDC → wings session exchange. No `mise wings login` step in workflow YAML, no long-lived secrets to rotate. When mise (built with wings support — see jdx/mise#9458) sees `MISE_WINGS_ENABLED=1` and detects the GHA OIDC env vars (`ACTIONS_ID_TOKEN_REQUEST_URL` + `ACTIONS_ID_TOKEN_REQUEST_TOKEN`), it: 1. Fetches the runner's OIDC token, scoped to the wings deployment audience 2. POSTs it to `https://api.<host>/auth` to mint a wings CI session JWT 3. Caches the JWT in-process for the rest of the workflow 4. Transparently rewrites `registry.npmjs.org` / `github.com` / `api.github.com` URLs to the wings cache subdomains and attaches the JWT as a Bearer header ## Why opt-in (not opt-out) The default-off posture is deliberate. Many workflows already declare `permissions: id-token: write` for unrelated reasons (SLSA provenance, AWS OIDC, Sigstore, npm provenance). If `wings_enabled` defaulted to `true`, those workflows would silently send the runner's OIDC identity claims to a third-party cache without explicit consent. Cursor Bugbot HIGH + Greptile P1+security flagged a prior "default true" iteration of this PR as a privacy regression. Explicit opt-in keeps the gate visible in the workflow YAML. ## Workflow requirements ```yaml permissions: id-token: write # required for OIDC jobs: build: steps: - uses: jdx/mise-action@<sha> with: wings_enabled: true ``` The action emits a clear warning when `wings_enabled: true` but `id-token: write` is missing — without that hint, the user would see "wings configured but doing nothing" and have no clue why. ## Notes - Older mise binaries see `MISE_WINGS_ENABLED` and silently ignore it — forward-compatible. - `setupMise` fetches the mise binary itself with `curl`, which doesn't go through mise's HTTP layer; the wings rewriter only kicks in once the resulting mise binary runs `mise install`. The action sets the env var before any `mise` subcommand runs. |
||
|---|---|---|
| .github | ||
| .husky | ||
| dist | ||
| scripts | ||
| src | ||
| .eslintrc.yml | ||
| .gitattributes | ||
| .gitignore | ||
| .npmrc | ||
| .prettierignore | ||
| .prettierrc.json | ||
| action.yml | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| cliff.toml | ||
| CODEOWNERS | ||
| eslint.config.mjs | ||
| LICENSE | ||
| mise.lock | ||
| mise.toml | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| rollup.config.mjs | ||
| tsconfig.json | ||
Example Workflow
name: test
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v4
with:
version: 2026.3.10 # [default: latest] mise version to install
install: true # [default: true] run `mise install`
install_args: "bun" # [default: ""] additional arguments to `mise install`
cache: true # [default: true] cache mise using GitHub's cache
experimental: true # [default: false] enable experimental features
log_level: debug # [default: info] log level
# automatically write this .tool-versions file
tool_versions: |
shellcheck 0.11.0
# or, if you prefer .mise.toml format:
mise_toml: |
[tools]
shellcheck = "0.11.0"
working_directory: app # [default: .] directory to run mise in
reshim: false # [default: false] run `mise reshim -f`
github_token: ${{ secrets.GITHUB_TOKEN }} # [default: ${{ github.token }}] GitHub token for API authentication
- run: shellcheck scripts/*.sh
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: jdx/mise-action@v4
# .tool-versions will be read from repo root
- run: node ./my_app.js
Cache Configuration
You can customize the cache key used by the action:
- uses: jdx/mise-action@v4
with:
cache_key: "my-custom-cache-key" # Override the entire cache key
cache_key_prefix: "mise-v1" # Or just change the prefix (default: "mise-v0")
Template Variables in Cache Keys
When using cache_key, you can use template variables to reference internal values:
- uses: jdx/mise-action@v4
with:
cache_key: "mise-{{platform}}-{{version}}-{{file_hash}}"
version: "2026.3.10"
install_args: "node python"
Available template variables:
{{version}}- The mise version (from theversioninput){{cache_key_prefix}}- The cache key prefix (fromcache_key_prefixinput or default){{platform}}- The target platform (e.g., "linux-x64", "macos-arm64"){{file_hash}}- Hash of all mise configuration files{{mise_env}}- The MISE_ENV environment variable value{{install_args_hash}}- SHA256 hash of the sorted tools from install args{{default}}- The processed default cache key (useful for extending)
Conditional logic is also supported using Handlebars syntax like {{#if version}}...{{/if}}.
Example using multiple variables:
- uses: jdx/mise-action@v4
with:
cache_key: "mise-v1-{{platform}}-{{install_args_hash}}-{{file_hash}}"
install_args: "node@24 python@3.14"
You can also extend the default cache key:
- uses: jdx/mise-action@v4
with:
cache_key: "{{default}}-custom-suffix"
install_args: "node@24 python@3.14"
This gives you full control over cache invalidation based on the specific aspects that matter to your workflow.
GitHub API Rate Limits
When installing tools hosted on GitHub (like gh, node, bun, etc.), mise needs to make API calls to GitHub's releases API. Without authentication, these calls are subject to GitHub's rate limit of 60 requests per hour, which can cause installation failures.
- uses: jdx/mise-action@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# your other configuration
Note: The action automatically uses ${{ github.token }} as the default, so in most cases you don't need to explicitly provide it. However, if you encounter rate limit errors, make sure the token is being passed correctly.
Alternative Installation
Alternatively, mise is easy to use in GitHub Actions even without this:
jobs:
build:
steps:
- run: |
curl https://mise.run | sh
echo "$HOME/.local/share/mise/bin" >> $GITHUB_PATH
echo "$HOME/.local/share/mise/shims" >> $GITHUB_PATH