Skip to content

Commit 6feacf5

Browse files
committed
chore(sync): cascade fleet template@86742ed
Auto-applied by socket-wheelhouse sync-scaffolding into vscode-socket-security. 7 file(s) touched: - .config/oxlint-plugin/rules/no-cached-for-on-iterable.mts - .config/oxlint-plugin/rules/no-file-scope-oxlint-disable.mts - .config/socket-registry-pins.json - scripts/check-lock-step-header.mts - scripts/install-claude-plugins.mts - scripts/test/check-lock-step-refs.test.mts - scripts/test/install-claude-plugins.test.mts
1 parent ae7169d commit 6feacf5

7 files changed

Lines changed: 146 additions & 183 deletions

.config/oxlint-plugin/rules/no-cached-for-on-iterable.mts

Lines changed: 1 addition & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.config/oxlint-plugin/rules/no-file-scope-oxlint-disable.mts

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,29 @@
11
/**
2-
* @file Forbid file-scope `oxlint-disable <rule>` comments — every
3-
* exemption must be justified per call site via
4-
* `oxlint-disable-next-line <rule> -- <reason>`.
2+
* @file Forbid file-scope `oxlint-disable <rule>` comments — every exemption
3+
* must be justified per call site via `oxlint-disable-next-line <rule> --
4+
* <reason>`. Why: a file-scope `/* oxlint-disable
5+
* socket/no-console-prefer-logger *\/` block at the top of a file silently
6+
* exempts the entire file from a fleet rule. The exemption applies to lines
7+
* the author never thought about — including future edits — and the reason
8+
* field at the top is easy to forget by the time someone adds a new call
9+
* below. Inline `oxlint-disable-next-line socket/<rule> -- <reason>` forces
10+
* the author to write a fresh justification per call site, which surfaces in
11+
* code review and in `git blame` next to the actual disabled code. Allowed:
512
*
6-
* Why: a file-scope `/* oxlint-disable socket/no-console-prefer-logger *\/`
7-
* block at the top of a file silently exempts the entire file from a
8-
* fleet rule. The exemption applies to lines the author never thought
9-
* about — including future edits — and the reason field at the top is
10-
* easy to forget by the time someone adds a new call below.
11-
*
12-
* Inline `oxlint-disable-next-line socket/<rule> -- <reason>` forces the
13-
* author to write a fresh justification per call site, which surfaces
14-
* in code review and in `git blame` next to the actual disabled code.
15-
*
16-
* Allowed:
1713
* - `// oxlint-disable-next-line <rule> -- <reason>` (per call site)
1814
* - `/* oxlint-disable-next-line <rule> *\/` block form, also per call
19-
* - File-scope disable for **plugin-internal rules** where the file
20-
* itself defines the rule and intentionally contains the banned
21-
* shape as lookup-table data (e.g. `no-status-emoji.mts` containing
22-
* the emoji it bans). Matched by file path: any file under
23-
* `.config/oxlint-plugin/rules/` is exempt from this rule.
24-
*
25-
* Banned:
15+
* - File-scope disable for **plugin-internal rules** where the file itself
16+
* defines the rule and intentionally contains the banned shape as
17+
* lookup-table data (e.g. `no-status-emoji.mts` containing the emoji it
18+
* bans). Matched by file path: any file under
19+
* `.config/oxlint-plugin/rules/` is exempt from this rule. Banned:
2620
* - `/* oxlint-disable <rule> *\/` at file scope (no `-next-line`)
2721
* - `// oxlint-disable <rule>` at file scope (no `-next-line`)
2822
* - Block `oxlint-enable` toggles that come paired with file-scope
29-
* `oxlint-disable` blocks — same anti-pattern.
30-
*
31-
* No autofix: the rule reports each file-scope disable; the human
32-
* moves each one to the call site that needs it (or removes it if
33-
* the code can be rewritten to satisfy the rule).
23+
* `oxlint-disable` blocks — same anti-pattern. No autofix: the rule reports
24+
* each file-scope disable; the human moves each one to the call site that
25+
* needs it (or removes it if the code can be rewritten to satisfy the
26+
* rule).
3427
*/
3528

