From 7927a7f02830c57b048d24f5b7c2649935f73e85 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:42:00 +0800 Subject: [PATCH] refactor(tee)!: rename CLIs to seismic-tee-node / seismic-tee-network Node vs network scope is the real boundary between the two CLIs, and after the cli/{node,network} layout the old names no longer taught it. "bootstrap" also undersold the internal CLI, which tears down and reconfigures cohorts, not just founds networks. Pure rename of the installed commands and their mentions; module paths are untouched. The live infra identifiers seismic-tee-deploy (Pulumi project) and seismic-tee-dev (Azure resource group) are deliberately unchanged. Re-run `uv sync` after pulling to get the new entry points. --- pyproject.toml | 4 +- tee/README.md | 64 ++++++++++----------- tee/cli/common/descriptor.py | 5 +- tee/cli/common/manifest.py | 2 +- tee/cli/common/plumbing.py | 2 +- tee/cli/network/__init__.py | 2 +- tee/cli/network/app.py | 14 ++--- tee/cli/network/cohort_configure.py | 6 +- tee/cli/network/orchestrator.py | 20 +++---- tee/cli/node/__init__.py | 2 +- tee/cli/node/app.py | 8 +-- tee/cli/node/configure.py | 14 ++--- tee/cli/node/status.py | 2 +- tee/networks/README.md | 2 +- tee/pulumi/seismic_node/Pulumi.dev.yaml | 2 +- tee/pulumi/seismic_node/README.md | 6 +- tee/pulumi/seismic_node/node.bootstrap.toml | 2 +- tee/pulumi/seismic_node/node.toml | 2 +- 18 files changed, 80 insertions(+), 79 deletions(-) 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.