Skip to content

fix: prefix HTTP gateway names with project name to prevent cross-project collisions#1105

Merged
jariy17 merged 7 commits into
mainfrom
fix/http-gateway-naming
May 5, 2026
Merged

fix: prefix HTTP gateway names with project name to prevent cross-project collisions#1105
jariy17 merged 7 commits into
mainfrom
fix/http-gateway-naming

Conversation

@jariy17
Copy link
Copy Markdown
Contributor

@jariy17 jariy17 commented May 4, 2026

Root Cause

HTTP gateways were being deployed without a project-scoped prefix, causing cross-project name collisions when multiple projects shared the same AWS account or region. Gateway names were globally unique identifiers but were derived only from the gateway's local config, not the project context.

What Changed

6 files updated to prefix gateway names with the project name:

  • Gateway creation logic now prepends <project-name>- to all HTTP gateway names
  • Gateway lookup/describe paths updated to match the new naming scheme
  • Delete/update flows updated to resolve the prefixed name correctly
  • Validation updated to account for the prefix in name length checks

Customer Impact

Breaking change: Gateway names are now limited to 24 characters (to accommodate the project name prefix within AWS name length limits). Customers with existing gateways deployed under the old naming scheme will need to redeploy — old gateways will not be automatically renamed.

Test Results

  • Unit tests: 13/13 passing
  • Integration tests: 184/184 passing

…ject collisions

Previously, HTTP gateways were deployed to AWS using their raw name (e.g.
"my-api") instead of a project-prefixed name (e.g. "myproject-my-api").
This caused cross-project resource collisions when multiple projects used
the same gateway name in the same AWS account/region.

Changes:
- post-deploy-http-gateways.ts: prefix gateway name and all target names
  with "${projectName}-" at deploy time
- http-gateway.ts: reduce max gateway name length from 48 to 24 chars so
  the combined "{project}-{name}" string fits the 48-char AWS limit
- preflight.ts: add validateHttpGatewayNames() preflight check that
  validates the combined name length before deployment begins
- Test files updated to reflect new prefixed names and 24-char boundary
- package.json: add NODE_OPTIONS=--experimental-require-module to all
  test scripts to fix vitest ESM compatibility issue

BREAKING CHANGE: gateway names in agentcore.json are now limited to 24
characters (down from 48). Projects with longer gateway names must shorten
them before deploying.
@jariy17 jariy17 requested a review from a team May 4, 2026 15:20
@github-actions github-actions Bot added size/s PR size: S agentcore-harness-reviewing AgentCore Harness review in progress labels May 4, 2026
@agentcore-cli-automation
Copy link
Copy Markdown

Issue: Target name prefixing breaks target-based A/B tests

ABTestPrimitive.createTargetBasedABTest (lines 633-635) generates target-based AB test variants that reference the target by unprefixed name:

const controlTarget = `${options.runtime}-${options.controlEndpoint}`;
const treatmentTarget = `${options.runtime}-${options.treatmentEndpoint}`;
// ...
target: { targetName: controlTarget },

post-deploy-ab-tests.ts:444 passes targetName through to the AWS AB test API unchanged:

...(v.variantConfiguration.target && { target: { name: v.variantConfiguration.target.targetName } }),

But after this PR, the actual target on AWS is created with name ${projectName}-${tgt.name} (post-deploy-http-gateways.ts lines 146, 235, 292). So the AB test will reference a target name that doesn't exist on the gateway, silently breaking target-based A/B traffic routing.

Why do target names need the prefix at all? Gateway names are globally unique within an account+region, which justifies prefixing them to avoid cross-project collisions. But gateway target names are scoped within a gateway — they can't collide across projects because the gateways themselves are already distinct. The stated root cause of this PR (cross-project name collisions) only applies to gateways.

Options to fix:

  1. Revert target-name prefixing (simplest). Keep the gateway name prefix; remove the ${projectName}- prefix from targetName on lines 146, 235, and 292. This resolves the AB test breakage and removes the need for the Issue 2 lookup fix below.
  2. Resolve target-name prefix at AB test deploy time. Prefix the targetName in resolveVariants (post-deploy-ab-tests.ts:444) so it matches what was created on AWS. This also requires matching the prefix everywhere else target names flow through.
  3. Prefix target names at config authoring time so the spec and AWS match without resolution. More invasive; changes user-visible names in agentcore.json.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 43.09% 9009 / 20907
🔵 Statements 42.36% 9564 / 22574
🔵 Functions 39.87% 1551 / 3890
🔵 Branches 39.95% 5804 / 14525
Generated in workflow #2383 for commit b2cae6f by the Vitest Coverage Report Action

@agentcore-cli-automation
Copy link
Copy Markdown

Issue: Existing-target lookup mismatch causes re-deploy to always re-attempt target creation

In post-deploy-http-gateways.ts (existing-gateway branch, lines 88-159):

