Skip to content

Commit e92b4c9

Browse files
authored
Removing SHA256 manifests from the tag listing (#89)
* Remove sha256 manifest from the tag list + Handle invalid n values + Dynamically add the next link if needed * Update tests to exclude SHA256 from tag listing * Change typo to camelCase
1 parent 5586e2d commit e92b4c9

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

src/router.ts

+26-8
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ v2Router.delete("/:name+/blobs/uploads/:id", async (req, env: Env) => {
330330

331331
// this is the first thing that the client asks for in an upload
332332
v2Router.post("/:name+/blobs/uploads/", async (req, env: Env) => {
333-
const { name } = req.params;
333+
const { name } = req.params;
334334
const [uploadObject, err] = await wrap<UploadObject | RegistryError, Error>(env.REGISTRY_CLIENT.startUpload(name));
335335

336336
if (err) {
@@ -525,31 +525,49 @@ v2Router.get("/:name+/tags/list", async (req, env: Env) => {
525525

526526
const { n: nStr = 50, last } = req.query;
527527
const n = +nStr;
528-
if (isNaN(n)) {
528+
if (isNaN(n) || n <= 0) {
529529
throw new ServerError("invalid 'n' parameter", 400);
530530
}
531531

532-
const tags = await env.REGISTRY.list({
532+
let tags = await env.REGISTRY.list({
533533
prefix: `${name}/manifests`,
534534
limit: n,
535535
startAfter: last ? `${name}/manifests/${last}` : undefined,
536536
});
537+
// Filter out sha256 manifest
538+
let manifestTags = tags.objects.filter((tag) => !tag.key.startsWith(`${name}/manifests/sha256:`));
539+
// If results are truncated and the manifest filter removed some result, extend the search to reach the n number of results expected by the client
540+
while (tags.objects.length > 0 && tags.truncated && manifestTags.length !== n) {
541+
tags = await env.REGISTRY.list({
542+
prefix: `${name}/manifests`,
543+
limit: n - manifestTags.length,
544+
cursor: tags.cursor,
545+
});
546+
// Filter out sha256 manifest
547+
manifestTags = manifestTags.concat(
548+
tags.objects.filter((tag) => !tag.key.startsWith(`${name}/manifests/sha256:`)),
549+
);
550+
}
537551

538-
const keys = tags.objects.map((object) => object.key.split("/").pop()!);
552+
const keys = manifestTags.map((object) => object.key.split("/").pop()!);
539553
const url = new URL(req.url);
540554
url.searchParams.set("n", `${n}`);
541555
url.searchParams.set("last", keys.length ? keys[keys.length - 1] : "");
556+
const responseHeaders: { "Content-Type": string; "Link"?: string } = {
557+
"Content-Type": "application/json",
558+
};
559+
// Only supply a next link if the previous result is truncated
560+
if (tags.truncated) {
561+
responseHeaders.Link = `${url.toString()}; rel=next`;
562+
}
542563
return new Response(
543564
JSON.stringify({
544565
name,
545566
tags: keys,
546567
}),
547568
{
548569
status: 200,
549-
headers: {
550-
"Content-Type": "application/json",
551-
"Link": `${url.toString()}; rel=next`,
552-
},
570+
headers: responseHeaders,
553571
},
554572
);
555573
});

test/index.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ describe("v2 manifests", () => {
242242

243243
test("PUT then list tags with GET /v2/:name/tags/list", async () => {
244244
const { sha256 } = await createManifest("hello-world-list", await generateManifest("hello-world-list"), `hello`);
245-
const expectedRes = ["hello", sha256];
245+
const expectedRes = ["hello"];
246246
for (let i = 0; i < 50; i++) {
247247
expectedRes.push(`hello-${i}`);
248248
}
@@ -257,6 +257,7 @@ describe("v2 manifests", () => {
257257
const tags = (await tagsRes.json()) as TagsList;
258258
expect(tags.name).toEqual("hello-world-list");
259259
expect(tags.tags).toEqual(expectedRes);
260+
expect(tags.tags).not.contain(sha256)
260261

261262
const res = await fetch(createRequest("DELETE", `/v2/hello-world-list/manifests/${sha256}`, null));
262263
expect(res.ok).toBeTruthy();
@@ -514,8 +515,8 @@ describe("push and catalog", () => {
514515
"hello",
515516
"hello-2",
516517
"latest",
517-
"sha256:a8a29b609fa044cf3ee9a79b57a6fbfb59039c3e9c4f38a57ecb76238bf0dec6",
518518
]);
519+
expect(tags.tags).not.contain("sha256:a8a29b609fa044cf3ee9a79b57a6fbfb59039c3e9c4f38a57ecb76238bf0dec6");
519520

520521
const repositoryBuildUp: string[] = [];
521522
let currentPath = "/v2/_catalog?n=1";
@@ -557,8 +558,8 @@ describe("push and catalog", () => {
557558
"hello",
558559
"hello-2",
559560
"latest",
560-
"sha256:a70525d2dd357c6ece8d9e0a5a232e34ca3bbceaa1584d8929cdbbfc81238210",
561561
]);
562+
expect(tags.tags).not.contain("sha256:a70525d2dd357c6ece8d9e0a5a232e34ca3bbceaa1584d8929cdbbfc81238210");
562563

563564
const repositoryBuildUp: string[] = [];
564565
let currentPath = "/v2/_catalog?n=1";

0 commit comments

Comments
 (0)