@@ -167,6 +167,27 @@ export const socketHookMarkerFor = (filePath: string, rule: string): string =>
167167 : `# socket-hook: allow ${ rule } `
168168const LEGACY_ZIZMOR_MARKER_RE = / (?: # | \/ \/ | \/ \* ) \s * z i z m o r : \s * [ \w - ] + /
169169
170+ // Aliases: legacy marker names recognized as equivalent to a current
171+ // rule for one deprecation cycle, so callers can rename the canonical
172+ // rule without breaking files that still carry the old marker.
173+ //
174+ // Add entries as `<alias>: <canonical>`; both directions match in the
175+ // comparison below.
176+ const RULE_ALIASES : { [ k : string ] : string | undefined } = {
177+ __proto__ : null ,
178+ // 'logger' was the original name when the scanner only flagged
179+ // process.std{out,err}.write; it now flags console.* too, so the
180+ // canonical marker is 'console'. Keep 'logger' for one cycle.
181+ logger : 'console' ,
182+ }
183+
184+ function aliasMatches ( marker : string , rule : string ) : boolean {
185+ if ( marker === rule ) {
186+ return true
187+ }
188+ return RULE_ALIASES [ marker ] === rule || RULE_ALIASES [ rule ] === marker
189+ }
190+
170191function lineIsSuppressed ( line : string , rule ?: string ) : boolean {
171192 if ( LEGACY_ZIZMOR_MARKER_RE . test ( line ) ) {
172193 return true
@@ -179,8 +200,9 @@ function lineIsSuppressed(line: string, rule?: string): boolean {
179200 if ( ! m [ 1 ] ) {
180201 return true
181202 }
182- // Marker named a specific rule → only suppress that rule.
183- return rule === undefined || m [ 1 ] === rule
203+ // Marker named a specific rule → suppress when the names match
204+ // directly OR through an alias.
205+ return rule === undefined || aliasMatches ( m [ 1 ] , rule )
184206}
185207
186208// Heuristic context flags: lines that look like "this is a doc example"
@@ -354,30 +376,39 @@ export const scanPrivateKeys = (text: string): LineHit[] => {
354376
355377// ── npx/dlx scanner ────────────────────────────────────────────────
356378//
357- // Match `npx` / `pnpm dlx` / ` yarn dlx` only when the token sits at a
358- // command position — preceded by start-of-line / whitespace / shell
359- // separator (`&&`, `||`, `;`, `|`, `(`, backtick), or directly after a
360- // PowerShell `& ` invoke. Exclude JSON-key, env-value, and identifier
361- // suffix contexts where `npx` shows up as an embedded substring:
379+ // Match `npx` / `yarn dlx` only when the token sits at a command
380+ // position — preceded by start-of-line / whitespace / shell separator
381+ // (`&&`, `||`, `;`, `|`, `(`, backtick), or directly after a PowerShell
382+ // `& ` invoke. Exclude JSON-key, env-value, and identifier suffix
383+ // contexts where `npx` shows up as an embedded substring:
362384// - `"socket-npx": …` (bin-name suffix)
363385// - `"dev:npx": "…SOCKET_CLI_MODE=npx node …"` (script key + env value)
364386// - `cmd-npx-helper` (identifier interior)
365387// The negative lookbehind catches hyphen / colon / equals / underscore /
366388// dot prefixes; the negative lookahead catches the same followed forms
367389// (`npx-helper`, `npx:foo`).
390+ //
391+ // **Allowed:** `pnpm dlx` / `pnpm exec` / `pn dlx` / `pn exec` / `pnx`
392+ // (the pnpm v11 shorthands for `pnpm dlx`). `pnpm dlx` is the
393+ // fleet-canonical fetch-and-run form for documentation lines that
394+ // describe ad-hoc CLI usage (where the consumer doesn't have the
395+ // package pinned in their workspace). `pnx` is the v11 shorthand and
396+ // is equally allowed.
368397
369- const NPX_DLX_RE = / (?< ! [ \w \- : = . ] ) \b ( n p x | p n p m d l x | y a r n d l x ) \b (? ! [ \w \- : = . ] ) /
398+ const NPX_DLX_RE = / (?< ! [ \w \- : = . ] ) \b ( n p x | y a r n d l x ) \b (? ! [ \w \- : = . ] ) /
370399
371400// Suggest the canonical replacement for a runtime npx/dlx call.
372401// Documentation contexts (comments, JSDoc) are exempt via
373402// looksLikeDocumentation(); we only ever land here for code lines, where
374403// the right swap is `pnpm exec` (since `pnpm` is the fleet's package
375- // manager) or `pnpm run` for script entries.
404+ // manager) or `pnpm run` for script entries. For documentation lines
405+ // that legitimately need a fetch-and-run command (user-facing
406+ // instructions where the consumer doesn't have the package pinned),
407+ // use `pnpm dlx` or its pnpm v11 shorthand `pnx` instead of `npx`.
376408function suggestNpxReplacement ( line : string ) : string {
377409 return line
378- . replace ( / \b p n p m d l x \b / g, 'pnpm exec' )
379410 . replace ( / \b y a r n d l x \b / g, 'pnpm exec' )
380- . replace ( / \b n p x \b / g, 'pnpm exec ' )
411+ . replace ( / \b n p x \b / g, 'pnpm dlx ' )
381412}
382413
383414export const scanNpxDlx = ( text : string ) : LineHit [ ] => {
@@ -406,8 +437,9 @@ export const scanNpxDlx = (text: string): LineHit[] => {
406437// `@socketsecurity/lib/logger`. Direct calls to `process.stderr.write`,
407438// `process.stdout.write`, `console.log`, `console.error`, `console.warn`,
408439// `console.info`, `console.debug` are blocked. Doc-context lines are
409- // exempt; lines carrying `// socket-hook: allow logger` (or `#` in
410- // non-TS files) are exempt too.
440+ // exempt; lines carrying `// socket-hook: allow console` (or `#` in
441+ // non-TS files) are exempt too. Legacy `allow logger` is accepted as
442+ // an alias for one deprecation cycle.
411443
412444const LOGGER_LEAK_RE =
413445 / \b ( p r o c e s s \. s t d (?: e r r | o u t ) \. w r i t e | c o n s o l e \. (?: l o g | e r r o r | w a r n | i n f o | d e b u g ) ) \s * \( /
@@ -435,7 +467,7 @@ export const scanLoggerLeaks = (text: string): LineHit[] => {
435467 if ( ! LOGGER_LEAK_RE . test ( line ) ) {
436468 continue
437469 }
438- if ( looksLikeDocumentation ( line , LOGGER_LEAK_RE , 'logger ' ) ) {
470+ if ( looksLikeDocumentation ( line , LOGGER_LEAK_RE , 'console ' ) ) {
439471 continue
440472 }
441473 hits . push ( {
0 commit comments