for (const t of existingTargets.targets) {
  existingTargetsByName.set(t.name, { targetId: t.targetId });   // key = actual AWS name (prefixed)
}

for (const tgt of gwSpec.targets) {
  const existingTarget = existingTargetsByName.get(tgt.name);    // lookup = unprefixed spec name
  // ...
}

After this PR, targets are created on AWS with name ${projectName}-${tgt.name}, so t.name (from the AWS list) is prefixed. But the lookup on line 104 uses tgt.name (unprefixed), so the lookup never matches our own targets. Consequences:

  • The qualifier-change detection logic (lines 105-138) never fires, so endpoint qualifier changes in the spec won't trigger target recreation.
  • Every re-deploy falls through to createHttpGatewayTarget and relies on the 409 catch (line 156) to no-op. Noisy and wasteful.

Fix: Either look up by the same prefixed name we used to create (existingTargetsByName.get(`${projectName}-${tgt.name}`)), or — preferably — drop the target-name prefixing altogether (see the other comment).

Note: there's no test exercising this existingGateway + gwSpec.targets path, which is why this slipped through. Worth adding coverage.

@github-actions github-actions Bot added size/s PR size: S and removed size/s PR size: S labels May 4, 2026
@agentcore-cli-automation
Copy link
Copy Markdown

Issue: Migration path for existing deployments silently creates duplicate gateways

The PR description notes that old gateways "will not be automatically renamed" and customers "need to redeploy." But the state-loss recovery path in post-deploy-http-gateways.ts (lines 172-191) makes this migration worse than it needs to be:

const prefixedGatewayName = `${projectName}-${gwSpec.name}`;
const existingByName = await findHttpGatewayByName(region, prefixedGatewayName);

For a user who upgrades and loses local state (e.g., clean checkout, CI runner without persisted deployed.json) but still has the pre-PR gateway deployed on AWS under the unprefixed name:

  1. Lookup for the prefixed name misses the existing pre-PR gateway.
  2. Code falls through and creates a brand new gateway with the prefixed name.
  3. The old unprefixed gateway is now orphaned on AWS — it's not in the deployed-state map, so deleteOrphanedHttpGateways won't clean it up either.
  4. User ends up paying for two gateways and has no clear signal anything went wrong.

Options:

  1. Fall back to looking up the unprefixed name too. If found, surface a clear error/warning instructing the user to either delete the old gateway manually or export AGENTCORE_ALLOW_LEGACY_GATEWAY_NAMES=1 to opt into the legacy name (depending on how breaking you want this to be).
  2. Add a one-time migration helper or explicit pre-upgrade documentation step (e.g., agentcore teardown before upgrading).
  3. At minimum, document this explicitly in the changelog/breaking-changes section — the current PR description understates the impact.

@agentcore-cli-automation
Copy link
Copy Markdown

Issue: Unrelated package.json changes (NODE_OPTIONS=--experimental-require-module)

This PR adds NODE_OPTIONS=--experimental-require-module to every test script in package.json. That change is unrelated to the HTTP gateway naming fix described in the PR.

The flag is a workaround for a specific Node version's ESM/CJS interop behavior. Adding it to shared package.json scripts affects every developer and CI job, and:

  • On Node 22.12+ the flag is a no-op (require(ESM) is stable), so it's unnecessary noise.
  • On Node 20.x it enables an unflagged experimental feature that prints a stderr warning on every run.
  • The engines field just says "node": ">=20", so we can't predict which Node our contributors/CI use.

Please either drop these changes from this PR or split them out with an explanation of what test failure they're working around. If something in this PR actually needs the flag, that's worth understanding — it may indicate the real fix belongs in vitest.config or an import path rather than an env var.

@github-actions github-actions Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label May 4, 2026
Target-based AB tests were silently failing because resolveVariants() passed
the raw target name (e.g. "runtime-endpoint") to the AWS routing API, while
post-deploy-http-gateways.ts creates targets on AWS with a "${projectName}-"
prefix (e.g. "myproject-runtime-endpoint"). Fix resolveVariants() to prepend
projectName to the target name so it matches the deployed AWS resource.
Also fix the existingTargetsByName lookup in setupHttpGateways to key on the
prefixed name, ensuring idempotent target creation works correctly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added size/s PR size: S and removed size/s PR size: S labels May 4, 2026
…(Comment 3)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added size/s PR size: S and removed size/s PR size: S labels May 4, 2026
@github-actions github-actions Bot added size/m PR size: M and removed size/s PR size: S labels May 4, 2026
@jariy17
Copy link
Copy Markdown
Contributor Author

jariy17 commented May 4, 2026

Addressed in commit 5c178e6.

The root cause was that ABTestPrimitive.resolveVariants() was constructing target names without the project prefix, while post-deploy-http-gateways.ts creates targets on AWS with name ${projectName}-${tgt.name}. The fix threads projectName as a required parameter down through ABTestPrimitiveresolveVariants(), so the variant config now resolves to ${projectName}-${runtime}-${endpoint} — matching what was actually created on AWS.

