docs: Q1c GREEN — reboot survival automatic since agent 0.84.0 (feature doc + audit §7 + CONTEXT + REPORT)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -227,4 +227,74 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{if .Deletable}}
|
||||
<!-- Danger zone (v0.47.0): rendered ONLY for non-online hosts — deleting a live
|
||||
host would brick its heartbeat channel, so the affordance never exists for one.
|
||||
Impact + type-to-confirm dialog per the global-floor confirm pattern. -->
|
||||
<section class="card" style="border-color: var(--crit);">
|
||||
<h2>Danger zone</h2>
|
||||
<p class="text-muted" style="font-size: 0.85rem;">
|
||||
Removing this host deletes its reports, guests, log bundles and WireGuard peer, and
|
||||
permanently invalidates its API key — a still-running agent would receive 401s.
|
||||
Re-enrollment requires the Day-0 passphrase flow.
|
||||
</p>
|
||||
<button type="button" class="btn btn-danger btn-sm" onclick="hostDeleteConfirm('{{.HostID}}')">Remove host…</button>
|
||||
<div id="host-delete-confirm-{{.HostID}}" style="display: none; margin-top: 0.75rem; padding: 0.75rem; border: 1px solid var(--crit); background: var(--crit-dim); border-radius: var(--radius); max-width: 44em;">
|
||||
<p id="host-delete-impact-{{.HostID}}" style="margin: 0 0 0.5rem; font-size: 0.9em;">…</p>
|
||||
<label id="host-delete-escrow-row-{{.HostID}}" style="display: none; margin: 0 0 0.5rem; font-size: 0.85em;">
|
||||
<input type="checkbox" id="host-delete-escrow-{{.HostID}}">
|
||||
Also delete the key escrow + DR bundle for this host
|
||||
</label>
|
||||
<p style="margin: 0 0 0.5rem; font-size: 0.85em; color: var(--text-2);">Type the host id to confirm:</p>
|
||||
<form method="POST" action="/hosts/{{.HostID}}/delete" id="host-delete-form-{{.HostID}}" style="display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap;">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}">
|
||||
<input type="hidden" name="confirm_host_id" id="host-delete-confirm-hidden-{{.HostID}}" value="">
|
||||
<input type="hidden" name="delete_escrow" id="host-delete-escrow-hidden-{{.HostID}}" value="">
|
||||
<input type="text" id="host-delete-confirm-input-{{.HostID}}" placeholder="retype the host id…" style="padding: 0.3em 0.5em; width: 16em;">
|
||||
<button type="button" class="btn btn-danger btn-sm" onclick="hostDeleteSubmit('{{.HostID}}')">Confirm & remove</button>
|
||||
<button type="button" class="btn btn-sm btn-outline" onclick="document.getElementById('host-delete-confirm-{{.HostID}}').style.display='none';">Cancel</button>
|
||||
</form>
|
||||
<p id="host-delete-err-{{.HostID}}" style="margin: 0.4em 0 0; font-size: 0.8em; color: var(--crit);"></p>
|
||||
</div>
|
||||
</section>
|
||||
<script>
|
||||
function hostDeleteConfirm(hostID) {
|
||||
var box = document.getElementById('host-delete-confirm-' + hostID);
|
||||
var impact = document.getElementById('host-delete-impact-' + hostID);
|
||||
document.getElementById('host-delete-confirm-input-' + hostID).value = '';
|
||||
document.getElementById('host-delete-err-' + hostID).textContent = '';
|
||||
box.style.display = 'block';
|
||||
impact.textContent = 'Checking impact…';
|
||||
fetch('/hosts/' + encodeURIComponent(hostID) + '/delete-impact')
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(d){
|
||||
var parts = ['Deleting ' + hostID + ' removes ' + d.guests + ' guest row(s), ' +
|
||||
d.reports + ' host report(s), ' + d.log_bundles + ' agent log bundle(s)'];
|
||||
if (d.wg_peer_bound) parts.push('the bound WireGuard peer');
|
||||
if (d.pbs_secret_present) parts.push('the staged PBS secret');
|
||||
if (d.recovery_present) parts.push('the break-glass recovery credential');
|
||||
impact.textContent = parts.join(', ') + '. Host status: ' + d.status + '.' +
|
||||
(d.deletable ? '' : ' Host is ONLINE — deletion will be refused.');
|
||||
document.getElementById('host-delete-escrow-row-' + hostID).style.display =
|
||||
d.escrow_present ? 'block' : 'none';
|
||||
})
|
||||
.catch(function(){ impact.textContent = 'Could not compute the impact — the server will still enforce every gate.'; });
|
||||
}
|
||||
function hostDeleteSubmit(hostID) {
|
||||
var typed = document.getElementById('host-delete-confirm-input-' + hostID).value.trim();
|
||||
var err = document.getElementById('host-delete-err-' + hostID);
|
||||
if (typed !== hostID) { err.textContent = 'Confirmation does not match the host id.'; return; }
|
||||
var escrowRow = document.getElementById('host-delete-escrow-row-' + hostID);
|
||||
var escrowCb = document.getElementById('host-delete-escrow-' + hostID);
|
||||
if (escrowRow.style.display !== 'none' && !escrowCb.checked) {
|
||||
err.textContent = 'This host has a key escrow — tick the acknowledgement to delete it too.';
|
||||
return;
|
||||
}
|
||||
document.getElementById('host-delete-confirm-hidden-' + hostID).value = typed;
|
||||
document.getElementById('host-delete-escrow-hidden-' + hostID).value = escrowCb.checked ? '1' : '';
|
||||
document.getElementById('host-delete-form-' + hostID).submit();
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user