package lua import ( "os" "path/filepath" "testing" ) // TestAccessOverrideSurvivesReload is the test that matters for an access // restriction. An in-memory map makes "billing is admin-only" look like it // worked right up to the next restart, and then the restriction is simply gone // with nothing in the logs to explain it. Both the plugin-level audience and // the per-endpoint spec must come back. func TestAccessOverrideSurvivesReload(t *testing.T) { dir := t.TempDir() src := `local P = {} P.name = "api" P.version = "1.0.0" P.http = { { path = "health", handler = "health", roles = { "admin" } }, } function P.health(req) return { json = { ok = true } } end return P ` first := NewPlugins(NewVM(dir), dir) if err := first.LoadSource("api", src); err != nil { t.Fatal(err) } first.SetPluginVisibility("api", "admin, user") if err := first.SetEndpointAccess("api", "health", "@homeagent"); err != nil { t.Fatal(err) } if _, err := os.Stat(filepath.Join(dir, accessFileName)); err != nil { t.Fatalf("override was not written: %v", err) } // A fresh Plugins over the same dir is what a restart looks like. second := NewPlugins(NewVM(dir), dir) // The plugin source is on disk too, so this second instance sees both the // plugin and the overrides — the same pair a restart sees. Loading only the // overrides would leave no endpoints to walk, and the assertion below would // pass vacuously. if err := second.LoadSource("api", src); err != nil { t.Fatal(err) } if err := second.LoadAccessOverrides(); err != nil { t.Fatalf("reload overrides: %v", err) } if got := second.VisibilityOverride("api"); got != "admin, user" { t.Errorf("plugin visibility lost across reload: %q", got) } found := false for _, e := range second.EndpointAccess() { if e.Path == "health" && len(e.OverrideKeys) == 1 && e.OverrideKeys[0] == "homeagent" { found = true } } if !found { t.Error("endpoint override lost across reload") } } // TestAccessOverrideClearedRemovesFile keeps the "nothing overridden" state // distinguishable from "overridden with something". func TestAccessOverrideClearedRemovesFile(t *testing.T) { dir := t.TempDir() ps := NewPlugins(NewVM(dir), dir) ps.SetPluginVisibility("api", "admin") path := filepath.Join(dir, accessFileName) if _, err := os.Stat(path); err != nil { t.Fatalf("expected an access file: %v", err) } ps.SetPluginVisibility("api", "") if _, err := os.Stat(path); !os.IsNotExist(err) { t.Errorf("clearing the last override should remove the file, got %v", err) } } // TestVisibilityOverridesExcludeEndpointKeys keeps endpoint policy out of the // plugin-audience listing. Both live in one map, and reporting "probe#hello" // under visibility is how the plugin page ends up offering to save an audience // of that name — which nothing reads as an audience. func TestVisibilityOverridesExcludeEndpointKeys(t *testing.T) { dir := t.TempDir() src := `local P = {} P.name = "api" P.version = "1.0.0" P.http = { { path = "health", handler = "health", roles = { "admin" } } } function P.health(req) return { json = { ok = true } } end return P ` ps := NewPlugins(NewVM(dir), dir) if err := ps.LoadSource("api", src); err != nil { t.Fatal(err) } ps.SetPluginVisibility("api", "admin, user") if err := ps.SetEndpointAccess("api", "health", "@homeagent"); err != nil { t.Fatal(err) } got := ps.VisibilityOverrides() if got["api"] != "admin, user" { t.Errorf("plugin audience missing: %+v", got) } if _, leaked := got["api#health"]; leaked { t.Errorf("endpoint override leaked into the audience map: %+v", got) } if len(got) != 1 { t.Errorf("expected exactly the plugin audience, got %+v", got) } }