Skip to content

fix(hooks): guard doc-file-warning stdin listeners behind require.main#2358

Open
sshworld wants to merge 2 commits into
affaan-m:mainfrom
sshworld:fix/doc-file-warning-require-main-guard
Open

fix(hooks): guard doc-file-warning stdin listeners behind require.main#2358
sshworld wants to merge 2 commits into
affaan-m:mainfrom
sshworld:fix/doc-file-warning-require-main-guard

Conversation

@sshworld

Copy link
Copy Markdown

Closes #2357

Problem

doc-file-warning.js attaches process.stdin data/end listeners at module scope and also exports run(). run-with-flags.js require()s any hook that exports run() for its in-process fast path, so importing this hook leaks stdin listeners into the dispatcher process and corrupts the PreToolUse stdout JSON — the exact case its own SAFETY comment warns about. 24 sibling hooks already guard this with require.main === module; this one didn't.

Repro on current main:

node -e "require('./scripts/hooks/doc-file-warning.js'); console.log(process.stdin.listenerCount('end'))"
# 1  (should be 0)

Changes

  • doc-file-warning.js: move the stdin entrypoint into main(), export it, and gate it behind require.main === module.
  • pre-write-doc-warn.js: call main() explicitly instead of relying on the import side effect (so the backward-compat entrypoint keeps working).
  • doc-file-warning.test.js: regression coverage — require() attaches no stdin listeners, run()/main() stay exported, and the pre-write-doc-warn shim still emits its warning.

Testing

  • node tests/hooks/doc-file-warning.test.js → 63/63
  • node tests/run-all.js → 2894/2894
  • node scripts/ci/validate-hooks.js → pass

@sshworld sshworld requested a review from affaan-m as a code owner June 25, 2026 07:36
@ecc-tools

ecc-tools Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 36d19935-fb92-4500-88ed-72d3ba4c03b5

📥 Commits

Reviewing files that changed from the base of the PR and between 17fa10d and 6ac1bcd.

📒 Files selected for processing (1)
  • scripts/hooks/doc-file-warning.js
📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{js,ts,jsx,tsx,py,java,cs,go,rb,php,scala,kt}

📄 CodeRabbit inference engine (.cursor/rules/common-coding-style.md)

**/*.{js,ts,jsx,tsx,py,java,cs,go,rb,php,scala,kt}: Always create new objects, never mutate existing ones. Use immutable patterns to prevent hidden side effects and enable safe concurrency
Organize code into many small files (200-400 lines typical, 800 lines max) organized by feature/domain rather than by type
Always handle errors explicitly at every level and never silently swallow errors
Always validate all user input before processing at system boundaries
Use schema-based validation where available
Fail fast with clear error messages when validation fails
Never trust external data (API responses, user input, file content)
Ensure code is readable and well-named
Keep functions small (less than 50 lines)
Keep files focused (less than 800 lines)
Avoid deep nesting (more than 4 levels)
Do not use hardcoded values; use constants or configuration instead

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,swift,kt,rs,c,cpp,h,hpp}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

No hardcoded secrets (API keys, passwords, tokens) - validate before any commit

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php}: All user inputs must be validated
Enable CSRF protection on all state-changing endpoints
Verify authentication and authorization for all protected endpoints
Implement rate limiting on all endpoints to prevent abuse
Ensure error messages do not leak sensitive data in responses

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,sql}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

Use parameterized queries to prevent SQL injection

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,html,php,java,cs,rb,go}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

Implement XSS prevention by sanitizing HTML output

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,py,java,cs,rb,go,php,swift,kt,rs,c,cpp,h,hpp,properties,yml,yaml,json,env,config}

📄 CodeRabbit inference engine (.cursor/rules/common-security.md)

NEVER hardcode secrets in source code - ALWAYS use environment variables or a secret manager

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript-coding-style.md)

**/*.{ts,tsx,js,jsx}: Use spread operator for immutable updates in TypeScript/JavaScript instead of direct mutation
Use async/await with try-catch for error handling in TypeScript/JavaScript
Use Zod for schema-based input validation in TypeScript/JavaScript
No console.log statements in production code; use proper logging libraries instead

