From 63eb6acb35a4d6ae95d650d8bbd3db79166866c4 Mon Sep 17 00:00:00 2001 From: aguil Date: Thu, 11 Jun 2026 14:08:45 -0600 Subject: [PATCH 1/2] feat(mise): apply security mitigation checklist Harden mise with paranoid mode, ceiling paths, disabled asdf backends, and lockfiles for global and repo-local QA tools. Trust the chezmoi source via trusted_config_paths and a post-apply hook so tmux restores do not fail on the repo .mise.toml. --- .../run_after_05-mise-trust.sh.tmpl | 20 +++++ .mise.toml | 2 + .../Microsoft.PowerShell_profile.ps1.tmpl | 4 + .../Microsoft.PowerShell_profile.ps1.tmpl | 4 + .../Microsoft.PowerShell_profile.ps1.tmpl | 4 + .../Microsoft.PowerShell_profile.ps1.tmpl | 4 + docs/repo-maintenance.md | 6 ++ dot_agents/skills/mise-security/SKILL.md | 70 +++++++++++++++ .../chezmoi/profile.d/mise-security.sh.tmpl | 7 ++ dot_config/mise/config.toml.tmpl | 15 ++++ dot_config/mise/mise.lock | 83 ++++++++++++++++++ mise.lock | 87 +++++++++++++++++++ qa.just | 8 +- 13 files changed, 310 insertions(+), 4 deletions(-) create mode 100644 .chezmoiscripts/run_after_05-mise-trust.sh.tmpl create mode 100644 dot_agents/skills/mise-security/SKILL.md create mode 100644 dot_config/chezmoi/profile.d/mise-security.sh.tmpl create mode 100644 dot_config/mise/config.toml.tmpl create mode 100644 dot_config/mise/mise.lock create mode 100644 mise.lock diff --git a/.chezmoiscripts/run_after_05-mise-trust.sh.tmpl b/.chezmoiscripts/run_after_05-mise-trust.sh.tmpl new file mode 100644 index 0000000..a8be006 --- /dev/null +++ b/.chezmoiscripts/run_after_05-mise-trust.sh.tmpl @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +{{ if eq .chezmoi.os "windows" }} +exit 0 +{{ else }} + +command -v mise >/dev/null 2>&1 || exit 0 + +mise_config="${XDG_CONFIG_HOME:-$HOME/.config}/mise/config.toml" +if [[ -f "$mise_config" ]]; then + mise trust -y "$mise_config" >/dev/null 2>&1 || true +fi + +repo_mise="{{ .chezmoi.sourceDir }}/.mise.toml" +if [[ -f "$repo_mise" ]]; then + mise trust -y "$repo_mise" >/dev/null 2>&1 || true +fi + +{{ end }} diff --git a/.mise.toml b/.mise.toml index 9284540..7525807 100644 --- a/.mise.toml +++ b/.mise.toml @@ -1,3 +1,5 @@ +# Repo-local QA toolchain. Refresh lockfile after version bumps: mise lock +# Lock enforcement: qa.just uses `mise exec --locked` (see mise-security skill). [tools] shellcheck = "0.11.0" shfmt = "3.12.0" diff --git a/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl b/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl index d87dfe0..9bc9aaf 100644 --- a/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl +++ b/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl @@ -14,6 +14,10 @@ if (-not $miseExe -and (Test-Path -LiteralPath $miseFallback)) { } if ($miseExe) { + if (-not $env:MISE_PARANOID) { $env:MISE_PARANOID = "1" } + if (-not $env:MISE_CEILING_PATHS) { $env:MISE_CEILING_PATHS = $HOME } + if (-not $env:MISE_EXPERIMENTAL) { $env:MISE_EXPERIMENTAL = "0" } + $miseBin = Split-Path -Parent $miseExe if (-not (($env:PATH -split ';') -contains $miseBin)) { $env:PATH = "$miseBin;$env:PATH" diff --git a/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl b/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl index 710b82f..7f75ecc 100644 --- a/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl +++ b/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl @@ -14,6 +14,10 @@ if (-not $miseExe -and (Test-Path -LiteralPath $miseFallback)) { } if ($miseExe) { + if (-not $env:MISE_PARANOID) { $env:MISE_PARANOID = "1" } + if (-not $env:MISE_CEILING_PATHS) { $env:MISE_CEILING_PATHS = $HOME } + if (-not $env:MISE_EXPERIMENTAL) { $env:MISE_EXPERIMENTAL = "0" } + $miseBin = Split-Path -Parent $miseExe if (-not (($env:PATH -split ';') -contains $miseBin)) { $env:PATH = "$miseBin;$env:PATH" diff --git a/OneDrive/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl b/OneDrive/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl index 710b82f..7f75ecc 100644 --- a/OneDrive/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl +++ b/OneDrive/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl @@ -14,6 +14,10 @@ if (-not $miseExe -and (Test-Path -LiteralPath $miseFallback)) { } if ($miseExe) { + if (-not $env:MISE_PARANOID) { $env:MISE_PARANOID = "1" } + if (-not $env:MISE_CEILING_PATHS) { $env:MISE_CEILING_PATHS = $HOME } + if (-not $env:MISE_EXPERIMENTAL) { $env:MISE_EXPERIMENTAL = "0" } + $miseBin = Split-Path -Parent $miseExe if (-not (($env:PATH -split ';') -contains $miseBin)) { $env:PATH = "$miseBin;$env:PATH" diff --git a/OneDrive/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl b/OneDrive/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl index 710b82f..7f75ecc 100644 --- a/OneDrive/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl +++ b/OneDrive/Documents/WindowsPowerShell/Microsoft.PowerShell_profile.ps1.tmpl @@ -14,6 +14,10 @@ if (-not $miseExe -and (Test-Path -LiteralPath $miseFallback)) { } if ($miseExe) { + if (-not $env:MISE_PARANOID) { $env:MISE_PARANOID = "1" } + if (-not $env:MISE_CEILING_PATHS) { $env:MISE_CEILING_PATHS = $HOME } + if (-not $env:MISE_EXPERIMENTAL) { $env:MISE_EXPERIMENTAL = "0" } + $miseBin = Split-Path -Parent $miseExe if (-not (($env:PATH -split ';') -contains $miseBin)) { $env:PATH = "$miseBin;$env:PATH" diff --git a/docs/repo-maintenance.md b/docs/repo-maintenance.md index ba4e149..7ea363e 100644 --- a/docs/repo-maintenance.md +++ b/docs/repo-maintenance.md @@ -73,6 +73,12 @@ Install QA tools with mise in this repo: mise install ``` +Lockfiles (`mise.lock`) pin exact binary hashes for QA and global tools. After +bumping a tool version, run `mise lock` (or `mise lock --global`) and commit the +lockfile. QA recipes pass `--locked` to `mise exec`. Global mise security +settings (paranoid mode, ceiling paths, disabled asdf backend) are managed by +chezmoi — see `~/.agents/skills/mise-security/SKILL.md`. + Run internal QA recipes via `qa.just`: ```bash diff --git a/dot_agents/skills/mise-security/SKILL.md b/dot_agents/skills/mise-security/SKILL.md new file mode 100644 index 0000000..e5b1c59 --- /dev/null +++ b/dot_agents/skills/mise-security/SKILL.md @@ -0,0 +1,70 @@ +--- +name: mise-security +description: >- + Security mitigation checklist for mise: supply-chain backends, paranoid trust, + ceiling paths, lockfiles, secrets handling, and CI hardening. Use when adding + mise tools, trusting a new mise.toml, or reviewing mise configuration in this + dotfiles repo or project checkouts. +--- + +# mise security mitigation checklist + +These settings are applied globally via chezmoi (`~/.config/mise/config.toml`, +`~/.config/chezmoi/profile.d/mise-security.sh`) and in this repo's `.mise.toml`. + +## Supply chain + +| Action | Status here | +| ------------------------------------------------------------------------------ | ----------------------------- | +| **Disable legacy backends** — `disable_backends = ["asdf"]` in global config | Applied | +| **Prefer verified backends** — use `aqua:`, `vfox:`, or `cargo:` when possible | Documented; QA tools use aqua | + +## Configuration + +| Action | Status here | +| ---------------------------------------------------------------------------------------------------------------------------------- | -------------------- | +| **Paranoid mode** — `MISE_PARANOID=1` before `mise activate` | Applied in profile.d | +| **Directory ceilings** — `MISE_CEILING_PATHS="$HOME"` | Applied in profile.d | +| **Trusted dotfiles source** — chezmoi source in `trusted_config_paths`; `chezmoi apply` runs `mise trust` on global + repo configs | Applied | + +Before running `mise trust` on a **new** repository, manually inspect `[tasks]` +and `[env]` in its `mise.toml` (and any `_.file` includes). + +## Reproducibility + +| Action | Status here | +| ------------------------------------------------------ | --------------------------------------------------------------------------------- | +| **Enforce lockfiles** — `mise lock` pins binary hashes | Global `~/.config/mise/mise.lock`; repo `mise.lock`; QA uses `mise exec --locked` | + +After bumping a tool version: + +```bash +mise lock --global # ~/.config/mise +mise lock # chezmoi source (QA tools) +``` + +Commit updated lockfiles with the version bump. + +## Secrets management + +| Action | Guidance | +| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| **Programmatic first** | Fetch infra secrets at runtime via centralized managers (AWS Secrets Manager, Vault, etc.) in shell hooks — not committed env files | +| **Encrypted local storage** | For local-only overrides, encrypt at rest with SOPS + age; reference via `_.file` in `mise.toml` | + +## CI/CD hardening + +| Action | Status here | +| --------------------------------------------------------- | --------------------------------------------------------------------------------- | +| **Disable experimental features** — `MISE_EXPERIMENTAL=0` | Applied in profile.d (default); override only when testing unstable mise features | + +In CI scripts that invoke mise, export the same vars or pass +`mise exec --locked`. + +## Quick verification + +```bash +mise settings disable_backends # expect: ["asdf"] +echo "$MISE_PARANOID $MISE_CEILING_PATHS $MISE_EXPERIMENTAL" +mise exec --locked -- shellcheck --version # from chezmoi source +``` diff --git a/dot_config/chezmoi/profile.d/mise-security.sh.tmpl b/dot_config/chezmoi/profile.d/mise-security.sh.tmpl new file mode 100644 index 0000000..f3dd621 --- /dev/null +++ b/dot_config/chezmoi/profile.d/mise-security.sh.tmpl @@ -0,0 +1,7 @@ +# mise security env — loaded before `mise activate` in dot_bash_profile / dot_zshrc. +# See ~/.agents/skills/mise-security/SKILL.md +{{- if ne .chezmoi.os "windows" }} +export MISE_PARANOID="${MISE_PARANOID:-1}" +export MISE_CEILING_PATHS="${MISE_CEILING_PATHS:-$HOME}" +export MISE_EXPERIMENTAL="${MISE_EXPERIMENTAL:-0}" +{{- end }} diff --git a/dot_config/mise/config.toml.tmpl b/dot_config/mise/config.toml.tmpl new file mode 100644 index 0000000..d1d2c73 --- /dev/null +++ b/dot_config/mise/config.toml.tmpl @@ -0,0 +1,15 @@ +# mise global config — security posture in ~/.agents/skills/mise-security/SKILL.md +# +# Supply chain: block legacy asdf shell-script backends; prefer aqua, vfox, or +# cargo (checksums / attestations) when adding tools. +[settings] +disable_backends = ["asdf"] +# Dotfiles chezmoi source: repo-local QA .mise.toml (no tasks/env); auto-trusted under paranoid mode. +trusted_config_paths = [ + "{{ if hasPrefix .chezmoi.homeDir .chezmoi.sourceDir }}{{ replace .chezmoi.homeDir "~" .chezmoi.sourceDir }}{{ else }}{{ .chezmoi.sourceDir }}{{ end }}", +] + +# Reproducibility: refresh after version bumps with `mise lock --global`. +[tools] +bun = "1.3.13" +python = "3.13.0" diff --git a/dot_config/mise/mise.lock b/dot_config/mise/mise.lock new file mode 100644 index 0000000..fd53c73 --- /dev/null +++ b/dot_config/mise/mise.lock @@ -0,0 +1,83 @@ +# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html + +[[tools.bun]] +version = "1.3.13" +backend = "core:bun" + +[tools.bun."platforms.linux-arm64"] +checksum = "sha256:70bae41b3908b0a120e1e58c5c8af30e74afae3b8d11b0d3fdd8e787ddfb4b22" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-linux-aarch64.zip" + +[tools.bun."platforms.linux-arm64-musl"] +checksum = "sha256:5385e978107ce4934298d8d6afe9bfbb898683f6cc23e6753a0da60bc60c5b81" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-linux-aarch64-musl.zip" + +[tools.bun."platforms.linux-x64"] +checksum = "sha256:79c0771fa8b92c33aae41e15a0e0d307ea99d0e2f00317c71c6c53237a78e25a" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-linux-x64.zip" + +[tools.bun."platforms.linux-x64-baseline"] +checksum = "sha256:9d8a24292a7068090205daac0a5a223f5f69736f5287e37bf88d3b4031edc750" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-linux-x64-baseline.zip" + +[tools.bun."platforms.linux-x64-musl"] +checksum = "sha256:5b91a48f0b00df9fd2da8bff1a795d2659d842da966432969203f25da19d1c74" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-linux-x64-musl.zip" + +[tools.bun."platforms.linux-x64-musl-baseline"] +checksum = "sha256:88ca7c7ad235b498f549eea2f770f434e9f0f5e9ba95168a2d3a1f235184c394" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-linux-x64-musl-baseline.zip" + +[tools.bun."platforms.macos-arm64"] +checksum = "sha256:5467e3f65dba526b9fea98f0cce04efafc0c63e169733ec27b876a3ad32da190" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-darwin-aarch64.zip" + +[tools.bun."platforms.macos-x64"] +checksum = "sha256:e5a6c8b64f419925232d111ecb13e25f0abf55e54f792341f987623fd0778009" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-darwin-x64.zip" + +[tools.bun."platforms.macos-x64-baseline"] +checksum = "sha256:a98ba6a480f22fda9b343626b906a4e26aa53618bf85d2bc5928ecf2ba45f0ed" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-darwin-x64-baseline.zip" + +[tools.bun."platforms.windows-x64"] +checksum = "sha256:85b14f3e0584218e9b63407b3aa6b90c4835ec5c32435c1f12cb6fc13667c7c9" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-windows-x64.zip" + +[tools.bun."platforms.windows-x64-baseline"] +checksum = "sha256:c68c7903c1190101590cc1b2129835f47211b3b37ae87759f2b97d6534aa3ad1" +url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-windows-x64-baseline.zip" + +[[tools.python]] +version = "3.13.0" +backend = "core:python" + +[tools.python."platforms.linux-arm64"] +checksum = "sha256:06e633164cb0133685a2ce14af88df0dbcaea4b0b2c5d3348d6b81393307481a" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20241016/cpython-3.13.0+20241016-aarch64-unknown-linux-gnu-install_only_stripped.tar.gz" +provenance = "github-attestations" + +[tools.python."platforms.linux-x64"] +checksum = "sha256:b5e74d1e16402b633c6f04519618231fc0dbae7d2f9e4b1ac17c294cc3d3d076" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20241016/cpython-3.13.0+20241016-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz" +provenance = "github-attestations" + +[tools.python."platforms.linux-x64-musl"] +checksum = "sha256:10978500ab6589760716c644aeadffa0f2c0bf31ea10f0c6160fee933933a567" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20241016/cpython-3.13.0+20241016-x86_64-unknown-linux-musl-install_only_stripped.tar.gz" +provenance = "github-attestations" + +[tools.python."platforms.macos-arm64"] +checksum = "sha256:e94fafbac07da52c965cb6a7ffc51ce779bd253cd98af801347aac791b96499f" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20241016/cpython-3.13.0+20241016-aarch64-apple-darwin-install_only_stripped.tar.gz" +provenance = "github-attestations" + +[tools.python."platforms.macos-x64"] +checksum = "sha256:406664681bd44af35756ad08f5304f1ec57070bb76fae8ff357ff177f229b224" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20241016/cpython-3.13.0+20241016-x86_64-apple-darwin-install_only_stripped.tar.gz" +provenance = "github-attestations" + +[tools.python."platforms.windows-x64"] +checksum = "sha256:c8134287496727922a5c47896b4f2b1623e3aab91cbb7c1ca64542db7593f3f1" +url = "https://github.com/astral-sh/python-build-standalone/releases/download/20241016/cpython-3.13.0+20241016-x86_64-pc-windows-msvc-install_only_stripped.tar.gz" +provenance = "github-attestations" diff --git a/mise.lock b/mise.lock new file mode 100644 index 0000000..ca5e2bb --- /dev/null +++ b/mise.lock @@ -0,0 +1,87 @@ +# @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html + +[[tools.bats]] +version = "1.13.0" +backend = "aqua:bats-core/bats-core" + +[tools.bats."platforms.linux-arm64"] +url = "https://github.com/bats-core/bats-core/archive/refs/tags/v1.13.0.tar.gz" + +[tools.bats."platforms.linux-arm64-musl"] +url = "https://github.com/bats-core/bats-core/archive/refs/tags/v1.13.0.tar.gz" + +[tools.bats."platforms.linux-x64"] +url = "https://github.com/bats-core/bats-core/archive/refs/tags/v1.13.0.tar.gz" + +[tools.bats."platforms.linux-x64-musl"] +url = "https://github.com/bats-core/bats-core/archive/refs/tags/v1.13.0.tar.gz" + +[tools.bats."platforms.macos-arm64"] +url = "https://github.com/bats-core/bats-core/archive/refs/tags/v1.13.0.tar.gz" + +[tools.bats."platforms.macos-x64"] +url = "https://github.com/bats-core/bats-core/archive/refs/tags/v1.13.0.tar.gz" + +[[tools.shellcheck]] +version = "0.11.0" +backend = "aqua:koalaman/shellcheck" + +[tools.shellcheck."platforms.linux-arm64"] +checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz" + +[tools.shellcheck."platforms.linux-arm64-musl"] +checksum = "sha256:12b331c1d2db6b9eb13cfca64306b1b157a86eb69db83023e261eaa7e7c14588" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.aarch64.tar.xz" + +[tools.shellcheck."platforms.linux-x64"] +checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz" + +[tools.shellcheck."platforms.linux-x64-musl"] +checksum = "sha256:8c3be12b05d5c177a04c29e3c78ce89ac86f1595681cab149b65b97c4e227198" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz" + +[tools.shellcheck."platforms.macos-arm64"] +checksum = "sha256:56affdd8de5527894dca6dc3d7e0a99a873b0f004d7aabc30ae407d3f48b0a79" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.aarch64.tar.xz" + +[tools.shellcheck."platforms.macos-x64"] +checksum = "sha256:3c89db4edcab7cf1c27bff178882e0f6f27f7afdf54e859fa041fca10febe4c6" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.darwin.x86_64.tar.xz" + +[tools.shellcheck."platforms.windows-x64"] +checksum = "sha256:8a4e35ab0b331c85d73567b12f2a444df187f483e5079ceffa6bda1faa2e740e" +url = "https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.zip" + +[[tools.shfmt]] +version = "3.12.0" +backend = "aqua:mvdan/sh" + +[tools.shfmt."platforms.linux-arm64"] +checksum = "sha256:5f3fe3fa6a9f766e6a182ba79a94bef8afedafc57db0b1ad32b0f67fae971ba4" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_linux_arm64" + +[tools.shfmt."platforms.linux-arm64-musl"] +checksum = "sha256:5f3fe3fa6a9f766e6a182ba79a94bef8afedafc57db0b1ad32b0f67fae971ba4" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_linux_arm64" + +[tools.shfmt."platforms.linux-x64"] +checksum = "sha256:d9fbb2a9c33d13f47e7618cf362a914d029d02a6df124064fff04fd688a745ea" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_linux_amd64" + +[tools.shfmt."platforms.linux-x64-musl"] +checksum = "sha256:d9fbb2a9c33d13f47e7618cf362a914d029d02a6df124064fff04fd688a745ea" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_linux_amd64" + +[tools.shfmt."platforms.macos-arm64"] +checksum = "sha256:d903802e0ce3ecbc82b98512f55ba370b0d37a93f3f78de394f5b657052b33dd" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_darwin_arm64" + +[tools.shfmt."platforms.macos-x64"] +checksum = "sha256:c31548693de6584e6164b7ed5fbb7b4a083f2d937ca94b4e0ddf59aa461a85e4" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_darwin_amd64" + +[tools.shfmt."platforms.windows-x64"] +checksum = "sha256:c8bda517ba1c640ce4a715c0fa665439ddbe4357ba5e9b77b0e51e70e2b9c94b" +url = "https://github.com/mvdan/sh/releases/download/v3.12.0/shfmt_v3.12.0_windows_amd64.exe" diff --git a/qa.just b/qa.just index 3ddb3a0..347ddc6 100644 --- a/qa.just +++ b/qa.just @@ -8,18 +8,18 @@ lint-shell: @set -euo pipefail; \ fmt_files=("{{ justfile_directory() }}/scripts/bookmark-pr-hygiene.sh" "{{ justfile_directory() }}/scripts/repos-smoke.sh"); \ while IFS= read -r _file; do fmt_files+=("$_file"); done < <(find "{{ justfile_directory() }}/tests/shell" -type f \( -name '*.sh' -o -name '*.bash' -o -name '*.bats' \) 2>/dev/null | sort); \ - mise exec -- shfmt -d -i 2 -ci "${fmt_files[@]}"; \ + mise exec --locked -- shfmt -d -i 2 -ci "${fmt_files[@]}"; \ sc_files=("{{ justfile_directory() }}/scripts/bookmark-pr-hygiene.sh" "{{ justfile_directory() }}/scripts/repos-smoke.sh"); \ while IFS= read -r _file; do sc_files+=("$_file"); done < <(find "{{ justfile_directory() }}/tests/shell" -type f \( -name '*.sh' -o -name '*.bash' \) 2>/dev/null | sort); \ - mise exec -- shellcheck "${sc_files[@]}" + mise exec --locked -- shellcheck "${sc_files[@]}" # Run deterministic shell unit tests. test-shell-unit: - @mise exec -- bats "{{ justfile_directory() }}/tests/shell/unit" + @mise exec --locked -- bats "{{ justfile_directory() }}/tests/shell/unit" # Run black-box integration shell tests. test-shell-integration: - @mise exec -- bats "{{ justfile_directory() }}/tests/shell/integration" + @mise exec --locked -- bats "{{ justfile_directory() }}/tests/shell/integration" # Run lightweight smoke checks for public just command contracts. smoke-shell: From 2b22076956039486c0c06fd7a7cfec5b780b9021 Mon Sep 17 00:00:00 2001 From: aguil Date: Thu, 11 Jun 2026 17:18:51 -0600 Subject: [PATCH 2/2] fix(pre-commit): use system prettier hook Switch the markdown Prettier hook to language: system so hook setup does not run npm install against the Workiva registry. Install prettier in CI for the same hook on ubuntu-latest. --- .github/workflows/pre-commit.yml | 7 +++++++ .pre-commit-config.yaml | 8 ++++++-- repos.just | 4 +++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 5e08499..2fdeef1 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -15,4 +15,11 @@ jobs: with: python-version: "3.12" + - uses: actions/setup-node@v5 + with: + node-version: "20" + + - name: Install prettier for system hook + run: npm install -g prettier@3.1.0 + - uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 51ae37b..32c3cf2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,8 +9,12 @@ repos: args: [--markdown-linebreak-ext=md] files: \.md$ - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v3.1.0 + # System prettier avoids npm install during hook setup (Workiva npm registry + # in ~/.wk/config/npm.toml breaks mirrors-prettier node hooks locally). + - repo: local hooks: - id: prettier + name: prettier (markdown) + entry: prettier --write --ignore-unknown + language: system types_or: [markdown] diff --git a/repos.just b/repos.just index 8fb862c..c0e49d1 100644 --- a/repos.just +++ b/repos.just @@ -29,7 +29,8 @@ hygiene-prune *args: bash "$script" prune {{ args }} # Install the git pre-commit hook for this repo (markdown Prettier + whitespace). -# Run once per clone. Requires the `pre-commit` CLI (e.g. brew install pre-commit). +# Run once per clone. Requires the `pre-commit` CLI (e.g. brew install pre-commit) +# and `prettier` on PATH (e.g. brew install prettier). pre-commit-install: @set -euo pipefail; \ _root="{{ justfile_directory() }}"; \ @@ -38,6 +39,7 @@ pre-commit-install: cd "$_root" && pre-commit install # Run the same hooks as CI on all tracked files (offline parity check). +# Requires `prettier` on PATH (brew install prettier). pre-commit-verify: @set -euo pipefail; \ _root="{{ justfile_directory() }}"; \