Skip to content

Commit

Permalink
Merge branch 'main' into bobertzh/logging
Browse files Browse the repository at this point in the history
  • Loading branch information
HBobertz authored Dec 8, 2024
2 parents 5bcdaad + 0e5ced1 commit 1dce3bf
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 197 deletions.
1 change: 1 addition & 0 deletions .projenrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const project = new typescript.TypeScriptProject({
jestConfig: {
verbose: true,
maxWorkers: '50%',
randomize: true,
},
configFilePath: 'jest.config.json',
},
Expand Down
1 change: 1 addition & 0 deletions jest.config.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions lib/private/docker-credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ export function cdkCredentialsConfig(): DockerCredentialsConfig | undefined {
return _cdkCredentials;
}

/**
* Just for testing
*/
export function _clearCdkCredentialsConfigCache() {
_cdkCredentials = undefined;
}

/** Fetches login credentials from the configured source (e.g., SecretsManager, ECR) */
export async function fetchDockerLoginCredentials(
aws: IAws,
Expand Down
10 changes: 5 additions & 5 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 68 additions & 41 deletions test/docker-images.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
DescribeImagesCommand,
DescribeRepositoriesCommand,
GetAuthorizationTokenCommand,
GetAuthorizationTokenResponse,
} from '@aws-sdk/client-ecr';
import { MockAws, mockEcr } from './mock-aws';
import { MockAws, mockEcr, resetDefaultAwsMockBehavior } from './mock-aws';
import { mockSpawn } from './mock-child_process';
import mockfs from './mock-fs';
import { AssetManifest, AssetPublishing, IAws } from '../lib';
Expand All @@ -23,6 +24,7 @@ err.name = 'ImageNotFoundException';

beforeEach(() => {
jest.resetAllMocks();
resetDefaultAwsMockBehavior();
delete process.env.CDK_DOCKER;

// By default, assume no externally-configured credentials.
Expand Down Expand Up @@ -78,6 +80,39 @@ beforeEach(() => {
},
},
}),
'/multi2/cdk.out/assets.json': JSON.stringify({
version: Manifest.version(),
dockerImages: {
theAsset1: {
source: {
directory: 'dockerdir',
},
destinations: {
theDestination: {
region: 'us-north-50',
account: '12345',
assumeRoleArn: 'arn:aws:role',
repositoryName: 'repo',
imageTag: 'theAsset1',
},
},
},
theAsset2: {
source: {
directory: 'dockerdir',
},
destinations: {
theDestination: {
region: 'us-north-50',
account: '12346',
assumeRoleArn: 'arn:aws:role',
repositoryName: 'repo2',
imageTag: 'theAsset2',
},
},
},
},
}),
'/external/cdk.out/assets.json': JSON.stringify({
version: Manifest.version(),
dockerImages: {
Expand Down Expand Up @@ -256,40 +291,42 @@ afterEach(() => {
});

test('logging in twice for two repository domains (containing account id & region)', async () => {
const pub = new AssetPublishing(AssetManifest.fromPath(mockfs.path('/multi/cdk.out')), {
const pub = new AssetPublishing(AssetManifest.fromPath(mockfs.path('/multi2/cdk.out')), {
aws,
throwOnError: false,
throwOnError: true,
});

mockEcr
.on(DescribeRepositoriesCommand)
.resolvesOnce({
repositories: [{ repositoryUri: '12345.amazonaws.com/aws-cdk/assets' }],
})
.resolvesOnce({
repositories: [{ repositoryUri: '12346.amazonaws.com/aws-cdk/assets' }],
})
.resolves({
repositories: [
{
repositoryName: 'repo',
repositoryUri: '12345.amazonaws.com/repo',
},
],
});
mockEcr.on(DescribeRepositoriesCommand).callsFake((input) => {
const url = {
repo: '12345.amazonaws.com/repo',
repo2: '12346.amazonaws.com/repo2',
}[input.repositoryNames[0]];
if (!url) {
throw new Error(`Unexpected repo: ${JSON.stringify(input)}`);
}
return {
repositories: [{ repositoryUri: url }],
};
});

mockEcr
.on(GetAuthorizationTokenCommand)
.resolvesOnce({
const responses: GetAuthorizationTokenResponse[] = [
{
authorizationData: [
{ authorizationToken: 'dXNlcjpwYXNz', proxyEndpoint: 'https://12345.proxy.com/' },
],
})
.resolvesOnce({
},
{
authorizationData: [
{ authorizationToken: 'dXNlcjpwYXNz', proxyEndpoint: 'https://12346.proxy.com/' },
],
});
},
];

let i = 0;
// For some reason, `mockResolvedValueOnce()` doesn't work here, but this does.
mockEcr.on(GetAuthorizationTokenCommand).callsFake(() => {
return responses[i++];
});

const expectAllSpawns = mockSpawn(
{
Expand All @@ -305,17 +342,12 @@ test('logging in twice for two repository domains (containing account id & regio
{ commandLine: ['docker', 'inspect', 'cdkasset-theasset1'], exitCode: 1 },
{
commandLine: ['docker', 'build', '--tag', 'cdkasset-theasset1', '.'],
cwd: '/multi/cdk.out/dockerdir',
cwd: 'multi2/cdk.out/dockerdir',
},
{
commandLine: [
'docker',
'tag',
'cdkasset-theasset1',
'12345.amazonaws.com/aws-cdk/assets:theAsset1',
],
commandLine: ['docker', 'tag', 'cdkasset-theasset1', '12345.amazonaws.com/repo:theAsset1'],
},
{ commandLine: ['docker', 'push', '12345.amazonaws.com/aws-cdk/assets:theAsset1'] },
{ commandLine: ['docker', 'push', '12345.amazonaws.com/repo:theAsset1'] },
{
commandLine: [
'docker',
Expand All @@ -329,17 +361,12 @@ test('logging in twice for two repository domains (containing account id & regio
{ commandLine: ['docker', 'inspect', 'cdkasset-theasset2'], exitCode: 1 },
{
commandLine: ['docker', 'build', '--tag', 'cdkasset-theasset2', '.'],
cwd: '/multi/cdk.out/dockerdir',
cwd: 'multi2/cdk.out/dockerdir',
},
{
commandLine: [
'docker',
'tag',
'cdkasset-theasset2',
'12346.amazonaws.com/aws-cdk/assets:theAsset2',
],
commandLine: ['docker', 'tag', 'cdkasset-theasset2', '12346.amazonaws.com/repo2:theAsset2'],
},
{ commandLine: ['docker', 'push', '12346.amazonaws.com/aws-cdk/assets:theAsset2'] }
{ commandLine: ['docker', 'push', '12346.amazonaws.com/repo2:theAsset2'] }
);

await pub.publish();
Expand Down
33 changes: 17 additions & 16 deletions test/mock-aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@ import { mockClient } from 'aws-sdk-client-mock';
import { Account, ClientOptions, DefaultAwsClient } from '../lib/aws';

export const mockEcr = mockClient(ECRClient);
mockEcr.on(DescribeRepositoriesCommand).resolves({
repositories: [
{
repositoryName: 'repo',
repositoryUri: '12345.amazonaws.com/repo',
},
],
});
mockEcr.on(DescribeImagesCommand).resolves({});

export const mockS3 = mockClient(S3Client);
mockS3.on(UploadPartCommand).resolves({ ETag: '1' });
mockS3.on(PutObjectCommand).resolves({});

export const mockSecretsManager = mockClient(SecretsManagerClient);
export const mockSTS = mockClient(STSClient);
mockSTS
.on(GetCallerIdentityCommand)
.resolves({ Account: '123456789012', Arn: 'aws:swa:123456789012:some-other-stuff' });

export function resetDefaultAwsMockBehavior() {
mockEcr.on(DescribeRepositoriesCommand).resolves({
repositories: [
{
repositoryName: 'repo',
repositoryUri: '12345.amazonaws.com/repo',
},
],
});
mockEcr.on(DescribeImagesCommand).resolves({});
mockS3.on(UploadPartCommand).resolves({ ETag: '1' });
mockS3.on(PutObjectCommand).resolves({});
mockSTS
.on(GetCallerIdentityCommand)
.resolves({ Account: '123456789012', Arn: 'aws:swa:123456789012:some-other-stuff' });
}

export class MockAws extends DefaultAwsClient {
discoverPartition(): Promise<string> {
Expand Down
3 changes: 2 additions & 1 deletion test/placeholders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import 'aws-sdk-client-mock-jest';
import { Manifest } from '@aws-cdk/cloud-assembly-schema';
import { DescribeImagesCommand } from '@aws-sdk/client-ecr';
import { ListObjectsV2Command } from '@aws-sdk/client-s3';
import { MockAws, mockEcr, mockS3 } from './mock-aws';
import { MockAws, mockEcr, mockS3, resetDefaultAwsMockBehavior } from './mock-aws';
import mockfs from './mock-fs';
import { AssetManifest, AssetPublishing, IAws } from '../lib';

let aws: IAws;
beforeEach(() => {
resetDefaultAwsMockBehavior();
mockfs({
'/simple/cdk.out/assets.json': JSON.stringify({
version: Manifest.version(),
Expand Down
10 changes: 6 additions & 4 deletions test/private/docker-credentials.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as crypto from 'crypto';
import * as os from 'os';
import * as path from 'path';
import { GetAuthorizationTokenCommand } from '@aws-sdk/client-ecr';
import { GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';
import { IAws } from '../../lib/aws';
import {
_clearCdkCredentialsConfigCache,
cdkCredentialsConfig,
cdkCredentialsConfigFile,
DockerCredentialsConfig,
Expand All @@ -18,6 +20,8 @@ let aws: IAws;
beforeEach(() => {
jest.resetModules();
jest.resetAllMocks();
mockSecretWithSecretString({ username: 'secretUser', secret: 'secretPass' });
_clearCdkCredentialsConfigCache();

aws = new MockAws();

Expand Down Expand Up @@ -45,8 +49,9 @@ describe('cdkCredentialsConfigFile', () => {
});

describe('cdkCredentialsConfig', () => {
const credsFile = '/tmp/foo/bar/does/not/exist/config.json';
let credsFile: string;
beforeEach(() => {
credsFile = `/tmp/foo/bar/does/not/exist/config${crypto.randomUUID()}.json`;
process.env.CDK_DOCKER_CREDS_FILE = mockfs.path(credsFile);
});

Expand Down Expand Up @@ -118,8 +123,6 @@ describe('fetchDockerLoginCredentials', () => {
});

test('does not throw on correctly configured raw domain', async () => {
mockSecretWithSecretString({ username: 'secretUser', secret: 'secretPass' });

await expect(
fetchDockerLoginCredentials(aws, config, 'https://secret.example.com/v1/')
).resolves.toBeTruthy();
Expand All @@ -139,7 +142,6 @@ describe('fetchDockerLoginCredentials', () => {
});

test('supports assuming a role', async () => {
mockSecretWithSecretString({ username: 'secretUser', secret: 'secretPass' });
const secretsManagerClient = jest.spyOn(aws, 'secretsManagerClient');

const creds = await fetchDockerLoginCredentials(aws, config, 'secretwithrole.example.com');
Expand Down
Loading

0 comments on commit 1dce3bf

Please sign in to comment.