Skip to content

Add filterSensitiveLog for Union types #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 34 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b897f8d
Add writeFilterSensitiveLog to UnionGenerator with check for sensitiv…
trivikr Jun 30, 2020
561f40a
Return $undefined if no value matched in filterSensitiveLog
trivikr Jun 30, 2020
002a84b
Remove fromEntries as TSConfig doesn't have it on type ObjectConstructor
trivikr Jul 1, 2020
4b7cecd
Non-sensitive SimpleShape in Union.filterSensitiveLog
trivikr Jul 1, 2020
22d6bc2
Add check for obj.$unknown defined in Union.filterSensitiveLog
trivikr Jul 1, 2020
6189a58
Call writeStructureFilterSensitiveLog from Union
trivikr Jul 1, 2020
c648d9b
Union.filterSensitiveLog for complex members
trivikr Jul 1, 2020
97412a4
Add check for UnionShape in filterSensitiveLog
trivikr Jul 1, 2020
4d13d52
Update documentation for UnionGenerator
trivikr Jul 1, 2020
7a06e94
Add newlines within Union components
trivikr Jul 1, 2020
b99b1e6
Fix checkstyle errors
trivikr Jul 6, 2020
72662ea
Test callsFilterForUnionWithSensitiveData
trivikr Jul 6, 2020
4a19728
Test callsFilterInUnionWithSensitiveData
trivikr Jul 6, 2020
424ee10
Test filtersSensitiveUnion
trivikr Jul 6, 2020
91fa099
Test callsFilterForUnionWithoutSensitiveData
trivikr Jul 6, 2020
6bd3830
Test callsFilterInUnionWithoutSensitiveData
trivikr Jul 6, 2020
dfb9d1c
rename test-insensitive-structure
trivikr Jul 6, 2020
8d165e4
Test filtersSensitiveMemberPointingToUnion
trivikr Jul 6, 2020
b800fa3
Test callsFilterForListWithUnionWithSensitiveData
trivikr Jul 6, 2020
69a8c46
Test callsFilterInListWithUnionWithSensitiveData
trivikr Jul 6, 2020
4eb95bf
Test callsFilterForMapWithUnionWithSensitiveData
trivikr Jul 6, 2020
967e673
Test callsFilterInMapWithUnionWithSensitiveData
trivikr Jul 6, 2020
7ad784f
Fix ordering of objects in callsFilterInUnionWithoutSensitiveData
trivikr Aug 18, 2020
bd2893b
Remove unused memberTarget instanceof UnionShape
trivikr Aug 19, 2020
1c8f28a
Disable filterSensitiveLog for event stream
trivikr Aug 19, 2020
016b071
Rename STREAMING_TRAIT to STREAMING_CONTENT
trivikr Aug 21, 2020
dce7317
Log unknown union member as 'UNKNOWN'
trivikr Aug 21, 2020
62fa62d
Use isStructureShape() and isUnionShape() instead of instanceof
trivikr Aug 21, 2020
4fbbd93
Added newline at the end of .smithy test files
trivikr Aug 21, 2020
7e62b08
Add tests for complex shapes inside Union
trivikr Aug 21, 2020
d83f565
Create new function writeMemberFilterSensitiveLog
trivikr Aug 21, 2020
ca63ff5
Call writeMemberFilterSensitiveLog from Union
trivikr Aug 21, 2020
4d94416
Call writeMemberFilterSensitiveLog from Collection/Member
trivikr Aug 25, 2020
17b63af
Throw CodegenException in the else block of writeMemberFilterSensitiv…
trivikr Aug 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
import software.amazon.smithy.model.shapes.MapShape;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.SimpleShape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.traits.IdempotencyTokenTrait;
import software.amazon.smithy.model.traits.SensitiveTrait;
import software.amazon.smithy.model.traits.StreamingTrait;

