Skip to content

fix(schema): relax requestHeaderAllowlist validation to match runtime contract#1155

Closed
aidandaly24 wants to merge 1 commit into
mainfrom
fix/1151-93d27c63
Closed

fix(schema): relax requestHeaderAllowlist validation to match runtime contract#1155
aidandaly24 wants to merge 1 commit into
mainfrom
fix/1151-93d27c63

Conversation

@aidandaly24

Copy link
Copy Markdown
Contributor

Description

Relaxes the client-side validation for requestHeaderAllowlist to match the
expanded contract described in the AgentCore Runtime docs:
https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-header-allowlist.html

Previously, the CLI/CDK Zod schema rejected any header that wasn't either
Authorization or prefixed with X-Amzn-Bedrock-AgentCore-Runtime-Custom-.
The runtime now accepts any non-restricted HTTP header name (alphanumerics,
hyphens, underscores), so the strict prefix check produced false negatives for
valid headers like X-Custom-Signature, X-Api-Key, etc.

What changed

src/schema/schemas/agent-env.ts (mirrored in the CDK repo)

  • Replaced the strict .refine() rule with a superRefine() that rejects:
    • names that don't match /^[A-Za-z0-9_-]+$/ (now allows underscores),
    • the documented restricted-headers list (Cookie, Host, Accept,
      Content-Type, etc.),
    • x-amz-* (reserved for SigV4),
    • x-amzn-* other than the AgentCore custom prefix.
  • Authorization and any header starting with the AgentCore custom prefix
    remain explicitly allowed (back-compat).
  • Added a top-level superRefine() that rejects case-insensitive duplicates.
  • Exposed HEADER_NAME_REGEX, RESTRICTED_HEADER_NAMES, and a
    getHeaderRejectionReason(name) helper for shared reuse.

src/cli/commands/shared/header-utils.ts

  • normalizeHeaderName no longer auto-prepends the AgentCore custom prefix to
    arbitrary names. It only canonicalizes Authorization casing and the legacy
    AgentCore custom prefix casing.
  • validateHeaderAllowlist now delegates to getHeaderRejectionReason so the
    CLI/TUI surface the same rules as the schema (restricted-list, reserved
    prefixes, duplicate detection).

Tests (src/cli/commands/shared/__tests__/header-utils.test.ts)

  • Updated assertions for the new semantics (MyHeaderMyHeader,
    not auto-prefixed).
  • Added cases for: X-Custom-Signature, X-Api-Key, underscore-containing
    names, restricted headers (Cookie, Host, Accept, Content-Type,
    User-Agent, Connection), x-amz-*, x-amzn-* non-allowlist,
    case-insensitive duplicates. 38 tests pass (was 27).

Help text & docs

  • src/cli/primitives/AgentPrimitive.tsx — updated --request-header-allowlist
    description.
  • src/cli/tui/screens/agent/AddAgentScreen.tsx,
    src/cli/tui/screens/generate/GenerateWizardUI.tsx — updated dim-text
    guidance under the allowlist prompt.
  • docs/configuration.md — refreshed requestHeaderAllowlist row with a
    link to the AWS docs page.

Companion CDK change

The matching schema change for the L3 constructs lives in
aws/agentcore-l3-cdk-constructs on branch fix/1151-93d27c63
(commit a62396b) and must merge alongside this PR to keep the duplicated
src/schema/schemas/agent-env.ts in sync.

Related Issue

Closes #1151

Documentation PR

N/A — the AWS Bedrock AgentCore developer guide already documents the
relaxed contract this PR aligns with.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Note: while this is technically more permissive validation (not a contract
break), config files that previously relied on the auto-prefix behavior of
the TUI/--request-header-allowlist flag will now record the user-typed
name verbatim instead of X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader.
Existing fully-qualified names continue to round-trip identically.

Testing

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
    • Targeted vitest runs against header-utils.test.ts (38/38),
      agent-env.test.ts (85/85), schema-mapper.test.ts,
      import-runtime-handler.test.ts, and agentcore-control.test.ts
      (101/101 across the latter three) all pass. Full suite to be exercised
      by CI.
  • I ran npm run typecheck — clean in both repos.
  • I ran npm run lint — pre-commit lint-staged hook ran clean on every
    modified file.
  • If I modified src/assets/, I ran npm run test:update-snapshots and
    committed the updated snapshots — N/A, no snapshot fixtures touched.

New test coverage

  • Positive: X-Custom-Signature, X-Api-Key, Some_Header_With_Underscores,
    case-insensitive Authorization, mixed allow-listed entries.
  • Negative: each restricted-header category (Cookie/Host/Accept/Content-Type/
    User-Agent/Connection), case-insensitive restricted check, X-Amz-Date,
    X-Amzn-Foo, duplicate detection (MyHeader, myheader).

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my
    feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the
    feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published — companion CDK
    branch ready for review/merge alongside this PR.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the
terms of your choice.

@aidandaly24 aidandaly24 requested a review from a team May 7, 2026 17:00
@github-actions github-actions Bot added size/m PR size: M agentcore-harness-reviewing AgentCore Harness review in progress labels May 7, 2026
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 43.25% 9063 / 20953
🔵 Statements 42.53% 9623 / 22625
🔵 Functions 40.03% 1560 / 3897
🔵 Branches 40.06% 5830 / 14551
Generated in workflow #2593 for commit 0c95cac by the Vitest Coverage Report Action

@agentcore-cli-automation agentcore-cli-automation left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for putting together the docs/tests for this — the schema relaxation clearly matches the AgentCore Runtime contract now.

