C1: SHA-pin tooling dependencies (2026-04 cycle) (#344)
All checks were successful
Deploy Fly.io Proxy / deploy (push) Successful in 1m45s
All checks were successful
Deploy Fly.io Proxy / deploy (push) Successful in 1m45s
## Summary Monthly tooling dependency refresh, with a one-time conversion from version-tag pins (`rev = "vX.Y.Z"`, `image:tag`, `>=`) to SHA / digest pins everywhere. ## Changes - **prek hooks**: all `rev = "vX.Y.Z"` → commit SHA + `# vX.Y.Z` comment. Bumped trufflehog (3.94.0→3.95.2), kingfisher (1.91.0→1.97.0), ruff (0.15.7→0.15.12), shfmt (3.13.0→3.13.1), prettier (3.8.1→3.8.3), actionlint (1.7.11→1.7.12). - **fly/Dockerfile**: tag pins → `image@sha256:...` digest pins. Bumped nginx (1.29.6→1.30.0-alpine), tailscale (v1.94.1→v1.94.2 — still inside the safe pre-1.96.5 range), alloy (v1.14.1→v1.16.0). - **mise-tasks**: PEP 723 inline deps converted from `>=` to `==` (PEP 508 doesn't support hashes inline). All scripts pinned to current latest: rich 15.0.0, typer 0.25.0, pyyaml 6.0.3, httpx 0.28.1. - **prek `additional_dependencies`**: ansible-lint==26.4.0, ansible-core==2.20.5. - **taplo-lint**: pass `--no-schema`. Upstream's `--default-schema-catalogs` returns a format taplo v0.9.3 can't parse — we don't validate against TOML schemas anyway, so this turns off the broken catalog fetch. - **docs/update-tooling-dependencies**: documents the SHA-pin convention, `docker buildx imagetools inspect` for digest lookup, and `prek clean` before re-verifying (cache grows to several GiB). Forgejo workflow `actions/checkout@v6.0.2` was already at the latest SHA — no change. ## Test plan - [x] `prek run --all-files` passes after `prek clean` - [x] `deploy-fly` workflow builds and deploys the new fly image on merge - [x] `fly status -a blumeops-proxy` healthy after deploy - [x] Spot-check a few mise tasks (`mise run blumeops-tasks`, `mise run docs-check-links`) to confirm pinned deps resolve cleanly Reviewed-on: #344
This commit is contained in:
parent
5096223b48
commit
f6e392b80c
29 changed files with 174 additions and 47 deletions
1
docs/changelog.d/update-tooling-deps-2026-04.doc.md
Normal file
1
docs/changelog.d/update-tooling-deps-2026-04.doc.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
New how-to: rotate-fly-deploy-token. Documents the 75-day rotation cadence, why we use `org`-scoped tokens (silences the cosmetic metrics-token warning on `fly status` with marginal blast-radius cost given the single-app personal org), and the procedure for rotation + Forgejo Actions secret sync.
|
||||||
1
docs/changelog.d/update-tooling-deps-2026-04.infra.md
Normal file
1
docs/changelog.d/update-tooling-deps-2026-04.infra.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Monthly tooling dependency refresh: prek hooks (trufflehog, kingfisher, ruff, shfmt, prettier, actionlint, ansible-lint), fly proxy base images (nginx 1.30.0, tailscale v1.94.2, alloy v1.16.0), normalize pyyaml lower bound in mise-tasks.
|
||||||
108
docs/how-to/configuration/rotate-fly-deploy-token.md
Normal file
108
docs/how-to/configuration/rotate-fly-deploy-token.md
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
---
|
||||||
|
title: Rotate the Fly.io API Token
|
||||||
|
modified: 2026-04-30
|
||||||
|
last-reviewed: 2026-04-30
|
||||||
|
tags:
|
||||||
|
- how-to
|
||||||
|
- fly-io
|
||||||
|
- secrets
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rotate the Fly.io API Token
|
||||||
|
|
||||||
|
How to rotate the Fly.io API token used to deploy [[flyio-proxy]]. The token lives in 1Password at `op://blumeops/fly.io admin/add more/deploy-token` and is consumed by [`mise run fly-deploy`](../../../mise-tasks/fly-deploy) and the `deploy-fly` Forgejo workflow (via the `FLY_DEPLOY_TOKEN` secret).
|
||||||
|
|
||||||
|
## When to rotate
|
||||||
|
|
||||||
|
- Every 75 days (Todoist recurring task)
|
||||||
|
- After any compromise / accidental disclosure
|
||||||
|
- If `fly deploy` starts returning auth errors
|
||||||
|
|
||||||
|
Fly.io tokens default to a 20-year expiry, but a short rotation cadence limits the blast radius of an undetected leak. Token expiry is set to **90 days** (longer than the rotation window), leaving a 15-day buffer if a rotation is delayed.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Use **`fly tokens create org`**, not `deploy`.
|
||||||
|
|
||||||
|
| Scope | What it grants | Practical blast radius (this org) |
|
||||||
|
|-------|---------------|-----------------------------------|
|
||||||
|
| `deploy` | Manage one app and its resources | Same single-app surface as `org` for current setup |
|
||||||
|
| `org` | Manage one org and its resources | Adds: ability to create new apps (billing abuse) and read org-level metadata |
|
||||||
|
| `readonly` | Read one org | Not enough to deploy |
|
||||||
|
| Personal access token | Full account | Excessive |
|
||||||
|
|
||||||
|
The personal Fly org currently contains a single app (`blumeops-proxy`), so the marginal blast radius of `org` over `deploy` is small. The benefit of `org` is that `fly status` works without a `Metrics token unavailable: ... context canceled` warning. That warning happens because `fly status` always tries to fetch org-level metrics-token info, and an app-scoped `deploy` token can't query the org. The warning is benign but persistent and could mask a real future failure.
|
||||||
|
|
||||||
|
If a second Fly app is ever added to this org, reconsider — at that point the marginal scope cost of `org` grows.
|
||||||
|
|
||||||
|
## Procedure
|
||||||
|
|
||||||
|
### 1. Authenticate flyctl with the current token
|
||||||
|
|
||||||
|
```fish
|
||||||
|
fly auth login
|
||||||
|
```
|
||||||
|
|
||||||
|
(Browser-based. Required to mint a new token, since the existing deploy token can't create tokens.)
|
||||||
|
|
||||||
|
### 2. Mint the new token
|
||||||
|
|
||||||
|
```fish
|
||||||
|
fly tokens create org \
|
||||||
|
--org personal \
|
||||||
|
--name "blumeops-proxy deploy $(date +%Y-%m-%d)" \
|
||||||
|
--expiry 2160h
|
||||||
|
```
|
||||||
|
|
||||||
|
(`2160h` = 90 days, paired with the 75-day rotation cadence for a 15-day buffer. Capture the output — it's the only time the token is shown.)
|
||||||
|
|
||||||
|
### 3. Update 1Password
|
||||||
|
|
||||||
|
```fish
|
||||||
|
op item edit on5slfaygtdjrxmdwezyhfmqsq 'add more.deploy-token=<paste-new-token>' --vault vg6xf6vvfmoh5hqjjhlhbeoaie
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Sync to Forgejo Actions
|
||||||
|
|
||||||
|
The `deploy-fly` workflow reads the same token from a Forgejo Actions secret named `FLY_DEPLOY_TOKEN`, populated by the `forgejo_actions_secrets` ansible role:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
mise run provision-indri -- --tags forgejo_actions_secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Verify
|
||||||
|
|
||||||
|
```fish
|
||||||
|
mise run fly-deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
A successful deploy confirms the new token works locally. Watch for the metrics-token warning — it should be **absent** with an `org`-scoped token. If still present, the rotation produced a `deploy`-scoped token by mistake.
|
||||||
|
|
||||||
|
Then trigger the CI workflow (push a no-op commit touching `fly/`, or dispatch manually) to confirm Forgejo Actions has the new secret.
|
||||||
|
|
||||||
|
### 6. Revoke the old token
|
||||||
|
|
||||||
|
```fish
|
||||||
|
fly tokens list
|
||||||
|
fly tokens revoke <old-token-id>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
### `fly deploy` returns "unauthorized"
|
||||||
|
|
||||||
|
Token is invalid (expired, revoked, or wrong scope). Repeat the procedure.
|
||||||
|
|
||||||
|
### `Metrics token unavailable: ... context canceled` after rotation
|
||||||
|
|
||||||
|
The new token was created with `deploy` scope, not `org`. Either accept it (cosmetic) or re-mint with `fly tokens create org`.
|
||||||
|
|
||||||
|
### Forgejo Actions deploy fails but local works
|
||||||
|
|
||||||
|
The Forgejo secret wasn't synced. Re-run `mise run provision-indri -- --tags forgejo_actions_secrets` and confirm the secret value in Forgejo matches 1Password.
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[flyio-proxy]] — Service reference card
|
||||||
|
- [[manage-flyio-proxy]] — Day-to-day operations and Tailscale auth-key rotation (separate 90-day rotation)
|
||||||
|
- [[expose-service-publicly]] — Full setup architecture
|
||||||
|
|
@ -28,33 +28,45 @@ Out of scope: ArgoCD-deployed service images, Ansible role versions, NixOS flake
|
||||||
|
|
||||||
### 1. Check prek hook versions
|
### 1. Check prek hook versions
|
||||||
|
|
||||||
For each repo in `prek.toml` with a `rev =` value, check the upstream GitHub releases page for a newer tag. Update each `rev` to the latest release tag. Also check `additional_dependencies` entries for PyPI version bumps.
|
For each repo in `prek.toml` with a `rev =` value, check the upstream GitHub releases page for a newer tag. Update each `rev` to the **commit SHA** of the latest release with a trailing `# vX.Y.Z` comment (matches the `additional_dependencies` and Forgejo workflow pinning style). Also check `additional_dependencies` entries for PyPI version bumps and pin them with `==`.
|
||||||
|
|
||||||
Verify after updating:
|
|
||||||
|
|
||||||
```fish
|
```fish
|
||||||
|
git ls-remote --tags https://github.com/<owner>/<repo>.git 'refs/tags/v*' | sort -t/ -k3 -V | tail -5
|
||||||
|
```
|
||||||
|
|
||||||
|
Clear the prek cache before verifying — it can grow to several GiB (one venv per hook per version) and old cached environments can mask resolution failures or stale catalogs:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
prek clean
|
||||||
prek run --all-files
|
prek run --all-files
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Check Fly.io Dockerfile pins
|
### 2. Check Fly.io Dockerfile pins
|
||||||
|
|
||||||
Review `fly/Dockerfile` for pinned image tags:
|
Review `fly/Dockerfile` for pinned image digests. Each `FROM` and `COPY --from=` uses `image@sha256:...` digest pinning with a comment line above documenting the human-readable version.
|
||||||
|
|
||||||
- **nginx** — check [Docker Hub](https://hub.docker.com/_/nginx) for latest stable alpine tag
|
- **nginx** — check [Docker Hub](https://hub.docker.com/_/nginx) for latest stable alpine tag
|
||||||
- **grafana/alloy** — check [GitHub releases](https://github.com/grafana/alloy/releases)
|
- **grafana/alloy** — check [GitHub releases](https://github.com/grafana/alloy/releases)
|
||||||
- **tailscale/tailscale** — uses `stable` rolling tag, no action needed
|
- **tailscale/tailscale** — pinned to a known-good version. Do not bump to v1.96.5 or later (MagicDNS regression breaks the proxy boot)
|
||||||
|
|
||||||
|
To resolve a tag to a digest:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
docker buildx imagetools inspect docker.io/<image>:<tag>
|
||||||
|
# Use the top-level "Digest:" line (multi-arch index) — not the per-platform sub-digest
|
||||||
|
```
|
||||||
|
|
||||||
After updating, the deploy-fly workflow will build and deploy on merge to main. Verify with `fly status -a blumeops-proxy` after deploy.
|
After updating, the deploy-fly workflow will build and deploy on merge to main. Verify with `fly status -a blumeops-proxy` after deploy.
|
||||||
|
|
||||||
### 3. Normalize mise task dependency bounds
|
### 3. Pin mise task dependencies
|
||||||
|
|
||||||
Mise tasks use `uv run --script` with inline PEP 723 dependency metadata. Check that lower bounds are consistent across all scripts:
|
Mise tasks use `uv run --script` with inline PEP 723 dependency metadata. All packages are pinned with `==` (PEP 508 doesn't support hashes inline). Check that pinned versions are consistent across all scripts:
|
||||||
|
|
||||||
```fish
|
```fish
|
||||||
grep -r 'dependencies' mise-tasks/ | grep '# dependencies'
|
grep -r 'dependencies' mise-tasks/ | grep '# dependencies'
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensure all scripts using the same package agree on the minimum version. When a package has a new major or breaking minor release, bump the lower bound across all scripts at once.
|
For each package in use (`httpx`, `rich`, `typer`, `pyyaml`), pick the latest PyPI version and update every script in lockstep — divergence between scripts is the failure mode this catches. Bump everything together; don't leave one script behind.
|
||||||
|
|
||||||
### 4. Pin Forgejo workflow action versions
|
### 4. Pin Forgejo workflow action versions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,10 @@ The auth key expires every 90 days. To rotate:
|
||||||
2. Re-run setup to stage the new secret: `mise run fly-setup`
|
2. Re-run setup to stage the new secret: `mise run fly-setup`
|
||||||
3. Deploy to pick up the new secret: `mise run fly-deploy`
|
3. Deploy to pick up the new secret: `mise run fly-deploy`
|
||||||
|
|
||||||
|
## Rotate Fly.io API Token
|
||||||
|
|
||||||
|
See [[rotate-fly-deploy-token]] for the full rotation procedure (75-day cadence, `org`-scoped).
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
**502 Bad Gateway on fresh deploy**: MagicDNS may not be ready when nginx starts. The `start.sh` script polls `nslookup` before launching nginx, but if it still fails, check that `tailscale status` is healthy inside the container.
|
**502 Bad Gateway on fresh deploy**: MagicDNS may not be ready when nginx starts. The `start.sh` script polls `nslookup` before launching nginx, but if it still fails, check that `tailscale status` is healthy inside the container.
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
FROM nginx:1.29.6-alpine
|
# nginx 1.30.0-alpine
|
||||||
|
FROM nginx@sha256:0272e4604ed93c1792f03695a033a6e8546840f86e0de20a884bb17d2c924883
|
||||||
|
|
||||||
# Copy tailscale binaries from official image
|
# Copy tailscale binaries from official image (v1.94.2)
|
||||||
COPY --from=docker.io/tailscale/tailscale:v1.94.1 \
|
COPY --from=docker.io/tailscale/tailscale@sha256:95e528798bebe75f39b10e74e7051cf51188ee615934f232ba7ad06a3390ffa1 \
|
||||||
/usr/local/bin/tailscaled /usr/local/bin/tailscaled
|
/usr/local/bin/tailscaled /usr/local/bin/tailscaled
|
||||||
COPY --from=docker.io/tailscale/tailscale:v1.94.1 \
|
COPY --from=docker.io/tailscale/tailscale@sha256:95e528798bebe75f39b10e74e7051cf51188ee615934f232ba7ad06a3390ffa1 \
|
||||||
/usr/local/bin/tailscale /usr/local/bin/tailscale
|
/usr/local/bin/tailscale /usr/local/bin/tailscale
|
||||||
|
|
||||||
RUN mkdir -p /var/run/tailscale /var/lib/tailscale \
|
RUN mkdir -p /var/run/tailscale /var/lib/tailscale \
|
||||||
|
|
@ -12,8 +13,8 @@ RUN mkdir -p /var/run/tailscale /var/lib/tailscale \
|
||||||
&& apk add --no-cache fail2ban \
|
&& apk add --no-cache fail2ban \
|
||||||
&& rm -f /etc/fail2ban/jail.d/alpine-ssh.conf
|
&& rm -f /etc/fail2ban/jail.d/alpine-ssh.conf
|
||||||
|
|
||||||
# Copy Alloy binary from official image (Ubuntu-based, needs libc6-compat)
|
# Copy Alloy binary from official image (v1.16.0, Ubuntu-based, needs libc6-compat)
|
||||||
COPY --from=docker.io/grafana/alloy:v1.14.1 \
|
COPY --from=docker.io/grafana/alloy@sha256:6e00cf7c5a692ff5f24844529416ed017d76fce922f8199004e73d5eca46b6b8 \
|
||||||
/bin/alloy /usr/local/bin/alloy
|
/bin/alloy /usr/local/bin/alloy
|
||||||
|
|
||||||
RUN mkdir -p /var/log/nginx /etc/alloy /tmp/alloy-data
|
RUN mkdir -p /var/log/nginx /etc/alloy /tmp/alloy-data
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="List Blumeops tasks from Todoist sorted by priority"
|
#MISE description="List Blumeops tasks from Todoist sorted by priority"
|
||||||
"""Fetch and display Blumeops tasks from Todoist, sorted by priority.
|
"""Fetch and display Blumeops tasks from Todoist, sorted by priority.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Delete branches that have been merged into main (local and remote)"
|
#MISE description="Delete branches that have been merged into main (local and remote)"
|
||||||
#MISE alias="bc"
|
#MISE alias="bc"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["typer>=0.24.0", "httpx>=0.28.1"]
|
# dependencies = ["typer==0.25.0", "httpx==0.28.1"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Trigger container build workflows via Forgejo API"
|
#MISE description="Trigger container build workflows via Forgejo API"
|
||||||
#USAGE arg "<container>" help="Container name (directory under containers/)"
|
#USAGE arg "<container>" help="Container name (directory under containers/)"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="List available containers and their recent tags"
|
#MISE description="List available containers and their recent tags"
|
||||||
#USAGE arg "[name]" help="Optional container name to filter output"
|
#USAGE arg "[name]" help="Optional container name to filter output"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["pyyaml>=6.0.2", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["pyyaml==6.0.3", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Validate container version consistency across container.py, Dockerfiles, nix derivations, and service-versions.yaml"
|
#MISE description="Validate container version consistency across container.py, Dockerfiles, nix derivations, and service-versions.yaml"
|
||||||
#USAGE flag "--all-files" help="Check all containers, not just changed ones"
|
#USAGE flag "--all-files" help="Check all containers, not just changed ones"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Delete orphaned ACME challenge TXT records in eblu.me"
|
#MISE description="Delete orphaned ACME challenge TXT records in eblu.me"
|
||||||
#USAGE flag "--dry-run" help="List orphans without deleting"
|
#USAGE flag "--dry-run" help="List orphans without deleting"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0"]
|
# dependencies = ["rich==15.0.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Check that all docs have required frontmatter fields"
|
#MISE description="Check that all docs have required frontmatter fields"
|
||||||
"""Validate that all documentation files have required YAML frontmatter.
|
"""Validate that all documentation files have required YAML frontmatter.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0"]
|
# dependencies = ["rich==15.0.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Validate all wiki-links point to existing doc files"
|
#MISE description="Validate all wiki-links point to existing doc files"
|
||||||
"""Validate that all wiki-links in documentation point to existing files.
|
"""Validate that all wiki-links in documentation point to existing files.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "pyyaml>=6.0.2", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "pyyaml==6.0.3", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="View active Mikado dependency chains for C2 changes"
|
#MISE description="View active Mikado dependency chains for C2 changes"
|
||||||
#USAGE arg "[card]" help="Card stem to show chain for"
|
#USAGE arg "[card]" help="Card stem to show chain for"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["pyyaml>=6.0.2", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["pyyaml==6.0.3", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Build docs with Dagger and serve locally, opening to a specific card"
|
#MISE description="Build docs with Dagger and serve locally, opening to a specific card"
|
||||||
#USAGE arg "<card>" help="Card path relative to docs/, e.g. how-to/knowledgebase/review-documentation"
|
#USAGE arg "<card>" help="Card path relative to docs/, e.g. how-to/knowledgebase/review-documentation"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["pyyaml>=6.0.2", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["pyyaml==6.0.3", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Review the most stale documentation card by last-reviewed date"
|
#MISE description="Review the most stale documentation card by last-reviewed date"
|
||||||
#USAGE flag "--limit <limit>" default="15" help="Number of docs to show in the table"
|
#USAGE flag "--limit <limit>" default="15" help="Number of docs to show in the table"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Report docs by git-last-modified date, highlighting stale ones"
|
#MISE description="Report docs by git-last-modified date, highlighting stale ones"
|
||||||
#USAGE flag "--threshold <threshold>" default="180" help="Days before a doc is considered stale"
|
#USAGE flag "--threshold <threshold>" default="180" help="Days before a doc is considered stale"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["pyyaml>=6.0.2", "rich>=14.0.0"]
|
# dependencies = ["pyyaml==6.0.3", "rich==15.0.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Print frontmatter tag inventory across all docs"
|
#MISE description="Print frontmatter tag inventory across all docs"
|
||||||
"""Print every frontmatter tag with usage count and file list.
|
"""Print every frontmatter tag with usage count and file list.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Validate Mikado Branch Invariant on mikado/* branches"
|
#MISE description="Validate Mikado Branch Invariant on mikado/* branches"
|
||||||
#USAGE arg "[commit_msg_file]" help="Commit message file (passed by commit-msg hook)"
|
#USAGE arg "[commit_msg_file]" help="Commit message file (passed by commit-msg hook)"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Encrypt a 1Password .1pux export and send to indri for borgmatic"
|
#MISE description="Encrypt a 1Password .1pux export and send to indri for borgmatic"
|
||||||
#USAGE arg "[export_path]" help="Path to .1pux export file (prompted if omitted)"
|
#USAGE arg "[export_path]" help="Path to .1pux export file (prompted if omitted)"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="List unresolved comments on a PR"
|
#MISE description="List unresolved comments on a PR"
|
||||||
#USAGE arg "<pr_number>" help="Pull request number"
|
#USAGE arg "<pr_number>" help="Pull request number"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Prune old NixOS generations on ringtail, preserving rollback safety"
|
#MISE description="Prune old NixOS generations on ringtail, preserving rollback safety"
|
||||||
#MISE alias="prg"
|
#MISE alias="prg"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["pyyaml>=6.0.2", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["pyyaml==6.0.3", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Review the most stale compensating control"
|
#MISE description="Review the most stale compensating control"
|
||||||
#USAGE flag "--limit <limit>" default="10" help="Number of controls to show in the table"
|
#USAGE flag "--limit <limit>" default="10" help="Number of controls to show in the table"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["rich>=14.0.0", "typer>=0.24.0", "pyyaml>=6.0"]
|
# dependencies = ["rich==15.0.0", "typer==0.25.0", "pyyaml==6.0.3"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Summarize the latest Prowler and Kingfisher compliance reports from sifaka"
|
#MISE description="Summarize the latest Prowler and Kingfisher compliance reports from sifaka"
|
||||||
#USAGE flag "--full" help="Show all unmuted failures, not just new ones"
|
#USAGE flag "--full" help="Show all unmuted failures, not just new ones"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="List recent Forgejo Actions runs or fetch logs for a specific job"
|
#MISE description="List recent Forgejo Actions runs or fetch logs for a specific job"
|
||||||
#USAGE arg "[run_number]" help="Run number to show jobs for (omit to list recent runs)"
|
#USAGE arg "[run_number]" help="Run number to show jobs for (omit to list recent runs)"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["pyyaml>=6.0.2", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["pyyaml==6.0.3", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Review the most stale service for version freshness"
|
#MISE description="Review the most stale service for version freshness"
|
||||||
#USAGE flag "--limit <limit>" default="15" help="Number of services to show in the table"
|
#USAGE flag "--limit <limit>" default="15" help="Number of services to show in the table"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env -S uv run --script
|
#!/usr/bin/env -S uv run --script
|
||||||
# /// script
|
# /// script
|
||||||
# requires-python = ">=3.12"
|
# requires-python = ">=3.12"
|
||||||
# dependencies = ["httpx>=0.28.1", "rich>=14.0.0", "typer>=0.24.0"]
|
# dependencies = ["httpx==0.28.1", "rich==15.0.0", "typer==0.25.0"]
|
||||||
# ///
|
# ///
|
||||||
#MISE description="Create a spork (floating-branch soft-fork) of a mirrored upstream project"
|
#MISE description="Create a spork (floating-branch soft-fork) of a mirrored upstream project"
|
||||||
#USAGE arg "<repo_name>" help="Repository name in the mirrors/ org on forge (e.g. kingfisher)"
|
#USAGE arg "<repo_name>" help="Repository name in the mirrors/ org on forge (e.g. kingfisher)"
|
||||||
|
|
|
||||||
24
prek.toml
24
prek.toml
|
|
@ -22,13 +22,13 @@ hooks = [
|
||||||
# check-yaml with --unsafe (builtin fast path doesn't support --unsafe yet)
|
# check-yaml with --unsafe (builtin fast path doesn't support --unsafe yet)
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/pre-commit/pre-commit-hooks"
|
repo = "https://github.com/pre-commit/pre-commit-hooks"
|
||||||
rev = "v6.0.0"
|
rev = "3e8a8703264a2f4a69428a0aa4dcb512790b2c8c" # v6.0.0
|
||||||
hooks = [{ id = "check-yaml", args = ["--unsafe"] }]
|
hooks = [{ id = "check-yaml", args = ["--unsafe"] }]
|
||||||
|
|
||||||
# Secret detection (running both tools in parallel to compare coverage)
|
# Secret detection (running both tools in parallel to compare coverage)
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/trufflesecurity/trufflehog"
|
repo = "https://github.com/trufflesecurity/trufflehog"
|
||||||
rev = "v3.94.0"
|
rev = "17456f8c7d042d8c82c9a8ca9e937231f9f42e26" # v3.95.2
|
||||||
hooks = [
|
hooks = [
|
||||||
{ id = "trufflehog", entry = "trufflehog git file://. --since-commit HEAD --no-verification --fail", stages = [
|
{ id = "trufflehog", entry = "trufflehog git file://. --since-commit HEAD --no-verification --fail", stages = [
|
||||||
"pre-commit",
|
"pre-commit",
|
||||||
|
|
@ -38,7 +38,7 @@ hooks = [
|
||||||
|
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/mongodb/kingfisher"
|
repo = "https://github.com/mongodb/kingfisher"
|
||||||
rev = "v1.91.0"
|
rev = "9ddec4ab8b53653d4941e6b3fd4ff602ce91d81b" # v1.97.0
|
||||||
hooks = [
|
hooks = [
|
||||||
{ id = "kingfisher", args = [
|
{ id = "kingfisher", args = [
|
||||||
"scan",
|
"scan",
|
||||||
|
|
@ -56,7 +56,7 @@ hooks = [
|
||||||
# YAML linting
|
# YAML linting
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/adrienverge/yamllint"
|
repo = "https://github.com/adrienverge/yamllint"
|
||||||
rev = "v1.38.0"
|
rev = "cba56bcde1fdd01c1deb3f945e69764c291a6530" # v1.38.0
|
||||||
hooks = [{ id = "yamllint", args = ["-c", ".yamllint.yaml"] }]
|
hooks = [{ id = "yamllint", args = ["-c", ".yamllint.yaml"] }]
|
||||||
|
|
||||||
# Ansible linting
|
# Ansible linting
|
||||||
|
|
@ -69,12 +69,12 @@ name = "ansible-lint"
|
||||||
entry = "env ANSIBLE_ROLES_PATH=ansible/roles ansible-lint"
|
entry = "env ANSIBLE_ROLES_PATH=ansible/roles ansible-lint"
|
||||||
language = "python"
|
language = "python"
|
||||||
files = "^ansible/"
|
files = "^ansible/"
|
||||||
additional_dependencies = ["ansible-lint>=26.3.0", "ansible-core>=2.18"]
|
additional_dependencies = ["ansible-lint==26.4.0", "ansible-core==2.20.5"]
|
||||||
|
|
||||||
# Python - ruff for linting and formatting
|
# Python - ruff for linting and formatting
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/astral-sh/ruff-pre-commit"
|
repo = "https://github.com/astral-sh/ruff-pre-commit"
|
||||||
rev = "v0.15.7"
|
rev = "6fec9b7edb08fd9989088709d864a7826dc74e80" # v0.15.12
|
||||||
hooks = [{ id = "ruff", args = ["--fix"] }, { id = "ruff-format" }]
|
hooks = [{ id = "ruff", args = ["--fix"] }, { id = "ruff-format" }]
|
||||||
|
|
||||||
# Python - ty type checker
|
# Python - ty type checker
|
||||||
|
|
@ -92,30 +92,30 @@ pass_filenames = false
|
||||||
# Shell scripts - shellcheck and shfmt
|
# Shell scripts - shellcheck and shfmt
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/shellcheck-py/shellcheck-py"
|
repo = "https://github.com/shellcheck-py/shellcheck-py"
|
||||||
rev = "v0.11.0.1"
|
rev = "745eface02aef23e168a8afb6b5737818efbea95" # v0.11.0.1
|
||||||
hooks = [{ id = "shellcheck", args = ["--severity=warning"] }]
|
hooks = [{ id = "shellcheck", args = ["--severity=warning"] }]
|
||||||
|
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/scop/pre-commit-shfmt"
|
repo = "https://github.com/scop/pre-commit-shfmt"
|
||||||
rev = "v3.13.0-1"
|
rev = "05c1426671b9237fb5e1444dd63aa5731bec0dfb" # v3.13.1-1
|
||||||
hooks = [{ id = "shfmt", args = ["-i", "2", "-ci", "-bn"] }]
|
hooks = [{ id = "shfmt", args = ["-i", "2", "-ci", "-bn"] }]
|
||||||
|
|
||||||
# TOML - taplo
|
# TOML - taplo
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/ComPWA/taplo-pre-commit"
|
repo = "https://github.com/ComPWA/taplo-pre-commit"
|
||||||
rev = "v0.9.3"
|
rev = "23eab0f0eedcbedebff420f5fdfb284744adc7b3" # v0.9.3
|
||||||
hooks = [{ id = "taplo-format" }, { id = "taplo-lint" }]
|
hooks = [{ id = "taplo-format" }, { id = "taplo-lint", args = ["--no-schema"] }]
|
||||||
|
|
||||||
# JSON formatting (prettier for consistent style)
|
# JSON formatting (prettier for consistent style)
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/rbubley/mirrors-prettier"
|
repo = "https://github.com/rbubley/mirrors-prettier"
|
||||||
rev = "v3.8.1"
|
rev = "515f543f5718ebfd6ce22e16708bb32c68ff96e1" # v3.8.3
|
||||||
hooks = [{ id = "prettier", types_or = ["json"], args = ["--tab-width", "2"] }]
|
hooks = [{ id = "prettier", types_or = ["json"], args = ["--tab-width", "2"] }]
|
||||||
|
|
||||||
# GitHub/Forgejo Actions workflow linting
|
# GitHub/Forgejo Actions workflow linting
|
||||||
[[repos]]
|
[[repos]]
|
||||||
repo = "https://github.com/rhysd/actionlint"
|
repo = "https://github.com/rhysd/actionlint"
|
||||||
rev = "v1.7.11"
|
rev = "914e7df21a07ef503a81201c76d2b11c789d3fca" # v1.7.12
|
||||||
hooks = [
|
hooks = [
|
||||||
{ id = "actionlint-system", args = [
|
{ id = "actionlint-system", args = [
|
||||||
"-config-file",
|
"-config-file",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue