fresh auth token for each deploy
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
type Repository,
|
||||
type Tag,
|
||||
RepositoryNotFoundException,
|
||||
GetAuthorizationTokenCommand,
|
||||
} from "@aws-sdk/client-ecr";
|
||||
import { tryCatch } from "@trigger.dev/core";
|
||||
import { logger } from "~/services/logger.server";
|
||||
@@ -58,7 +59,7 @@ export async function getDeploymentImageRef({
|
||||
};
|
||||
}
|
||||
|
||||
function isEcrRegistry(registryHost: string) {
|
||||
export function isEcrRegistry(registryHost: string) {
|
||||
return registryHost.includes("amazonaws.com");
|
||||
}
|
||||
|
||||
@@ -196,3 +197,39 @@ async function ensureEcrRepositoryExists({
|
||||
|
||||
return newRepo;
|
||||
}
|
||||
|
||||
export async function getEcrAuthToken({
|
||||
registryHost,
|
||||
registryId,
|
||||
}: {
|
||||
registryHost: string;
|
||||
registryId?: string;
|
||||
}): Promise<{ username: string; password: string }> {
|
||||
const region = getEcrRegion(registryHost);
|
||||
if (!region) {
|
||||
logger.error("Invalid ECR registry host", { registryHost });
|
||||
throw new Error("Invalid ECR registry host");
|
||||
}
|
||||
|
||||
const ecr = new ECRClient({ region });
|
||||
const response = await ecr.send(
|
||||
new GetAuthorizationTokenCommand({
|
||||
registryIds: registryId ? [registryId] : undefined,
|
||||
})
|
||||
);
|
||||
|
||||
if (!response.authorizationData) {
|
||||
throw new Error("Failed to get ECR authorization token");
|
||||
}
|
||||
|
||||
const authData = response.authorizationData[0];
|
||||
|
||||
if (!authData.authorizationToken) {
|
||||
throw new Error("No authorization token returned from ECR");
|
||||
}
|
||||
|
||||
const authToken = Buffer.from(authData.authorizationToken, "base64").toString();
|
||||
const [username, password] = authToken.split(":");
|
||||
|
||||
return { username, password };
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import { env } from "~/env.server";
|
||||
import { depot as execDepot } from "@depot/cli";
|
||||
import { FinalizeDeploymentService } from "./finalizeDeployment.server";
|
||||
import { remoteBuildsEnabled } from "../remoteImageBuilder.server";
|
||||
import { getEcrAuthToken, isEcrRegistry } from "../getDeploymentImageRef.server";
|
||||
import { tryCatch } from "@trigger.dev/core";
|
||||
|
||||
export class FinalizeDeploymentV2Service extends BaseService {
|
||||
public async call(
|
||||
@@ -172,11 +174,27 @@ async function executePushToRegistry(
|
||||
{ depot, registry, deployment }: ExecutePushToRegistryOptions,
|
||||
writer?: WritableStreamDefaultWriter
|
||||
): Promise<ExecutePushResult> {
|
||||
// Step 1: We need to "login" to the digital ocean registry
|
||||
const configDir = await ensureLoggedIntoDockerRegistry(registry.host, {
|
||||
username: registry.username,
|
||||
password: registry.password,
|
||||
});
|
||||
// Step 1: We need to "login" to the registry
|
||||
const [loginError, configDir] = await tryCatch(
|
||||
ensureLoggedIntoDockerRegistry(registry.host, {
|
||||
username: registry.username,
|
||||
password: registry.password,
|
||||
})
|
||||
);
|
||||
|
||||
if (loginError) {
|
||||
logger.error("Failed to login to registry", {
|
||||
deployment,
|
||||
registryHost: registry.host,
|
||||
error: loginError.message,
|
||||
});
|
||||
|
||||
return {
|
||||
ok: false as const,
|
||||
error: "Failed to login to registry",
|
||||
logs: "",
|
||||
};
|
||||
}
|
||||
|
||||
const imageTag = deployment.imageReference;
|
||||
|
||||
@@ -244,12 +262,18 @@ async function executePushToRegistry(
|
||||
|
||||
async function ensureLoggedIntoDockerRegistry(
|
||||
registryHost: string,
|
||||
auth: { username: string; password: string }
|
||||
auth: { username: string; password: string } | undefined = undefined
|
||||
) {
|
||||
const tmpDir = await createTempDir();
|
||||
// Read the current docker config
|
||||
const dockerConfigPath = join(tmpDir, "config.json");
|
||||
|
||||
// If this is an ECR registry, get fresh credentials
|
||||
if (isEcrRegistry(registryHost)) {
|
||||
auth = await getEcrAuthToken({ registryHost, registryId: env.DEPLOY_REGISTRY_ID });
|
||||
} else if (!auth) {
|
||||
throw new Error("Authentication required for non-ECR registry");
|
||||
}
|
||||
|
||||
await writeJSONFile(dockerConfigPath, {
|
||||
auths: {
|
||||
[registryHost]: {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { getDeploymentImageRef, getEcrRegion } from "../app/v3/getDeploymentImageRef.server";
|
||||
import {
|
||||
getDeploymentImageRef,
|
||||
getEcrAuthToken,
|
||||
getEcrRegion,
|
||||
} from "../app/v3/getDeploymentImageRef.server";
|
||||
import { ECRClient, DeleteRepositoryCommand } from "@aws-sdk/client-ecr";
|
||||
|
||||
describe.skipIf(process.env.RUN_REGISTRY_TESTS !== "1")("getDeploymentImageRef", () => {
|
||||
@@ -101,3 +105,35 @@ describe.skipIf(process.env.RUN_REGISTRY_TESTS !== "1")("getDeploymentImageRef",
|
||||
).rejects.toThrow("Invalid ECR registry host: invalid.ecr.amazonaws.com");
|
||||
});
|
||||
});
|
||||
|
||||
describe.skipIf(process.env.RUN_REGISTRY_AUTH_TESTS !== "1")("getEcrAuthToken", () => {
|
||||
const registryId = process.env.DEPLOY_REGISTRY_ID;
|
||||
const testHost = "123456789012.dkr.ecr.us-east-1.amazonaws.com";
|
||||
|
||||
it("should return valid ECR credentials", async () => {
|
||||
const auth = await getEcrAuthToken({
|
||||
registryHost: testHost,
|
||||
registryId,
|
||||
});
|
||||
|
||||
// Check the structure and basic validation of the returned credentials
|
||||
expect(auth).toHaveProperty("username");
|
||||
expect(auth).toHaveProperty("password");
|
||||
expect(auth.username).toBe("AWS");
|
||||
expect(typeof auth.password).toBe("string");
|
||||
expect(auth.password.length).toBeGreaterThan(0);
|
||||
|
||||
// Verify the token format (should be a base64-encoded string)
|
||||
const base64Regex = /^[A-Za-z0-9+/=]+$/;
|
||||
expect(base64Regex.test(auth.password)).toBe(true);
|
||||
});
|
||||
|
||||
it("should throw error for invalid region", async () => {
|
||||
await expect(
|
||||
getEcrAuthToken({
|
||||
registryHost: "invalid.ecr.amazonaws.com",
|
||||
registryId,
|
||||
})
|
||||
).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user