Files
satellite-provider/_docs/02_tasks/todo/AZ-1126_captured_at_datetimeoffset.md
T
Oleksandr Bezdieniezhnykh b055450e40 [AZ-1124] Cycle 12 closure docs and cycle 13 task slate
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 13:21:00 +03:00

5.1 KiB

Migrate UAV upload capturedAt to DateTimeOffset

Task: AZ-1126_captured_at_datetimeoffset Name: Migrate UavTileMetadata.capturedAt to DateTimeOffset (F-AZ810-2) Description: Close security carry-over F-AZ810-2 by typing UavTileMetadata.CapturedAt as DateTimeOffset instead of DateTime, eliminating ambiguous DateTimeKind.Unspecified handling on the UAV upload metadata input path. Complexity: 2 points Dependencies: AZ-810 (HARD — metadata validation layer); AZ-488 (original upload endpoint) Component: SatelliteProvider.Common (UavTileMetadata) + SatelliteProvider.Api (validators) + SatelliteProvider.Services.TileDownloader (quality gate + upload handler) Tracker: AZ-1126 Epic: AZ-795

Problem

Security finding F-AZ810-2 (cycle 8, open through cycle 12) flags that UavTileMetadata.CapturedAt is typed DateTime rather than DateTimeOffset. DateTime accepts DateTimeKind.Unspecified values that deserialize from offset-less ISO-8601 strings, forcing manual Kind normalization in the upload handler and quality gate. This is a time-handling correctness gap that can skew freshness-window checks in non-UTC dev environments.

Outcome

  • capturedAt on the UAV upload metadata input is unambiguously UTC-aware at the type level
  • Offset-less or Unspecified timestamps are rejected before persistence
  • F-AZ810-2 is marked resolved in the next security audit cycle
  • Wire compatibility preserved for clients sending ISO-8601 UTC with explicit offset (Z or +00:00)

Scope

Included

  • Change UavTileMetadata.CapturedAt from DateTime to DateTimeOffset
  • Update FluentValidation rules, quality gate, and upload handler to compare via UTC without manual Kind branching
  • Reject offset-less / ambiguous capturedAt values with HTTP 400
  • Unit tests for the new rejection path and existing freshness-window rules
  • Integration test proving offset-less capturedAt is rejected
  • Patch _docs/02_document/contracts/api/uav-tile-upload.md 1.2.0 → 1.2.1 (change log + clarify offset requirement)

Excluded

  • TileInventoryEntry.CapturedAt response field (remains DateTime? — DB read path)
  • TileEntity.CapturedAt persistence layer type
  • Changes to gRPC tile delivery or other non-UAV-upload surfaces
  • MAJOR contract version bump (wire JSON shape unchanged for compliant clients)

Acceptance Criteria

AC-1: Type migration Given the UAV upload metadata DTO When deserialized from JSON Then CapturedAt is DateTimeOffset and freshness comparisons use UTC without manual DateTimeKind normalization

AC-2: Reject ambiguous timestamps Given a UAV upload batch with capturedAt lacking an explicit UTC offset (offset-less ISO string) When POST /api/satellite/upload Then HTTP 400 with a validation or deserialization error referencing capturedAt

AC-3: Backward-compatible UTC clients Given a UAV upload batch with capturedAt as ISO-8601 UTC (...Z or ...+00:00) When POST /api/satellite/upload with otherwise valid payload Then HTTP 200 (or the same non-timestamp rejection as before timestamp validation)

AC-4: Contract patch Given the implementation is complete When uav-tile-upload.md is reviewed Then version is 1.2.1 with a change-log entry documenting the offset requirement and F-AZ810-2 closure

Non-Functional Requirements

Compatibility

  • Compliant clients already sending Z-suffixed timestamps must not break

Security

  • Closes F-AZ810-2 (Low / informational time-handling finding)

Unit Tests

AC Ref What to Test Required Outcome
AC-1 UavTileMetadataValidator freshness window with DateTimeOffset Future/too-old rules still fire
AC-2 Deserializer or validator with offset-less capturedAt Rejected
AC-1 UavTileQualityGate captured-at rules Still accept/reject correctly

Blackbox Tests

AC Ref Initial Data/Conditions What to Test Expected Behavior NFR References
AC-2 Valid JPEG + metadata with capturedAt: "2026-06-26T12:00:00" (no offset) POST /api/satellite/upload HTTP 400 mentioning capturedAt
AC-3 Valid JPEG + metadata with capturedAt as DateTime.UtcNow.ToString("o") POST /api/satellite/upload HTTP 200 (happy path unchanged) Compatibility

Constraints

  • Must remain a child of epic AZ-795 strict-validation theme
  • No breaking wire change for offset-aware clients

Risks & Mitigation

Risk 1: Client sends offset-less timestamps

  • Risk: Legitimate clients using "2026-06-26T12:00:00" without Z start failing
  • Mitigation: Contract patch documents requirement; rejection is intentional per F-AZ810-2

Contract

This task patches the producer contract at _docs/02_document/contracts/api/uav-tile-upload.md (1.2.0 → 1.2.1).

Consumers: gps-denied-onboard, mission planner UI, any UAV upload client.

Document Dependencies

  • _docs/02_document/contracts/api/uav-tile-upload.md v1.2.0 (patch to 1.2.1)
  • _docs/02_document/contracts/api/error-shape.md v1.0.0 (unchanged)