Skip to content

Latest commit

 

History

History
49 lines (35 loc) · 7.52 KB

File metadata and controls

49 lines (35 loc) · 7.52 KB

Node installer

These modules are packaged as node-install.pyz, which Web serves at /node-install/. They install a sandbox node on a Linux host that runs sandboxes for one Core; they never install Core. The bootstrap is one file that runs with the host's python3.

Module Role
node_install.py, node_spec.py, node_generations.py Node installer and generation helper. node_spec.py is generated by go run ./services/core/cmd/specification-contract -write
distribution.py Verified artifacts, private temporary files, release metadata and Docker image identity
install_display.py, node_output.py Terminal output
provider_assets.py Node provider artifact names, generated by go run ./services/core/cmd/provider-artifacts
node_payload.py Publish a release's node files without replacing bytes already installed

Accounts and permissions

The node installer runs as root and prepares the host for one node per installation.

  • It creates or adopts the oac-node system user, adds it to the docker or kvm group (no other group), and installs one root-owned system service per installation that runs the node program as User=oac-node. Nodes on a host share that account, so a host serves one Core.
  • Docker group membership makes that user, and so the node, root-equivalent on the host; that is inherent to Docker sandboxes. microsandbox needs only kvm, user KVM access and the Linux runtime libraries.
  • Node configuration and identity live under ~/.oac/nodes/<installation-id>/ in the node account's home (/var/lib/oac-node); microsandbox uses a separate short private Runtime home.
  • The node service owns its provider processes outside the Core container. KillMode=process keeps resident microVM and helper processes across a service restart. The service restarts after failures with no start limit, so a node outlasts a Core outage, and stops restarting when the node program exits 78 because Core answered 401 to its credential (a removed node).
  • It never installs Docker, KVM or packages and never changes device permissions. It refuses SELinux-enforcing hosts and changes nothing when a check fails. The enrollment token comes only on standard input, never in arguments or the environment.
  • Files the service account owns are read, written and deleted only with that account's credentials. The one exception is root removing the account's home after userdel, when no process can still run as that account. That work runs in a child that starts its own session with /dev/null as input, joins a new session keyring and dies with its parent; root shows its output only as plain text (terminal controls become ?). SIGINT, SIGHUP and SIGTERM stop that child and what it started.
  • Root never runs a file the service account can write, opens a URL it wrote, or follows a link in its home. Capture the trusted bootstrap bytes before dropping to the service account and pass them through the fork; the service account writes its own retained generation helper. Never open the caller's private download directory to it or let root write into service-owned state.
  • The generated bootstrap passes only the six standard HTTP/HTTPS proxy and bypass variables through sudo and gives both spellings the lowercase value when present, even if empty, so curl, urllib and the Go registration command follow the same rules. The installation child keeps just those names beside its fixed environment. Proxy values stay out of arguments, saved configuration, service units and diagnostics; never use broad sudo environment inheritance. This covers installation downloads only, not the node service.
  • --uninstall removes a node only after Core rejects its credential, except for a node that never registered and with --force, which Web offers when the old Core address no longer responds. It never touches sandboxes, volumes or images (the Runtime image and the microsandbox store stay), deletes the account only when the installer created it and no node remains, and otherwise removes only the groups it added.
  • Refuse resources of an older product name for the same installation ID; never adopt them or remove another installation's resources.

Download contract

The generated command uses ~/.oac/node-bootstrap in the invoking account's home. Under download.lock, it discards an unfinished download.partial, downloads and verifies the bootstrap, then publishes <sha256>.pyz. The lock is released before invoking sudo; verified files stay available to running installers. Node file writes share distribution.temporary_file: under the caller's installation lock, remove the previous temporary file, write privately, and publish atomically. The same lifecycle covers payloads, extraction, helpers, settings and enrollment tokens. Registration tokens are removed even when a rerun finds the node already registered.

Configuration files are published only after their complete contents are written; a retry preserves an existing matching file and refuses conflicting contents. Generation leases are durable locks, not disposable temporary files: interruption between creating a lease and recording its inode identity requires operator inspection. A retry refuses that unrecorded lease instead of replacing an inode that a Runtime helper could still hold.

The distribution manifest is the one download contract for nodes: flat versioned file names, and the compressed and unpacked size and SHA-256 of the Runtime.

  • A Compose installation keeps only the node metadata from its release archive; Core's image never acquires execution-only payloads.
  • A node obtains bootstrap metadata from the console that generated its command. Web serves artifacts it has locally and redirects missing declared execution artifacts to the versioned HTTPS release base in the verified manifest. Web never downloads or caches those bytes.
  • Only artifact requests may follow HTTPS redirects, and only without credentials or cookies. Metadata and enrollment requests stay on the configured console. The console publishes only fixed non-secret files and declared artifact names.
  • Download into private temporary files, verify size and SHA-256 before an atomic rename, clear leftover temporary downloads and extracted files before retrying, and reuse only verified cache entries or exact image identities. Never select a release other than the pinned one.
  • Release downloads are anonymous. Never add repository credentials to installed node or Runtime configuration.
  • Manual builds use the build-<full SHA> release tag and tag builds the v* tag. The manifest's download base must match the release tag; artifact file names and source provenance keep the full source SHA.

Image identity

The manifest's images records each exported image's config digest, and image_manifest_digests its OCI manifest or index digest. Derive and verify both from the same archive, including its referenced config and layer bytes, and require the build host's selected image ID to match one of them.

Docker's classic image store identifies images by config digest, and its containerd store by the OCI descriptor. The build therefore takes the digest the local store resolves from BuildKit's build metadata, never the --iidfile config digest alone, and disables provenance attestations so each image and archive holds one platform manifest in both stores.

The node installer confirms Linux amd64 and the returned immutable local ID, and service and provider configuration and Runtime launches use that ID. Tags never replace identity verification. The microsandbox runtime_ref is independent of Docker's local store identity.