Compare commits
2 Commits
4c86472740
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c4299118f7 | |||
| e648bc4dc6 |
@@ -1,71 +1,63 @@
|
|||||||
# wireguard-admin
|
# wireguard-admin
|
||||||
|
|
||||||
This repository contains a root-only native terminal interface for one existing
|
This repository contains a root-only native terminal interface for one existing WireGuard interface and configurable systemd service. It connects the validated settings loader, byte-preserving server configuration editor, encrypted client vault, recoverable saved-file persistence, backups, Commit, previewed restore, explicit restart, read-only runtime statistics, and client file/QR delivery. The interface keeps draft, saved, and applied states distinct. Commit saves files; restore replaces saved state; only an explicit, verified restart applies saved changes to the running interface.
|
||||||
WireGuard interface and configurable systemd service. It connects the validated
|
|
||||||
settings loader, byte-preserving server configuration editor, encrypted client
|
|
||||||
vault, recoverable saved-file persistence, backups, Commit, previewed restore,
|
|
||||||
explicit restart, read-only runtime statistics, and client file/QR delivery.
|
|
||||||
The interface keeps draft, saved, and applied states distinct. Commit saves
|
|
||||||
files; restore replaces saved state; only an explicit, verified restart applies
|
|
||||||
saved changes to the running interface.
|
|
||||||
|
|
||||||
The package requires Rust 1.97.1 or newer and uses the Rust 2024 edition. From
|
The package requires Rust 1.97.1 or newer and uses the Rust 2024 edition. From the repository root, run:
|
||||||
the repository root, run:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cargo run -- --help
|
cargo run -- --help
|
||||||
cargo run -- --version
|
cargo run -- --version
|
||||||
```
|
```
|
||||||
|
|
||||||
`--help` and `--version` work without root, settings, or a terminal. Starting
|
`--help` and `--version` work without root, settings, or a terminal. Starting with no arguments requires root and a suitable interactive terminal. Settings are read from `wireguard-admin.toml` beside the executable. If terminal checks or saved-state recovery fail, startup exits before entering raw mode or performing setup mutations.
|
||||||
with no arguments requires root and a suitable interactive terminal. Settings
|
|
||||||
are read from `wireguard-admin.toml` beside the executable. If terminal checks
|
|
||||||
or saved-state recovery fail, startup exits before entering raw mode or
|
|
||||||
performing setup mutations.
|
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
Settings use TOML in the fixed file `wireguard-admin.toml` beside the
|
Copy this example to `wireguard-admin.toml` beside the executable. Adapt every address, range, path, interface name, and service name to the existing server; `192.0.2.1` is a documentation address, not a usable public endpoint. This configuration manages an existing WireGuard interface and systemd service; it does not create either one.
|
||||||
executable. Start from [`config/wireguard-admin.example.toml`](config/wireguard-admin.example.toml).
|
|
||||||
The required fields are:
|
|
||||||
|
|
||||||
- `interface_name`: existing WireGuard interface name (1–15 ASCII characters).
|
```toml
|
||||||
- `server_config_path`: path to the existing server configuration.
|
# Copy this file to wireguard-admin.toml beside the wireguard-admin executable.
|
||||||
- `client_source_directory`: directory containing existing client files.
|
# Relative paths are resolved from that executable directory, never from the
|
||||||
- `server_endpoint`: hostname or IPv4 address followed by `:port`, or IPv6 in
|
# process working directory. This example uses documentation-only addresses.
|
||||||
brackets followed by `:port` (for example, `[2001:db8::2]:51820`).
|
|
||||||
- `ipv4_allocation_range` and `ipv6_allocation_range`: CIDR ranges of the
|
|
||||||
matching address family.
|
|
||||||
- `dns_addresses`: non-empty list of IPv4 and/or IPv6 literal addresses.
|
|
||||||
- `systemd_unit`: service unit name ending in `.service`.
|
|
||||||
- `restart_timeout_seconds`: positive integer.
|
|
||||||
|
|
||||||
`data_root` is optional. It defaults to `Backup` beside the executable;
|
interface_name = "wg0"
|
||||||
current internal data and the encrypted vault are under `data`, and archives
|
server_config_path = "/etc/wireguard/wg0.conf"
|
||||||
are under `archives`. Relative configured paths, including an explicit
|
client_source_directory = "clients"
|
||||||
`data_root`, resolve from the executable directory. Absolute paths remain
|
server_endpoint = "37.26.136.232:51820"
|
||||||
absolute. Settings validation checks syntax and values only; it does not
|
ipv4_allocation_range = "10.9.0.0/24"
|
||||||
require the referenced files, directories, or service to exist and does not
|
ipv6_allocation_range = "2001:db8:1::/64"
|
||||||
perform DNS lookups.
|
dns_addresses = ["10.9.0.1", "192.168.0.200"]
|
||||||
|
systemd_unit = "wg-quick@wg0.service"
|
||||||
|
restart_timeout_seconds = 30
|
||||||
|
|
||||||
For installation, backup custody, restart failure handling and manual recovery,
|
# Optional. Defaults to Backup beside the executable. The application stores
|
||||||
see [`docs/OPERATIONS.md`](docs/OPERATIONS.md). The qualified evidence and the
|
# current data in <data_root>/data and archives in <data_root>/archives.
|
||||||
current host release-candidate assessment are in
|
# data_root = "Backup"
|
||||||
[`docs/RELEASE_READINESS.md`](docs/RELEASE_READINESS.md); those records do not
|
```
|
||||||
claim a completed systemd VM run or real IPv6 qualification.
|
|
||||||
|
The parser requires every uncommented field above and rejects unknown fields.
|
||||||
|
The example values are **not defaults**. Only `data_root` has a default.
|
||||||
|
|
||||||
|
| Parameter | Required? | Purpose and validated constraints |
|
||||||
|
| ------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `interface_name` | Yes | Name of the existing WireGuard interface. Must be 1–15 ASCII letters, digits, `.`, `_`, or `-`; `.` and `..` are rejected. |
|
||||||
|
| `server_config_path` | Yes | Path to the existing, authoritative server configuration. Must be non-empty. The settings parser does not check that the file exists; startup validates the saved installation. |
|
||||||
|
| `client_source_directory` | Yes | Directory of original client configuration files used for initial vault import and explicit selected-file import. Must be non-empty. Scans consider immediate regular `.conf` files without following symlinks; originals are neither modified nor deleted. |
|
||||||
|
| `server_endpoint` | Yes | Address and port written to generated client configurations: a hostname or IPv4 address followed by `:port`, or an IPv6 address in brackets followed by `:port`. Port must be 1–65535. Hostnames are syntax-checked but not resolved during settings validation. |
|
||||||
|
| `ipv4_allocation_range` | Yes | IPv4 CIDR range from which new-client IPv4 addresses are allocated. Must parse as an IPv4 CIDR network. |
|
||||||
|
| `ipv6_allocation_range` | Yes | IPv6 CIDR range from which new-client IPv6 addresses are allocated. Must parse as an IPv6 CIDR network. |
|
||||||
|
| `dns_addresses` | Yes | Non-empty list of IPv4 and/or IPv6 literal DNS server addresses included in generated client configurations. This does not configure the host's DNS settings. Hostnames are rejected. |
|
||||||
|
| `systemd_unit` | Yes | Existing systemd service targeted by an explicitly requested restart. Must end in `.service`, be at most 255 ASCII bytes, and use only letters, digits, `.`, `_`, `-`, `@`, or `:`; paths and whitespace are rejected. |
|
||||||
|
| `restart_timeout_seconds` | Yes | Positive integer number of seconds for the shared restart deadline. After the mandatory backup, it covers systemd connection, subscription, unit resolution, request and job completion, then the runtime interface read and verification deadline check. It does not time the precautionary backup or durable verification-state write. |
|
||||||
|
| `data_root` | No | Non-empty root directory for application data. Defaults to `Backup` beside the executable. Current internal data and the encrypted vault are stored in `<data_root>/data`; archives are stored in `<data_root>/archives`. |
|
||||||
|
|
||||||
|
The settings file name and location are fixed: `wireguard-admin.toml` must sit beside the executable, regardless of the process working directory. Relative values for `server_config_path`, `client_source_directory`, and `data_root` resolve from that executable directory; absolute paths stay absolute. Settings validation checks syntax and values without checking referenced paths or the service for existence. Commit and Restore change saved state only. Restart is separate and explicit; only successful service completion followed by matching interface/client verification and durable bookkeeping marks the saved state applied. The separate [`config/wireguard-admin.example.toml`](config/wireguard-admin.example.toml) is another example, with different illustrative values.
|
||||||
|
|
||||||
|
For installation, backup custody, restart failure handling and manual recovery, see [`docs/OPERATIONS.md`](docs/OPERATIONS.md). The qualified evidence and the current host release-candidate assessment are in [`docs/RELEASE_READINESS.md`](docs/RELEASE_READINESS.md); those records do not claim a completed systemd VM run or real IPv6 qualification.
|
||||||
|
|
||||||
## Terminal workflows
|
## Terminal workflows
|
||||||
|
|
||||||
The bordered **Keys** panel at the bottom of the screen shows shortcuts for the
|
The bordered **Keys** panel at the bottom of the screen shows shortcuts for the current screen and form. On narrow list and details screens it prioritizes navigation and Help, and indicates when additional actions are omitted; resize the terminal to see more. Forms, QR disclosure and progress show only their applicable controls. Press `?` from the list or details screen to open Help, which contains the complete shortcut reference. The client list supports arrow-key selection, Enter for details, and `q` to exit. Exit warns when a draft would be discarded; it never commits implicitly. Uppercase shortcuts are distinct from lowercase shortcuts (`R` previews restart, while `r` renames; `B` creates a backup, while `b` lists backups):
|
||||||
current screen and form. On narrow list and details screens it prioritizes
|
|
||||||
navigation and Help, and indicates when additional actions are omitted; resize
|
|
||||||
the terminal to see more. Forms, QR disclosure and progress show only their
|
|
||||||
applicable controls. Press `?` from the list or details screen to open Help,
|
|
||||||
which contains the complete shortcut reference. The client list supports
|
|
||||||
arrow-key selection, Enter for details, and `q` to exit. Exit warns when a draft
|
|
||||||
would be discarded; it never commits implicitly. Uppercase shortcuts are
|
|
||||||
distinct from lowercase shortcuts (`R` previews restart, while `r` renames;
|
|
||||||
`B` creates a backup, while `b` lists backups):
|
|
||||||
|
|
||||||
| Key | Action |
|
| Key | Action |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -79,43 +71,15 @@ distinct from lowercase shortcuts (`R` previews restart, while `r` renames;
|
|||||||
| `s` / `i` | Initial vault setup / import one selected client file |
|
| `s` / `i` | Initial vault setup / import one selected client file |
|
||||||
| `!` | Inspect document and peer anomalies |
|
| `!` | Inspect document and peer anomalies |
|
||||||
|
|
||||||
The list header labels **Draft**, **Saved**, and **Applied** separately. Draft
|
The list header labels **Draft**, **Saved**, and **Applied** separately. Draft reports pending changes even when only vault or managed metadata changed. Saved counts peer sections in the saved server file, including peers this manager cannot edit, and separately counts managed clients. Applied reports verification of the saved configuration; a draft is excluded. “Not verified” does not claim that a restart is pending when that divergence is unknown. A saved peer row does not prove active access, and handshake or traffic counters are observations, not proof that the saved configuration was applied. Details distinguish document or peer problems from valid configuration shapes that are currently outside the management model.
|
||||||
reports pending changes even when only vault or managed metadata changed. Saved
|
|
||||||
counts peer sections in the saved server file, including peers this manager
|
|
||||||
cannot edit, and separately counts managed clients. Applied reports verification
|
|
||||||
of the saved configuration; a draft is excluded. “Not verified” does not claim
|
|
||||||
that a restart is pending when that divergence is unknown. A saved peer row does
|
|
||||||
not prove active access, and handshake or traffic counters are observations,
|
|
||||||
not proof that the saved configuration was applied. Details distinguish
|
|
||||||
document or peer problems from valid configuration shapes that are currently
|
|
||||||
outside the management model.
|
|
||||||
|
|
||||||
In Help, Up/Down scroll by one displayed row and PageUp/PageDown move by the
|
In Help, Up/Down scroll by one displayed row and PageUp/PageDown move by the visible page. The Help panel shows the current row range and clamps navigation when the terminal is resized. Press `?` to return to the beginning or Esc to return to the client list without changing the selected peer or application state.
|
||||||
visible page. The Help panel shows the current row range and clamps navigation
|
|
||||||
when the terminal is resized. Press `?` to return to the beginning or Esc to
|
|
||||||
return to the client list without changing the selected peer or application
|
|
||||||
state.
|
|
||||||
|
|
||||||
Forms use Enter to advance or submit, Tab to change fields/options, and Esc to
|
Forms use Enter to advance or submit, Tab to change fields/options, and Esc to cancel. Backup restore previews identify the selected archive and require an explicit confirmation. Restore does not prompt for the vault password and does not restart WireGuard. Client configuration output is a disclosure: first delivery requires a successful Commit in the same session; QR appears only after file publication. Esc closes and clears a QR disclosure. Help in the interface contains the full current shortcut list.
|
||||||
cancel. Backup restore previews identify the selected archive and require an
|
|
||||||
explicit confirmation. Restore does not prompt for the vault password and does
|
|
||||||
not restart WireGuard. Client configuration output is a disclosure: first
|
|
||||||
delivery requires a successful Commit in the same session; QR appears only
|
|
||||||
after file publication. Esc closes and clears a QR disclosure. Help in the
|
|
||||||
interface contains the full current shortcut list.
|
|
||||||
|
|
||||||
## Library configuration API
|
## Library configuration API
|
||||||
|
|
||||||
The library exposes `wireguard_admin::wireguard::ConfigDocument` for UTF-8
|
The library exposes `wireguard_admin::wireguard::ConfigDocument` for UTF-8 configuration bytes supplied by the caller. It retains the source and renders unmodified input byte-for-byte, including line endings and a missing final newline. Peer inspection exposes public identities, parsed `AllowedIPs`, spans, and redacted issues; arbitrary directive values are not included in the view. The edit methods `add_client`, `delete_client`, `rename_client`, and `insert_legacy_metadata` return new in-memory documents. They do not read or write files, save changes, or alter the running VPN. See [`docs/CONFIG_FORMAT.md`](docs/CONFIG_FORMAT.md) for the managed metadata block format.
|
||||||
configuration bytes supplied by the caller. It retains the source and renders
|
|
||||||
unmodified input byte-for-byte, including line endings and a missing final
|
|
||||||
newline. Peer inspection exposes public identities, parsed `AllowedIPs`, spans,
|
|
||||||
and redacted issues; arbitrary directive values are not included in the view.
|
|
||||||
The edit methods `add_client`, `delete_client`, `rename_client`, and
|
|
||||||
`insert_legacy_metadata` return new in-memory documents. They do not read or
|
|
||||||
write files, save changes, or alter the running VPN. See
|
|
||||||
[`docs/CONFIG_FORMAT.md`](docs/CONFIG_FORMAT.md) for the managed metadata block
|
|
||||||
format.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -127,76 +91,25 @@ let updated = document.rename_client(&public_key, "office laptop")?;
|
|||||||
let bytes_to_review = updated.render(); // no persistence or VPN operation
|
let bytes_to_review = updated.render(); // no persistence or VPN operation
|
||||||
```
|
```
|
||||||
|
|
||||||
Runtime and restart behavior has synthetic fixture and fake-adapter coverage;
|
Runtime and restart behavior has synthetic fixture and fake-adapter coverage; the accepted Alpine milestone also exercised real IPv4 WireGuard traffic and the Rustix reader. The Alpine fixture did not use systemd/D-Bus, and the retired systemd VM milestone did not establish real-system acceptance. Real IPv6 capability and traffic remain unverified.
|
||||||
the accepted Alpine milestone also exercised real IPv4 WireGuard traffic and
|
|
||||||
the Rustix reader. The Alpine fixture did not use systemd/D-Bus, and the
|
|
||||||
disposable systemd VM milestone has not been run. Real IPv6 capability and
|
|
||||||
traffic remain unverified.
|
|
||||||
|
|
||||||
## Saved state, Commit, and backups
|
## Saved state, Commit, and backups
|
||||||
|
|
||||||
wireguard_admin::app::Application opens saved files through
|
wireguard_admin::app::Application opens saved files through wireguard_admin::persistence::SavedStore, stages client and vault changes, creates manual and mandatory operation backups, and previews/confirms a full restore. Commit writes saved files only. Restore also changes saved files only; neither operation reloads or restarts WireGuard. The server file is kept at its trusted configured path, while internal state and the encrypted vault are kept under Backup/data by default. Archives are stored under Backup/archives and contain fixed logical members, not source client files or prior archives.
|
||||||
wireguard_admin::persistence::SavedStore, stages client and vault changes,
|
|
||||||
creates manual and mandatory operation backups, and previews/confirms a full
|
|
||||||
restore. Commit writes saved files only. Restore also changes saved files only;
|
|
||||||
neither operation reloads or restarts WireGuard. The server file is kept at its
|
|
||||||
trusted configured path, while internal state and the encrypted vault are kept
|
|
||||||
under Backup/data by default. Archives are stored under Backup/archives and
|
|
||||||
contain fixed logical members, not source client files or prior archives.
|
|
||||||
|
|
||||||
The persistence journal recovers interrupted file replacement on reopen and
|
The persistence journal recovers interrupted file replacement on reopen and returns a recovery error while earlier work remains unresolved. A confirmed restart marks the saved generation applied only after a successful service job, a matching complete runtime observation, and journaled verification-state write. Restoring a backup does not restore runtime state: the running interface is unknown until a later explicit restart and verification. Pending deleted-client addresses remain reserved through Commit, reopen, and restore. See [docs/BACKUP_FORMAT.md](docs/BACKUP_FORMAT.md) and [docs/PERSISTENCE.md](docs/PERSISTENCE.md) for archive and recovery details, and [docs/RUNTIME.md](docs/RUNTIME.md) for observation and restart boundaries.
|
||||||
returns a recovery error while earlier work remains unresolved. A confirmed
|
|
||||||
restart marks the saved generation applied only after a successful service job,
|
|
||||||
a matching complete runtime observation, and journaled verification-state write.
|
|
||||||
Restoring a backup does not restore runtime state: the running interface is
|
|
||||||
unknown until a later explicit restart and verification. Pending deleted-client
|
|
||||||
addresses remain reserved through Commit, reopen, and restore. See
|
|
||||||
[docs/BACKUP_FORMAT.md](docs/BACKUP_FORMAT.md) and
|
|
||||||
[docs/PERSISTENCE.md](docs/PERSISTENCE.md) for archive and recovery details,
|
|
||||||
and [docs/RUNTIME.md](docs/RUNTIME.md) for observation and restart boundaries.
|
|
||||||
|
|
||||||
## Vault and existing-client import library
|
## Vault and existing-client import library
|
||||||
|
|
||||||
`wireguard_admin::vault` provides WireGuard key handling, an encrypted versioned
|
`wireguard_admin::vault` provides WireGuard key handling, an encrypted versioned vault bundle, caller-buffer client configuration parsing, and reconciliation against a supplied server document. The source adapter can prepare an initial encrypted bundle or explicitly import candidates into an existing prepared bundle. These operations return in-memory data only: they do not install or save a vault, edit source files or server configuration, Commit, or touch the VPN.
|
||||||
vault bundle, caller-buffer client configuration parsing, and reconciliation
|
|
||||||
against a supplied server document. The source adapter can prepare an initial
|
|
||||||
encrypted bundle or explicitly import candidates into an existing prepared
|
|
||||||
bundle. These operations return in-memory data only: they do not install or save
|
|
||||||
a vault, edit source files or server configuration, Commit, or touch the VPN.
|
|
||||||
|
|
||||||
Directory scans use the resolved `client_source_directory` only. A candidate is
|
Directory scans use the resolved `client_source_directory` only. A candidate is an immediate regular file whose name ends in `.conf` (case-insensitive); the adapter does not recurse, follow symlinks, or read files larger than 1 MiB. A scan is limited to 4,096 directory entries, 1,024 candidates, and 32 MiB total input. Per-file failures are redacted and do not prevent other files from being examined. Enumeration, read, or limit failures mark the scan incomplete. The original files remain untouched. Adapter examples and behavior are covered with synthetic temporary directories in `tests/vault_import.rs`.
|
||||||
an immediate regular file whose name ends in `.conf` (case-insensitive); the
|
|
||||||
adapter does not recurse, follow symlinks, or read files larger than 1 MiB. A
|
|
||||||
scan is limited to 4,096 directory entries, 1,024 candidates, and 32 MiB total
|
|
||||||
input. Per-file failures are redacted and do not prevent other files from being
|
|
||||||
examined. Enumeration, read, or limit failures mark the scan incomplete. The
|
|
||||||
original files remain untouched. Adapter examples and behavior are covered with
|
|
||||||
synthetic temporary directories in `tests/vault_import.rs`.
|
|
||||||
|
|
||||||
## Client delivery and reissue
|
## Client delivery and reissue
|
||||||
|
|
||||||
`Application::prepare_new_client` stages a dual-stack peer and encrypted key.
|
`Application::prepare_new_client` stages a dual-stack peer and encrypted key. After a successful `commit`, `deliver_first_issue_file` can publish its first configuration without a vault password during that same session; a failed file publication can be retried to a newly selected destination. The first file is mandatory. `deliver_first_issue_file_and_qr` optionally returns a QR matrix from the same authorized bytes after file publication. Both success results carry an activation warning unless this session has verified the exact installed saved generation and its matching applied peer snapshot; historical verification and unknown runtime state do not suppress it.
|
||||||
After a successful `commit`, `deliver_first_issue_file` can publish its first
|
|
||||||
configuration without a vault password during that same session; a failed file
|
|
||||||
publication can be retried to a newly selected destination. The first file is
|
|
||||||
mandatory. `deliver_first_issue_file_and_qr` optionally returns a QR matrix from
|
|
||||||
the same authorized bytes after file publication. Both success results carry an
|
|
||||||
activation warning unless this session has verified the exact installed saved
|
|
||||||
generation and its matching applied peer snapshot; historical verification and
|
|
||||||
unknown runtime state do not suppress it.
|
|
||||||
|
|
||||||
Later delivery uses `Application::reissue_client_file`, which takes the client
|
Later delivery uses `Application::reissue_client_file`, which takes the client public key, a password for that action, a prepared destination, and an optional QR choice. It freshly unlocks the installed saved vault each time, reads saved server/settings bytes rather than draft state, preserves validated imported parameters, and rejects blocked or stale records. It never reads original plaintext client files as a fallback. The result reports a secret-free failure stage and warns when the current saved peer set has not been verified as applied in this live session. Historical verification timestamps do not suppress that warning after reopen. File output uses mode `0600`, explicit overwrite confirmation, and separate QR failure reporting. These APIs and the TUI password prompt/terminal QR display have synthetic fixture coverage. No production configuration or key is included in the repository.
|
||||||
public key, a password for that action, a prepared destination, and an optional
|
|
||||||
QR choice. It freshly unlocks the installed saved vault each time, reads saved
|
|
||||||
server/settings bytes rather than draft state, preserves validated imported
|
|
||||||
parameters, and rejects blocked or stale records. It never reads original
|
|
||||||
plaintext client files as a fallback. The result reports a secret-free failure
|
|
||||||
stage and warns when the current saved peer set has not been verified as applied
|
|
||||||
in this live session. Historical verification timestamps do not suppress that
|
|
||||||
warning after reopen. File output uses mode `0600`, explicit overwrite
|
|
||||||
confirmation, and separate QR failure reporting. These APIs and the TUI
|
|
||||||
password prompt/terminal QR display have synthetic fixture coverage. No
|
|
||||||
production configuration or key is included in the repository.
|
|
||||||
|
|
||||||
## Test commands and integration limits
|
## Test commands and integration limits
|
||||||
|
|
||||||
@@ -207,19 +120,6 @@ cargo test --locked --test tui_workflow
|
|||||||
cargo test --locked tui::
|
cargo test --locked tui::
|
||||||
```
|
```
|
||||||
|
|
||||||
The first exercises setup, client staging, Commit, delivery, backup listing,
|
The first exercises setup, client staging, Commit, delivery, backup listing, and restore through the serialized worker with temporary files and a fake statistics reader. The second covers navigation/forms/rendering, delayed worker behavior, terminal lifecycle seams, and QR sizing. Neither command starts the management UI or uses host service/runtime mutation. See [`docs/TESTING.md`](docs/TESTING.md) for full gates and the isolated Alpine (M8) and disposable systemd VM (M9) boundaries. An actual PTY smoke run using synthetic application/runtime adapters is included in `tui_workflow`; it uses `script` and a fake unavailable-statistics reader, without root or host settings. It checks an 80×24 to 40×8 to 80×24 resize sequence and terminal cleanup after `q`. The workflow also checks that Esc clears a returned QR disclosure; the
|
||||||
and restore through the serialized worker with temporary files and a fake
|
focused renderer test checks complete quiet-zone fit. Do not use the development host's settings or VPN as a substitute. M1–M8 qualification evidence and the remaining M9 limitations are summarized in [`docs/RELEASE_READINESS.md`](docs/RELEASE_READINESS.md).
|
||||||
statistics reader. The second covers navigation/forms/rendering, delayed worker
|
|
||||||
behavior, terminal lifecycle seams, and QR sizing. Neither command starts the
|
|
||||||
management UI or uses host service/runtime mutation. See
|
|
||||||
[`docs/TESTING.md`](docs/TESTING.md) for full gates and the isolated Alpine
|
|
||||||
(M8) and disposable systemd VM (M9) boundaries. An actual PTY smoke run using
|
|
||||||
synthetic application/runtime adapters is included in `tui_workflow`; it uses
|
|
||||||
`script` and a fake unavailable-statistics reader, without root or host settings.
|
|
||||||
It checks an 80×24 to 40×8 to 80×24 resize sequence and terminal cleanup after
|
|
||||||
`q`. The workflow also checks that Esc clears a returned QR disclosure; the
|
|
||||||
focused renderer test checks complete quiet-zone fit. Do not use the development
|
|
||||||
host's settings or VPN as a substitute.
|
|
||||||
M1–M8 qualification evidence and the remaining M9 limitations are summarized
|
|
||||||
in [`docs/RELEASE_READINESS.md`](docs/RELEASE_READINESS.md).
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user