Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(referrers): support referrers API #180

Merged
merged 47 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e3e1217
push manifest with subject
Nov 18, 2024
846e173
add unit tests
Nov 19, 2024
7fca0cb
add unit tests
Nov 19, 2024
ec93662
Merge branch 'main' into feature/pushManifestWithSubject
Nov 19, 2024
7809549
resolve merge conflicts
Nov 19, 2024
c7e4418
add tests
Nov 19, 2024
a6d552f
add comments
Nov 19, 2024
685ab70
add unit test
Nov 20, 2024
1b9ade3
add unit tests
Nov 20, 2024
5041592
resolve comments
Nov 21, 2024
c26ccb6
add SetReferrersSupportLevel func and unit tests
Nov 21, 2024
ddbf048
remove NoReferrerUpdateException and update tests accordingly
Nov 22, 2024
d6e8499
add Index constructor
Nov 24, 2024
cf431f0
add license header
Nov 26, 2024
50e696e
resolve merge conflicts
Nov 26, 2024
856c0ef
add lock on SetReferrerState
Nov 29, 2024
fcb121e
simplify ApplyReferrerChanges
Nov 29, 2024
2b24e07
resolve comments
Dec 3, 2024
7df36ca
Merge branch 'main' into feature/pushManifestWithSubject
Dec 3, 2024
c30d6b2
resolve comments
Dec 13, 2024
b20a202
resolve comments
Dec 20, 2024
07d8e06
resolve comments
Dec 23, 2024
27382ae
resolve comments
Dec 23, 2024
b858999
Merge branch 'main' into feature/pushManifestWithSubject
Dec 23, 2024
404337e
resolve comments
Dec 23, 2024
1041bc0
resolve comments
Dec 23, 2024
85435cc
list referrers
Jan 10, 2025
cd05c4b
fix merge conflict
Jan 12, 2025
e17c50c
add unit tests
Jan 13, 2025
db582c2
add unit tests
Jan 15, 2025
966b2ad
add comments
Feb 3, 2025
037b092
format codes
Feb 3, 2025
71fcfcb
add headers
Feb 3, 2025
dfb1291
Merge branch 'main' into feature/listReferrers
Feb 5, 2025
447a280
add invalidResponseException tests
Feb 5, 2025
f668c22
Merge branch 'main' into feature/listReferrers
Feb 10, 2025
7f0553f
Merge branch 'main' into feature/listReferrers
Feb 18, 2025
7724d7f
address comments
Feb 19, 2025
9f1cc15
address comments
Feb 19, 2025
c64338f
verify returned manifest
Feb 24, 2025
9880d45
change callback function to return IAsyncEnumerable
Feb 25, 2025
703df70
resolve conflicts
Feb 25, 2025
b923532
resolve comments
Feb 26, 2025
5a51f41
resolve comments
Feb 26, 2025
b98b303
resolve comments
Feb 26, 2025
8c7b38e
resolve comments
Feb 26, 2025
28d3be2
resolve comments
Feb 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/OrasProject.Oras/Registry/Remote/Referrers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,14 @@ internal static bool IsReferrersFilterApplied(string? appliedFilters, string req
}

var filters = Strings.Split(appliedFilters, ",");
for (int i = 0; i < filters.Length; ++i)
foreach (var filter in filters)
{
if (filters[i] == requestedFilter)
if (filter == requestedFilter)
{
return true;
}
}

return false;
}

Expand Down
30 changes: 20 additions & 10 deletions src/OrasProject.Oras/Registry/Remote/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@
public RepositoryOptions Options => _opts;

private int _referrersState = (int) Referrers.ReferrersState.Unknown;

/// <summary>
/// _filterTypeArtifactType is the "artifactType" filter applied on the list of referrers.
///
/// References:
/// - Latest spec: https://github.com/opencontainers/distribution-spec/blob/v1.1.1/spec.md#listing-referrers
/// </summary>
private const string _filterTypeArtifactType = "artifactType";

