Skip to content

Commit 2b7247e

Browse files
committed
chore(wheelhouse): cascade template@b4c14391
Auto-applied by socket-wheelhouse sync-scaffolding into socket-vscode. 325 file(s) touched: - .claude/commands/fleet/green-ci-local.md - .claude/commands/fleet/researching-recency.md - .claude/commands/fleet/update-hooks-dry.md - .claude/hooks/fleet/_shared/brew-supply-chain.mts - .claude/hooks/fleet/_shared/npmrc-trust.mts - .claude/hooks/fleet/_shared/public-surfaces.mts - .claude/hooks/fleet/_shared/sparkle-auto-update.mts - .claude/hooks/fleet/_shared/token-patterns.mts - .claude/hooks/fleet/_shared/trust-gates.mts - .claude/hooks/fleet/_shared/unbacked-claims.mts - .claude/hooks/fleet/_shared/uv-config.mts - .claude/hooks/fleet/ai-config-drift-reminder/index.mts - .claude/hooks/fleet/alpha-sort-reminder/index.mts - .claude/hooks/fleet/brew-supply-chain-guard/README.md - .claude/hooks/fleet/brew-supply-chain-guard/index.mts - .claude/hooks/fleet/brew-supply-chain-guard/package.json - .claude/hooks/fleet/brew-supply-chain-guard/test/index.test.mts - .claude/hooks/fleet/brew-supply-chain-guard/tsconfig.json - .claude/hooks/fleet/changelog-no-empty-guard/index.mts - .claude/hooks/fleet/claude-md-rule-add-guard/README.md ... and 305 more
1 parent 96177ef commit 2b7247e

325 files changed

