Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
UI test files are linted with eslint-plugin-testing-library scoped to
*.test.{ts,tsx} (evidence: ui/eslint.config.js).
Fuzz tests exist in pkg/iprange, pkg/config, and pkg/processor;
make fuzz-replay replays the committed seed corpus shape with
go test -run=Fuzz and is wired into CI.
Tool versions come from manifests: Go 1.26.4 in go.mod, React/Vite/TypeScript/Tailwind in ui/package.json.
Go analysis tool versions are pinned in Makefile: govulncheckv1.3.0, Staticcheck v0.7.0, and golangci-lint v2.11.4.
Canonical commands
Main Go module: make test, make race, make lint,
make coverage, make vulncheck, make staticcheck, make golangci-lint,
make fuzz-replay, and make bench (evidence: Makefile).
JSON codec benchmark comparisons: make jsonbench runs the isolated
tools/jsonbench module so third-party JSON candidates can be measured
without adding them to the main application dependency graph.
Nested tool modules: make test-tools (currently covers
tools/dronebl2ipsets). make race also runs the nested module's race
tests, and make coverage-tools writes
tools/dronebl2ipsets/coverage.out for its separate coverage gate.
UI behavioral tests: make ui-test or pnpm --dir ui test. The
package script disables Node 25 experimental Web Storage for Vitest because
Node's global localStorage path emits --localstorage-file warnings in the
jsdom worker context.
UI browser smoke tests: make ui-e2e or pnpm --dir ui test:e2e.
These build the production bundle first and run the small Chromium
Playwright suite under ui/e2e/.
The package script clears NO_COLOR for Playwright because the runner sets
color forcing internally and Node warns when both NO_COLOR and
FORCE_COLOR are present.
Strict flake/order smoke for scheduler, engine, and web packages:
make test-strict (go test -shuffle=on -count=3 ./pkg/scheduler ./pkg/engine ./pkg/web).
Direct coverage command used by CI: make coverage for the root module and
make coverage-tools for tools/dronebl2ipsets (evidence:
.github/workflows/ci.yml).
Codacy coverage upload is owned by the CI coverage job. It uploads the
root coverage.out and tools/dronebl2ipsets/coverage.out reports only on
trusted push events to main or master, using CODACY_API_TOKEN and
Codacy's Go coverage parser. Pull-request runs intentionally skip the upload
so untrusted/fork/Dependabot contexts do not need Codacy secrets.
Embedded admin UI static is generated by make ui-static. Root Go
build/test/coverage/race/strict/cross targets depend on it so clean CI
checkouts build the same pkg/web/static/index.html and
pkg/web/static/assets/ shape that install.sh embeds. Direct go test ./... from a clean checkout is not the release gate because pkg/web
compile-time embeds the generated SPA shell.
Nested DroneBL module when touched: cd tools/dronebl2ipsets && go test ./... (evidence: nested tools/dronebl2ipsets/go.mod; root go test ./... does not enter nested modules).
Root ESLint bridge changes: make eslint-root-config or
pnpm --dir ui test:eslint-root-config verifies that repository-root
eslint.config.mjs imports the UI flat config, resolves TS/TSX/JS/MJS file
shapes, applies the UI TypeScript rules, and applies Node script rules for
modern .mjs maintenance scripts covered by Codacy/GitHub scanners.
UI pnpm build-script policy lives in ui/pnpm-workspace.yaml; keep
pnpm 11 CI installs green by classifying dependency lifecycle scripts there.
UI bundle-size changes: make ui-budget or pnpm --dir ui build:budget.
The budget checker reads ui/dist/assets after a production build, matches
stable chunk-name prefixes, and does not require generated assets to be
committed.
Browser-level UI changes: install the selected Playwright browser runtime
with pnpm --dir ui exec playwright install chromium, then run
make ui-e2e. CI installs Chromium with system dependencies before this
gate.
Install verification when runtime behavior changes: ./install.sh, then smoke endpoints (evidence: install.sh, README.md).
CI facts
GitHub Actions validates Go build/test/race/vet/cross-build, strict
shuffled tests, fuzz seed replay, blocking govulncheck, blocking
staticcheck, blocking golangci-lint, and 50% coverage thresholds for
both the root module and tools/dronebl2ipsets (evidence:
.github/workflows/ci.yml).
UI install, behavioral tests, lint, and build are wired into CI
(evidence: .github/workflows/ci.yml).
Root go test ./... does not cover the nested tools/dronebl2ipsets
module; make test-tools, make race, make coverage-tools,
make vulncheck, make staticcheck, and make golangci-lint explicitly
enter that module.
Fixture patterns
Prefer small inline YAML, text, JSON, and archive fixtures in tests.
Use t.TempDir() for filesystem state; do not write into repo source paths.
Test fixtures should use restrictive file and directory modes (0600 for
files, 0700 for directories) unless the test explicitly verifies a
public/shared mode contract. Do not use 0644/0755 as generic fixture
defaults.
Use httptest for downloader and web/API behavior.
Treat configs/firehol/ as a real catalog fixture for catalog validation tests.
When catalog source inventory changes, update all duplicated source-count
assertions, not only pkg/config/catalog_verify_test.go; search for the old
count across pkg/config, pkg/processor, and other test packages (from SOW-0008).
Feed-catalog changes need installed-service validation that affected feeds
publish committed public sets; URL checks and parser smoke counts alone do
not prove the downloader-to-processor-to-publication path completed (from SOW-0008).
Provider/catalog role changes need tests for both catalog/provider membership
and generated artifact coverage, plus serving-path tests showing public routes
do not generate missing feed-scoped artifacts on request (from SOW-0025
regression).
Engine tests must use the package-local newEngineFixture helper instead of
direct &Engine{} literals. pkg/engine/engine_fixture_test.go contains an
AST regression guard that enforces this construction boundary (from SOW-0046).
Same-package Go tests may call unexported helpers only when the helper is an
internal algorithm or writer contract where exported behavior would be much
slower, broader, or less precise. When an exported engine API already exposes
the same behavior, use the exported API instead (from SOW-0049).
New Go tests for packages with stable exported APIs should default to an
external pkg_test package. Keep same-package tests for internal algorithms,
package fixtures, global registries, or lock/queue invariants only when the
SOW or test comments make the contract reason clear (from SOW-0064).
ASN/geolocation default-provider changes need tests for config validation,
default-first provider API ordering, engine preferred-provider selection, and
default-provider drift marker behavior that forces rebuilds after config
changes (from SOW-0028).
Static config-backed feeds need tests for validation and end-to-end staging:
static: YAML lines must materialize through the normal raw source,
processor, and finalized set path, not through hardcoded internal providers
(from SOW-0017).
Real-use validation
API/server changes: run the daemon or installed service and verify with curl against /healthz, /api/v1/status, /api/v1/sets, and affected admin/public routes.
Integrity/mtime changes require installed-service validation: run
./install.sh, use admin repair/reprocess endpoints rather than manual file
edits, and verify both /api/v1/admin/integrity and
/api/v1/admin/integrity/entities return clean after background work
settles (from SOW-0017 regression).
UI changes: run pnpm --dir ui build and pnpm --dir ui lint; install when generated static assets or embedded serving are involved.
UI route-splitting changes need a browser smoke check against the embedded
serving model or installed service that proves the changed route loads
through the lazy boundary. Record any build-time asset warnings separately
from functional failures (from SOW-0033).
Playwright smoke tests run against ui/e2e/static-server.mjs, not
vite preview. The production bundle uses /static/ as its public asset
base; vite preview treats that as the app base too, while the embedded Go
server serves public routes from / and assets from /static/*. Keep the
browser test server aligned with the Go serving model (from SOW-0054).
UI component tests must stay black-box behavioral: render real components
through ui/src/test/render.tsx, drive interactions with userEvent, mock
backend boundaries with MSW handlers, and assert visible roles/text/links,
accessible names, URL/navigation outcomes, or request parameters. Do not mock
hooks, child components, TanStack Query, or internal state (from SOW-0034).
New UI tests should be colocated as *.test.tsx next to the component or
page under test. Shared test helpers and fixtures belong under
ui/src/test/ (from SOW-0034).
Page/component tests that cover accessible flows should include a small
vitest-axe check when the jsdom surface can represent the behavior. Disable
jsdom-impossible rules such as color-contrast locally instead of accepting
noisy failures (from SOW-0034).
Treat actionable vitest-axe findings as product bugs, not test noise. Fix
source issues such as unlabeled form controls, empty table headers, missing
dialog labeling, and nested interactive controls before disabling a rule.
Disable only checks that jsdom cannot evaluate faithfully (from SOW-0052).
Critical-infrastructure reference-feed tests must cover provider-set drift:
scheduler due/force behavior, stale provider_set_id rejection in public and
direct JSON routes, insights ignoring stale aggregates, integrity malformed
detection, stale removed-provider artifact deletion, reserved provider names,
generated artifact namespace collisions, exact public feed names that resemble
generated artifact files, static critical IP/CIDR validation, tier-aware
hard/soft/contextual insight thresholds, feed-page default ordering that puts
hard/soft/contextual criticality before matched-IP volume, per-provider
integrity expectations for unloaded providers, stale artifacts for feeds that
stop being comparable targets, raw-route/compose rejection for
non-redistributable critical reference feeds, and role conflicts with
bogons (from SOW-0017).
Critical provider-set scheduler tests must cover the active-engine window:
when provider-set drift exists and an engine run is already active, automatic
due evaluation must not repeatedly force-enqueue critical providers before the
active run publishes the new marker (from SOW-0017 install regression).
Semantic-classification regressions need adversarial names. Tests should
include configured feed/provider names containing artifact tokens such as
_bogons_, _critical_, _critical_infrastructure, _asn_, and
_country_, and prove exact configured identities win over substring
parsing (from SOW-0017 regression).
Mtime/integrity regressions need end-to-end publication assertions. Tests
should verify every generated public artifact family participating in
integrity has an mtime at least as recent as the cache ProcessedDate after
staged publish; include history, changesets, retention, metadata, comparison,
geo/ASN/bogon, critical, insights, and entity artifacts when touched (from
SOW-0017 regression).
Entity integrity mtime tests must cover provider-derived payload mtimes
moving forward while a feed entity sidecar's JSON stays unchanged. The test
should assert the feed sidecar, private country/ASN sidecars, public
country/ASN payloads, and entity integrity plan all agree after repair (from
SOW-0017 regression).
Pipeline integrity regressions should be added to the table-driven scenario
harness in pkg/engine/pipeline_integrity_scenario_test.go: each row should
advance a logical timestamp, mutate mocked feed/provider input with add/remove
entries, run the scheduler-style update path, settle queued entity refreshes,
verify expected feed entries when relevant, and fail on any feed-output or
entity-artifact integrity finding. Keep the branch matrix covering initial
publish, ordinary updates, same-body forced/unforced checks, geo/ASN/bogon
provider fan-out, merge exclude recomposition, scoped/global reprocess, and
critical provider-set marker repair (from SOW-0017 regression).
Admin entity-integrity tests must cover both suppression windows:
StatusSnapshot.Running for main engine runs and Entity artifacts *
background tasks for entity-specific repairs/refreshes. Without both, the
admin API can show transient stale rows as settled issues (from SOW-0017
regression).
Admin pipeline/entity integrity tests must prove GET handlers are passive
cache-first readers: cold or stale cache returns in-progress/cache-state with
no current findings and no queued engine-lane work, fresh cache returns
settled findings, and reprocess uses fresh cached findings instead of running
a live scan from the HTTP handler. Admin status summaries must also report
zero current findings for stale/cold/queued/running caches. POST
refresh/reprocess actions own engine-lane tickets and coalescing state as
observable API contract (from SOW-0117 regression).
Scheduler recovery tests for artifact parents must include DroneBL-style
staged parent artifacts and prove recovery queues the parent in the
downloader FIFO without materializing children directly from startup recovery
(from SOW-0117).
Merge subtraction tests must cover more than the happy path: multiple
subtractive parents, disabled/no-additive state, strict subtractive
dependency failures, integrity blockers, and enableAll behavior (from
SOW-0025 regression).
Raw-feed access tests must cover every public raw body route together,
including /api/v1/sets/{name}/data, /api/v1/compose,
/files/{feed}.ipset|netset, and direct /{feed}.ipset|netset, because
metadata visibility and raw redistributability are intentionally different
policies (from SOW-0025 follow-up).
Raw-feed route tests should include failure cases where the catalog/cache says
a feed exists but the materialized .ipset/.netset file is missing, so
direct compatibility downloads cannot regress to empty 200 OK responses
(from SOW-0025 regression).
Web file-cache tests must cover observable serving behavior under entry,
byte, and per-file cache limits, and must prove raw .ipset/.netset routes
do not populate the JSON/static artifact cache (from SOW-0036).
Broad web route tests should use the package-local webHTTPTestServer
fixture so middleware, auth, CORS, gzip, route registration, and file serving
are exercised through real HTTP. Keep direct httptest.NewRecorder tests for
focused middleware, gzip, file-cache, and single-handler path-safety unit
checks where a server adds no contract value (from SOW-0047).
Public artifact-serving tests should prove Options.WebDir is the served
tree and remove the served artifact while leaving runtime/live-builder inputs
present, so accidental request-time fallback is caught (from SOW-0025
follow-up).
Integrity tests for public raw-body policy should include stale published
metadata artifacts, not only fresh code paths. A non-redistributable or
archived feed whose {feed}.json still exposes raw/source fields must be
flagged malformed so normal repair regenerates it (from SOW-0025 regression).
Public artifact minimality needs stale-artifact tests, not only fresh writer
tests. Pairwise comparison tests must prove common == 0 rows are omitted,
stale zero-overlap rows are removed during incremental merge, and integrity
flags old comparison artifacts that still contain explicit zero rows (from
SOW-0026).
Raw-feed path safety tests should cover unexpected cache entry file paths and
non-redistributable feeds in both include and exclude positions for public
compose (from SOW-0025 follow-up).
Signed-merge comparison tests must prove subtractive parents are not treated
as positive lineage for pairwise related and unique-share filtering (from
SOW-0025 follow-up).
Empty-feed investigations should distinguish public feeds from hidden/internal
admin rows, then classify each remaining empty as upstream-empty,
downloader/unavailable, parser/config bug, or intentional synthetic-source
empty state (from SOW-0008).
Feed-health regressions for reference/provider roles must test both sides of
the contract: old-but-stable critical_infrastructure, provider_context,
asn, and geoip sources stay healthy on age alone, while zero-entry
publications for the same roles still classify as empty (from SOW-0037).
Scheduler/background-work refactors need targeted policy tests for queued
action dedupe, active download refetch deferral/release, processing deferral
while active, provider-default drift enqueue, staged-work recovery, and
download-input-settled ordering. Run make race and installed-service smoke
against /api/v1/admin/status queue/metrics visibility when scheduler
runtime code changes (from SOW-0030).
Scheduler tests for public trigger/run-loop behavior should use the
package-local startSchedulerRunner harness and assert observable activity,
artifacts, or snapshots. Keep direct private queue-field tests only for
admission, lock, ordering, and requeue invariants that are not exposed without
slow or timing-sensitive full-runner flows (from SOW-0066).
Engine heavy-phase cancellation tests should prove bounded worker helpers stop
admitting new jobs after context cancellation and that artifact writers return
context.Canceled without publishing partial outputs (from SOW-0035).
Daemon/background cancellation tests should verify both sides of the
contract: the owner waits for its goroutine to exit, and sender-side fan-out
loops stop scheduling new jobs when context cancellation happens while a
worker is blocked (from SOW-0042).
Scheduler cancellation tests must cancel and wait for Runner.Run to return
before test cleanup. A test that only calls cancel() can hide real runner
ownership bugs as timing-sensitive t.TempDir cleanup failures (from
SOW-0035).
Go tests must not use time.Sleep as synchronization. Use an observable
condition with a bounded ticker/timer, a channel/HTTP readiness signal, or a
package status snapshot. For admin/background-work tests, prove the scheduled
work produced its expected artifact or state change and that the relevant
background task list is empty before cleanup (from SOW-0032).
Use t.Setenv instead of raw os.Setenv/os.Unsetenv in tests, so
process-wide environment changes are scoped to the test and remain
incompatible with unsafe parallel ancestors (from SOW-0032).
Prefer structured assertions over rendered strings: parse JSON and assert
fields, inspect returned state, or assert structured slog attributes when
logging is the contract. Avoid substring checks on logs, HTML, or bundled UI
output unless the substring itself is the public contract (from SOW-0032).
New or touched benchmarks should use b.Loop() on the Go 1.26 toolchain
instead of the legacy for i := 0; i < b.N; i++ loop shape (from SOW-0032).
Parser/config/set-algebra changes should consider stdlib fuzz/property tests
before adding dependencies. Good local patterns are FuzzLoadYAML,
FuzzRunDeterministicTextProcessors, and multi-range testing/quick
invariants for pkg/iprange (from SOW-0032).
Cancellation and bounded fan-out tests that do not need external network or
process time should prefer testing/synctest with the whole operation inside
the bubble and synctest.Wait() before assertions; pkg/engine
cancellation tests are the first local pattern (from SOW-0039).
Shared test helpers must not be added to already-large test files just
because the callers live there. Put reusable helpers in focused
*_test.go helper files and let the architecture posture gate block
accidental large-file growth (from SOW-0039).
Lifecycle/shutdown tests should assert externally meaningful settled state
after the owning run call returns: scheduler activity snapshots have no
active work, web listeners are closed, background-task lists are empty, or
expected artifacts are fully published. Do not use package-wide goroutine
counts when public owner state provides the contract (from SOW-0048).
Three/WebGL UI changes need a browser validation pass: render the scene at a
desktop-sized viewport, capture or inspect a nonblank canvas/screenshot, and
unmount/remount enough to prove cleanup removes the canvas without console
errors from the component (from SOW-0033).
Public methodology/docs/UI-copy changes need a surface-fit validation pass using project-content-surfaces; tests alone are insufficient. For methodology pages, scan for misplaced implementation markers such as configs/, pkg/, use:, artifact filenames, YAML fences, and raw API route lists when those details are not part of the page's public interpretation job (from SOW-0017 regression).
Performance/telemetry changes: compare admin status/telemetry snapshots over elapsed time and CPU/memory/I/O deltas.
For hot-path helper changes, add or update a regression guard that checks cost shape, not only correctness. In engine code, TestEffectiveEntryHelpersExposeSnapshotCost prevents cheap-looking effective-entry/feed-health helpers and fresh full-cache snapshot calls inside loops (from SOW-0024).
Allocation-shape tests that use testing.AllocsPerRun must not fail under
-race; race detector instrumentation changes allocation counts. Keep the
allocation ceiling active in normal make test, and gate only the
allocation-count assertion under the race build tag when needed (from
SOW-0117).
Release/security changes: include explicit secret/path scans and document what was checked.