117 lines
5.8 KiB
Markdown
117 lines
5.8 KiB
Markdown
---
|
|
phase: 16-ci-dependency-audit-and-security-checks
|
|
plan: "03"
|
|
subsystem: infra
|
|
tags: [eslint, security, eslint-plugin-security, static-analysis, ci]
|
|
|
|
# Dependency graph
|
|
requires:
|
|
- phase: 13-real-lint-gate-eslint
|
|
provides: root flat ESLint config (eslint.config.js) that this plan extends
|
|
provides:
|
|
- eslint-plugin-security folded into the existing pnpm lint gate as blocking errors (D-03)
|
|
- 14 of 15 security rules active; detect-object-injection disabled globally with justification
|
|
- Targeted inline suppressions at 2 detect-non-literal-fs-filename false-positive sites
|
|
affects:
|
|
- 16-05 (documents the lint gate fold; no new ci.yml step needed — lint already enforces it)
|
|
|
|
# Tech tracking
|
|
tech-stack:
|
|
added:
|
|
- eslint-plugin-security@3.0.1 (root devDependencies, pinned exact)
|
|
patterns:
|
|
- Security rules folded into existing lint step: no extra CI install cost, same pnpm lint gate
|
|
- High-FP rules disabled globally with inline justification comment; site-specific FPs get eslint-disable-next-line with rationale
|
|
|
|
key-files:
|
|
created: []
|
|
modified:
|
|
- eslint.config.js
|
|
- package.json
|
|
- pnpm-lock.yaml
|
|
- apps/api/src/index.ts
|
|
- apps/api/tests/broker/expand.test.ts
|
|
|
|
key-decisions:
|
|
- "D-03-SEC-VERSION: Pinned eslint-plugin-security@3.0.1 (not 4.0.1) — 3.0.1 has more bake time; both are flat-config compatible"
|
|
- "D-03-OBJ-INJECT: detect-object-injection disabled globally — all hits were numeric loop indices (arr[i]) and schema-derived keys, not user-controlled input; remaining 14 rules enforced at error"
|
|
- "D-03-FS-FILENAME: detect-non-literal-fs-filename suppressed at 2 sites (realpathSync(process.argv[1]) and test fixture readFileSync) — both are runtime/test-controlled paths, not user input"
|
|
|
|
patterns-established:
|
|
- "Security lint fold: add security plugin block before prettierConfig (must stay last); disable only pervasively-FP rules globally with justification"
|
|
- "Inline suppression format: // eslint-disable-next-line security/<rule> -- <rationale>"
|
|
|
|
requirements-completed: [SEC-02]
|
|
|
|
# Metrics
|
|
duration: 2min
|
|
completed: 2026-06-13
|
|
---
|
|
|
|
# Phase 16 Plan 03: eslint-plugin-security Static Lint Gate Summary
|
|
|
|
**eslint-plugin-security@3.0.1 folded into the existing pnpm lint gate as 14 blocking error-level rules; detect-object-injection disabled globally for Drizzle/TS-generic FPs; pnpm lint green**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** 2 min
|
|
- **Started:** 2026-06-13T09:21:47Z
|
|
- **Completed:** 2026-06-13T09:24:29Z
|
|
- **Tasks:** 2
|
|
- **Files modified:** 5
|
|
|
|
## Accomplishments
|
|
|
|
- eslint-plugin-security@3.0.1 installed to root devDependencies (exact pin)
|
|
- Flat config extended: new security block (`files: apps/**/*.{ts,tsx}`) with `...pluginSecurity.configs.recommended` spread, placed before `prettierConfig` (which stays last)
|
|
- Triaged 4 total violations: 2 detect-non-literal-fs-filename (inline suppressions with justification), 2 detect-object-injection (globally disabled with justification comment)
|
|
- `pnpm lint` exits 0 with `--max-warnings 0` across both apps; ESLint pin unchanged at 9.39.4
|
|
|
|
## Task Commits
|
|
|
|
1. **Task 1: Install eslint-plugin-security and fold it into the flat config** - `826a23a` (chore)
|
|
2. **Task 2: Triage security-rule violations until pnpm lint is green** - `59e49ec` (chore)
|
|
|
|
## Files Created/Modified
|
|
|
|
- `eslint.config.js` — added `pluginSecurity` import + security config block (section 5, before prettierConfig); detect-object-injection globally disabled with justification
|
|
- `package.json` — eslint-plugin-security@3.0.1 added to root devDependencies
|
|
- `pnpm-lock.yaml` — lockfile updated to reflect new package
|
|
- `apps/api/src/index.ts` — inline `eslint-disable-next-line` for `detect-non-literal-fs-filename` on `realpathSync(process.argv[1])`
|
|
- `apps/api/tests/broker/expand.test.ts` — inline `eslint-disable-next-line` for `detect-non-literal-fs-filename` on test-fixture `readFileSync`
|
|
|
|
## Decisions Made
|
|
|
|
- **Version choice:** Pinned eslint-plugin-security@3.0.1 (not 4.0.1) — 4.0.1 was published the same day as phase research (freshness concern); 3.0.1 is stable and flat-config compatible with ESLint 9.39.4.
|
|
- **detect-object-injection disabled globally:** After running lint and auditing all 2 hits: both were `ranks[i] > ranks[i - 1]` numeric loop index comparisons in tests — not user-controlled keys. Disabling the single highest-noise rule globally while keeping the remaining 14 rules at error. Matches RESEARCH triage Option A recommendation.
|
|
- **detect-non-literal-fs-filename: inline suppressions at 2 sites:** Not disabled globally because only 2 hits exist and both are clearly false positives. Site-level suppression is the minimal-change approach that keeps the rule active for any future truly dynamic `fs.*` calls.
|
|
|
|
## Deviations from Plan
|
|
|
|
None — plan executed exactly as written. Triage decision to disable detect-object-injection globally vs. annotating sites (Option A vs. B per RESEARCH) was explicitly delegated to the executor; Option A was chosen after confirming all hits were numeric loop indices.
|
|
|
|
## Issues Encountered
|
|
|
|
None. Only 4 lint violations found (2 rules, 2 sites each), far fewer than the "dozens" anticipated for Drizzle ORM bracket access — the codebase does not have heavy obj[key] usage in API source files.
|
|
|
|
## Threat Surface Scan
|
|
|
|
No new network endpoints, auth paths, file access patterns, or schema changes introduced. This plan adds only dev-tooling configuration.
|
|
|
|
## Known Stubs
|
|
|
|
None.
|
|
|
|
## User Setup Required
|
|
|
|
None — no external service configuration required. The security lint fold is automatic via `pnpm lint` (existing CI step).
|
|
|
|
## Next Phase Readiness
|
|
|
|
- Plan 16-04 (gitleaks secret scanning) is ready to proceed
|
|
- Plan 16-05 (CI documentation) will reference this plan's D-03 fold — the lint step already enforces it; no new ci.yml job step needed for the security lint
|
|
|
|
---
|
|
*Phase: 16-ci-dependency-audit-and-security-checks*
|
|
*Completed: 2026-06-13*
|