1595 lines
55 KiB
Markdown
1595 lines
55 KiB
Markdown
# WireGuard Manager — implementation milestones
|
|
|
|
## 1. Purpose of this document
|
|
|
|
This file is the sequential implementation plan for the MVP described in `MVP.md`.
|
|
It is written so that a coding agent with limited project context can complete one milestone at a time without redesigning the project.
|
|
|
|
The source-of-truth order is:
|
|
|
|
1. `AGENTS.md` — engineering and safety rules.
|
|
2. `MVP.md` — product scope and expected behavior.
|
|
3. `PLANS.md` — implementation sequence and verification checkpoints.
|
|
4. Existing code and tests — current implementation state.
|
|
|
|
If these documents conflict, stop and resolve the conflict before changing production behavior.
|
|
|
|
## 2. Required Codex workflow
|
|
|
|
For every milestone, follow this loop:
|
|
|
|
1. Read `AGENTS.md`, `MVP.md`, and the complete current milestone.
|
|
2. Inspect the existing files and `git status` before editing.
|
|
3. Confirm that all prerequisite milestones are complete.
|
|
4. Mark the current milestone as `IN PROGRESS` in the progress table.
|
|
5. Follow the multi-agent protocol in section 2.2 and delegate only the scope listed under **Changes** to Luna.
|
|
6. Ensure the Luna worker adds or updates tests in the same milestone as the behavior.
|
|
7. Run every command under **Verification**.
|
|
8. If any check fails, repair it and rerun the complete milestone verification.
|
|
9. Review the diff for scope creep, unsafe paths, and leaked secrets.
|
|
10. Perform the listed manual checks when the environment supports them.
|
|
11. Mark the milestone `DONE` only after all acceptance criteria pass.
|
|
12. Add a short entry to **Execution log** with decisions, checks, and known limitations.
|
|
13. Report the suggested commit message; do not create a commit unless the user asks.
|
|
|
|
Stop-and-fix rule:
|
|
|
|
- Never move to the next milestone while a required verification is failing.
|
|
- Never weaken or delete a test merely to make a milestone pass.
|
|
- If a command cannot run because an optional tool is absent, record `SKIP` and run the documented fallback.
|
|
- If a required dependency or safe test environment is missing, stop and report the exact blocker.
|
|
- Never test mutations against the host's real `/etc/wireguard` configuration.
|
|
- Run Git-specific checks only when the directory is already a Git worktree.
|
|
- If it is not a Git worktree, record those checks as `SKIP`; do not initialize Git unless the user asks.
|
|
|
|
## 2.1. Development environment constraint
|
|
|
|
The development machine does not have a WireGuard server installed or configured.
|
|
This is an expected project constraint, not a blocker.
|
|
|
|
Apply these rules to every milestone:
|
|
|
|
- Required verification must run without `wg`, `wg-quick`, a WireGuard kernel interface, root access, systemd, firewall access, or `/etc/wireguard`.
|
|
- Tests must use fixtures plus executable mocks placed first in a test-only `PATH`.
|
|
- Tests must use an isolated temporary root for configs, clients, metadata, backups, logs, locks, and archives.
|
|
- No required test may inspect or depend on the development machine's actual networking, routes, firewall, services, sysctl values, or journal.
|
|
- The absence of real WireGuard commands on the development machine is not grounds for marking a milestone `BLOCKED`.
|
|
- Mock behavior must cover successful output, malformed output, missing command, nonzero exit, timeout where relevant, apply failure, and rollback failure.
|
|
- Command-contract tests must assert the exact argument arrays passed to external tools.
|
|
- A test must fail if production code bypasses the mock directory and invokes a host networking command.
|
|
- Real WireGuard integration checks are deferred to the deployment server and are not required to mark development milestones complete.
|
|
- Deployment checks remain documented so they can be run manually after the project is copied to a disposable or non-production WireGuard environment.
|
|
- Real-server observations must never be fabricated from mock results.
|
|
- Optional smoke tests with a real `gum`, `qrencode`, or ShellCheck may run when those tools are present, but their absence is not a product failure.
|
|
|
|
## 2.2. Required multi-agent milestone orchestration
|
|
|
|
Every milestone implementation uses a senior coordinator and lower-cost execution subagents.
|
|
|
|
### Agent roles
|
|
|
|
- The primary coordinator uses `gpt-5.6-sol` with `high` reasoning.
|
|
- Initial implementation is delegated to the project agent `milestone_worker`.
|
|
- Every implementation subagent must explicitly use `gpt-5.6-luna`.
|
|
- Corrections after review are delegated to `milestone_repairer` on `gpt-5.6-luna`.
|
|
- The project defaults are stored in `.codex/config.toml`.
|
|
- The custom subagent definitions are stored in `.codex/agents/`.
|
|
- An explicit host or user model override can take precedence over project defaults; do not silently claim the configured model was used when the host reports otherwise.
|
|
- If a milestone starts in a primary session explicitly running a model other than `gpt-5.6-sol`, stop before implementation and request a Sol session or explicit user direction.
|
|
|
|
### Coordinator responsibilities
|
|
|
|
The Sol coordinator must:
|
|
|
|
1. Read `AGENTS.md`, `MVP.md`, the complete current milestone, current progress, and the current worktree state.
|
|
2. Confirm prerequisites and select exactly one milestone.
|
|
3. Mark it `IN PROGRESS` before delegation.
|
|
4. Break the milestone into bounded tasks with explicit files, behavior, constraints, acceptance criteria, and verification commands.
|
|
5. Delegate implementation to `milestone_worker` with `model = gpt-5.6-luna` explicitly selected.
|
|
6. Use multiple Luna workers only when their work is independent and they will not edit the same files.
|
|
7. Prefer sequential delegation for write-heavy work in `wg-manager.sh` to avoid conflicting edits.
|
|
8. Wait for every delegated task to finish before reviewing the combined result.
|
|
9. Inspect the actual files and diff; never accept only the subagent's summary.
|
|
10. Run or independently confirm every milestone verification command.
|
|
11. Review behavior, tests, quoting, path safety, secret handling, rollback, mock isolation, and acceptance criteria.
|
|
12. Decide whether the milestone passes, needs Luna repair, or is genuinely blocked.
|
|
13. Keep the milestone `IN PROGRESS` throughout all repair cycles.
|
|
14. Mark it `DONE` only after the complete verification gate passes and no material review findings remain.
|
|
15. Update the execution log and report the suggested commit message.
|
|
|
|
The coordinator owns architecture, scope, review, and completion decisions.
|
|
It must not outsource the final acceptance decision to Luna.
|
|
|
|
### Initial Luna assignment contract
|
|
|
|
Each `milestone_worker` prompt must include:
|
|
|
|
- the exact milestone identifier and title;
|
|
- the milestone goal;
|
|
- prerequisites already satisfied;
|
|
- files the worker may edit;
|
|
- files or systems it must not touch;
|
|
- the required implementation steps;
|
|
- the development-machine constraint;
|
|
- required fixtures and mocks;
|
|
- exact verification commands;
|
|
- acceptance criteria relevant to the delegated task;
|
|
- the required return format: changed files, tests, command results, uncertainties, and blockers.
|
|
|
|
Do not delegate a vague request such as “implement the next milestone.”
|
|
The Luna task must be concrete enough to execute without making architecture decisions.
|
|
|
|
### Mandatory Sol review gate
|
|
|
|
After Luna finishes, the Sol coordinator must perform all of these checks:
|
|
|
|
1. Read the returned summary, but treat it only as a navigation aid.
|
|
2. Inspect every changed file and the complete diff.
|
|
3. Confirm no unrelated file or user change was overwritten.
|
|
4. Confirm the implementation matches the assigned milestone rather than only passing tests.
|
|
5. Confirm tests cover success, expected failure, rollback, and unsafe input where applicable.
|
|
6. Confirm all host interactions remain behind mocks in development verification.
|
|
7. Confirm no private key, preshared key, client config, real endpoint, or secret appears in output or fixtures.
|
|
8. Run the milestone's full required verification, not only the worker's focused tests.
|
|
9. Inspect test output and exit codes rather than relying on a verbal “passed” claim.
|
|
10. Check `git diff --check` when the directory is a Git worktree.
|
|
11. Compare the result against every acceptance criterion.
|
|
12. Record concrete findings with file paths, observed behavior, expected behavior, and reproduction commands.
|
|
|
|
### Luna repair loop
|
|
|
|
If the Sol review finds any material problem:
|
|
|
|
1. Do not fix the implementation silently in the coordinator thread.
|
|
2. Keep the milestone status `IN PROGRESS`.
|
|
3. Delegate a repair task to `milestone_repairer` with `model = gpt-5.6-luna` explicitly selected.
|
|
4. Provide each finding in this format:
|
|
- location or affected behavior;
|
|
- what is wrong;
|
|
- expected result;
|
|
- reproduction or failing verification command;
|
|
- constraints that the repair must preserve.
|
|
5. Require a regression test for every reproducible defect.
|
|
6. Wait for the repairer to finish.
|
|
7. Reinspect the actual diff and rerun the complete milestone verification as Sol.
|
|
8. Repeat the Luna repair cycle for remaining or newly introduced findings.
|
|
9. Stop only when the milestone passes or a genuine external blocker prevents further safe progress.
|
|
|
|
Do not impose an arbitrary retry count.
|
|
Repeated failures are handled by making the next repair prompt more specific with evidence from the latest review.
|
|
If the same blocker persists and cannot be solved within repository scope, record it as `BLOCKED` with exact evidence.
|
|
|
|
### Parallelism rules
|
|
|
|
- Parallel Luna agents are encouraged for independent read-only exploration, fixture design, or review of disjoint concerns.
|
|
- Only one Luna agent may edit `wg-manager.sh` at a time.
|
|
- Do not run implementation and repair agents concurrently on the same milestone.
|
|
- Do not let two agents edit the same test or fixture files concurrently.
|
|
- The Sol coordinator merges conclusions and resolves disagreements.
|
|
- All subagents share the repository state, so assignments must name file ownership explicitly.
|
|
|
|
### Completion evidence
|
|
|
|
The execution-log entry for each completed milestone must include:
|
|
|
|
- coordinator model: `gpt-5.6-sol`;
|
|
- implementation subagent model: `gpt-5.6-luna`;
|
|
- custom agent names used;
|
|
- number of repair cycles;
|
|
- Sol review findings and their resolution;
|
|
- full verification commands and results;
|
|
- any optional checks recorded as `SKIP`;
|
|
- the suggested commit message.
|
|
|
|
## 3. Intended MVP architecture
|
|
|
|
The implementation remains a portable project directory with one production entry point:
|
|
|
|
```text
|
|
wireguard-scripts/
|
|
├── AGENTS.md
|
|
├── MVP.md
|
|
├── PLANS.md
|
|
├── README.md
|
|
├── add-user.sh # legacy reference; not the final entry point
|
|
├── wg-manager.sh # production CLI and TUI entry point
|
|
├── wg-manager.conf.example # documented safe example
|
|
├── bin/
|
|
│ └── gum # optional operator-provided binary
|
|
├── backups/ # runtime data; ignored by version control
|
|
├── logs/ # runtime data; ignored by version control
|
|
├── state/
|
|
│ ├── clients/ # runtime client metadata
|
|
│ └── archive/ # recoverable removed-client files
|
|
└── tests/
|
|
├── run.sh
|
|
├── helpers.sh
|
|
├── fixtures/
|
|
└── mocks/bin/
|
|
```
|
|
|
|
For the MVP, production functions may remain in `wg-manager.sh`, grouped in this order:
|
|
|
|
1. constants and exit codes;
|
|
2. generic output and error helpers;
|
|
3. path and dependency resolution;
|
|
4. restricted configuration parsing and validation;
|
|
5. WireGuard config parsing;
|
|
6. client metadata;
|
|
7. locking, backup, staging, apply, and rollback;
|
|
8. client operations;
|
|
9. diagnostics;
|
|
10. CLI presentation;
|
|
11. `gum` TUI wrappers and screens;
|
|
12. argument parsing and `main`.
|
|
|
|
The final guard must allow the script to be sourced by tests without running `main`:
|
|
|
|
```bash
|
|
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
main "$@"
|
|
fi
|
|
```
|
|
|
|
Do not introduce an installer, uninstaller, daemon, package manager, database, JSON parser, or second TUI framework.
|
|
|
|
## 4. Stable design decisions
|
|
|
|
These decisions are fixed for the MVP unless the user explicitly changes them:
|
|
|
|
- Bash is the implementation language.
|
|
- `wg-manager.sh` is the only production entry point.
|
|
- The project is run locally and is not installed into `PATH`.
|
|
- `gum` is the TUI framework.
|
|
- The operator supplies or installs the `gum` binary.
|
|
- CLI functions must work without `gum`.
|
|
- `gum` lookup order is `WG_MANAGER_GUM`, local `bin/gum`, then `PATH`.
|
|
- `qrencode`, systemd, `nft`, and `iptables` are optional capabilities.
|
|
- Runtime tests use fixtures and mocks, never the live host configuration.
|
|
- Configuration uses a restricted `KEY=VALUE` parser, not unrestricted `source`.
|
|
- Client identity is the WireGuard public key; the name is display metadata.
|
|
- Runtime metadata is stored as one root-readable file per managed client.
|
|
- Mutations use `flock`, backup, staged config, atomic replacement, apply verification, and rollback.
|
|
- Removed client files are archived by default rather than permanently deleted.
|
|
- User-facing messages are in Russian.
|
|
- Code identifiers and CLI command names are in English.
|
|
|
|
## 5. Progress tracker
|
|
|
|
Allowed status values: `NOT STARTED`, `IN PROGRESS`, `BLOCKED`, `DONE`.
|
|
|
|
| Milestone | Status | Outcome |
|
|
|---|---|---|
|
|
| M0 | DONE | Test harness and safe project skeleton |
|
|
| M1 | DONE | Runtime foundation, CLI shell, and config loading |
|
|
| M2 | NOT STARTED | WireGuard parser, client model, `status`, and `list` |
|
|
| M3 | NOT STARTED | Locking, backups, atomic apply, and rollback engine |
|
|
| M4 | NOT STARTED | Safe client creation |
|
|
| M5 | NOT STARTED | Client detail, config export, and QR display |
|
|
| M6 | NOT STARTED | Safe client removal and archival |
|
|
| M7 | NOT STARTED | Diagnostics engine and report |
|
|
| M8 | NOT STARTED | Backup listing/restoration and audit log UX |
|
|
| M9 | NOT STARTED | TUI foundation, dashboard, and read-only screens |
|
|
| M10 | NOT STARTED | Complete TUI mutation workflows |
|
|
| M11 | NOT STARTED | Hardening, documentation, and MVP acceptance |
|
|
|
|
---
|
|
|
|
# Milestone M0 — Test harness and safe project skeleton
|
|
|
|
## Goal
|
|
|
|
Create the minimal repository structure and a dependency-free Bash test harness so every later milestone can be implemented with fast, isolated verification.
|
|
|
|
## Prerequisites
|
|
|
|
- `AGENTS.md`, `MVP.md`, and `PLANS.md` exist.
|
|
- No implementation milestone has started.
|
|
|
|
## Changes
|
|
|
|
1. Create `wg-manager.sh` with:
|
|
- Bash shebang;
|
|
- `set -Eeuo pipefail`;
|
|
- `umask 077`;
|
|
- a no-op `main` that supports only `help` initially;
|
|
- the source-safe `main` guard;
|
|
- no root requirement for `help`.
|
|
2. Create `wg-manager.conf.example` with placeholder values only.
|
|
3. Create `.gitignore` entries for:
|
|
- `wg-manager.conf`;
|
|
- `backups/`;
|
|
- `logs/`;
|
|
- `state/`;
|
|
- generated client configs and key files;
|
|
- temporary test output.
|
|
4. Create `tests/run.sh` as a pure Bash test runner.
|
|
5. Create `tests/helpers.sh` with helpers for:
|
|
- creating one isolated temporary test root;
|
|
- copying fixtures;
|
|
- prepending `tests/mocks/bin` to `PATH`;
|
|
- asserting equality, exit status, substring, file existence, and file mode;
|
|
- printing a final pass/fail summary;
|
|
- cleanup through `trap`.
|
|
6. Create fixture directories and one minimal valid `wg0.conf` fixture.
|
|
7. Create mock placeholders for `wg` and `wg-quick` that fail loudly on unexpected arguments.
|
|
8. Create mock placeholders for `ip`, `systemctl`, `journalctl`, `ss`, `sysctl`, `nft`, `iptables`, `qrencode`, and `gum` as they become needed.
|
|
9. Add initial tests for:
|
|
- sourcing `wg-manager.sh` does not execute `main`;
|
|
- `help` exits with status 0;
|
|
- an unknown command exits nonzero;
|
|
- the test harness never references `/etc/wireguard` for writes.
|
|
10. Add a guard that records every external mock invocation and fails on unexpected commands or arguments.
|
|
11. Do not implement WireGuard operations yet.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash -n tests/run.sh
|
|
bash -n tests/helpers.sh
|
|
bash tests/run.sh
|
|
./wg-manager.sh help
|
|
```
|
|
|
|
If ShellCheck is installed, also run:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/run.sh tests/helpers.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Review:
|
|
|
|
```bash
|
|
git diff --check
|
|
git status --short
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- The test suite runs without root.
|
|
- The test suite creates all writable data below a temporary test directory.
|
|
- No test can alter `/etc/wireguard`.
|
|
- The test suite does not require real `wg`, `wg-quick`, root, a network interface, or systemd.
|
|
- Unexpected external command invocations fail loudly.
|
|
- `wg-manager.sh help` works from outside the project directory.
|
|
- No real key, endpoint, or public IP is committed.
|
|
- All verification commands pass.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
test: add isolated Bash test harness and project skeleton
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M1 — Runtime foundation, CLI shell, and configuration
|
|
|
|
## Goal
|
|
|
|
Build the reusable runtime foundation: path discovery, errors, exit codes, dependency detection, restricted configuration loading, and predictable CLI dispatch.
|
|
|
|
## Prerequisites
|
|
|
|
- M0 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Define stable exit codes for:
|
|
- success;
|
|
- usage error;
|
|
- validation error;
|
|
- missing dependency;
|
|
- permission error;
|
|
- operation failure;
|
|
- rollback failure.
|
|
2. Implement `die`, `warn`, `info`, and debug helpers.
|
|
3. Keep stdout for command results and stderr for progress/errors.
|
|
4. Resolve `SCRIPT_DIR` without depending on the current directory.
|
|
5. Add overridable runtime paths derived from `SCRIPT_DIR`:
|
|
- config path;
|
|
- backup directory;
|
|
- log directory;
|
|
- metadata directory;
|
|
- archive directory;
|
|
- lock file.
|
|
6. Implement a restricted parser for simple `KEY=VALUE` lines:
|
|
- ignore blank lines and full-line comments;
|
|
- allow only documented keys;
|
|
- reject duplicate keys;
|
|
- reject command substitutions, shell syntax, and embedded newlines;
|
|
- trim only documented surrounding whitespace;
|
|
- do not call `source` or `eval`.
|
|
7. Validate required configuration:
|
|
- interface name;
|
|
- absolute server config path;
|
|
- absolute client directory path;
|
|
- endpoint and port;
|
|
- IPv4 prefix and host range;
|
|
- IPv6 settings when enabled;
|
|
- supported client mode;
|
|
- backup retention count;
|
|
- recent-handshake threshold.
|
|
8. Implement command discovery helpers for required and optional commands.
|
|
9. Implement `gum` resolution in the fixed order:
|
|
- `WG_MANAGER_GUM`;
|
|
- `${SCRIPT_DIR}/bin/gum`;
|
|
- `command -v gum`.
|
|
10. Add CLI dispatch for:
|
|
- `help`;
|
|
- `version`;
|
|
- placeholder known commands that report “not implemented” with a stable status;
|
|
- unknown command and extra argument errors.
|
|
11. Require root only inside future mutating command paths, not globally.
|
|
12. Add unit tests for all parsing, validation, path, and `gum` resolution branches.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh
|
|
./wg-manager.sh help
|
|
./wg-manager.sh version
|
|
```
|
|
|
|
Verify execution from a different directory:
|
|
|
|
```bash
|
|
(cd /tmp && /home/sasa/share/bash/wireguard-scripts/wg-manager.sh help)
|
|
```
|
|
|
|
Verify invalid configuration fixtures fail without executing embedded text:
|
|
|
|
```bash
|
|
bash tests/run.sh config
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then run:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- No configuration content is executed as shell code.
|
|
- Running from another working directory resolves project-local paths correctly.
|
|
- CLI help and version do not require root, WireGuard, or `gum`.
|
|
- CLI operations can be tested with an alternate config and runtime root.
|
|
- Missing real WireGuard tools are handled through dependency checks and controlled mocks.
|
|
- All invalid configuration cases fail before any mutation.
|
|
- `gum` resolution order is covered by tests.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(core): add validated configuration and CLI foundation
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M2 — WireGuard parser, client model, status, and list
|
|
|
|
## Goal
|
|
|
|
Read persistent and active WireGuard state without mutation, normalize peers into a client model, and expose reliable `status` and `list` commands.
|
|
|
|
## Prerequisites
|
|
|
|
- M1 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Add fixtures for:
|
|
- interface with no peers;
|
|
- one managed peer;
|
|
- multiple managed peers;
|
|
- a legacy `### Client NAME` peer;
|
|
- an unmanaged peer;
|
|
- duplicate public keys;
|
|
- duplicate and overlapping `AllowedIPs`;
|
|
- IPv4 and IPv6 peers.
|
|
2. Implement parsing of `[Interface]` and `[Peer]` sections without executing config text.
|
|
3. Preserve exact public keys and normalized address lists.
|
|
4. Parse managed block markers and legacy client comments.
|
|
5. Implement one metadata file per client under `state/clients`.
|
|
6. Define and validate metadata fields:
|
|
- `NAME`;
|
|
- `PUBLIC_KEY`;
|
|
- `IPV4`;
|
|
- optional `IPV6`;
|
|
- `CREATED_AT`;
|
|
- `CONFIG_PATH`;
|
|
- `CLIENT_MODE`;
|
|
- `MANAGED`.
|
|
7. Never trust metadata over the public key and current config.
|
|
8. Implement normalized client records combining:
|
|
- disk config;
|
|
- metadata;
|
|
- `wg show <interface> dump` output.
|
|
9. Implement client states:
|
|
- `active` when latest handshake is within the configured threshold;
|
|
- `inactive` when a nonzero handshake is older;
|
|
- `never` when handshake is zero;
|
|
- `unmanaged` when no trusted managed identity exists.
|
|
10. Implement `status` with:
|
|
- interface name;
|
|
- runtime availability;
|
|
- listening port;
|
|
- peer count;
|
|
- managed/unmanaged counts;
|
|
- active/recent count.
|
|
11. Implement `list` with deterministic, tabular plain-text output.
|
|
12. Do not use ANSI decoration when stdout is not a terminal.
|
|
13. Ensure read-only commands return useful results when systemd is absent.
|
|
14. Add tests for parser errors and all state classifications.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh parser
|
|
bash tests/run.sh status
|
|
bash tests/run.sh list
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Verify redirected output entirely through fixtures and mocks:
|
|
|
|
```bash
|
|
bash tests/run.sh list-redirected
|
|
```
|
|
|
|
Using only test configuration and mocks, confirm deterministic output:
|
|
|
|
```bash
|
|
LC_ALL=C bash tests/run.sh list-deterministic
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Finally:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- Persistent config and runtime dump parsing are independently tested.
|
|
- A client name is never used as peer identity without a matching public key.
|
|
- Managed, legacy, and unmanaged peers are distinguishable.
|
|
- Empty and stopped interfaces produce useful output rather than crashes.
|
|
- No read-only command writes runtime state.
|
|
- `status` and `list` work without `gum`.
|
|
- Required verification does not query the development host's actual interfaces or services.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(clients): add WireGuard state parsing and client listing
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M3 — Transaction, backup, apply, and rollback engine
|
|
|
|
## Goal
|
|
|
|
Provide one safe mutation primitive that all later add, remove, and restore operations must use.
|
|
|
|
## Prerequisites
|
|
|
|
- M2 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Add mocks for successful and failing variants of:
|
|
- `flock` behavior where practical;
|
|
- `wg-quick strip`;
|
|
- `wg syncconf`;
|
|
- active-state verification.
|
|
2. Implement exclusive locking with one documented lock path.
|
|
3. Re-read source config and relevant metadata after locking.
|
|
4. Implement timestamped backup creation with:
|
|
- UTC timestamp;
|
|
- interface name;
|
|
- original file mode and ownership information where available;
|
|
- copied metadata relevant to the operation;
|
|
- a small manifest.
|
|
5. Implement backup retention without removing the only known-good backup.
|
|
6. Create staging files on the same filesystem as the target config.
|
|
7. Use `umask 077` and explicitly enforce restrictive modes.
|
|
8. Validate a staged config with `wg-quick strip` before replacement.
|
|
9. Atomically replace the server config.
|
|
10. Apply runtime configuration using `wg syncconf` with stripped configuration.
|
|
11. Verify that expected public keys and `AllowedIPs` are active.
|
|
12. On apply or verification failure:
|
|
- restore the prior disk config;
|
|
- restore prior runtime state;
|
|
- verify rollback;
|
|
- return a distinct rollback-failure status if recovery fails.
|
|
13. Preserve the original config if staging validation fails.
|
|
14. Ensure cleanup preserves the operation's final exit status.
|
|
15. Expose the engine only through internal functions; do not add add/remove yet.
|
|
16. Add interruption tests where feasible using a controlled mock.
|
|
17. Assert exact `wg-quick strip` and `wg syncconf` argument arrays in command-contract tests.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh transaction
|
|
bash tests/run.sh rollback
|
|
bash tests/run.sh locking
|
|
bash tests/run.sh backups
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Verify the original fixture remains byte-identical after each failure test:
|
|
|
|
```bash
|
|
bash tests/run.sh mutation-preserves-source
|
|
```
|
|
|
|
Inspect permissions in the test root:
|
|
|
|
```bash
|
|
bash tests/run.sh secret-modes
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- Concurrent mutations cannot both enter the critical section.
|
|
- Invalid staging content never replaces the live file.
|
|
- Apply failure restores disk and runtime state in tests.
|
|
- Rollback failure is visible and has a distinct status.
|
|
- Backups are root-readable only by default.
|
|
- No later mutation needs to reimplement locking or rollback.
|
|
- Transaction verification is complete using mocks; it does not claim a real WireGuard apply occurred.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(safety): add atomic WireGuard mutation and rollback engine
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M4 — Safe client creation
|
|
|
|
## Goal
|
|
|
|
Replace the unsafe mutation behavior of `add-user.sh` with a tested `add` command built on the transaction engine.
|
|
|
|
## Prerequisites
|
|
|
|
- M3 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Implement strict client-name validation.
|
|
2. Reject names with:
|
|
- spaces;
|
|
- slashes;
|
|
- leading option markers when unsafe;
|
|
- control characters;
|
|
- newlines;
|
|
- glob characters;
|
|
- characters outside `[A-Za-z0-9._-]`.
|
|
3. Check for conflicts in:
|
|
- managed metadata;
|
|
- server peer comments;
|
|
- public keys;
|
|
- client config and key files;
|
|
- IPv4 and IPv6 `AllowedIPs`.
|
|
4. Implement deterministic next-free IPv4 selection within the configured range.
|
|
5. Implement optional IPv6 allocation derived from the validated host identity.
|
|
6. Fail cleanly when the address pool is exhausted.
|
|
7. Generate private, public, and preshared keys using `wg` without logging them.
|
|
8. Avoid placing key values in command-line arguments.
|
|
9. Build the client config with:
|
|
- address;
|
|
- DNS;
|
|
- server public key;
|
|
- preshared key;
|
|
- endpoint and port;
|
|
- persistent keepalive;
|
|
- full-tunnel or split-tunnel `AllowedIPs`.
|
|
10. Build an explicit managed peer block in the server config.
|
|
11. Keep the block format stable and covered by golden fixtures.
|
|
12. Write client key and config files with mode `0600`.
|
|
13. Persist metadata only when the server mutation succeeds.
|
|
14. Remove newly generated files if the operation fails before commit.
|
|
15. Use the M3 transaction engine for the server config.
|
|
16. Add `add NAME` CLI parsing and optional documented flags for mode or endpoint.
|
|
17. Require root for the actual add operation.
|
|
18. Keep `add-user.sh` unchanged as a legacy reference during this milestone.
|
|
19. Add tests for successful add, collision cases, pool exhaustion, and rollback.
|
|
20. Use deterministic fake key material from the mock `wg`; do not require cryptographically valid WireGuard keys on the development machine.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh add-client
|
|
bash tests/run.sh address-allocation
|
|
bash tests/run.sh add-collisions
|
|
bash tests/run.sh add-rollback
|
|
bash tests/run.sh secret-modes
|
|
bash tests/run.sh no-secret-logs
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Inspect generated fixture output for exact sections:
|
|
|
|
```bash
|
|
bash tests/run.sh add-golden-config
|
|
```
|
|
|
|
Verify invalid names never reach the mocked `wg genkey` command:
|
|
|
|
```bash
|
|
bash tests/run.sh add-invalid-names
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- A client can be added through CLI using only mocked test state.
|
|
- All conflicts are detected before persistent mutation.
|
|
- Generated secret files have mode `0600`.
|
|
- Failed apply leaves no active peer, persistent peer, or orphaned metadata.
|
|
- Full-tunnel and split-tunnel configs are independently tested.
|
|
- No secret appears in captured stdout, stderr, or audit output.
|
|
- Tests verify the `wg genkey`, `wg pubkey`, and `wg genpsk` command contract without requiring the real binaries.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(clients): add transactional client creation
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M5 — Client detail, config export, and QR display
|
|
|
|
## Goal
|
|
|
|
Allow an administrator to inspect a client, locate its configuration, and display a QR code without exposing secrets accidentally.
|
|
|
|
## Prerequisites
|
|
|
|
- M4 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Implement `show NAME` with non-secret fields:
|
|
- name;
|
|
- public key;
|
|
- assigned addresses;
|
|
- client mode;
|
|
- creation date;
|
|
- endpoint;
|
|
- last handshake;
|
|
- transfer counters;
|
|
- managed/unmanaged state;
|
|
- client config path when available.
|
|
2. Implement `config NAME` to print the validated config path by default.
|
|
3. Require an explicit flag or interactive confirmation before printing full config content.
|
|
4. Never print separate private key or preshared key files.
|
|
5. Implement `qr NAME` using `qrencode -t ansiutf8` when available.
|
|
6. If `qrencode` is absent:
|
|
- return the documented optional-capability status;
|
|
- show the config path and a clear message;
|
|
- do not fail unrelated commands.
|
|
7. Reject unmanaged peers for config and QR operations unless a safe managed file association exists.
|
|
8. Validate that the config path stays inside the configured client directory.
|
|
9. Reject symlink or ownership surprises that could expose an unrelated file.
|
|
10. Add tests for missing clients, missing config, unmanaged peers, and missing `qrencode`.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh show-client
|
|
bash tests/run.sh config-export
|
|
bash tests/run.sh qr
|
|
bash tests/run.sh path-safety
|
|
bash tests/run.sh no-secret-default-output
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Confirm normal detail output contains no private material:
|
|
|
|
```bash
|
|
bash tests/run.sh no-secret-logs
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- `show` is safe to use in routine administration.
|
|
- Full config content requires an explicit action.
|
|
- `qr` works with a mock `qrencode` and degrades clearly without it.
|
|
- Unmanaged peers cannot cause arbitrary file reads.
|
|
- Config paths are validated before access.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(clients): add client details and secure config export
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M6 — Safe client removal and archival
|
|
|
|
## Goal
|
|
|
|
Remove a managed peer from persistent and active WireGuard state while preserving recoverable client artifacts.
|
|
|
|
## Prerequisites
|
|
|
|
- M5 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Implement `remove NAME` for managed clients only.
|
|
2. Resolve the exact target through metadata and public key.
|
|
3. Refuse ambiguous names, duplicate identities, and unmanaged peers.
|
|
4. Display the exact name, public key suffix, and addresses before confirmation.
|
|
5. For interactive CLI, require explicit confirmation.
|
|
6. For noninteractive CLI, require a documented `--yes` flag.
|
|
7. Remove only the exact managed peer block.
|
|
8. Reject removal if block boundaries or public key do not match expectations.
|
|
9. Use the transaction engine to apply the new server config.
|
|
10. After successful server mutation, move client files and metadata into a timestamped archive directory.
|
|
11. Do not follow unexpected symlinks while archiving.
|
|
12. If artifact archival fails after peer removal:
|
|
- report the partial failure clearly;
|
|
- keep metadata sufficient for recovery;
|
|
- do not silently claim full success.
|
|
13. Record the removal in the audit log without secrets.
|
|
14. Do not implement permanent purge in the MVP.
|
|
15. Add tests for cancellation, exact-block removal, rollback, and archival failure.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh remove-client
|
|
bash tests/run.sh remove-cancel
|
|
bash tests/run.sh remove-exact-block
|
|
bash tests/run.sh remove-rollback
|
|
bash tests/run.sh archive-client
|
|
bash tests/run.sh archive-path-safety
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Confirm a neighboring peer is byte-identical after removal:
|
|
|
|
```bash
|
|
bash tests/run.sh remove-preserves-neighbors
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- Only the selected public key is removed.
|
|
- Cancellation makes no changes.
|
|
- Apply failure restores the peer and leaves artifacts in place.
|
|
- Successful removal archives client files with restrictive permissions.
|
|
- Unmanaged peers cannot be removed through the managed-client command.
|
|
- The audit event contains no key material beyond a permitted shortened identifier.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(clients): add safe client removal and archival
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M7 — Diagnostics engine
|
|
|
|
## Goal
|
|
|
|
Provide an evidence-based `diagnose` command that identifies common WireGuard, routing, permission, and firewall problems without modifying the server.
|
|
|
|
## Prerequisites
|
|
|
|
- M6 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Define a diagnostic result record with:
|
|
- check identifier;
|
|
- status: `OK`, `WARN`, `FAIL`, or `SKIP`;
|
|
- concise Russian summary;
|
|
- optional remediation guidance.
|
|
2. Keep checks independent so one failure does not stop the report.
|
|
3. Implement checks for:
|
|
- required commands;
|
|
- readable server config;
|
|
- config and key permissions;
|
|
- interface existence;
|
|
- active WireGuard dump;
|
|
- systemd service state when systemd is present;
|
|
- config parsing and duplicate keys;
|
|
- duplicate or overlapping `AllowedIPs`;
|
|
- IPv4 forwarding;
|
|
- IPv6 forwarding when enabled;
|
|
- expected interface addresses and routes;
|
|
- configured UDP listening port using available tools;
|
|
- firewall/NAT visibility through `nft` or `iptables` when available;
|
|
- disk versus runtime peer differences;
|
|
- recent relevant journal entries when `journalctl` is usable.
|
|
4. Never claim a firewall is correct merely because one command exists.
|
|
5. Use `SKIP` for unsupported init systems or missing optional tools.
|
|
6. Use `WARN` for uncertain or policy-dependent conditions.
|
|
7. Use `FAIL` only for conditions that clearly prevent expected operation or violate a required invariant.
|
|
8. Return nonzero when any `FAIL` exists.
|
|
9. Add `diagnose --quiet` or equivalent machine-friendly summary if useful, but JSON is not required.
|
|
10. Add fixtures and mocks for every status branch.
|
|
11. Ensure diagnostics are read-only.
|
|
12. Force diagnostic tests to consume mock host state rather than the development machine's actual `/proc`, service manager, routes, firewall, or journal.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh diagnostics
|
|
bash tests/run.sh diagnostics-systemd
|
|
bash tests/run.sh diagnostics-firewall
|
|
bash tests/run.sh diagnostics-forwarding
|
|
bash tests/run.sh diagnostics-runtime-diff
|
|
bash tests/run.sh diagnostics-read-only
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Verify exit behavior:
|
|
|
|
```bash
|
|
bash tests/run.sh diagnostics-exit-codes
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- Every check reports exactly one recognized status.
|
|
- Independent checks continue after failures.
|
|
- Missing optional tools produce `SKIP`, not a crash.
|
|
- At least one tested scenario produces each of `OK`, `WARN`, `FAIL`, and `SKIP`.
|
|
- The command exits nonzero when critical failures exist.
|
|
- No diagnostic check mutates config, runtime state, firewall, routes, or sysctl values.
|
|
- Results describe fixture state only and do not depend on the development host.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(diagnostics): add read-only WireGuard health checks
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M8 — Backup restoration and audit log UX
|
|
|
|
## Goal
|
|
|
|
Expose safe backup management and administrator-visible audit history using the primitives already created by mutations.
|
|
|
|
## Prerequisites
|
|
|
|
- M7 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Finalize structured, line-oriented audit events with:
|
|
- UTC timestamp;
|
|
- effective UID or operator identity;
|
|
- operation;
|
|
- safe target identifier;
|
|
- outcome;
|
|
- concise error code or summary.
|
|
2. Ensure all existing add, remove, apply, rollback, and backup actions log their final outcome.
|
|
3. Implement `log` with:
|
|
- newest or oldest ordering documented;
|
|
- optional bounded number of entries;
|
|
- readable behavior when no log exists.
|
|
4. Implement `backup` to create an explicit manual backup.
|
|
5. Implement `backups` to list valid backup manifests only.
|
|
6. Treat malformed or incomplete backup directories as invalid and report them safely.
|
|
7. Implement `restore BACKUP` with:
|
|
- strict backup identifier validation;
|
|
- containment inside the configured backup directory;
|
|
- validation of the backup config;
|
|
- preview of timestamp and interface;
|
|
- explicit confirmation;
|
|
- a backup of current state before restoration;
|
|
- transaction-engine apply and rollback.
|
|
8. Require `--yes` for noninteractive restoration.
|
|
9. Do not restore a backup for a different interface without explicit future support.
|
|
10. Add tests for tampered manifests, traversal attempts, apply failure, and restoration rollback.
|
|
11. Add tests that search all audit output for fixture secrets.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh audit
|
|
bash tests/run.sh audit-no-secrets
|
|
bash tests/run.sh backup-list
|
|
bash tests/run.sh restore
|
|
bash tests/run.sh restore-invalid
|
|
bash tests/run.sh restore-rollback
|
|
bash tests/run.sh backup-path-safety
|
|
bash tests/run.sh
|
|
```
|
|
|
|
Inspect permissions:
|
|
|
|
```bash
|
|
bash tests/run.sh runtime-file-modes
|
|
```
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- Audit logs cover every mutating path and rollback result.
|
|
- Fixture private and preshared keys are absent from logs.
|
|
- Backup listing ignores invalid entries without executing content.
|
|
- Restore cannot escape the configured backup directory.
|
|
- Restore validates before mutation and backs up current state first.
|
|
- Failed restore returns the host to its prior test state.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(backup): add audited backup listing and restoration
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M9 — TUI foundation and read-only screens
|
|
|
|
## Goal
|
|
|
|
Create a consistent `gum` TUI shell and expose the dashboard, client list, client detail, diagnostics, logs, and backups without duplicating backend logic.
|
|
|
|
## Prerequisites
|
|
|
|
- M8 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Implement small TUI wrapper functions for:
|
|
- style/header;
|
|
- choose;
|
|
- filter;
|
|
- input;
|
|
- confirm;
|
|
- table;
|
|
- pager;
|
|
- spinner.
|
|
2. Keep all raw `gum` flags inside wrappers.
|
|
3. Resolve and validate `gum` before entering the TUI.
|
|
4. Detect noninteractive stdin/stdout and refuse TUI cleanly.
|
|
5. Treat Escape and cancellation as normal navigation.
|
|
6. Implement the main dashboard with:
|
|
- configured interface;
|
|
- runtime state;
|
|
- managed peer count;
|
|
- active/recent count;
|
|
- warning count where inexpensive to obtain.
|
|
7. Implement a shallow main menu for:
|
|
- status;
|
|
- clients;
|
|
- add placeholder or action entry;
|
|
- remove placeholder or action entry;
|
|
- diagnostics;
|
|
- audit log;
|
|
- backups;
|
|
- exit.
|
|
8. Implement searchable client selection using stable hidden identity, not only display text.
|
|
9. Implement read-only screens by calling existing backend functions:
|
|
- status;
|
|
- list;
|
|
- show;
|
|
- diagnostics;
|
|
- log;
|
|
- backups.
|
|
10. Use a pager for long output.
|
|
11. Do not parse decorated TUI output back into backend data.
|
|
12. Keep the layout usable at 80 columns.
|
|
13. Do not rely on color alone for status.
|
|
14. Add a mock `gum` that records arguments and returns scripted selections.
|
|
15. Add tests for menu routing, cancellation, missing `gum`, resolution order, and non-TTY refusal.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh gum-resolution
|
|
bash tests/run.sh tui-routing
|
|
bash tests/run.sh tui-cancel
|
|
bash tests/run.sh tui-read-only
|
|
bash tests/run.sh tui-no-gum
|
|
bash tests/run.sh tui-non-tty
|
|
bash tests/run.sh
|
|
```
|
|
|
|
If a usable `gum` binary and interactive terminal are available, an optional smoke test may run with the test configuration and mocked system commands:
|
|
|
|
```bash
|
|
WG_MANAGER_GUM="$(command -v gum)" \
|
|
WG_MANAGER_CONFIG="$(pwd)/tests/fixtures/configs/valid.conf" \
|
|
PATH="$(pwd)/tests/mocks/bin:$PATH" \
|
|
./wg-manager.sh
|
|
```
|
|
|
|
Manual checks:
|
|
|
|
- open and exit every read-only screen;
|
|
- press Escape from each selection screen;
|
|
- verify long output is scrollable;
|
|
- verify no screen writes production state;
|
|
- resize the terminal to approximately 80 columns.
|
|
|
|
If real `gum` is unavailable, record the manual smoke test as `SKIP`; the scripted mock-TUI tests remain the required gate.
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- TUI startup fails clearly when `gum` is absent or unusable.
|
|
- CLI remains fully operational without `gum`.
|
|
- Every read-only screen uses existing backend data/functions.
|
|
- Cancellation returns to the expected previous screen.
|
|
- TUI tests do not require a real terminal or real WireGuard instance.
|
|
- No second TUI framework is introduced.
|
|
- Required TUI verification does not require real WireGuard or real `gum`.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(tui): add gum dashboard and read-only workflows
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M10 — Complete TUI mutation workflows
|
|
|
|
## Goal
|
|
|
|
Expose add, remove, QR, manual backup, and restore workflows through `gum` while preserving all CLI safety guarantees.
|
|
|
|
## Prerequisites
|
|
|
|
- M9 is `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Implement the add-client TUI flow:
|
|
- prompt for name;
|
|
- validate immediately;
|
|
- choose full-tunnel or split-tunnel;
|
|
- collect split networks when required;
|
|
- optionally confirm configured endpoint;
|
|
- preview non-secret result;
|
|
- confirm creation;
|
|
- call the existing add backend;
|
|
- show final config path and optional QR action.
|
|
2. Implement the remove-client TUI flow:
|
|
- select only managed clients;
|
|
- display exact target and addresses;
|
|
- require explicit confirmation;
|
|
- call the existing remove backend;
|
|
- display archive location.
|
|
3. Implement client actions:
|
|
- details;
|
|
- show config after confirmation;
|
|
- show QR when available;
|
|
- remove.
|
|
4. Implement manual backup from TUI.
|
|
5. Implement restore flow:
|
|
- select a validated backup;
|
|
- show manifest details;
|
|
- use a stronger confirmation prompt;
|
|
- call the restore backend;
|
|
- show rollback outcome on failure.
|
|
6. Use spinners only around backend operations whose errors are captured and shown.
|
|
7. Never place secrets inside `gum` command arguments.
|
|
8. Never use a spinner that discards actionable stderr.
|
|
9. Return to a stable menu after success or cancellation.
|
|
10. Stop returning to the menu after a critical rollback failure; show the error and exit nonzero.
|
|
11. Add scripted mock-TUI tests for each success, cancel, validation failure, backend failure, and rollback-failure flow.
|
|
|
|
## Verification
|
|
|
|
Run:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash tests/run.sh tui-add
|
|
bash tests/run.sh tui-remove
|
|
bash tests/run.sh tui-client-actions
|
|
bash tests/run.sh tui-backup
|
|
bash tests/run.sh tui-restore
|
|
bash tests/run.sh tui-backend-failure
|
|
bash tests/run.sh tui-no-secret-args
|
|
bash tests/run.sh
|
|
```
|
|
|
|
With a usable `gum` and a test-only mocked backend, optionally verify:
|
|
|
|
- add flow success and cancellation;
|
|
- invalid name correction;
|
|
- split-tunnel input;
|
|
- removal confirmation defaults to safe cancellation;
|
|
- QR fallback when `qrencode` is missing;
|
|
- restore requires deliberate confirmation;
|
|
- backend errors remain readable after a spinner.
|
|
|
|
If real `gum` is unavailable, record these manual checks as `SKIP`; all scripted mutation-flow tests remain mandatory.
|
|
|
|
If available:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Then:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
## Acceptance criteria
|
|
|
|
- TUI mutation paths call the same backend functions as CLI paths.
|
|
- Cancellation makes no changes.
|
|
- User input is validated before backend execution.
|
|
- Destructive actions show the exact target and require confirmation.
|
|
- Secrets are absent from recorded `gum` arguments and logs.
|
|
- Critical rollback failure exits instead of pretending the TUI can continue safely.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
feat(tui): add safe client and backup workflows
|
|
```
|
|
|
|
---
|
|
|
|
# Milestone M11 — Hardening, documentation, and MVP acceptance
|
|
|
|
## Goal
|
|
|
|
Verify the complete MVP as one coherent tool, close safety gaps, document operation, and produce a release-ready baseline.
|
|
|
|
## Prerequisites
|
|
|
|
- M0 through M10 are `DONE`.
|
|
|
|
## Changes
|
|
|
|
1. Review every requirement in `MVP.md` and map it to code and tests.
|
|
2. Review every applicable rule in `AGENTS.md`.
|
|
3. Add end-to-end fixture scenarios for:
|
|
- fresh server with no clients;
|
|
- existing managed clients;
|
|
- mixed managed and unmanaged peers;
|
|
- add, inspect, QR fallback, remove, and restore;
|
|
- failed apply and successful rollback;
|
|
- failed rollback;
|
|
- missing optional dependencies;
|
|
- stopped WireGuard interface;
|
|
- malformed configuration and metadata.
|
|
4. Add a test that scans repository fixtures and test output for known secret markers.
|
|
5. Add a test that prevents writes outside the isolated test root.
|
|
6. Add a test that fails if production code invokes host networking or service commands instead of test mocks.
|
|
7. Review all filesystem operations for traversal and symlink risks.
|
|
8. Review every command invocation for quoting and option injection.
|
|
9. Review every error path for secret leakage.
|
|
10. Review exit codes for consistency.
|
|
11. Decide the legacy `add-user.sh` outcome:
|
|
- keep it explicitly documented as deprecated reference; or
|
|
- replace it with a small compatibility wrapper;
|
|
- do not leave two independent mutation implementations.
|
|
12. Create `README.md` with:
|
|
- purpose and limitations;
|
|
- supported environment;
|
|
- directory layout;
|
|
- required and optional dependencies;
|
|
- operator-managed `gum` placement;
|
|
- configuration procedure;
|
|
- CLI examples;
|
|
- TUI launch;
|
|
- backup and rollback behavior;
|
|
- file permissions;
|
|
- safe test procedure;
|
|
- troubleshooting;
|
|
- warning that handshake data is not a full connection history.
|
|
13. Document that development verification is mock-based and does not prove kernel, distribution, firewall, or live tunnel compatibility.
|
|
14. Add a separate deployment-server verification checklist to README.
|
|
15. Ensure examples contain placeholder endpoints and keys only.
|
|
16. Update `MVP.md` only if implemented behavior intentionally changes the approved scope.
|
|
17. Complete the execution log and decision log below.
|
|
|
|
## Verification
|
|
|
|
Run the complete automated gate:
|
|
|
|
```bash
|
|
bash -n wg-manager.sh
|
|
bash -n tests/run.sh
|
|
bash -n tests/helpers.sh
|
|
bash tests/run.sh
|
|
```
|
|
|
|
If available, run:
|
|
|
|
```bash
|
|
shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*
|
|
```
|
|
|
|
Run repository checks:
|
|
|
|
```bash
|
|
git diff --check
|
|
git status --short
|
|
```
|
|
|
|
Run focused security checks:
|
|
|
|
```bash
|
|
bash tests/run.sh no-secret-logs
|
|
bash tests/run.sh path-safety
|
|
bash tests/run.sh symlink-safety
|
|
bash tests/run.sh no-host-writes
|
|
bash tests/run.sh no-host-command-bypass
|
|
bash tests/run.sh rollback
|
|
```
|
|
|
|
The following deployment-server checklist is not run on the development machine and does not block M11.
|
|
Run it later only on a disposable or explicitly authorized non-production WireGuard interface:
|
|
|
|
1. Create or select a non-production test interface and config.
|
|
2. Point `wg-manager.conf` only to that interface and isolated client directory.
|
|
3. Run `status`, `list`, and `diagnose`.
|
|
4. Add a test client through CLI.
|
|
5. Confirm disk config, runtime peer, metadata, file modes, and audit event.
|
|
6. Inspect the client through TUI and display a QR code when available.
|
|
7. Remove the test client through TUI.
|
|
8. Confirm the peer is gone and artifacts are archived.
|
|
9. Restore the pre-add backup.
|
|
10. Confirm disk and runtime state match the initial state.
|
|
|
|
Additional deployment checks:
|
|
|
|
11. Run `diagnose` and compare its claims with independently observed server state.
|
|
12. Confirm the actual `wg-quick` and WireGuard versions are supported.
|
|
13. Confirm the supplied `gum` binary matches the server architecture and starts over SSH.
|
|
14. Confirm the server firewall backend is detected conservatively.
|
|
15. Record distribution-specific differences as follow-up issues rather than weakening offline tests.
|
|
|
|
Do not run this checklist against a production interface as part of unattended verification.
|
|
Do not mark mock results as evidence that this checklist passed.
|
|
|
|
## Acceptance criteria
|
|
|
|
- Every MVP criterion has a corresponding passing check or documented manual verification.
|
|
- Full automated tests pass without root and without touching host WireGuard state.
|
|
- Shell syntax checks pass.
|
|
- ShellCheck has no unexplained findings when available.
|
|
- CLI works without `gum`.
|
|
- TUI behavior passes scripted `gum` mock tests; a real-`gum` smoke test is optional on the development machine.
|
|
- Add, remove, and restore are transactional and recoverable.
|
|
- No known secret is present in logs, diffs, or test artifacts.
|
|
- README instructions match observed behavior.
|
|
- No independent unsafe mutation path remains in `add-user.sh`.
|
|
- `git diff --check` passes when the project is a Git worktree.
|
|
- Required verification passes without real WireGuard commands, root access, systemd, or host networking access.
|
|
- The deferred deployment-server checklist is documented and clearly marked as not yet executed.
|
|
|
|
## Suggested commit message
|
|
|
|
```text
|
|
docs: finalize WireGuard Manager MVP and operations guide
|
|
```
|
|
|
|
## Suggested MVP release commit message
|
|
|
|
Use this only if the completed milestones are squashed into one commit:
|
|
|
|
```text
|
|
feat: deliver portable WireGuard management MVP
|
|
|
|
Add a Bash CLI and gum-based TUI for listing, creating, inspecting,
|
|
diagnosing, removing, backing up, and restoring WireGuard clients with
|
|
transactional configuration updates, rollback, and secret-safe auditing.
|
|
```
|
|
|
|
---
|
|
|
|
# 6. Decision log
|
|
|
|
Add entries only for decisions that affect later milestones.
|
|
Do not record routine implementation details.
|
|
|
|
| Date | Milestone | Decision | Reason | Consequence |
|
|
|---|---|---|---|---|
|
|
| YYYY-MM-DD | Mx | Example decision | Why it was necessary | What later work must preserve |
|
|
|
|
# 7. Execution log
|
|
|
|
Append one concise entry after completing or blocking a milestone.
|
|
|
|
Use this template:
|
|
|
|
```text
|
|
## YYYY-MM-DD — Mx — DONE|BLOCKED
|
|
|
|
- Implemented: ...
|
|
- Coordinator: `gpt-5.6-sol` (`high`)
|
|
- Subagents: `milestone_worker` / `milestone_repairer`, `gpt-5.6-luna` (`medium`)
|
|
- Repair cycles: 0 | number
|
|
- Sol review: findings and resolution | no material findings
|
|
- Verification: `command`, `command`
|
|
- Result: ...
|
|
- Decisions: none | link to decision-log entry
|
|
- Known limitations: none | ...
|
|
- Next milestone: My
|
|
```
|
|
|
|
## 2026-10-11 — M0 — DONE
|
|
|
|
- Implemented: strict source-safe `wg-manager.sh` help shell, placeholder configuration, runtime ignores, isolated pure-Bash test harness, minimal WireGuard fixture, and deny-by-default logged mocks for all planned external commands.
|
|
- Coordinator: `gpt-5.6-sol` (`high`)
|
|
- Subagents: `milestone_worker` / `milestone_repairer`, `gpt-5.6-luna` (`medium`)
|
|
- Repair cycles: 2
|
|
- Sol review: replaced a tautological host-path check with a recursive pure-Bash guard; made mocks deny empty calls unless explicitly authorized and assert exact invocation logs; removed an unused production path variable, added a narrow ShellCheck source directive, and cleared unintended index staging.
|
|
- Verification: `bash -n wg-manager.sh`, `bash -n tests/run.sh`, `bash -n tests/helpers.sh`, `bash -n tests/mocks/bin/*`, `bash tests/run.sh`, `./wg-manager.sh help`, `(cd /tmp && /home/sasa/share/bash/wireguard-scripts/wg-manager.sh help)`, `git diff --check`, `git diff --no-index --check /dev/null <new-file>`, `git status --short`
|
|
- Result: all required checks passed; 13 test assertions passed; unknown commands and extra arguments returned status 64; executable modes and isolated mock behavior were verified. Optional `shellcheck wg-manager.sh tests/run.sh tests/helpers.sh tests/mocks/bin/*` was `SKIP` because ShellCheck is unavailable.
|
|
- Decisions: none
|
|
- Known limitations: real WireGuard, networking, service, firewall, route, sysctl, journal, and deployment-server checks were not run; M0 verification is fixture- and mock-based as required.
|
|
- Suggested commit message: `test: add isolated Bash test harness and project skeleton`
|
|
- Next milestone: M1
|
|
|
|
## 2026-10-11 — M1 — DONE
|
|
|
|
- Implemented: stable exit codes and output helpers, caller-independent project paths with scoped runtime overrides, restricted non-executing configuration parsing and semantic validation, dependency discovery, fixed-order `gum` resolution, version/help and known-command CLI dispatch, focused configuration tests, and M1 usage documentation.
|
|
- Coordinator: `gpt-5.6-sol` (`high`)
|
|
- Subagents: `milestone_worker` / `milestone_repairer`, `gpt-5.6-luna` (`medium`)
|
|
- Repair cycles: 3
|
|
- Sol review: replaced duplicate-masked semantic tests with single-cause fixtures; added real focused-test dispatch and missing parser/validator/gum/dependency/CLI branches; made disabled debug strict-mode safe; fixed server-address range containment, empty/trailing DNS elements, numeric endpoint and hostname validation, gum regular-file checks, malformed IPv6 compression, and bracket-glob paths; removed unintended staging from two test helpers.
|
|
- Verification: `bash -n wg-manager.sh`, `bash -n tests/*.sh`, `bash -n tests/mocks/bin/*`, `bash tests/run.sh`, `./wg-manager.sh help`, `./wg-manager.sh version`, `(cd /tmp && /home/sasa/share/bash/wireguard-scripts/wg-manager.sh help)`, `bash tests/run.sh config`, `git diff --check`, `git diff --no-index --check /dev/null <new-file>`, redirected-output checks, and independent IPv6/path/debug boundary probes.
|
|
- Result: all required checks passed; the full suite passed 158 assertions and the focused configuration suite passed 109 assertions. Help and version required no configuration, root, WireGuard, or `gum`; malicious configuration remained inert; alternate runtime paths and gum precedence passed through isolated fixtures and mocks. Optional `shellcheck wg-manager.sh tests/*.sh tests/mocks/bin/*` was `SKIP` because ShellCheck is unavailable.
|
|
- Decisions: none
|
|
- Known limitations: real WireGuard, networking, service, firewall, route, sysctl, journal, and deployment-server checks were not run; M1 verification is fixture- and mock-based as required.
|
|
- Suggested commit message: `feat(core): add validated configuration and CLI foundation`
|
|
- Next milestone: M2
|
|
|
|
# 8. Final completion rule
|
|
|
|
The MVP is complete only when:
|
|
|
|
- M0 through M11 are marked `DONE`;
|
|
- the complete M11 verification passes;
|
|
- all known critical failures are fixed;
|
|
- optional skipped checks are documented;
|
|
- the execution log describes the delivered state;
|
|
- the user receives the final verification summary and suggested release commit message.
|
|
|
|
Do not mark the project complete merely because the implementation exists.
|
|
Completion requires evidence from tests, static checks, diff review, and the documented acceptance flow.
|