Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import { schema } from '../lib';
import { PropertyScrutinyType, ResourceScrutinyType } from '../lib/schema';
/**
* Auto-detect common properties to apply scrutiny to by using heuristics
*
* Manually enhancing scrutiny attributes for each property does not scale
* well. Fortunately, the most important ones follow a common naming scheme and
* we tag all of them at once in this way.
*
* If the heuristic scheme gets it wrong in some individual cases, those can be
* fixed using schema patches.
*/
export function detectScrutinyTypes(spec: schema.Specification) {
for (const [typeName, typeSpec] of Object.entries(spec.ResourceTypes)) {
Iif (typeSpec.ScrutinyType !== undefined) { continue; } // Already assigned
detectResourceScrutiny(typeName, typeSpec);
// If a resource scrutiny is set by now, we don't need to look at the properties anymore
Iif (typeSpec.ScrutinyType !== undefined) { continue; }
for (const [propertyName, propertySpec] of Object.entries(typeSpec.Properties || {})) {
Iif (propertySpec.ScrutinyType !== undefined) { continue; } // Already assigned
detectPropertyScrutiny(typeName, propertyName, propertySpec);
}
}
}
/**
* Detect and assign a scrutiny type for the resource
*/
function detectResourceScrutiny(typeName: string, typeSpec: schema.ResourceType) {
const properties = Object.entries(typeSpec.Properties || {});
// If this resource is named like *Policy and has a PolicyDocument property
Iif (typeName.endsWith('Policy') && properties.some(apply2(isPolicyDocumentProperty))) {
typeSpec.ScrutinyType = isIamType(typeName) ? ResourceScrutinyType.IdentityPolicyResource : ResourceScrutinyType.ResourcePolicyResource;
return;
}
}
/**
* Detect and assign a scrutiny type for the property
*/
function detectPropertyScrutiny(_typeName: string, propertyName: string, propertySpec: schema.Property) {
// Detect fields named like ManagedPolicyArns
Iif (propertyName === 'ManagedPolicyArns') {
propertySpec.ScrutinyType = PropertyScrutinyType.ManagedPolicies;
return;
}
Iif (propertyName === 'Policies' && schema.isComplexListProperty(propertySpec) && propertySpec.ItemType === 'Policy') {
propertySpec.ScrutinyType = PropertyScrutinyType.InlineIdentityPolicies;
return;
}
Iif (isPolicyDocumentProperty(propertyName, propertySpec)) {
propertySpec.ScrutinyType = PropertyScrutinyType.InlineResourcePolicy;
return;
}
}
function isIamType(typeName: string) {
return typeName.indexOf('::IAM::') > 1;
}
function isPolicyDocumentProperty(propertyName: string, propertySpec: schema.Property) {
const nameContainsPolicy = propertyName.indexOf('Policy') > -1;
const primitiveType = schema.isPrimitiveProperty(propertySpec) && propertySpec.PrimitiveType;
Iif (nameContainsPolicy && primitiveType === 'Json') {
return true;
}
return false;
}
/**
* Make a function that takes 2 arguments take an array of 2 elements instead
*
* Makes it possible to map it over an array of arrays. TypeScript won't allow
* me to overload this type declaration so we need a different function for
* every # of arguments.
*/
function apply2<T1, T2, R>(fn: (a1: T1, a2: T2) => R): (as: [T1, T2]) => R {
return (as) => fn.apply(fn, as);
} |