diff --git a/.agents/skills/dmf-platform-umbrella-conventions/SKILL.md b/.agents/skills/dmf-platform-umbrella-conventions/SKILL.md index 0b0cdee..92286e0 100644 --- a/.agents/skills/dmf-platform-umbrella-conventions/SKILL.md +++ b/.agents/skills/dmf-platform-umbrella-conventions/SKILL.md @@ -1,15 +1,15 @@ --- name: dmf-platform-umbrella-conventions -description: DMF Platform umbrella workspace conventions, boot ritual, and cross-repo state rules +description: dmfdeploy platform umbrella workspace conventions, boot ritual, and cross-repo state rules source: auto-skill extracted_at: '2026-06-10T13:00:00.000Z' --- -# DMF Platform Umbrella Conventions +# dmfdeploy platform Umbrella Conventions ## Context -This repo (`dmf-init`) is a component of the **DMF Platform**, an umbrella workspace with multiple component repos checked out alongside it. Operators set `$DMFDEPLOY_UMBRELLA` to its local path. +This repo (`dmf-init`) is a component of the **dmfdeploy platform**, an umbrella workspace with multiple component repos checked out alongside it. Operators set `$DMFDEPLOY_UMBRELLA` to its local path. ## Before any non-trivial change @@ -23,7 +23,7 @@ Then read in order: 1. `dmfdeploy/STATUS.md` — what's happening across all repos right now 2. `dmfdeploy/QWEN.md` — full boot ritual + skills index + Qwen-specific rules 3. `dmfdeploy/docs/decisions/INDEX.md` — ADRs applicable to your task -4. The most recent file under `dmfdeploy/docs/handoffs/` +4. The comments on your tracking issue (the old [handoff notes](https://github.com/dmfdeploy/dmfdeploy/tree/22f351cd1cf4b16a391a013861015666b065e55c/docs/handoffs) were removed from the umbrella tree) ## Cross-repo state diff --git a/.githooks/pre-commit b/.githooks/pre-commit index ac7976f..c278b59 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,7 +1,7 @@ #!/usr/bin/env bash # .githooks/pre-commit — secret scan via gitleaks. # -# Mirrors the umbrella DMF Platform pre-commit hook for sub-repos. +# Mirrors the umbrella dmfdeploy platform pre-commit hook for sub-repos. # Refuses any commit whose staged changes match a gitleaks rule from # the .gitleaks.toml at the repo root. # diff --git a/.gitignore b/.gitignore index 4590dae..68c5a56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# === DMF Platform .gitignore === +# === dmfdeploy platform .gitignore === # Repo-specific rules go above the baseline block at the bottom. # Python (FastAPI backend) @@ -55,8 +55,8 @@ __MACOSX/ *.swo *~ -# === Secrets-prevention baseline (DMF Platform 2026-05-07) === -# Patterns that should never be committed across any DMF Platform repo. +# === Secrets-prevention baseline (dmfdeploy platform 2026-05-07) === +# Patterns that should never be committed across any dmfdeploy platform repo. # Repo-specific rules belong above this block; add new shared rules here. # Kubeconfigs diff --git a/.gitleaks.toml b/.gitleaks.toml index 40ab869..b31af8b 100644 --- a/.gitleaks.toml +++ b/.gitleaks.toml @@ -1,4 +1,4 @@ -# DMF Platform — sub-repo gitleaks config +# dmfdeploy platform — sub-repo gitleaks config # # Mirrors the public-safe subset of the umbrella's .gitleaks.toml so each # public repo's local pre-commit catches the same leak categories: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b97ddc4..6495e9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,16 +2,13 @@ The Day-0 stateless init/bootstrap container (React + FastAPI) that wraps the dmf-env wizard + toolchain behind a localhost web UI. -This repo is part of the **DMF Platform**. GitHub is the canonical home and the +This repo is part of the **dmfdeploy platform**. GitHub is the canonical home and the single source of truth: all changes land via **Pull Request** against `main`. -(The full pre-publish history lives in a LAN-only `dmf-init-archive` Forgejo -repo, reachable as a read-only `archive` git remote — it is **not** an upstream -and is never a contribution path.) ## Quick start 1. Read the platform overview in the [dmfdeploy/dmfdeploy](https://github.com/dmfdeploy/dmfdeploy) umbrella repo - (`docs/architecture/DMF Platform Plan.md`) and apply any relevant ADRs from + (`docs/architecture/dmfdeploy-platform-plan.md`) and apply any relevant ADRs from `docs/decisions/INDEX.md`. 2. Fork or branch, make your change on a topic branch, open a PR against `main`. 3. Ensure CI is green and your commits are **signed off** (see DCO below). diff --git a/LICENSE b/LICENSE index 90c70d3..6878f97 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2026 DMF Platform contributors + Copyright 2026 dmfdeploy platform contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE b/NOTICE index 4a0e35a..1e0d66f 100644 --- a/NOTICE +++ b/NOTICE @@ -1,8 +1,8 @@ -DMF Platform — dmf-init (Day-0 stateless init/bootstrap container) -Copyright 2026 DMF Platform contributors +dmfdeploy platform — dmf-init (Day-0 stateless init/bootstrap container) +Copyright 2026 dmfdeploy platform contributors Licensed under the Apache License, Version 2.0 (see LICENSE). -This product packages, but does not vendor, the DMF Platform env tooling +This product packages, but does not vendor, the dmfdeploy platform env tooling (dmf-env), generic playbooks/roles (dmf-infra), and AWX launcher runbooks (dmf-runbooks). Those are pulled at image-build time from their own repositories; each is governed by its own LICENSE. The container image diff --git a/README.md b/README.md index 9aee0be..39808f9 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,18 @@ [![CI](https://github.com/dmfdeploy/dmf-init/actions/workflows/ci.yml/badge.svg)](https://github.com/dmfdeploy/dmf-init/actions/workflows/ci.yml) -**Day-0 self-contained init & bootstrap container** for the DMF Platform. +**Day-0 installer container** that commissions a dmfdeploy platform cluster on a node you bring, through a localhost-only web UI. + +Part of [dmfdeploy](https://github.com/dmfdeploy/dmfdeploy), an independent open prototype that explores the ideas of the EBU Dynamic Media Facility on commodity infrastructure. Status: prototype, single-node sandbox. > **New to the project vocabulary?** See the [DMF Glossary](https://github.com/dmfdeploy/dmfdeploy/blob/main/docs/GLOSSARY.md) for project-coined terms (appliance, checkpoint, age key, answers-file, …). -A single container that puts a friendly, localhost-only web UI on the existing -[`dmf-env`](https://github.com/dmfdeploy/dmf-env) env-creation + `bin/` -bootstrap toolchain, drives a cluster from zero to verified, and offers a -**passphrase-wrapped backup as a browser download** at each checkpoint — so the -operator can commission a cluster, save the backup wherever they choose, and -then delete the container with nothing left behind. +A single container puts a friendly, localhost-only web UI on the existing +[`dmf-env`](https://github.com/dmfdeploy/dmf-env) env-creation and `bin/` +bootstrap toolchain. It drives a cluster from zero to verified. At each +checkpoint it offers a **passphrase-wrapped backup as a browser download**. You +can commission a cluster, save the backup wherever you choose, and then delete +the container with nothing left behind. Reached as `http://localhost`, which is a browser **secure context** (clipboard + WebAuthn work) with no certificate warning; HTTPS is opt-in for non-localhost access. @@ -23,7 +25,7 @@ what it does and does not show, is on the > **What you get (the deliverable):** a **commissioned, verified cluster** plus > one or more **passphrase-wrapped encrypted backups** (browser downloads). The -> container is **disposable / run-once** — delete it when you're done and the +> container is **disposable / run-once**; delete it when you're done and the > backups + your passphrase are all that remain. It does **not** build or emit a > deployable image; it *commissions a cluster*. @@ -34,12 +36,12 @@ Architecture orientation: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). | Mode | Purpose | |---|---| | **Create new** | Collect inputs, render the env bundle, seal a downloadable passphrase-wrapped backup (checkpoint #1), then orchestrate the full sandbox bootstrap (pre-seed → seed → post-seed → configure → verify) with live logs and per-checkpoint downloads. | -| **Manage** | Restore an env by uploading a previously downloaded encrypted backup (passphrase-unwrapped), then re-run playbooks, upgrade, rotate, or tear down — offering a fresh downloadable backup on any change. | +| **Manage** | Restore an env by uploading a previously downloaded encrypted backup (passphrase-unwrapped), then re-run playbooks, upgrade, rotate, or tear down, offering a fresh downloadable backup on any change. | ## Design principles - **Stateless.** All env state lives in a tmpfs scratch root; nothing durable is - written to the host. After commissioning, the downloaded encrypted backup(s) + + written to the host. After commissioning, the downloaded encrypted backups and the operator passphrase are the only artifacts that matter. - **Passphrase wraps the age key.** The age private key rides inside the backup; the backup is encrypted by an operator passphrase (the single human-held @@ -54,22 +56,25 @@ Architecture orientation: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). ### Quick start (launcher) -If you just want to get going, the `dmf-init` launcher wraps Docker for you — it +To get started, the `dmf-init` launcher wraps Docker for you; it starts the container with the correct flags, waits until it's ready, extracts the one-time launch link, and opens your browser. No clone required: +Read the launcher before you run it. Download it, read it, then run it: + ```bash -curl -fsSL https://raw.githubusercontent.com/dmfdeploy/dmf-init/main/bin/dmf-init | bash -s -- up +curl -fsSL https://raw.githubusercontent.com/dmfdeploy/dmf-init/main/bin/dmf-init -o dmf-init +less dmf-init +bash dmf-init up ``` -> Piping a script into your shell runs remote code — if you'd rather read it -> first (recommended), download then run: -> ```bash -> curl -fsSL https://raw.githubusercontent.com/dmfdeploy/dmf-init/main/bin/dmf-init -o dmf-init -> less dmf-init && bash dmf-init up -> ``` +If you trust the source, you can pipe the launcher into your shell instead. This runs remote code without a chance to read it first: + +```bash +curl -fsSL https://raw.githubusercontent.com/dmfdeploy/dmf-init/main/bin/dmf-init | bash -s -- up +``` -From a clone, it's just `bin/dmf-init`: +From a clone, run `bin/dmf-init`: ```bash bin/dmf-init up # start + open the browser (prints the link too) @@ -80,13 +85,13 @@ bin/dmf-init down # stop and remove the container Options for `up`: `--port N` (default 8000), `--tls` (HTTPS), `--image REF`, `--repo-base-url URL` (private mirror). Run `bin/dmf-init --help` for details. The -launcher never weakens the security posture — it always publishes on `127.0.0.1` +launcher never weakens the security posture; it always publishes on `127.0.0.1` only and mounts the tmpfs data root. The explicit `docker run` invocations below remain the advanced/reference path (and are what the launcher runs under the hood). ### Prerequisites -A **BuildKit-capable Docker** is mandatory — the `Dockerfile` pins +A **BuildKit-capable Docker** is mandatory; the `Dockerfile` pins `# syntax=docker/dockerfile:1.7` and `bin/build-bundle.sh` forces `DOCKER_BUILDKIT=1`, so classic builders will fail. **Docker 23.0+** is a sensible minimum. @@ -101,7 +106,7 @@ Pick based on whether the host has **runtime network access**: | **Image** | `ghcr.io/dmfdeploy/dmf-init:latest` | `dmf-init:bundle` | | **Repos** | Fetched at startup | Baked into the tarball | -**Networked** (canonical ghcr image — simplest path): +**Networked** (canonical ghcr image: simplest path): ```bash docker run --rm -p 127.0.0.1:8000:8000 \ @@ -120,7 +125,7 @@ docker run --rm -p 127.0.0.1:8000:8000 \ > `-e DMF_ALLOW_NON_TMPFS_DATA_ROOT=true` (dev/test only). `docker rm` stays > safe because nothing durable is written to host disk. -Repos are fetched from the public org `https://github.com/dmfdeploy` by default — +Repos are fetched from the public org `https://github.com/dmfdeploy` by default; no extra env needed. To pull from a private mirror, override the base URL (and optionally supply credentials): @@ -134,7 +139,7 @@ docker run --rm -p 127.0.0.1:8000:8000 \ Multi-arch (amd64 + arm64), published by [`.github/workflows/publish-image.yml`](.github/workflows/publish-image.yml). -**Air-gapped** (bundle — repos baked in via `bin/build-bundle.sh`): +**Air-gapped** (bundle: repos baked in via `bin/build-bundle.sh`): ```bash # on a machine with Docker + the umbrella checked out: @@ -152,7 +157,7 @@ it by a non-localhost address. **Lost your session / launch link?** The session refreshes while you're active and lasts well beyond a single run idle, but if it lapses (or you closed the tab) -the one-time launch link is spent. You don't need to restart — re-mint a fresh +the one-time launch link is spent. You don't need to restart; re-mint a fresh link on the *running* container (preserving the in-progress run) by sending it `SIGHUP`, then open the new link printed in the logs: @@ -166,18 +171,22 @@ Canonical spec: ### Target node -The installer provisions a **node you bring** — an SSH-reachable **Debian 12 or -13, ARM64** host (a cloud VM, a spare box, a Raspberry Pi). Other distros and -architectures are untested for now. Your own workstation OS doesn't matter; the -installer runs in a browser. On the wizard's *Target node* step you supply: - -- **Node IP** — an address reachable *from this installer container*. Not - `localhost` / `127.0.0.1`: that resolves to the container itself, not your node. -- **Ansible user** — the SSH login on that node (`root`, or the image's default +The installer provisions a **node you bring**: an SSH-reachable **Debian, ARM64** +host (a cloud VM, a spare box, a Raspberry Pi). The installer does not check the +Debian version itself. The running v0.1 sandbox is a Debian 13 (Trixie) ARM64 +node with 4 vCPU, 16 GB RAM and a 60 GB disk, and the full stack uses about 7 GB +RAM and 30 GB disk at idle. Treat that as the minimum. The +[`dmf-infra`](https://github.com/dmfdeploy/dmf-infra) baseline playbook also +handles Debian 12 (Bookworm). Other distros and architectures are untested for +now. Your own workstation OS doesn't matter; the installer runs in a browser. On the wizard's *Target node* step you supply: + +- **Node IP**: an address reachable *from this installer container*. Do not use + `localhost` or `127.0.0.1`, which resolve to the container itself. +- **Ansible user**: the SSH login on that node (`root`, or the image's default user such as `debian`). -- **Interface** — the node's primary network interface (`eth0`, `ens3`, …). +- **Interface**: the node's primary network interface (`eth0`, `ens3`, …). -These fields are intentionally blank by default — fill them for *your* node. +These fields are intentionally blank by default; fill them for *your* node. > **macOS convenience (not the paved path):** `dmf-env/bin/recreate-sandbox-vm.sh` > spins up a local Lima VM (whose user / interface are `lima` / `lima0`). It @@ -186,11 +195,15 @@ These fields are intentionally blank by default — fill them for *your* node. ## Dependencies -- [`dmf-env`](https://github.com/dmfdeploy/dmf-env) — env tooling (`init-wizard.sh`, `bin/` scripts) the container wraps. -- [`dmf-infra`](https://github.com/dmfdeploy/dmf-infra) — generic bootstrap playbooks/roles. -- [`dmf-runbooks`](https://github.com/dmfdeploy/dmf-runbooks) — catalog launcher (post-seed). +- [`dmf-env`](https://github.com/dmfdeploy/dmf-env): env tooling (`init-wizard.sh`, `bin/` scripts) the container wraps. +- [`dmf-infra`](https://github.com/dmfdeploy/dmf-infra): generic bootstrap playbooks/roles. +- [`dmf-runbooks`](https://github.com/dmfdeploy/dmf-runbooks): catalog launcher (post-seed). + +## For contributors + +`AGENTS.md`, `CLAUDE.md` and `QWEN.md` hold instructions for AI coding agents that help maintain this repository. Human contributors can skip them and start with [CONTRIBUTING.md](CONTRIBUTING.md). ## License -Apache License, Version 2.0 — see [LICENSE](LICENSE). +Apache License, Version 2.0. See [LICENSE](LICENSE). Third-party components are listed in [NOTICE](NOTICE).