Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 1 addition & 17 deletions src/core/project/manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2095,22 +2095,6 @@ describe("FsProjectManager.deploy", () => {
expect(await Bun.file(targetsFile(root)).json()).toEqual(targets);
});

test("rejects an unsupported region without calling STS or writing the file", async () => {
const root = await inTempDirectory();
const subject = deployManager();
const project = await projectWithTargets(root, undefined);

const attempt = deploy(subject.manager, project, "default", { region: "af-south-1" });

await expect(attempt).rejects.toThrow(/'af-south-1' is not an AgentCore-supported region/);
await expect(
deploy(subject.manager, project, "default", { region: "af-south-1" }),
).rejects.toThrow(/Supported regions: .*us-east-1.*Re-run with --region/s);
expect(subject.calls).toEqual([]);
expect(subject.accountCalls).toEqual([]);
expect(await Bun.file(targetsFile(root)).exists()).toBe(false);
});

test("reports an actionable error when the account cannot be resolved", async () => {
const root = await inTempDirectory();
const subject = deployManager({
Expand All @@ -2121,7 +2105,7 @@ describe("FsProjectManager.deploy", () => {
await expect(
deploy(subject.manager, project, "default", { region: "us-east-2" }),
).rejects.toThrow(
/the AWS account could not be resolved: The security token included in the request is expired[\s\S]*aws login/,
/the AWS account could not be resolved in region 'us-east-2': The security token included in the request is expired[\s\S]*Check that 'us-east-2' is a region enabled[\s\S]*aws login/,
);
expect(subject.calls).toEqual([]);
expect(await Bun.file(targetsFile(root)).exists()).toBe(false);
Expand Down
24 changes: 8 additions & 16 deletions src/core/project/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ import { CdkBackend, type TransactionSearchEnabler } from "./backends/cdk";
import { resolveAwsAccount } from "./backends/cdk/environment";
import type { ProjectBackend } from "./backends/types";
import {
AgentCoreRegionSchema,
AwsDeploymentTargetSchema,
AwsDeploymentTargetsSchema,
DEFAULT_TARGET_NAME,
Expand Down Expand Up @@ -1789,34 +1788,27 @@ export class FsProjectManager implements ProjectManager {
targetsPath: string,
region: string,
): Promise<AwsDeploymentTarget> {
const supportedRegion = AgentCoreRegionSchema.safeParse(region);
if (!supportedRegion.success) {
throw new InputValidationError(
`Cannot create the default deployment target for project '${project.name}': ` +
`'${region}' is not an AgentCore-supported region.\n` +
`Supported regions: ${AgentCoreRegionSchema.options.join(", ")}.\n` +
`Re-run with --region <region> or set AWS_REGION to one of them.`,
);
}

let account: string;
try {
account = await this.resolveAccount(supportedRegion.data);
account = await this.resolveAccount(region);
} catch (error) {
const cause = AgentCoreCLIError.fromError(error);
throw new InvalidEnvironmentError(
`Cannot create the default deployment target for project '${project.name}' because ` +
`the AWS account could not be resolved: ${cause.message}\n` +
`Sign in with 'aws login' (or set AWS_PROFILE or credential environment variables) ` +
`and re-run 'agentcore deploy'.`,
`the AWS account could not be resolved in region '${region}': ${cause.message}\n` +
// With no region allowlist, a mistyped or not-enabled region surfaces here as an STS
// failure, so the hint names the region before suggesting credentials.
`Check that '${region}' is a region enabled for your account (--region or AWS_REGION), ` +
`and sign in with 'aws login' (or set AWS_PROFILE or credential environment variables), ` +
`then re-run 'agentcore deploy'.`,
{ cause: error },
);
}

const entry = AwsDeploymentTargetSchema.safeParse({
name: DEFAULT_TARGET_NAME,
account,
region: supportedRegion.data,
region,
});
if (!entry.success) {
throw new MalformedServiceResponseError(
Expand Down
26 changes: 0 additions & 26 deletions src/handlers/project/deploy/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,18 +630,6 @@ describe("project deploy handler", () => {
]);
});

test("rejects an unsupported region instead of writing an invalid target", async () => {
const subject = await testDeployCommand({ outputs: {} });
const projectRoot = await inProjectWithTargets(JSON.stringify([]));

const message = await messageFrom(subject.run(["--region", "af-south-1"]));

expect(message).toContain("'af-south-1' is not an AgentCore-supported region");
expect(message).toContain("us-east-1");
expect(subject.calls).toEqual([]);
expect(await Bun.file(join(projectRoot, "agentcore", "aws-targets.json")).text()).toBe("[]");
});

test("explains how to fix unresolvable credentials", async () => {
const subject = await testDeployCommand({ outputs: {} }, [], {
resolveAccount: async () => {
Expand Down Expand Up @@ -669,20 +657,6 @@ async function messageFrom(command: Promise<void>): Promise<string> {
}

describe("project deploy reports which field of aws-targets.json is wrong", () => {
test("names the offending field for an unsupported region", async () => {
const subject = await testDeployCommand({ outputs: {} });
await inProjectWithTargets(
JSON.stringify([{ name: "default", account: "111122223333", region: "us-east-11" }]),
);

const message = await messageFrom(subject.run());

expect(message).toContain("aws-targets.json");
expect(message).toContain("at [0].region");
expect(message).toContain('"us-east-1"');
expect(subject.calls).toEqual([]);
});

test("surfaces the duplicate target name", async () => {
const subject = await testDeployCommand({ outputs: {} });
await inProjectWithTargets(JSON.stringify([DEFAULT_TARGET, DEFAULT_TARGET]));
Expand Down
20 changes: 6 additions & 14 deletions src/projectSchemas/aws-targets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,14 @@ describe("AWS deployment targets", () => {
).toBe(false);
});

test.each([
"ap-south-2",
"ap-southeast-5",
"ap-southeast-7",
"cn-north-1",
"cn-northwest-1",
"eu-south-1",
"eu-south-2",
"us-gov-west-1",
"us-west-1",
])("accepts supported region %s", (region) => {
expect(AgentCoreRegionSchema.safeParse(region).success).toBe(true);
test("accepts a region without AgentCore, leaving CloudFormation to reject it", () => {
expect(AgentCoreRegionSchema.safeParse("ap-northeast-3").success).toBe(true);
});

test("rejects an AWS region where AgentCore is unavailable", () => {
expect(AgentCoreRegionSchema.safeParse("af-south-1").success).toBe(false);
test("trims whitespace and rejects an empty region", () => {
expect(AgentCoreRegionSchema.parse(" us-east-1 ")).toBe("us-east-1");
expect(AgentCoreRegionSchema.safeParse("").success).toBe(false);
expect(AgentCoreRegionSchema.safeParse(" ").success).toBe(false);
});

test.each([
Expand Down
31 changes: 3 additions & 28 deletions src/projectSchemas/aws-targets.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,9 @@
import { z } from "zod";
import { uniqueBy } from "./zod-util";

// Keep in sync with https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-regions.html
// and with the library copy at agentcore-l3-cdk-constructs/src/schema/schemas/aws-targets.ts.
export const AgentCoreRegionSchema = z.enum([
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"ap-south-2",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-5",
"ap-southeast-7",
"ca-central-1",
"cn-north-1",
"cn-northwest-1",
"eu-central-1",
"eu-north-1",
"eu-south-1",
"eu-south-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
"us-gov-west-1",
]);
// Accepts any region: AgentCore availability changes faster than CLI releases, so a
// region without AgentCore is left for CloudFormation to reject at deploy time.
export const AgentCoreRegionSchema = z.string().trim().min(1, "Region must not be empty");

/**
* The target `agentcore deploy` uses when --target is omitted. Only this target
Expand Down
Loading