checkUpstreamProvenance fetches the skill's SKILL.md via the contents API to check if it contains github-repo metadata pointing to a different repository, indicating the skill was re-published from an upstream source. In interactive mode, the user is asked whether to install from the re-publisher or
(opts *InstallOptions, client *api.Client, hostname string, skill discovery.Skill, commitSHA string)
| 1287 | // installs from the re-publisher. |
| 1288 | // Returns (repo to redirect to, whether upstream was detected, error). |
| 1289 | func checkUpstreamProvenance(opts *InstallOptions, client *api.Client, hostname string, skill discovery.Skill, commitSHA string) (ghrepo.Interface, bool, error) { |
| 1290 | apiPath := fmt.Sprintf("repos/%s/%s/contents/%s?ref=%s", |
| 1291 | opts.repo.RepoOwner(), opts.repo.RepoName(), |
| 1292 | skill.Path+"/SKILL.md", commitSHA) |
| 1293 | var fileResp struct { |
| 1294 | Content string `json:"content"` |
| 1295 | Encoding string `json:"encoding"` |
| 1296 | } |
| 1297 | if err := client.REST(hostname, "GET", apiPath, nil, &fileResp); err != nil { |
| 1298 | return nil, false, nil //nolint:nilerr // best-effort check; failing to fetch is not fatal |
| 1299 | } |
| 1300 | if fileResp.Encoding != "base64" { |
| 1301 | return nil, false, nil |
| 1302 | } |
| 1303 | decoded, decodeErr := io.ReadAll(base64.NewDecoder(base64.StdEncoding, strings.NewReader(fileResp.Content))) |
| 1304 | if decodeErr != nil { |
| 1305 | return nil, false, nil //nolint:nilerr // best-effort; decode failure is not fatal |
| 1306 | } |
| 1307 | content := string(decoded) |
| 1308 | |
| 1309 | result, parseErr := frontmatter.Parse(content) |
| 1310 | if parseErr != nil || result.Metadata.Meta == nil { |
| 1311 | //nolint:nilerr // unparseable frontmatter means no upstream to detect |
| 1312 | return nil, false, nil |
| 1313 | } |
| 1314 | |
| 1315 | existingRepo, _ := result.Metadata.Meta["github-repo"].(string) |
| 1316 | if existingRepo == "" { |
| 1317 | return nil, false, nil |
| 1318 | } |
| 1319 | |
| 1320 | currentRepoURL := source.BuildRepoURL(hostname, opts.repo.RepoOwner(), opts.repo.RepoName()) |
| 1321 | if existingRepo == currentRepoURL { |
| 1322 | return nil, false, nil |
| 1323 | } |
| 1324 | |
| 1325 | upstreamRepo, parseErr := source.ParseRepoURL(existingRepo) |
| 1326 | if parseErr != nil { |
| 1327 | //nolint:nilerr // invalid repo URL means we can't redirect; install normally |
| 1328 | return nil, false, nil |
| 1329 | } |
| 1330 | |
| 1331 | cs := opts.IO.ColorScheme() |
| 1332 | upstreamLabel := ghrepo.FullName(upstreamRepo) |
| 1333 | repoSource := ghrepo.FullName(opts.repo) |
| 1334 | |
| 1335 | fmt.Fprintf(opts.IO.ErrOut, "%s This skill was originally published in %s\n", cs.WarningIcon(), upstreamLabel) |
| 1336 | |
| 1337 | if opts.Upstream { |
| 1338 | fmt.Fprintf(opts.IO.ErrOut, "Redirecting install to %s...\n", upstreamLabel) |
| 1339 | return upstreamRepo, true, nil |
| 1340 | } |
| 1341 | |
| 1342 | if !opts.IO.CanPrompt() { |
| 1343 | fmt.Fprintf(opts.IO.ErrOut, " Installing from %s (use --upstream or interactive mode to choose upstream)\n", repoSource) |
| 1344 | return nil, true, nil |
| 1345 | } |
| 1346 |
no test coverage detected