Initial server source import
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# Defect: Windows scan timestamps lose their UTC offset
|
||||
|
||||
## Status
|
||||
|
||||
Open and reproducible in the accepted Windows worker package validated on
|
||||
2026-09-25. The live validation did not modify product code so that the tested
|
||||
package remained identical to the accepted artifact.
|
||||
|
||||
## Symptom
|
||||
|
||||
Windows `scan.result_error` diagnostics can be stored with `occurred_at` about
|
||||
the machine's local UTC offset in the future. In the validation environment the
|
||||
offset was approximately three hours. The same naive timestamps also populate
|
||||
Windows `target_scans.started_at` and `target_scans.ended_at`.
|
||||
|
||||
This can misorder diagnostics, distort time-window filters, and make the admin
|
||||
panel show a scan event later than the server receipt that contains it.
|
||||
|
||||
## Live evidence
|
||||
|
||||
The accepted Windows package ran with a fresh state directory and one slot. In
|
||||
the expanded live cohort, all 45 Windows `scan.result_error` diagnostics had an
|
||||
`occurred_at` to server `received_at` delta between approximately 10,816 and
|
||||
10,819 seconds. All 135 normal Windows scan-result rows used naive local start
|
||||
and end timestamps with the same approximately three-hour displacement when
|
||||
treated as UTC. The four Windows timeout-path rows and all 102 Linux rows had
|
||||
normal small timing deltas.
|
||||
|
||||
The retained raw scanner material contained an explicit `+03:00` timestamp.
|
||||
The persisted diagnostic retained the same wall-clock digits but labeled them
|
||||
as UTC with `Z`. Monotonic scan durations and worker progress transport
|
||||
timestamps remained correct.
|
||||
|
||||
Sensitive raw targets, scanner output, and credentials are retained only in the
|
||||
restricted live evidence file and are intentionally not reproduced here.
|
||||
|
||||
## Root cause
|
||||
|
||||
`app/scanner.py` creates scan timestamps with naive local datetimes:
|
||||
|
||||
- `scan_target_result()` uses `datetime.now().isoformat()` for
|
||||
`scan_started_at` and `timestamp` near lines 16339 and 16416.
|
||||
- fallback result construction in `scan_single_target()` does the same near
|
||||
lines 16844, 16863, and 16877.
|
||||
|
||||
Diagnostic construction parses those values and, when no timezone is present,
|
||||
uses `occurred.replace(tzinfo=timezone.utc)` near line 16581. That operation
|
||||
relabels local wall-clock time as UTC instead of converting it. The error is
|
||||
visible on non-UTC hosts and is hidden on UTC Linux hosts.
|
||||
|
||||
## Expected behavior
|
||||
|
||||
All persisted protocol timestamps must identify a real UTC instant. Scanner
|
||||
result timestamps should be emitted as timezone-aware UTC values, and legacy
|
||||
naive values must not be silently reinterpreted as known UTC instants.
|
||||
|
||||
## Suggested correction and regression coverage
|
||||
|
||||
Emit `datetime.now(timezone.utc).isoformat()` at every result-construction site
|
||||
and preserve the offset through serialization. Add a non-UTC-host regression
|
||||
test that verifies:
|
||||
|
||||
- scanner start/end timestamps identify the actual UTC instant;
|
||||
- diagnostic `occurred_at` precedes or closely tracks server `received_at`;
|
||||
- Windows and Linux admin time-window filters return the same logical events;
|
||||
- monotonic duration fields remain unchanged.
|
||||
|
||||
## Validation artifact
|
||||
|
||||
The expanded unrestricted evidence is retained at
|
||||
`build/live-trace-20260925/raw-evidence-expanded.json`. It contains sensitive
|
||||
raw internals and must not be published as a general operator report.
|
||||
Reference in New Issue
Block a user