guildhouse-spire-plugins/pkg/gsap/selectors_test.go
Tyler J King fe5e2cf3c6 feat(spire): gsap-attestor WorkloadAttestor plugin
SPIRE WorkloadAttestor that reads governance env vars from /proc/{pid}/environ
(walking up the process tree to find gsh) and emits gsap: selectors on workload
SVIDs. Maps BASCULE_* vars set by bascule-shell and future GSH_* vars to the
11-selector vocabulary defined in gsap-types/src/selectors.rs.

- pkg/gsap/selectors.go: shared Go constants mirroring Rust vocabulary
- cmd/gsap-attestor/: plugin implementation with /proc reading, process tree
  walking, capability ceiling translation, and fail-open for non-governed processes
- 28 tests covering selector extraction, proc parsing, tree walking, and depth limits
- Makefile, Dockerfile, deploy config updated

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 03:59:08 -04:00

101 lines
2.7 KiB
Go

package gsap
import (
"strings"
"testing"
)
func TestAllSelectorKeysCount(t *testing.T) {
if got := len(AllSelectorKeys); got != 11 {
t.Errorf("expected 11 selector keys, got %d", got)
}
}
func TestSelectorType(t *testing.T) {
if SelectorType != "gsap" {
t.Errorf("expected SelectorType %q, got %q", "gsap", SelectorType)
}
}
func TestSelectorKeysNoWhitespaceOrColons(t *testing.T) {
for _, key := range AllSelectorKeys {
if strings.ContainsAny(key, " \t\n:") {
t.Errorf("selector key %q contains whitespace or colon", key)
}
if key == "" {
t.Error("selector key is empty")
}
}
}
func TestFormatSelector(t *testing.T) {
tests := []struct {
key, value, want string
}{
{"context_id", "abc-123", "gsap:context_id:abc-123"},
{"capability_mask", "0x07", "gsap:capability_mask:0x07"},
{"principal_did", "did:web:example.com/alice", "gsap:principal_did:did:web:example.com/alice"},
}
for _, tt := range tests {
got := FormatSelector(tt.key, tt.value)
if got != tt.want {
t.Errorf("FormatSelector(%q, %q) = %q, want %q", tt.key, tt.value, got, tt.want)
}
}
}
func TestCapabilityCeilingToHex(t *testing.T) {
expected := map[string]string{
"CAP_NONE": "0x00",
"CAP_READ": "0x01",
"CAP_PROPOSE": "0x03",
"CAP_MUTATE": "0x07",
"CAP_GOVERN": "0x0f",
}
for name, wantHex := range expected {
got, ok := CapabilityCeilingToHex[name]
if !ok {
t.Errorf("CapabilityCeilingToHex missing entry for %q", name)
continue
}
if got != wantHex {
t.Errorf("CapabilityCeilingToHex[%q] = %q, want %q", name, got, wantHex)
}
}
if len(CapabilityCeilingToHex) != len(expected) {
t.Errorf("CapabilityCeilingToHex has %d entries, expected %d", len(CapabilityCeilingToHex), len(expected))
}
}
func TestCapabilityCeilingToHex_UnknownAbsent(t *testing.T) {
if _, ok := CapabilityCeilingToHex["CAP_UNKNOWN"]; ok {
t.Error("CapabilityCeilingToHex should not contain CAP_UNKNOWN")
}
}
func TestVocabularyMatchesRust(t *testing.T) {
// Contract test: these exact strings must match gsap-types/src/selectors.rs.
// If this test fails, the Go and Rust vocabularies have drifted.
rustKeys := map[string]bool{
"context_id": true,
"capability_mask": true,
"corpus_cid": true,
"parameters_cid": true,
"accord_template": true,
"playbook": true,
"principal_did": true,
"driver_id": true,
"session_mode": true,
"shell_class": true,
"posture_level": true,
}
for _, key := range AllSelectorKeys {
if !rustKeys[key] {
t.Errorf("Go selector key %q not in Rust vocabulary", key)
}
delete(rustKeys, key)
}
for key := range rustKeys {
t.Errorf("Rust selector key %q missing from Go vocabulary", key)
}
}