package execution_test import ( "context" "errors" "path/filepath" "testing" "github.com/kami/hexis/internal/domain" "github.com/kami/hexis/internal/execution" "github.com/kami/hexis/internal/nexusclient" "github.com/kami/hexis/internal/provider" "github.com/kami/hexis/internal/storage" ) // fakeNexus stands in for the Nexus entity registry: whatever is in entities // exists, anything else is a 404, and err simulates Nexus being unreachable. type fakeNexus struct { entities map[string]*nexusclient.Entity err error calls int } func (f *fakeNexus) GetEntity(ctx context.Context, id string) (*nexusclient.Entity, error) { f.calls++ if f.err != nil { return nil, f.err } if e, ok := f.entities[id]; ok { return e, nil } return nil, nexusclient.ErrEntityNotFound } func newTargetEngine(t *testing.T, nexus execution.EntityLookup) (*execution.Engine, *storage.Store) { t.Helper() store, err := storage.Open(filepath.Join(t.TempDir(), "hexis.db")) if err != nil { t.Fatalf("open storage: %v", err) } t.Cleanup(func() { store.Close() }) reg := provider.NewRegistry() reg.Register(&fakeProvider{name: "fake"}) return execution.New(store, reg, execution.WithEntityLookup(nexus)), store } func activeNexus() *fakeNexus { return &fakeNexus{entities: map[string]*nexusclient.Entity{ "ent_container_maven": {ID: "ent_container_maven", Type: "container", State: "active"}, "ent_host_homesrv": {ID: "ent_host_homesrv", Type: "host", State: "active"}, "ent_retired_thing": {ID: "ent_retired_thing", Type: "container", State: "retired"}, }} } // TestExecute_RejectsFreeTextTarget pins ECOSYSTEM-SPEC.md ยง4.3: a target // that is not a canonical ent_ ID is refused without even asking Nexus. func TestExecute_RejectsFreeTextTarget(t *testing.T) { nexus := activeNexus() eng, store := newTargetEngine(t, nexus) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} }) for _, target := range []string{"maven", "the maven container", "container_maven", "ent_", "ent_bad id", ""} { _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: target}) if !errors.Is(err, execution.ErrTargetMalformed) { t.Errorf("target %q: expected ErrTargetMalformed, got %v", target, err) } } if nexus.calls != 0 { t.Errorf("malformed targets must not reach Nexus, got %d calls", nexus.calls) } } func TestExecute_RejectsUnknownTarget(t *testing.T) { eng, store := newTargetEngine(t, activeNexus()) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} }) _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_does_not_exist"}) if !errors.Is(err, execution.ErrTargetNotFound) { t.Fatalf("expected ErrTargetNotFound, got %v", err) } } func TestExecute_RejectsWrongTargetType(t *testing.T) { eng, store := newTargetEngine(t, activeNexus()) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} }) _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_host_homesrv"}) if !errors.Is(err, execution.ErrTargetTypeMismatch) { t.Fatalf("expected ErrTargetTypeMismatch, got %v", err) } } func TestExecute_RejectsRetiredTarget(t *testing.T) { eng, store := newTargetEngine(t, activeNexus()) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} }) _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_retired_thing"}) if !errors.Is(err, execution.ErrTargetNotActive) { t.Fatalf("expected ErrTargetNotActive, got %v", err) } } func TestExecute_AcceptsMatchingTarget(t *testing.T) { eng, store := newTargetEngine(t, activeNexus()) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} }) res, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_container_maven"}) if err != nil { t.Fatalf("expected success, got %v", err) } if res.Execution.Status != domain.ExecutionSucceeded { t.Fatalf("expected succeeded, got %q (%s)", res.Execution.Status, res.Execution.Error) } } // TestExecute_EmptyTargetTypesStillRequiresRealEntity documents the deliberate // meaning of an empty TargetTypes: no *type* constraint, but the entity must // still exist and be active. It is not a bypass. func TestExecute_EmptyTargetTypesStillRequiresRealEntity(t *testing.T) { eng, store := newTargetEngine(t, activeNexus()) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = nil }) if _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_nope"}); !errors.Is(err, execution.ErrTargetNotFound) { t.Fatalf("expected ErrTargetNotFound, got %v", err) } if _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_host_homesrv"}); err != nil { t.Fatalf("any existing type should be accepted, got %v", err) } } // TestExecute_FailsClosedWhenNexusUnreachable is the whole point of the // guard: a Nexus outage must not degrade into accepting arbitrary targets. func TestExecute_FailsClosedWhenNexusUnreachable(t *testing.T) { eng, store := newTargetEngine(t, &fakeNexus{err: errors.New("connection refused")}) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} }) _, err := eng.Execute(&domain.ExecuteRequest{CapabilityID: cap.ID, TargetEntityID: "ent_container_maven"}) if !errors.Is(err, execution.ErrTargetUnverifiable) { t.Fatalf("expected ErrTargetUnverifiable, got %v", err) } } // TestCreateConfirmation_ValidatesTarget stops a confirmation being minted // for a target that execute would later refuse. func TestCreateConfirmation_ValidatesTarget(t *testing.T) { eng, store := newTargetEngine(t, activeNexus()) cap := mustCreateCapability(t, store, func(c *domain.Capability) { c.TargetTypes = []string{"container"} c.RequiresConfirmation = true }) if _, err := eng.CreateConfirmation(cap.ID, "just some words", "test", nil); !errors.Is(err, execution.ErrTargetMalformed) { t.Fatalf("expected ErrTargetMalformed, got %v", err) } if _, err := eng.CreateConfirmation(cap.ID, "ent_host_homesrv", "test", nil); !errors.Is(err, execution.ErrTargetTypeMismatch) { t.Fatalf("expected ErrTargetTypeMismatch, got %v", err) } if _, err := eng.CreateConfirmation(cap.ID, "ent_container_maven", "test", nil); err != nil { t.Fatalf("expected valid target to be accepted, got %v", err) } }