Document the PHP api layer and fix what documenting it exposed
Writing down what each endpoint actually guarantees made the places it didn't obvious — shell arguments reaching a crontab or a bash -c unescaped, master.conf written without tmp+rename, and conf edits that could be saved without ever being parsed.
This commit is contained in:
@@ -1,6 +1,52 @@
|
||||
<?php
|
||||
// Connectivity test — SSH echo to a partner host with round-trip latency.
|
||||
// GET ?id=HOST2 (GET avoids the bodyless-POST issue on this nginx setup).
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||
// PURPOSE
|
||||
// Partner connectivity test. Runs one SSH `echo ok` against a named host slot and reports
|
||||
// success plus round-trip latency — the "Test" button on the partnership tab.
|
||||
//
|
||||
// OPERATIONAL MODEL
|
||||
// Deliberately a GET, despite being an action. php -S and this nginx setup drop POST
|
||||
// bodies on Unraid PHP 8.4, so a POST would arrive with no id at all. The operation is
|
||||
// safe to repeat and changes nothing, which is what makes GET acceptable here rather than
|
||||
// merely convenient.
|
||||
//
|
||||
// DESIGN PRINCIPLES
|
||||
// Tests the real path, not a substitute for it.
|
||||
// The probe is SSH over the Tailscale IP with the same key every partnership operation
|
||||
// uses. An ICMP ping would answer a question nobody is asking — what matters is whether
|
||||
// this host can actually drive the partner.
|
||||
//
|
||||
// Distinguishes why it failed.
|
||||
// vv_pt_ping() returns separate errors for an unknown slot, a missing key, and an
|
||||
// unresolvable Tailscale name, because those need three different fixes.
|
||||
//
|
||||
// OPERATIONAL SAFEGUARDS
|
||||
// The host id is pattern-matched before it is used.
|
||||
// ^host\d+$ (case-insensitive) is enforced here, and the value is then only used as a
|
||||
// conf-key lookup — it never reaches a path or a shell. The remote command is the fixed
|
||||
// literal `echo ok`; nothing from the request composes it.
|
||||
//
|
||||
// The probe is time-boxed at 8 seconds.
|
||||
// vv_pt_ping() passes an explicit timeout to vv_pt_ssh(), which also sets BatchMode=yes
|
||||
// so it can never sit waiting for a password. A powered-off partner costs 8s, not a
|
||||
// stuck request.
|
||||
//
|
||||
// Read-only on the partner. `echo ok` is the entire remote payload.
|
||||
//
|
||||
// Never cached.
|
||||
// Cache-Control: no-store, no-cache — a connectivity test served from cache is worse
|
||||
// than no test, because it reports a partner reachable after it has gone dark.
|
||||
//
|
||||
// REQUEST
|
||||
// GET ?id=host<n> (case-insensitive; the slot name, not the hostname)
|
||||
//
|
||||
// RESPONSE
|
||||
// {"ok":true,"ms":int,…} on success
|
||||
// {"ok":false,"error":string} invalid id, no key, unresolvable, or no reply
|
||||
//
|
||||
// DEPENDS ON
|
||||
// include/partnership.php vv_pt_ping() → vv_pt_ssh(), vv_resolve_tailscale_ip()
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||
header('Content-Type: application/json');
|
||||
header('Cache-Control: no-store, no-cache');
|
||||
require_once dirname(__DIR__) . '/include/partnership.php';
|
||||
|
||||
Reference in New Issue
Block a user