source/playbooks/CIS120/ssmdocs/scripts/cis_parse_input.py [21:94]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        finding_id_arn
    )
    if check_finding_id:
        control_id = check_finding_id.group(1)
        return control_id
    else:
        exit(f'ERROR: Finding Id is invalid: {finding_id_arn}')

def parse_event(event, context):
    expected_control_id = event['expected_control_id']
    parse_id_pattern = event['parse_id_pattern']
    resource_id_matches = []
    finding = event['Finding']
    testmode = bool('testmode' in finding)

    finding_id = finding['Id']
        
    account_id = finding.get('AwsAccountId', '')
    if not re.match('^\\d{12}$', account_id):
        exit(f'ERROR: AwsAccountId is invalid: {account_id}')

    control_id = get_control_id_from_arn(finding['Id'])

    # ControlId present and valid
    if not control_id:
        exit(f'ERROR: Finding Id is invalid: {finding_id} - missing Control Id')

    # ControlId is the expected value
    if control_id not in expected_control_id:
        exit(f'ERROR: Control Id from input ({control_id}) does not match {str(expected_control_id)}')

    # ProductArn present and valid
    product_arn = finding['ProductArn']
    if not re.match('^arn:(?:aws|aws-cn|aws-us-gov):securityhub:(?:[a-z]{2}(?:-gov)?-[a-z]+-\\d)::product/aws/securityhub$', product_arn):
        exit(f'ERROR: ProductArn is invalid: {product_arn}')

    resource = finding['Resources'][0]

    # Details
    details = finding['Resources'][0].get('Details', {})

    # Regex match Id to get remediation-specific identifier
    identifier_raw = finding['Resources'][0]['Id']
    resource_id = identifier_raw

    if parse_id_pattern:
        identifier_match = re.match(
            parse_id_pattern,
            identifier_raw
        )

        if identifier_match:
            for group in range(1, len(identifier_match.groups())+1):
                resource_id_matches.append(identifier_match.group(group))
            resource_id = identifier_match.group(event.get('resource_index', 1))
        else:
            exit(f'ERROR: Invalid resource Id {identifier_raw}')   

    if not resource_id:
        exit('ERROR: Resource Id is missing from the finding json Resources (Id)')

    affected_object = {'Type': resource['Type'], 'Id': resource_id, 'OutputKey': 'Remediation.Output'}
    return {
        "account_id": account_id,
        "resource_id": resource_id, 
        "finding_id": finding_id, 
        "control_id": control_id,
        "product_arn": product_arn, 
        "object": affected_object,
        "matches": resource_id_matches,
        "details": details,
        "testmode": testmode,
        "resource": resource
    }
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



source/playbooks/PCI321/ssmdocs/scripts/pci_parse_input.py [21:94]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        finding_id_arn
    )
    if check_finding_id:
        control_id = check_finding_id.group(1)
        return control_id
    else:
        exit(f'ERROR: Finding Id is invalid: {finding_id_arn}')

def parse_event(event, context):
    expected_control_id = event['expected_control_id']
    parse_id_pattern = event['parse_id_pattern']
    resource_id_matches = []
    finding = event['Finding']
    testmode = bool('testmode' in finding)

    finding_id = finding['Id']
        
    account_id = finding.get('AwsAccountId', '')
    if not re.match('^\\d{12}$', account_id):
        exit(f'ERROR: AwsAccountId is invalid: {account_id}')

    control_id = get_control_id_from_arn(finding['Id'])

    # ControlId present and valid
    if not control_id:
        exit(f'ERROR: Finding Id is invalid: {finding_id} - missing Control Id')

    # ControlId is the expected value
    if control_id not in expected_control_id:
        exit(f'ERROR: Control Id from input ({control_id}) does not match {str(expected_control_id)}')

    # ProductArn present and valid
    product_arn = finding['ProductArn']
    if not re.match('^arn:(?:aws|aws-cn|aws-us-gov):securityhub:(?:[a-z]{2}(?:-gov)?-[a-z]+-\\d)::product/aws/securityhub$', product_arn):
        exit(f'ERROR: ProductArn is invalid: {product_arn}')

    resource = finding['Resources'][0]

    # Details
    details = finding['Resources'][0].get('Details', {})

    # Regex match Id to get remediation-specific identifier
    identifier_raw = finding['Resources'][0]['Id']
    resource_id = identifier_raw

    if parse_id_pattern:
        identifier_match = re.match(
            parse_id_pattern,
            identifier_raw
        )

        if identifier_match:
            for group in range(1, len(identifier_match.groups())+1):
                resource_id_matches.append(identifier_match.group(group))
            resource_id = identifier_match.group(event.get('resource_index', 1))
        else:
            exit(f'ERROR: Invalid resource Id {identifier_raw}')   

    if not resource_id:
        exit('ERROR: Resource Id is missing from the finding json Resources (Id)')

    affected_object = {'Type': resource['Type'], 'Id': resource_id, 'OutputKey': 'Remediation.Output'}
    return {
        "account_id": account_id,
        "resource_id": resource_id, 
        "finding_id": finding_id, 
        "control_id": control_id,
        "product_arn": product_arn, 
        "object": affected_object,
        "matches": resource_id_matches,
        "details": details,
        "testmode": testmode,
        "resource": resource
    }
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



