import { Provider } from "../base"; import type { ProviderResult } from "../types"; import { stsGetCallerIdentity } from "./client"; import { type CredentialSource, fromContainerMetadata, fromEnv, fromInstanceMetadata, fromProfile, fromTokenFile, getAvailableProfiles, } from "./credentials"; const TIMEOUT_MS = 5000; const STS_REGION = process.env["AWS_REGION"] ?? "us-east-1"; interface AccountIdentity { source: string; account: string; arn: string; userId: string; staticCredentials: boolean; } function withTimeout( promise: Promise, ms: number, label: string, ): Promise { let timer: ReturnType | undefined; const timeout = new Promise((_, reject) => { timer = setTimeout( () => reject(new Error(`Timeout after ${ms}ms (${label})`)), ms, ); }); return Promise.race([promise, timeout]).finally(() => { if (timer) clearTimeout(timer); }); } export class AwsAccountService extends Provider { constructor() { super("aws", "sts"); } private async resolveIdentity( source: CredentialSource, ): Promise { const creds = await source.resolve(); const identity = await stsGetCallerIdentity(creds, STS_REGION); return { source: source.label, account: identity.account ?? "", arn: identity.arn ?? "", userId: identity.userId ?? "", staticCredentials: Boolean( creds.accessKeyId && creds.secretAccessKey && !creds.sessionToken, ), }; } async execute(): Promise { const sources: CredentialSource[] = [ fromEnv(), fromTokenFile(), fromContainerMetadata(), fromInstanceMetadata(), ]; const profiles = await getAvailableProfiles(); for (const profile of profiles) { sources.push(fromProfile(profile)); } const settled = await Promise.all( sources.map((source) => withTimeout( this.resolveIdentity(source), TIMEOUT_MS, source.label, ).catch(() => null), ), ); const results = settled.filter((r): r is AccountIdentity => r !== null); if (results.length === 0) { return this.failure("No accessible AWS credentials found!"); } return this.success(results); } }