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); } |