Archipelago — open-source initial import

This commit is contained in:
Archipelago
2026-08-12 10:55:50 +00:00
commit 1e5d0cd313
1931 changed files with 440577 additions and 0 deletions
@@ -0,0 +1,131 @@
---
phase: 01-federation-mesh-hardening
plan: 20
subsystem: infra
tags: [tor, doctor, shell, mesh, permissions]
requires:
- phase: 01-federation-mesh-hardening
provides: "scripts/container-doctor.sh's fix_* convention and the archipelago-doctor.timer (OnUnitActiveSec=5min) that drives it"
provides:
- "A permission predicate that tests the property that matters (group/other denied) instead of exact-matching one octal string"
- "A 30-minute Tor restart backoff, so a restart storm is structurally impossible even if some future condition makes the fix fire repeatedly"
affects: [tor, mesh, doctor]
tech-stack:
added: []
patterns:
- "Assert the property, not the representation: `2700` and `700` both deny group and other, which is the security property. Exact-matching the string `700` turned Tor's own setgid bit into a permanent false positive."
- "Pair a predicate fix with a rate limit: the predicate stops today's loop, the backoff stops the whole class of loop. One is a fix, both is a guarantee."
key-files:
created: []
modified:
- scripts/container-doctor.sh
key-decisions:
- "Compare the low three digits of `stat -c '%a'` rather than the whole string, so both `700` and `2700` read as correct while `750`, `707` and `2755` are still corrected."
- "The 'already correct' path logs at debug level only. The original defect was invisible precisely because 'Fixed permissions on … (2700 -> 700)' looked like the doctor working — a healthy node should stay quiet."
- "Backoff state lives in `/var/lib/archipelago/doctor-tor-last-restart` with a 1800s window, and non-numeric/missing content reads as 0 so a corrupt state file fails open into 'restart allowed' rather than wedging the fix permanently."
requirements-completed: [FED-09]
coverage:
- id: D1
description: "The doctor no longer restarts Tor on every run — Tor uptime grows past the doctor's 5-minute interval"
requirement: "FED-09"
verification:
- kind: manual_procedural
ref: "archi-dev-box 2026-08-02: tor@default active since 2026-08-01 15:25:45 — 15+ hours continuous, spanning ~180 doctor intervals"
status: pass
human_judgment: false
- id: D2
description: "A hidden-service directory at Tor's own 2700 is recognised as correct — no chmod, no restart"
requirement: "FED-09"
verification:
- kind: other
ref: "Predicate exercised directly on tmpdirs: 2700 -> low3=700 -> ACCEPTED; 700 -> ACCEPTED"
status: pass
- kind: manual_procedural
ref: "archi-dev-box: zero 'Fixed permissions … hidden_service' lines across 542 doctor log entries in 6 hours"
status: pass
human_judgment: false
- id: D3
description: "A genuinely insecure directory (group/other readable) is still corrected"
requirement: "FED-09"
verification:
- kind: other
ref: "Predicate exercised on 750, 707 and 2755 — all three fall through to the corrective chmod"
status: pass
human_judgment: false
- id: D4
description: "Even on a real fix, Tor cannot be restarted more than once per backoff window"
requirement: "FED-09"
verification:
- kind: other
ref: "TOR_RESTART_BACKOFF_SECONDS=1800 gates the restart against TOR_RESTART_STATE_FILE; non-numeric state reads as 0"
status: pass
human_judgment: false
- id: D5
description: "Tor retains its consensus/HSDir cache long enough to resolve .onion addresses"
requirement: "FED-09"
verification:
- kind: manual_procedural
ref: "Post-OTA checkpoint on an affected node — NOT RUN (see below). 15h of unbroken Tor uptime on archi-dev-box is the necessary precondition and is met."
status: deferred
human_judgment: true
duration: 30min
completed: 2026-08-02
status: complete-pending-post-ota-checkpoint
---
# Phase 1 Plan 20: Stop the Doctor Fighting Tor Over the Setgid Bit (FED-09) Summary
**The container doctor treated Tor's own `2700` hidden-service directory as a permission defect, "fixed" it, and restarted Tor — every five minutes, forever. Tor never lived long enough to build a usable HSDir cache, so onion lookups failed and the mesh's Tor fallback died with it.**
## Performance
- **Duration:** ~30 min (code committed 2026-07-31 as `4435f95e`; verification and this SUMMARY 2026-08-02)
- **Tasks:** 1/2 (Task 2 is a post-OTA checkpoint — see below)
- **Files modified:** 1
## Accomplishments
- The predicate now compares the low three digits of `stat -c '%a'`, so Tor's setgid `2700` and a plain `700` both read as correct, while `750`, `707` and `2755` are still corrected. Verified directly against all five modes.
- A 30-minute restart backoff (`/var/lib/archipelago/doctor-tor-last-restart`) makes a restart storm impossible even if some future condition makes the fix fire repeatedly. The predicate fixes today's bug; the backoff retires the class.
- The "already correct" branch logs at debug level so a healthy node stays quiet — the original defect hid inside a log line that read like success.
## Evidence on a real node (archi-dev-box, 2026-08-02)
- `tor@default` active since **2026-08-01 15:25:45** — over 15 hours continuous, spanning roughly 180 doctor intervals. Before the fix, observed restarts were 13:07:56 → 13:13:14 → 13:18:39 → 13:23:57, each within a second of a timer firing.
- **Zero** `Fixed permissions … hidden_service` lines across **542** doctor log entries in the preceding 6 hours.
## Deviations from Plan
None. The implementation matches the plan's action exactly: predicate corrected at the property level, backoff added, logging made quiet-when-healthy.
**Process note:** the code landed on 2026-07-31 as `4435f95e` but no SUMMARY was written and the roadmap entry was never ticked, so the plan looked unstarted for two days. That is the bookkeeping gap this file closes.
## Known Stubs
None.
## Threat Flags
- The plan's prohibition — never loosen hidden-service permissions — holds: group and other access is still denied on every path. `2700` is accepted precisely *because* it denies them; the setgid bit is orthogonal to that property.
- **Scope boundary respected:** the FIPS direct-transport `connect_fail` (problem 1 in the diagnosis) was deliberately NOT touched here. It belongs with FED-03's structured review of the transport/dial layer.
## Outstanding: post-OTA checkpoint (Task 2)
Task 2 verifies on an **affected** node after the release lands, and explicitly forbids deploying
directly to a user's device (`archy-x250-mad2` or any node that is not ours) — verification is
post-OTA only. Remaining there:
1. Tor uptime keeps growing across three doctor intervals (met on archi-dev-box; needs repeating on an affected node)
2. No recurring "Fixed permissions" lines (met on archi-dev-box)
3. Onion resolution works — a mesh send to a Tor-only peer succeeds and `No more HSDir available to query` is gone
4. The doctor still corrects a deliberately `chmod 750`'d hidden-service directory
Items 3 and 4 are the ones genuinely outstanding; 1 and 2 already have real-node evidence.
</content>