{"record":{"id":"9c9e39faac532a72","repo":"router-for-me/CLIProxyAPI","slug":"direct-plugin-sync-artifact-d-must-use-https","errorCode":null,"errorMessage":"direct plugin sync artifact %d must use https","messagePattern":"direct plugin sync artifact (.+?) must use https","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/home_sync.go","lineNumber":94,"sourceCode":"\t\t\t\treturn fmt.Errorf(\"plugin sync item %d auth %d: %w\", index, authIndex, errAuth)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validatePluginSyncManifestURLs(manifest Manifest) error {\n\tif manifest.InstallType() != InstallTypeDirect {\n\t\treturn nil\n\t}\n\tplan := NormalizeInstallPlan(manifest.Install)\n\tif len(plan.Artifacts) == 0 {\n\t\treturn fmt.Errorf(\"direct plugin sync manifest requires pinned artifacts\")\n\t}\n\tfor index, artifact := range plan.Artifacts {\n\t\tparsed, errParse := url.Parse(strings.TrimSpace(artifact.URL))\n\t\tif errParse != nil || !strings.EqualFold(parsed.Scheme, \"https\") {\n\t\t\treturn fmt.Errorf(\"direct plugin sync artifact %d must use https\", index)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (r *PluginSyncResponse) Clear() {\n\tif r == nil {\n\t\treturn\n\t}\n\tfor index := range r.Items {\n\t\tr.Items[index].Clear()\n\t}\n\tr.Items = nil\n\tr.ExpiresAt = time.Time{}\n\tr.SchemaVersion = 0\n}\n","sourceCodeStart":76,"sourceCodeEnd":111,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/home_sync.go#L76-L111","documentation":"For a direct-install manifest, artifact number N (0-based) has a URL that either failed url.Parse or whose scheme is not https (case-insensitive check). The sync protocol requires HTTPS for all pinned artifact downloads to prevent tampering in transit.","triggerScenarios":"Validate on a direct manifest where an artifact URL is http://, has no scheme (bare host/path), or contains characters that make url.Parse fail.","commonSituations":"Internal HTTP mirror used for artifact hosting; URL missing the scheme after a copy-paste; trailing whitespace/control characters breaking the parse.","solutions":["Change the artifact URL to https://","Put the plain-HTTP mirror behind TLS (or a self-signed CA added to system trust, still served as https)","Fix malformed URLs — verify with url.Parse before publishing the manifest"],"exampleFix":"// before\n{\"url\":\"http://artifacts.internal/p_1.0.0_linux_amd64.zip\"}\n\n// after\n{\"url\":\"https://artifacts.internal/p_1.0.0_linux_amd64.zip\"}","handlingStrategy":"validation","validationCode":"for k, a := range plan.Artifacts {\n    u, e := url.Parse(strings.TrimSpace(a.URL))\n    if e != nil || !strings.EqualFold(u.Scheme, \"https\") {\n        return fmt.Errorf(\"artifact %d not https: %s\", k, a.URL)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"must use https\") {\n    // block install, surface the offending URL for correction\n}","preventionTips":["Enforce https in manifest authoring templates and CI","Parse artifact URLs with url.Parse before publishing","Host internal mirrors over TLS instead of relaxing the check"],"tags":["https","artifact-url","security","manifest","go"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}