black/isort/flake8 configured but never run in CI; eslint declared but its parser was never installed (broken since forever); vitest never in CI
Makefile (lint, lint-fix, typecheck) + .github/workflows/lint.yml/tests.yml wire it all up: blocking where clean, ratcheted (changed-files-only) where a real backlog exists (mypy, eslint)
husky pre-commit + lint-staged mirror the clean checks locally; make lint now covers flowsint-app too (was Python-only)
Python toolchain migrated black+isort+flake8 → ruff (one tool, one config)
real bugs surfaced by turning the tools on for the first time: bare excepts, a duplicate test silently shadowing another, dead code, all 19 react-hooks/rules-of-hooks violations, several real type mismatches (backend/frontend API contract drift, a generator mistyped as returning its yielded value directly, a DOM-vs-domain Event type collision)
frontend no-explicit-any backlog reduced ~294 → ~112 across the API service layer and the react-force-graph subsystem
mypy backlog resolved to 0 real errors on every file this branch touches (pydantic mypy plugin enabled project-wide, scoped overrides for two patterns mypy structurally can't verify — enricher InputType/OutputType and Tool.launch's per-subclass signatures — rest is real fixes)
regression found and fixed: the react-hooks/set-state-in-effect cleanup's "adjust state during render" pattern silently dropped the first value on mount whenever a component could mount with data already available (query cache hit) — form panels (node details, sketch settings, analysis title, profile, custom-type editor) stayed empty until a second, different value came in
added CONTRIBUTING.md with the pre-commit verification checklist
CI fix: make lint was wired to also run flowsint-app's prettier/eslint, but the job invoking it only set up uv, not Node/yarn — prettier: not found. Added Node+yarn setup and removed the now-redundant standalone frontend-lint job it duplicated
merged main in (GPLv3 dep removal: holehe/pydig/ignorant/hibpwned, incl. the phone_to_infos enricher that depended on them) and regenerated uv.lock from the merged pyproject.tomls instead of hand-splicing the lockfile conflict
security: pinned minimum_version = TLSVersion.TLSv1_2 on the two remaining get_domain_from_ssl SSL contexts (CodeQL high-severity "insecure protocol version" — create_default_context() already excludes TLS1/1.1 by default, but the alert wants it explicit rather than implicit)
while touching that function, found it duplicated three times (flowsint-core, flowsint-enrichers, flowsint-api) with zero callers anywhere in the repo — deleted all three. flowsint-api/app/utils.py turned out to be a fully dead file (nothing imports it at all); flowsint_enrichers/utils.py trimmed to its one actually-used function (get_root_domain)
Test plan
make lint / make typecheck green (all 4 Python packages + frontend)
uv run pytest green in all 4 Python packages
yarn build / npx vitest run / npx tsc --noEmit (frontend) green
CI green on this branch (lint, typecheck, tests, both Python and frontend, CodeQL)
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/reconurge/flowsint/pull/214
**Author:** [@dextmorgn](https://github.com/dextmorgn)
**Created:** 8/24/2026
**Status:** ✅ Merged
**Merged:** 8/26/2026
**Merged by:** [@dextmorgn](https://github.com/dextmorgn)
**Base:** `main` ← **Head:** `chore/lint-ci-hooks`
---
### 📝 Commits (10+)
- [`2fc6027`](https://github.com/reconurge/flowsint/commit/2fc60276ba7eba614d8d68fd98d442eb0028be7e) ci: wire lint/typecheck/pre-commit gates that existed but never ran
- [`eb30268`](https://github.com/reconurge/flowsint/commit/eb30268c56316a893ecd77499b3411a04959be19) style(python): apply black/isort formatting workspace-wide
- [`501ebee`](https://github.com/reconurge/flowsint/commit/501ebee93281cf911d2b6a36dd72dc2c5b9a318f) style(frontend): apply prettier formatting workspace-wide
- [`24e1e27`](https://github.com/reconurge/flowsint/commit/24e1e276c8d0a4139f00e0a35e28d1acf680f59c) fix(python): correctness fixes surfaced by turning flake8 on
- [`a620635`](https://github.com/reconurge/flowsint/commit/a620635c02ab1c11f692815390c879ab92abb464) fix(frontend): resolve all react-hooks/rules-of-hooks violations
- [`cf69a7e`](https://github.com/reconurge/flowsint/commit/cf69a7e088dba55c68debff6b3a9c4f189b35d6b) fix(ci): make isort's first-party grouping invocation-independent
- [`9239d40`](https://github.com/reconurge/flowsint/commit/9239d4037704292aaca1348b1895614619dc3bb6) fix(ci): isort still disagreed with itself after the previous fix
- [`73f258f`](https://github.com/reconurge/flowsint/commit/73f258f3b105bd1fc9b95ad2eec709195a4cce40) fix(frontend): resolve react-hooks/exhaustive-deps across live code
- [`6410091`](https://github.com/reconurge/flowsint/commit/64100914d753426cd96362149e33d6d1fde141e2) fix(frontend): resolve no-unescaped-entities and ban-ts-comment
- [`189048e`](https://github.com/reconurge/flowsint/commit/189048ea03ef584f15d2921ea74ca40b0285df66) fix(frontend): clear the small eslint rule violations
### 📊 Changes
**468 files changed** (+7955 additions, -6145 deletions)
<details>
<summary>View changed files</summary>
➕ `.github/workflows/lint.yml` (+85 -0)
📝 `.github/workflows/tests.yml` (+13 -0)
➕ `.husky/pre-commit` (+1 -0)
➕ `CONTRIBUTING.md` (+51 -0)
📝 `Makefile` (+68 -1)
📝 `README.md` (+2 -1)
📝 `flowsint-api/alembic/env.py` (+9 -4)
📝 `flowsint-api/alembic/versions/0160b0f70a02_add_context_to_chat_message.py` (+6 -6)
📝 `flowsint-api/alembic/versions/0ab8ee0a782c_add_cascade_delete_to_messages.py` (+3 -6)
📝 `flowsint-api/alembic/versions/1098b7a5eabc_change_keys_structure_with_iv_salt_.py` (+33 -27)
📝 `flowsint-api/alembic/versions/1d0f26dbbef5_add_passive_delete_v2.py` (+3 -6)
📝 `flowsint-api/alembic/versions/2da47dbd4a52_add_cascade_delete_to_scans_and_logs.py` (+33 -13)
📝 `flowsint-api/alembic/versions/40ece72583b7_add_email_and_hashed_password_to_profile.py` (+12 -12)
📝 `flowsint-api/alembic/versions/661ff8ef4425_rename_transforms_to_flows.py` (+9 -10)
📝 `flowsint-api/alembic/versions/6be831edfda7_add_investigation_roles_permissions.py` (+32 -7)
📝 `flowsint-api/alembic/versions/6dfa83113ad7_change_content_colum_of_log_to_json.py` (+3 -5)
📝 `flowsint-api/alembic/versions/6e49acfb3816_add_investigation_roles_permissions.py` (+114 -35)
📝 `flowsint-api/alembic/versions/71a3e5b4db2a_update_scan_status_enum.py` (+93 -53)
📝 `flowsint-api/alembic/versions/76f5436251e3_add_relationship_between_investigations_.py` (+3 -6)
📝 `flowsint-api/alembic/versions/8173aba964e7_add_custom_types_table.py` (+38 -22)
_...and 80 more files_
</details>
### 📄 Description
## Summary
- black/isort/flake8 configured but never run in CI; eslint declared but its parser was never installed (broken since forever); vitest never in CI
- Makefile (`lint`, `lint-fix`, `typecheck`) + `.github/workflows/lint.yml`/`tests.yml` wire it all up: blocking where clean, ratcheted (changed-files-only) where a real backlog exists (mypy, eslint)
- husky pre-commit + lint-staged mirror the clean checks locally; `make lint` now covers `flowsint-app` too (was Python-only)
- Python toolchain migrated black+isort+flake8 → ruff (one tool, one config)
- ESLint config migrated `.eslintrc.cjs` → flat config (`eslint.config.ts`), eslint 8 → 9 (verified finding-count-identical before/after)
- real bugs surfaced by turning the tools on for the first time: bare excepts, a duplicate test silently shadowing another, dead code, all 19 react-hooks/rules-of-hooks violations, several real type mismatches (backend/frontend API contract drift, a generator mistyped as returning its yielded value directly, a DOM-vs-domain `Event` type collision)
- frontend `no-explicit-any` backlog reduced ~294 → ~112 across the API service layer and the react-force-graph subsystem
- mypy backlog resolved to 0 real errors on every file this branch touches (pydantic mypy plugin enabled project-wide, scoped overrides for two patterns mypy structurally can't verify — enricher `InputType`/`OutputType` and `Tool.launch`'s per-subclass signatures — rest is real fixes)
- regression found and fixed: the react-hooks/set-state-in-effect cleanup's "adjust state during render" pattern silently dropped the *first* value on mount whenever a component could mount with data already available (query cache hit) — form panels (node details, sketch settings, analysis title, profile, custom-type editor) stayed empty until a second, different value came in
- added `CONTRIBUTING.md` with the pre-commit verification checklist
- CI fix: `make lint` was wired to also run `flowsint-app`'s prettier/eslint, but the job invoking it only set up `uv`, not Node/yarn — `prettier: not found`. Added Node+yarn setup and removed the now-redundant standalone `frontend-lint` job it duplicated
- merged `main` in (GPLv3 dep removal: holehe/pydig/ignorant/hibpwned, incl. the `phone_to_infos` enricher that depended on them) and regenerated `uv.lock` from the merged `pyproject.toml`s instead of hand-splicing the lockfile conflict
- security: pinned `minimum_version = TLSVersion.TLSv1_2` on the two remaining `get_domain_from_ssl` SSL contexts (CodeQL high-severity "insecure protocol version" — `create_default_context()` already excludes TLS1/1.1 by default, but the alert wants it explicit rather than implicit)
- while touching that function, found it duplicated **three times** (`flowsint-core`, `flowsint-enrichers`, `flowsint-api`) with zero callers anywhere in the repo — deleted all three. `flowsint-api/app/utils.py` turned out to be a fully dead file (nothing imports it at all); `flowsint_enrichers/utils.py` trimmed to its one actually-used function (`get_root_domain`)
## Test plan
- [x] `make lint` / `make typecheck` green (all 4 Python packages + frontend)
- [x] `uv run pytest` green in all 4 Python packages
- [x] `yarn build` / `npx vitest run` / `npx tsc --noEmit` (frontend) green
- [x] CI green on this branch (lint, typecheck, tests, both Python and frontend, CodeQL)
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/reconurge/flowsint/pull/214
Author: @dextmorgn
Created: 8/24/2026
Status: ✅ Merged
Merged: 8/26/2026
Merged by: @dextmorgn
Base:
main← Head:chore/lint-ci-hooks📝 Commits (10+)
2fc6027ci: wire lint/typecheck/pre-commit gates that existed but never raneb30268style(python): apply black/isort formatting workspace-wide501ebeestyle(frontend): apply prettier formatting workspace-wide24e1e27fix(python): correctness fixes surfaced by turning flake8 ona620635fix(frontend): resolve all react-hooks/rules-of-hooks violationscf69a7efix(ci): make isort's first-party grouping invocation-independent9239d40fix(ci): isort still disagreed with itself after the previous fix73f258ffix(frontend): resolve react-hooks/exhaustive-deps across live code6410091fix(frontend): resolve no-unescaped-entities and ban-ts-comment189048efix(frontend): clear the small eslint rule violations📊 Changes
468 files changed (+7955 additions, -6145 deletions)
View changed files
➕
.github/workflows/lint.yml(+85 -0)📝
.github/workflows/tests.yml(+13 -0)➕
.husky/pre-commit(+1 -0)➕
CONTRIBUTING.md(+51 -0)📝
Makefile(+68 -1)📝
README.md(+2 -1)📝
flowsint-api/alembic/env.py(+9 -4)📝
flowsint-api/alembic/versions/0160b0f70a02_add_context_to_chat_message.py(+6 -6)📝
flowsint-api/alembic/versions/0ab8ee0a782c_add_cascade_delete_to_messages.py(+3 -6)📝
flowsint-api/alembic/versions/1098b7a5eabc_change_keys_structure_with_iv_salt_.py(+33 -27)📝
flowsint-api/alembic/versions/1d0f26dbbef5_add_passive_delete_v2.py(+3 -6)📝
flowsint-api/alembic/versions/2da47dbd4a52_add_cascade_delete_to_scans_and_logs.py(+33 -13)📝
flowsint-api/alembic/versions/40ece72583b7_add_email_and_hashed_password_to_profile.py(+12 -12)📝
flowsint-api/alembic/versions/661ff8ef4425_rename_transforms_to_flows.py(+9 -10)📝
flowsint-api/alembic/versions/6be831edfda7_add_investigation_roles_permissions.py(+32 -7)📝
flowsint-api/alembic/versions/6dfa83113ad7_change_content_colum_of_log_to_json.py(+3 -5)📝
flowsint-api/alembic/versions/6e49acfb3816_add_investigation_roles_permissions.py(+114 -35)📝
flowsint-api/alembic/versions/71a3e5b4db2a_update_scan_status_enum.py(+93 -53)📝
flowsint-api/alembic/versions/76f5436251e3_add_relationship_between_investigations_.py(+3 -6)📝
flowsint-api/alembic/versions/8173aba964e7_add_custom_types_table.py(+38 -22)...and 80 more files
📄 Description
Summary
lint,lint-fix,typecheck) +.github/workflows/lint.yml/tests.ymlwire it all up: blocking where clean, ratcheted (changed-files-only) where a real backlog exists (mypy, eslint)make lintnow coversflowsint-apptoo (was Python-only).eslintrc.cjs→ flat config (eslint.config.ts), eslint 8 → 9 (verified finding-count-identical before/after)Eventtype collision)no-explicit-anybacklog reduced ~294 → ~112 across the API service layer and the react-force-graph subsystemInputType/OutputTypeandTool.launch's per-subclass signatures — rest is real fixes)CONTRIBUTING.mdwith the pre-commit verification checklistmake lintwas wired to also runflowsint-app's prettier/eslint, but the job invoking it only set upuv, not Node/yarn —prettier: not found. Added Node+yarn setup and removed the now-redundant standalonefrontend-lintjob it duplicatedmainin (GPLv3 dep removal: holehe/pydig/ignorant/hibpwned, incl. thephone_to_infosenricher that depended on them) and regenerateduv.lockfrom the mergedpyproject.tomls instead of hand-splicing the lockfile conflictminimum_version = TLSVersion.TLSv1_2on the two remainingget_domain_from_sslSSL contexts (CodeQL high-severity "insecure protocol version" —create_default_context()already excludes TLS1/1.1 by default, but the alert wants it explicit rather than implicit)flowsint-core,flowsint-enrichers,flowsint-api) with zero callers anywhere in the repo — deleted all three.flowsint-api/app/utils.pyturned out to be a fully dead file (nothing imports it at all);flowsint_enrichers/utils.pytrimmed to its one actually-used function (get_root_domain)Test plan
make lint/make typecheckgreen (all 4 Python packages + frontend)uv run pytestgreen in all 4 Python packagesyarn build/npx vitest run/npx tsc --noEmit(frontend) green🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.