/**
* Generates objects, interfaces, enums, etc.
Expand Down Expand Up @@ -74,27 +76,37 @@ void writeFilterSensitiveLog(TypeScriptWriter writer, String objectParam) {
writer.write("...$L,", objectParam);
for (MemberShape member : members) {
if (isMemberOverwriteRequired(member, new HashSet<String>())) {
Shape memberTarget = model.expectShape(member.getTarget());
String memberName = getSanitizedMemberName(member);
String memberParam = String.format("%s.%s", objectParam, memberName);
writer.openBlock("...($1L.$2L && { $2L: ", "}),", objectParam, memberName, () -> {
if (member.getMemberTrait(model, SensitiveTrait.class).isPresent()) {
// member is Sensitive, hide the value.
writer.write("SENSITIVE_STRING");
} else if (memberTarget instanceof StructureShape) {
writeStructureFilterSensitiveLog(writer, memberTarget, memberParam);
} else if (memberTarget instanceof CollectionShape) {
MemberShape collectionMember = ((CollectionShape) memberTarget).getMember();
writeCollectionFilterSensitiveLog(writer, collectionMember, memberParam);
} else if (memberTarget instanceof MapShape) {
MemberShape mapMember = ((MapShape) memberTarget).getValue();
writeMapFilterSensitiveLog(writer, mapMember, memberParam);
}
String memberParam = String.format("%s.%s", objectParam, memberName);
writeMemberFilterSensitiveLog(writer, member, memberParam);
});
}
}
}

void writeMemberFilterSensitiveLog(TypeScriptWriter writer, MemberShape member, String memberParam) {
Shape memberTarget = model.expectShape(member.getTarget());
if (member.getMemberTrait(model, SensitiveTrait.class).isPresent()) {
// member is Sensitive, hide the value.
writer.write("SENSITIVE_STRING");
} else if (memberTarget instanceof SimpleShape) {
writer.write(memberParam);
} else if (memberTarget.isStructureShape() || memberTarget.isUnionShape()) {
writeStructureFilterSensitiveLog(writer, memberTarget, memberParam);
} else if (memberTarget instanceof CollectionShape) {
MemberShape collectionMember = ((CollectionShape) memberTarget).getMember();
writeCollectionFilterSensitiveLog(writer, collectionMember, memberParam);
} else if (memberTarget instanceof MapShape) {
MemberShape mapMember = ((MapShape) memberTarget).getValue();
writeMapFilterSensitiveLog(writer, mapMember, memberParam);
} else {
throw new CodegenException(String.format(
"MemberFilterSensitiveLog attempted for %s", memberTarget.getType()
));
}
}

/**
* Recursively writes filterSensitiveLog for StructureShape.
*/
Expand All @@ -106,10 +118,13 @@ private void writeStructureFilterSensitiveLog(
if (structureTarget.hasTrait(SensitiveTrait.class)) {
// member is Sensitive, hide the value.
writer.write("SENSITIVE_STRING");
return;
} else if (structureTarget.hasTrait(StreamingTrait.class) && structureTarget.isUnionShape()) {
// disable logging for StreamingTrait
writer.write("'STREAMING_CONTENT'");
} else {
// Call filterSensitiveLog on Structure.
writer.write("$T.filterSensitiveLog($L)", symbolProvider.toSymbol(structureTarget), structureParam);
}
// Call filterSensitiveLog on Structure.
writer.write("$T.filterSensitiveLog($L)", symbolProvider.toSymbol(structureTarget), structureParam);
}

