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
10 changes: 3 additions & 7 deletions src/core/abTestExecutionRole.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type IAMClient,
} from "@aws-sdk/client-iam";
import { createHash } from "node:crypto";
import { parseArn, resourceNameFromArn } from "./arn";

const AB_TEST_POLICY_NAME = "ABTestExecutionPolicy";

Expand All @@ -16,13 +17,8 @@ export function abTestExecutionRoleName(testName: string): string {
return `${base.slice(0, 55)}-${hash}`;
}

export function roleNameFromArn(roleArn: string): string {
const parts = roleArn.split("/");
return parts[parts.length - 1] ?? roleArn;
}

export function accountIdFromArn(arn: string): string {
const accountId = arn.split(":")[4];
const accountId = parseArn(arn)?.account;
if (!accountId) throw new Error(`could not extract account id from ARN: ${arn}`);
return accountId;
}
Expand Down Expand Up @@ -139,7 +135,7 @@ export async function provisionAbTestRole(
}

export async function deleteAbTestRole(iam: IAMClient, roleArn: string): Promise<void> {
const roleName = roleNameFromArn(roleArn);
const roleName = resourceNameFromArn(roleArn);
try {
await iam.send(
new DeleteRolePolicyCommand({ RoleName: roleName, PolicyName: AB_TEST_POLICY_NAME }),
Expand Down
6 changes: 3 additions & 3 deletions src/core/eval.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,10 @@ import {
grantOnlineEvalScope,
isManagedOnlineEvalRole,
revokeOnlineEvalScope,
roleNameFromArn,
scopePolicyName,
} from "./onlineEvalExecutionRole";
import { accountIdFromArn, deleteAbTestRole, provisionAbTestRole } from "./abTestExecutionRole";
import { resourceNameFromArn } from "./arn";
import { harnessRuntimeFromResponse } from "./harness";

const DEFAULT_INGESTION_WAIT_MS = 180_000;
Expand Down Expand Up @@ -1289,7 +1289,7 @@ export class EvalClient implements CoreEvalClient {
options.region,
newLogGroups,
kmsKeys,
roleNameFromArn(roleArn!),
resourceNameFromArn(roleArn!),
);
const oldPolicyName = scopePolicyName(
executionPolicy(
Expand All @@ -1312,7 +1312,7 @@ export class EvalClient implements CoreEvalClient {
if (newPolicyName !== oldPolicyName) {
const revoked = await revokeOnlineEvalScope(
iam,
roleNameFromArn(managedRoleArn),
resourceNameFromArn(managedRoleArn),
oldPolicyName,
).catch(() => false);
// The config is already correct; the role just still grants a data
Expand Down
3 changes: 2 additions & 1 deletion src/core/executionRole.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
PutRolePolicyCommand,
type IAMClient,
} from "@aws-sdk/client-iam";
import { parseArn } from "./arn";

// Default harness execution role provisioning.
//
Expand Down Expand Up @@ -223,7 +224,7 @@ function executionPolicy(region: string, accountId: string, harnessName: string)
// (arn:aws:iam::<account>:role/<name>), which saves an STS lookup: the account
// only becomes relevant once we hold the role's ARN anyway.
function accountIdFromRoleArn(arn: string): string {
const accountId = arn.split(":")[4];
const accountId = parseArn(arn)?.account;
if (!accountId) {
throw new Error(`Cannot extract an account id from role ARN "${arn}"`);
}
Expand Down
9 changes: 3 additions & 6 deletions src/core/onlineEvalExecutionRole.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
PutRolePolicyCommand,
type IAMClient,
} from "@aws-sdk/client-iam";
import { parseArn, resourceNameFromArn } from "./arn";

// Default online-evaluation execution role provisioning, mirroring
// core/executionRole.tsx's pattern for harnesses: CreateOnlineEvaluationConfig
Expand Down Expand Up @@ -49,15 +50,11 @@ function truncatedRolePrefix(configName: string): string {
return `${ROLE_NAME_PREFIX}${configName.slice(0, room)}-`;
}

export function roleNameFromArn(roleArn: string): string {
return roleArn.slice(roleArn.lastIndexOf("/") + 1);
}

// isManagedOnlineEvalRole recognises the CLI's default role for a config. Roles
// created before the hash moved off Bun.hash carry a different suffix, so a
// truncated name is matched on its prefix rather than recomputed.
export function isManagedOnlineEvalRole(roleArn: string, configName: string): boolean {
const roleName = roleNameFromArn(roleArn);
const roleName = resourceNameFromArn(roleArn);
const full = `${ROLE_NAME_PREFIX}${configName}`;
if (full.length <= ROLE_NAME_MAX) return roleName === full;
return roleName.startsWith(truncatedRolePrefix(configName));
Expand Down Expand Up @@ -188,7 +185,7 @@ export function executionPolicy(
}

export function accountIdFromRoleArn(arn: string): string {
const accountId = arn.split(":")[4];
const accountId = parseArn(arn)?.account;
if (!accountId) {
throw new Error(`Cannot extract an account id from role ARN "${arn}"`);
}
Expand Down
9 changes: 3 additions & 6 deletions src/core/policy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
import type { Logger } from "../logging";
import type { ProgressEvent } from "../tui/progress";
import type { AwsClients, CoreOptions } from "./types";
import { resourceNameFromArn } from "./arn";
import { toClientConfig } from "./utils";

export type PolicyGenerationWait = {
Expand All @@ -32,10 +33,6 @@ export type PolicyGenerationWait = {

const DEFAULT_WAIT: PolicyGenerationWait = { maxWaitTime: 60, minDelay: 2, maxDelay: 5 };

function resourceIdFromArn(value: string): string {
return value.startsWith("arn:") ? value.slice(value.lastIndexOf("/") + 1) : value;
}

export class PolicyClient implements CorePolicyClient {
constructor(
private readonly clients: AwsClients,
Expand All @@ -49,7 +46,7 @@ export class PolicyClient implements CorePolicyClient {
signal?: AbortSignal,
): AsyncGenerator<ProgressEvent, PolicyGenerationResult> {
const control = this.clients.control(toClientConfig(options));
const gatewayId = resourceIdFromArn(input.gatewayId);
const gatewayId = resourceNameFromArn(input.gatewayId);

yield { type: "step", message: `Resolving gateway ${gatewayId}` };
const gateway = await control.send(new GetGatewayCommand({ gatewayIdentifier: gatewayId }), {
Expand All @@ -62,7 +59,7 @@ export class PolicyClient implements CorePolicyClient {
`gateway '${gatewayId}' has no Policy Engine attached; pass --policy-engine-id`,
);
}
const policyEngineId = resourceIdFromArn(engine);
const policyEngineId = resourceNameFromArn(engine);

yield { type: "step", message: `Starting policy generation ${input.name}` };
const started = await control.send(
Expand Down
5 changes: 3 additions & 2 deletions src/core/project/bedrockAgentImport/baseTranslator.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { regionFromArn, resourceNameFromArn } from "../../arn";
import { IMPORT_NOTES_FILE, renderImportNotes } from "./importNotes";
import { generateImportPyproject } from "./pyproject";
import type {
Expand Down Expand Up @@ -220,7 +221,7 @@ def ${pythonIdentifier(fn.name)}(${parameters}) -> str:
*/
export function providerFromModelArn(foundationModel: string): string | undefined {
if (!foundationModel.startsWith("arn:")) return undefined;
const resource = foundationModel.split("/").pop() ?? "";
const resource = resourceNameFromArn(foundationModel);
const provider = resource.split(".")[0];
return provider && provider !== resource ? provider.toLowerCase() : undefined;
}
Expand All @@ -230,7 +231,7 @@ export function providerFromModelArn(foundationModel: string): string | undefine
* its ARN and fall back to the agent's region only when the ARN was unavailable.
*/
export function knowledgeBaseRegion(knowledgeBase: { arn?: string }, agentRegion: string): string {
return knowledgeBase.arn?.split(":")[3] || agentRegion;
return regionFromArn(knowledgeBase.arn ?? "") ?? agentRegion;
}

/** The root snapshot followed by every collaborator reachable from it, depth-first. */
Expand Down
5 changes: 2 additions & 3 deletions src/core/project/templates/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { Memory } from "../../../projectSchemas/memory";
import type { EnvLocalEntry } from "../../../handlers/project/types";
import { InputValidationError } from "../../../errors/errors";
import { toPythonPackageName } from "../fsUtils";
import { resourceNameFromArn } from "../../arn";

type ProjectSpec = z.infer<typeof ProjectSpecSchema>;

Expand Down Expand Up @@ -768,9 +769,7 @@ function resolveSkills(
for (const skill of gitSkillSources) {
const reference = skill.auth?.credentialArn ?? skill.auth?.credentialName;
if (!reference) continue;
const name = reference.includes("/")
? reference.slice(reference.lastIndexOf("/") + 1)
: reference;
const name = resourceNameFromArn(reference);
if (seenGitCredentials.has(name)) continue;
seenGitCredentials.add(name);
if (!credentials.some((c) => c.name === name)) {
Expand Down
Loading