From 8dcf561e4e02445ad1f4dfa846b366ed2f5b1a0c Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Sun, 11 Oct 2026 04:09:06 +0100 Subject: [PATCH] Check absent agent-token registration before another install A normal-host enrolment report supplies lookup and host-report 401s, repeated installs and an absent inventory record. Document one named server-side registration check before touching the affected agent, with separate limits for persistence, credential hand-off and accepted reports. Contract-Neutral: Existing authentication help and its source-alignment controls only; no runtime, API, scope, route or credential-policy change. Change-source: pulse-maintainer --- docs/UNIFIED_AGENT.md | 18 ++++++++++++++ frontend-modern/public/docs/UNIFIED_AGENT.md | 18 ++++++++++++++ scripts/tests/test_agent_auth_docs.py | 25 ++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/docs/UNIFIED_AGENT.md b/docs/UNIFIED_AGENT.md index 469b68c8b7..100056f600 100644 --- a/docs/UNIFIED_AGENT.md +++ b/docs/UNIFIED_AGENT.md @@ -1112,6 +1112,24 @@ service is presenting the same token. Last-used metadata is not a token-use audit and does not identify which consumer authenticated. These observations do not prove that the running service is using that record. +**If the intended record is absent:** separate server registration from the +agent's credential hand-off before another installation. On that same instance, +open **Settings → Infrastructure → Install on a host**, give one new install +token a distinct name and choose **Generate token**. Leave command execution +disabled for a monitoring-only host. Before running any install command, reopen +**Settings → API Access** and refresh the page: does that named record appear +and remain? Generating the record alone does not change the Pi or any other +agent's saved credential. + +If the new record is missing or disappears, stop there; do not generate more +tokens, rerun the installer or restart Pulse to test it. Report only whether +generation showed an error and whether the named record appeared after the page +refresh, with any error manually redacted. If it remains, that establishes +current registration, not persistence across a server restart, successful +credential hand-off or accepted host reports. Retain the existing installation +while those remaining distinctions are investigated. A listed record with +`Never` is not, by itself, a reason to mint a replacement. + If asked about the inventory, report only whether the record exists and the relevant metadata; do not share the token or its hint. Keep service environments, token files and connection files private; do not paste a credential into a diff --git a/frontend-modern/public/docs/UNIFIED_AGENT.md b/frontend-modern/public/docs/UNIFIED_AGENT.md index 469b68c8b7..100056f600 100644 --- a/frontend-modern/public/docs/UNIFIED_AGENT.md +++ b/frontend-modern/public/docs/UNIFIED_AGENT.md @@ -1112,6 +1112,24 @@ service is presenting the same token. Last-used metadata is not a token-use audit and does not identify which consumer authenticated. These observations do not prove that the running service is using that record. +**If the intended record is absent:** separate server registration from the +agent's credential hand-off before another installation. On that same instance, +open **Settings → Infrastructure → Install on a host**, give one new install +token a distinct name and choose **Generate token**. Leave command execution +disabled for a monitoring-only host. Before running any install command, reopen +**Settings → API Access** and refresh the page: does that named record appear +and remain? Generating the record alone does not change the Pi or any other +agent's saved credential. + +If the new record is missing or disappears, stop there; do not generate more +tokens, rerun the installer or restart Pulse to test it. Report only whether +generation showed an error and whether the named record appeared after the page +refresh, with any error manually redacted. If it remains, that establishes +current registration, not persistence across a server restart, successful +credential hand-off or accepted host reports. Retain the existing installation +while those remaining distinctions are investigated. A listed record with +`Never` is not, by itself, a reason to mint a replacement. + If asked about the inventory, report only whether the record exists and the relevant metadata; do not share the token or its hint. Keep service environments, token files and connection files private; do not paste a credential into a diff --git a/scripts/tests/test_agent_auth_docs.py b/scripts/tests/test_agent_auth_docs.py index a697f13b3f..c4af9fa4a7 100644 --- a/scripts/tests/test_agent_auth_docs.py +++ b/scripts/tests/test_agent_auth_docs.py @@ -106,6 +106,31 @@ class AgentAuthDocsTest(unittest.TestCase): "missing record", "service is presenting the same token"): self.assertIn(fact, text) + def test_missing_record_check_registers_once_before_touching_the_agent(self): + text = " ".join(section().split()) + install = (ROOT / "frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx").read_text() + generation = install.split("const generateInstallToken = async (", 1)[1].split( + "const handleGenerateToken = async", 1)[0] + self.assertIn("NodesAPI.createHostAgentInstallToken", generation) + self.assertIn("enableCommands: withCommands", generation) + self.assertNotIn("deleteToken", generation) + ui = (ROOT / "frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx").read_text() + self.assertIn("Generate token", ui) + inventory = (ROOT / "internal/api/security_tokens.go").read_text() + listing = inventory.split("func (r *Router) handleListAPITokens(", 1)[1].split( + "// handleGetAPIToken", 1)[0] + self.assertIn("range r.config.APITokens", listing) + self.assertIn("toAPITokenDTO(record)", listing) + for fact in ("If the intended record is absent", "server registration", + "one new install token a distinct name", "Before running any install command", + "refresh the page", "does not change the Pi or any other agent's saved credential", + "Leave command execution disabled", "missing or disappears, stop there", + "do not generate more tokens", "generation showed an error", + "not persistence across a server restart", "successful credential hand-off", + "accepted host reports", "Retain the existing installation", + "not, by itself, a reason to mint a replacement"): + self.assertIn(fact, text) + if __name__ == "__main__": unittest.main()