Skip to content

Commit 0aa8380

Browse files
committed
build(skills): generate .agents/ cross-tool skill mirror
The gen-agents-skills-mirror check expects a committed, in-sync .agents/skills/ mirror of .claude/skills/, but the generated output was never committed — so the Check lane failed (72 drifts) and blocked the 6.0.8 release. Commit the regenerated mirror (39 skills, incl the newly added tidying-worktrees) so the check passes.
1 parent fd25f0e commit 0aa8380

72 files changed

Lines changed: 12745 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
name: fleet-agent-ci
3+
description: Run this repo's GitHub Actions workflows locally in Docker with Agent CI to validate changes before pushing. Use before opening or updating a PR, after editing a workflow YAML under .github/workflows, or whenever catching a CI failure locally beats waiting on a remote runner.
4+
user-invocable: true
5+
allowed-tools: Bash, Read, Edit
6+
model: claude-haiku-4-5
7+
context: fork
8+
---
9+
10+
# agent-ci
11+
12+
Run the repo's CI pipeline locally before pushing. CI was green before you started, so any failure the local run surfaces comes from your changes.
13+
14+
RedwoodJS wrote the upstream tool and skill (MIT, https://github.com/redwoodjs/agent-ci). The fleet pins `@redwoodjs/agent-ci` in the wheelhouse catalog and wires it as the `ci:local` package script (resolved via `node_modules/.bin`, never `pnpm exec`/`npx`). Edit only in `socket-wheelhouse/template/`; the cascade refreshes downstream copies.
15+
16+
## Requirements
17+
18+
- **Docker must be running** — each job runs in a container. On macOS the fleet uses **OrbStack** (`open -a OrbStack`; recommended over Docker Desktop). If the daemon is down, agent-ci fails fast with `couldn't use a Docker socket at /var/run/docker.sock … missing or a dangling symlink` and exit 1 — that's the daemon, not a workflow failure. Start the provider, confirm with `docker info`, re-run. No daemon and can't start one → fall back to `greening-ci` (push + watch remote).
19+
- **The dep is already installed**`@redwoodjs/agent-ci` is a fleet devDependency (`catalog:`), provisioned by `pnpm install`.
20+
- **`--github-token` for remote reusable workflows** — every socket-\* repo's `ci.yml` calls a `SocketDev/socket-registry/.github/workflows/…` reusable workflow. agent-ci can't fetch it without a token; pass `--github-token` (no value → auto-resolves via `gh auth token`). Omitting it makes a remote-reusable CI silently fail to resolve.
21+
- **macOS jobs (`runs-on: macos-*`)** run in a throwaway VM and need `tart` + `sshpass` on an Apple Silicon host (`brew install cirruslabs/cli/tart hudochenkov/sshpass/sshpass`). Without both, macOS jobs are skipped with a reason — the rest of the run still proceeds.
22+
23+
## Run
24+
25+
The blessed entry is the canonical `ci:local` script — it already carries the full flag set (`--all --quiet --pause-on-failure --github-token`), and pnpm resolves the `agent-ci` binary from `node_modules/.bin` cross-platform:
26+
27+
```bash
28+
pnpm run ci:local
29+
```
30+
31+
`--all` runs the PR/push workflows for the current branch. `--quiet` suppresses the live renderer (pipe-safe). `--pause-on-failure` stops at the first failed step and holds the container open for `retry`. `--github-token` (bare → `gh auth token`) fetches the socket-registry reusable workflow every fleet `ci.yml` calls. Pipes are safe: when stdout is not a TTY the launcher detaches and the foreground process exits **77** the moment a step pauses, so `| tee log` and `> log.txt` work.
32+
33+
There is no `--list` or dry-run flag — `run` executes. Args after the subcommand pass through, so a typo'd flag becomes a workflow arg rather than an error.
34+
35+
To resolve the binary from a `.mts` script (not a package.json script — those resolve `node_modules/.bin` themselves), use the fleet helper, never a shelled-out `which`/`command -v` (which searches the global PATH and resolves the wrong binary — enforced by `socket/no-which-for-local-bin`):
36+
37+
```ts
38+
import { whichSync } from '@socketsecurity/lib-stable/bin/which'
39+
40+
const agentCi = whichSync('agent-ci', { path: nodeModulesBinDir, nothrow: true })
41+
```
42+
43+
## Fix and retry
44+
45+
When a step fails the run pauses (and the `run.paused` event carries the exact `retry_cmd` to copy). Fix the code, then retry the paused runner — don't restart the whole pipeline:
46+
47+
```bash
48+
node_modules/.bin/agent-ci retry --name <runner-name>
49+
```
50+
51+
Call the linked binary directly (the fleet form for an ad-hoc bin invocation, same as `node_modules/.bin/oxfmt` / `tsgo` in build scripts) — never `pnpm exec`/`npx`. Re-run from an earlier step with `--from-step <N>`. Repeat fix → retry until every job passes. Don't push to trigger remote CI when agent-ci can run it locally.
52+
53+
## Reference
54+
55+
- **Machine-readable `--json` event stream, the full requirements rationale, and the agent-ci-vs-remote-CI decision matrix**: see [reference.md](reference.md).
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# agent-ci reference
2+
3+
## Contents
4+
5+
- Machine-readable output (`--json`)
6+
- The exit-77 pause contract
7+
- Requirements rationale (Docker, install)
8+
- When to use agent-ci vs. remote CI
9+
- Command summary
10+
11+
## Machine-readable output (`--json`)
12+
13+
Add `--json` (or set `AGENT_CI_JSON=1`) to emit an NDJSON event stream on stdout — one JSON object per line. Use it for programmatic monitoring instead of grepping plaintext.
14+
15+
Events:
16+
17+
- `run.start` — carries `schemaVersion: 1` and `runId`.
18+
- `job.start`, `job.finish``status: passed | failed`.
19+
- `step.start`, `step.finish``status: passed | failed | skipped`.
20+
- `run.paused` — carries `runner` and `retry_cmd` (the exact command to resume).
21+
- `run.finish``status: passed | failed`.
22+
- `diagnostic` — non-fatal notices.
23+
24+
`--json` is independent of `--quiet`. The diff renderer is auto-suppressed under `--json` so ANSI escapes don't collide with the stream.
25+
26+
The robust agent loop: parse the stream, react to `run.paused` (fix the failure named in `runner`), then run the `retry_cmd` it carries. No plaintext parsing required.
27+
28+
## The exit-77 pause contract
29+
30+
When stdout is not a TTY (piped, redirected, captured by a parent process), the launcher detaches the run. The foreground process exits **77** the instant a step pauses. This frees the pipe — `| tee`, `> log.txt`, command substitution — while the container stays paused in the background, ready for `retry`. Exit 77 means "paused, awaiting retry," not "failed."
31+
32+
## Requirements rationale
33+
34+
- **Docker.** agent-ci executes each workflow job inside a container, the same way GitHub's runners do. It connects via `AGENT_CI_DOCKER_HOST` (default `unix:///var/run/docker.sock`) — **not** the standard `DOCKER_HOST` (setting `DOCKER_HOST` makes agent-ci exit with a rename error; use `AGENT_CI_DOCKER_HOST` for a remote `ssh://`/`tcp://` daemon). Without a running daemon the run cannot start; it fails fast with a dangling-socket message and exit 1. On macOS the fleet provider is **OrbStack** (`open -a OrbStack`, then `docker info` to confirm). There is no degraded mode; if you can't start a daemon, use `greening-ci` (push and watch remote CI) instead.
35+
- **Remote reusable workflows.** A fleet `ci.yml` doesn't contain the jobs — it `uses:` a `SocketDev/socket-registry/.github/workflows/ci.yml@<sha>` reusable workflow. agent-ci fetches that over the network, which needs `--github-token` (bare flag → `gh auth token`, or `AGENT_CI_GITHUB_TOKEN`). Without it the reusable workflow can't resolve and the run can't assemble the job graph.
36+
- **macOS jobs.** `runs-on: macos-*` jobs run in a real throwaway macOS VM via `tart` (Apple Silicon only) with `sshpass`. Missing either tool, or on Linux/Intel, those jobs **skip with a reason** rather than failing the run; the Linux/container jobs still execute. VM concurrency caps at `AGENT_CI_MACOS_VM_CONCURRENCY` (default 2 — tart's free tier). Windows jobs (`runs-on: windows-*`) always skip (unsupported).
37+
- **Missing tools in the runner image.** Jobs run in `ghcr.io/actions/actions-runner:latest`, which ships node/git/curl/jq/unzip but **not** build toolchains, `python3`, or `xz`. A job failing on a missing tool isn't your code — add a `.github/agent-ci.Dockerfile` (`FROM ghcr.io/actions/actions-runner:latest` + `apt-get install`); agent-ci picks it up automatically and caches by content hash.
38+
- **Install.** `@redwoodjs/agent-ci` is a fleet devDependency declared as `catalog:` in every repo's `package.json`, pinned in the wheelhouse `pnpm-workspace.yaml` catalog. `pnpm install` provisions it. The published package is a self-contained Node CLI (`dist/cli.js`) — it has no platform-binary dependencies and its `ssh2` native build scripts are declined in the fleet's `allowBuilds`/`allowScripts` (the CLI runs without them).
39+
40+
## When to use agent-ci vs. remote CI
41+
42+
| Situation | Use |
43+
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
44+
| Edited a workflow YAML (`.github/workflows/*.yml`) | agent-ci first — a malformed workflow fails the same locally and remotely, skipping the push/wait loop. |
45+
| Code change that only needs lint / typecheck / unit tests | `pnpm run check --all` — faster than spinning up containers for the pure-Node gates. |
46+
| Workflow does something the local scripts don't (matrix, container steps, action wiring, secrets-shaped env) | agent-ci. |
47+
| No Docker, or the failure needs an off-machine action (a deploy, a remote service) | push and use `greening-ci`. |
48+
49+
## Command summary
50+
51+
| Command | Purpose |
52+
| -------------------------------------------------------------------- | ----------------------------------------------------------- |
53+
| `pnpm run ci:local` | Blessed entry — `agent-ci run --all` via `node_modules/.bin`. |
54+
| `node_modules/.bin/agent-ci run --all --pause-on-failure --github-token` | Run the branch's PR/push workflows; pause on first failure; fetch remote reusable workflows. |
55+
| `node_modules/.bin/agent-ci run --workflow <path>` | Run a single workflow file. |
56+
| `node_modules/.bin/agent-ci retry --name <runner>` | Resume a paused runner after a fix. |
57+
| `node_modules/.bin/agent-ci retry --name <runner> --from-step <N>` | Resume from an earlier step. |
58+
| `node_modules/.bin/agent-ci abort --name <runner>` | Tear down a paused runner without retrying. |
59+
60+
Add `--quiet` to suppress the live renderer, `--json` for the NDJSON stream. Invoke the binary via `node_modules/.bin/agent-ci` or the `ci:local` script — never `pnpm exec`/`npx` (fleet tooling ban).
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
name: fleet-auditing-gha
3+
description: Audits a repo's GitHub Actions permissions + allowlist against the fleet baseline. Reports drift only. Fixes are manual in Settings → Actions because flipping these silently is unsafe. Use when a CI failure looks like "action X is not allowed to be used", when onboarding a new fleet repo, or as a periodic fleet-wide health check.
4+
user-invocable: true
5+
allowed-tools: Read, Grep, Glob, Bash(gh:*), Bash(node:*), Bash(jq:*)
6+
model: claude-haiku-4-5
7+
context: fork
8+
---
9+
10+
# auditing-gha
11+
12+
Diff a fleet repo's GitHub Actions repository-level settings against the canonical baseline. Read-only: surfaces what to change, doesn't change it.
13+
14+
## When to use
15+
16+
- **"action X is not allowed to be used" CI failure**: the allowlist is missing an entry, or the policy got flipped from `selected` to `local_only`.
17+
- **Onboarding a new fleet repo**: before the first CI run, confirm the new repo matches the baseline so the first push doesn't hit policy errors.
18+
- **Periodic fleet health check**: drift accumulates. Somebody adds a workflow that needs a new action and silently flips `verified_allowed: true` to make it work instead of adding the explicit pattern.
19+
20+
## What the baseline checks
21+
22+
| Setting (per repo) | Baseline | Why |
23+
| ---------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
24+
| `enabled` | `true` | Per-repo override is on. **Note**: `enabled: false` does NOT mean Actions are off — it means the per-repo override is unset and org policy is the source of truth. To get drift-detection on a repo, opt in to per-repo settings + mirror the canonical baseline. |
25+
| `allowed_actions` | `'selected'` | "Allow enterprise, and select non-enterprise, actions and reusable workflows" — the only mode where the explicit allowlist is the source of truth. |
26+
| `github_owned_allowed` | `false` | Don't blanket-allow `actions/*`. The canonical patterns list already names every github-owned action we need; unlisted ones must be explicit. |
27+
| `verified_allowed` | `false` | Marketplace "verified creator" is not implicit allow — every action must be on the canonical patterns list. |
28+
| `patterns_allowed ⊇ canonical set` | Each fleet pattern present | Each canonical entry is referenced by at least one socket-registry shared workflow; missing one breaks every consumer. |
29+
30+
The **canonical patterns** (every fleet repo must have all of these):
31+
32+
- `actions/cache/restore@*`
33+
- `actions/cache/save@*`
34+
- `actions/cache@*`
35+
- `actions/checkout@*`
36+
- `actions/deploy-pages@*`
37+
- `actions/download-artifact@*`
38+
- `actions/github-script@*`
39+
- `actions/setup-go@*`
40+
- `actions/setup-node@*`
41+
- `actions/setup-python@*`
42+
- `actions/upload-artifact@*`
43+
- `actions/upload-pages-artifact@*`
44+
- `depot/build-push-action@*`
45+
- `depot/setup-action@*`
46+
- `github/codeql-action/upload-sarif@*`
47+
48+
Extras beyond the canonical set are tolerated (reported as info, not failure). A repo may pin a one-off action, but each extra should map to a real consumer; orphans should be pruned.
49+
50+
**Third-party actions are NOT on the allowlist.** Anything outside `actions/`, `github/`, and `depot/` should be ported to a hand-rolled composite under `SocketDev/socket-registry/.github/actions/` rather than added here. The current set of socket-registry composite replacements:
51+
52+
| Third-party | socket-registry composite |
53+
| --------------------------------- | -------------------------- |
54+
| `dtolnay/rust-toolchain` | `setup-rust-toolchain` |
55+
| `hendrikmuhs/ccache-action` | `setup-ccache` |
56+
| `HaaLeo/publish-vscode-extension` | `publish-vscode-extension` |
57+
| `mlugg/setup-zig` | `setup-zig` |
58+
| `pnpm/action-setup` | `setup-pnpm` |
59+
| `softprops/action-gh-release` | `create-gh-release` |
60+
| `Swatinem/rust-cache` | `setup-rust-cache` |
61+
62+
Note: `enabled: false` from the per-repo API does NOT mean Actions are disabled. It means the per-repo override is unset and org-level policy is in effect. The skill explains this in its output.
63+
64+
## How to invoke
65+
66+
node .claude/skills/fleet/auditing-gha/run.mts SocketDev/socket-btm SocketDev/socket-cli
67+
68+
Or all-at-once with the canonical fleet list (manual today; the orchestrator skill prompt expands the list at call time):
69+
70+
node .claude/skills/fleet/auditing-gha/run.mts \
71+
SocketDev/socket-btm \
72+
SocketDev/socket-cli \
73+
SocketDev/socket-lib \
74+
SocketDev/socket-mcp \
75+
SocketDev/socket-packageurl-js \
76+
SocketDev/socket-registry \
77+
SocketDev/socket-sdk-js \
78+
SocketDev/socket-sdxgen \
79+
SocketDev/socket-stuie \
80+
SocketDev/socket-vscode \
81+
SocketDev/socket-webext \
82+
SocketDev/socket-wheelhouse \
83+
SocketDev/ultrathink
84+
85+
For machine-readable output (one finding per repo):
86+
87+
node .claude/skills/fleet/auditing-gha/run.mts --json SocketDev/socket-btm | jq
88+
89+
## How to fix the findings
90+
91+
Each finding line names the exact toggle to flip. The fix is **manual**: the runner does not write. Flipping these silently is a credible attack vector and should always be a human action.
92+
93+
Two paths:
94+
95+
1. **Web UI (preferred)**: Repo → Settings → Actions → General. The settings map 1:1 with the audit findings:
96+
- "Allow enterprise, and select non-enterprise, actions and reusable workflows" → flips `allowed_actions` to `selected`.
97+
- Uncheck "Allow actions created by GitHub" → `github_owned_allowed: false`.
98+
- Uncheck "Allow Marketplace actions by verified creators" → `verified_allowed: false`.
99+
- "Allow specified actions and reusable workflows" textarea: paste the canonical patterns list (one per line). Existing extras can stay; remove only ones with no consumer.
100+
101+
2. **`gh api` PUT (admin-scoped tokens only)**: surfaced for completeness; prefer the UI:
102+
103+
gh api -X PUT repos/<owner>/<repo>/actions/permissions \
104+
-F enabled=true -F allowed_actions=selected
105+
gh api -X PUT repos/<owner>/<repo>/actions/permissions/selected-actions \
106+
-F github_owned_allowed=false -F verified_allowed=false \
107+
-f patterns_allowed[]='actions/cache/restore@*' \
108+
-f patterns_allowed[]='actions/cache/save@*' \
109+
# ...one -f per canonical pattern...
110+
111+
The whole-list replace semantics on the selected-actions endpoint mean **omitting a repo's existing extras drops them**. Preserve them when relevant.
112+
113+
## Anti-patterns
114+
115+
- **Auto-PUT-ing the baseline from a script.** Don't. The settings affect every workflow on the repo and a wrong setting silently weakens supply-chain posture. The user runs the audit, the user fixes.
116+
- **Adding an action to the allowlist to make a one-off workflow happy.** First ask: should the workflow use a shared socket-registry workflow that already references an approved action? Adding entries to the canonical set means cascading them to every consumer org. A real commitment.
117+
- **Treating the audit as a security review.** It checks policy state, not workflow content. A workflow that uses an allowed action insecurely (e.g. `pull_request_target` + `actions/checkout` of untrusted ref) is invisible to this audit; that's `pull-request-target-guard`'s job.
118+
119+
## Companion: `greening-ci`
120+
121+
If a CI failure shows `action <X> is not allowed by enterprise admin` or `not allowed to be used in this repository`, that's an allowlist gap. Run this audit, fix the gap manually, then re-run `/green-ci` to confirm the build goes green.

0 commit comments

Comments
 (0)