/**
Expand All @@ -123,32 +138,15 @@ private void writeCollectionFilterSensitiveLog(
if (collectionMember.getMemberTrait(model, SensitiveTrait.class).isPresent()) {
// member is Sensitive, hide the value.
writer.write("SENSITIVE_STRING");
return;
} else if (model.expectShape(collectionMember.getTarget()) instanceof SimpleShape) {
writer.write(collectionParam);
} else {
writer.openBlock("$L.map(", ")", collectionParam, () -> {
String itemParam = "item";
writer.write("$L => ", itemParam);
writeMemberFilterSensitiveLog(writer, collectionMember, itemParam);
});
}

writer.openBlock("$L.map(", ")", collectionParam, () -> {
String itemParam = "item";
Shape collectionMemberTarget = model.expectShape(collectionMember.getTarget());
writer.write("$L => ", itemParam);
if (collectionMemberTarget instanceof StructureShape) {
writeStructureFilterSensitiveLog(writer, collectionMemberTarget, itemParam);
} else if (collectionMemberTarget instanceof CollectionShape) {
MemberShape nestedCollectionMember = ((CollectionShape) collectionMemberTarget).getMember();
writeCollectionFilterSensitiveLog(writer, nestedCollectionMember, itemParam);
} else if (collectionMemberTarget instanceof MapShape) {
MemberShape mapMember = ((MapShape) collectionMemberTarget).getValue();
writeMapFilterSensitiveLog(writer, mapMember, itemParam);
} else {
// This path should not reach because of recursive isMemberOverwriteRequired.
throw new CodegenException(String.format(
"CollectionFilterSensitiveLog attempted for %s while it was not required",
collectionMemberTarget.getType()
));
// For quick-fix in case of high severity issue:
// comment out the exception above and uncomment the line below.
// writer.write("$1L => $1L", itemParam);
}
});
}

/**
Expand All @@ -158,41 +156,23 @@ private void writeMapFilterSensitiveLog(TypeScriptWriter writer, MemberShape map
if (mapMember.getMemberTrait(model, SensitiveTrait.class).isPresent()) {
// member is Sensitive, hide the value.
writer.write("SENSITIVE_STRING");
return;
} else if (model.expectShape(mapMember.getTarget()) instanceof SimpleShape) {
writer.write(mapParam);
} else {
String accParam = "acc"; // accumulator for the reducer
String keyParam = "key"; // key of the Object.entries() key-value pair
String valueParam = "value"; // value of the Object.entries() key-value pair

// Reducer is common to all shapes.
writer.openBlock("Object.entries($L).reduce(($L: any, [$L, $L]: [string, $T]) => ({", "}), {})",
mapParam, accParam, keyParam, valueParam, symbolProvider.toSymbol(mapMember), () -> {
writer.write("...$L,", accParam);
writer.openBlock("[$L]: ", ",", keyParam, () -> {
writeMemberFilterSensitiveLog(writer, mapMember, valueParam);
});
}
);
}

String accParam = "acc"; // accumulator for the reducer
String keyParam = "key"; // key of the Object.entries() key-value pair
String valueParam = "value"; // value of the Object.entries() key-value pair

// Reducer is common to all shapes.
writer.openBlock("Object.entries($L).reduce(($L: any, [$L, $L]: [string, $T]) => ({", "}), {})",
mapParam, accParam, keyParam, valueParam, symbolProvider.toSymbol(mapMember), () -> {
writer.write("...$L,", accParam);
Shape mapMemberTarget = model.expectShape(mapMember.getTarget());
writer.openBlock("[$L]: ", ",", keyParam, () -> {
if (mapMemberTarget instanceof StructureShape) {
writeStructureFilterSensitiveLog(writer, mapMemberTarget, valueParam);
} else if (mapMemberTarget instanceof CollectionShape) {
MemberShape collectionMember = ((CollectionShape) mapMemberTarget).getMember();
writeCollectionFilterSensitiveLog(writer, collectionMember, valueParam);
} else if (mapMemberTarget instanceof MapShape) {
MemberShape nestedMapMember = ((MapShape) mapMemberTarget).getValue();
writeMapFilterSensitiveLog(writer, nestedMapMember, valueParam);
} else {
// This path should not reach because of recursive isMemberOverwriteRequired.
throw new CodegenException(String.format(
"MapFilterSensitiveLog attempted for %s while it was not required",
mapMemberTarget.getType()
));
// For quick-fix in case of high severity issue:
// comment out the exception above and uncomment the line below.
// writer.write("$L", valueParam);
}

});
}
);
}

/**
Expand All @@ -209,7 +189,10 @@ private boolean isMemberOverwriteRequired(MemberShape member, Set<String> parent

Shape memberTarget = model.expectShape(member.getTarget());
parents.add(symbolProvider.toMemberName(member));
if (memberTarget instanceof StructureShape) {
if (memberTarget.isUnionShape()) {
// always call filterSensitiveLog for UnionShape
return true;
} else if (memberTarget.isStructureShape()) {
Collection<MemberShape> structureMemberList = ((StructureShape) memberTarget).getAllMembers().values();
for (MemberShape structureMember: structureMemberList) {
if (!parents.contains(symbolProvider.toMemberName(structureMember))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@
* if (value.bear !== undefined) return visitor.bear(value.bear);
* return visitor._(value.$unknown[0], value.$unknown[1]);
* }
* export const filterSensitiveLog = (obj: Attacker) => {
* if (obj.lion !== undefined)
* return { lion: Lion.filterSensitiveLog(obj.lion) };
* if (obj.tiger !== undefined)
* return { tiger: Tiger.filterSensitiveLog(obj.tiger) };
* if (obj.bear !== undefined)
* return { bear: Bear.filterSensitiveLog(obj.bear) };
* if (obj.$unknown !== undefined)
* return { [obj.$unknown[0]]: 'UNKNOWN' };
* }
* }
* }</pre>
*
Expand Down Expand Up @@ -148,13 +158,15 @@ public void run() {
writeUnionMemberInterfaces();
writeVisitorType();
writeVisitorFunction();
writeFilterSensitiveLog();
});
}

private void writeUnionMemberInterfaces() {
writer.openBlock("interface $$Base {", "}", () -> {
writer.write("__type?: $S;", shape.getId().getName());
});
writer.write("");

for (MemberShape member : shape.getAllMembers().values()) {
String name = variantMap.get(member.getMemberName());
Expand All @@ -170,6 +182,7 @@ private void writeUnionMemberInterfaces() {
}
writer.write("$$unknown?: never;");
});
writer.write("");
}

// Write out the unknown variant.
Expand All @@ -179,6 +192,7 @@ private void writeUnionMemberInterfaces() {
}
writer.write("$$unknown: [string, any];");
});
writer.write("");
}

private void writeVisitorType() {
Expand All @@ -189,6 +203,7 @@ private void writeVisitorType() {
}
writer.write("_: (name: string, value: any) => T;");
});
writer.write("");
}

private void writeVisitorFunction() {
Expand All @@ -203,5 +218,28 @@ private void writeVisitorFunction() {
}
writer.write("return visitor._(value.$$unknown[0], value.$$unknown[1]);");
writer.dedent().write("}");
writer.write("");
}

private void writeFilterSensitiveLog() {
String objectParam = "obj";
writer.openBlock("export const filterSensitiveLog = ($L: $L): any => {", "}",
objectParam, symbol.getName(),
() -> {
for (MemberShape member : shape.getAllMembers().values()) {
String memberName = symbolProvider.toMemberName(member);
StructuredMemberWriter structuredMemberWriter = new StructuredMemberWriter(
model, symbolProvider, shape.getAllMembers().values());
writer.openBlock("if (${1L}.${2L} !== undefined) return {${2L}: ", "};",
objectParam, memberName, () -> {
String memberParam = String.format("%s.%s", objectParam, memberName);
structuredMemberWriter.writeMemberFilterSensitiveLog(writer, member, memberParam);
}
);
}
writer.write("if (${1L}.$$unknown !== undefined) return {[${1L}.$$unknown[0]]: 'UNKNOWN'};",
objectParam);
}
);
}
}
Loading