I flagged a few things I think should be resolved before merging, all around cross-cutting consequences of removing the auto-prefix behavior from normalizeHeaderName. Nothing wrong with the schema logic itself; the concerns are about (a) the L3 CDK construct still rejecting the new headers at synth/deploy time, (b) an unannounced behavior change for agentcore invoke -H / agentcore dev -H, and (c) missing schema-level tests. Details inline.

}
seen.add(k);
});
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Deploy-time schema drift with @aws/agentcore-cdk.

The vended CDK project (src/assets/cdk/package.json) depends on @aws/agentcore-cdk at ^0.1.0-alpha.19, which re-validates the spec at synth time using its own copy of RequestHeaderAllowlistSchema. Until the companion change in aws/agentcore-l3-cdk-constructs is merged and a new version is published to npm, any new-style allowlist entry (X-Api-Key, X-Custom-Signature, Some_Header_With_Underscores, …) that passes CLI validation will fail at cdk synth / agentcore deploy with the old strict-prefix error — a confusing regression for end users.

Possible resolutions (pick one):

  1. Hold this PR until the CDK companion is merged and a version bump is published, then bump @aws/agentcore-cdk in src/assets/cdk/package.json to a version guaranteed to include the relaxation.
  2. Pin @aws/agentcore-cdk to an exact pre-release that contains the fix (avoids a cached caret range pulling a stale version).
  3. If the duplicated src/schema/schemas/agent-env.ts here is treated as the authoritative runtime validator pre-CDK, add an upfront check that the resolved @aws/agentcore-cdk version supports the relaxed schema so users get a clear error rather than a deep synth-time Zod stack.

At minimum the PR description should call out the published-version dependency, and CI in this repo should be exercising the e2e path against a CDK tarball that already has the fix (e.g. via npm run bundle) so this doesn't silently regress after merge.

return `${HEADER_ALLOWLIST_PREFIX}${input.slice(HEADER_ALLOWLIST_PREFIX.length)}`;
}
return `${HEADER_ALLOWLIST_PREFIX}${input}`;
return input;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Breaking behavior change for agentcore invoke -H and agentcore dev -H.

Because parseHeaderFlag (→ normalizeHeaderName) is on the hot path for the -H / --header flags in both src/cli/commands/invoke/command.tsx and src/cli/commands/dev/command.tsx, and the resulting headers are forwarded as literal HTTP headers to the runtime (see invoke/action.ts lines 161/245/325/369/426/460), this change alters what gets sent on the wire. Previously:

agentcore invoke -H "MyHeader: val"

sent X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader: val. After this PR it sends MyHeader: val verbatim. Users with an existing deployed runtime whose allowlist still contains X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader will silently stop receiving the header at the agent — the invoke will appear to succeed but the agent won't see the value. This is a behavior break that is distinct from the schema relaxation and isn't called out in the PR description or CHANGELOG.md.

Options to address:

  1. Preserve auto-prefix only in parseHeaderFlag (the invoke/dev CLI path) and remove it only from the allowlist-normalization path. The two paths don't actually need to share normalization — one configures the runtime, the other talks to it.
  2. Keep this change but add an explicit "Breaking changes" section to the PR body + CHANGELOG.md, and ideally have parseHeaderFlag emit a one-time warning when a bare name (not Authorization, not X-Amzn-Bedrock-…-Custom-) is passed via -H, suggesting the user either add the full prefix or the literal name to their allowlist.
  3. If (1) is rejected because we want the CLI to always send what the user typed, at least document the migration explicitly so users don't debug silently-dropped headers.

if (reason) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: reason });
}
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing unit tests for RequestHeaderAllowlistSchema itself.

All new coverage is in header-utils.test.ts, which exercises the wrapper utilities. The Zod schema's inner superRefine (here) and the array-level duplicate detection on lines 328–341 are the last line of defense when a user hand-edits agentcore/agentcore.json or imports a config that wasn't produced by the TUI/CLI — but src/schema/schemas/__tests__/agent-env.test.ts has nothing for RequestHeaderAllowlistSchema today.

Please add safeParse tests that at minimum cover:

  • accepts ['Authorization'], ['X-Amzn-Bedrock-AgentCore-Runtime-Custom-Foo'], ['X-Api-Key'], ['Some_Header_With_Underscores'];
  • rejects ['Cookie'], ['cookie'], ['X-Amz-Date'], ['X-Amzn-Foo'], ['Bad Header'], ['Bad@Header'], [''];
  • rejects duplicates at the array level — e.g. ['MyHeader', 'myheader'] — and verify the issue's path points at the duplicate index (the schema emits path: [i], and that contract is worth pinning);
  • rejects arrays of length 21.

The util-layer tests are valuable but don't prove the schema itself behaves correctly when config comes from a path other than the TUI/CLI.

error: `Duplicate header (case-insensitive): "${raw}".`,
};
}
seen.add(key);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor: validateHeaderAllowlist now computes headers = parseAndNormalizeHeaders(value) on line 77 (which already dedups case-insensitively), then runs a second manual dedup loop over rawNames on lines 79–88 to produce the duplicate-rejection error. Only headers.length from the first call is used after that. Functionally fine today, but the two passes will silently disagree if parseAndNormalizeHeaders's dedup semantics ever change. Worth collapsing to a single enumeration of rawNames that produces both the count and the duplicate diagnostic — especially since there are no direct tests for the schema's dedup yet (see my other comment).

@github-actions github-actions Bot removed the agentcore-harness-reviewing AgentCore Harness review in progress label May 7, 2026
@aidandaly24

Copy link
Copy Markdown
Contributor Author

Closing: duplicate from batch test run

@aidandaly24 aidandaly24 closed this May 7, 2026
@aidandaly24 aidandaly24 deleted the fix/1151-93d27c63 branch May 13, 2026 14:19
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.

Relax Custom Header regex to allow new pattern

2 participants