feat: release 2.7.0-rc2
This commit is contained in:
+113
-14
@@ -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")}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user