Files
familysync/.planning/milestones/v1.1-phases/16-ci-dependency-audit-and-security-checks/16-03-SUMMARY.md
T
2026-06-18 22:21:38 -04:00

5.8 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
16-ci-dependency-audit-and-security-checks 03 infra
eslint
security
eslint-plugin-security
static-analysis
ci
phase provides
13-real-lint-gate-eslint root flat ESLint config (eslint.config.js) that this plan extends
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
16-05 (documents the lint gate fold; no new ci.yml step needed — lint already enforces it)
added patterns
eslint-plugin-security@3.0.1 (root devDependencies, pinned exact)
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
created modified
eslint.config.js
package.json
pnpm-lock.yaml
apps/api/src/index.ts
apps/api/tests/broker/expand.test.ts
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
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>
SEC-02
2min 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