3629
import type { AstNode, RuleContext } from '../lib/rule-types.mts'
@@ -62,7 +55,7 @@ const rule = {
6255
fixable: undefined,
6356
messages: {
6457
fileScopeDisable:
65-
'File-scope `oxlint-disable {{rule}}` silently exempts the whole file from a fleet rule. Move the disable to `oxlint-disable-next-line {{rule}} -- <reason>` on the specific line that needs it. If the entire file legitimately can\'t comply, the file probably needs a refactor instead.',
58+
"File-scope `oxlint-disable {{rule}}` silently exempts the whole file from a fleet rule. Move the disable to `oxlint-disable-next-line {{rule}} -- <reason>` on the specific line that needs it. If the entire file legitimately can't comply, the file probably needs a refactor instead.",
6659
},
6760
schema: [],
6861
},

.config/socket-registry-pins.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/check-lock-step-header.mts

Lines changed: 37 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,36 @@
11
#!/usr/bin/env node
22
/**
3-
* @file Lock-step header byte-equality gate. Mantra: the four impls
4-
* of a quadruplet agree about WHAT THE FILE IS FOR. The `BEGIN
5-
* LOCK-STEP HEADER` / `END LOCK-STEP HEADER` block names that
6-
* contract; every member of the quadruplet carries the same block,
7-
* byte-for-byte (after stripping the `// ` comment prefix). Drift
8-
* on the contract is a different failure mode from a stale path
9-
* reference (which `check-lock-step-refs.mts` catches) — this gate
10-
* is the _intent_ tripwire.
3+
* @file Lock-step header byte-equality gate. Mantra: the four impls of a
4+
* quadruplet agree about WHAT THE FILE IS FOR. The `BEGIN LOCK-STEP HEADER` /
5+
* `END LOCK-STEP HEADER` block names that contract; every member of the
6+
* quadruplet carries the same block, byte-for-byte (after stripping the `// `
7+
* comment prefix). Drift on the contract is a different failure mode from a
8+
* stale path reference (which `check-lock-step-refs.mts` catches) — this gate
9+
* is the _intent_ tripwire. Opt-in per repo: uses the same
10+
* `.config/lock-step-refs.json` as the path gate. Without the config, the
11+
* gate is a no-op. With the config, the gate walks every scanned source file,
12+
* looks for a `BEGIN LOCK-STEP HEADER` marker on the canonical side (a file
13+
* whose header contains one or more `Lock-step with <Lang>: <path>` refs),
14+
* extracts the header content, then opens each named peer and demands its
15+
* header block be byte-identical. "Canonical side" is determined by the
16+
* header content itself:
1117
*
12-
* Opt-in per repo: uses the same `.config/lock-step-refs.json` as
13-
* the path gate. Without the config, the gate is a no-op. With the
14-
* config, the gate walks every scanned source file, looks for a
15-
* `BEGIN LOCK-STEP HEADER` marker on the canonical side (a file
16-
* whose header contains one or more `Lock-step with <Lang>: <path>`
17-
* refs), extracts the header content, then opens each named peer
18-
* and demands its header block be byte-identical.
19-
*
20-
* "Canonical side" is determined by the header content itself:
21-
*
22-
* - A file with `Lock-step with <Lang>: <path>` is canonical for
23-
* that peer. (The peer should reciprocate with
24-
* `Lock-step from <Lang>: <my-path>`, but the gate doesn't rely
25-
* on that — symmetry is a §5 rule, not a §7 rule.)
26-
* - A file with only `Lock-step from <Lang>: <path>` is a port
27-
* and is checked against its canonical source.
28-
*
29-
* Header format (single-line `// ` across every language):
30-
*
31-
* // BEGIN LOCK-STEP HEADER
32-
* // Class Parsing (Declarations, Expressions, Elements, Methods)
33-
* //
34-
* // Lock-step with Go: src/parser/class.go
35-
* // Lock-step with C++: src/parser/class.cpp
36-
* // END LOCK-STEP HEADER
37-
*
38-
* Comparison strips the `// ` prefix from each line; an empty
39-
* comment line (`//`) is preserved as an empty content line. The
40-
* content between BEGIN and END is the contract.
41-
*
42-
* Usage:
43-
*
44-
* node scripts/check-lock-step-header.mts # report + fail
45-
* node scripts/check-lock-step-header.mts --json # machine-readable
46-
* node scripts/check-lock-step-header.mts --quiet # silent on clean
47-
*
48-
* Exit codes:
49-
*
50-
* 0 — clean (no quadruplets diverged, or config absent)
51-
* 1 — at least one quadruplet has a header diff
52-
* 2 — gate itself crashed
18+
* - A file with `Lock-step with <Lang>: <path>` is canonical for that peer.
19+
* (The peer should reciprocate with `Lock-step from <Lang>: <my-path>`, but
20+
* the gate doesn't rely on that — symmetry is a §5 rule, not a §7 rule.)
21+
* - A file with only `Lock-step from <Lang>: <path>` is a port and is checked
22+
* against its canonical source. Header format (single-line `// ` across
23+
* every language): // BEGIN LOCK-STEP HEADER // Class Parsing
24+
* (Declarations, Expressions, Elements, Methods) // // Lock-step with Go:
25+
* src/parser/class.go // Lock-step with C++: src/parser/class.cpp // END
26+
* LOCK-STEP HEADER Comparison strips the `// ` prefix from each line; an
27+
* empty comment line (`//`) is preserved as an empty content line. The
28+
* content between BEGIN and END is the contract. Usage: node
29+
* scripts/check-lock-step-header.mts # report + fail node
30+
* scripts/check-lock-step-header.mts --json # machine-readable node
31+
* scripts/check-lock-step-header.mts --quiet # silent on clean Exit codes:
32+
* 0 — clean (no quadruplets diverged, or config absent) 1 — at least one
33+
* quadruplet has a header diff 2 — gate itself crashed
5334
*/
5435

