Skip to content

Commit 6f095f1

Browse files
authored
feat: base64 encode reason when multibyte characters exist (cdklabs#1000)
Fixes cdklabs#999
1 parent 9471cb1 commit 6f095f1

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

src/utils/nag-suppression-helper.ts

+17-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
SPDX-License-Identifier: Apache-2.0
44
*/
5+
import { Buffer } from 'buffer';
56
import { CfnResource, Stack } from 'aws-cdk-lib';
67
import {
78
NagPackSuppression,
@@ -14,25 +15,37 @@ interface NagCfnMetadata {
1415

1516
interface NagCfnSuppression extends Omit<NagPackSuppression, 'appliesTo'> {
1617
applies_to?: NagPackSuppressionAppliesTo[];
18+
is_reason_encoded?: boolean;
1719
}
1820

1921
export class NagSuppressionHelper {
2022
static toCfnFormat(suppression: NagPackSuppression): NagCfnSuppression {
21-
const { appliesTo, ...result } = suppression;
23+
const { appliesTo, reason, ...result } = suppression;
2224

2325
if (appliesTo) {
2426
(result as NagCfnSuppression).applies_to = appliesTo;
2527
}
26-
return result;
28+
if (
29+
[...reason].some((c) =>
30+
c.codePointAt(0) === undefined ? false : c.codePointAt(0)! > 255
31+
)
32+
) {
33+
(result as NagCfnSuppression).is_reason_encoded = true;
34+
return { reason: Buffer.from(reason).toString('base64'), ...result };
35+
}
36+
return { reason, ...result };
2737
}
2838

2939
static toApiFormat(suppression: NagCfnSuppression): NagPackSuppression {
30-
const { applies_to, ...result } = suppression;
40+
const { applies_to, reason, is_reason_encoded, ...result } = suppression;
3141

3242
if (applies_to) {
3343
(result as any).appliesTo = applies_to;
3444
}
35-
return result;
45+
if (is_reason_encoded) {
46+
return { reason: Buffer.from(reason, 'base64').toString(), ...result };
47+
}
48+
return { reason, ...result };
3649
}
3750

3851
static addRulesToMetadata(

test/Engine.test.ts

+38
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,25 @@ describe('Rule suppression system', () => {
696696
const metadata = test.getMetadata('cdk_nag')?.rules_to_suppress;
697697
expect(metadata).toContainEqual(expect.objectContaining(suppression));
698698
});
699+
test('Reason containing multibyte characters is base64 encoded', () => {
700+
const stack = new Stack();
701+
Aspects.of(stack).add(new AwsSolutionsChecks());
702+
const test = new CfnRoute(stack, 'CfnRoute', { routeTableId: 'foo' });
703+
const suppression = {
704+
id: 'AwsSolutions-EC23',
705+
reason: 'あいうえおかきくけこ',
706+
};
707+
const suppressionInMetadata = {
708+
id: 'AwsSolutions-EC23',
709+
reason: '44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT',
710+
is_reason_encoded: true,
711+
};
712+
NagSuppressions.addResourceSuppressions(test, [suppression]);
713+
const metadata = test.getMetadata('cdk_nag')?.rules_to_suppress;
714+
expect(metadata).toContainEqual(
715+
expect.objectContaining(suppressionInMetadata)
716+
);
717+
});
699718
test('suppressed rule logging enabled', () => {
700719
const stack = new Stack();
701720
Aspects.of(stack).add(new AwsSolutionsChecks({ logIgnores: true }));
@@ -1031,6 +1050,25 @@ describe('Report system', () => {
10311050
];
10321051
expect(pack.lines.sort()).toEqual(expectedOuput.sort());
10331052
});
1053+
test('Suppression values are written properly when multibyte characters are used in reason', () => {
1054+
const app = new App();
1055+
const stack = new Stack(app, 'Stack1');
1056+
const pack = new TestPack();
1057+
Aspects.of(app).add(pack);
1058+
const resource = new CfnResource(stack, 'rResource', { type: 'foo' });
1059+
NagSuppressions.addResourceSuppressions(resource, [
1060+
{
1061+
id: `${pack.readPackName}-${NagRuleCompliance.NON_COMPLIANT}`,
1062+
reason: 'あいうえおかきくけこ',
1063+
},
1064+
]);
1065+
app.synth();
1066+
const expectedOuput = [
1067+
'"Test-Compliant","Stack1/rResource","Compliant","N/A","Error","foo."\n',
1068+
'"Test-Non-Compliant","Stack1/rResource","Suppressed","あいうえおかきくけこ","Error","foo."\n',
1069+
];
1070+
expect(pack.lines.sort()).toEqual(expectedOuput.sort());
1071+
});
10341072
test('Error values are written properly', () => {
10351073
const app = new App();
10361074
const stack = new Stack(app, 'Stack1');

0 commit comments

Comments
 (0)