Skip to content

Commit

Permalink
Fixed image sustitution resulting in failed authentication with the c…
Browse files Browse the repository at this point in the history
…ustom registry. Now the domain part is properly separated from the path part of the image substitution prefix
  • Loading branch information
ilia-beliaev-miro committed Apr 4, 2024
1 parent a802d93 commit 177c7e6
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 2 deletions.
122 changes: 122 additions & 0 deletions packages/testcontainers/src/container-runtime/image-name.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ describe("ContainerImage", () => {
try {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = customRegistry;
const imageName = new ImageName(undefined, "image", "tag");
expect(imageName.registry).toBe("custom.com");
expect(imageName.image).toBe("registry/image");
expect(imageName.tag).toBe("tag");
expect(imageName.string).toBe("custom.com/registry/image:tag");
} finally {
if (oldEnvValue === undefined) {
Expand Down Expand Up @@ -159,4 +162,123 @@ describe("ContainerImage", () => {
expect(imageName.tag).toBe("1");
});
});

describe.each([
{ customRegistry: "custom.com/registry", expectedRegistry: "custom.com", expectedImagePrefix: "registry/" },
{ customRegistry: "custom.com/registry/", expectedRegistry: "custom.com", expectedImagePrefix: "registry/" },
{ customRegistry: "custom.com", expectedRegistry: "custom.com", expectedImagePrefix: "" },
{
customRegistry: "custom.com/registry/with/slashes",
expectedRegistry: "custom.com",
expectedImagePrefix: "registry/with/slashes/",
},
])(
"fromString with TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX set to $customRegistry",
({ customRegistry, expectedRegistry, expectedImagePrefix }) => {
let oldEnvValue: string | undefined;
beforeEach(() => {
oldEnvValue = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = customRegistry;
});

afterEach(() => {
if (oldEnvValue === undefined) {
delete process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;
} else {
process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX = oldEnvValue;
}
});

it("should work", () => {
const imageName = ImageName.fromString("image:latest");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}image`);
expect(imageName.tag).toBe("latest");
});

it("should work without tag", () => {
const imageName = ImageName.fromString("image");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}image`);
expect(imageName.tag).toBe("latest");
});

it("should work with registry", () => {
const imageName = ImageName.fromString("domain.com/image:latest");

expect(imageName.registry).toBe("domain.com");
expect(imageName.image).toBe("image");
expect(imageName.tag).toBe("latest");
});

it("should work with registry with port", () => {
const imageName = ImageName.fromString("domain.com:5000/image:latest");

expect(imageName.registry).toBe("domain.com:5000");
expect(imageName.image).toBe("image");
expect(imageName.tag).toBe("latest");
});

it("should work with registry without tag", () => {
const imageName = ImageName.fromString("domain.com/image");

expect(imageName.registry).toBe("domain.com");
expect(imageName.image).toBe("image");
expect(imageName.tag).toBe("latest");
});

it("should work with nested image", () => {
const imageName = ImageName.fromString("parent/child:latest");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}parent/child`);
expect(imageName.tag).toBe("latest");
});

it("should work with registry and nested image", () => {
const imageName = ImageName.fromString("domain.com/parent/child:latest");

expect(imageName.registry).toBe("domain.com");
expect(imageName.image).toBe("parent/child");
expect(imageName.tag).toBe("latest");
});

it("should work with tag being a hash", () => {
const imageName = ImageName.fromString("image@sha256:1234abcd1234abcd1234abcd1234abcd");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(`${expectedImagePrefix}image`);
expect(imageName.tag).toBe("sha256:1234abcd1234abcd1234abcd1234abcd");
});

it("should work with image being an image ID", () => {
const imageName = ImageName.fromString("aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(
`${expectedImagePrefix}aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f`
);
expect(imageName.tag).toBe("latest");
});

it("should work with image being an image ID and an explicit tag", () => {
// Note: Such an ID will not be accepted by docker:
//
// > "invalid repository name [...], cannot specify 64-byte hexadecimal strings"
//
// However, parsing it this way is probably least surprising.
const imageName = ImageName.fromString("aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f:1");

expect(imageName.registry).toEqual(expectedRegistry);
expect(imageName.image).toEqual(
`${expectedImagePrefix}aa285b773a2c042056883845aea893a743d358a5d40f61734fa228fde93dae6f`
);
expect(imageName.tag).toBe("1");
});

// Add more tests here for different scenarios with prefix
}
);
});
18 changes: 16 additions & 2 deletions packages/testcontainers/src/container-runtime/image-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,22 @@ export class ImageName {
public readonly tag: string
) {
if (!this.registry && process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX) {
this.registry = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX.replace(/\/$/, "");
log.info(`Applying changes to image ${image} with tag ${tag}: added registry ${this.registry}`);
const prefix = process.env.TESTCONTAINERS_HUB_IMAGE_NAME_PREFIX;

// Parse the registry. If it's undefined - then the whole prefix is a registry.
const registry = ImageName.getRegistry(prefix);
this.registry = registry ?? prefix;

// If the registry is defined, then the imagePrefix is the rest of the prefix.
const imagePrefix = registry ? prefix.substring(prefix.indexOf("/") + 1).replace(/\/?$/, "/") : "";
const originalImage = this.image;
this.image = `${imagePrefix}${this.image}`;

let message = `Applying changes to image ${originalImage} with tag ${tag}: added registry ${this.registry}`;
if (this.image !== originalImage) {
message += ` and changed image to ${this.image}`;
}
log.info(message);
}
if (this.registry) {
if (this.tag.startsWith("sha256:")) {
Expand Down

0 comments on commit 177c7e6

Please sign in to comment.