Handle client keys, encrypted vault
This commit is contained in:
@@ -266,11 +266,11 @@ No Alpine build, container tunnel, or VM/systemd check is claimed by M1 acceptan
|
||||
|
||||
#### Review and repair
|
||||
|
||||
| Finding | Iteration | Location and impact | Owner | Resolution and evidence | State |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| M1-R1-01 | R1/R2 | `src/domain.rs` constructor can claim verified without a matching applied snapshot; misleading state | repairer | constructor rejects inconsistent Verified; Commit/mismatch demote stale Verified; 13 focused, 22 total tests passed; R2 confirmed | closed |
|
||||
| M1-R1-02 | R1/R2 | `AGENTS.md` still claims no Rust application exists | coordinator | opening statement updated to limited scaffold; R2 confirmed | closed |
|
||||
| M1-R1-03 | R1/R2 | `Cargo.lock` existed outside Git index | coordinator | `git add -N Cargo.lock`; `git ls-files --error-unmatch Cargo.lock` succeeds; R2 confirmed; no commit/content staging | closed |
|
||||
| Finding | Iteration | Location and impact | Owner | Resolution and evidence | State |
|
||||
| -------- | --------- | ---------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------- | ------ |
|
||||
| M1-R1-01 | R1/R2 | `src/domain.rs` constructor can claim verified without a matching applied snapshot; misleading state | repairer | constructor rejects inconsistent Verified; Commit/mismatch demote stale Verified; 13 focused, 22 total tests passed; R2 confirmed | closed |
|
||||
| M1-R1-02 | R1/R2 | `AGENTS.md` still claims no Rust application exists | coordinator | opening statement updated to limited scaffold; R2 confirmed | closed |
|
||||
| M1-R1-03 | R1/R2 | `Cargo.lock` existed outside Git index | coordinator | `git add -N Cargo.lock`; `git ls-files --error-unmatch Cargo.lock` succeeds; R2 confirmed; no commit/content staging | closed |
|
||||
|
||||
#### Evidence and handoff
|
||||
|
||||
@@ -619,9 +619,409 @@ remain. Stop here; milestone 3 is the next action only on a new request.
|
||||
|
||||
### Milestone 3 — Client keys, encrypted vault, and existing-client import
|
||||
|
||||
Implement separate vault/client key pairs, recipient encryption, password-protected vault identity, and versioned secret storage. Import from the configured directory on initial setup without deleting originals. Verify key correspondence and classify anomalies; conflicts block reissue until resolved.
|
||||
Status: accepted (2026-10-19T20:08:32Z; independent R7 review and coordinator gates passed).
|
||||
Prerequisites: milestones 1 and 2 accepted; pinned native Rust environment and
|
||||
access to compatible approved cryptographic dependencies or a populated cache.
|
||||
No root, running WireGuard, systemd, Docker, VM, or production input is needed.
|
||||
|
||||
Acceptance: new secrets encrypt without password entry, correct/incorrect password and corruption paths are covered, original files are unchanged, duplicates/conflicts are represented correctly, and persisted application data contains no plaintext client private keys. WireGuard key handling uses approved libraries, not utility subprocesses.
|
||||
#### Outcome and scope
|
||||
|
||||
Deliver library operations for WireGuard client key generation, encrypted vault
|
||||
initialization, password-free encryption of new records, password-authorized
|
||||
secret retrieval, and safe reconciliation/import of existing client files.
|
||||
Reuse M1 identities/settings and M2 server inspection without rewriting originals.
|
||||
|
||||
Read SPEC.md Data sources, Encrypted vault, Importing existing clients, Connection
|
||||
delivery, and Backups and restoration; ADRs 0002 and 0003; CONFIG_FORMAT.md;
|
||||
DEPENDENCIES.md, DEVELOPMENT.md, and TESTING.md. Preserve the distinction between
|
||||
vault encryption, server secrets, and an unencrypted output file.
|
||||
|
||||
This milestone prepares versioned vault bytes and encrypted import results;
|
||||
filesystem persistence/Commit and its mandatory backups belong to milestone 4.
|
||||
Initial setup prepares encryption of valid existing files immediately in the
|
||||
same setup operation, but must not install a vault, rewrite the server, or bypass
|
||||
the later persistence gate. Use supplied buffers and an explicit read-only source
|
||||
adapter; no automatic scan at application startup. TUI/password prompts, delivery
|
||||
files/QR and first-delivery session orchestration belong to milestones 6 and 7.
|
||||
No runtime or service operations are introduced.
|
||||
|
||||
#### Existing code and integration constraints
|
||||
|
||||
- M1 provides `domain::PublicKey`, `Client`, `ClientAddresses`, `Snapshot`,
|
||||
`ClientStates`, and validated/resolved settings, including the source directory
|
||||
and data paths. Public keys, not filenames or repeated aliases, identify secrets.
|
||||
- M2 exposes `wireguard::ConfigDocument::parse`, `render`, `peers`, `sections`,
|
||||
and `source_slice`, plus explicit add/delete/rename/legacy-metadata edits.
|
||||
`PeerInspection` provides identity candidates, AllowedIPs, metadata, and issues.
|
||||
Its raw source may contain secrets; never expose it through import reports.
|
||||
- `project_client` requires valid attached metadata and a supported address shape.
|
||||
Do not make successful projection a prerequisite for preserving or reconciling
|
||||
existing records. Missing metadata, IPv6-only peers, extra routes, and ambiguous
|
||||
keys must remain inspectable rather than being silently dropped or normalized.
|
||||
- Managed metadata is already v1: Base64url alias and optional strict UTC creation
|
||||
string in an attached comment block. Keep that grammar unchanged. The server
|
||||
alias wins; a filename/public-key fallback is display-only until an explicit
|
||||
metadata edit. Do not assign import time as an unknown creation date.
|
||||
- Server parsing is not client parsing: a client file's `[Interface] PrivateKey`
|
||||
identifies the client, while its `[Peer] PublicKey` normally identifies the
|
||||
server. Never use that server key as the client's identity.
|
||||
- Cargo currently contains base64, ipnet, rustix, serde, thiserror, and toml.
|
||||
Add only the approved crypto crates needed here: age, x25519-dalek, getrandom,
|
||||
secrecy, and zeroize; tempfile may be a dev-dependency for source-adapter tests.
|
||||
Verify current official APIs, maintained compatible versions, feature flags,
|
||||
and secret-type compatibility before choosing them. No custom cipher/KDF,
|
||||
OpenSSL subprocess, `wg genkey`, unapproved crate, or unrelated upgrade.
|
||||
|
||||
#### Context and implementation steps
|
||||
|
||||
Run these tasks sequentially with one writer. GPT-6-Sol/medium coordinates;
|
||||
GPT-6-Luna/high implements, reviews independently, and repairs. The coordinator
|
||||
supplies scope, owned files, relevant documents, accepted interfaces, checks, and
|
||||
required report contents. Workers do not accept milestones or edit PLANS.md.
|
||||
|
||||
| Task | Owner | Files and deliverable |
|
||||
| --- | --- | --- |
|
||||
| M3.1 | implementer | `src/vault.rs`, optional `src/vault/keys.rs`, `src/lib.rs`, Cargo files: secret-safe WireGuard key types, generation and matching |
|
||||
| M3.2 | implementer | `src/vault/` modules as needed, `docs/VAULT_FORMAT.md`: asymmetric vault setup, password-protected identity, versioned envelopes and load validation |
|
||||
| M3.3 | implementer | `src/vault/import.rs` or a narrow import module: caller-buffer client parsing, reconciliation reports and encrypted import preparation |
|
||||
| M3.4 | implementer | read-only configured-directory adapter, `tests/vault_import.rs`, synthetic temporary inputs and README guidance: initial setup/import workflow and failure coverage |
|
||||
| M3.5 | reviewer, repairer | Independent crypto/use-of-library, import and integrated regression review; bounded fixes and re-review |
|
||||
| M3.6 | coordinator | Integrated gates, findings/evidence and acceptance/handoff in PLANS.md |
|
||||
|
||||
M3.1 wraps private keys/passwords in secret-aware containers with redacted or no
|
||||
Debug, no implicit Display/Serialize, and explicit exposure only at necessary
|
||||
cryptographic/encoding boundaries. Generate WireGuard-compatible private keys
|
||||
using OS randomness and derive their public key using x25519-dalek. Preserve
|
||||
canonical WireGuard Base64 on output; validate decoded length/encoding on input.
|
||||
Keep imported private-key bytes intact rather than replacing them with newly
|
||||
generated keys. Test generation/derivation and matching without leaking values
|
||||
in assertion failures. Handle random-source errors as recoverable errors.
|
||||
|
||||
M3.2 initializes a separate age recipient/identity pair, never reusing a WireGuard
|
||||
key. Store only the recipient and password-encrypted vault identity in the public
|
||||
serialized bundle; encrypt each client record to that recipient without requiring
|
||||
the password. Use the age library's established authenticated encryption and
|
||||
password protection; do not implement the cryptographic construction manually.
|
||||
|
||||
Document exact v1 vault/record formats, component filenames/layout intended for
|
||||
M4, version handling, public record identifiers, and size limits before encoding
|
||||
production data. Use serde/TOML or opaque age payloads as appropriate, without
|
||||
silently introducing a second serializer dependency. Ensure serialization cannot
|
||||
write plaintext secrets through a generic derive. Reject unknown versions and
|
||||
truncated/oversized structures with redacted typed errors.
|
||||
|
||||
Bind the decrypted payload to its expected client public key and vault context;
|
||||
derive its public key again and reject mislabelled/swapped records. On unlocking,
|
||||
verify the decrypted vault identity matches the declared recipient. Do not allow
|
||||
public envelope metadata alone to authorize a key's identity or reissue status.
|
||||
Do not invent cryptography to authenticate a plaintext index: document the limits
|
||||
of unauthenticated public metadata and perform the necessary checks after decrypt.
|
||||
|
||||
Each authorized retrieval accepts a fresh password, decrypts only for that
|
||||
operation, validates binding, and returns an explicit short-lived secret result.
|
||||
Do not cache an unlocked identity, retain the password between requests, or fall
|
||||
back to original plaintext files after wrong password, missing/corrupt records,
|
||||
or password loss. Keep cloning/exposure of secrets minimal; zeroize supported
|
||||
owned buffers on drop and document unavoidable library-managed copies without
|
||||
claiming all process memory can be erased. Password-policy/UI additions are not
|
||||
part of this milestone.
|
||||
|
||||
M3.3 parses supplied client content without generic lossy INI serialization.
|
||||
Require one unambiguous client private key and derive its PublicKey for matching.
|
||||
Validate client Address values while retaining enough information to report
|
||||
unsupported shapes and compare addresses rather than conflating client prefixes
|
||||
with server host routes. Preserve existing optional connection parameters needed
|
||||
later, including any valid preshared secret, inside the encrypted payload; do not
|
||||
introduce new MTU/keepalive/PSK settings or generation. Reject ambiguous or malformed
|
||||
secret fields rather than choosing the last occurrence. Do not run PostUp/hooks,
|
||||
resolve DNS, mutate routes, or execute text from imported files.
|
||||
|
||||
Reconcile against the authoritative M2 server inspection and provide explicit,
|
||||
secret-free results for server-only, file-only, matched, mismatched, invalid,
|
||||
and ambiguous/duplicate candidates. Missing/invalid managed metadata and narrow
|
||||
projection failures are represented separately from cryptographic key mismatch.
|
||||
Compare the client file's server peer key with the server identity when it can
|
||||
be determined safely; absent/ambiguous server identity is unresolved, not assumed
|
||||
valid. Do not infer identity from filenames or friendly aliases.
|
||||
|
||||
Matching key material may be encrypted even when address parameters conflict,
|
||||
but record/report that reissue is blocked pending explicit reconciliation. Do
|
||||
not truncate routes, overwrite server metadata, automatically add a file-only
|
||||
client to the VPN, or treat public filename fallback as authoritative. Duplicate
|
||||
files or existing vault entries must not cause silent overwrite or last-wins
|
||||
selection; preserve the prior record and return an explicit resolution issue.
|
||||
A repeat import without decryption must not claim plaintext equality it cannot
|
||||
verify. Define deterministic handling and tests rather than guessing equivalence.
|
||||
|
||||
M3.4 supplies a bounded read-only adapter for the configured source directory:
|
||||
regular files only, documented candidate selection, no recursive traversal or
|
||||
symlink following, bounded content sizes, and redacted per-file errors. A source
|
||||
file failure must not abort other valid imports; a directory-enumeration failure
|
||||
must be visible and must not be called a successful complete scan. Use safe file
|
||||
opening for privileged future callers; expanding rustix's approved feature set
|
||||
is permitted when required, but no new direct crate is implicitly approved.
|
||||
|
||||
Initial setup combines vault creation with attempted import of valid candidates.
|
||||
Return the encrypted prepared bundle and a report; invalid/conflicting candidates
|
||||
remain visible and originals are untouched. Explicit later import reuses the
|
||||
vault recipient without asking for a password or replacing the protected identity.
|
||||
Reissue authorization remains separate. Keep directory IO out of pure parsing and
|
||||
crypto tests; all adapter tests use synthetic temporary directories, never actual
|
||||
configured server/client paths. All writes in this milestone are test artifacts
|
||||
or explicit serialization buffers, not installed application state.
|
||||
|
||||
#### Acceptance and validation
|
||||
|
||||
- [x] M3-A1: generated WireGuard keys derive valid PublicKey values; imported key
|
||||
correspondence and malformed Base64/length handling are tested without tools.
|
||||
- [x] M3-A2: vault setup uses an independent key pair and password-protected
|
||||
identity; serialized application vault data contains no plaintext private keys,
|
||||
passwords, or imported secret-bearing configurations.
|
||||
- [x] M3-A3: new record encryption and later explicit import need only the public
|
||||
recipient, not a password/unlocked identity; loading ciphertext needs no password.
|
||||
- [x] M3-A4: correct-password retrieval returns the selected secret; wrong/missing
|
||||
password, unknown versions, malformed/truncated ciphertext, recipient mismatch,
|
||||
and record relabelling fail without fallback or loss of the original bundle.
|
||||
- [x] M3-A5: independent retrieval operations require fresh authorization, with no
|
||||
reusable unlocked identity/password exposed through ordinary vault APIs. Errors,
|
||||
reports and Debug are redacted; secret serialization is explicit and protected.
|
||||
- [x] M3-A6: matching uses the public key derived from client Interface PrivateKey,
|
||||
not its server peer key or alias. Reports cover matched/server-only/file-only,
|
||||
conflicts, invalid files, duplicate/ambiguous keys and unsupported address shapes.
|
||||
- [x] M3-A7: address/server-binding discrepancies remain explicit and block the
|
||||
authorized reissue path until resolved; a valid secret may still be encrypted.
|
||||
Duplicate imports never silently replace existing secrets or trusted metadata.
|
||||
- [x] M3-A8: setup prepares encrypted imports from valid source files while skipping
|
||||
invalid candidates with explanations. Regular-file selection, limits, symlink
|
||||
rejection and enumeration failures are tested using temporary data only.
|
||||
- [x] M3-A9: source files and original server bytes are unchanged; no metadata is
|
||||
implicitly inserted, no creation dates invented, and M2 parsing/editing guarantees
|
||||
remain intact. Missing metadata does not prevent encrypted preservation of a key.
|
||||
- [x] M3-A10: serialized bundle round-trip preserves encrypted identity/records
|
||||
without decryption, ready for M4 backup/persistence; no filesystem installation,
|
||||
implicit Commit/runtime change, UI delivery or first-issue bypass is introduced.
|
||||
- [x] M3-A11: standard integrated gates and M1/M2 regressions pass; independent
|
||||
review closes actionable crypto, import, secret-lifetime and boundary findings.
|
||||
|
||||
Planned commands from the repository root after M3 tests and lockfile exist:
|
||||
|
||||
```sh
|
||||
cargo test --locked vault
|
||||
cargo test --locked --test vault_import
|
||||
cargo test --locked --test config_preservation
|
||||
cargo fmt --all -- --check
|
||||
cargo clippy --locked --all-targets -- -D warnings
|
||||
cargo test --locked
|
||||
cargo build --locked --release
|
||||
./target/release/wireguard-admin --help
|
||||
./target/release/wireguard-admin --version
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Ensure the focused filter runs tests and record counts/results; all gates should
|
||||
exit zero. Resolve approved new dependencies/update the lockfile before locked
|
||||
checks. Keep password-encryption tests bounded while exercising real library
|
||||
crypto; do not weaken production KDF parameters simply to speed up tests. Use
|
||||
synthetic generated keys and no sensitive panic/assert output. No root, Docker,
|
||||
VM, actual WireGuard interface, or production config is required or claimed.
|
||||
|
||||
#### Progress
|
||||
|
||||
- [x] Description prepared against accepted M1/M2 code and current documents.
|
||||
- [x] M3.1 — implementer (`/root/implementer_m3_1`) completed 2026-10-18T19:41:39Z; secret-safe WireGuard key generation, parse, derivation and matching.
|
||||
- [x] M3.2 — implementer (`/root/implementer_m3_2`) completed 2026-10-18T19:46:09Z; versioned age-encrypted bundle, fresh-password retrieval, format documentation.
|
||||
- [x] M3.3 — implementer (`/root/implementer_m3_3`) completed 2026-10-18T19:52:45Z; caller-buffer parse/reconciliation and authenticated import status.
|
||||
- [x] M3.4 — implementer (`/root/implementer_m3_4`) completed 2026-10-18T19:58:55Z; bounded read-only directory adapter, initial setup/import flow and synthetic tests.
|
||||
- [x] M3.5 — fresh reviewer (`/root/reviewer_m3_r1`) completed R1–R7; repairer (`/root/repairer_m3_r1`) resolved all findings; R7 found no actionable issue.
|
||||
- [x] M3.6 — coordinator integrated gates passed and acceptance recorded.
|
||||
|
||||
#### Review and repair
|
||||
|
||||
| Finding | Iteration | Location and impact | Owner | Resolution and evidence | State |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| M3-R1-01 | R1 | `src/vault.rs:134` Debug printed untrusted imported connection fields | repairer | Redacted imported payload Debug; sentinel regression and R2 passed | closed |
|
||||
| M3-R1-02 | R1 | `src/vault/source.rs:110` directory path was reopened after secure FD open, allowing enumeration/read inventory mismatch | repairer | Enumerates through pinned `rustix::fs::Dir`; path-replacement regression and R2 passed | closed |
|
||||
| M3-R1-03 | R1 | `src/vault/import.rs:409` unknown server identity was collapsed into a known key mismatch | repairer | Added Matches/Mismatch/Unresolved and blocked retrieval regression; R2 passed | closed |
|
||||
| M3-R1-04 | R1 | `src/vault/source.rs:206` duplicate existing vault entry was generic encryption failure | repairer | Added equality-unverified duplicate issue; repeat-import regression and R2 passed | closed |
|
||||
| M3-R2-01 | R2 | `docs/VAULT_FORMAT.md` omitted intended component filename/layout for M4 | repairer | Documented intended `data_directory/vault.toml` without persistence; R3 confirmed | closed |
|
||||
| M3-R2-02 | R2 | Secret-bearing test `assert_eq!` output could disclose synthetic key/config bytes on failure | repairer | Replaced with redacted boolean assertions; R3 confirmed | closed |
|
||||
| M3-R3-01 | R3 | `src/vault.rs:306` unsupported encrypted payload version reported as `RecordMismatch`, not actionable `UnsupportedVersion` | repairer | Split version/label checks; valid encrypted unsupported-version regression and R4 passed | closed |
|
||||
| M3-R4-01 | R4 | `src/vault.rs:48` canonical Base64 comparison created a plaintext key `String` without zeroization | repairer | Wrapped in `Zeroizing<String>`; R5 confirmed | closed |
|
||||
| M3-R5-01 | R5 | `src/vault.rs:38` Base64 decode could drop partially decoded key bytes on malformed input before zeroizing wrapper | repairer | Decode into zeroizing buffer from allocation onward; R6 confirmed | closed |
|
||||
| M3-R5-02 | R5 | `src/vault.rs:287` identity UTF-8 conversion cloned decrypted identity into ordinary Vec, vulnerable on error | repairer | Borrow from zeroizing plaintext; R6 confirmed | closed |
|
||||
| M3-R6-01 | R6 | `src/vault/import.rs:112` allocated ordinary directive String before knowing whether value was secret/ignored | repairer | Borrowed dispatch; zeroizing PrivateKey/PSK allocations, duplicate/error paths and regressions passed; R7 confirmed | closed |
|
||||
|
||||
The reviewer otherwise found crypto binding, fresh authorization and bounded
|
||||
scan behavior sound at fixture level. No finding may be closed by hiding a
|
||||
conflict, disabling tests, or relaxing encryption.
|
||||
|
||||
#### Evidence and handoff
|
||||
|
||||
Planning inspected Cargo.toml, exported M2 document/edit/metadata APIs,
|
||||
CONFIG_FORMAT.md, M1 model constraints, approved dependencies and ADR 0002.
|
||||
M2 records independent R3 acceptance, 42 unit plus 9 integration tests, and passing
|
||||
integrated gates. Those results are historical evidence; this planning task did
|
||||
not rerun application tests, select crypto versions, or add dependencies/source.
|
||||
No workers were dispatched and no source directory, private key, service, or
|
||||
network environment was accessed.
|
||||
|
||||
Next execution action: verify configured model roles and the current repository,
|
||||
review official APIs/compatibility for the approved cryptographic libraries, then
|
||||
dispatch M3.1 with the bounded task and acceptance criteria. Escalate unavailable
|
||||
packages as dependency/environment blockers rather than changing approved crypto.
|
||||
|
||||
Execution verified the coordinator session as `gpt-6-sol`/`medium`; M1 and M2
|
||||
are accepted. At start, the only worktree change was this prepared M3 plan.
|
||||
Rustc/Cargo 1.97.1, rustfmt 1.9.0 and Clippy 0.1.97 match the pinned baseline.
|
||||
Official crate documentation was checked for `age` 0.12.1 (Rust 1.74 minimum,
|
||||
recipient and passphrase APIs, no default features), `x25519-dalek`,
|
||||
`getrandom`, and `secrecy`. `age` re-exports its compatible `secrecy` via
|
||||
`age-core`; use that re-export rather than adding a conflicting direct version.
|
||||
The local cache initially lacked `age`; a read-only `cargo info age@0.12.1`
|
||||
failed under sandbox DNS restrictions, then succeeded with approved network
|
||||
escalation. No manifest or source was changed during this prerequisite check.
|
||||
Next: assign M3.1 to the configured implementer.
|
||||
M3.1 added `vault::WireGuardPrivateKey` using approved `x25519-dalek` 2.0.1,
|
||||
`getrandom` 0.3.4, and `zeroize` 1.9.0; no `age`/`secrecy` direct dependency was
|
||||
introduced prematurely. The coordinator inspected the new key API and manifest.
|
||||
The implementer ran `cargo test --locked vault` (3 tests), `cargo test --locked`
|
||||
(45 unit and 9 preservation integration tests), fmt, Clippy, release build and
|
||||
diff check successfully. Its turn context was verified `gpt-6-luna`/`high`.
|
||||
No production data or service was accessed. Next: M3.2 versioned age vault
|
||||
format and authorized retrieval on top of this key type.
|
||||
M3.2 added approved `age` 0.12.1, `VaultBundle` recipient encryption and
|
||||
passphrase-protected identity, bounded TOML loading, ciphertext/recipient/key
|
||||
binding checks, and `docs/VAULT_FORMAT.md`. The coordinator inspected source,
|
||||
format and manifest. The worker ran `cargo test --locked vault` (9 tests),
|
||||
`cargo test --locked` (51 unit and 9 preservation integration tests), fmt,
|
||||
Clippy, release build and diff check successfully; its turn context was
|
||||
verified `gpt-6-luna`/`high`. This is task progress, not integrated M3
|
||||
acceptance. M3.3 must extend encrypted records to retain imported connection
|
||||
parameters and enforce duplicate/no-overwrite and conflict reissue semantics;
|
||||
independent review must scrutinize the current public `reissue_blocked` flag's
|
||||
authority and secret lifetime. Next: M3.3 caller-buffer import/reconciliation.
|
||||
M3.3 added `src/vault/import.rs` and extended the encrypted v1 record payload
|
||||
to retain imported connection parameters, including valid PSKs. It changed
|
||||
duplicate insertion to fail without overwrite and moved the conflict gate into
|
||||
the authenticated payload; the public flag is advisory. The coordinator
|
||||
inspected implementation and updated format documentation. The worker ran
|
||||
`cargo test --locked vault` (15 tests), `cargo test --locked` (57 unit and 9
|
||||
preservation integration tests), fmt, Clippy, release build and diff check
|
||||
successfully; its turn context was verified `gpt-6-luna`/`high`. This remains
|
||||
pending independent review. Potential review focus: unresolved versus
|
||||
mismatched server identity classification, preservation and lifetime of source
|
||||
buffers, and absence of conflict-clearing bypass. Next: M3.4 bounded read-only
|
||||
directory adapter and setup/import workflow.
|
||||
M3.4 added `src/vault/source.rs`, `tests/vault_import.rs`, README guidance,
|
||||
approved `tempfile` 3.23.0 as a development dependency, and `rustix` fs/std
|
||||
features. It uses Linux `openat2` no-symlink file opens, per-file/aggregate
|
||||
limits and incomplete-scan reporting. The coordinator inspected the adapter,
|
||||
fixture tests and manifest. The worker ran `cargo test --locked vault` (16
|
||||
tests), `cargo test --locked --test vault_import` (5),
|
||||
`cargo test --locked --test config_preservation` (9), `cargo test --locked`
|
||||
(58 unit, 9 preservation and 5 vault-import tests), fmt, Clippy, release build
|
||||
and diff check successfully; its turn context was verified `gpt-6-luna`/`high`.
|
||||
No production path or service was accessed. Possible review focus: path-based
|
||||
directory enumeration after secure fd open, explicit duplicate-existing-record
|
||||
reporting, and whether server-key unknown is distinct from mismatch. Linux
|
||||
`openat2` absence yields an incomplete scan, not success. Next: fresh integrated
|
||||
independent review M3.5 before acceptance.
|
||||
Fresh R1 reviewer turn used `gpt-6-luna`/`high`. It inspected integrated code
|
||||
and ran focused vault (16), vault-import (5), and M2 preservation (9) tests;
|
||||
the full suite passed 58 unit plus 14 integration tests, and fmt, Clippy,
|
||||
release build, help/version and diff check passed. It found M3-R1-01 through
|
||||
M3-R1-04 above. These passing tests do not close the review findings. Next:
|
||||
repair, re-review, then coordinator integrated gates.
|
||||
The repairer (`/root/repairer_m3_r1`, `gpt-6-luna`/`high`) reported all four
|
||||
R1 findings repaired with focused regressions. It ran `cargo test --locked
|
||||
vault` (18), vault-import (5), M2 preservation (9), full tests (60 unit plus
|
||||
14 integration), fmt, Clippy, release build and diff check successfully. The
|
||||
coordinator inspected changed paths. Findings remain pending independent R2
|
||||
re-review; no acceptance is claimed yet.
|
||||
R2 independently confirmed M3-R1-01 through M3-R1-04 and found no remaining
|
||||
defect in those paths. It found M3-R2-01 and M3-R2-02 above. Focused vault
|
||||
(18), vault-import (5), preservation (9), full tests (60 unit plus 14
|
||||
integration), fmt, Clippy, release build, help/version and diff check passed;
|
||||
the passing gates do not resolve the documentation and test-output gaps. Next:
|
||||
narrow repair and R3 re-review.
|
||||
R3 independently closed M3-R2-01/02 and confirmed R1 repairs remain intact.
|
||||
It found M3-R3-01 and noted an M3-A7 evidence gap: the existing known
|
||||
server-key mismatch test also has unsupported address projection, so an
|
||||
isolated mismatch-blocks-reissue test is needed. Aggregate scan-byte and
|
||||
directory-entry limits are implemented but lack dedicated boundary tests;
|
||||
their coverage should be strengthened if practical. R3 reran focused vault
|
||||
(18), vault-import (5), preservation (9), full suite (60 unit plus 14
|
||||
integration), fmt, Clippy, release build, help/version and diff check
|
||||
successfully. Passing checks do not close M3-R3-01. Next: repair and R4.
|
||||
The repairer (`/root/repairer_m3_r1`) split encrypted payload version and
|
||||
label checks, added a valid age-encrypted unsupported-version regression, an
|
||||
isolated known server-key-mismatch/reissue-block regression, and inexpensive
|
||||
aggregate-byte/directory-entry cap tests through private testable limits. It
|
||||
reported 22 focused vault tests, 5 vault-import tests, 9 M2 preservation
|
||||
tests, 64 unit plus 14 integration tests in the full suite, and passing fmt,
|
||||
Clippy, release build and diff check. The coordinator inspected the new code;
|
||||
R4 independent re-review is pending. No M3 acceptance is claimed yet.
|
||||
R4 independently confirmed M3-R3-01 and all earlier repairs. It reran focused
|
||||
vault (22), vault-import (5), M2 preservation (9), full tests (64 unit plus
|
||||
14 integration), fmt, Clippy, release build, help/version and diff check,
|
||||
all passing. It found M3-R4-01 above; this must be repaired before M3
|
||||
acceptance. No production access or real-system result is claimed.
|
||||
R5 independently confirmed M3-R4-01 but identified M3-R5-01/02 in adjacent
|
||||
secret-lifetime paths. Focused vault (22), vault-import (5), preservation (9),
|
||||
full tests (64 unit plus 14 integration), fmt, Clippy, release build,
|
||||
help/version and diff check all passed; these checks do not prove zeroization
|
||||
on failure. Earlier repairs remain intact. Next: targeted cleanup and R6
|
||||
re-review; M3 is not accepted.
|
||||
R6 independently confirmed M3-R5-01/02: base64 decoding now occurs inside a
|
||||
zeroizing Vec even on failure, and age identity parsing borrows from zeroizing
|
||||
bytes. It found M3-R6-01 in the import parser. It reran focused vault (22),
|
||||
vault-import (5), M2 preservation (9), full suite (64 unit plus 14
|
||||
integration), fmt, Clippy, release build, help/version and diff check, all
|
||||
passing. No production access or real-system result was claimed. Next:
|
||||
targeted parser cleanup and R7.
|
||||
The repairer changed `src/vault/import.rs` to borrow section, directive key and
|
||||
value until dispatch; ignored/misplaced values are not allocated. Recognized
|
||||
PrivateKey/PSK values enter zeroizing storage immediately, including
|
||||
duplicate/error paths. Redaction regressions were added. It reported focused
|
||||
vault (22), full tests (64 unit plus 14 integration), fmt, Clippy, release
|
||||
build and diff check passing; the coordinator inspected the changed parser.
|
||||
Independent R7 re-review was the next gate after this repair.
|
||||
R7 independent reviewer (configured `gpt-6-luna`/`high`) inspected the final
|
||||
parser, prior repairs, cryptographic/secret lifetimes, source-directory safety
|
||||
and M3-A1–A11. It found no remaining actionable issue and recommended
|
||||
acceptance. The coordinator reran the full planned command set on the final
|
||||
integrated source on 2026-10-19: `cargo test --locked vault` passed 22 tests;
|
||||
`cargo test --locked --test vault_import` passed 5; `cargo test --locked --test
|
||||
config_preservation` passed 9; `cargo fmt --all -- --check`, `cargo clippy
|
||||
--locked --all-targets -- -D warnings`, `cargo build --locked --release`, and
|
||||
`git diff --check` exited zero; `cargo test --locked` passed 64 unit tests,
|
||||
9 preservation integration tests and 5 vault-import integration tests (0 doc
|
||||
tests); release `--help` and `--version` both exited zero with existing safe
|
||||
startup output. The focused vault filter ran 22 actual tests. These are
|
||||
unprivileged synthetic/unit fixture results only. No production files,
|
||||
running VPN, host service, Alpine container or systemd VM was accessed;
|
||||
container/VM checks are not required for this M3 library milestone and are
|
||||
not claimed. No M3 blocker remains.
|
||||
|
||||
#### Decisions and discoveries
|
||||
|
||||
The client's Interface private key and the server's Peer public key have different
|
||||
roles. Existing M2 source/span APIs support authoritative reconciliation but must
|
||||
not be reused as an unsafe source-dump parser for secrets. M1 projection cannot
|
||||
represent all legacy peers; use richer import inspection without changing that
|
||||
model or metadata v1 merely to suppress anomalies.
|
||||
|
||||
Prepared vault encoding is the M3/M4 interface: M3 supplies versioned encrypted
|
||||
components; M4 owns atomic installation, backup-before-mutation, restore, and
|
||||
Commit deletion. M6 owns file/QR generation and first-delivery session policy.
|
||||
This boundary avoids persisting unbacked state during an import/crypto milestone.
|
||||
|
||||
#### Outcome
|
||||
|
||||
Accepted after independent R7 review, closure of all findings and passing
|
||||
M3-A1–A11 gates. Stop here; milestone 4 is the next action only on a new
|
||||
request. No vault installation, Git commit, deployment or production access
|
||||
occurred.
|
||||
|
||||
### Milestone 4 — Backups, safe Commit, and full restoration
|
||||
|
||||
@@ -661,11 +1061,12 @@ Acceptance: real D-Bus job handling, separate restart verification, address rele
|
||||
|
||||
## Current progress and resume point
|
||||
|
||||
- Milestones 1 and 2 are accepted; milestones 3–9 remain pending.
|
||||
- Milestones 1, 2 and 3 are accepted; milestones 4–9 remain pending.
|
||||
- The approved dependency list is in [DEPENDENCIES.md](docs/DEPENDENCIES.md); container testing methodology is in [TESTING.md](docs/TESTING.md).
|
||||
- Milestone 1 is expanded and the Rust environment is pinned.
|
||||
- Milestone 2 delivered a lossless in-memory WireGuard configuration editor, versioned metadata, and behavioral preservation tests.
|
||||
- Next action: stop after accepted M2; begin M3 only if separately requested.
|
||||
- Milestone 3 delivered secret-safe key handling, a versioned encrypted vault, caller-buffer reconciliation, and a bounded read-only source-directory import adapter.
|
||||
- Next action: stop after accepted M3; begin M4 only if separately requested.
|
||||
- M1 integrated gates and independent re-review passed. No container or VM results are claimed.
|
||||
|
||||
## Plan maintenance
|
||||
|
||||
Reference in New Issue
Block a user