From a0ae8f3e3bfbed453f81ec153414333a67f9c006 Mon Sep 17 00:00:00 2001 From: jariy17 Date: Tue, 27 Oct 2026 17:32:43 +0000 Subject: [PATCH 1/2] feat(deploy): accept any region for deployment targets AgentCore region availability changes faster than CLI releases, so the allowlist blocked deploys to newly launched regions until a release caught up. AgentCoreRegionSchema is now z.string() and the default-target region check is gone; a region without AgentCore is rejected by CloudFormation at deploy time. --- src/core/project/manager.test.ts | 16 ------------ src/core/project/manager.tsx | 15 ++--------- src/handlers/project/deploy/index.test.ts | 26 ------------------- src/projectSchemas/aws-targets.test.ts | 18 ++----------- src/projectSchemas/aws-targets.ts | 31 +++-------------------- 5 files changed, 7 insertions(+), 99 deletions(-) diff --git a/src/core/project/manager.test.ts b/src/core/project/manager.test.ts index 61977d57e..e481d148d 100644 --- a/src/core/project/manager.test.ts +++ b/src/core/project/manager.test.ts @@ -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({ diff --git a/src/core/project/manager.tsx b/src/core/project/manager.tsx index 0d143ef48..2564562df 100644 --- a/src/core/project/manager.tsx +++ b/src/core/project/manager.tsx @@ -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, @@ -1789,19 +1788,9 @@ export class FsProjectManager implements ProjectManager { targetsPath: string, region: string, ): Promise { - 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 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( @@ -1816,7 +1805,7 @@ export class FsProjectManager implements ProjectManager { const entry = AwsDeploymentTargetSchema.safeParse({ name: DEFAULT_TARGET_NAME, account, - region: supportedRegion.data, + region, }); if (!entry.success) { throw new MalformedServiceResponseError( diff --git a/src/handlers/project/deploy/index.test.ts b/src/handlers/project/deploy/index.test.ts index d1bed99cc..24ebaec16 100644 --- a/src/handlers/project/deploy/index.test.ts +++ b/src/handlers/project/deploy/index.test.ts @@ -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 () => { @@ -669,20 +657,6 @@ async function messageFrom(command: Promise): Promise { } 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])); diff --git a/src/projectSchemas/aws-targets.test.ts b/src/projectSchemas/aws-targets.test.ts index 71f9e7747..93136c19c 100644 --- a/src/projectSchemas/aws-targets.test.ts +++ b/src/projectSchemas/aws-targets.test.ts @@ -51,22 +51,8 @@ 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("rejects an AWS region where AgentCore is unavailable", () => { - expect(AgentCoreRegionSchema.safeParse("af-south-1").success).toBe(false); + test("accepts a region without AgentCore, leaving CloudFormation to reject it", () => { + expect(AgentCoreRegionSchema.safeParse("ap-northeast-3").success).toBe(true); }); test.each([ diff --git a/src/projectSchemas/aws-targets.ts b/src/projectSchemas/aws-targets.ts index 3f9b6146b..b778aa123 100644 --- a/src/projectSchemas/aws-targets.ts +++ b/src/projectSchemas/aws-targets.ts @@ -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(); /** * The target `agentcore deploy` uses when --target is omitted. Only this target From ff5d215e4c48caaf385249a23cacb1bed41c6a51 Mon Sep 17 00:00:00 2001 From: jariy17 Date: Tue, 27 Oct 2026 17:54:44 +0000 Subject: [PATCH 2/2] fix(deploy): name the region when the default target's account can't be resolved Without a region allowlist, a mistyped or not-enabled region fails at STS and was reported as a credentials problem. The message now names the region and asks the user to check it. AgentCoreRegionSchema also trims whitespace and rejects an empty region so aws-targets.json errors point at the field. --- src/core/project/manager.test.ts | 2 +- src/core/project/manager.tsx | 9 ++++++--- src/projectSchemas/aws-targets.test.ts | 6 ++++++ src/projectSchemas/aws-targets.ts | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/core/project/manager.test.ts b/src/core/project/manager.test.ts index e481d148d..7c81b1c56 100644 --- a/src/core/project/manager.test.ts +++ b/src/core/project/manager.test.ts @@ -2105,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); diff --git a/src/core/project/manager.tsx b/src/core/project/manager.tsx index 2564562df..0772c7f00 100644 --- a/src/core/project/manager.tsx +++ b/src/core/project/manager.tsx @@ -1795,9 +1795,12 @@ export class FsProjectManager implements ProjectManager { 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 }, ); } diff --git a/src/projectSchemas/aws-targets.test.ts b/src/projectSchemas/aws-targets.test.ts index 93136c19c..076e1817c 100644 --- a/src/projectSchemas/aws-targets.test.ts +++ b/src/projectSchemas/aws-targets.test.ts @@ -55,6 +55,12 @@ describe("AWS deployment targets", () => { expect(AgentCoreRegionSchema.safeParse("ap-northeast-3").success).toBe(true); }); + 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([ ["the same name", target], ["a name that differs only by case", { ...target, name: "Default" }], diff --git a/src/projectSchemas/aws-targets.ts b/src/projectSchemas/aws-targets.ts index b778aa123..e3f5532e1 100644 --- a/src/projectSchemas/aws-targets.ts +++ b/src/projectSchemas/aws-targets.ts @@ -3,7 +3,7 @@ import { uniqueBy } from "./zod-util"; // 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(); +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