{ "adr_refs": [ "adr-037", "adr-038", "adr-039" ], "description": "First-time full platform bootstrap. Builds buildkit-runner golden image off-platform, deploys libre-wuji with temporary bootstrap zot, migrates images to wuji S3-backed zot, deploys libre-daoshi (CI/build cluster), deploys ops-vm (signing), and bootstraps Radicle governance repos. Run exactly once per platform instantiation.", "emit_audit": true, "id": "bootstrap_initial", "name": "Initial Bootstrap", "params": [ { "default_val": "libre-wuji", "description": "Primary workspace (must be libre-wuji)", "name": "workspace", "required": true }, { "default_val": "", "description": "hcloud context name", "name": "hetzner_context", "required": true }, { "default_val": "", "description": "DigitalOcean context (for ops-vm)", "name": "do_context", "required": true }, { "default_val": "", "description": "Temporary OCI registry for image bootstrap", "name": "bootstrap_zot_url", "required": true }, { "default_val": "libre-wuji-zot", "description": "S3 bucket for wuji zot", "name": "s3_bucket", "required": true }, { "default_val": "", "description": "ops-vm SSH host (once provisioned)", "name": "ops_vm_host", "required": false }, { "default_val": "", "description": "Path to ops-controller Ed25519 private key PEM", "name": "ops_controller_key", "required": true }, { "default_val": "", "description": "Path to keeper Ed25519 private key PEM", "name": "keeper_key", "required": true }, { "default_val": "", "description": "Radicle DID of first governance delegate", "name": "initial_delegate_did", "required": true }, { "default_val": "false", "description": "Skip golden image build if already pushed", "name": "skip_golden_image", "required": false } ], "preconditions": [ "Hetzner Cloud API token available and project created", "DigitalOcean API token available for ops-vm", "S3 bucket for zot (libre-wuji-zot) exists with versioning enabled", "NATS account server configured and account JWTs available", "Domain DNS delegated (for ingress on wuji/daoshi)", "SOPS age key generated and accessible", "Radicle identity (rad auth) initialized for bootstrapping operator", "Bootstrap zot: local registry or any reachable OCI registry for initial image push", "Ed25519 key pair generated for initial ops-controller, keeper, and radicle delegate" ], "rollback_strategy": "manual", "steps": [ { "depends_on": [], "dry_run_arg": "--dry-run", "id": "verify_prerequisites", "name": "Verify all bootstrap prerequisites", "on_error": "Stop", "params": {}, "script": "steps/verify_prerequisites.nu" }, { "depends_on": [ "verify_prerequisites" ], "dry_run_arg": "--dry-run", "id": "build_golden_image", "name": "Build buildkit-runner golden image off-platform", "on_error": "Stop", "params": {}, "script": "steps/build_golden_image.nu" }, { "depends_on": [ "build_golden_image" ], "dry_run_arg": "--dry-run", "id": "push_to_bootstrap_zot", "name": "Push golden image to bootstrap registry", "on_error": "Stop", "params": {}, "script": "steps/push_to_bootstrap_zot.nu" }, { "depends_on": [ "push_to_bootstrap_zot" ], "dry_run_arg": "--dry-run", "id": "deploy_libre_wuji", "name": "Deploy libre-wuji cluster (using bootstrap zot)", "on_error": "Stop", "params": {}, "script": "steps/deploy_libre_wuji.nu" }, { "depends_on": [ "deploy_libre_wuji" ], "dry_run_arg": "--dry-run", "id": "verify_wuji_zot_live", "name": "Wait for wuji S3-backed zot to be healthy", "on_error": "Stop", "params": {}, "script": "steps/verify_wuji_zot_live.nu" }, { "depends_on": [ "verify_wuji_zot_live" ], "dry_run_arg": "--dry-run", "id": "migrate_to_wuji_zot", "name": "Migrate images from bootstrap registry to wuji zot", "on_error": "Stop", "params": {}, "script": "steps/migrate_to_wuji_zot.nu" }, { "depends_on": [ "verify_wuji_zot_live" ], "dry_run_arg": "--dry-run", "id": "bootstrap_radicle_governance", "name": "Create initial Radicle governance repos and set delegation", "on_error": "Stop", "params": {}, "script": "steps/bootstrap_radicle_governance.nu" }, { "depends_on": [ "migrate_to_wuji_zot", "bootstrap_radicle_governance" ], "dry_run_arg": "--dry-run", "id": "deploy_libre_daoshi", "name": "Deploy libre-daoshi CI/build cluster", "on_error": "Continue", "params": {}, "script": "steps/deploy_libre_daoshi.nu" }, { "depends_on": [ "bootstrap_radicle_governance" ], "dry_run_arg": "--dry-run", "id": "deploy_ops_vm", "name": "Deploy ops-vm on DigitalOcean (signing isolation)", "on_error": "Continue", "params": {}, "script": "steps/deploy_ops_vm.nu" }, { "depends_on": [ "deploy_libre_daoshi", "deploy_ops_vm" ], "dry_run_arg": "--dry-run", "id": "verify_end_to_end", "name": "Run end-to-end ops pipeline smoke test", "on_error": "Continue", "params": {}, "script": "steps/verify_end_to_end.nu" }, { "depends_on": [ "verify_end_to_end" ], "dry_run_arg": "--dry-run", "id": "emit_audit", "name": "Emit bootstrap-complete audit event", "on_error": "Continue", "params": { "event_type": "bootstrap_complete" }, "script": "steps/emit_audit.nu" } ], "success_criteria": [ "libre-wuji cluster running with all components healthy (zot, ops-controller, radicle-seed, observability)", "zot serving images from S3 bucket — bootstrap registry no longer needed", "Radicle repos created: policy-libre-wuji, desired-libre-wuji, state-libre-wuji, policy-libre-daoshi, desired-libre-daoshi, state-libre-daoshi", "Initial delegation set (M=1 threshold) written to all policy repos", "libre-daoshi cluster running with forgejo, woodpecker, postgresql, radicle-seed", "ops-vm running on DigitalOcean AMS3 with keeper-daemon and radicle-seed", "End-to-end: test op submitted via NATS → signed by keeper → applied → audit event in SurrealDB", "ops history shows bootstrap-complete audit event" ], "version": 1 }