**/*.{ts,tsx,js,jsx}: Auto-format JavaScript/TypeScript files using Prettier after edit
Warn about console.log statements in edited files
Check all modified files for console.log statements before session ends

**/*.{ts,tsx,js,jsx}: Use the ApiResponse interface pattern with generic type parameter: interface ApiResponse<T> { success: boolean; data?: T; error?: string; meta?: { total: number; page: number; limit: number; } }
Implement custom React hooks following the pattern: export a named function with use prefix, generic type parameters, and proper useEffect cleanup for side effects

**/*.{ts,tsx,js,jsx}: Never hardcode secrets; always use environment variables for sensitive credentials like API keys
Throw an error when required environment variables are not configured to fail fast and ensure security prerequisites are met

Use Playwright as the E2E testing framework for critical user flows in TypeScript/JavaScript

Files:

  • scripts/hooks/doc-file-warning.js
{package.json,*.config.js,scripts/**/*.js}

📄 CodeRabbit inference engine (CLAUDE.md)

Package manager detection should support npm, pnpm, yarn, and bun, with configuration via CLAUDE_PACKAGE_MANAGER environment variable or project config.

Files:

  • scripts/hooks/doc-file-warning.js
scripts/**/*.js

📄 CodeRabbit inference engine (CLAUDE.md)

Ensure cross-platform support for Windows, macOS, and Linux via Node.js scripts in the scripts/ directory.

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts,jsx,tsx}: Always create new objects and never mutate in place; return new copies instead
Keep files between 200–400 lines typical, with a maximum of 800 lines
Extract helpers when a file exceeds 200 lines
Handle errors explicitly at every level; never swallow errors silently
Validate all user input before processing; use schema-based validation where available
Never trust external data (API responses, file content, query params); always validate
All user inputs must be validated and sanitized
Error messages must be scrubbed of sensitive internals
Use readable, well-named identifiers in all code
Keep functions under 50 lines
Keep files under 800 lines
Avoid nesting deeper than 4 levels
Implement comprehensive error handling in all code
Do not hardcode values; use constants or environment configuration instead
Do not use in-place mutation; always return new objects or state

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,json,env*}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Do not hardcode secrets, API keys, passwords, or tokens

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{js,ts}: Use parameterized queries for all database writes (no string interpolation)
Auth/authz must be checked server-side for every sensitive path
Rate limiting must be applied to all public endpoints

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{jsx,tsx,js,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

HTML output must be sanitized where applicable

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,env*}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Required environment variables must be validated at startup

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,py,java,go,rs,kt,cpp,c,fs}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx,py,java,go,rs,kt,cpp,c,fs}: Write tests before implementation using TDD workflow: write failing test (RED), implement minimal code (GREEN), then refactor (IMPROVE)
Keep functions small (<50 lines) and files focused (<800 lines, typical 200-400 lines)
Avoid deep nesting (>4 levels)

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{js,ts,jsx,tsx,py,java,go,rs,kt}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx,py,java,go,rs,kt}: Never mutate existing objects; always create new objects with changes applied (Immutability requirement)
Handle errors at every level; provide user-friendly messages in UI code and detailed context in server-side logs
Ensure error messages don't leak sensitive data

Files:

  • scripts/hooks/doc-file-warning.js
