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"` Provider map[string]any `json:"provider,omitempty"` Auth map[string]any `json:"auth,omitempty"` Sync map[string]any `json:"sync,omitempty"` EventTypes []string `json:"eventTypes,omitempty"` SourceTime map[string]any `json:"sourceTime,omitempty"` ConfigSchema map[string]any `json:"configSchema,omitempty"` SecretSchema map[string]any `json:"secretSchema,omitempty"` Diagnostics map[string]any `json:"diagnostics,omitempty"` Runtime map[string]any `json:"runtime,omitempty"` InstallRequirements map[string]any `json:"installRequirements,omitempty"` Changelog []map[string]any `json:"changelog,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, } var schemaVersions = map[string]bool{"1.0": true, "attesto.connector.v2": true} var supportedAuthModes = map[string]bool{ "api-key": true, "basic-auth": true, "oauth2": true, "signed-webhook": true, "storage-credentials": true, "token": true, } var supportedSyncModes = map[string]bool{ "manual": true, "object-commit": true, "polling": true, "webhook": true, } var requiredDiagnostics = []string{ "providerAuthStatus", "replayConflictCheck", "revocationCheck", "syncLag", "testConnection", } var requiredRuntimeMethods = []string{ "diagnostics", "emitProofstreamEvent", "handleWebhook", "metadata", "revoke", "sync", "testConnection", "validateConfig", } 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 !schemaVersions[manifest.SchemaVersion] { findings = append(findings, Finding{"manifest.invalid_schema_version", "error", "schemaVersion must be 1.0 or attesto.connector.v2"}) } 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"}) } if manifest.AssetType == "connector" && manifest.SchemaVersion == "attesto.connector.v2" { findings = appendV2Findings(manifest, findings) } 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 appendV2Findings(manifest Manifest, findings []Finding) []Finding { if !hasRequiredKeys(manifest.Provider, []string{"id", "name", "websiteUrl"}) { findings = append(findings, Finding{"provider.invalid", "error", "provider.id, provider.name and provider.websiteUrl are required"}) } if !hasRequiredKeys(manifest.Auth, []string{"mode", "scopes"}) { findings = append(findings, Finding{"auth.invalid", "error", "auth.mode and auth.scopes are required"}) } else if !supportedAuthModes[toString(manifest.Auth["mode"])] { findings = append(findings, Finding{"auth.invalid_mode", "error", "unsupported auth.mode"}) } else if len(stringSet(manifest.Auth["scopes"])) == 0 { findings = append(findings, Finding{"auth.invalid_scopes", "error", "auth.scopes must be a non-empty list"}) } if !hasRequiredKeys(manifest.Sync, []string{"modes", "supportsReplay", "rateLimitPolicy"}) { findings = append(findings, Finding{"sync.invalid", "error", "sync.modes, sync.supportsReplay and sync.rateLimitPolicy are required"}) } else { modes := stringSet(manifest.Sync["modes"]) if len(modes) == 0 || !subset(modes, supportedSyncModes) { findings = append(findings, Finding{"sync.invalid_modes", "error", "unsupported sync.modes"}) } } if len(manifest.EventTypes) == 0 { findings = append(findings, Finding{"event_types.invalid", "error", "eventTypes must be non-empty strings"}) } if !hasRequiredKeys(manifest.SourceTime, []string{"required", "timezonePolicy"}) { findings = append(findings, Finding{"source_time.invalid", "error", "sourceTime.required and sourceTime.timezonePolicy are required"}) } else if manifest.SourceTime["required"] != true { findings = append(findings, Finding{"source_time.not_required", "error", "sourceTime.required must be true for production connectors"}) } if manifest.ConfigSchema["type"] != "object" { findings = append(findings, Finding{"configSchema.invalid", "error", "configSchema.type must be object"}) } if manifest.SecretSchema["type"] != "object" { findings = append(findings, Finding{"secretSchema.invalid", "error", "secretSchema.type must be object"}) } if !hasRequiredKeys(manifest.Diagnostics, requiredDiagnostics) { findings = append(findings, Finding{"diagnostics.incomplete", "error", "diagnostics must cover auth, connection, lag, replay and revoke state"}) } if !hasRequiredKeys(manifest.Runtime, []string{"officialConnectorKit", "sdkSurfaces", "requiredMethods", "canary"}) { findings = append(findings, Finding{"runtime.incomplete", "error", "runtime must declare connector-kit, SDK surfaces, methods and canary"}) } else { if manifest.Runtime["officialConnectorKit"] != true { findings = append(findings, Finding{"runtime.unofficial", "error", "runtime.officialConnectorKit must be true"}) } surfaces := stringSet(manifest.Runtime["sdkSurfaces"]) for _, surface := range []string{"python", "typescript", "go", "cli"} { if !surfaces[surface] { findings = append(findings, Finding{"runtime.sdk_surfaces", "error", "runtime.sdkSurfaces must include python, typescript, go and cli"}) break } } methods := stringSet(manifest.Runtime["requiredMethods"]) for _, method := range requiredRuntimeMethods { if !methods[method] { findings = append(findings, Finding{"runtime.required_methods", "error", "runtime.requiredMethods is missing connector runtime methods"}) break } } canary, ok := manifest.Runtime["canary"].(map[string]any) if !ok || canary["status"] != "green" { findings = append(findings, Finding{"runtime.canary", "error", "runtime.canary.status must be green before publication"}) } } if !hasRequiredKeys(manifest.InstallRequirements, []string{"tenantLoginRequired", "entitlementRequired"}) { findings = append(findings, Finding{"install_requirements.invalid", "error", "installRequirements must declare tenant login and entitlement requirements"}) } else if manifest.InstallRequirements["tenantLoginRequired"] != true || manifest.InstallRequirements["entitlementRequired"] != true { findings = append(findings, Finding{"install_requirements.unsafe", "error", "install/download/configure must require tenant login and entitlement"}) } if len(manifest.Changelog) == 0 { findings = append(findings, Finding{"changelog.invalid", "error", "changelog must include versioned entries"}) } return findings } func hasRequiredKeys(value map[string]any, keys []string) bool { if value == nil { return false } for _, key := range keys { if _, ok := value[key]; !ok { return false } } return true } func toString(value any) string { if text, ok := value.(string); ok { return text } return "" } func stringSet(value any) map[string]bool { out := map[string]bool{} switch values := value.(type) { case []string: for _, item := range values { if item != "" { out[item] = true } } case []any: for _, item := range values { if text, ok := item.(string); ok && text != "" { out[text] = true } } } return out } func subset(values map[string]bool, allowed map[string]bool) bool { for value := range values { if !allowed[value] { return false } } return true } func hasCapability(values []string, target string) bool { for _, value := range values { if value == target { return true } } return false }