kitsune-kit 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +143 -2
- data/CONTRIBUTING.md +83 -0
- data/README.md +112 -135
- data/SECURITY.md +25 -0
- data/bin/kit +4 -1
- data/docs/architecture/decisions/0001-product-boundary.md +23 -0
- data/docs/architecture/decisions/0002-core-and-interfaces.md +23 -0
- data/docs/architecture/decisions/0003-configuration-state-and-secrets.md +23 -0
- data/docs/architecture/decisions/0004-supported-platforms.md +19 -0
- data/docs/architecture/decisions/0005-operation-semantics.md +19 -0
- data/docs/architecture/decisions/0006-tui-backend.md +21 -0
- data/docs/architecture/decisions/0007-compose-customization.md +30 -0
- data/docs/architecture/provider-adapters.md +49 -0
- data/docs/architecture.md +93 -0
- data/docs/commands.md +224 -0
- data/docs/configuration.md +226 -0
- data/docs/getting-started.md +133 -0
- data/docs/providers/digitalocean.md +52 -0
- data/docs/releasing.md +43 -0
- data/docs/roadmap.md +46 -0
- data/docs/security-audit.md +130 -0
- data/docs/security.md +116 -0
- data/docs/services/compose.md +164 -0
- data/docs/services/postgres.md +78 -0
- data/docs/services/redis.md +53 -0
- data/docs/testing.md +200 -0
- data/docs/troubleshooting.md +123 -0
- data/docs/tui.md +57 -0
- data/lib/kitsune/kit/adapters/confirming_host_key_verifier.rb +42 -0
- data/lib/kitsune/kit/adapters/digitalocean_provider.rb +217 -0
- data/lib/kitsune/kit/adapters/fake_clock.rb +34 -0
- data/lib/kitsune/kit/adapters/fake_provider.rb +107 -0
- data/lib/kitsune/kit/adapters/fake_reporter.rb +34 -0
- data/lib/kitsune/kit/adapters/fake_secret_store.rb +35 -0
- data/lib/kitsune/kit/adapters/fake_state_store.rb +91 -0
- data/lib/kitsune/kit/adapters/fake_transport.rb +56 -0
- data/lib/kitsune/kit/adapters/net_ssh_transport.rb +155 -0
- data/lib/kitsune/kit/adapters/provider.rb +34 -0
- data/lib/kitsune/kit/adapters/transport.rb +22 -0
- data/lib/kitsune/kit/adapters/transport_factory.rb +116 -0
- data/lib/kitsune/kit/application.rb +170 -0
- data/lib/kitsune/kit/cancellation.rb +21 -0
- data/lib/kitsune/kit/cli.rb +879 -64
- data/lib/kitsune/kit/clock.rb +11 -0
- data/lib/kitsune/kit/configuration.rb +577 -0
- data/lib/kitsune/kit/errors.rb +98 -0
- data/lib/kitsune/kit/events.rb +55 -0
- data/lib/kitsune/kit/operations/ensure_dns_records.rb +165 -0
- data/lib/kitsune/kit/operations/ensure_server.rb +135 -0
- data/lib/kitsune/kit/operations/ensure_service.rb +302 -0
- data/lib/kitsune/kit/operations/remote_script.rb +214 -0
- data/lib/kitsune/kit/operations/service_backup.rb +71 -0
- data/lib/kitsune/kit/operations/service_files.rb +131 -0
- data/lib/kitsune/kit/operations/service_firewall.rb +190 -0
- data/lib/kitsune/kit/operations/service_state.rb +59 -0
- data/lib/kitsune/kit/plan.rb +72 -0
- data/lib/kitsune/kit/reporters/human.rb +89 -0
- data/lib/kitsune/kit/reporters/json.rb +65 -0
- data/lib/kitsune/kit/reporters/reporter.rb +11 -0
- data/lib/kitsune/kit/result.rb +28 -0
- data/lib/kitsune/kit/run_journal.rb +102 -0
- data/lib/kitsune/kit/run_logger.rb +37 -0
- data/lib/kitsune/kit/scripts/docker.sh +142 -0
- data/lib/kitsune/kit/scripts/firewall.sh +210 -0
- data/lib/kitsune/kit/scripts/metrics.sh +59 -0
- data/lib/kitsune/kit/scripts/ssh.sh +95 -0
- data/lib/kitsune/kit/scripts/swap.sh +86 -0
- data/lib/kitsune/kit/scripts/unattended.sh +86 -0
- data/lib/kitsune/kit/scripts/user.sh +114 -0
- data/lib/kitsune/kit/secret_filter.rb +54 -0
- data/lib/kitsune/kit/secret_store.rb +32 -0
- data/lib/kitsune/kit/secret_stores/store.rb +12 -0
- data/lib/kitsune/kit/service_compose.rb +272 -0
- data/lib/kitsune/kit/state_store.rb +158 -0
- data/lib/kitsune/kit/state_stores/store.rb +15 -0
- data/lib/kitsune/kit/tui/actions.rb +72 -0
- data/lib/kitsune/kit/tui/application.rb +35 -0
- data/lib/kitsune/kit/tui/controller.rb +162 -0
- data/lib/kitsune/kit/tui/renderer.rb +134 -0
- data/lib/kitsune/kit/tui/state.rb +18 -0
- data/lib/kitsune/kit/tui/store.rb +88 -0
- data/lib/kitsune/kit/tui/terminal.rb +95 -0
- data/lib/kitsune/kit/version.rb +1 -1
- data/lib/kitsune/kit/workflows/apply_plan.rb +145 -0
- data/lib/kitsune/kit/workflows/base.rb +31 -0
- data/lib/kitsune/kit/workflows/build_plan.rb +33 -0
- data/lib/kitsune/kit/workflows/destroy_server.rb +84 -0
- data/lib/kitsune/kit/workflows/doctor.rb +225 -0
- data/lib/kitsune/kit/workflows/eject_compose.rb +82 -0
- data/lib/kitsune/kit/workflows/environment_selection.rb +70 -0
- data/lib/kitsune/kit/workflows/import_server.rb +100 -0
- data/lib/kitsune/kit/workflows/initialize_project.rb +129 -0
- data/lib/kitsune/kit/workflows/inspect_environment.rb +44 -0
- data/lib/kitsune/kit/workflows/rollback.rb +54 -0
- data/lib/kitsune/kit/workflows/support_bundle.rb +82 -0
- data/lib/kitsune/kit.rb +42 -2
- metadata +125 -79
- data/.rspec +0 -3
- data/Rakefile +0 -8
- data/kitsune-kit-logo.jpg +0 -0
- data/lib/kitsune/blueprints/.env.template +0 -31
- data/lib/kitsune/blueprints/docker/postgres.yml +0 -27
- data/lib/kitsune/blueprints/docker/redis.yml +0 -23
- data/lib/kitsune/blueprints/kit.env.template +0 -1
- data/lib/kitsune/kit/ansi_color.rb +0 -78
- data/lib/kitsune/kit/commands/bootstrap.rb +0 -134
- data/lib/kitsune/kit/commands/bootstrap_docker.rb +0 -66
- data/lib/kitsune/kit/commands/dns.rb +0 -112
- data/lib/kitsune/kit/commands/init.rb +0 -148
- data/lib/kitsune/kit/commands/install_docker_engine.rb +0 -146
- data/lib/kitsune/kit/commands/postinstall_docker.rb +0 -142
- data/lib/kitsune/kit/commands/provision.rb +0 -43
- data/lib/kitsune/kit/commands/setup_do_metrics.rb +0 -123
- data/lib/kitsune/kit/commands/setup_docker_prereqs.rb +0 -151
- data/lib/kitsune/kit/commands/setup_firewall.rb +0 -132
- data/lib/kitsune/kit/commands/setup_postgres_docker.rb +0 -246
- data/lib/kitsune/kit/commands/setup_redis_docker.rb +0 -241
- data/lib/kitsune/kit/commands/setup_swap.rb +0 -151
- data/lib/kitsune/kit/commands/setup_unattended.rb +0 -132
- data/lib/kitsune/kit/commands/setup_user.rb +0 -189
- data/lib/kitsune/kit/commands/ssh.rb +0 -46
- data/lib/kitsune/kit/commands/switch_env.rb +0 -42
- data/lib/kitsune/kit/defaults.rb +0 -91
- data/lib/kitsune/kit/env_loader.rb +0 -41
- data/lib/kitsune/kit/options_builder.rb +0 -26
- data/lib/kitsune/kit/provisioner.rb +0 -107
- data/sig/kitsune/kit.rbs +0 -6
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ADR 0003: Configuration, state and secrets
|
|
2
|
+
|
|
3
|
+
- Status: accepted
|
|
4
|
+
- Date: 2026-08-14
|
|
5
|
+
|
|
6
|
+
## Decision
|
|
7
|
+
|
|
8
|
+
- `.kitsune/config.yml` contains versioned, non-secret project configuration.
|
|
9
|
+
- `.kitsune/environments/<name>.yml` contains versioned environment overrides.
|
|
10
|
+
- `.kitsune/state/<name>.json` contains versioned, non-secret managed-resource state.
|
|
11
|
+
- Secrets come from environment variables initially. Secret-store adapters may be added later.
|
|
12
|
+
- Configuration precedence is CLI, environment variables, the selected environment file, project file, safe defaults.
|
|
13
|
+
- The active environment is selected by `--env`, then `KITSUNE_ENV`, then `.kitsune/environment`, then `development`.
|
|
14
|
+
- State writes are locked and atomic.
|
|
15
|
+
- State stores provider IDs and previous managed values; deletion never relies only on a resource name.
|
|
16
|
+
- Reporters pass all values through one secret filter.
|
|
17
|
+
- Version 1 is the new product baseline; legacy preview formats are not migrated or interpreted.
|
|
18
|
+
- Any future schema transition must be an explicit, tested adjacent-version migration that preserves a backup.
|
|
19
|
+
- Unknown/future configuration and state versions fail with compatible-version or migration guidance.
|
|
20
|
+
|
|
21
|
+
## Consequences
|
|
22
|
+
|
|
23
|
+
Existing `.env` infrastructure files are not read by the new product. Sensitive data is never persisted in state or diagnostic bundles.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ADR 0004: Supported platforms
|
|
2
|
+
|
|
3
|
+
- Status: accepted
|
|
4
|
+
- Date: 2026-08-14
|
|
5
|
+
|
|
6
|
+
## Decision
|
|
7
|
+
|
|
8
|
+
- Ruby 3.2, 3.3 and 3.4 are supported (`>= 3.2`, `< 4.0`).
|
|
9
|
+
- CI tests every supported Ruby minor version.
|
|
10
|
+
- Local clients support macOS and Linux.
|
|
11
|
+
- Managed servers support Ubuntu 22.04 and 24.04 LTS.
|
|
12
|
+
- Docker Compose v2 is required.
|
|
13
|
+
- DigitalOcean is the only supported provider before 1.0.
|
|
14
|
+
|
|
15
|
+
Ruby 3.2 is selected because the new core uses immutable `Data` value objects. Dependencies that require a newer patch or minor version must not be mandatory until the support declaration is updated and verified.
|
|
16
|
+
|
|
17
|
+
Ruby 4 is excluded from the 0.5.0 contract because DropletKit 3.22 constrains `faraday-retry` to the 2.2 series,
|
|
18
|
+
whose gem metadata requires Ruby `< 4`. Support can be enabled once that provider dependency accepts a
|
|
19
|
+
Ruby-4-compatible `faraday-retry` release, or when the provider adapter no longer depends on that SDK.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ADR 0005: Plan, apply, rollback, remove and destroy semantics
|
|
2
|
+
|
|
3
|
+
- Status: accepted
|
|
4
|
+
- Date: 2026-08-14
|
|
5
|
+
|
|
6
|
+
## Decision
|
|
7
|
+
|
|
8
|
+
- `plan` observes and describes changes without mutation.
|
|
9
|
+
- `apply` converges actual state to desired state and verifies postconditions.
|
|
10
|
+
- `rollback` restores captured prior state when restoration is safe and supported.
|
|
11
|
+
- `remove` stops and removes a managed capability while preserving data.
|
|
12
|
+
- `destroy` permanently removes a provider resource.
|
|
13
|
+
- `destroy-data` permanently removes service data and is always separately confirmed.
|
|
14
|
+
|
|
15
|
+
Destructive operations show exact IDs and require the resource name as confirmation in an interactive terminal or an explicit confirmation option in non-interactive mode.
|
|
16
|
+
|
|
17
|
+
## Consequences
|
|
18
|
+
|
|
19
|
+
The word rollback is never used as a synonym for deleting a server or Docker volume. Operations that cannot restore prior state say so before execution.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# ADR 0006: Optional TUI backend
|
|
2
|
+
|
|
3
|
+
- Status: accepted
|
|
4
|
+
- Date: 2026-08-14
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Kitsune Kit needs a full-screen terminal interface without making it necessary for automation or conventional CLI use. RatatuiRuby 1.5 provides excellent widgets and headless testing, but currently requires Ruby 3.2.9 or newer, distributes native platform artifacts, and is LGPL-3.0-or-later. Kitsune Kit currently supports the Ruby 3.2 series and must remain installable as one portable Ruby gem.
|
|
9
|
+
|
|
10
|
+
## Decision
|
|
11
|
+
|
|
12
|
+
- The domain emits presentation-neutral events.
|
|
13
|
+
- `Tui::Store`, `Tui::Renderer`, `Tui::Controller` and `Tui::Terminal` are separate components.
|
|
14
|
+
- The initial renderer uses a small ANSI terminal backend and a deterministic text buffer.
|
|
15
|
+
- Every TUI action invokes the same workflow used by the conventional CLI.
|
|
16
|
+
- A future RatatuiRuby backend may replace only renderer, input and terminal lifecycle components.
|
|
17
|
+
- The TUI remains optional at runtime; non-TTY use never initializes it.
|
|
18
|
+
|
|
19
|
+
## Consequences
|
|
20
|
+
|
|
21
|
+
The gem has no native TUI dependency and works completely through CLI/JSON. The initial widget set is intentionally smaller than RatatuiRuby, but its state, navigation, worker and snapshots remain reusable if a richer backend is adopted.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# ADR 0007: Managed Compose customization boundary
|
|
2
|
+
|
|
3
|
+
- Status: accepted
|
|
4
|
+
- Date: 2026-08-14
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
The fixed PostgreSQL and Redis generators are safe and convenient, but cannot express every operational Docker
|
|
9
|
+
setting. Making arbitrary YAML fragments part of the core configuration would duplicate the Compose schema and
|
|
10
|
+
produce a weaker, less familiar interface.
|
|
11
|
+
|
|
12
|
+
## Decision
|
|
13
|
+
|
|
14
|
+
Managed services support three explicit modes: deterministic generated output, a generated base plus one project
|
|
15
|
+
overlay, and one complete project-owned custom document. All modes pass through a single renderer, fingerprint,
|
|
16
|
+
remote validation, state and recovery path.
|
|
17
|
+
|
|
18
|
+
Customization files remain within the project and are subject to size, type, secret and host-boundary validation.
|
|
19
|
+
Security-sensitive Compose settings fail closed unless `allow_unsafe` records an explicit operator decision.
|
|
20
|
+
Inline secrets always fail. The `eject` command creates a complete custom starting point and a configuration
|
|
21
|
+
backup instead of preserving compatibility with the earlier fixed blueprint internals.
|
|
22
|
+
|
|
23
|
+
## Consequences
|
|
24
|
+
|
|
25
|
+
- Users can express ordinary Compose settings without Kitsune Kit reimplementing the Compose schema.
|
|
26
|
+
- Generated mode remains the default and safest supported path.
|
|
27
|
+
- Custom mode transfers responsibility for image, health, network and volume semantics to the project.
|
|
28
|
+
- Kitsune Kit tracks and restores the ordered document set, but does not claim ownership of arbitrary host
|
|
29
|
+
resources introduced through the unsafe escape hatch.
|
|
30
|
+
- Docker's server-side `compose config` remains authoritative for Compose-version compatibility.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Provider and transport adapters
|
|
2
|
+
|
|
3
|
+
Kitsune Kit's adapter API version is `Kitsune::Kit::Adapters::API_VERSION`, currently `1`. It is a small internal extension boundary, not a dynamic plugin system. A breaking signature or semantic change must increment this value and the corresponding JSON/event schemas when affected.
|
|
4
|
+
|
|
5
|
+
## Provider contract
|
|
6
|
+
|
|
7
|
+
A provider subclasses `Kitsune::Kit::Adapters::Provider` and implements:
|
|
8
|
+
|
|
9
|
+
| Method | Contract |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `validate_credentials!` | Return `true`, or raise a typed authentication/provider error. |
|
|
12
|
+
| `validate_server_spec!(spec:)` | Check region, size and image availability without creating anything. |
|
|
13
|
+
| `find_server(name:, tags:)` | Return an exact owned `ServerRecord` or `nil`; never adopt by name alone. |
|
|
14
|
+
| `find_server_by_id(id:)` | Return the exact record or `nil`. |
|
|
15
|
+
| `create_server(spec:)` | Create once and return the provider ID immediately. |
|
|
16
|
+
| `wait_until_ready(id:, timeout:)` | Return an active record with a public IP or raise `TimeoutError`. |
|
|
17
|
+
| `delete_server(id:)` | Delete by exact provider ID. |
|
|
18
|
+
| DNS methods | Find/upsert/delete records while preserving exact IDs and zones. |
|
|
19
|
+
|
|
20
|
+
Provider exceptions must be translated into `Kitsune::Kit::Errors` without copying tokens or raw provider response bodies into messages. Availability errors are configuration errors because the user can correct the desired spec; transient API failures remain retryable provider errors.
|
|
21
|
+
The CLI `--timeout` value configures both DropletKit open/read timeouts and the separate readiness deadline.
|
|
22
|
+
|
|
23
|
+
## Transport contract
|
|
24
|
+
|
|
25
|
+
A transport subclasses `Kitsune::Kit::Adapters::Transport`. `execute` receives a command and a separate argument array, applies a deadline, and returns `CommandResult` with independent `stdout`, `stderr`, `exit_status` and `duration_ms`. It does not infer success from output. `upload` accepts explicit content, absolute normalized path and restrictive mode. Host-key verification belongs to the connection adapter and must never silently disable verification.
|
|
26
|
+
|
|
27
|
+
## Verification
|
|
28
|
+
|
|
29
|
+
The same shared examples run against `FakeProvider`/`DigitalOceanProvider` and `FakeTransport`/`NetSshTransport`. They cover credentials, spec validation, lifecycle, DNS, reachability, result shape, uploads and timeout mapping. Adapter-specific tests cover provider error translation, SSH quoting, unsafe paths, host keys and failed uploads.
|
|
30
|
+
|
|
31
|
+
Run them with:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bundle exec rspec spec/adapters spec/contracts
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Do not add a provider until it can pass these contracts and an opt-in real lifecycle test. The Hetzner
|
|
38
|
+
feasibility/sequencing review and the decision not to create a premature hook system are recorded in
|
|
39
|
+
[Roadmap and extension decisions](../roadmap.md).
|
|
40
|
+
|
|
41
|
+
The state boundary follows the same rule: `StateStores::Store` defines the port, while `StateStore` is the locked atomic filesystem adapter and `Adapters::FakeStateStore` is the deterministic in-memory adapter. Both execute `spec/contracts/state_store_contract.rb`.
|
|
42
|
+
|
|
43
|
+
`SecretStores::Store` and `Reporters::Reporter` are also explicit ports. Environment/fake secret stores and
|
|
44
|
+
human/JSON/fake reporters execute their shared contracts in `spec/adapters`; fakes make complete workflow tests
|
|
45
|
+
independent of the process environment and terminal.
|
|
46
|
+
|
|
47
|
+
`Clock` is the time port for workflow event timestamps, monotonic durations, journals and bounded waits.
|
|
48
|
+
`Adapters::FakeClock` advances deterministically without sleeping; both implementations execute
|
|
49
|
+
`spec/contracts/clock_contract.rb`.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Kitsune Kit is a desired-state infrastructure tool with two replaceable presentation layers over one domain core.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Conventional CLI ─┐
|
|
7
|
+
├─ workflows ─ operations ─ provider / SSH / state / secrets
|
|
8
|
+
Optional TUI ─────┘ │
|
|
9
|
+
└─ domain events ─ human / JSON / TUI / run log
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Presentation code does not create provider clients, open SSH connections or implement infrastructure rules. CLI and TUI call the same workflow objects and consume the same event stream.
|
|
13
|
+
|
|
14
|
+
## Layers
|
|
15
|
+
|
|
16
|
+
### Configuration and domain values
|
|
17
|
+
|
|
18
|
+
`Configuration` loads/merges typed schema values and validates them before adapters are constructed. `Change`, `Plan`, `Result`, typed errors and versioned events are presentation-neutral values.
|
|
19
|
+
|
|
20
|
+
### Workflows
|
|
21
|
+
|
|
22
|
+
Workflows coordinate use cases:
|
|
23
|
+
|
|
24
|
+
- initialize/select an environment;
|
|
25
|
+
- build/apply/resume a plan;
|
|
26
|
+
- inspect/doctor/rollback/destroy;
|
|
27
|
+
- generate support diagnostics.
|
|
28
|
+
|
|
29
|
+
They emit events but do not print. Apply uses `RunJournal` to record a compatible plan and step status for safe resume.
|
|
30
|
+
|
|
31
|
+
The event vocabulary includes run/plan start and finish, operation start/progress/success/failure/skip, and warnings. All subscribers receive the same versioned event values; progress currently guarantees operation boundary percentages and can become finer-grained without changing presentations.
|
|
32
|
+
|
|
33
|
+
### Operations
|
|
34
|
+
|
|
35
|
+
Each operation exposes a non-mutating `plan`, idempotent `apply` and, where meaningful, ownership-aware `rollback`. Operations include server creation, versioned remote scripts, services and DNS.
|
|
36
|
+
|
|
37
|
+
An operation verifies its result before writing a managed marker/state. Destructive replacement appears in the plan and is never applied implicitly.
|
|
38
|
+
|
|
39
|
+
### Ports and adapters
|
|
40
|
+
|
|
41
|
+
- `Provider`: server-spec validation, exact server/DNS lookup, create/wait/delete and credential validation.
|
|
42
|
+
- `Transport`: reachability, command execution with separate output/status/timing, and safe upload.
|
|
43
|
+
- `StateStores::Store`: read/update/delete and per-environment mutation-lock port; filesystem and in-memory fake adapters share a contract.
|
|
44
|
+
- `SecretStores::Store`: resolves secret values without adding them to domain configuration/state; environment
|
|
45
|
+
and deterministic fake adapters execute the same contract.
|
|
46
|
+
- `Reporters::Reporter`: event-consumer port for human output, stable JSON, TUI state and redacted logs.
|
|
47
|
+
- `Clock`: UTC wall time, monotonic durations and sleeping, with a deterministic nonblocking fake.
|
|
48
|
+
|
|
49
|
+
Real DigitalOcean/Net::SSH adapters and deterministic fakes satisfy shared contracts. This permits full workflow failure injection without a VPS while reserving real behavior for integration/E2E suites.
|
|
50
|
+
|
|
51
|
+
The public adapter contract is versioned as `Kitsune::Kit::Adapters::API_VERSION`. See [Provider and transport adapters](architecture/provider-adapters.md).
|
|
52
|
+
|
|
53
|
+
## State and ownership
|
|
54
|
+
|
|
55
|
+
State schema version 1 contains environment, timestamps, resource identities, operation history and run journals. The server provider ID is recorded immediately after creation. DNS records are persisted one at a time. Remote resources carry script/config fingerprints and previous-state metadata.
|
|
56
|
+
|
|
57
|
+
State updates acquire a per-environment file lock, validate the whole document, preserve a backup, fsync a restricted temporary file and atomically rename it. Unsupported schemas/environment mismatches are rejected.
|
|
58
|
+
|
|
59
|
+
Names/tags help find resources, but provider IDs plus recorded ownership authorize destructive operations.
|
|
60
|
+
|
|
61
|
+
## Remote execution
|
|
62
|
+
|
|
63
|
+
Remote setup is stored in versioned Bash files under `lib/kitsune/kit/scripts`. `RemoteScript` fingerprints script bytes plus validated arguments, compares a remote marker, uploads through stdin-safe base64 transport, applies, verifies and records the marker.
|
|
64
|
+
|
|
65
|
+
SSH host verification is explicit. Commands and arguments are distinct at the transport boundary. Root and deploy transports are selected per operation; user bootstrap rollback deliberately uses root access.
|
|
66
|
+
|
|
67
|
+
Safety-critical SSH/firewall operations execute inside one preserved authenticated transport session while their postconditions are tested through separate fresh connections. The preserved session restores the captured policy if either fresh check fails.
|
|
68
|
+
|
|
69
|
+
## Services
|
|
70
|
+
|
|
71
|
+
`EnsureService` composes smaller collaborators for generated, overlay or custom Compose YAML, file
|
|
72
|
+
transactions/backups, firewall reconciliation, data backup and state transitions. The ordered Compose file set is
|
|
73
|
+
fingerprinted and persisted so recovery can restart the prior definition. Data lifecycle is deliberately separate
|
|
74
|
+
from container/config lifecycle.
|
|
75
|
+
|
|
76
|
+
An enabled service in `external` mode is configuration metadata, not an operation. It is visible through the
|
|
77
|
+
CLI but excluded from VPS plans, Docker, firewall, doctor port checks and destructive lifecycle methods.
|
|
78
|
+
|
|
79
|
+
## TUI
|
|
80
|
+
|
|
81
|
+
The initial TUI is a pure-Ruby ANSI backend with deterministic renderer/store/controller boundaries. It has no native dependency and can be replaced without changing workflows. Headless tests feed events and keys into the store/controller and compare stable rendered buffers.
|
|
82
|
+
|
|
83
|
+
## Decisions
|
|
84
|
+
|
|
85
|
+
Detailed accepted decisions are in [architecture/decisions](architecture/decisions):
|
|
86
|
+
|
|
87
|
+
- product boundary and direct 0.5 rewrite;
|
|
88
|
+
- core/interface separation;
|
|
89
|
+
- configuration/state/secrets;
|
|
90
|
+
- supported platforms;
|
|
91
|
+
- operation semantics;
|
|
92
|
+
- optional TUI backend.
|
|
93
|
+
- managed Compose customization boundary.
|
data/docs/commands.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Command reference
|
|
2
|
+
|
|
3
|
+
The authoritative runtime reference is `kit help`, `kit help COMMAND` and the equivalent `kit COMMAND help`.
|
|
4
|
+
This document explains the semantics and automation contract that short help cannot capture.
|
|
5
|
+
|
|
6
|
+
## Global options
|
|
7
|
+
|
|
8
|
+
Global options may be passed to infrastructure commands:
|
|
9
|
+
|
|
10
|
+
| Option | Meaning |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| `-e`, `--env NAME` | Select an environment for this invocation. |
|
|
13
|
+
| `--root PATH` | Project root containing `.kitsune/`. Defaults to the current directory. |
|
|
14
|
+
| `--config PATH` | Use an alternative base configuration file. |
|
|
15
|
+
| `--format human|json` | Select human or versioned machine output. |
|
|
16
|
+
| `--no-color` | Disable ANSI styling. `NO_COLOR` is also respected by the entrypoint environment. |
|
|
17
|
+
| `--no-input` | Never prompt; fail with an actionable error when confirmation is required. |
|
|
18
|
+
| `--yes` | Approve reviewed, non-destructive changes. It never confirms permanent data/server destruction. |
|
|
19
|
+
| `--dry-run` | Build/display the plan without applying it. |
|
|
20
|
+
| `--quiet` | Limit human output to important findings and summaries. |
|
|
21
|
+
| `--verbose` | Include additional domain-event detail. |
|
|
22
|
+
| `--debug` | Include technical context/stack information for failures. |
|
|
23
|
+
| `--log` / `--no-log` | Enable/disable restricted redacted local logs. Enabled by default. |
|
|
24
|
+
| `--timeout SECONDS` | Upper bound for each remote step, provider HTTP request and readiness wait; must be positive. |
|
|
25
|
+
| `--trust-host-key SHA256:...` | Trust only this exact first-seen SSH fingerprint. |
|
|
26
|
+
|
|
27
|
+
## Core workflow
|
|
28
|
+
|
|
29
|
+
### `kit init [--force]`
|
|
30
|
+
|
|
31
|
+
Creates `.kitsune/config.yml`, a development overlay and environment selection. Existing generated files cause exit 9 unless `--force` is explicit. It also appends runtime artifacts to `.gitignore`.
|
|
32
|
+
|
|
33
|
+
### `kit doctor`
|
|
34
|
+
|
|
35
|
+
Read-only checks include Ruby/runtime, configuration, SSH-key permissions, security defaults, provider credentials, state schema, exact server ownership, verified SSH access, Ubuntu version, passwordless sudo, Docker/Compose, listening ports and managed drift.
|
|
36
|
+
|
|
37
|
+
Statuses are `pass`, `warn`, or `fail`. Warnings do not make the command fail; any failed check returns exit 1.
|
|
38
|
+
|
|
39
|
+
### `kit plan`
|
|
40
|
+
|
|
41
|
+
Calculates changes without mutation. Details exclude provider key IDs and secrets. Actions are `create`, `update`, `delete` and `no_change`; plans flag destructive changes.
|
|
42
|
+
|
|
43
|
+
### `kit apply`
|
|
44
|
+
|
|
45
|
+
Builds a fresh plan, displays it, rejects destructive replacement and asks for confirmation. `--yes --no-input` is the automation form. `--dry-run` guarantees no mutation.
|
|
46
|
+
|
|
47
|
+
Every run and step is journaled. The provider ID is saved immediately after server creation; remote markers and local state are saved after verified operations.
|
|
48
|
+
Human output ends with the redacted local log path and a post-apply `doctor`/zero-change-plan next step. Failed or
|
|
49
|
+
cancelled applies report the last confirmed step, run ID and exact `kit resume RUN_ID` command. JSON carries the
|
|
50
|
+
same guidance as a `warning_emitted` event and never receives an extra human-output line.
|
|
51
|
+
|
|
52
|
+
### `kit resume [RUN_ID]`
|
|
53
|
+
|
|
54
|
+
Resumes the named run or latest incomplete run. It rejects successful runs and saved operation sets that no longer match configuration. Completed steps are skipped. Confirmation is required (`--yes` in automation).
|
|
55
|
+
|
|
56
|
+
### `kit status`
|
|
57
|
+
|
|
58
|
+
Displays the selected environment, exact provider server and locally tracked resources. It does not run remote diagnostics; use `doctor` for that.
|
|
59
|
+
|
|
60
|
+
### `kit rollback`
|
|
61
|
+
|
|
62
|
+
Runs rollback in reverse dependency order for resources recorded as managed. It preserves the Droplet and service data volumes. It is not a universal snapshot restore: provider resources or pre-existing files that Kitsune Kit never owned are not touched.
|
|
63
|
+
|
|
64
|
+
## Server
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
kit server show
|
|
68
|
+
kit server status
|
|
69
|
+
kit server create
|
|
70
|
+
kit server configure
|
|
71
|
+
kit server ssh
|
|
72
|
+
kit server import --provider-id DROPLET_ID --confirm-import SERVER_NAME
|
|
73
|
+
kit server destroy --confirm-destroy SERVER_NAME
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- `show`/`status`: inspect server and state.
|
|
77
|
+
- `create`: apply only the server operation.
|
|
78
|
+
- `configure`: apply remote, service and DNS operations after the server operation.
|
|
79
|
+
- `ssh`: verify the managed connection, then replace the process with the system `ssh` client using strict known-host checking.
|
|
80
|
+
- `import`: recover only the server identity after state loss. It requires an exact numeric Droplet ID and configured server-name confirmation, then verifies name, tags, region, size, image, active status and public IP. It never imports remote-resource ownership.
|
|
81
|
+
- `destroy`: delete only the exact recorded provider ID after verifying name/tags, then restore/remove managed DNS and clear state. If provider deletion fails, DNS is left untouched; if DNS cleanup fails afterward, retrying completes cleanup without deleting a second server. It never deletes by name alone.
|
|
82
|
+
|
|
83
|
+
Interactive destruction asks the operator to type the exact server name. Automation must use `--confirm-destroy SERVER_NAME`; `--yes` is insufficient.
|
|
84
|
+
Before an interactive confirmation, Kitsune Kit prints the environment, provider, resource, recorded provider ID and recoverability. JSON confirmation errors include the same safe target context.
|
|
85
|
+
|
|
86
|
+
## Docker
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
kit docker status
|
|
90
|
+
kit docker install
|
|
91
|
+
kit docker uninstall --yes
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Uninstall refuses to run while managed services remain. Docker installation uses the official apt repository and creates the `kitsune-private` network.
|
|
95
|
+
|
|
96
|
+
## Services
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
kit service postgres status
|
|
100
|
+
kit service postgres install
|
|
101
|
+
kit service postgres backup
|
|
102
|
+
kit service postgres remove --yes
|
|
103
|
+
kit service postgres destroy-data --backup-before-destroy --confirm-destroy postgres@ENV
|
|
104
|
+
kit service postgres compose show
|
|
105
|
+
kit service postgres compose validate
|
|
106
|
+
kit service postgres compose diff
|
|
107
|
+
kit service postgres compose eject
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Replace `postgres` with `redis` for Redis.
|
|
111
|
+
|
|
112
|
+
- `install`: service must be enabled and its secret environment variable present.
|
|
113
|
+
- `backup`: pauses the service, creates a restricted tar archive of the volume on the server and always unpauses it.
|
|
114
|
+
- `remove`: removes containers/network attachment and firewall rules owned by Kitsune Kit, but keeps the volume and managed files needed for recovery.
|
|
115
|
+
- `destroy-data`: optionally creates a restricted data archive, then removes containers, volume, owned
|
|
116
|
+
configuration backups/files and state. In an interactive terminal it offers the backup and requires typing
|
|
117
|
+
`TYPE@ENV`; automation can request it with `--backup-before-destroy` and must supply `--confirm-destroy`.
|
|
118
|
+
The data archive is retained outside the service directory, but must be copied to independent storage.
|
|
119
|
+
- `compose show`: print the exact generated/custom documents that would be uploaded, without resolving secrets.
|
|
120
|
+
- `compose validate`: parse the configured YAML and run Kitsune Kit's local structure and security checks.
|
|
121
|
+
- `compose diff`: compare the desired Compose fingerprint with the last applied state. An older state without a
|
|
122
|
+
Compose fingerprint is reported as not installed/unknown rather than guessed.
|
|
123
|
+
- `compose eject`: write `.kitsune/compose/TYPE.yml`, back up `config.yml` as `config.yml.backup`, and switch the
|
|
124
|
+
service to `custom`. It refuses existing targets unless `--force` is explicit.
|
|
125
|
+
|
|
126
|
+
When an enabled service has `mode: external`, `status` returns only its configured host/port and
|
|
127
|
+
`managed: false`. All local lifecycle actions fail safely; Kitsune Kit never treats an external provider's data as
|
|
128
|
+
a VPS Docker volume.
|
|
129
|
+
|
|
130
|
+
`install` and `apply` additionally run `docker compose config --quiet` on the server before starting containers.
|
|
131
|
+
For overlay mode every `--file` is passed in deterministic base-then-overlay order. See
|
|
132
|
+
[Compose customization](services/compose.md).
|
|
133
|
+
|
|
134
|
+
## DNS
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
kit dns list
|
|
138
|
+
kit dns plan
|
|
139
|
+
kit dns apply
|
|
140
|
+
kit dns remove --yes
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
DNS operations use exact record IDs and store original values. `remove` restores updated records and deletes only records created by Kitsune Kit.
|
|
144
|
+
|
|
145
|
+
## Environments
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
kit env list
|
|
149
|
+
kit env current
|
|
150
|
+
kit env use NAME
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`use` validates that `.kitsune/environments/NAME.yml` exists and writes the selection atomically. An explicit `--env`/`KITSUNE_ENV` wins without changing the persisted selection.
|
|
154
|
+
|
|
155
|
+
## Support
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
kit support bundle
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The human-readable command prints the complete redacted bundle after writing it, so it can be reviewed before
|
|
162
|
+
sharing. JSON mode returns the local path without adding non-JSON output. Kitsune Kit never uploads the bundle.
|
|
163
|
+
|
|
164
|
+
Creates a permission-restricted JSON file under `.kitsune/support/` with versions, platform, redacted configuration/state, doctor results and selected redacted logs. The path is printed; Kitsune Kit never uploads it. Inspect it before sharing.
|
|
165
|
+
|
|
166
|
+
## TUI
|
|
167
|
+
|
|
168
|
+
`kit ui` starts the optional full-screen interface. Bare `kit` does the same only with interactive stdin/stdout; otherwise it prints help. See [TUI](tui.md).
|
|
169
|
+
|
|
170
|
+
## Version
|
|
171
|
+
|
|
172
|
+
`kit version`, `kit --version` and `kit -v` print the installed Kitsune Kit version without loading project configuration or contacting a provider.
|
|
173
|
+
|
|
174
|
+
## JSON output
|
|
175
|
+
|
|
176
|
+
Successful workflow documents use schema version 1 and include:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"schema_version": 1,
|
|
181
|
+
"command": "plan",
|
|
182
|
+
"environment": "production",
|
|
183
|
+
"run_id": "...",
|
|
184
|
+
"status": "success",
|
|
185
|
+
"duration_ms": 12,
|
|
186
|
+
"result": {},
|
|
187
|
+
"warnings": [],
|
|
188
|
+
"events": []
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Errors are JSON on standard error:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"schema_version": 1,
|
|
197
|
+
"status": "failure",
|
|
198
|
+
"error": {
|
|
199
|
+
"code": "configuration_error",
|
|
200
|
+
"message": "...",
|
|
201
|
+
"hint": "...",
|
|
202
|
+
"context": {}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Treat unknown additive keys as forward-compatible, but reject unsupported `schema_version` values in consumers.
|
|
208
|
+
|
|
209
|
+
## Exit codes
|
|
210
|
+
|
|
211
|
+
| Code | Meaning |
|
|
212
|
+
| ---: | --- |
|
|
213
|
+
| 0 | Success, including a no-change plan/apply. |
|
|
214
|
+
| 1 | Unexpected failure or failed `doctor` check. |
|
|
215
|
+
| 2 | Invalid CLI syntax/unknown command. |
|
|
216
|
+
| 3 | Invalid/missing configuration or unsupported environment. |
|
|
217
|
+
| 4 | Authentication failure. |
|
|
218
|
+
| 5 | Provider API failure. |
|
|
219
|
+
| 6 | SSH/network connection failure. |
|
|
220
|
+
| 7 | Remote command failure. |
|
|
221
|
+
| 8 | Post-change verification failure. |
|
|
222
|
+
| 9 | Unsafe operation or missing confirmation. |
|
|
223
|
+
| 10 | Timeout. |
|
|
224
|
+
| 130 | Interrupted by `SIGINT`. |
|