mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-08-13 11:03:30 +00:00
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
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
60 lines
2.6 KiB
Go
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)
|
|
}
|
|
}
|