5536
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
@@ -172,7 +153,8 @@ function extractHeader(file: string): HeaderBlock | undefined {
172153
const stripped = stripCommentPrefix(raw)
173154
bodyLines.push(stripped)
174155
}
175-
const withRe = /Lock-step with ([A-Za-z][A-Za-z0-9+#-]*): ([^\s:,]*[./][^\s:,]*)/g
156+
const withRe =
157+
/Lock-step with ([A-Za-z][A-Za-z0-9+#-]*): ([^\s:,]*[./][^\s:,]*)/g
176158
const withRefs: Array<{ lang: string; refPath: string }> = []
177159
for (const line of bodyLines) {
178160
withRe.lastIndex = 0
@@ -239,7 +221,9 @@ function bodyEqual(a: readonly string[], b: readonly string[]): boolean {
239221
function formatDiff(d: Diff, repoRoot: string): string {
240222
const out: string[] = []
241223
const rel = (p: string) => path.relative(repoRoot, p)
242-
out.push(`\n${rel(d.canonical)} (canonical) ↔ ${rel(d.peer)} (${d.lang} peer):`)
224+
out.push(
225+
`\n${rel(d.canonical)} (canonical) ↔ ${rel(d.peer)} (${d.lang} peer):`,
226+
)
243227
if (d.reason === 'peer-not-found') {
244228
out.push(` peer path doesn't exist on disk: ${rel(d.peer)}`)
245229
return out.join('\n')
@@ -274,9 +258,7 @@ function main(): void {
274258
try {
275259
config = loadConfig(repoRoot)
276260
} catch (e) {
277-
process.stderr.write(
278-
`check-lock-step-header: ${(e as Error).message}\n`,
279-
)
261+
process.stderr.write(`check-lock-step-header: ${(e as Error).message}\n`)
280262
process.exitCode = 2
281263
return
282264
}
@@ -307,12 +289,7 @@ function main(): void {
307289
}
308290
canonicalCount += 1
309291
for (const ref of header.withRefs) {
310-
const peerPath = resolveRefPath(
311-
config,
312-
repoRoot,
313-
ref.lang,
314-
ref.refPath,
315-
)
292+
const peerPath = resolveRefPath(config, repoRoot, ref.lang, ref.refPath)
316293
if (!peerPath) {
317294
diffs.push({
318295
canonical: file,

0 commit comments

Comments
 (0)