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
62 changes: 62 additions & 0 deletions src/cli/commands/import/__tests__/execution-role-import.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Tests for execution role import from starter toolkit YAML.
*/
import type { AgentEnvSpec } from '../../../../schema/schemas/agent-env';
import type { ParsedStarterToolkitConfig } from '../types';
import { parseStarterToolkitYaml } from '../yaml-parser';
import * as path from 'node:path';
import { describe, expect, it } from 'vitest';

const APP_DIR = 'app';

function toAgentEnvSpec(agent: ParsedStarterToolkitConfig['agents'][0]): AgentEnvSpec {
const codeLocation = path.join(APP_DIR, agent.name);
const entrypoint = path.basename(agent.entrypoint);
const spec: AgentEnvSpec = {
name: agent.name,
build: agent.build,
entrypoint: entrypoint as AgentEnvSpec['entrypoint'],
codeLocation: codeLocation as AgentEnvSpec['codeLocation'],
runtimeVersion: (agent.runtimeVersion ?? 'PYTHON_3_12') as AgentEnvSpec['runtimeVersion'],
protocol: agent.protocol,
networkMode: agent.networkMode,
instrumentation: { enableOtel: agent.enableOtel },
};
if (agent.networkMode === 'VPC' && agent.networkConfig) {
spec.networkConfig = agent.networkConfig;
}
if (agent.executionRoleArn) {
spec.executionRoleArn = agent.executionRoleArn;
}
return spec;
}

const FIXTURE = path.join(__dirname, 'fixtures', 'agent-with-execution-role.yaml');
const FIXTURE_NO_ROLE = path.join(__dirname, 'fixtures', 'different-agent.yaml');

describe('parseStarterToolkitYaml: executionRoleArn', () => {
it('extracts executionRoleArn from YAML with execution_role', () => {
const parsed = parseStarterToolkitYaml(FIXTURE);
expect(parsed.agents).toHaveLength(1);
expect(parsed.agents[0]!.executionRoleArn).toBe('arn:aws:iam::123456789012:role/StarterToolkitExecutionRole');
});

it('returns undefined executionRoleArn when execution_role is absent', () => {
const parsed = parseStarterToolkitYaml(FIXTURE_NO_ROLE);
expect(parsed.agents[0]!.executionRoleArn).toBeUndefined();
});
});

describe('toAgentEnvSpec: executionRoleArn', () => {
it('includes executionRoleArn in spec when present', () => {
const parsed = parseStarterToolkitYaml(FIXTURE);
const spec = toAgentEnvSpec(parsed.agents[0]!);
expect(spec.executionRoleArn).toBe('arn:aws:iam::123456789012:role/StarterToolkitExecutionRole');
});

it('omits executionRoleArn from spec when absent', () => {
const parsed = parseStarterToolkitYaml(FIXTURE_NO_ROLE);
const spec = toAgentEnvSpec(parsed.agents[0]!);
expect(spec.executionRoleArn).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
default_agent: my_agent
agents:
my_agent:
name: my_agent
entrypoint: main.py
deployment_type: direct_code_deploy
runtime_type: PYTHON_3_12
source_path: null
aws:
account: '123456789012'
region: us-west-2
execution_role: arn:aws:iam::123456789012:role/StarterToolkitExecutionRole
network_configuration:
network_mode: PUBLIC
protocol_configuration:
server_protocol: HTTP
observability:
enabled: true
bedrock_agentcore:
agent_id: AGENT_ROLE_123
agent_arn: arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/AGENT_ROLE_123
memory:
mode: NO_MEMORY
4 changes: 4 additions & 0 deletions src/cli/commands/import/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ function toAgentEnvSpec(agent: ParsedStarterToolkitConfig['agents'][0]): AgentEn
spec.networkConfig = agent.networkConfig;
}

if (agent.executionRoleArn) {
spec.executionRoleArn = agent.executionRoleArn;
}

if (agent.authorizerType) {
spec.authorizerType = agent.authorizerType;
}
Expand Down
2 changes: 2 additions & 0 deletions src/cli/commands/import/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface ParsedStarterToolkitAgent {
authorizerType?: RuntimeAuthorizerType;
/** Authorizer configuration (Custom JWT) */
authorizerConfiguration?: AuthorizerConfig;
/** ARN of the execution role from the starter toolkit deployment */
executionRoleArn?: string;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/cli/commands/import/yaml-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export function parseStarterToolkitYaml(filePath: string): ParsedStarterToolkitC
physicalAgentId: bedrockConfig?.agent_id as string | undefined,
physicalAgentArn: bedrockConfig?.agent_arn as string | undefined,
...extractAuthorizerConfig(agentConfig.authorizer_configuration),
executionRoleArn: (awsConfig?.execution_role as string) || undefined,
});

// Extract memory config per agent — ensure mode is a non-empty string
Expand Down
2 changes: 2 additions & 0 deletions src/schema/schemas/agent-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ export const AgentEnvSpecSchema = z
protocol: ProtocolModeSchema.optional(),
/** Allowed request headers forwarded to the runtime at invocation time. */
requestHeaderAllowlist: RequestHeaderAllowlistSchema.optional(),
/** ARN of an existing IAM execution role to use instead of creating a new one. */
executionRoleArn: z.string().optional(),
/** Authorizer type for inbound requests. Defaults to AWS_IAM. */
authorizerType: RuntimeAuthorizerTypeSchema.optional(),
/** Authorizer configuration. Required when authorizerType is CUSTOM_JWT. */
Expand Down
Loading