Reject mixed bootstrap metadata and align credential-safe fixtures

The root parser's legacy no-token alias accepted a new private-file command beside a legacy download URL. Reject every mixed alias, as the existing coherent-transport contract requires. Preserve backup-permission URL bindings. Align older secret-in-command and shared type fixtures, and exercise the actual wrong server installer parser.

Contract-Neutral: Enforce the already-declared coherent bootstrap transports and correct verification fixtures; no API, scope or documented behaviour delta.
Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-10-01 05:42:34 +01:00
parent 2fd114b3ac
commit 521acef97a
9 changed files with 52 additions and 12 deletions
@@ -149,6 +149,7 @@ describe('NodesAPI — branch coverage (downloadProxmoxSetupScript failure arms)
});
const pveBootstrap = (): ProxmoxSetupCommandResponse => ({
setupToken: 'synthetic-setup-token',
type: 'pve',
host: 'https://pve.example:8006',
url: 'https://pulse.example/base/api/setup-script?type=pve',
@@ -407,7 +407,7 @@ describe('NodesAPI', () => {
[field]: `unsafe-${secret}`,
});
await expect(
NodesAPI.getProxmoxSetupCommand({ type: 'pve', host: 'pve.example' }),
NodesAPI.getProxmoxSetupCommand({ type: 'pve', host: 'pve.example', backupPerms: false }),
).rejects.toThrow('Setup credentials must be entered separately from commands and URLs');
},
);
@@ -48,12 +48,24 @@ describe('tokenRevealStore', () => {
const state = tokenRevealStore.state();
expect(state).not.toBeNull();
expect(state!.token).toBe('secret-token');
expect(state!.record.id).toBe('token-1');
expect(state!.record!.id).toBe('token-1');
expect(state!.source).toBe('settings');
expect(state!.note).toBe('Test note');
expect(state!.issuedAt).toBeDefined();
});
it('reveals a temporary setup token without inventing an API token record', () => {
showTokenReveal({
token: 'synthetic-setup-token',
source: 'pve',
note: 'Private input only',
});
expect(tokenRevealStore.state()?.token).toBe('synthetic-setup-token');
expect(tokenRevealStore.state()?.record).toBeUndefined();
dismissTokenReveal();
expect(tokenRevealStore.state()).toBeNull();
});
it('sets issuedAt to current timestamp', () => {
const before = Date.now();
showTokenReveal({
+1 -1
View File
@@ -2349,7 +2349,7 @@ for _field_name, _value, _requires_token in command_fields:
if modern:
valid = "PULSE_SETUP_TOKEN_FILE=" in _value and "PULSE_SETUP_TOKEN=" not in _value and setup_token not in _value
else:
valid = ("PULSE_SETUP_TOKEN=" in _value and setup_token in _value) if _requires_token else ("PULSE_SETUP_TOKEN=" not in _value and setup_token not in _value)
valid = "PULSE_SETUP_TOKEN_FILE=" not in _value and (("PULSE_SETUP_TOKEN=" in _value and setup_token in _value) if _requires_token else ("PULSE_SETUP_TOKEN=" not in _value and setup_token not in _value))
if not valid:
if _field_name == "command":
setup_command = ""
@@ -542,10 +542,10 @@ func TestHandleAgentInstallCommand(t *testing.T) {
if resp.Token == "" || resp.Command == "" {
t.Fatalf("expected token and command in response")
}
if !bytes.Contains([]byte(resp.Command), []byte(resp.Token)) {
t.Fatalf("expected command to include token")
if bytes.Contains([]byte(resp.Command), []byte(resp.Token)) || !strings.Contains(resp.Command, `--token-file "$token_file"`) {
t.Fatal("credential must be entered privately, not included in copied command")
}
if !bytes.Contains([]byte(resp.Command), []byte("--proxmox-type "+posixShellQuote("pve"))) {
if resp.Command != BuildProxmoxAgentInstallCommand(AgentInstallCommandOptions{BaseURL: "http://example.com:8080", Token: resp.Token, InstallType: "pve", IncludeInstallType: true, EnableCommands: true}) {
t.Fatalf("expected command to include proxmox type")
}
if len(cfg.APITokens) != 1 {
@@ -633,7 +633,7 @@ func TestHandleAgentInstallCommand_NormalizesType(t *testing.T) {
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if !bytes.Contains([]byte(resp.Command), []byte("--proxmox-type "+posixShellQuote("pbs"))) {
if resp.Command != BuildProxmoxAgentInstallCommand(AgentInstallCommandOptions{BaseURL: "http://example.com:8080", Token: resp.Token, InstallType: "pbs", IncludeInstallType: true}) {
t.Fatalf("expected normalized proxmox type in command, got: %s", resp.Command)
}
}
@@ -435,7 +435,7 @@ func TestPVESetupScript_UsesFailFastRetryGuidance(t *testing.T) {
}
script := rr.Body.String()
if !containsString(script, `PULSE_BOOTSTRAP_COMMAND_WITH_ENV='curl -fsSL '"'"'http://sentinel-url:7656/api/setup-script?host=http%3A%2F%2Fsentinel-host%3A8006&pulse_url=http%3A%2F%2Fsentinel-url%3A7656&type=pve'"'"' | `) {
if !containsString(script, `PULSE_BOOTSTRAP_COMMAND_WITH_ENV=`+posixShellQuote(BuildSetupScriptCommand("http://sentinel-url:7656/api/setup-script?host=http%3A%2F%2Fsentinel-host%3A8006&pulse_url=http%3A%2F%2Fsentinel-url%3A7656&type=pve", ""))) {
t.Fatalf("expected canonical bootstrap command owner in setup script, got: %s", truncate(script, 700))
}
if !containsString(script, `echo " $PULSE_BOOTSTRAP_COMMAND_WITH_ENV"`) {
@@ -952,7 +952,8 @@ func TestPVESetupScriptSmokeTestsCreatedTokenBeforeAutoRegistration(t *testing.T
for _, needle := range []string{
`smoke_test_pve_token() {`,
`curl -kfsS --retry 2 --retry-delay 1`,
`Authorization: PVEAPIToken=$PULSE_TOKEN_ID=$TOKEN_VALUE`,
`printf 'Authorization: PVEAPIToken=%s=%s\n' "$PULSE_TOKEN_ID" "$TOKEN_VALUE" | curl`,
`-H @-`,
`${HOST_URL%/}/api2/json/nodes`,
`TOKEN_READY=false`,
`if smoke_test_pve_token; then`,
@@ -51,8 +51,12 @@ func TestHostedRuntimeMintsAgentInstallTokensWithoutLocalAuth(t *testing.T) {
if len(cfg.APITokens) != 1 {
t.Fatalf("persisted API tokens = %d, want 1", len(cfg.APITokens))
}
if resp.Command != "" && !strings.Contains(resp.Command, resp.Token) {
t.Fatalf("install command does not carry the minted token: %s", resp.Command)
if tc.name == "proxmox agent" {
if strings.Contains(resp.Command, resp.Token) || !strings.Contains(resp.Command, `--token-file "$token_file"`) {
t.Fatal("hosted Proxmox credential must use separate private input")
}
} else if resp.Command != "" && !strings.Contains(resp.Command, resp.Token) {
t.Fatal("generic host command lost its existing credential transport")
}
})
}
@@ -372,3 +372,25 @@ func TestPrivateBootstrapInteractiveHistoryContainsCommandButNotToken(t *testing
t.Fatal("silent input entered shell history or terminal output")
}
}
// The public server installer is not the telemetry installer. If it is served
// accidentally at the agent path, its real parser rejects --url before token
// input or privileged installation; a complete but wrong fetch is not success.
func TestPrivateAgentBootstrapRejectsActualServerInstaller(t *testing.T) {
source, err := os.ReadFile(filepath.Join("..", "..", "..", "install.sh"))
if err != nil {
t.Fatal(err)
}
root, env := bootstrapFixture(t, string(source))
command := BuildProxmoxAgentInstallCommand(AgentInstallCommandOptions{BaseURL: "https://pulse.example", Token: "synthetic-token", InstallType: "pve", IncludeInstallType: true})
out, err := runBootstrap(t, command, "", env, false)
if err == nil || !strings.Contains(string(out), "Unknown option: --url") {
t.Fatal("wrong installer was not rejected by its real parser")
}
dirs, _ := os.ReadFile(filepath.Join(root, "private-directories"))
for _, path := range strings.Fields(string(dirs)) {
if _, err := os.Stat(path); !os.IsNotExist(err) {
t.Fatal("wrong-installer failure left a private directory")
}
}
}
+1 -1
View File
@@ -598,7 +598,7 @@ func TestRootInstallScriptAutoRegisterUsesSecureContractShape(t *testing.T) {
`'if [ "$(id -u)" -eq 0 ]; then' not in _value`,
`'elif command -v sudo >/dev/null 2>&1; then' not in _value`,
`valid = "PULSE_SETUP_TOKEN_FILE=" in _value and "PULSE_SETUP_TOKEN=" not in _value and setup_token not in _value`,
`valid = ("PULSE_SETUP_TOKEN=" in _value and setup_token in _value) if _requires_token else ("PULSE_SETUP_TOKEN=" not in _value and setup_token not in _value)`,
`valid = "PULSE_SETUP_TOKEN_FILE=" not in _value and (("PULSE_SETUP_TOKEN=" in _value and setup_token in _value) if _requires_token else ("PULSE_SETUP_TOKEN=" not in _value and setup_token not in _value))`,
`not token_hint or token_hint == setup_token`,
`[[ "$setup_type" != "pve" ]]`,
`[[ "$setup_host" != "$normalized_host_url" ]]`,