chore: initialize standalone business plugin repository
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user