Pulse/internal/api/connections_command_policy_token_test.go
rcourtman 667cb086b0
Some checks failed
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Frontend & Backend (push) Waiting to run
Canonical Governance / governance (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 1/4) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 2/4) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 4/4) (push) Waiting to run
Unified Agent Native Verification / Linux ARM64 (push) Waiting to run
Unified Agent Native Verification / Linux x64 (push) Waiting to run
Unified Agent Native Verification / Windows x64 (push) Waiting to run
Unified Agent Native Verification / macOS ARM64 (push) Waiting to run
Unified Agent Native Verification / macOS Intel (push) Waiting to run
Unified Agent Native Verification / FreeBSD cross-build contract (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 3/4) (push) Waiting to run
Core E2E Tests / E2E verdict (push) Blocked by required conditions
Patrol Qualification Regression / Catalog, scorer, and replay regression (push) Has been cancelled
Fail closed on unresolvable agent tokens in the connections command-policy view
The desired side of the /api/connections command-policy comparison is
contractually the effective config served to the agent after token scope
and binding checks, but a host whose recorded TokenID no longer resolved
to a live API token skipped sanitization entirely and kept the raw
profile desire. A stale binding, typical after a token was revoked and
the agent reinstalled, then presented as Command policy mismatch even
though the served runtime config could never enable commands and the
operator had nothing to fix (seen on issue #1564). When API tokens
exist and the host's token cannot be resolved, desired command policy
now fails closed to disabled.

The contract delta also records the install-token mint semantics that
landed with the Add Pulse Agent scope fix, closing the deferred
agent-lifecycle delta noted on that commit's contract-neutral trailer.

Contract-Neutral: fail-closed bugfix bringing the connections command-policy view into conformance with the existing agent-lifecycle contract clause; the staged agent-lifecycle delta records the semantics, api-contracts/storage-recovery have no real delta
2026-07-18 13:09:18 +01:00

60 lines
2.6 KiB
Go

package api
import (
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/internal/monitoring"
)
func commandsEnabledConfig() monitoring.HostAgentConfig {
enabled := true
return monitoring.HostAgentConfig{CommandsEnabled: &enabled}
}
// The desired side of the /api/connections command-policy comparison must be
// the effective config after token scope and binding checks. A host whose
// TokenID resolves to no live token can never be served commands-enabled
// config, so desired must fail closed instead of fabricating a drift the
// operator cannot fix from the profile.
func TestEffectiveConnectionAgentConfigUnresolvableTokenFailsClosed(t *testing.T) {
execToken := config.APITokenRecord{ID: "tok-exec", Scopes: []string{config.ScopeAgentExec}}
tokenByID := map[string]*config.APITokenRecord{execToken.ID: &execToken}
staleHost := models.Host{ID: "agent-a", Hostname: "a", TokenID: "tok-revoked"}
cfg := effectiveConnectionAgentConfig(commandsEnabledConfig(), staleHost, tokenByID)
if cfg.CommandsEnabled == nil || *cfg.CommandsEnabled {
t.Fatalf("stale TokenID must force desired commands disabled, got %+v", cfg.CommandsEnabled)
}
untrackedHost := models.Host{ID: "agent-b", Hostname: "b"}
cfg = effectiveConnectionAgentConfig(commandsEnabledConfig(), untrackedHost, tokenByID)
if cfg.CommandsEnabled == nil || *cfg.CommandsEnabled {
t.Fatalf("untracked TokenID must force desired commands disabled, got %+v", cfg.CommandsEnabled)
}
}
func TestEffectiveConnectionAgentConfigResolvableAndAuthOptionalPaths(t *testing.T) {
execToken := config.APITokenRecord{
ID: "tok-exec",
Scopes: []string{config.ScopeAgentExec},
Metadata: map[string]string{
"bound_hostname": "a",
},
}
tokenByID := map[string]*config.APITokenRecord{execToken.ID: &execToken}
boundHost := models.Host{ID: "agent-a", Hostname: "a", TokenID: execToken.ID}
cfg := effectiveConnectionAgentConfig(commandsEnabledConfig(), boundHost, tokenByID)
if cfg.CommandsEnabled == nil || !*cfg.CommandsEnabled {
t.Fatalf("exec-scoped bound token must keep desired commands enabled, got %+v", cfg.CommandsEnabled)
}
// Auth-optional installs have no API tokens at all; the config passes
// through untouched rather than failing closed.
cfg = effectiveConnectionAgentConfig(commandsEnabledConfig(), models.Host{ID: "agent-c", Hostname: "c"}, nil)
if cfg.CommandsEnabled == nil || !*cfg.CommandsEnabled {
t.Fatalf("auth-optional path must keep desired commands enabled, got %+v", cfg.CommandsEnabled)
}
}