Skip to content

Commit

Permalink
fix: internally paginate list secret calls (#2113)
Browse files Browse the repository at this point in the history
  • Loading branch information
Amplifiyer authored Oct 15, 2024
1 parent 39ea5a0 commit f87cc87
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-snakes-accept.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aws-amplify/backend-secret': patch
---

fix: internally paginate list secret calls
66 changes: 66 additions & 0 deletions packages/backend-secret/src/ssm_secret.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { beforeEach, describe, it, mock } from 'node:test';
import {
GetParameterCommandOutput,
GetParametersByPathCommandInput,
GetParametersByPathCommandOutput,
InternalServerError,
ParameterNotFound,
Expand Down Expand Up @@ -306,6 +307,7 @@ void describe('SSMSecret', () => {
assert.deepStrictEqual(
mockGetParametersByPath.mock.calls[0].arguments[0],
{
NextToken: undefined,
Path: testBranchPath,
WithDecryption: true,
}
Expand Down Expand Up @@ -337,13 +339,76 @@ void describe('SSMSecret', () => {
assert.deepStrictEqual(
mockGetParametersByPath.mock.calls[0].arguments[0],
{
NextToken: undefined,
Path: testSharedPath,
WithDecryption: true,
}
);
assert.deepEqual(secrets, [testSecretListItem]);
});

void it('lists all secrets by internally paginating calls', async () => {
const mockGetParametersByPath = mock.method(
ssmClient,
'getParametersByPath',
(input: GetParametersByPathCommandInput) => {
let nextToken: string | undefined = undefined;
if (!input.NextToken) {
nextToken = '1';
} else if (input.NextToken === '1') {
nextToken = '2';
} else if (input.NextToken === '2') {
nextToken = undefined;
}
return Promise.resolve({
NextToken: nextToken,
Parameters: [
{
Name: testSharedSecretFullNamePath.concat(
input.NextToken ?? ''
),
Value: testSecretValue,
Version: testSecretVersion,
LastModifiedDate: testSecretLastUpdated,
},
],
} as GetParametersByPathCommandOutput);
}
);

const secrets = await ssmSecretClient.listSecrets(testBackendId);
assert.deepStrictEqual(mockGetParametersByPath.mock.calls.length, 3);
assert.deepStrictEqual(
mockGetParametersByPath.mock.calls[0].arguments[0],
{
NextToken: undefined,
Path: testSharedPath,
WithDecryption: true,
}
);
assert.deepStrictEqual(
mockGetParametersByPath.mock.calls[1].arguments[0],
{
NextToken: '1',
Path: testSharedPath,
WithDecryption: true,
}
);
assert.deepStrictEqual(
mockGetParametersByPath.mock.calls[2].arguments[0],
{
NextToken: '2',
Path: testSharedPath,
WithDecryption: true,
}
);
assert.deepEqual(secrets, [
{ ...testSecretListItem, name: testSecretName },
{ ...testSecretListItem, name: testSecretName + '1' },
{ ...testSecretListItem, name: testSecretName + '2' },
]);
});

void it('lists an empty list', async () => {
const mockGetParametersByPath = mock.method(
ssmClient,
Expand All @@ -359,6 +424,7 @@ void describe('SSMSecret', () => {
assert.deepStrictEqual(
mockGetParametersByPath.mock.calls[0].arguments[0],
{
NextToken: undefined,
Path: testBranchPath,
WithDecryption: true,
}
Expand Down
39 changes: 22 additions & 17 deletions packages/backend-secret/src/ssm_secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,24 +68,29 @@ export class SSMSecretClient implements SecretClient {
const result: SecretListItem[] = [];

try {
const resp = await this.ssmClient.getParametersByPath({
Path: path,
WithDecryption: true,
});
let nextToken: string | undefined;
do {
const resp = await this.ssmClient.getParametersByPath({
Path: path,
WithDecryption: true,
NextToken: nextToken,
});

resp.Parameters?.forEach((param) => {
if (!param.Name || !param.Value) {
return;
}
const secretName = param.Name.split('/').pop();
if (secretName) {
result.push({
name: secretName,
version: param.Version,
lastUpdated: param.LastModifiedDate,
});
}
});
resp.Parameters?.forEach((param) => {
if (!param.Name || !param.Value) {
return;
}
const secretName = param.Name.split('/').pop();
if (secretName) {
result.push({
name: secretName,
version: param.Version,
lastUpdated: param.LastModifiedDate,
});
}
});
nextToken = resp.NextToken;
} while (nextToken);
return result;
} catch (err) {
throw SecretError.createInstance(err as Error);
Expand Down

0 comments on commit f87cc87

Please sign in to comment.