package manifest import ( "crypto/ed25519" "encoding/base64" "encoding/json" "os" "path/filepath" "strings" "testing" ) func validManifest() Manifest { return Manifest{ SchemaVersion: 1, PluginID: "qiu.plugin-admin", Name: "Plugin Admin", Version: "1.0.0", CoreAPIBaseline: "sub2api-0.1.183", Capabilities: []string{"plugin.admin.v1", "diagnostics.v1"}, TestedCoreVersions: []string{"0.1.183"}, Backend: Backend{HealthPath: "/healthz", ReadinessPath: "/readyz", ListenEnv: "PLUGIN_PORT"}, UI: UI{Entrypoint: "/admin/", Menu: Menu{ID: "qiu.plugin-admin", Label: "Plugin Admin", Visibility: "admin", SortOrder: 200}}, Publisher: Publisher{KeyID: "publisher-key"}, CoreAPIAllowlist: RequiredAllowlist(), } } func TestValidateManifestAndRejectsUnsafeEntries(t *testing.T) { m := validManifest() if err := Validate(m); err != nil { t.Fatal(err) } for name, mutate := range map[string]func(*Manifest){ "duplicate allowlist": func(m *Manifest) { m.CoreAPIAllowlist = append(m.CoreAPIAllowlist, m.CoreAPIAllowlist[0]) }, "wildcard": func(m *Manifest) { m.CoreAPIAllowlist = append(m.CoreAPIAllowlist, "GET /api/v1/admin/*") }, "menu mismatch": func(m *Manifest) { m.UI.Menu.ID = "other.plugin" }, "traversal": func(m *Manifest) { m.UI.Entrypoint = "/admin/../secret" }, "entrypoint URL": func(m *Manifest) { m.UI.Entrypoint = "https://example.invalid/ui.js" }, "file drive path": func(m *Manifest) { m.Files = map[string]string{"C:/plugin.js": strings.Repeat("a", 64)} }, "file traversal": func(m *Manifest) { m.Files = map[string]string{"ui/../plugin.js": strings.Repeat("a", 64)} }, } { t.Run(name, func(t *testing.T) { candidate := m mutate(&candidate) if err := Validate(candidate); err == nil { t.Fatal("expected validation error") } }) } } func TestLoadRejectsUnknownAndTrailingJSON(t *testing.T) { dir := t.TempDir() for name, raw := range map[string]string{ "unknown": `{"schema_version":1,"extra":true}`, "trailing": `{"schema_version":1} {}`, "duplicate": `{"schema_version":1,"schema_version":1}`, } { path := filepath.Join(dir, name+".json") if err := os.WriteFile(path, []byte(raw), 0o600); err != nil { t.Fatal(err) } if _, _, err := Load(path); err == nil { t.Fatalf("%s: expected error", name) } } } func TestLoadRejectsNestedDuplicateJSONKeys(t *testing.T) { dir := t.TempDir() raw := `{"schema_version":1,"backend":{"health_path":"/healthz","health_path":"/readyz"}}` path := filepath.Join(dir, "nested-duplicate.json") if err := os.WriteFile(path, []byte(raw), 0o600); err != nil { t.Fatal(err) } if _, _, err := Load(path); err == nil { t.Fatal("expected nested duplicate key error") } } func TestSignatureAndKeyID(t *testing.T) { publicKey, privateKey, err := ed25519.GenerateKey(nil) if err != nil { t.Fatal(err) } manifestBytes := []byte(`{"schema_version":1}`) signature := Signature{Algorithm: "ed25519", KeyID: "publisher-key", Signature: base64.StdEncoding.EncodeToString(ed25519.Sign(privateKey, manifestBytes))} signatureBytes, err := json.Marshal(signature) if err != nil { t.Fatal(err) } publicKeyBytes := []byte(base64.StdEncoding.EncodeToString(publicKey)) if err := VerifyKeyID(signatureBytes, "publisher-key"); err != nil { t.Fatal(err) } if err := VerifySignature(manifestBytes, signatureBytes, publicKeyBytes); err != nil { t.Fatal(err) } if err := VerifySignature([]byte(`{"schema_version":2}`), signatureBytes, publicKeyBytes); err == nil { t.Fatal("expected tamper failure") } if err := VerifyKeyID([]byte(strings.TrimSuffix(string(signatureBytes), "}")+"}{}"), "publisher-key"); err == nil { t.Fatal("expected trailing signature failure") } duplicate := []byte(`{"algorithm":"ed25519","algorithm":"ed25519","key_id":"publisher-key","signature":""}`) if err := VerifyKeyID(duplicate, "publisher-key"); err == nil { t.Fatal("expected duplicate signature key failure") } } func TestCompatibility(t *testing.T) { m := validManifest() if got := m.EvaluateCompatibility("sub2api-0.1.183"); !got.Compatible || !got.Tested || got.Status != "compatible" { t.Fatalf("got %#v", got) } m.TestedCoreVersions = nil if got := m.EvaluateCompatibility("0.1.183"); !got.Compatible || got.Tested || got.Status != "untested" { t.Fatalf("got %#v", got) } if got := m.EvaluateCompatibility("0.1.184"); got.Compatible || got.Status != "incompatible" { t.Fatalf("got %#v", got) } }