Lines changed: 18918 additions & 2604 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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
description: Drive a repo's CI to green LOCALLY with Agent-CI (Docker) — run a workflow in containers, fix the first paused failure, retry in place, loop until green. The local pre-flight before a push or a remote build-matrix dispatch.
3+
---
4+
5+
Run `$ARGUMENTS` through Agent-CI locally and drive it to green without a push or
6+
remote runner minutes.
7+
8+
`$ARGUMENTS` is parsed as: `[workflow.yml]` `[--no-matrix]`. Default: all PR/push
9+
workflows for the current branch (`pnpm run ci:local`). Pass a workflow path to
10+
validate one (e.g. a release/build workflow before dispatching it remotely);
11+
`--no-matrix` collapses a matrix to one representative leg for a fast first pass.
12+
13+
Requires Docker running (OrbStack on macOS — `open -a OrbStack`, confirm
14+
`docker info`). On a paused step the model reads the failure log, fixes the code
15+
locally, and `agent-ci retry`s the SAME runner — it does not restart the
16+
pipeline. Env-gap failures (Depot/OIDC, runner-only libs, skipped macOS legs) are
17+
reported as the local boundary, not code defects, and still need the remote run.
18+
19+
The local twin of `/green-ci` (which watches GitHub Actions remotely + pushes
20+
fixes). Use this first to catch breaks in containers; use `/green-ci` for the
21+
remote run that produces real release artifacts.
22+
23+
Invokes the `greening-ci-local` skill.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
description: Research what the dev community is actually saying and shipping about a tool, library, language, or maintainer over the last 30 days — fans out across GitHub, Hacker News, Reddit, Lobsters, dev.to (opt-in X/Bluesky), ranks by real engagement, and synthesizes a cited brief. Read-only.
3+
---
4+
5+
Run the `researching-recency` skill.
6+
7+
Pass the topic as the argument, e.g. `/researching-recency rolldown` or
8+
`/researching-recency "Claude Fable 5 pricing vs Opus"`. Use it before adopting
9+
a dependency, choosing between tools, or whenever you need recent ground truth a
10+
stale README or training cutoff won't give you.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
description: Read-only DRY/KISS sweep of the fleet hook tree + oxlint plugin; writes a consolidation plan to .claude/reports/ via the updating-hooks-dry skill.
3+
---
4+
5+
Scan `.claude/hooks/fleet/**` and `.config/oxlint-plugin/fleet/**` for bloat: copy-paste clusters that should share a `_shared/` helper, dead `_shared/` exports, overlapping guards / redundant lint rules, and KISS smells (a hook far longer than its siblings, raw regex where the shared AST parser exists). Ranks findings by leverage and writes a report to `.claude/reports/hooks-dry-sweep-<date>.md` with evidence + a concrete consolidation sketch per cluster.
6+
7+
**Plan-only**: applies nothing, opens no PR — a human (or a follow-up `refactor-cleaner`) executes from the report. The mechanical, safe slice (dead `_shared/` exports) is already a `check --all` gate; this is the broader advisory sweep.
8+
9+
Use periodically, or after `codifying-disciplines` lands a burst of new hooks and the tree feels repetitive.
10+
11+
Invokes the `updating-hooks-dry` skill.
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/**
2+
* @file Single source of truth for "is this machine's Homebrew hardened to the
3+
* 6.0.0 supply-chain posture?" — shared by the brew-supply-chain-guard hook
4+
* (point-of-use block), the brew-supply-chain-is-hardened.mts check (drift
5+
* report in `check --all`), and setup-security-tools (which sets the knobs).
6+
* Homebrew 6.0.0 (https://brew.sh/2026/06/11/homebrew-6.0.0/) added two
7+
* opt-in supply-chain controls plus the machinery they depend on:
8+
*
9+
* - HOMEBREW_REQUIRE_TAP_TRUST: refuse to evaluate third-party tap code until
10+
* it is explicitly trusted (`brew trust …`). Closes the tap-as-RCE surface
11+
* — see docs.brew.sh/Tap-Trust.
12+
* - HOMEBREW_CASK_OPTS_REQUIRE_SHA: refuse a cask whose download has no pinned
13+
* checksum (`sha256 :no_check`). Closes the unverified-download surface —
14+
* see docs.brew.sh/Supply-Chain-Security. Both knobs are silently IGNORED
15+
* by an older Homebrew, so the only real enforcement is a version floor: a
16+
* `brew` below 6.0.0 is not hardenable and the guard blocks it until the
17+
* operator upgrades. This concern is DISTINCT from
18+
* package-manager-auto-update.mts (which owns the "don't change a tool
19+
* version mid-task" knob, HOMEBREW_NO_AUTO_UPDATE) — one module per
20+
* concern, per the single-responsibility hook rule.
21+
*/
22+
23+
// oxlint-disable-next-line socket/prefer-async-spawn -- detection runs in a sync hook + sync audit script; needs typed string stdout, no async.
24+
import { spawnSync } from '@socketsecurity/lib-stable/process/spawn/child'
25+
import os from 'node:os'
26+
import process from 'node:process'
27+
28+
import { gte } from '@socketsecurity/lib-stable/versions/compare'
29+
import { coerceVersion } from '@socketsecurity/lib-stable/versions/parse'
30+
31+
import { findInvocation } from './shell-command.mts'
32+
33+
// The Homebrew release that introduced the supply-chain knobs below. A `brew`
34+
// older than this silently ignores the env vars, so the floor is the gate.
35+
export const BREW_MIN_VERSION = '6.0.0'
36+
37+
// Docs the operator is pointed at when the guard / audit fires.
38+
export const BREW_TAP_TRUST_DOCS = 'https://docs.brew.sh/Tap-Trust'
39+
export const BREW_SUPPLY_CHAIN_DOCS =
40+
'https://docs.brew.sh/Supply-Chain-Security'
41+
42+
export interface BrewSecurityEnv {
43+
// The env-var name a shell `export` sets.
44+
name: string
45+
// The value that turns the control on (always '1' today).
46+
value: string
47+
// One-line description of what the control protects against, surfaced in
48+
// audit / guard output.
49+
protects: string
50+
}
51+
52+
// The Homebrew 6.0.0 supply-chain knobs setup-security-tools persists into the
53+
// managed shell-rc block on macOS. Single source of truth shared with the
54+
// detector below — the shell-rc bridge imports this list instead of hardcoding
55+
// a divergent copy, so a future brew knob added here flows into the persisted
56+
// block automatically. Listed alphabetically by env name.
57+
export const MACOS_BREW_SECURITY_ENV: readonly BrewSecurityEnv[] = [
58+
{
59+
name: 'HOMEBREW_CASK_OPTS_REQUIRE_SHA',
60+
value: '1',
61+
protects:
62+
'refuses a cask download with no pinned checksum (sha256 :no_check)',
63+
},
64+
{
65+
name: 'HOMEBREW_REQUIRE_TAP_TRUST',
66+
value: '1',
67+
protects:
68+
'refuses to evaluate an untrusted third-party tap until `brew trust` approves it',
69+
},
70+
]
71+
72+
export interface BrewSecurityStatus {
73+
// 'hardened' = brew is >= the floor AND every knob is on (good); 'unhardened'
74+
// = brew present but the floor or a knob is unmet (blockable drift); 'absent'
75+
// = brew isn't on PATH, so the check is not applicable (never blocks).
76+
state: 'hardened' | 'unhardened' | 'absent'
77+
// The detected Homebrew version, or undefined when brew is absent / its
78+
// version couldn't be read.
79+
version: string | undefined
80+
// True when the detected version is >= BREW_MIN_VERSION.
81+
versionOk: boolean
82+
// Env knobs that are NOT set to their hardened value.
83+
missingEnv: readonly BrewSecurityEnv[]
84+
// One-line explanation of what was read.
85+
reason: string
86+
}
87+
88+
// True when an env var is set to a truthy "on" value (1 / true / yes / on).
89+
export function brewEnvIsOn(name: string): boolean {
90+
const v = process.env[name]?.trim().toLowerCase()
91+
return v === '1' || v === 'true' || v === 'yes' || v === 'on'
92+
}
93+
94+
// True when `brew` resolves on PATH. `command -v` is a shell builtin (not
95+
// spawnable directly), so probe with the platform PATH resolver: `where` on
96+
// Windows, `which` elsewhere. Homebrew is macOS/Linux only; on win32 this is
97+
// always false.
98+
export function hasBrew(): boolean {
99+
const resolver = os.platform() === 'win32' ? 'where' : 'which'
100+
try {
101+
return spawnSync(resolver, ['brew'], { stdio: 'pipe' }).status === 0
102+
} catch {
103+
return false
104+
}
105+
}
106+
107+
// Read the installed Homebrew version, or undefined when brew is missing / the
108+
// call fails. `brew --version` prints e.g. "Homebrew 6.0.0\nHomebrew/..." — the
109+
// first line's trailing token is the version. coerceVersion tolerates the
110+
// occasional git-describe suffix (e.g. "6.0.0-1-gabc123").
111+
export function readBrewVersion(): string | undefined {
112+
let stdout: unknown
113+
try {
114+
const result = spawnSync('brew', ['--version'], { stdio: 'pipe' })
115+
if (result.status !== 0) {
116+
return undefined
117+
}
118+
;({ stdout } = result)
119+
} catch {
120+
return undefined
121+
}
122+
const text = typeof stdout === 'string' ? stdout : String(stdout)
123+
const firstLine = text.split(/\r?\n/u, 1)[0]?.trim() ?? ''
124+
const token = firstLine.replace(/^Homebrew\s+/iu, '').trim()
125+
const coerced = coerceVersion(token)
126+
return coerced ? String(coerced) : undefined
127+
}
128+
129+
// Read the current machine's Homebrew supply-chain posture. Pure-ish: only
130+
// reads env + `brew --version`. Never mutates.
131+
export function detectBrewSecurity(): BrewSecurityStatus {
132+
if (!hasBrew()) {
133+
return {
134+
state: 'absent',
135+
version: undefined,
136+
versionOk: false,
137+
missingEnv: [],
138+
reason: 'brew not on PATH',
139+
}
140+
}
141+
const version = readBrewVersion()
142+
const versionOk = version !== undefined && gte(version, BREW_MIN_VERSION)
143+
const missingEnv = MACOS_BREW_SECURITY_ENV.filter(
144+
knob => !brewEnvIsOn(knob.name),
145+
)
146+
if (versionOk && missingEnv.length === 0) {
147+
return {
148+
state: 'hardened',
149+
version,
150+
versionOk,
151+
missingEnv: [],
152+
reason: `Homebrew ${version} with tap-trust + cask-SHA enforced`,
153+
}
154+
}
155+
const parts: string[] = []
156+
if (!versionOk) {
157+
parts.push(
158+
version === undefined
159+
? 'Homebrew version unreadable'
160+
: `Homebrew ${version} is below the ${BREW_MIN_VERSION} floor`,
161+
)
162+
}
163+
if (missingEnv.length > 0) {
164+
parts.push(`unset: ${missingEnv.map(k => k.name).join(', ')}`)
165+
}
166+
return {
167+
state: 'unhardened',
168+
version,
169+
versionOk,
170+
missingEnv,
171+
reason: parts.join('; '),
172+
}
173+
}
174+
175+
// True when the Bash command invokes `brew` (AST-matched, no regex). Used by
176+
// the guard to decide whether to verify brew's posture before the call runs.
177+
export function commandInvokesBrew(command: string): boolean {
178+
return findInvocation(command, { binary: 'brew' })
179+
}
180+
181+
// The bypass phrase that suppresses the brew-supply-chain guard.
182+
export const BREW_SUPPLY_CHAIN_BYPASS_PHRASE = 'Allow brew-supply-chain bypass'

0 commit comments

Comments
 (0)