**/*.{jsx,tsx,html,js,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Sanitize HTML output to prevent XSS vulnerabilities

Files:

  • scripts/hooks/doc-file-warning.js
{scripts,bin}/**

⚙️ CodeRabbit configuration file

{scripts,bin}/**: Focus on command injection, unsafe subprocess usage, path traversal, SSRF, secret exposure, and missing tests for new CLI behavior.

Files:

  • scripts/hooks/doc-file-warning.js
🔇 Additional comments (1)
scripts/hooks/doc-file-warning.js (1)

72-77: LGTM!


📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved hook behavior so importing it in-process no longer attaches stdin listeners or performs work unexpectedly.
    • Added an explicit main() entrypoint so stdin-based fallback runs only when executed directly.
    • Preserved prior warning/output behavior, including consistent handling of additional context for denied files.
  • Tests

    • Added regression coverage for safe in-process imports, denied vs. allowed filename handling, and the compatibility entrypoint warning output.

Walkthrough

The hook moves stdin fallback handling into an exported main() guarded by require.main === module. The wrapper script now calls that entry point directly, and tests cover import safety, run() classification, and shim output.

Changes

Doc file warning hook

Layer / File(s) Summary
Stdin handling in main()
scripts/hooks/doc-file-warning.js
doc-file-warning.js removes module-scope stdin state, adds main() for stdin buffering and output, and gates direct execution behind require.main === module.
Shim call and regressions
scripts/hooks/pre-write-doc-warn.js, tests/hooks/doc-file-warning.test.js
pre-write-doc-warn.js calls main(), and tests cover import safety, in-process run() behavior, and the shim's warning output.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • affaan-m/ECC#2084: Touches the same scripts/hooks/doc-file-warning.js path and its warning output handling, with related changes to how the hook emits additional context.

Poem

A tiny hook took a careful stroll,
Hid its stdin dance in a main() role.
The shim still sings its warning tune,
While tests watch closely morning, noon.
Quiet imports, and output whole.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: guarding doc-file-warning stdin listeners behind require.main.
Description check ✅ Passed The description matches the hook listener fix, shim update, and regression tests described in the summary.
Linked Issues check ✅ Passed The changes satisfy #2357 by moving stdin listeners into main(), guarding them with require.main, and preserving the shim behavior.
Out of Scope Changes check ✅ Passed No unrelated code changes are indicated beyond the hook refactor, shim update, and regression tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a stdin listener leak in doc-file-warning.js where process.stdin data/end listeners were attached at module scope, causing corruption of the PreToolUse stdout JSON when run-with-flags.js loaded the hook in-process. The fix matches the pattern already used by 24 sibling hooks.

  • doc-file-warning.js: Wraps the stdin setup and data accumulator inside a new main() function, guards it with require.main === module, and exports both run and main.
  • pre-write-doc-warn.js: Updates the backward-compat shim to call .main() explicitly, since the module-scope side effect it previously relied on has been removed.
  • tests/hooks/doc-file-warning.test.js: Adds three targeted regression tests covering listener-count isolation on require(), in-process run() correctness, and end-to-end shim behavior.

Confidence Score: 5/5

Safe to merge — the change correctly isolates stdin listener setup to direct invocations only, matching the pattern used across 24 sibling hooks, and regression tests verify all three affected execution paths.

The fix is minimal and well-scoped: module-scope side effects are removed, the data accumulator is now local to each invocation, and the require.main guard follows the established pattern in the codebase. All three changed code paths — in-process require(), direct node invocation, and the backward-compat shim — are covered by new regression tests.

No files require special attention.

Important Files Changed

Filename Overview
scripts/hooks/doc-file-warning.js Moves stdin listeners and data accumulator into a gated main() function, exports both run() and main(), and adds require.main === module guard — cleanly eliminating the listener-leak bug.
scripts/hooks/pre-write-doc-warn.js Updated backward-compat shim to explicitly call main() instead of relying on the now-removed module-scope side effect; correct because this file is always a subprocess entrypoint and never required in-process.
tests/hooks/doc-file-warning.test.js Adds three regression tests: listener count assertion on require(), in-process run() classification, and end-to-end shim verification via spawnSync — covers all three changed code paths.

Reviews (3): Last reviewed commit: "docs(hooks): add JSDoc for doc-file-warn..." | Re-trigger Greptile

Comment thread scripts/hooks/doc-file-warning.js
doc-file-warning.js registered process.stdin data/end listeners at module
scope while also exporting run(). run-with-flags.js require()s any hook that
exports run() for its in-process fast path, so importing this hook attached
stray stdin listeners to the dispatcher process, corrupting the PreToolUse
stdout JSON contract. This is the exact failure run-with-flags' own SAFETY
comment warns about, and 24 sibling hooks already guard against it.

- Move the stdin entrypoint into main() and gate it behind require.main === module
- pre-write-doc-warn.js now calls main() explicitly instead of relying on the
  import side effect
- Add regression tests: require() attaches no stdin listeners, run()/main()
  stay exported, and the pre-write-doc-warn shim still warns
@sshworld sshworld force-pushed the fix/doc-file-warning-require-main-guard branch from b4d581e to 17fa10d Compare June 25, 2026 08:10
@ecc-tools

ecc-tools Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

Satisfies the docstring-coverage pre-merge check; documents the stdin
entrypoint and why it must not run on require().
@ecc-tools

ecc-tools Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@daltino daltino left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR improves the doc-file-warning hook by conditionally guarding stdin listeners with a require.main check, which prevents them from unintentionally activating when the file is imported. The developer also added a safeguard test to verify that importing the module in-process does not add stdin listeners. The changes are concise and adhere to the contribution guidelines. Nicely done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: doc-file-warning.js attaches stdin listeners at module scope (no require.main guard)

2 participants