Skip to content

Commit 3112313

Browse files
jesseturner21claude
andcommitted
fix(e2e): prevent API key credential provider quota exhaustion
E2E teardown deleted credential providers after CFN stack teardown, which often fails with "No resources defined". Leaked providers accumulated across CI runs until the account hit its quota limit, breaking all non-Bedrock e2e suites. Three changes: 1. Move credential provider deletion before CFN teardown in afterAll 2. Add cleanupStaleCredentialProviders() in beforeAll to purge leaks 3. Add CI workflow step to delete stale E2e* providers before tests Constraint: Teardown CFN step frequently fails when deploy never succeeded Rejected: Only fix teardown ordering | does not handle pre-existing leaks from past runs Confidence: high Scope-risk: narrow Not-tested: Race condition between parallel matrix jobs deleting same provider Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0b743db commit 3112313

2 files changed

Lines changed: 57 additions & 8 deletions

File tree

.github/workflows/e2e-tests.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@ jobs:
9898
- run: npm run build
9999
- name: Install CLI globally
100100
run: npm install -g "$(npm pack | tail -1)"
101+
- name: Clean up stale credential providers
102+
run: |
103+
# Delete leaked E2e* API key credential providers from previous CI runs
104+
# to prevent account quota exhaustion
105+
for name in $(aws bedrock-agentcore-control list-api-key-credential-providers \
106+
--region ${{ inputs.aws_region || 'us-east-1' }} \
107+
--query 'credentialProviders[?starts_with(name, `E2e`)].name' \
108+
--output text); do
109+
echo "Deleting stale provider: $name"
110+
aws bedrock-agentcore-control delete-api-key-credential-provider \
111+
--name "$name" --region ${{ inputs.aws_region || 'us-east-1' }} || true
112+
done
101113
- name: Run E2E tests (${{ matrix.cdk-source }})
102114
env:
103115
AWS_ACCOUNT_ID: ${{ steps.aws.outputs.account_id }}

e2e-tests/e2e-helper.ts

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
BedrockAgentCoreControlClient,
1111
DeleteApiKeyCredentialProviderCommand,
12+
ListApiKeyCredentialProvidersCommand,
1213
} from '@aws-sdk/client-bedrock-agentcore-control';
1314
import { execSync } from 'node:child_process';
1415
import { randomUUID } from 'node:crypto';
@@ -39,6 +40,9 @@ export function createE2ESuite(cfg: E2EConfig) {
3940
beforeAll(async () => {
4041
if (!canRun) return;
4142

43+
// Purge leaked credential providers from prior CI runs to avoid quota limits
44+
await cleanupStaleCredentialProviders();
45+
4246
testDir = join(tmpdir(), `agentcore-e2e-${randomUUID()}`);
4347
await mkdir(testDir, { recursive: true });
4448

@@ -292,20 +296,53 @@ export function installCdkTarball(projectPath: string): void {
292296
}
293297

294298
export async function teardownE2EProject(projectPath: string, agentName: string, modelProvider: string): Promise<void> {
295-
await spawnAndCollect('agentcore', ['remove', 'all', '--json'], projectPath);
296-
const result = await spawnAndCollect('agentcore', ['deploy', '--yes', '--json'], projectPath);
297-
if (result.exitCode !== 0) {
298-
console.log('Teardown stdout:', result.stdout);
299-
console.log('Teardown stderr:', result.stderr);
300-
}
299+
// Delete the API key credential provider FIRST — CFN teardown may fail,
300+
// and leaked providers accumulate until the account hits its quota limit.
301301
if (modelProvider !== 'Bedrock' && agentName) {
302302
const providerName = `${agentName}${modelProvider}`;
303303
const region = process.env.AWS_REGION ?? 'us-east-1';
304304
try {
305305
const client = new BedrockAgentCoreControlClient({ region });
306306
await client.send(new DeleteApiKeyCredentialProviderCommand({ name: providerName }));
307-
} catch {
308-
// Best-effort cleanup
307+
console.log(`Deleted credential provider: ${providerName}`);
308+
} catch (err) {
309+
console.warn(`Failed to delete credential provider ${providerName}:`, err);
310+
}
311+
}
312+
313+
await spawnAndCollect('agentcore', ['remove', 'all', '--json'], projectPath);
314+
const result = await spawnAndCollect('agentcore', ['deploy', '--yes', '--json'], projectPath);
315+
if (result.exitCode !== 0) {
316+
console.log('Teardown stdout:', result.stdout);
317+
console.log('Teardown stderr:', result.stderr);
318+
}
319+
}
320+
321+
/**
322+
* Delete stale E2e* API key credential providers left behind by previous
323+
* CI runs whose teardown failed. Call this before tests to prevent quota
324+
* exhaustion in the shared test account.
325+
*/
326+
export async function cleanupStaleCredentialProviders(): Promise<void> {
327+
const region = process.env.AWS_REGION ?? 'us-east-1';
328+
try {
329+
const client = new BedrockAgentCoreControlClient({ region });
330+
const response = await client.send(new ListApiKeyCredentialProvidersCommand({}));
331+
const providers = response.credentialProviders ?? [];
332+
const stale = providers.filter(p => p.name?.startsWith('E2e'));
333+
334+
if (stale.length === 0) return;
335+
336+
console.log(`Cleaning up ${stale.length} stale E2e* credential provider(s)...`);
337+
for (const provider of stale) {
338+
try {
339+
await client.send(new DeleteApiKeyCredentialProviderCommand({ name: provider.name! }));
340+
console.log(` Deleted: ${provider.name}`);
341+
} catch (err) {
342+
console.warn(` Failed to delete ${provider.name}:`, err);
343+
}
309344
}
345+
} catch (err) {
346+
console.warn('Failed to list credential providers for cleanup:', err);
310347
}
311348
}

0 commit comments

Comments
 (0)