Files
truf-server/docs/defect-windows-scan-timestamps-utc-2026-09-25.md
2026-09-30 20:30:56 +03:00

73 lines
3.2 KiB
Markdown

# 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.