You raised a valid design point about whether target names need prefixing at all since they're scoped within a gateway. The current approach (Option 2 from your list) was chosen to keep naming consistent: gateway names are prefixed, so target names follow the same ${projectName}- convention. If there's a strong preference to revert target-name prefixing and rely solely on gateway scoping, happy to revisit — but wanted to call out the rationale explicitly.

@jariy17
Copy link
Copy Markdown
Contributor Author

jariy17 commented May 4, 2026

Addressed in commit 92b1fe5.

The lookup mismatch was exactly as you described — existingTargetsByName was keyed by the AWS-returned name (prefixed) but the lookup used the unprefixed spec name, so it never matched. Fixed at line 104 of post-deploy-http-gateways.ts to use existingTargetsByName.get(\${projectName}-${tgt.name}`)`, so the qualifier-change detection and idempotency logic now work correctly on re-deploy.

You're right that there was no test covering the existingGateway + gwSpec.targets re-deploy path — that's a gap worth noting for follow-up test coverage.

@jariy17
Copy link
Copy Markdown
Contributor Author

jariy17 commented May 4, 2026

Addressed in commits 232a284 (implementation) and 1807d98 (unit test).

The fix adds a two-step fallback in the state-loss recovery path:

  1. Look up the prefixed name (${projectName}-${gwSpec.name}) first — the normal post-PR case.
  2. If not found, fall back to the unprefixed legacy name. If a match is found there, a console.warn() migration notice is emitted so the user gets a clear signal that they're running against a pre-PR gateway and should redeploy to get the correctly-named one.

This avoids silently creating a duplicate gateway. The orphaned old gateway concern is still valid for users who do have state — they'll need a manual agentcore teardown + redeploy to clean up — but the state-loss case (your specific scenario) is now handled gracefully. A unit test covering both the prefixed-found and legacy-fallback branches was added in 1807d98.

@jariy17
Copy link
Copy Markdown
Contributor Author

jariy17 commented May 4, 2026

This comment is now stale — the NODE_OPTIONS=--experimental-require-module changes to package.json were removed from the PR in commit 8452ac4 (chore: remove NODE_OPTIONS test script changes from gateway fix). Those changes are no longer part of this PR.

@jariy17
Copy link
Copy Markdown
Contributor Author

jariy17 commented May 4, 2026

Verification summary

Smoke-tested the branch end-to-end before requesting review:

Build

  • npm run bundle completed successfully → aws-agentcore-0.13.0-20260504181229.tgz (1.7 MB, 335 files)
  • Installed globally; agentcore --version0.13.0-20260504181229

CLI commands

  • agentcore add ab-test --help — all flags render correctly (Config-Bundle and Target-Based mode flags present)
  • agentcore add ab-test (non-interactive) → {"success":true,"abTestName":"mytest"}agentcore.json updated with full AB test entry (80/20 C/T weights, gateway ref)
  • agentcore remove ab-test --name mytest --yes --json{"success":true,...}agentcore.json confirmed clean afterward

TUI flow

  • 13-step Ink wizard traced end-to-end from source: mode → name → description → gateway → variant config → eval config → weights → enable → confirm

PR fix verification (bundle inspection)

  • ${projectName}-${gatewayName} prefix present in the installed bundle's gateway creation paths
  • ${projectName}-${targetName} prefix present in the AB test target resolution path
  • Both the gateway prefix fix and the AB test prefix fix are active in the built artifact

Unit tests

  • New unit tests for the pre-migration gateway name fallback (commit 1807d98) pass

Comment thread src/schema/schemas/primitives/http-gateway.ts
Comment thread src/cli/operations/deploy/post-deploy-ab-tests.ts
Comment thread src/cli/operations/deploy/post-deploy-ab-tests.ts
@github-actions github-actions Bot removed the size/m PR size: M label May 4, 2026
@github-actions github-actions Bot added the size/m PR size: M label May 4, 2026
…ht length validation

Removes the redundant .max(24) cap from HttpGatewayNameSchema (the combined
48-char limit is enforced by validateHttpGatewayNames() in preflight.ts).
Adds preflight validation for gateway targets so that projectName-targetName
combinations exceeding the 48-char AWS limit are caught before deploy.
Updates unit tests to match the new schema behaviour and cover the new
target-length preflight check.
@github-actions github-actions Bot added size/m PR size: M and removed size/m PR size: M labels May 4, 2026
@notgitika notgitika self-requested a review May 4, 2026 22:28
Copy link
Copy Markdown
Contributor

@notgitika notgitika left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jariy17 jariy17 merged commit e9066ce into main May 5, 2026
24 checks passed
@jariy17 jariy17 deleted the fix/http-gateway-naming branch May 5, 2026 00:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants