[eslint-miner] eslint-factory: add require-fs-stat-access-try-catch rule
- Dominant language
- Go
- Stars
- 5.1k
- Forks
- 541
- Avg merge
- 5h 48m
- Merged PRs (30d)
- 773
Description
> [!TIP]
> **Your pull request is ready to create! 🎉 ✅**
>
> Everything is OK—the changes have been pushed to a branch. Please review the protected files, then create the pull request when you are ready.
>
> **[Create the pull request](https://github.com/github/gh-aw/compare/main...eslint-miner/fs-stat-access-try-catch-35f6e519ab30a627?expand=1&title=%5Beslint-miner%5D%20eslint-factory%3A%20add%20require-fs-stat-access-try-catch%20rule&body=Closes%20%2360804)**
>
> The original pull request description is below.
---
### ESLint Miner: new rule `require-fs-stat-access-try-catch`
Adds one net-new custom ESLint rule enforcing try/catch wrapping for `fs.lstatSync`, `fs.accessSync`, and `fs.readlinkSync` calls in `actions/setup/js`.
**Why this gap existed:** existing fs-sync try/catch rules cover `readFileSync`/`writeFileSync`/`appendFileSync` (`require-fs-sync-try-catch`), `statSync`/`readdirSync`/`copyFileSync`/`unlinkSync`/`renameSync` (`require-fs-io-try-catch`), and `realpathSync` alone (`require-realpathsync-try-catch`) — but nothing covered `lstatSync`, `accessSync`, or `readlinkSync`, all of which throw synchronously on missing paths or permission errors and are used across symlink-guard and validation code paths.
**Evidence (static scan of `actions/setup/js`):** `gh` issue/discussion search was not available in this sandbox (CLI/API errors), so this rule was derived from a codebase scan for recurring unguarded fs sync calls.
Running `npm run lint:setup-js` flags 3 real unguarded call sites:
- `azure_devops_work_items.cjs:460` — `fs.lstatSync(current)` inside a loop, not directly wrapped at the call site.
- `memory_custom_validation.cjs:203` — `fs.readlinkSync(fullPath)` inside a recursive directory-walk helper.
- `symlink_guard.cjs:32` — `fs.lstatSync(filePath)` in the shared `lstatGuard()` helper (the file's own docstring already tells callers "Throws if `filePath` does not exist — callers that need to tolerate non-existent paths should wrap the call in a try/catch", so this is a useful reminder rather than a false positive).
Already-wrapped call sites (`mcp_server_core.cjs`, `mcp_cli_bridge.cjs`, `merge_remote_agent_github_folder.cjs`) are correctly left unflagged, indicating a low false-positive rate.
**Implementation:**
- `eslint-factory/src/rules/require-fs-stat-access-try-catch.ts` — new rule, modeled on `require-fs-io-try-catch.ts`, reusing shared helpers from `try-catch-rule-utils.ts` (`createFsSyncMethodResolver`, `isInsideTryBlock`, `findEnclosingStatement`, `buildTryCatchSuggestion`). Provides a `suggest` fix (not autofix) that wraps the offending statement in try/catch and re-throws with `{ cause }`.
- `eslint-factory/src/rules/require-fs-stat-access-try-catch.test.ts` — unit tests covering CJS/ESM, destructured/aliased bindings, and non-fs receivers.
- Registered in `eslint-factory/src/index.ts` and enabled as `"warn"` in `eslint-factory/eslint.config.cjs`.
- Documented in `eslint-factory/README.md`.
**Validation:**
- `npm install` ✅
- `npm run build` ✅
- `npx vitest run` — 684/684 tests pass (67 files), including the new rule's tests and the README/index parity check ✅
- `npm run lint:setup-js` ✅ (0 errors, 89 warnings total incl. 3 new from this rule)
**Scope:** changes limited to `eslint-factory/**` (TypeScript rule + tests + config + docs). No `actions/setup/js` source files were modified — the 3 flagged call sites are left for maintainers to address separately.
No steering issue number was provided for this run, so no `steer` feedback comments were available to incorporate.
---
> [!NOTE]
> **Protected files**
>
> This patch modifies protected files, which may affect project dependencies, CI/CD pipelines, or agent behaviour.
>
>
> Protected files
>
> - `README.md`
>
>
To route changes like this to a review issue instead of blocking, configure `protected-files: fallback-to-issue` in your workflow configuration.
> Generated by [ESLint Miner](https://github.com/github/gh-aw/actions/runs/34824807418) · copilot · auto · 272 AIC · ⌖ 23 AIC · ⊞ 7.2K · [◷](https://github.com/search?q=repo%3Agithub%2Fgh-aw+%22gh-aw-workflow-id%3A+eslint-miner%22&type=pullrequests)
> - [x] expires on Sep 21, 2026, 1:12 AM UTC-08:00
Contributor guide
Research direction
Start with eslint-factory/src/rules/require-fs-io-try-catch.ts and the shared helpers in try-catch-rule-utils.ts, then review the named test, index, config, and README files. Run the rule tests and the listed build, full-test, and lint commands; done means the new rule is registered, documented, tested across the stated binding forms, and all validation passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- eslint, typescript
- Domain
- documentation, testing, tooling
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 20/100