PR #153 merged: Postgres in CI + fix security_digest CVE duplication
Why
While auditing the MCP tools I hit two things that compound each other:
security_digestlists the same CVE up to 20× (confirmed live today —CVE-2026-47140twenty times in the critical block).- The reason it shipped: the test suite runs on SQLite, so the 27 Postgres-specific dashboard/MCP query tests (
DISTINCT ON,date_trunc, materialized views) all skip in CI. The query layer had zero automated coverage.
This PR fixes both — CI now runs on Postgres (activating the dormant tests), and the dedup bug is fixed with coverage.
1. Postgres in CI
tests.yml: adds apostgres:16service +DB_*env. The suite now runs on pgsql.Pest.php: refreshes thecross_platform_matchesmaterialized view before each test (createdWITH NO DATA; instant + transaction-safe on empty test tables).- Fixed the tests this exposed (all pre-existing, never run before):
GetSecurityDigestTest:firstOrCreateforghsa_all/krebs(seeded by theadd_new_data_sourcesmigration → factorycreate()hit a unique violation on pg).- Dashboard auth tests:
homehas no auth middleware (it's the public trends landing;/mcp-statsis the auth-gated one). The "guests redirected to login" assertion was stale — updated to assert the public200. Verified against the route, not assumed.
Result: 274 passed / 0 skipped on Postgres (was 246 passed / 28 skipped on SQLite). SQLite path still green for local runs.
2. security_digest dedup
queryCritical / queryHigh / queryNvdCisa had no dedup — they sorted all the re-fetched duplicate rows by CVSS and took 20. Wrapped each in a DISTINCT ON (url_hash) subquery (external_id for nvd_cisa), keeping the latest fetch per advisory, then sorting by CVSS in the outer query — the pattern querySecurityBlogs already used. medium_count → COUNT(DISTINCT url_hash).
New test seeds one advisory re-fetched 20× and asserts it appears once.
Test plan
- Postgres (local, clean DB): 274 passed / 0 skipped.
- SQLite: 246 passed / 28 skipped (unchanged).
-
pint --dirtyclean. - Post-deploy: re-run
security_digestvia MCP and confirm each CVE appears once.
Follow-ups (separate PRs, now testable on pg CI)
weekly_intelHN section sorts byurl_hashnot score.opportunity_finderonly ever tags[general].find_divergences: seed the 17-topic watchlist (never seeded → always empty) + add a discourse-level ceiling so it fires on genuinely quiet topics rather than already-loud ones.