Add marketplace foundation and cross-domain tenant auth
This commit is contained in:
120
connectorkit/manifest.go
Normal file
120
connectorkit/manifest.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package connectorkit
|
||||
|
||||
import "regexp"
|
||||
|
||||
type Manifest struct {
|
||||
SchemaVersion string `json:"schemaVersion"`
|
||||
Slug string `json:"slug"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
AssetType string `json:"assetType"`
|
||||
Category string `json:"category"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Publisher map[string]string `json:"publisher"`
|
||||
Repository map[string]string `json:"repository"`
|
||||
Documentation map[string]string `json:"documentation"`
|
||||
Capabilities []string `json:"capabilities"`
|
||||
Evidence map[string]bool `json:"evidence"`
|
||||
Security map[string]bool `json:"security"`
|
||||
SupportedLanguages []string `json:"supportedLanguages,omitempty"`
|
||||
}
|
||||
|
||||
type Finding struct {
|
||||
Code string
|
||||
Severity string
|
||||
Message string
|
||||
}
|
||||
|
||||
type ValidationResult struct {
|
||||
OK bool
|
||||
EvidenceScore int
|
||||
Tier string
|
||||
Findings []Finding
|
||||
}
|
||||
|
||||
var slugPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]{2,95}$`)
|
||||
var versionPattern = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][a-zA-Z0-9.-]+)?$`)
|
||||
var categories = map[string]bool{
|
||||
"ai-governance": true,
|
||||
"compliance": true,
|
||||
"crm": true,
|
||||
"devops": true,
|
||||
"erp": true,
|
||||
"iam": true,
|
||||
"security": true,
|
||||
"storage": true,
|
||||
}
|
||||
|
||||
func ValidateManifest(manifest Manifest) ValidationResult {
|
||||
findings := make([]Finding, 0)
|
||||
if !slugPattern.MatchString(manifest.Slug) {
|
||||
findings = append(findings, Finding{"manifest.invalid_slug", "error", "slug must be lower-kebab-case"})
|
||||
}
|
||||
if !versionPattern.MatchString(manifest.Version) {
|
||||
findings = append(findings, Finding{"manifest.invalid_version", "error", "version must be semantic versioning"})
|
||||
}
|
||||
if !categories[manifest.Category] {
|
||||
findings = append(findings, Finding{"manifest.invalid_category", "error", "unsupported category"})
|
||||
}
|
||||
if len(manifest.Capabilities) == 0 {
|
||||
findings = append(findings, Finding{"capabilities.empty", "error", "at least one capability is required"})
|
||||
}
|
||||
if manifest.SchemaVersion == "" || manifest.Name == "" || manifest.AssetType == "" {
|
||||
findings = append(findings, Finding{"manifest.missing_field", "error", "schemaVersion, name, and assetType are required"})
|
||||
}
|
||||
score := 0
|
||||
if len(findings) == 0 {
|
||||
score = 0
|
||||
if manifest.Evidence["receipts"] && manifest.Evidence["offlineVerification"] {
|
||||
score += 25
|
||||
} else {
|
||||
score += 18
|
||||
}
|
||||
if manifest.Security["secretScan"] && manifest.Security["dependencyScan"] {
|
||||
score += 20
|
||||
} else {
|
||||
score += 12
|
||||
}
|
||||
if manifest.Evidence["witnessCompatible"] {
|
||||
score += 15
|
||||
} else {
|
||||
score += 8
|
||||
}
|
||||
if manifest.Repository["url"] != "" && manifest.Documentation["url"] != "" {
|
||||
score += 15
|
||||
} else {
|
||||
score += 10
|
||||
}
|
||||
if hasCapability(manifest.Capabilities, "proofstream") {
|
||||
score += 15
|
||||
} else {
|
||||
score += 10
|
||||
}
|
||||
score += 5
|
||||
}
|
||||
tier := "hidden"
|
||||
switch {
|
||||
case score >= 95:
|
||||
tier = "platinum"
|
||||
case score >= 85:
|
||||
tier = "gold"
|
||||
case score >= 70:
|
||||
tier = "silver"
|
||||
case score >= 50:
|
||||
tier = "community"
|
||||
}
|
||||
if score < 50 && len(findings) == 0 {
|
||||
findings = append(findings, Finding{"score.hidden", "error", "Evidence Score below 50 cannot be publicly listed"})
|
||||
}
|
||||
return ValidationResult{OK: len(findings) == 0 && score >= 50, EvidenceScore: score, Tier: tier, Findings: findings}
|
||||
}
|
||||
|
||||
func hasCapability(values []string, target string) bool {
|
||||
for _, value := range values {
|
||||
if value == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user