feat: release 2.7.0-rc2

This commit is contained in:
2026-10-06 15:31:51 +00:00 Unverified
parent cd9fb512cd
commit c8de9ddcba
42 changed files with 6127 additions and 593 deletions
+113 -14
View File
@@ -6,6 +6,16 @@ import {
} from "../../server/registry";
describe("OCI registry digest resolution", () => {
const validManifest = JSON.stringify({
schemaVersion: 2,
mediaType: "application/vnd.oci.image.manifest.v1+json",
config: {
mediaType: "application/vnd.oci.image.config.v1+json",
digest: `sha256:${"a".repeat(64)}`,
size: 1,
},
layers: [],
});
test("parses tags, ports, defaults, and pinned references", () => {
expect(parseImageReference("localhost:5000/team/image:v1")).toMatchObject({
registry: "localhost:5000",
@@ -33,7 +43,9 @@ describe("OCI registry digest resolution", () => {
"_build",
"a".repeat(128),
]) {
expect(parseImageReference(`localhost:5000/team/my_image:${tag}`)).toEqual({
expect(
parseImageReference(`localhost:5000/team/my_image:${tag}`),
).toEqual({
registry: "localhost:5000",
repository: "team/my_image",
reference: tag,
@@ -41,7 +53,9 @@ describe("OCI registry digest resolution", () => {
}
const digest = `sha256:${"a".repeat(64)}` as const;
expect(
parseImageReference(`registry.example.com/team/my-image:Release_1@${digest}`),
parseImageReference(
`registry.example.com/team/my-image:Release_1@${digest}`,
),
).toEqual({
registry: "registry.example.com",
repository: "team/my-image",
@@ -49,7 +63,8 @@ describe("OCI registry digest resolution", () => {
digest,
});
expect(
parseImageReference(`registry.example.com/team/my-image@${digest}`).digest,
parseImageReference(`registry.example.com/team/my-image@${digest}`)
.digest,
).toBe(digest);
});
@@ -79,7 +94,9 @@ describe("OCI registry digest resolution", () => {
});
test("resolves an anonymous manifest using the advertised digest", async () => {
const expected = `sha256:${"b".repeat(64)}` as const;
const body = validManifest;
const expected =
`sha256:${createHash("sha256").update(body).digest("hex")}` as const;
const calls: Array<{ url: string; authorization: string | null }> = [];
const fetcher = async (
input: string | URL | Request,
@@ -90,7 +107,7 @@ describe("OCI registry digest resolution", () => {
url: String(input),
authorization: headers.get("authorization"),
});
return new Response("manifest", {
return new Response(body, {
headers: { "docker-content-digest": expected },
});
};
@@ -107,13 +124,28 @@ describe("OCI registry digest resolution", () => {
]);
});
test("rejects a valid but incorrect advertised manifest digest", async () => {
const body = validManifest;
const incorrect = `sha256:${"b".repeat(64)}`;
await expect(
resolveRegistryDigest("mismatch.example.com/team/image:v1", {
fetch: async () =>
new Response(body, {
headers: { "docker-content-digest": incorrect },
}),
}),
).rejects.toThrow("does not match Docker-Content-Digest");
});
test("caches successful digest resolutions with deterministic expiry and bounds", async () => {
let now = 0;
let calls = 0;
const body = validManifest;
const advertised = `sha256:${createHash("sha256").update(body).digest("hex")}`;
const fetcher = async () => {
calls += 1;
return new Response("manifest", {
headers: { "docker-content-digest": `sha256:${"d".repeat(64)}` },
return new Response(body, {
headers: { "docker-content-digest": advertised },
});
};
const options = {
@@ -157,8 +189,10 @@ describe("OCI registry digest resolution", () => {
init?: RequestInit,
) => {
authorizedCalls.push(new Headers(init?.headers).get("authorization")!);
return new Response("manifest", {
headers: { "docker-content-digest": `sha256:${"e".repeat(64)}` },
return new Response(validManifest, {
headers: {
"docker-content-digest": `sha256:${createHash("sha256").update(validManifest).digest("hex")}`,
},
});
};
for (const username of ["one", "two"]) {
@@ -171,7 +205,8 @@ describe("OCI registry digest resolution", () => {
});
test("resolves through a trusted internal registry origin", async () => {
const expected = `sha256:${"c".repeat(64)}` as const;
const expected =
`sha256:${createHash("sha256").update(validManifest).digest("hex")}` as const;
let requested = "";
await expect(
resolveRegistryDigest("registry.example.com/team/image:v1", {
@@ -179,8 +214,10 @@ describe("OCI registry digest resolution", () => {
insecure: true,
fetch: async (input) => {
requested = String(input);
return new Response("manifest", {
headers: { "docker-content-digest": expected },
return new Response(validManifest, {
headers: {
"docker-content-digest": `sha256:${createHash("sha256").update(validManifest).digest("hex")}`,
},
});
},
}),
@@ -191,7 +228,8 @@ describe("OCI registry digest resolution", () => {
});
test("follows a standard bearer challenge and hashes a digest-less response", async () => {
const body = '{"schemaVersion":2}';
const body =
'{"schemaVersion":2,"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[]}';
const expected =
`sha256:${createHash("sha256").update(body).digest("hex")}` as const;
const calls: Array<{ url: string; authorization: string | null }> = [];
@@ -250,7 +288,7 @@ describe("OCI registry digest resolution", () => {
).rejects.toThrow("401");
const malformed = async () =>
new Response("body", {
new Response(validManifest, {
headers: { "docker-content-digest": "sha256:bad" },
});
await expect(
@@ -259,4 +297,65 @@ describe("OCI registry digest resolution", () => {
}),
).rejects.toThrow("Invalid SHA-256");
});
test("rejects empty, non-JSON, and malformed manifests with or without digest headers", async () => {
const malformedBodies = [
"",
"sensitive registry response body",
'{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","layers":[]}',
];
for (const [index, body] of malformedBodies.entries()) {
for (const includeDigest of [false, true]) {
const headers = includeDigest
? {
"docker-content-digest": `sha256:${createHash("sha256").update(body).digest("hex")}`,
}
: undefined;
await expect(
resolveRegistryDigest(
`invalid-${index}-${includeDigest}.example/team/image`,
{
cacheTtlMs: 0,
fetch: async () => new Response(body, { headers }),
},
),
).rejects.toThrow("invalid manifest");
}
}
});
test("accepts supported manifest/index media types with generic content type", async () => {
const fixtures = [
validManifest,
JSON.stringify({
schemaVersion: 2,
mediaType: "application/vnd.docker.distribution.manifest.v2+json",
config: {},
layers: [],
}),
JSON.stringify({
schemaVersion: 2,
mediaType: "application/vnd.oci.image.index.v1+json",
manifests: [],
}),
JSON.stringify({
schemaVersion: 2,
mediaType: "application/vnd.docker.distribution.manifest.list.v2+json",
manifests: [],
}),
];
for (const [index, body] of fixtures.entries()) {
await expect(
resolveRegistryDigest(`valid-${index}.example/team/image`, {
cacheTtlMs: 0,
fetch: async () =>
new Response(body, {
headers: { "content-type": "application/octet-stream" },
}),
}),
).resolves.toBe(
`sha256:${createHash("sha256").update(body).digest("hex")}`,
);
}
});
});