fix(api): localize shipped security doc refs

This commit is contained in:
rcourtman
2026-03-28 20:35:10 +00:00
parent 90c33da777
commit 7747b78740
8 changed files with 31 additions and 2 deletions
@@ -124,6 +124,7 @@ management, and fleet control surfaces.
7. Preserve canonical token-lifecycle reads in shared `internal/api/` auth/security helpers so lifecycle-adjacent setup and install flows do not revoke a displayed relay pairing token after `lastUsedAt` proves that an already paired device is actively depending on that credential.
8. Preserve backend-owned Pulse Mobile relay runtime credential minting in those same shared `internal/api/` auth/security helpers so lifecycle-adjacent setup and install flows reuse the canonical mobile token route instead of reintroducing wildcard or browser-authored runtime token bundles.
9. Preserve the dedicated backend-owned `relay:mobile:access` capability and its governed backward-compatible route inventory plus the shared helper call sites around it, so lifecycle-adjacent setup and install flows do not widen the mobile device credential back into general AI chat/execute scope ownership.
10. Preserve shipped security-doc guidance in shared lifecycle setup helpers so `internal/api/config_setup_handlers.go` and adjacent install/setup runtime paths point operators at the running build's local security documentation route rather than GitHub `main` links.
## Forbidden Paths
@@ -1417,6 +1418,11 @@ Proxmox install commands in `internal/api/config_setup_handlers.go` and
configured, the canonical agent-install-command API must return tokenless
install transport and must not persist a new API token record just because an
operator opened a backend-driven install surface.
That same backend-owned setup/install boundary also owns shipped security-doc
guidance in runtime responses and logs: `internal/api/config_setup_handlers.go`
and adjacent lifecycle setup helpers must not point operators at GitHub
`main` for security instructions that the running build already serves
locally, and should use the shipped `/docs/SECURITY.md` path instead.
The same optional-auth continuity must hold after install as well: Unified Agent
runtime startup may not reject a blank token unless enrollment is explicitly
enabled, agent report transport must omit auth headers when no token is
@@ -184,6 +184,7 @@ Own canonical runtime payload shapes between backend and frontend.
17. Governed frontend API clients open-coding `if (!response.ok) { if (isAPIResponseStatus(...)) throw new Error(...) }` status-to-user-message branches instead of using canonical shared custom-status error helpers
18. Monitoring command-trigger clients open-coding `parseOptionalAPIResponse(response, { success: true }, ...)` success-envelope fallbacks instead of using a canonical shared success-envelope helper
19. Governed frontend API clients open-coding `try/catch` wrappers around `apiFetchJSON(...)` just to map `402` or `404` into `[]`, `{ plans: [] }`, or `null` instead of using canonical shared API-error-status fallback helpers
20. Backend config/settings handlers pointing operator guidance at GitHub `main` docs when the running build already ships that guidance locally under `/docs/`
## Completion Obligations
@@ -77,6 +77,7 @@ querying, and the operator-facing storage health presentation layer.
16. Preserve optional-auth tokenless behavior in those same shared backend install-command helpers so adjacent transport surfaces do not implicitly persist API tokens and flip auth-configured state when an operator only requested a Proxmox install command on a token-optional Pulse instance.
17. Preserve backend-owned Pulse Mobile relay runtime credential minting in those same shared `internal/api/` auth/security helpers so storage- and recovery-adjacent transport surfaces do not inherit browser-authored wildcard token bundles when they depend on the canonical security helper layer.
18. Preserve the dedicated backend-owned `relay:mobile:access` capability and its governed backward-compatible route inventory plus the shared helper call sites around it, so storage- and recovery-adjacent transport surfaces do not treat the mobile relay credential as a general AI scope bundle.
19. Preserve shipped local security-doc guidance in shared `internal/api/` config/setup helpers so storage- and recovery-adjacent transport surfaces do not reintroduce GitHub `main` security links when the running build already serves its own local security documentation route.
## Forbidden Paths
@@ -87,5 +87,11 @@ func TestHandleVerifyTemperatureSSH(t *testing.T) {
if !bytes.Contains(rec.Body.Bytes(), []byte("invalid-host-name-for-test")) {
t.Error("expected affected node in failure list")
}
if !bytes.Contains(rec.Body.Bytes(), []byte("/docs/SECURITY.md")) {
t.Error("expected shipped security doc reference in failure guidance")
}
if bytes.Contains(rec.Body.Bytes(), []byte("github.com/rcourtman/Pulse/blob/main/SECURITY.md")) {
t.Error("expected failure guidance to avoid GitHub main security doc links")
}
})
}
+1 -1
View File
@@ -837,7 +837,7 @@ func (h *ConfigHandlers) getOrGenerateSSHKeys() SSHKeyPair {
if isContainer && !devModeAllowSSH {
log.Error().Msg("SECURITY BLOCK: SSH key generation disabled in containerized deployments")
log.Error().Msg("Temperature monitoring via SSH is disabled in containerized deployments")
log.Error().Msg("See: https://github.com/rcourtman/Pulse/blob/main/SECURITY.md#critical-security-notice-for-container-deployments")
log.Error().Msg("See: " + shippedSecurityContainerNoticeDocAnchor)
log.Error().Msg("To test SSH keys in dev/lab only: PULSE_DEV_ALLOW_CONTAINER_SSH=true (NEVER in production!)")
return SSHKeyPair{}
}
+1 -1
View File
@@ -152,7 +152,7 @@ func (h *ConfigHandlers) handleVerifyTemperatureSSH(w http.ResponseWriter, r *ht
response.WriteString(fmt.Sprintf(" • %s\n", node))
}
response.WriteString("\n")
response.WriteString("See: https://github.com/rcourtman/Pulse/blob/main/SECURITY.md for detailed SSH configuration options.\n")
response.WriteString("See: " + shippedSecurityDocPath + " for detailed SSH configuration options.\n")
}
w.Header().Set("Content-Type", "text/plain")
+9
View File
@@ -5708,6 +5708,15 @@ func TestContract_EmbeddedFrontendWarningUsesCanonicalDevEntrypoints(t *testing.
}
}
func TestContract_ShippedSecurityDocReferencesStayLocal(t *testing.T) {
if shippedSecurityDocPath != "/docs/SECURITY.md" {
t.Fatalf("expected shipped security doc path, got %q", shippedSecurityDocPath)
}
if shippedSecurityContainerNoticeDocAnchor != "/docs/SECURITY.md#critical-security-notice-for-container-deployments" {
t.Fatalf("expected shipped security container notice path, got %q", shippedSecurityContainerNoticeDocAnchor)
}
}
func mustStreamEvent(t *testing.T, eventType string, data interface{}) chat.StreamEvent {
t.Helper()
+6
View File
@@ -0,0 +1,6 @@
package api
const (
shippedSecurityDocPath = "/docs/SECURITY.md"
shippedSecurityContainerNoticeDocAnchor = shippedSecurityDocPath + "#critical-security-notice-for-container-deployments"
)