[AZ-263] Bootstrap: repo skeleton + Docker + CI + Alembic + Tier-1 tests

Implements the AZ-263 / E-BOOT initial structure task:

- Python src/-layout package `gps_denied_onboard/` with per-component
  interface stubs (14 components), type-only DTOs under `_types/`,
  shared helpers under `helpers/` (R14 LightGlue ownership), structured
  JSON logging, runtime composition root with env-var fail-fast gate,
  healthcheck module shared by Docker and CI smoke.
- CMake top-level + `cmake/{build_options,dependencies,strategies}.cmake`
  with the BUILD_* per-binary flags (ADR-002) and pinned external git
  refs for OKVIS2 / VINS-Mono / GTSAM / FAISS / OpenCV >=4.12.0.
- Three Dockerfiles (companion-tier1, operator-tooling,
  mock-suite-sat-service) + two compose files (dev + Tier-1 test).
- Four GitHub Actions workflows: ci.yml (lint/unit/integration/dual
  binary build/SBOM diff/security), ci-tier2.yml (self-hosted Jetson
  AC-bound NFTs), release.yml, cve-rescan.yml.
- Two CI gate scripts: `ci/sbom_diff.py` (deployment SBOM subset +
  R02 exclusion), `ci/opencv_pin_gate.py` (>=4.12.0 enforcement,
  D-CROSS-CVE-1).
- Alembic-driven Postgres 16 initial migration `0001_initial.py`
  mirroring satellite-provider tiles + flights + sector_classifications
  + manifests + engine_cache_entries (data_model.md s 2).
- Tier-1 test scaffolding: 95 passing unit tests covering every AC,
  per-component smoke tests, structured logging JSON output check,
  env-var gate check, healthcheck import check. Two CI-gated tests
  (cmake configure, actionlint) skip locally with explicit reasons.
- Batch report + code review report under `_docs/03_implementation/`.

Verdict: PASS_WITH_WARNINGS (two Low findings, both informational).
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 01:00:28 +03:00
parent 880eabcb3f
commit b12db61444
168 changed files with 3688 additions and 3 deletions
@@ -0,0 +1,9 @@
"""Structured JSON logging entrypoint (E-CC-LOG / AZ-245).
Bootstrap (AZ-263) ships a working `get_logger` so every other module can import it;
the concrete sink + redaction policy is layered on by AZ-266.
"""
from gps_denied_onboard.logging.structured import get_logger
__all__ = ["get_logger"]
@@ -0,0 +1,83 @@
"""Structured JSON logging.
E-CC-LOG / AZ-245 contract: one JSON object per log line. Bootstrap provides a
minimal working `get_logger(name)` so every other module can import it; AZ-266
will add full redaction and the FDR sink.
"""
from __future__ import annotations
import json
import logging
import os
import sys
import time
from typing import Any
class _JsonFormatter(logging.Formatter):
"""Emit a single JSON object per log line — no narrative log lines (E-CC-LOG)."""
def format(self, record: logging.LogRecord) -> str:
payload: dict[str, Any] = {
"ts": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(record.created))
+ f".{int(record.msecs):03d}Z",
"level": record.levelname,
"logger": record.name,
"msg": record.getMessage(),
}
if record.exc_info:
payload["exc"] = self.formatException(record.exc_info)
for key, value in record.__dict__.items():
if key in (
"args",
"msg",
"levelname",
"name",
"exc_info",
"exc_text",
"stack_info",
"created",
"msecs",
"relativeCreated",
"thread",
"threadName",
"processName",
"process",
"module",
"funcName",
"filename",
"pathname",
"lineno",
"levelno",
):
continue
payload.setdefault(key, value)
return json.dumps(payload, separators=(",", ":"), default=str)
_CONFIGURED = False
def _configure_root_once() -> None:
global _CONFIGURED
if _CONFIGURED:
return
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(_JsonFormatter())
root = logging.getLogger()
root.handlers.clear()
root.addHandler(handler)
level_name = os.getenv("LOG_LEVEL", "INFO").upper()
root.setLevel(getattr(logging, level_name, logging.INFO))
_CONFIGURED = True
def get_logger(name: str) -> logging.Logger:
"""Return a structured JSON logger.
Every component imports its logger via
`from gps_denied_onboard.logging import get_logger`.
"""
_configure_root_once()
return logging.getLogger(name)