Files
sasa e7e728cd23 Add OpenAI specific configuration
- add AGENTS.md and PLANS.md based on MPV
- add subagents configuration
2026-10-11 23:06:05 +03:00

301 lines
15 KiB
Markdown

# AGENTS.md
## Scope
- These rules apply to the entire repository.
- Build a local WireGuard management tool for Linux servers.
- Keep `wg-manager.sh` as the primary entry point.
- The project is copied as a directory and is not installed into `PATH`.
- Do not add installer or uninstaller scripts unless explicitly requested.
- Treat `MVP.md` as the product scope and acceptance reference.
- Treat `PLANS.md` as the required milestone sequence for MVP implementation.
- Complete and verify one milestone before starting the next one.
- Update the `PLANS.md` progress and execution log as milestones are completed.
- Run milestones under the Sol coordinator and Luna worker/reviewer loop defined in `PLANS.md` and `.codex/`.
- The coordinator must independently review Luna's changes and delegate explicit Luna repairs until verification passes or a genuine blocker remains.
- Use the existing `add-user.sh` only as a behavioral reference.
- New code must improve its safety rather than copy its weaknesses.
## General priorities
- Preserve a working WireGuard configuration above all else.
- Prefer correctness and recoverability over cleverness.
- Keep CLI behavior independent from the TUI.
- Make every mutating operation explicit and auditable.
- Keep secrets out of output, logs, tests, and error messages.
- Minimize required dependencies.
- Support operation over SSH and ordinary terminal emulators.
- Write user-facing text in Russian unless the surrounding interface uses another language.
- Keep identifiers, functions, CLI command names, and code comments in English.
- Avoid unrelated refactors while implementing a focused change.
## Bash baseline
- Use Bash, not POSIX `sh`.
- Start executable scripts with `#!/usr/bin/env bash`.
- Enable `set -Eeuo pipefail` in production entry points.
- Understand strict-mode exceptions before suppressing them.
- Use `if command; then` when a nonzero status is expected.
- Do not append `|| true` unless the ignored failure is intentional and documented.
- Set `umask 077` before creating configs, keys, metadata, logs, or backups.
- Require a supported Bash version at startup when using version-specific features.
- Prefer Bash builtins over unnecessary subprocesses.
- Use `printf` rather than `echo -e`.
- Use `[[ ... ]]` for Bash conditionals.
- Use `(( ... ))` for arithmetic conditions.
- Use `case` for command dispatch and finite state handling.
- Use `local` for function-local variables.
- Declare variables close to first use.
- Use `readonly` for constants after configuration is loaded.
- Use uppercase names only for exported variables and true constants.
- Use lowercase snake_case for local variables and functions.
- Give functions verb-based names such as `load_config` or `add_client`.
- Keep functions focused and normally below about 60 lines.
- Return statuses from functions; print data only when output is the contract.
- Do not mix machine-readable results with progress messages.
- Send errors and diagnostics to stderr.
- Use explicit exit codes for expected CLI failure categories.
## Quoting and data handling
- Double-quote parameter expansions unless splitting is deliberately required.
- Use `"${array[@]}"` when forwarding array elements.
- Use arrays to build commands; never construct commands as strings.
- Never use `eval`.
- Never pass user-controlled text to `bash -c`.
- Avoid command substitution for multiline or NUL-sensitive data.
- Use `mapfile -t` for line-oriented command output when appropriate.
- Use `IFS= read -r` to read literal lines.
- Use `read -r -d ''` or NUL delimiters for arbitrary file names.
- Use `--` before user-derived positional arguments where supported.
- Do not rely on locale-sensitive parsing.
- Set `LC_ALL=C` locally for command output that must be parsed predictably.
- Do not parse human-formatted output when a stable dump format exists.
- Prefer `wg show <interface> dump` for WireGuard state parsing.
- Treat names, endpoints, addresses, paths, and config values as untrusted input.
- Validate input with allowlists and semantic checks.
- Reject control characters and embedded newlines in user input.
- Never derive a filesystem path from an unchecked client name.
- Canonicalize or constrain paths before reading or writing them.
## Configuration
- Keep server-specific values in `wg-manager.conf`.
- Resolve the project directory from `${BASH_SOURCE[0]}`.
- Do not depend on the caller's current working directory.
- Do not silently overwrite administrator configuration.
- Validate every required setting at startup.
- Reject unknown enum values such as unsupported tunnel modes.
- Validate numeric ranges before arithmetic use.
- Validate IPv4, IPv6, CIDR, port, and hostname values before use.
- Do not `source` a configuration file that may be writable by untrusted users.
- If sourcing is retained, require root ownership and non-group/world-writable permissions.
- Prefer a restricted `KEY=VALUE` parser for long-term safety.
- Environment overrides must be documented and narrowly scoped.
- Never accept key material through command-line arguments.
- Avoid exporting secrets into the process environment.
## Temporary files and cleanup
- Create temporary files with `mktemp`.
- Create mutation staging files on the same filesystem as the target.
- Never use predictable temporary filenames.
- Register cleanup immediately after creating temporary resources.
- Use a cleanup function with `trap` for `EXIT`, `INT`, and `TERM`.
- Quote trap bodies safely; avoid premature expansion.
- Preserve the original exit status during cleanup.
- Do not remove a path unless this process created it or validated it exactly.
- Apply restrictive permissions before writing secret content.
- Do not leave key material in world-readable temporary directories.
## WireGuard safety
- Require root only for commands that need privileged access or mutation.
- Allow safe read-only commands without root when system permissions permit it.
- Check that the configured interface and config file agree.
- Identify peers by public key, not only by display name.
- Treat comments such as `### Client NAME` as metadata, not identity.
- Detect duplicate public keys and overlapping `AllowedIPs`.
- Detect address collisions before generating any persistent file.
- Distinguish managed peers from unmanaged peers.
- Never modify an unmanaged peer implicitly.
- Do not regenerate server keys automatically.
- Do not rotate or replace client keys without explicit confirmation.
- Never print private or preshared keys in routine output.
- Never include key values in traces or debug logs.
- Disable shell tracing around all secret-handling code.
- Store client files with mode `0600`.
- Keep directories containing client material at mode `0700`.
## Mutating operations
- Serialize mutations with `flock`.
- Acquire the lock before re-reading mutable state.
- Revalidate assumptions after the lock is acquired.
- Create a backup before every persistent change.
- Write the complete proposed config to a staging file.
- Validate the staged config before replacing the live config.
- Preserve the target owner, group, and restrictive mode.
- Replace files atomically with a same-filesystem rename.
- Apply the new configuration only after durable storage succeeds.
- Verify active state after applying the change.
- Roll back both disk and runtime state on failure.
- Report rollback failure as a critical error.
- Never append directly to the live WireGuard config.
- Never use broad text deletion to remove a peer block.
- Match an exact managed block and its public key.
- Default to archiving client files instead of permanent deletion.
- Require explicit confirmation before destructive or restorative actions.
- Make repeated operations fail safely or behave idempotently.
## Backups and audit log
- Timestamp backups in an unambiguous UTC format.
- Include the interface name in backup metadata or filenames.
- Keep a bounded number of automatic backups.
- Never prune the only known-good backup.
- Validate a backup before offering restoration.
- Back up the current state before restoring an older state.
- Record who initiated a mutation when that information is available.
- Log the operation, target, timestamp, outcome, and concise error.
- Do not log private keys, preshared keys, or full client configs.
- Avoid logging full environment dumps or command lines with secrets.
- Make logs readable only by root by default.
- Log failed mutations and rollback outcomes.
## CLI design
- TUI actions must call the same backend functions as CLI commands.
- Keep CLI commands usable when `gum` is unavailable.
- Provide `help` and useful usage errors.
- Reject unknown commands and extra positional arguments.
- Keep command names stable once documented.
- Use stdout for requested data and stderr for warnings or progress.
- Do not add decorative ANSI output when stdout is not a terminal.
- Honor `NO_COLOR` for CLI colors where colors are used.
- Return zero only when the requested operation succeeded.
- Use distinct nonzero statuses for usage, validation, dependency, and runtime errors.
- Avoid interactive prompts when a CLI command is explicitly noninteractive.
- Require a confirmation flag for destructive noninteractive commands.
- Never let localization change machine-parsed values or exit codes.
## TUI with gum
- Use `gum` as the only planned TUI framework.
- Do not add `dialog`, `whiptail`, or a second TUI framework.
- Do not download or install `gum` from the application.
- Resolve `gum` in this order: `WG_MANAGER_GUM`, local `bin/gum`, then `PATH`.
- Validate that the resolved path is executable.
- Check required `gum` subcommands or minimum version at startup.
- Fail with a clear message when TUI is requested without usable `gum`.
- Keep all `gum` invocation details in small UI wrapper functions.
- Backend functions must never call `gum` directly.
- Use `gum choose` for short finite menus.
- Use `gum filter` for searchable client selection.
- Use `gum input` for short validated text fields.
- Use `gum confirm` before deletion, restoration, or key rotation.
- Use `gum table` only for display or selection, not as a data store.
- Use `gum pager` for logs, diagnostics, and long text.
- Use `gum spin` only when the wrapped operation can safely hide routine output.
- Preserve stderr from failed commands behind a spinner.
- Never show secret content inside a spinner command line.
- Keep stable internal values separate from translated display labels.
- Treat cancellation and Escape as normal control flow, not an error.
- Return to the previous screen after cancellation.
- Do not trap users in an endless menu loop after repeated failures.
- Keep the main menu shallow and task-oriented.
- Show interface name and current status on the main screen.
- Use consistent verbs: view, add, remove, diagnose, restore, exit.
- Show the exact target before asking for destructive confirmation.
- Require stronger confirmation for restoring backups or deleting client material.
- Keep colors readable on light and dark terminals.
- Do not communicate status by color alone.
- Keep layouts usable at 80 columns.
- Avoid assumptions about mouse support.
- Do not clear valuable terminal output after an error.
- Detect noninteractive stdin or stdout before starting TUI.
- Never emit TUI control output into pipelines or redirected files.
## Error handling
- Provide one concise user-facing error plus actionable context.
- Preserve the failing command's status where meaningful.
- Do not expose secret variable values in error messages.
- Distinguish validation errors from system failures.
- Distinguish skipped diagnostic checks from successful checks.
- Diagnostic results use `OK`, `WARN`, `FAIL`, or `SKIP`.
- A critical diagnostic failure must produce a nonzero status.
- Include remediation guidance when it is reliable and specific.
- Avoid guessing firewall fixes across distributions.
- Continue independent diagnostic checks after a nonfatal failure.
## Dependencies and portability
- Assume a Linux server with Bash and WireGuard tools.
- Keep required dependencies listed in `MVP.md` and README.
- Treat `qrencode`, systemd, `nft`, and `iptables` as optional capabilities.
- Detect optional commands before using them.
- Do not fail the entire diagnostic run because one optional tool is absent.
- Prefer feature detection over distribution detection.
- Do not assume systemd is PID 1 on every supported server.
- Support at least Linux `x86_64`; document additional tested architectures.
- Do not assume the bundled `gum` binary matches the current architecture.
- Report architecture mismatch clearly.
## Tests
- Add regression tests for every fixed bug.
- Tests must not modify the host's real `/etc/wireguard`.
- Use fixtures for server configs, peer blocks, and metadata.
- Mock external commands through a controlled test `PATH`.
- Cover `wg`, `wg-quick`, `ip`, `systemctl`, `journalctl`, `nft`, and `iptables` as needed.
- Test success, expected failure, rollback, and interruption paths.
- Test client names containing spaces, newlines, glob characters, and option prefixes.
- Test duplicate keys, duplicate IPs, and overlapping networks.
- Test empty peer lists and unmanaged peers.
- Test CLI behavior without `gum`.
- Test local binary, environment override, and `PATH` resolution for `gum`.
- Test that logs do not contain generated secrets.
- Test concurrent mutation attempts.
- Test restoration failure and failed rollback reporting.
- Keep tests deterministic; do not depend on external network access.
- Use temporary test directories and remove them safely.
## Quality gates
- Run `bash -n` on every changed shell script.
- Run ShellCheck on every changed shell script when available.
- Run the relevant automated tests.
- Format consistently; use `shfmt` when the project adopts a fixed style.
- Do not silence ShellCheck globally to hide local problems.
- Add a narrow inline suppression only with an explanatory comment.
- Review diffs for accidental key material before finishing.
- Review file permissions in tests that create secrets.
- Verify that failure paths preserve the original config.
- Verify CLI output with stdout redirected.
- Verify TUI entry and cancellation in an interactive terminal.
## Documentation
- Update `MVP.md` only when product scope or architecture changes.
- Keep operational usage in README once implementation begins.
- Document every CLI command and its exit behavior.
- Document required and optional dependencies separately.
- Include examples that use placeholder keys and addresses only.
- Never commit real endpoints, private keys, preshared keys, or client configs.
- Explain backup and restore behavior before users rely on it.
- Document limitations of handshake history and traffic visibility.
## Definition of done
- The requested behavior is implemented through shared backend functions.
- Mutations are locked, validated, backed up, atomic, and reversible.
- CLI operation remains available independently of the TUI.
- TUI uses the configured `gum` resolution order.
- Errors are actionable and do not reveal secrets.
- Relevant tests pass.
- `bash -n` passes.
- ShellCheck has no unexplained findings.
- Documentation matches observable behavior.
- No unrelated files or user changes are overwritten.