diff --git a/pyproject.toml b/pyproject.toml index 2c48723..21c68aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,9 +37,9 @@ dev = ["ruff>=0.8.0", "ty>=0.0.1a1"] [project.scripts] seismic-deploy = "deploy_gcp.seismic_deploy.cli:cli" # Operator-facing: act on your own node. Cloud-agnostic, never wraps Pulumi. -seismic-tee = "tee.cli.node.app:app" +seismic-tee-node = "tee.cli.node.app:app" # Seismic-internal: bootstrap a network (provision cohort + genesis ceremony). -seismic-tee-bootstrap = "tee.cli.network.app:app" +seismic-tee-network = "tee.cli.network.app:app" [tool.setuptools.packages.find] include = ["deploy_gcp*", "tee*"] diff --git a/tee/README.md b/tee/README.md index 7cf2a45..587e1c3 100644 --- a/tee/README.md +++ b/tee/README.md @@ -9,8 +9,8 @@ service starts. This README is intentionally architectural. By the end you should understand the layering and the two CLIs split by audience — -`seismic-tee` (operator-facing: act on your own node) and -`seismic-tee-bootstrap` (Seismic-internal: found a network — provision a +`seismic-tee-node` (operator-facing: act on your own node) and +`seismic-tee-network` (Seismic-internal: found a network — provision a cohort and run the genesis ceremony) — what each does vs. what the operator does, and what's still pending cleanup. @@ -19,7 +19,7 @@ operator does, and what's still pending cleanup. A "Seismic TEE node" is a TDX-confidential VM running a [seismic-images](https://github.com/SeismicSystems/seismic-images) mkosi image. On first boot, the VM runs a small HTTP service `tdx-init` that's waiting on port `:8080` -for its [InitConfig](https://github.com/SeismicSystems/enclave/blob/seismic/crates/tdx-init/src/config.rs#L8). Attesting the VM and POSTing that config is the job of the `seismic-tee configure` command. +for its [InitConfig](https://github.com/SeismicSystems/enclave/blob/seismic/crates/tdx-init/src/config.rs#L8). Attesting the VM and POSTing that config is the job of the `seismic-tee-node configure` command. ## Prerequisites @@ -29,10 +29,10 @@ for its [InitConfig](https://github.com/SeismicSystems/enclave/blob/seismic/crat never provisions; it consumes a descriptor of an already-running node. VHD upload to the Azure image registry is a seismic-images concern (`make push-azure-*`), not this tool. -- **For `seismic-tee-bootstrap genesis-ceremony`:** the `genesis` binary (built from +- **For `seismic-tee-network genesis-ceremony`:** the `genesis` binary (built from summit) on PATH. (The summit genesis template defaults to the artifact-set copy beside `--manifest`.) -- **For `seismic-tee-bootstrap up`** (cohort provisioning): the `pulumi` +- **For `seismic-tee-network up`** (cohort provisioning): the `pulumi` CLI on PATH. The passphrase secrets provider needs `PULUMI_CONFIG_PASSPHRASE` — set it, or let `up`/`down` prompt you on first run (empty = no passphrase). Required as an env var only in @@ -50,8 +50,8 @@ uv sync The two CLIs are then available: ```bash -uv run seismic-tee --help # operator-facing -uv run seismic-tee-bootstrap --help # Seismic-internal +uv run seismic-tee-node --help # operator-facing +uv run seismic-tee-network --help # Seismic-internal ``` ## How it's organized: two CLIs, by audience @@ -59,21 +59,21 @@ uv run seismic-tee-bootstrap --help # Seismic-internal The split is "act on my own node" vs "bring a whole network into existence." Only the first is ever external, so it's its own CLI; the second is Seismic-internal. The boundary between them is the **node -descriptor** file: `seismic-tee-bootstrap` *produces* descriptors (by -provisioning) and *consumes* them (genesis ceremony), while `seismic-tee` +descriptor** file: `seismic-tee-network` *produces* descriptors (by +provisioning) and *consumes* them (genesis ceremony), while `seismic-tee-node` only consumes one to reach an already-running node. | CLI | Command | Run by | Purpose | |---|---|---|---| -| `seismic-tee` | `configure` | any operator, on first boot | POST the node TOML to tdx-init. Reads the node address from `--node `. (Attestation verification is disabled pending attested-tls — see below.) | -| `seismic-tee-bootstrap` | `up` / `down` | Seismic, internal | Provision / tear down a cohort of TDX nodes, one independent Pulumi stack each (drives Pulumi via the Automation API). | -| `seismic-tee-bootstrap` | `genesis-ceremony` | Seismic, once per network | Gather the cohort's summit pubkeys, build `genesis.toml`, POST it to each node. One-shot: `send_genesis` only exists in the pre-genesis node API. | -| `seismic-tee-bootstrap` | `manifest` | Seismic | Assemble / validate the network manifest. | +| `seismic-tee-node` | `configure` | any operator, on first boot | POST the node TOML to tdx-init. Reads the node address from `--node `. (Attestation verification is disabled pending attested-tls — see below.) | +| `seismic-tee-network` | `up` / `down` | Seismic, internal | Provision / tear down a cohort of TDX nodes, one independent Pulumi stack each (drives Pulumi via the Automation API). | +| `seismic-tee-network` | `genesis-ceremony` | Seismic, once per network | Gather the cohort's summit pubkeys, build `genesis.toml`, POST it to each node. One-shot: `send_genesis` only exists in the pre-genesis node API. | +| `seismic-tee-network` | `manifest` | Seismic | Assemble / validate the network manifest. | -Only `seismic-tee` is cloud-agnostic and **never wraps Pulumi**; -`seismic-tee-bootstrap` is the one allowed to. A **node descriptor** is a +Only `seismic-tee-node` is cloud-agnostic and **never wraps Pulumi**; +`seismic-tee-network` is the one allowed to. A **node descriptor** is a small JSON (`public_ip`/`fqdn`) describing one provisioned node — see -`tee/cli/common/descriptor.py`. It's what `seismic-tee-bootstrap up` emits +`tee/cli/common/descriptor.py`. It's what `seismic-tee-network up` emits (just `{public_ip, fqdn}`); a BYO-infra operator can hand-write it (or use `pulumi stack output --json` — only those two keys are read). @@ -89,9 +89,9 @@ front-ends over the same state. Longer-term these two CLIs are intended to live in **two repos**, split on the same audience line: -- **Public (operator):** `seismic-tee` + the `pulumi/seismic_node/` +- **Public (operator):** `seismic-tee-node` + the `pulumi/seismic_node/` program — the primitives for configuring and provisioning *one* node. -- **Private (this repo):** `seismic-tee-bootstrap` + `pulumi/playground/` +- **Private (this repo):** `seismic-tee-network` + `pulumi/playground/` — founding a *network* (orchestrating a cohort, the genesis ceremony), which only Seismic does. @@ -118,7 +118,7 @@ cd pulumi/seismic_node pulumi up --stack my-node && pulumi stack output --json --stack my-node > /tmp/node.json cd - -uv run seismic-tee configure --node /tmp/node.json \ +uv run seismic-tee-node configure --node /tmp/node.json \ --peer http://:7878 --manifest ./network-manifest.json ``` @@ -129,7 +129,7 @@ identity doc you're given for the network you're joining; it pins the `network_id`. The reth genesis JSON is POSTed alongside it (from `--reth-genesis`, defaulting to `reth-genesis.json` beside the manifest — the artifact-set layout); tdx-init writes it for reth's `--chain`. You -never run `seismic-tee-bootstrap` — that's Seismic-internal network +never run `seismic-tee-network` — that's Seismic-internal network creation. ### Creating a new network (genesis ceremony) @@ -156,12 +156,12 @@ template identity that can also found a throwaway test devnet (see # regenerated from the inputs — the directory is everything needed to # (re)configure, join, or debug the network later. assemble needs # `seismic-reth` on PATH for the offline genesis-hash gate. -uv run seismic-tee-bootstrap manifest init tee/networks/devnet-3 \ +uv run seismic-tee-network manifest init tee/networks/devnet-3 \ --reth-genesis ../seismic-reth/crates/seismic/chainspec/res/genesis/dev.json \ --measurements ../seismic-images/build/measurements.json \ --measurement-id seismic_2026-06-11.abc123.vhd # → edit tee/networks/devnet-3/summit-template.toml (namespace, …) -uv run seismic-tee-bootstrap manifest assemble tee/networks/devnet-3 +uv run seismic-tee-network manifest assemble tee/networks/devnet-3 # 2. Provision the cohort — one independent Pulumi stack per node — and # capture each node's descriptor. Shared settings inherit from the dev @@ -175,15 +175,15 @@ uv run seismic-tee-bootstrap manifest assemble tee/networks/devnet-3 # writes the descriptors into /nodes/ (gitignored: infra state, not # identity). Without --network they land in a shared gitignored # descriptors/ dir next to the Pulumi project; --out-dir overrides either. -uv run seismic-tee-bootstrap up --count 2 --network tee/networks/devnet-3 +uv run seismic-tee-network up --count 2 --network tee/networks/devnet-3 # → tee/networks/devnet-3/nodes/dev-bootstrap-node-{1,2}.json # 3. Configure the whole cohort in one command: exactly one genesis node # (mints root_key) plus N joiners pointed at it (each fetches root_key # from node 1 over the attested handshake); every first-boot disk wipe # is watched in parallel. (A node joining the live network later uses -# `seismic-tee configure` instead — see "Joining an existing network".) -uv run seismic-tee-bootstrap configure \ +# `seismic-tee-node configure` instead — see "Joining an existing network".) +uv run seismic-tee-network configure \ --genesis tee/networks/devnet-3/nodes/dev-bootstrap-node-1.json \ --join tee/networks/devnet-3/nodes/dev-bootstrap-node-2.json \ --manifest tee/networks/devnet-3/network-manifest.json @@ -198,7 +198,7 @@ uv run seismic-tee-bootstrap configure \ # to the artifact-set copy beside --manifest (verified against the # manifest's summit.genesis_template_hash); --node defaults to the # descriptors in the nodes/ dir beside it. -uv run seismic-tee-bootstrap genesis-ceremony \ +uv run seismic-tee-network genesis-ceremony \ --manifest tee/networks/devnet-3/network-manifest.json ``` @@ -211,8 +211,8 @@ There is no per-node TOML. The config is assembled from flags + the descriptor, so nothing is copy-pasted per node (and can't drift): - `[enclave]` — `peers` from `--peer` (a `http://host:7878` URL, or a descriptor path that resolves to `http://:7878`). `genesis_node` - is `false` for `seismic-tee configure` (join); it is `true` only for the one - node configured by `seismic-tee-bootstrap configure`. + is `false` for `seismic-tee-node configure` (join); it is `true` only for the one + node configured by `seismic-tee-network configure`. - `[domain]` — `name` from the descriptor's `fqdn` (the cert domain), `email` from `--email` (default `ops@seismic.systems`). - `[network].manifest_base64` — from `--manifest`. @@ -225,7 +225,7 @@ this is the body a joining node POSTs: ```toml [enclave] -genesis_node = false # true only via `seismic-tee-bootstrap configure` +genesis_node = false # true only via `seismic-tee-network configure` peers = ["http://az-1.seismicdev.net:7878"] # from --peer [domain] # injected: descriptor fqdn + --email @@ -266,11 +266,11 @@ only gates against a second POST within the same boot. - **Two root_key-genesis nodes silently split the network.** Each genesis enclave generates a fresh `OsRng` `root_key` locally; downstream nodes that fetch from one cohort can't decrypt state from the other. - `seismic-tee-bootstrap configure` makes this unrepresentable within one + `seismic-tee-network configure` makes this unrepresentable within one invocation (exactly one `--genesis`), but nothing yet stops a second *invocation* against a fresh VM — a durable guard (genesis mode refusing to start against an already-formatted volume or a live peer) is planned - upstream in tdx-init. (The operator `seismic-tee configure` can't + upstream in tdx-init. (The operator `seismic-tee-node configure` can't trigger it: it only joins.) - **The `:8080` listener is unauthenticated, first-POST-wins.** An attacker who reaches port 8080 ahead of the operator can @@ -281,7 +281,7 @@ only gates against a second POST within the same boot. ## Attestation verification (currently disabled) -`seismic-tee configure` does **not** verify the node's TDX attestation +`seismic-tee-node configure` does **not** verify the node's TDX attestation today — it only POSTs the config. The `--measurements` flag is gated off and errors if passed, rather than pretending to verify. diff --git a/tee/cli/common/descriptor.py b/tee/cli/common/descriptor.py index acc337f..5bf4cd5 100644 --- a/tee/cli/common/descriptor.py +++ b/tee/cli/common/descriptor.py @@ -6,12 +6,13 @@ by Pulumi and run standalone) and this CLI: the CLI consumes a descriptor and never shells out to or wraps Pulumi. -`seismic-tee-bootstrap up` emits exactly `{public_ip, fqdn}`. A +`seismic-tee-network up` emits exactly `{public_ip, fqdn}`. A bring-your-own-infra operator (Terraform, manual console, …) can hand-write the same shape — `pulumi stack output --json` works too, since only `public_ip`/`fqdn` are read and any extra keys are ignored: - seismic-tee configure --node dev-bootstrap-node-2.json --peer … --manifest m.json + seismic-tee-node configure --node dev-bootstrap-node-2.json \ + --peer … --manifest m.json """ import json diff --git a/tee/cli/common/manifest.py b/tee/cli/common/manifest.py index 9d6a397..afd238e 100644 --- a/tee/cli/common/manifest.py +++ b/tee/cli/common/manifest.py @@ -916,7 +916,7 @@ def main() -> None: print( f"Scaffolded {args.dir}. Edit the inputs (at minimum review " f"{INPUT_SUMMIT_TEMPLATE_FILENAME}), then:\n" - f" seismic-tee-bootstrap manifest assemble {args.dir}{id_hint}" + f" seismic-tee-network manifest assemble {args.dir}{id_hint}" ) elif args.command == "assemble": policy_bytes = promote_measurements( diff --git a/tee/cli/common/plumbing.py b/tee/cli/common/plumbing.py index a66503c..419333a 100644 --- a/tee/cli/common/plumbing.py +++ b/tee/cli/common/plumbing.py @@ -1,6 +1,6 @@ """Shared plumbing for the tee click front-ends. -Both CLIs — `seismic-tee` (operator) and `seismic-tee-bootstrap` +Both CLIs — `seismic-tee-node` (operator) and `seismic-tee-network` (internal network founding) — are thin click groups that forward each leaf's arguments verbatim to that module's own argparse `main()`, so per-command flags and `--help` are unchanged. Subcommand imports are diff --git a/tee/cli/network/__init__.py b/tee/cli/network/__init__.py index 5443a90..124d8e9 100644 --- a/tee/cli/network/__init__.py +++ b/tee/cli/network/__init__.py @@ -1,4 +1,4 @@ -"""`seismic-tee-bootstrap` — internal CLI to found a network. +"""`seismic-tee-network` — internal CLI to found a network. May import ..node and ..common. """ diff --git a/tee/cli/network/app.py b/tee/cli/network/app.py index 4fd088b..9168413 100644 --- a/tee/cli/network/app.py +++ b/tee/cli/network/app.py @@ -1,11 +1,11 @@ -"""`seismic-tee-bootstrap` — internal CLI to found a Seismic TEE network. +"""`seismic-tee-network` — internal CLI to found a Seismic TEE network. Seismic-internal, NOT a tool node operators run: it provisions a cohort of TDX nodes (`up` / `down`) and runs the one-time network-creation steps (`manifest`, `genesis-ceremony`). This is the CLI that is *allowed* to wrap Pulumi — `up` / `down` drive the seismic_node Automation-API orchestrator. The -operator CLI (`seismic-tee`) deliberately is not; the boundary is the node +operator CLI (`seismic-tee-node`) deliberately is not; the boundary is the node descriptor file (see tee/cli/common/descriptor.py), which this CLI produces (via provisioning) and consumes (during the genesis ceremony). @@ -29,7 +29,7 @@ def up(argv: tuple[str, ...]) -> None: """Provision a cohort of TDX nodes (one independent Pulumi stack each).""" from tee.cli.network import orchestrator - forward(orchestrator.up_main, "seismic-tee-bootstrap up", argv) + forward(orchestrator.up_main, "seismic-tee-network up", argv) @app.command(name="down", context_settings=PASSTHROUGH, add_help_option=False) @@ -38,7 +38,7 @@ def down(argv: tuple[str, ...]) -> None: """Tear down cohort node(s); each stack destroys independently.""" from tee.cli.network import orchestrator - forward(orchestrator.down_main, "seismic-tee-bootstrap down", argv) + forward(orchestrator.down_main, "seismic-tee-network down", argv) @app.command(name="configure", context_settings=PASSTHROUGH, add_help_option=False) @@ -47,7 +47,7 @@ def configure(argv: tuple[str, ...]) -> None: """Configure a cohort in parallel: one genesis + N joiners, one command.""" from tee.cli.network import cohort_configure - forward(cohort_configure.main, "seismic-tee-bootstrap configure", argv) + forward(cohort_configure.main, "seismic-tee-network configure", argv) @app.command( @@ -58,7 +58,7 @@ def genesis_ceremony(argv: tuple[str, ...]) -> None: """One-shot genesis ceremony: build genesis.toml from the cohort, fan it out.""" from tee.cli.network import genesis as genesis_mod - forward(genesis_mod.main, "seismic-tee-bootstrap genesis-ceremony", argv) + forward(genesis_mod.main, "seismic-tee-network genesis-ceremony", argv) @app.command(name="manifest", context_settings=PASSTHROUGH, add_help_option=False) @@ -67,7 +67,7 @@ def manifest(argv: tuple[str, ...]) -> None: """Scaffold (init) / assemble / validate a network artifact-set dir.""" from tee.cli.common import manifest as manifest_mod - forward(manifest_mod.main, "seismic-tee-bootstrap manifest", argv) + forward(manifest_mod.main, "seismic-tee-network manifest", argv) if __name__ == "__main__": diff --git a/tee/cli/network/cohort_configure.py b/tee/cli/network/cohort_configure.py index 4f0a45e..09f6c45 100644 --- a/tee/cli/network/cohort_configure.py +++ b/tee/cli/network/cohort_configure.py @@ -1,4 +1,4 @@ -"""`seismic-tee-bootstrap configure` — found a network in one command. +"""`seismic-tee-network configure` — found a network in one command. Configures a whole cohort at once: the one genesis node (`--genesis`, mints `root_key` locally) plus every joining node (`--join`, fetches `root_key` from @@ -8,7 +8,7 @@ to a per-node flag — so a double-genesis network split is unrepresentable. Founding is an internal act, so this lives on the bootstrap CLI; joining an -already-live network is the operator `seismic-tee configure`. Both go through +already-live network is the operator `seismic-tee-node configure`. Both go through the same `build_config` / `post_config_to_tdx_init` primitives and `status.poll_provisioning`, so each node's POSTed config and wipe-watch are identical — only the role (`genesis_node`/`peers`) differs. @@ -243,7 +243,7 @@ def _report(nodes: list[Node], results: dict[str, bool]) -> None: def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( - prog="seismic-tee-bootstrap configure", + prog="seismic-tee-network configure", description="Configure a network cohort in parallel: one genesis + N joiners.", ) parser.add_argument( diff --git a/tee/cli/network/orchestrator.py b/tee/cli/network/orchestrator.py index 2071cfb..fa9be56 100644 --- a/tee/cli/network/orchestrator.py +++ b/tee/cli/network/orchestrator.py @@ -1,7 +1,7 @@ """Cohort orchestrator: bring up / tear down N TDX nodes as one command. -Drives the `seismic-tee-bootstrap up` / `down` subcommands. -`seismic-tee-bootstrap up --count N` brings up N independent Pulumi stacks +Drives the `seismic-tee-network up` / `down` subcommands. +`seismic-tee-network up --count N` brings up N independent Pulumi stacks of the single-node `seismic_node` program via the Pulumi Automation API (local-program workspace), and writes one node descriptor per node (the same `{public_ip, fqdn, …}` shape `pulumi stack output --json` emits — see @@ -19,9 +19,9 @@ Scope is provisioning only, and genesis-agnostic: the genesis/join distinction is applied later at configure time (genesis via -`seismic-tee-bootstrap configure`, join via `seismic-tee configure`), not +`seismic-tee-network configure`, join via `seismic-tee-node configure`), not infra config. One stack per node, so -`seismic-tee-bootstrap down --stack dev-bootstrap-node-3` recycles a single +`seismic-tee-network down --stack dev-bootstrap-node-3` recycles a single node without touching the others. Runtime: like the `pulumi` CLI, the Automation API shells out to the @@ -310,12 +310,12 @@ def up_main() -> None: f"\nProvisioned {args.count} node(s) for {args.network}. Next:\n" "\n" "1. Configure the cohort (re-run on every node reboot):\n" - f" seismic-tee-bootstrap configure --genesis {genesis_desc}" + f" seismic-tee-network configure --genesis {genesis_desc}" f"{join_flags} \\\n" f" --manifest {manifest_arg}\n" "2. Run the genesis ceremony (one-shot; --node defaults to the\n" f" descriptors in {out_dir}):\n" - f" seismic-tee-bootstrap genesis-ceremony --manifest {manifest_arg}" + f" seismic-tee-network genesis-ceremony --manifest {manifest_arg}" ) return node_flags = " ".join( @@ -327,17 +327,17 @@ def up_main() -> None: "\n" "1. Create the network directory (once per network; assemble shells out\n" " to `seismic-reth genesis-hash`, so seismic-reth must be on PATH):\n" - f" seismic-tee-bootstrap manifest init {net} \\\n" + f" seismic-tee-network manifest init {net} \\\n" " --reth-genesis \\\n" " --measurements --measurement-id \n" f" # edit {net}/summit-template.toml, then:\n" - f" seismic-tee-bootstrap manifest assemble {net}\n" + f" seismic-tee-network manifest assemble {net}\n" "2. Configure the cohort (re-run on every node reboot):\n" - f" seismic-tee-bootstrap configure --genesis {genesis_desc}" + f" seismic-tee-network configure --genesis {genesis_desc}" f"{join_flags} \\\n" f" --manifest {net}/network-manifest.json\n" "3. Run the genesis ceremony (one-shot) over the same descriptors:\n" - f" seismic-tee-bootstrap genesis-ceremony {node_flags} \\\n" + f" seismic-tee-network genesis-ceremony {node_flags} \\\n" f" --manifest {net}/network-manifest.json" ) diff --git a/tee/cli/node/__init__.py b/tee/cli/node/__init__.py index 5f543b2..ce1c341 100644 --- a/tee/cli/node/__init__.py +++ b/tee/cli/node/__init__.py @@ -1 +1 @@ -"""`seismic-tee` — operator CLI for a single node. Imports only ..common.""" +"""`seismic-tee-node` — operator CLI for a single node. Imports only ..common.""" diff --git a/tee/cli/node/app.py b/tee/cli/node/app.py index 3153634..21f8992 100644 --- a/tee/cli/node/app.py +++ b/tee/cli/node/app.py @@ -1,10 +1,10 @@ -"""`seismic-tee` — operator CLI for a single Seismic TEE node. +"""`seismic-tee-node` — operator CLI for a single Seismic TEE node. Operator-facing: the commands a node operator runs against their own already-provisioned node (configure today; stake / sync later). It is cloud-agnostic and descriptor-based — it never wraps Pulumi. Standing up a network (provisioning + genesis ceremony) is a Seismic-internal act and -lives in the separate `seismic-tee-bootstrap` CLI. +lives in the separate `seismic-tee-network` CLI. Wired via [project.scripts] in pyproject.toml. Each leaf forwards its argv to that module's argparse `main()`; see tee/cli/common/plumbing.py. @@ -26,7 +26,7 @@ def configure(argv: tuple[str, ...]) -> None: """Configure a node to join a network: assemble + POST config to tdx-init.""" from tee.cli.node import configure as configure_mod - forward(configure_mod.main, "seismic-tee configure", argv) + forward(configure_mod.main, "seismic-tee-node configure", argv) @app.command(name="status", context_settings=PASSTHROUGH, add_help_option=False) @@ -35,7 +35,7 @@ def status(argv: tuple[str, ...]) -> None: """Watch a node's first-boot LUKS provisioning progress.""" from tee.cli.node import status as status_mod - forward(status_mod.main, "seismic-tee status", argv) + forward(status_mod.main, "seismic-tee-node status", argv) if __name__ == "__main__": diff --git a/tee/cli/node/configure.py b/tee/cli/node/configure.py index e71eb69..067772d 100644 --- a/tee/cli/node/configure.py +++ b/tee/cli/node/configure.py @@ -4,12 +4,12 @@ Assemble a node's tdx-init config from flags + a descriptor + the network manifest, and POST it to a provisioned node's tdx-init HTTP receiver: - seismic-tee configure --node n2.json --peer n1.json --manifest m.json + seismic-tee-node configure --node n2.json --peer n1.json --manifest m.json The operator CLI only ever *joins* an existing network (`genesis_node = false`): the node fetches `root_key` from a `--peer` via `getWrappedRootKey`. Founding a network — designating the one genesis node that mints `root_key` -locally — is an internal act owned by `seismic-tee-bootstrap configure`, not +locally — is an internal act owned by `seismic-tee-network configure`, not exposed here. `build_config`/`deliver_config` below are the shared primitives both CLIs call; `genesis_node=True` is only ever set by the bootstrap side. @@ -199,8 +199,8 @@ def deliver_config( ) -> None: """Build + POST one node's config, then (unless `no_wait`) watch its first-boot LUKS wipe. The shared per-node delivery path behind both - `seismic-tee configure` (join: genesis_node=False + peers) and - `seismic-tee-bootstrap configure` (genesis: genesis_node=True + no peers). + `seismic-tee-node configure` (join: genesis_node=False + peers) and + `seismic-tee-network configure` (genesis: genesis_node=True + no peers). Resolves the node's public_ip/fqdn from its descriptor (fqdn is the cert domain and must resolve to this node, so it's required — a wrong/absent @@ -256,7 +256,7 @@ def deliver_config( "reach a ready state within the watch window (enclave-server :7878 " "never came up, or the LUKS wipe errored). It may still be " "bootstrapping, or stuck — check enclave-server logs on the node, " - "then re-watch with:\n seismic-tee status --node " + "then re-watch with:\n seismic-tee-node status --node " ) _print_summary(fqdn, public_ip) @@ -280,7 +280,7 @@ def verify_attestation(public_ip: str, measurements_path: Path, home: str) -> No def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( - prog="seismic-tee configure", + prog="seismic-tee-node configure", description="Configure a provisioned Seismic TEE node to join a network.", ) parser.add_argument( @@ -312,7 +312,7 @@ def parse_args() -> argparse.Namespace: required=True, metavar="FILE", help=( - "Network manifest JSON (from `seismic-tee-bootstrap manifest assemble`). " + "Network manifest JSON (from `seismic-tee-network manifest assemble`). " "Merged into the POSTed config as [network].manifest_base64; shared " "across every node, so it lives outside the per-node flags." ), diff --git a/tee/cli/node/status.py b/tee/cli/node/status.py index b93445c..22719bf 100644 --- a/tee/cli/node/status.py +++ b/tee/cli/node/status.py @@ -4,7 +4,7 @@ enclave-server serves `getLuksProvisioningStatus` on :7878 (JSON-RPC) for the duration of the first-boot disk wipe — the one long (1h+), otherwise opaque phase. This module polls it and renders a progress bar, and is the -shared poller behind both `seismic-tee status` and `configure`'s default +shared poller behind both `seismic-tee-node status` and `configure`'s default post-POST wait. States (see enclave/crates/tdx-init's `LuksProvisioningStatus`): diff --git a/tee/networks/README.md b/tee/networks/README.md index 3d5928b..693aa80 100644 --- a/tee/networks/README.md +++ b/tee/networks/README.md @@ -3,7 +3,7 @@ One directory per network: the committable identity of a founded (or foundable) network. Each holds the three authored inputs (`reth-genesis.json`, `summit-template.toml`, `measurements.json`) plus -the artifact set `seismic-tee-bootstrap manifest assemble` derives from them +the artifact set `seismic-tee-network manifest assemble` derives from them (`network-manifest.json` — whose SHA-256 is the network's `network_id` — `summit-genesis-template.toml`, `measurement-policy.json`). The founding workflow lives in the tee README ("Creating a new network"). diff --git a/tee/pulumi/seismic_node/Pulumi.dev.yaml b/tee/pulumi/seismic_node/Pulumi.dev.yaml index 269b5ac..6857e7e 100644 --- a/tee/pulumi/seismic_node/Pulumi.dev.yaml +++ b/tee/pulumi/seismic_node/Pulumi.dev.yaml @@ -1,5 +1,5 @@ # `dev` stack config for one seismic_node — AND the default template that -# `seismic-tee-bootstrap up` inherits shared settings from when bootstrapping a +# `seismic-tee-network up` inherits shared settings from when bootstrapping a # network: it reads this `config:` block and overrides only the per-node names # (resource_group / vm_name / dns_record_name → -). Copy to a sibling # Pulumi..yaml (e.g. testnet) for non-dev cohorts. diff --git a/tee/pulumi/seismic_node/README.md b/tee/pulumi/seismic_node/README.md index a3065a6..bc75790 100644 --- a/tee/pulumi/seismic_node/README.md +++ b/tee/pulumi/seismic_node/README.md @@ -88,10 +88,10 @@ command depends on the node's role in `root_key` bootstrap: ```bash # Founding a brand-new network (exactly one node): the genesis node mints # root_key locally. This is an internal act, so it's on the bootstrap CLI. -uv run seismic-tee-bootstrap configure --genesis \ +uv run seismic-tee-network configure --genesis \ --manifest network-manifest.json # Every other node joins (operator CLI), fetching root_key from an existing peer: -uv run seismic-tee configure --node \ +uv run seismic-tee-node configure --node \ --peer http://:7878 --manifest network-manifest.json ``` @@ -100,7 +100,7 @@ unblocks: enclave starts, nginx-ssl-setup acquires a cert, reth/summit start. Public RPC at `https:///rpc` then. `/run/seismic/conf` is tmpfs, so the config is re-POSTed on every boot. After -the first bootstrap, re-POST a genesis node with `seismic-tee configure` +the first bootstrap, re-POST a genesis node with `seismic-tee-node configure` (pointing `--peer` at a cohort node) so it fetches the existing network `root_key` instead of minting a new one; the durable guard against a genesis node re-minting is enclave-side. diff --git a/tee/pulumi/seismic_node/node.bootstrap.toml b/tee/pulumi/seismic_node/node.bootstrap.toml index 0908551..d34399a 100644 --- a/tee/pulumi/seismic_node/node.bootstrap.toml +++ b/tee/pulumi/seismic_node/node.bootstrap.toml @@ -1,4 +1,4 @@ -# Per-node config POSTed via `seismic-tee configure`, which supplies the rest: +# Per-node config POSTed via `seismic-tee-node configure`, which supplies the rest: # [domain] (name from the descriptor fqdn + --email) and [network] (from # --manifest). This file carries [enclave] only. diff --git a/tee/pulumi/seismic_node/node.toml b/tee/pulumi/seismic_node/node.toml index 139aff5..34c1674 100644 --- a/tee/pulumi/seismic_node/node.toml +++ b/tee/pulumi/seismic_node/node.toml @@ -1,4 +1,4 @@ -# Per-node config POSTed via `seismic-tee configure`, which supplies the rest: +# Per-node config POSTed via `seismic-tee-node configure`, which supplies the rest: # [domain] (name from the descriptor fqdn + --email) and [network] (from # --manifest). This file carries [enclave] only.