Repository navigation
test(ingestor): pin clientRxCoverage.sources through LoadConfig (#278) - #290
Conversation
…oduce #278 gaps Loads the documented key through the real LoadConfig, so a typo in the struct tag (json:"sourcez") no longer leaves the suite green while the allowlist silently fails open. Also reproduces the missing startup warning for an allowlisted name that matches several mqttSources[].name, and the missing doc entries for the hardcoded drop-log interval and line cap. Relates to #278 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ral sources (#278) mqttSources[].name is not required to be unique and matching is case-insensitive, so one allowlisted name can admit several brokers. checkClientRxSources now logs one startup WARNING listing every such name and the sources it matches. Warning only; no behaviour change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ble values (#278) AGENTS.md rule 8: clientRxSourceWarnInterval (10 minutes) and clientRxSourceWarnMax (10 lines) are hardcoded; list them under "Configurable values (future customizer)" and document the duplicate-name startup warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rapport — CS-pve-agent3 PR#290 #278 — head 3db1111Status: All three follow-ups are implemented and each is tested red before and green after, with mutants. The draft PR is open and CI passed on the first attempt (no re-runs). Evidence tags: [T] test I ran, [A] analysis / code reading, [K] command output. Branch base: Requirement 1 — pin
|
| Change | Test only. The struct tag json:"sources,omitempty" is already correct [A] |
| Test | TestLoadConfigClientRxCoverageSources writes JSON with two mqttSources (a, b) and "clientRxCoverage": { "enabled": true, "sources": ["a"] }, then calls the real LoadConfig. It asserts Sources == ["a"], that a is allowed and that b is rejected [T] |
| Red before | Passes on master because the tag is correct. Under mutant M1 it is red [T] |
| Mutant | M1: tag sources → sourcez. Only this test fails, which confirms the gap from the #274 review is now closed [K] |
| Server | Not applicable. cmd/server's ClientRxCoverageConfig has only Enabled, so the server does not read sources and has nothing to pin [A]. A server started with {"clientRxCoverage": {"enabled": true, "sources": ["a"]}} reports clientRxCoverage: true in /api/config/client [K] |
Requirement 2 — warn at startup on duplicate source names
| Change | checkClientRxSources counts the matching mqttSources[].name per allowlisted name (trimmed, case-insensitive). When a name matches more than one source, it logs one WARNING listing the entry, the count and the matching source names (quoted with %q). Warning only. The signature, the return value and the unknown-name warning are unchanged [A] |
| Tests | TestCheckClientRxSourcesDuplicateName: sources auth, Auth, legacy, LEGACY with allowlist AUTH. Expects exactly one warning naming AUTH, "auth", " Auth " and the count 2, no mention of the non-allowlisted duplicate legacy, and no unknown names. TestCheckClientRxSourcesUniqueNamesNoDuplicateWarning: unique names produce no warning [T] |
| Red before | TestCheckClientRxSourcesDuplicateName fails on master: "expected exactly one warning line, got 0" [T] |
| Mutants | M2: warning block disabled → red. M3: threshold > 1 → > 2 → red [K] |
Requirement 3 — docs (AGENTS rule 8)
| Change | docs/client-rx-coverage.md: "Configurable values (future customizer)" now lists clientRxSourceWarnInterval (10 minutes) and clientRxSourceWarnMax (10 lines), and notes that they would become ingestor config keys, not customizer controls. The matching rules under "Restricting which MQTT sources may contribute" also mention the duplicate-name warning [A] |
| Test | TestClientRxCoverageDocListsDropLogLimits reads that section and requires `clientRxSourceWarnInterval`, 10 minutes and `clientRxSourceWarnMax`, 10 lines, with both values built from the Go constants [T] |
| Red before | Fails on master: neither entry is present [T] |
| Mutants | M4: doc entry removed → red. M5: interval constant changed to 15 minutes without updating the docs → red. M6: cap constant changed to 20 without updating the docs → red [K] |
Each mutant was applied on its own, run against TestLoadConfig*|TestCheckClientRxSources*|TestClientRxCoverage*|TestClientRxSource*, and reverted. In every case only the new test for that item failed [K].
Local verification [K]
| Command | Result |
|---|---|
cd cmd/ingestor && go vet ./... && go test -count=1 -timeout 30m ./... |
ok (777 s) |
cd cmd/server && go vet ./... && go test -count=1 -timeout 30m ./... |
ok (728 s) |
sh test-all.sh |
220 passed, 0 failed (220 files) |
node test-frontend-helpers.js |
707 passed, 0 failed |
gofmt -l on the touched Go files |
clean |
E2E ran against a local Go server on a scratch copy of e2e-fixture.db, prepared as in CI: freshen, the inline seed SQL from deploy.yml, corescope-migrate, then seeds 2073, 199 and 245. The server was stopped by pid and the port checked free afterwards [K].
- Default config (coverage off, as in CI):
test-node-reach-e2e.jsOK,test-issue-1630-reach-mobile-e2e.js7/0,test-reach-rank-e2e.js14/0.test-node-reach-coverage-e2e.jsandtest-rx-coverage-mobile-nav-e2e.jsSKIP (coverage disabled), as in CI [T] - Config with
enabled: trueandsources: ["a"]:test-rx-coverage-mobile-nav-e2e.js3/0,test-node-reach-e2e.jsOK [T].test-node-reach-coverage-e2e.jsfails withquery failedbecause the fixture has noclient_*tables. Those are created by the ingestor, not bycorescope-migrate, and CI never runs this test with coverage on. This is the same fixture limitation reported in the feat(ingestor): accept client RX coverage only from configured sources (#265) #274 review and is unrelated to this PR, which does not touchcmd/serverorpublic/[K][A]
Always-checks [K]
- Diff:
cmd/ingestor/client_rx_sources.go, the newcmd/ingestor/client_rx_sources_278_test.go, anddocs/client-rx-coverage.md. Nothing undercmd/server,public/or.github, socmd/serverstays read-only. - No new
map[string]interface{}(0 added lines, test file included). - No hardcoded colours. The only hex-like matches in the diff are the
#278/#265issue references. bash scripts/check-xss-sinks.sh --diff origin/master: nopublic/changes, exit 0.- Fork guards unchanged: 9 in
deploy.yml, 1 inrelease-fast-path.yml. - No closing keywords in the commits, title or body. The body starts with "Relates to Follow-ups to #274: pin the clientRxCoverage.sources JSON key, warn on duplicate source names, list log limits as configurable #278".
CI per job
Run 37400330950, attempt 1, head 3db11114 [K]:
| Job | Result |
|---|---|
| ✅ Go Build & Test | pass (19m17s) |
| 🎭 Playwright E2E Tests | pass (20m46s), first attempt; the #271 flake did not appear |
| 🏗️ Build & Publish Docker Image | pass (51s) |
| 📦 Release Artifacts | skipping (fork guard / tag-only) |
| 🚀 Deploy Staging | skipping (fork guard / push-only) |
| 📝 Publish Badges & Summary | skipping (fork guard / push-only) |
Remaining / notes
- Startup call not executed end to end. The new warning lives in
checkClientRxSources, whichmain()already calls once afterResolvedSources().mainis not unit-tested, so that call site has no test of its own [A]. - No live MQTT run. The duplicate warning is verified on captured log output, not against real brokers.
- Allowlist duplicates are not de-duplicated. If the allowlist itself repeats a name (
["auth", "AUTH"]) and that name matches several sources, it shows up twice in the one warning line. This is cosmetic and was left as is. - No browser validation. This PR makes no UI changes.
- No merge, ready-for-review, or issue state change.
Review — CS-Macmini PR#290 — head 3db1111Dom: APPROVE med nits Independent, read-only review. Verified on a Findings
No blocking finding. Nothing in N1–N4 changes behaviour: Requirements1 — pin 2 — warn on duplicate source names. Met. Red before on 3 — docs (AGENTS rule 8). Met. Red before on master (neither entry present) [T]. Both constants Tests I ranOn the merged tree, all green [T][K]:
Red-before, on E2E against a local Go server on a scratch copy of
Mutants I ranSix of my own, each applied alone and reverted, run against
MUT-B is the core of the fix and MUT-A the core of the pinning test; both die. The two survivors are Edge cases I triedSix probes in a throwaway test file, removed afterwards [T]:
Scope and always-checks [K]
CI per jobRun 37400330950, attempt 1, head
Only one run exists for this branch, so nothing was re-run to get green. The known flakes #256 Not verified
|
Relates to #278
Follow-ups from the review of #274 (#265): close the
LoadConfigtest gap forclientRxCoverage.sources, warn at startup when one allowlisted name matches more than one MQTT source, and list the hardcoded drop-log limits as configurable values.Plan
Each item gets a test that goes red first, then the code or docs change, then at least one mutant that turns the test red again.
LoadConfigTestLoadConfigClientRxCoverageSourcescheckClientRxSourcescounts matches per allowlisted name and logs oneWARNINGthat lists every name matching more than onemqttSources[].name(case-insensitive)TestCheckClientRxSourcesDuplicateName,TestCheckClientRxSourcesUniqueNamesNoDuplicateWarningdocs/client-rx-coverage.md: list the 10-minute re-log interval and the 10-line cap under "Configurable values (future customizer)", and add a note on duplicate names to the matching rulesTestClientRxCoverageDocListsDropLogLimits(reads the section and checks it against the Go constants)Details
1.
LoadConfiground trip. The test writes aconfig.jsonwith twomqttSources(a,b) and"clientRxCoverage": { "enabled": true, "sources": ["a"] }, then loads it through the realLoadConfig. It asserts thatSources == ["a"], thatais allowed and thatbis rejected. Before this, every allowlist test builtClientRxCoverageConfigdirectly, sojson:"sourcez"left the suite green while the documented key did nothing. That fails open: every source would be accepted.The server does not read
sources.cmd/server'sClientRxCoverageConfighas onlyEnabled, so there is no server-side key to pin, and this PR does not touchcmd/server. As a check, a server started with the sameclientRxCoverageblock still reportsclientRxCoverage: true(see the E2E results below).2. Duplicate names.
mqttSources[].nameis not required to be unique and matching is case-insensitive. So"sources": ["auth"]with sources namedauthandAuthadmits both brokers, which quietly widens a trust boundary. At startup,checkClientRxSourcesnow logs, for example:This is a warning only, with no behaviour change. Source names are printed with
%q, so an odd config value cannot forge log lines. Duplicated names that are not on the allowlist are not reported, because they do not affect the allowlist. The function signature and the existing unknown-name warning are unchanged.3. Docs. The interval and the cap are now listed with their constant names (
clientRxSourceWarnInterval,clientRxSourceWarnMax) and values. The doc test builds the expected text from the constants, so changing either constant without updating the docs turns the test red.Tests
origin/masterwith only the new test file,TestCheckClientRxSourcesDuplicateNamefails (no warning line) andTestClientRxCoverageDocListsDropLogLimitsfails (neither value is listed).TestLoadConfigClientRxCoverageSourcespasses on master because the tag is correct; it fails under mutant M1.TestLoadConfig*|TestCheckClientRxSources*|TestClientRxCoverage*|TestClientRxSource*, then reverted:sources→sourcezTestLoadConfigClientRxCoverageSources(and only that test)TestCheckClientRxSourcesDuplicateName> 1→> 2TestCheckClientRxSourcesDuplicateNameTestClientRxCoverageDocListsDropLogLimitsclientRxSourceWarnInterval10 → 15 min, docs unchangedTestClientRxCoverageDocListsDropLogLimitsclientRxSourceWarnMax10 → 20, docs unchangedTestClientRxCoverageDocListsDropLogLimitsScope and invariants
cmd/ingestor/client_rx_sources.go, the newcmd/ingestor/client_rx_sources_278_test.goanddocs/client-rx-coverage.md. Nothing undercmd/server,public/or.github.map[string]interface{}and no colours.scripts/check-xss-sinks.sh --diff origin/masteris clean (nopublic/changes).deploy.yml, 1 inrelease-fast-path.yml.🤖 Generated with Claude Code