wgtunnel: S3 Part 1 — pure-Go keygen + hub wire (WireWireguard, report stanza, RegisterWG)
key.go: create-once 0600/0700, corrupt-refusal (never overwrite — may be escrowed identity), clamp for CANONICAL STORED form (x/crypto X25519 clamps derivation internally — discovered during red-proof (c); the stored-clamped test is the real anchor). Fixed vectors generated with real wg pubkey (provenance in test). hub: WireDesiredState.Wireguard + WireguardStatus report stanza + RegisterWG client (typed errors, token-free). S2 golden copied BYTE-IDENTICAL + field-exact decode test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
+38
-1
@@ -47,6 +47,22 @@ type HostReport struct {
|
||||
// (SPIKE-dr-recipe-2026-06-16). Derived from the facts above; carries ONLY identifiers/intents/
|
||||
// sizes/coordinates, never a secret. The hub assembles it with the controller's app half.
|
||||
DRRecipe *DRRecipeHostHalf `json:"dr_recipe"`
|
||||
|
||||
// Wireguard is the offsite-tunnel status stanza (S3, doc 06 §4.6). Present only when the
|
||||
// wg_tunnel feature is enabled. The report is stored opaquely hub-side, so no hub change is
|
||||
// needed; the pubkey here is the operator's revocation-recovery handle (re-add the peer with
|
||||
// it). Carries NO secret — the pubkey is public by definition.
|
||||
Wireguard *WireguardStatus `json:"wireguard,omitempty"`
|
||||
}
|
||||
|
||||
// WireguardStatus is the per-heartbeat offsite-tunnel status (S3). LastHandshakeAgeS is nil when
|
||||
// the handshake age is unreadable (service down, capability degraded) — nil ≠ 0.
|
||||
type WireguardStatus struct {
|
||||
Pubkey string `json:"pubkey"`
|
||||
Registered bool `json:"registered"` // the registration marker exists
|
||||
Active bool `json:"active"` // wg-quick@wg-felhom is-active
|
||||
LastHandshakeAgeS *int64 `json:"last_handshake_age_s,omitempty"`
|
||||
AssignedIP string `json:"assigned_ip,omitempty"` // from the marker, e.g. "10.77.0.2/32"
|
||||
}
|
||||
|
||||
// HostMetrics is the host block, sourced from proxmox NodeStatus.
|
||||
@@ -285,7 +301,9 @@ type DesiredStateResponse struct {
|
||||
// parts it can today (guests: benign deltas reconciled, an explicit decommission gated
|
||||
// pending_signature); the rest are FORWARD-COMPAT — carried + cached, NOT acted on in 10A. The
|
||||
// restore_directive is consumed in 10D (host/guest-loss DR); storage_manifest / backup_policy /
|
||||
// pbs_namespace are placeholders kept opaque so the wire is stable as those land.
|
||||
// pbs_namespace are placeholders kept opaque so the wire is stable as those land. The wireguard
|
||||
// block (S3) is HUB-OWNED state merged into the served document at read time (hub S2) — consumed
|
||||
// by internal/wgtunnel via the desired.Syncer raw-consumer seam.
|
||||
type WireDesiredState struct {
|
||||
Guests []WireDesiredGuest `json:"guests"`
|
||||
|
||||
@@ -293,6 +311,25 @@ type WireDesiredState struct {
|
||||
BackupPolicy json.RawMessage `json:"backup_policy,omitempty"`
|
||||
PBSNamespace string `json:"pbs_namespace,omitempty"`
|
||||
RestoreDirective *WireRestoreDirective `json:"restore_directive,omitempty"` // slice 10D (forward-compat)
|
||||
Wireguard *WireWireguard `json:"wireguard,omitempty"` // S3 (doc 06 §3.2; golden-pinned)
|
||||
}
|
||||
|
||||
// WireWireguard is the hub-owned offsite-tunnel assignment (S3) — field-exact with the S2 golden
|
||||
// (testdata/desired-state-wireguard.golden.json, byte-identical hub copy). Client-side
|
||||
// AllowedIPs, PersistentKeepalive=25 and MTU 1420 are deliberately NOT wire fields — wgtunnel
|
||||
// constants derived from endpoint.pbs_tunnel_ip + doc 06 §4.
|
||||
type WireWireguard struct {
|
||||
Endpoint WireWireguardEndpoint `json:"endpoint"`
|
||||
Pubkey string `json:"pubkey"` // the box's registered pubkey
|
||||
AssignedIP string `json:"assigned_ip"` // e.g. "10.77.0.2/32"
|
||||
}
|
||||
|
||||
// WireWireguardEndpoint is the endpoint half of the wireguard block.
|
||||
type WireWireguardEndpoint struct {
|
||||
DNSName string `json:"dns_name"`
|
||||
WGPort int `json:"wg_port"`
|
||||
ServerPubkey string `json:"server_pubkey"`
|
||||
PBSTunnelIP string `json:"pbs_tunnel_ip"`
|
||||
}
|
||||
|
||||
// WireDesiredGuest is one guest's target (slice 10A). Every field is optional ("unmanaged"); the
|
||||
|
||||
Reference in New Issue
Block a user