/// <summary>
/// ReferrersState indicates the Referrers API state of the remote repository.
Expand All @@ -71,15 +79,15 @@
/// <summary>
/// ReferrerListPageSize specifies the page size when invoking the Referrers API.
/// If zero, the page size is determined by the remote registry.
/// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#listing-referrers
/// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.1/spec.md#listing-referrers
/// </summary>
public int ReferrerListPageSize;

/// <summary>
/// _headerOciFiltersApplied is the "OCI-Filters-Applied" header.
/// If present on the response, it contains a comma-separated list of the applied filters.
/// Reference:
/// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#listing-referrers
/// - https://github.com/opencontainers/distribution-spec/blob/v1.1.1/spec.md#listing-referrers
/// </summary>
private const string _headerOciFiltersApplied = "OCI-Filters-Applied";

Expand Down Expand Up @@ -409,8 +417,8 @@
{
await ReferrersByApi(descriptor, artifactType, fn, cancellationToken).ConfigureAwait(false);
if (ReferrersState == Referrers.ReferrersState.Supported)
{
return;

Check warning on line 421 in src/OrasProject.Oras/Registry/Remote/Repository.cs

View check run for this annotation

Codecov / codecov/patch

src/OrasProject.Oras/Registry/Remote/Repository.cs#L420-L421

Added lines #L420 - L421 were not covered by tests
}
}
catch (NotSupportedException)
Expand Down Expand Up @@ -468,14 +476,13 @@
{
// If ReferrerListPageSize is greater than 0, modify the URL to include the page size query parameter
if (ReferrerListPageSize > 0)
{
// TODO
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("n", ReferrerListPageSize.ToString());
uriBuilder.Query = query.ToString();
url = uriBuilder.Uri;
}

Check warning on line 485 in src/OrasProject.Oras/Registry/Remote/Repository.cs

View check run for this annotation

Codecov / codecov/patch

src/OrasProject.Oras/Registry/Remote/Repository.cs#L479-L485

Added lines #L479 - L485 were not covered by tests
using var response = await _opts.HttpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
switch (response.StatusCode)
{
Expand Down Expand Up @@ -507,7 +514,7 @@
using var content = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
var referrersIndex = JsonSerializer.Deserialize<Index>(content);
if (referrersIndex == null)
{

Check warning on line 517 in src/OrasProject.Oras/Registry/Remote/Repository.cs

View check run for this annotation

Codecov / codecov/patch

src/OrasProject.Oras/Registry/Remote/Repository.cs#L517

Added line #L517 was not covered by tests
throw new InvalidResponseException($"{response.RequestMessage?.Method} {response.RequestMessage?.RequestUri}: failed to decode response");
}
var referrers = referrersIndex.Manifests;
Expand All @@ -515,7 +522,7 @@
// If artifactType is specified, apply any filters based on the artifact type
if (!string.IsNullOrEmpty(artifactType))
{
if (!response.Headers.TryGetValues(_headerOciFiltersApplied, out var values) || !Referrers.IsReferrersFilterApplied(values.FirstOrDefault(), artifactType))
if (!response.Headers.TryGetValues(_headerOciFiltersApplied, out var values) || !Referrers.IsReferrersFilterApplied(values.FirstOrDefault(), _filterTypeArtifactType))
{
// Filter the referrers based on the artifact type if necessary
referrers = Referrers.FilterReferrers(referrers, artifactType);
Expand Down Expand Up @@ -566,14 +573,17 @@
{
try
{
var (desc, content) = await FetchAsync(referrersTag, cancellationToken).ConfigureAwait(false);
var index = JsonSerializer.Deserialize<Index>(content);
if (index == null)
var result = await FetchAsync(referrersTag, cancellationToken).ConfigureAwait(false);
using (var content = result.Item2)
{
throw new JsonException($"null index manifests list for referrersTag {referrersTag}");
}
var index = JsonSerializer.Deserialize<Index>(content);
if (index == null)
{
throw new JsonException($"null index manifests list for referrersTag {referrersTag}");

Check warning on line 582 in src/OrasProject.Oras/Registry/Remote/Repository.cs

View check run for this annotation

Codecov / codecov/patch

src/OrasProject.Oras/Registry/Remote/Repository.cs#L581-L582

Added lines #L581 - L582 were not covered by tests
}

return (desc, index.Manifests);
return (result.Item1, index.Manifests);
}
}
catch (NotFoundException)
{
Expand Down
12 changes: 6 additions & 6 deletions tests/OrasProject.Oras.Tests/Remote/ReferrersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@
Referrers.ReferrerOperation.Add
);

var (updatedReferrers, updateRequired) = Referrers.ApplyReferrerChanges(oldReferrers, referrerChange);

Check warning on line 251 in tests/OrasProject.Oras.Tests/Remote/ReferrersTest.cs

View workflow job for this annotation

GitHub Actions / Analyze (8.0.x)

Argument of type 'List<Descriptor?>' cannot be used for parameter 'oldReferrers' of type 'IList<Descriptor>' in '(IList<Descriptor>, bool) Referrers.ApplyReferrerChanges(IList<Descriptor> oldReferrers, ReferrerChange referrerChange)' due to differences in the nullability of reference types.

Check warning on line 251 in tests/OrasProject.Oras.Tests/Remote/ReferrersTest.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x)

Argument of type 'List<Descriptor?>' cannot be used for parameter 'oldReferrers' of type 'IList<Descriptor>' in '(IList<Descriptor>, bool) Referrers.ApplyReferrerChanges(IList<Descriptor> oldReferrers, ReferrerChange referrerChange)' due to differences in the nullability of reference types.
Assert.Single(updatedReferrers);
for (var i = 0; i < updatedReferrers.Count; ++i)
{
Expand All @@ -272,7 +272,7 @@
public void IsReferrersFilterApplied_AppliedFiltersNull_ReturnsFalse()
{
string? appliedFilters = null;
const string requestedFilter = "someFilter";
const string requestedFilter = "artifactType";
var result = Referrers.IsReferrersFilterApplied(appliedFilters, requestedFilter);
Assert.False(result);
}
Expand All @@ -281,24 +281,24 @@
public void IsReferrersFilterApplied_AppliedFiltersEmpty_ReturnsFalse()
{
const string appliedFilters = "";
const string requestedFilter = "someFilter";
const string requestedFilter = "artifactType";
var result = Referrers.IsReferrersFilterApplied(appliedFilters, requestedFilter);
Assert.False(result);
}

[Fact]
public void IsReferrersFilterApplied_RequestedFilterNull_ReturnsFalse()
{
const string appliedFilters = "filter1,filter2";
const string appliedFilters = "artifactType,annotation";
string? requestedFilter = null;
var result = Referrers.IsReferrersFilterApplied(appliedFilters, requestedFilter);

Check warning on line 294 in tests/OrasProject.Oras.Tests/Remote/ReferrersTest.cs

View workflow job for this annotation

GitHub Actions / Analyze (8.0.x)

Possible null reference argument for parameter 'requestedFilter' in 'bool Referrers.IsReferrersFilterApplied(string? appliedFilters, string requestedFilter)'.

Check warning on line 294 in tests/OrasProject.Oras.Tests/Remote/ReferrersTest.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x)

Possible null reference argument for parameter 'requestedFilter' in 'bool Referrers.IsReferrersFilterApplied(string? appliedFilters, string requestedFilter)'.
Assert.False(result);
}

[Fact]
public void IsReferrersFilterApplied_RequestedFilterEmpty_ReturnsFalse()
{
const string appliedFilters = "filter1,filter2";
const string appliedFilters = "artifactType,annotation";
const string requestedFilter = "";
var result = Referrers.IsReferrersFilterApplied(appliedFilters, requestedFilter);
Assert.False(result);
Expand All @@ -307,8 +307,8 @@
[Fact]
public void IsReferrersFilterApplied_RequestedFilterMatches_ReturnsTrue()
{
const string appliedFilters = "filter1,filter2";
const string requestedFilter = "filter1";
const string appliedFilters = "artifactType,annotation";
const string requestedFilter = "artifactType";

var result = Referrers.IsReferrersFilterApplied(appliedFilters, requestedFilter);
Assert.True(result);
Expand Down
Loading