commitSubjectReferrers is responsible for updating the fallback tag manifest to track descriptors referring to a subject for registries that don't yet support the Referrers API. TODO: use conditional requests to avoid race conditions
(ctx context.Context, sub name.Digest, add v1.Descriptor)
| 506 | // commitSubjectReferrers is responsible for updating the fallback tag manifest to track descriptors referring to a subject for registries that don't yet support the Referrers API. |
| 507 | // TODO: use conditional requests to avoid race conditions |
| 508 | func (w *writer) commitSubjectReferrers(ctx context.Context, sub name.Digest, add v1.Descriptor) error { |
| 509 | // Check if the registry supports Referrers API. |
| 510 | // TODO: This should be done once per registry, not once per subject. |
| 511 | u := w.url(fmt.Sprintf("/v2/%s/referrers/%s", w.repo.RepositoryStr(), sub.DigestStr())) |
| 512 | req, err := http.NewRequest(http.MethodGet, u.String(), nil) |
| 513 | if err != nil { |
| 514 | return err |
| 515 | } |
| 516 | req.Header.Set("Accept", string(types.OCIImageIndex)) |
| 517 | resp, err := w.client.Do(req.WithContext(ctx)) |
| 518 | if err != nil { |
| 519 | return err |
| 520 | } |
| 521 | defer resp.Body.Close() |
| 522 | |
| 523 | if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound, http.StatusBadRequest); err != nil { |
| 524 | return err |
| 525 | } |
| 526 | if resp.StatusCode == http.StatusOK { |
| 527 | // The registry supports Referrers API. The registry is responsible for updating the referrers list. |
| 528 | return nil |
| 529 | } |
| 530 | |
| 531 | // The registry doesn't support Referrers API, we need to update the manifest tagged with the fallback tag. |
| 532 | // Make the request to GET the current manifest. |
| 533 | t := fallbackTag(sub) |
| 534 | u = w.url(fmt.Sprintf("/v2/%s/manifests/%s", w.repo.RepositoryStr(), t.Identifier())) |
| 535 | req, err = http.NewRequest(http.MethodGet, u.String(), nil) |
| 536 | if err != nil { |
| 537 | return err |
| 538 | } |
| 539 | req.Header.Set("Accept", string(types.OCIImageIndex)) |
| 540 | resp, err = w.client.Do(req.WithContext(ctx)) |
| 541 | if err != nil { |
| 542 | return err |
| 543 | } |
| 544 | defer resp.Body.Close() |
| 545 | |
| 546 | var im v1.IndexManifest |
| 547 | if err := transport.CheckError(resp, http.StatusOK, http.StatusNotFound); err != nil { |
| 548 | return err |
| 549 | } else if resp.StatusCode == http.StatusNotFound { |
| 550 | // Not found just means there are no attachments. Start with an empty index. |
| 551 | im = v1.IndexManifest{ |
| 552 | SchemaVersion: 2, |
| 553 | MediaType: types.OCIImageIndex, |
| 554 | Manifests: []v1.Descriptor{add}, |
| 555 | } |
| 556 | } else { |
| 557 | if err := json.NewDecoder(resp.Body).Decode(&im); err != nil { |
| 558 | return err |
| 559 | } |
| 560 | if im.SchemaVersion != 2 { |
| 561 | return fmt.Errorf("fallback tag manifest is not a schema version 2: %d", im.SchemaVersion) |
| 562 | } |
| 563 | if im.MediaType != types.OCIImageIndex { |
| 564 | return fmt.Errorf("fallback tag manifest is not an OCI image index: %s", im.MediaType) |
| 565 | } |
no test coverage detected