Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tasks: provisioning-api-service

Feature Spec And Setup

  • Create feature branch and worktree
  • Draft and review design.md
  • Reframe feature from provision-restructure to provisioning-api-service
  • Create scripts/atomixos_provision/pyproject.toml with deps and metadata
  • Update the design to use Litestar instead of the original Starlette direction
  • Compare against Litestar fullstack reference and record applicable patterns

Package Structure

  • Create src/atomixos_provision/ package with __init__.py
  • Create module files: app, auth, config, config_builder, quadlet, quadlet_sync, activation, jobs, provision, bundle, ui, server
  • Create tests/ directory with conftest.py

Config Parsing And Generation

  • Move config.toml parsing and schema validation to config.py
  • Preserve tomllib usage and validation rules
  • Keep config generation logic in config_builder.py for tests/future use; no /generate route is exposed
  • Add tests covering config parsing and config generation behavior

Authentication

  • Move SSH signature verification logic to auth.py
  • Implement nonce issuance, TTL, and single-use consumption
  • Implement Litestar guards with first-boot bypass
  • Preserve ssh-keygen -Y verify subprocess verification
  • Require SSH auth after provisioning for /api/config and /api/validate
  • Keep job polling authorized by unguessable job UUID only
  • Add tests covering valid signatures, invalid signatures, expired nonces, replay, and unprovisioned bypass

Quadlet Rendering And Sync

  • Move container, network, volume, and build rendering to quadlet.py
  • Move quadlet-runtime.json tracking logic
  • Move rendered-unit copy logic to quadlet_sync.py
  • Add tests covering rendering and sync behavior

Bundle Import

  • Move tar.gz/tar.zst extraction and file placement to bundle.py
  • Preserve ${CONFIG_DIR} and ${FILES_DIR} token substitution behavior
  • Add tests covering bundle import behavior

Activation And Rollback

  • Move activation script execution to activation.py
  • Move rootful and rootless service health checks to activation.py
  • Move candidate, active, and rollback config swap handling to activation.py
  • Add F2FS-safe parent-directory fsync during promotion
  • Add tests covering activation and rollback behavior

Async Job API

  • Create jobs.py with single-flight job execution
  • Define job states: SUBMITTED, RUNNING, SUCCEEDED, FAILED
  • Track rollback status in failed jobs
  • Implement mutual exclusion for concurrent submissions
  • Bound retained job history to avoid unbounded memory growth
  • Add tests for concurrent submission, state transitions, and cleanup

Litestar HTTP Application

  • Create app.py with Litestar app factory
  • Wire API routes: GET /api/nonce, POST /api/config, GET /api/jobs/{id}, GET /api/health, POST /api/validate
  • Integrate SSH auth guards with first-boot bypass
  • Integrate job manager for POST /api/config

Boot UI Routes

  • Create ui.py with HTML form endpoints
  • GET / — serve Boot UI HTML
  • GET /assets/atomixos.png — serve static logo
  • POST /apply — multipart form to sync provision to HTML result
  • Do not expose /generate; first-boot UI only uploads or pastes a prepared config
  • Escape user-controlled HTML output

Server Entry Point

  • Create server.py with click-based CLI
  • Implement commands: serve, validate, import, recover, sync-quadlet
  • Implement sd_listen_fds socket inheritance from systemd
  • Preserve systemd unit compatibility

Nix Integration

  • Update modules/first-boot.nix to reference the new Python package
  • Build Python environment with Litestar, uvicorn, and the new package
  • Bind first-boot socket to 0.0.0.0:8080, then rebind to provisioned LAN IP
  • Preserve PATH dependencies (openssh, gzip, zstd, systemd, util-linux)
  • Update nix/tests/first-boot-provision.nix for the new package
  • Update nix/tests/first-boot-source-discovery.nix for the new package

Cleanup And Close

  • Move provisioning implementation into scripts/atomixos_provision/ while preserving the first-boot-provision command interface
  • Update docs and reference pages for the new package layout
  • Update docs/src/planned-features.md to mark feature complete
  • Add boot-ui-htmx to planned-features.md as a follow-up feature
  • Run full Nix build and VM tests on aarch64-linux builder

Service Foundation Follow-Up

  • Add settings.py with a small environment-backed AppSettings object
  • Add deps.py with Litestar dependency providers for settings and service facades
  • Add exceptions.py for consistent domain-error to HTTP-response mapping
  • Add typed schemas for nonce, validation, submit-config, job, job event, and provision result responses
  • Convert job response serialization to use the typed schemas
  • Split /api/health into a domain/system/controller.py
  • Split /api/nonce into a domain/auth/controller.py
  • Split /api/jobs/{id} into a domain/jobs/controller.py
  • Split /api/config and /api/validate into a domain/config/controller.py
  • Add a ConfigService facade for apply and validate operations
  • Keep create_app() route wiring explicit; do not add domain auto-discovery yet
  • Add OpenAPI operation IDs, summaries, tags, and typed response metadata for API routes
  • Add docs updates for docs/src/provisioning.md, docs/src/data-flow.md, docs/src/runtime-boundaries.md, docs/src/reference/project-structure.md, docs/src/code-reference/scripts.md, and docs/src/testing.md when service API behavior changes
  • Keep Boot UI routes in ui.py until the boot-ui-htmx follow-up splits server-rendered partials

Future Dynamic API Direction

  • Design GET /api/config/current to return normalized current desired state
  • Design GET /api/config/export to export a backup/clone config bundle
  • Design typed user partial updates such as PATCH /api/config/users/{name}
  • Design typed network partial updates such as PATCH /api/config/network
  • Design typed container partial updates such as PATCH /api/config/containers/{name}
  • Ensure every partial update loads current desired state, applies a typed patch, validates full desired state, renders candidate state, promotes atomically, activates, reports job progress, and rolls back on failure
  • Do not allow partial API paths to directly mutate derived files or runtime systemd/Quadlet state
  • Define normalized desired-state import and export bookends before implementing partial mutation APIs
  • Add import/export round-trip tests so API-managed state can always be backed up or cloned as a config bundle
  • Add drift detection/reporting expectations for rendered files under /data/config/

Validation And Readiness

  • Run uv run --extra dev pytest for the provisioning package
  • Run uv run --extra dev ruff check . for the provisioning package
  • Run Nix parse checks for touched modules and VM tests
  • Run the relevant NixOS VM tests after controller/service refactors
  • Verify rootfs closure remains within the 1 GB squashfs budget after dependency changes
  • Search docs for stale synchronous /api/config response descriptions after API changes
  • T999: Reconcile final implementation, feature specs, and docs before close-out

Explicitly Deferred

  • Do not add SQLAlchemy, a database, or repository abstractions without a persistent data model that cannot be represented by config state
  • Do not add Redis/SAQ unless jobs must survive service restarts or run independently of the provisioning process
  • Do not add OAuth/JWT auth unless SSH-signature administration stops meeting operator needs
  • Do not add Vite/SPA integration for the bootstrap UI; prefer server-rendered/HTMX follow-up work