feat: api key outbound authorization with configurable placement for gateway targets#1527
feat: api key outbound authorization with configurable placement for gateway targets#1527aidandaly24 wants to merge 14 commits into
Conversation
Converts raw placement inputs (location/parameterName/prefix) into the optional ApiKeyOutboundConfig block, returning undefined when values match the CDK defaults (HEADER / x-api-key / no prefix) to avoid writing redundant config blocks.
…way-target Registers three new optional CLI flags on `add gateway-target` for API key placement customisation (HEADER vs QUERY_PARAMETER, parameter name, and value prefix). Validation rejects placement flags when outbound auth type is not API_KEY and enforces valid location values and length constraints on name/prefix. Placement is threaded into the outboundAuth block for the mcpServer, schema-based (openApiSchema/ smithyModel), and apiGateway branches via buildApiKeyPlacement. Also widens the TUI config types (McpServerTargetConfig, ApiGatewayTargetConfig, SchemaBasedTargetConfig, GatewayTargetWizardState) to carry the optional apiKey placement field, unblocking downstream TUI tasks.
Add a concrete end-to-end test that drives ApiKeyPlacementInput through
the checklist (cursor down x2 to prefix, Space toggle, Enter confirm)
into the prefix TextInput, types 'Bearer', and asserts onComplete is
called with { prefix: 'Bearer' }. Also tighten the default-labels test
to assert the full annotation strings ('Location (default: HEADER)' and
'Parameter name (default: x-api-key)') instead of loose substrings.
…help text + wizard back-nav
Adds a TDD-verified guard in the lambdaFunctionArn validation branch that
rejects --api-key-* placement flags before the file-existence check, closes
the silent-drop bug. Updates placement sub-form help text to MULTI_SELECT
and adds exitEnabled={false} to AddGatewayTargetScreen to match the sibling
gateway wizard and activate onBack/onExit handlers correctly.
|
Claude Security Review: the review did not actually analyze this PR (model took 0 turns — the skill likely failed during setup). See the run for details; a later push or re-run is needed for a real review. |
Package TarballHow to installgh release download pr-1527-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.19.0.tgz |
Coverage Report
|
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Nice work — schema/CLI/TUI/import all hang together cleanly, the lockstep with the CDK is well-justified, and test coverage (schema guards, CLI validation, import round-trip, integ) is solid.
Found one regression I'd like to see fixed before merging: setting exitEnabled={false} at the top of AddGatewayTargetScreen globally disables Escape/Ctrl+Q exit for the entire wizard, not just the placement sub-form. Details inline.
| onExit={onExit} | ||
| helpText={helpText} | ||
| headerContent={headerContent} | ||
| exitEnabled={false} |
There was a problem hiding this comment.
Wizard exit (Escape / Ctrl+Q) is now broken on the first step.
exitEnabled={false} disables useExitHandler on the parent Screen for every step of the wizard, but the per-step useListNavigation hooks all bind Escape/Ctrl+Q to wizard.goBack(), which is a no-op at the first step (steps[currentIndex - 1] is undefined). Net effect:
- Pre-PR, on the target-type step: Esc → nav hook calls
goBack(no-op) → Screen handler also fires → wizard exits. ✅ - Post-PR, on the target-type step: Esc → nav hook calls
goBack(no-op) → Screen handler is disabled → nothing happens. User is stuck on the wizard with only Ctrl+C (SIGINT) as an escape hatch. Same for Ctrl+Q.
I suspect the goal here was to stop double-firing on non-first steps (where the old behavior was goBack and exit at the same time — a separate pre-existing bug). A few ways to fix:
- Conditional exitEnabled — only let the Screen handle exit on the first step and when no sub-form is active:
exitEnabled={wizard.currentIndex === 0 && !awaitingApiKeyPlacement}
- Route Screen's onExit through goBack semantics — pass a smart handler so Esc at the screen level mirrors the existing TextInput pattern at line 352:
This also fixes the pre-existing double-fire (because nav hook would
onExit={() => (wizard.currentIndex === 0 ? onExit() : wizard.goBack())} exitEnabled={!awaitingApiKeyPlacement}
goBackand Screen handler would alsogoBack, idempotent). - Keep exitEnabled true and stop nav hooks from intercepting at step 0 — narrower change, but each
useListNavigationsite needsonExit: () => (wizard.currentIndex === 0 ? onExit() : wizard.goBack()), which is more invasive.
Option 1 or 2 seems cleanest. Whichever you pick, please add a test that covers Escape on the target-type step closing the wizard so this doesn't regress again.
There was a problem hiding this comment.
Fixed in c5e6a1f:
- Reverted
exitEnabled={false}onAddGatewayTargetScreen. It was an out-of-scope tweak that globally disabled Escape/Ctrl+Q exit for the whole wizard (and, as you noted, broke exit on the first step wheregoBackis a no-op). The screen is back to its pre-PR behavior; the placement sub-form's own back/exit handling is unaffected. The underlying 'Esc should step back rather than exit' question is pre-existing and out of scope for this PR. - Also dropped the committed
schemas/agentcore.schema.v1.jsonchange — I'd regenerated it locally, but theschema-checkgate correctly flags that the JSON schema is regenerated during the release workflow, not in feature PRs. Reverted to matchmain.
PR title fixed too (lowercase subject for validate-pr-title). All three CI failures should clear on the next run.
…rated schema
- Remove exitEnabled={false} from AddGatewayTargetScreen: it globally disabled
Escape/Ctrl+Q exit for the whole wizard (regression on the first step where
goBack is a no-op). Reverts to the pre-PR Screen behavior. The placement
sub-form's own back handling is unaffected.
- Revert schemas/agentcore.schema.v1.json to main: the repo regenerates the
JSON schema during the release workflow; it must not be committed in feature
PRs (schema-check CI gate).
|
Claude Security Review: the review did not actually analyze this PR (model took 0 turns — the skill likely failed during setup). See the run for details; a later push or re-run is needed for a real review. |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Nice work — the design (lockstep schema + CDK-default elision, shared buildApiKeyPlacement, sub-form reuse for the TUI) is clean and the integration coverage looks solid. One real gap before merge: the new feature surface isn't instrumented for telemetry. Details inline.
| : {}), | ||
| // apiGateway only ever resolves to API_KEY | NONE (OAUTH is rejected in validation), | ||
| // so the helper's wider OAUTH | API_KEY | NONE type is narrowed here. | ||
| ...(buildOutboundAuthForCli(cliOptions) as Pick<ApiGatewayTargetConfig, 'outboundAuth'>), |
There was a problem hiding this comment.
Missing telemetry for the new placement feature.
AddGatewayTargetAttrs in src/cli/telemetry/schemas/command-run.ts still only records gateway_target_type, gateway_target_host, and outbound_auth_type. Per src/cli/telemetry/README.md, new features should be instrumented — without it we can't tell how many users actually customize placement vs. take the default, or which location they pick (the whole point of this PR).
A minimal addition that fits the safe-schema rules:
api_key_placement_customized: z.boolean()— true when any of--api-key-location/--api-key-parameter-name/--api-key-prefixis set (or when the TUI sub-form returned a non-undefinedplacement). Should also betruefor non-default placement coming through the OAuth/API_KEY auth step in the TUI.api_key_location: z.enum(['header', 'query_parameter', 'none']).optional()— the resolved location, or'none'whenoutbound_auth_type !== 'api-key'.
Both should be added to safeSchema in command-run.ts, derived from cliOptions here (and from the TUI completion path), and merged into telemetryAttrs around line 387. The same attrs should be set on the apiGateway / schema-based / mcpServer branches since all three now support placement.
Happy to leave the exact attribute shape to your judgment, but please don't ship the feature uninstrumented.
|
Closing — this work is shipping via the private staging repo's summit release branch instead (ported onto |
Description
Adds an API key outbound authorization strategy with configurable placement to MCP / gateway targets in the CLI.
Users can now control how the gateway sends an API key to an upstream target via three new
add gateway-targetflags:This sends
Authorization: Bearer <key>— previously the placement was hardcoded to thex-api-keyheader, which the new control makes configurable.mcpServertargets now supportAPI_KEYoutbound auth (previously OAUTH/NONE only); the same placement applies toopenApiSchemaandapiGatewaytargets.How it works
The credential itself is unchanged —
add credentialproduces an AgentCore Identity API-key provider, and the gateway target references it by ARN plus the per-target placement. Placement is modeled as an optional nestedapiKey: { location?, parameterName?, prefix? }block onoutboundAuth; defaults (HEADER/x-api-key) are applied in the CDK so existing configs are unaffected.Changes by layer
ApiKeyOutboundConfigSchema+ optionalapiKeyonOutboundAuthSchema;mcpServerallowedAPI_KEY; guard rule; regeneratedagentcore.schema.v1.json(lockstep with@aws/agentcore-cdk).--api-key-location/--api-key-parameter-name/--api-key-prefixwith validation; sharedbuildApiKeyPlacementhelper.ApiKeyPlacementInputsub-form — forced credential selection, then a skippable placement checklist; reuses the existingAddIdentityScreenfor credential creation (unchanged).import gatewaynow round-trips placement (was silently dropping it).docs/gateway.mdupdated with the placement flags + theAuthorization: Bearerexample.Related Issue
Closes #
Documentation PR
docs/gateway.mdupdated in this PR. (No separate agent-docs PR.)Type of Change
Testing
How have you tested the change?
npm run test:unitandnpm run test:integnpm run typechecknpm run lintsrc/assets/, I rannpm run test:update-snapshots— N/A (nosrc/assets/changes)Additional verification:
main(unrelateduseDevDeploy/LogsScreen) — zero regressions introduced.get-gateway-targetconfirmed the exact placement reached the service. mcpServer + API_KEY proven against a reachable MCP endpoint.apiKey.Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.