Skip to content

Safety model

Hostwright’s safety posture is conservative and enforced by the command surface: the runtime can be mutated only through explicit, confirmed lifecycle plans and a separate cleanup gate.

Safety flow: validate the manifest, compute a plan, confirm destructive actions, then apply; dry-run exits before any mutation.

  • Plan before mutation. up, down, run, start, stop, restart, rm, and update each recompute their plan against a live observation and refuse to run unless --confirm-plan <hash> matches it. apply is the same gate under its earlier name.
  • Every plan is a closed DAG. A confirmed plan lists exactly the nodes it will execute, in dependency order, before anything runs. Nothing outside that plan is touched, and a node whose preconditions no longer hold is never silently skipped or substituted.
  • Dry-run before deletion. cleanup --dry-run, and every destructive image or volume command, classifies every candidate and prints an exact confirmation token or plan hash. Only the matching confirmation deletes anything.
  • Intent before mutation. Operation intent, recovery groups, and checkpoints are persisted to the resolved state database before the runtime is touched.
  • Conservative validation. Unsafe or ambiguous manifests are refused outright. See the policy engine.
  • Ownership-tracked cleanup. No broad garbage collection. Cleanup, image pruning, and volume pruning touch only resources Hostwright can prove it owns.
  • No secret leakage. Plans, events, logs, state rows, and errors carry redacted values only.

A lifecycle command refuses mutation when, among other cases, the state database or plan hash is missing or mismatched, observation fails, the plan has blockers, capabilities or provider identity have drifted since the dry run, a create step uses mounts or privileged ports or broad bind addresses, a required image cannot be confirmed locally, or another operation still holds an active lease on the same project. Created port bindings publish to 127.0.0.1 explicitly. A managed restart additionally requires exact Hostwright ownership, live observed running state, and a fresh persisted unhealthy health result where the service declares one.

Once confirmed, execution runs ready nodes with bounded parallelism and re-observes between waves, so a later node still sees current reality rather than a stale snapshot from the dry run. An interrupted operation can resume only when its persisted checkpoint proves the exact remaining work; anything ambiguous stays in a safe hold and is reported by hostwright recovery, which can then resume or roll back the held operation once you review it.

Hostwright distinguishes resources it created from resources you created by hand. Hostwright-created containers carry versioned identifiers and exact ownership labels, mirrored by ownership records in the state store. The rule is strict: cleanup never deletes a resource it cannot prove Hostwright owns.

Cleanup classifications from the dry run: eligible, ambiguous, stale, running (never deleted), unknown, blocked, and never-delete. Only eligible (an exact Hostwright-owned created/stopped/exited container covered by the current token) is ever deleted. Images, volumes, networks, and unmanaged containers are never touched, and broad flags like --all or --force are never used.

Secrets are not committed into manifests. Plaintext sensitive keys under env fail validation; secret values enter only through keychain:// references resolved at the last moment before a confirmed create.