Add install-mise composite action
This commit is contained in:
3 files changed
+162
-7
No files matched your search
@@ -31,7 +31,7 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
status=0
|
||||
for f in install-grype/action.yml install-syft/action.yml scan-image/action.yml; do
|
||||
for f in install-grype/action.yml install-syft/action.yml install-mise/action.yml scan-image/action.yml; do
|
||||
if [ ! -f "$f" ]; then
|
||||
echo "::error::missing $f"
|
||||
status=1
|
||||
@@ -101,11 +101,15 @@ jobs:
|
||||
- name: Install Syft
|
||||
uses: ./install-syft
|
||||
|
||||
- name: Install mise
|
||||
uses: ./install-mise
|
||||
|
||||
- name: Verify installs
|
||||
run: |
|
||||
set -euo pipefail
|
||||
grype version
|
||||
syft version
|
||||
mise --version
|
||||
|
||||
- name: Generate SBOM fixture
|
||||
run: |
|
||||
|
||||
@@ -12,6 +12,7 @@ whether a finding notifies, fails the run, blocks a push, or blocks a deploy.
|
||||
| --- | --- |
|
||||
| `install-grype` | Installs a pinned, signature-verified Grype (and the pinned Cosign used to verify it) into a job-local directory on `PATH`. |
|
||||
| `install-syft` | Installs a pinned, signature-verified Syft the same way, for SBOM generation. |
|
||||
| `install-mise` | Installs a pinned, signature-verified mise (and the pinned minisign used to verify it) into a job-local directory on `PATH`. |
|
||||
| `scan-image` | Scans an image, directory, or SBOM with Grype and fails the step on fixable findings at the configured severities; writes the raw JSON report. |
|
||||
|
||||
## Usage
|
||||
@@ -124,6 +125,27 @@ Outputs: `syft-path`, `version`.
|
||||
|
||||
Supports `amd64` and `arm64`, verified the same way as Grype.
|
||||
|
||||
### `install-mise`
|
||||
|
||||
| Input | Default | Notes |
|
||||
| --- | --- | --- |
|
||||
| `mise-version` | `v2026.10.9` | Release tag including `v`. |
|
||||
| `minisign-version` | `0.12` | minisign used only to verify mise's checksums. |
|
||||
| `install-dir` | job-local dir on `PATH` | Override to choose the install location. |
|
||||
|
||||
Outputs: `mise-path`, `version`.
|
||||
|
||||
Supports `amd64` and `arm64`. This is the one action here that does not use
|
||||
Cosign, because mise publishes no keyless-signed checksum file: it bootstraps
|
||||
minisign (itself checksum-pinned, in a tarball carrying both architectures) and
|
||||
verifies `SHASUMS256.txt` against mise's minisign public key, pinned in the
|
||||
action, before checking the release archive against the verified file.
|
||||
|
||||
Only the `mise` binary is installed. A caller that then runs `mise install`
|
||||
decides for itself where the toolchain lands (`MISE_DATA_DIR`), and what to do
|
||||
with the result: `mise` has no audit command, so vulnerability coverage comes
|
||||
from scanning the installed artifacts.
|
||||
|
||||
### `scan-image`
|
||||
|
||||
| Input | Default | Notes |
|
||||
@@ -142,9 +164,11 @@ and `fail-on-fixable` is `true`. Combine with `continue-on-error: true` and
|
||||
|
||||
## Versioning
|
||||
|
||||
`install-grype` and `install-syft` centralise the Cosign, Grype, and Syft
|
||||
versions. Bump them here, deliberately, and tag a new release (`v1`, `v2`, ...)
|
||||
so callers can pin.
|
||||
`install-grype`, `install-syft` and `install-mise` centralise the Cosign, Grype,
|
||||
Syft, mise, and minisign versions. Bump them here, deliberately, and tag a new
|
||||
release (`v1`, `v2`, ...) so callers can pin. The mise action also carries a
|
||||
minisign bootstrap checksum and mise's minisign public key; bump those together
|
||||
with the versions they belong to.
|
||||
|
||||
## Consuming safely
|
||||
|
||||
@@ -154,9 +178,12 @@ release to every consumer:
|
||||
|
||||
- **Pin a commit SHA, not a moving ref.** `@v1` can be moved; a full SHA cannot.
|
||||
- Keep secrets in the calling workflow; nothing here reads or writes secrets.
|
||||
- Installs verify their payloads against keyless Cosign signatures (and pinned
|
||||
Cosign checksums) before use, fetching only from
|
||||
`github.com/sigstore/cosign` and `github.com/anchore/{grype,syft}`.
|
||||
- Installs verify their payloads before use: `install-grype` and `install-syft`
|
||||
against keyless Cosign signatures (with checksum-pinned Cosign bootstraps),
|
||||
and `install-mise` against mise's minisign signature (with a checksum-pinned
|
||||
minisign bootstrap). They fetch only from `github.com/sigstore/cosign`,
|
||||
`github.com/anchore/{grype,syft}`, `github.com/jedisct1/minisign` and
|
||||
`github.com/jdx/mise`.
|
||||
- Report suspected issues privately to the maintainer (see `CODEOWNERS`) rather
|
||||
than opening a public issue.
|
||||
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
name: Install mise
|
||||
description: >-
|
||||
Install a pinned, signature-verified mise into a job-local directory and add
|
||||
it to PATH. Also bootstraps the pinned minisign used to verify mise's release
|
||||
checksums.
|
||||
|
||||
# Mechanism only. The caller decides what to install with mise, and what to do
|
||||
# with the result.
|
||||
#
|
||||
# Unlike Grype and Syft, mise publishes no keyless-signed checksum file, so this
|
||||
# verifies the way mise itself does: minisign over SHASUMS256.txt against a
|
||||
# pinned public key, then sha256 over the release archive. See README.md.
|
||||
|
||||
inputs:
|
||||
mise-version:
|
||||
description: mise release tag, including the leading "v".
|
||||
required: false
|
||||
default: v2026.10.9
|
||||
minisign-version:
|
||||
description: >-
|
||||
minisign release tag used to verify mise's signed checksums. The release
|
||||
tarball carries both x86_64 and aarch64 builds.
|
||||
required: false
|
||||
default: '0.12'
|
||||
install-dir:
|
||||
description: >-
|
||||
Directory to install the binary into. Defaults to a job-local directory
|
||||
that is added to PATH.
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
outputs:
|
||||
mise-path:
|
||||
description: Absolute path to the installed mise binary.
|
||||
value: ${{ steps.install.outputs.mise-path }}
|
||||
version:
|
||||
description: Installed mise version string.
|
||||
value: ${{ steps.install.outputs.version }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- id: install
|
||||
shell: bash
|
||||
env:
|
||||
INPUT_MISE_VERSION: ${{ inputs.mise-version }}
|
||||
INPUT_MINISIGN_VERSION: ${{ inputs.minisign-version }}
|
||||
INPUT_INSTALL_DIR: ${{ inputs.install-dir }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
mise_version="${INPUT_MISE_VERSION:?mise-version is required}"
|
||||
minisign_version="${INPUT_MINISIGN_VERSION:?minisign-version is required}"
|
||||
install_dir="${INPUT_INSTALL_DIR:-${RUNNER_TEMP:-/tmp}/mise-bin}"
|
||||
|
||||
# mise names its assets differently from uname, and minisign names them
|
||||
# differently from mise. Bump the minisign checksum with its version.
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64)
|
||||
mise_arch=x64
|
||||
minisign_arch=x86_64
|
||||
minisign_sha=9a599b48ba6eb7b1e80f12f36b94ceca7c00b7a5173c95c3efc88d9822957e73
|
||||
;;
|
||||
aarch64|arm64)
|
||||
mise_arch=arm64
|
||||
minisign_arch=aarch64
|
||||
minisign_sha=9a599b48ba6eb7b1e80f12f36b94ceca7c00b7a5173c95c3efc88d9822957e73
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported architecture: $(uname -m)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
mkdir -p "$install_dir"
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
cd "$work"
|
||||
|
||||
# Bootstrap minisign: pinned by checksum before it is trusted. One
|
||||
# tarball serves both architectures.
|
||||
curl --fail --location --retry 3 --output minisign.tar.gz \
|
||||
"https://github.com/jedisct1/minisign/releases/download/${minisign_version}/minisign-${minisign_version}-linux.tar.gz"
|
||||
printf '%s %s\n' "$minisign_sha" minisign.tar.gz | sha256sum --check --status -
|
||||
tar -xzf minisign.tar.gz "minisign-linux/${minisign_arch}/minisign"
|
||||
install -m 0755 "minisign-linux/${minisign_arch}/minisign" ./minisign
|
||||
|
||||
# mise's minisign public key, copied from minisign.pub in jdx/mise and
|
||||
# pinned here so it cannot change without a review in this repository.
|
||||
# Bump deliberately, together with mise-version.
|
||||
printf '%s\n' \
|
||||
'untrusted comment: minisign public key 64113EDF160FDEC2' \
|
||||
'RWTC3g8W3z4RZK3V3qv7fa1QY4JEWyBtqIHW+85QlJpZc5yG+uNYNBSZ' \
|
||||
> mise.pub
|
||||
|
||||
base="https://github.com/jdx/mise/releases/download/${mise_version}"
|
||||
tarball="mise-${mise_version}-linux-${mise_arch}.tar.gz"
|
||||
|
||||
curl --fail --location --retry 3 --output SHASUMS256.txt "${base}/SHASUMS256.txt"
|
||||
curl --fail --location --retry 3 --output SHASUMS256.txt.minisig "${base}/SHASUMS256.txt.minisig"
|
||||
|
||||
# Verify mise's checksum file with the pinned key, then the archive
|
||||
# against the verified file.
|
||||
./minisign -V -p mise.pub -m SHASUMS256.txt -x SHASUMS256.txt.minisig
|
||||
|
||||
curl --fail --location --retry 3 --output "$tarball" "${base}/${tarball}"
|
||||
|
||||
# mise's entries are "./"-prefixed, unlike anchore's bare filenames.
|
||||
check="$(awk -v t="$tarball" '{ n=$2; sub(/^\.\//, "", n); if (n == t) print }' SHASUMS256.txt)"
|
||||
[ -n "$check" ] || { echo "No checksum entry for ${tarball}" >&2; exit 1; }
|
||||
printf '%s\n' "$check" | sha256sum --check --status -
|
||||
|
||||
tar -xzf "$tarball"
|
||||
install -m 0755 mise/bin/mise "$install_dir/mise"
|
||||
|
||||
echo "$install_dir" >> "${GITHUB_PATH:-/dev/null}"
|
||||
|
||||
version="$("$install_dir/mise" --version 2>/dev/null | awk '{print $1}')"
|
||||
{
|
||||
echo "mise-path=$install_dir/mise"
|
||||
echo "version=${version}"
|
||||
} >> "${GITHUB_OUTPUT:-/dev/null}"
|
||||
|
||||
echo "Installed mise ${version:-$mise_version} at $install_dir/mise"
|
||||
Reference in new issue
Block a user