# Buggy code
def _attach_firewall_rules(neo4j_session, fw, gcp_update_tag):
    """
    Attach the allow_rules to the Firewall object
    :param neo4j_session: The Neo4j session
    :param fw: The Firewall object
    :param gcp_update_tag: The timestamp
    :return: Nothing
    """
    query = """
    MATCH (fw:GCPFirewall{id:{FwPartialUri}})

    MERGE (rule:IpRule:IpPermissionInbound:GCPIpRule{id:{RuleId}})
    ON CREATE SET rule.firstseen = timestamp(),
    rule.ruleid = {RuleId}
    SET rule.protocol = {Protocol},
    rule.fromport = {FromPort},
    rule.toport = {ToPort},
    rule.lastupdated = {gcp_update_tag}

    MERGE (rng:IpRange{id:{Range}})
    ON CREATE SET rng.firstseen = timestamp(),
    rng.range = {Range}
    SET rng.lastupdated = {gcp_update_tag}

    MERGE (rng)-[m:MEMBER_OF_IP_RULE]->(rule)
    ON CREATE SET m.firstseen = timestamp()
    SET m.lastupdated = {gcp_update_tag}
    """
    for list_type in "transformed_allow_list", "transformed_deny_list":
        if list_type == "transformed_allow_list":
            query += """
            MERGE (fw)<-[r:ALLOWED_BY]-(rule)
            ON CREATE SET r.firstseen = timestamp()
            SET r.lastupdated = {gcp_update_tag}
            """
        else:
            query += """
            MERGE (fw)<-[r:DENIED_BY]-(rule)
            ON CREATE SET r.firstseen = timestamp()
            SET r.lastupdated = {gcp_update_tag}
            """
        for rule in fw[list_type]:
            # It is possible for sourceRanges to not be specified for this rule
            # If sourceRanges is not specified then the rule must specify sourceTags.
            # Since an IP range cannot have a tag applied to it, it is ok if we don't ingest this rule.
            for ip_range in fw.get("sourceRanges", []):
                neo4j_session.run(
                    query,
                    FwPartialUri=fw["id"],
                    RuleId=rule["ruleid"],
                    Protocol=rule["protocol"],
                    FromPort=rule.get("fromport"),
                    ToPort=rule.get("toport"),
                    Range=ip_range,
                    gcp_update_tag=gcp_update_tag,
                )


# Traceback (neobolt.exceptions.CypherSyntaxError)
...
INFO:cartography.sync:Finishing sync stage 'aws'
INFO:cartography.sync:Starting sync stage 'gcp'
INFO:oauth2client.transport:Attempting refresh to obtain initial access_token
INFO:oauth2client.client:Refreshing access_token
INFO:oauth2client.transport:Attempting refresh to obtain initial access_token
INFO:oauth2client.client:Refreshing access_token
INFO:cartography.intel.gcp:Syncing GCP project example-project.
INFO:cartography.intel.gcp.compute:Syncing Compute objects for project example-project.
INFO:oauth2client.transport:Attempting refresh to obtain initial access_token
INFO:oauth2client.client:Refreshing access_token

ERROR:cartography.graph.job:Unhandled error while executing statement in job 'cleanup GCP Instances': Variable `r` already declared (line 25, column 26 (offset: 799))
" MERGE (fw)<-[r:DENIED_BY]-(rule)"
^
ERROR:cartography.sync:Unhandled exception during sync stage 'gcp'
Traceback (most recent call last):
File "/usr/lib/python3.7/site-packages/cartography/sync.py", line 68, in run
stage_func(neo4j_session, config)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/__init__.py", line 134, in start_gcp_ingestion
_sync_multiple_projects(neo4j_session, resources, projects, config.update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/__init__.py", line 94, in _sync_multiple_projects
_sync_single_project(neo4j_session, resources, project_id, gcp_update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/__init__.py", line 72, in _sync_single_project
compute.sync(neo4j_session, resources.compute, project_id, gcp_update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/compute.py", line 948, in sync
sync_gcp_firewall_rules(neo4j_session, compute, project_id, gcp_update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/compute.py", line 911, in sync_gcp_firewall_rules
cleanup_gcp_firewall_rules(neo4j_session, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/compute.py", line 853, in cleanup_gcp_firewall_rules
run_cleanup_job('gcp_compute_firewall_cleanup.json', neo4j_session, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/util.py", line 29, in run_cleanup_job
common_job_parameters,
File "/usr/lib/python3.7/site-packages/cartography/graph/job.py", line 95, in run_from_json
job.run(neo4j_session)
File "/usr/lib/python3.7/site-packages/cartography/graph/job.py", line 45, in run
stm.run(neo4j_session)
File "/usr/lib/python3.7/site-packages/cartography/graph/statement.py", line 47, in run
self._run_iterative(session)
File "/usr/lib/python3.7/site-packages/cartography/graph/statement.py", line 81, in _run_iterative
for r in results:
File "/usr/lib/python3.7/site-packages/neo4j/__init__.py", line 948, in records
self._session.fetch()
File "/usr/lib/python3.7/site-packages/neo4j/__init__.py", line 523, in fetch
detail_count, _ = self._connection.fetch()
File "/usr/lib/python3.7/site-packages/neobolt/direct.py", line 422, in fetch
return self._fetch()
File "/usr/lib/python3.7/site-packages/neobolt/direct.py", line 464, in _fetch
response.on_failure(summary_metadata or {})
File "/usr/lib/python3.7/site-packages/neobolt/direct.py", line 759, in on_failure
raise CypherError.hydrate(**metadata)
neobolt.exceptions.CypherSyntaxError: Variable `r` already declared (line 25, column 26 (offset: 799))
" MERGE (fw)<-[r:DENIED_BY]-(rule)"
^
Traceback (most recent call last):
File "/usr/bin/cartography", line 11, in <module>
load_entry_point('cartography==0.10.0', 'console_scripts', 'cartography')()
File "/usr/lib/python3.7/site-packages/cartography/cli.py", line 182, in main
return CLI(default_sync, prog='cartography').main(argv)
File "/usr/lib/python3.7/site-packages/cartography/cli.py", line 162, in main
return cartography.sync.run_with_config(self.sync, config)
File "/usr/lib/python3.7/site-packages/cartography/sync.py", line 134, in run_with_config
return sync.run(neo4j_driver, config)
File "/usr/lib/python3.7/site-packages/cartography/sync.py", line 68, in run
stage_func(neo4j_session, config)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/__init__.py", line 134, in start_gcp_ingestion
_sync_multiple_projects(neo4j_session, resources, projects, config.update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/__init__.py", line 94, in _sync_multiple_projects
_sync_single_project(neo4j_session, resources, project_id, gcp_update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/__init__.py", line 72, in _sync_single_project
compute.sync(neo4j_session, resources.compute, project_id, gcp_update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/compute.py", line 948, in sync
sync_gcp_firewall_rules(neo4j_session, compute, project_id, gcp_update_tag, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/compute.py", line 911, in sync_gcp_firewall_rules
cleanup_gcp_firewall_rules(neo4j_session, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/intel/gcp/compute.py", line 853, in cleanup_gcp_firewall_rules
run_cleanup_job('gcp_compute_firewall_cleanup.json', neo4j_session, common_job_parameters)
File "/usr/lib/python3.7/site-packages/cartography/util.py", line 29, in run_cleanup_job
common_job_parameters,
File "/usr/lib/python3.7/site-packages/cartography/graph/job.py", line 95, in run_from_json
job.run(neo4j_session)
File "/usr/lib/python3.7/site-packages/cartography/graph/job.py", line 45, in run
stm.run(neo4j_session)
File "/usr/lib/python3.7/site-packages/cartography/graph/statement.py", line 47, in run
self._run_iterative(session)
File "/usr/lib/python3.7/site-packages/cartography/graph/statement.py", line 81, in _run_iterative
for r in results:
File "/usr/lib/python3.7/site-packages/neo4j/__init__.py", line 948, in records
self._session.fetch()
File "/usr/lib/python3.7/site-packages/neo4j/__init__.py", line 523, in fetch
detail_count, _ = self._connection.fetch()
File "/usr/lib/python3.7/site-packages/neobolt/direct.py", line 422, in fetch
return self._fetch()
File "/usr/lib/python3.7/site-packages/neobolt/direct.py", line 464, in _fetch
response.on_failure(summary_metadata or {})
File "/usr/lib/python3.7/site-packages/neobolt/direct.py", line 759, in on_failure
raise CypherError.hydrate(**metadata)
neobolt.exceptions.CypherSyntaxError: Variable `r` already declared (line 25, column 26 (offset: 799))
" MERGE (fw)<-[r:DENIED_BY]-(rule)"
^

# Fixed code
def _attach_firewall_rules(neo4j_session, fw, gcp_update_tag):
    """
    Attach the allow_rules to the Firewall object
    :param neo4j_session: The Neo4j session
    :param fw: The Firewall object
    :param gcp_update_tag: The timestamp
    :return: Nothing
    """
    template = Template("""
    MATCH (fw:GCPFirewall{id:{FwPartialUri}})

    MERGE (rule:IpRule:IpPermissionInbound:GCPIpRule{id:{RuleId}})
    ON CREATE SET rule.firstseen = timestamp(),
    rule.ruleid = {RuleId}
    SET rule.protocol = {Protocol},
    rule.fromport = {FromPort},
    rule.toport = {ToPort},
    rule.lastupdated = {gcp_update_tag}

    MERGE (rng:IpRange{id:{Range}})
    ON CREATE SET rng.firstseen = timestamp(),
    rng.range = {Range}
    SET rng.lastupdated = {gcp_update_tag}

    MERGE (rng)-[m:MEMBER_OF_IP_RULE]->(rule)
    ON CREATE SET m.firstseen = timestamp()
    SET m.lastupdated = {gcp_update_tag}

    MERGE (fw)<-[r:$fw_rule_relationship_label]-(rule)
    ON CREATE SET r.firstseen = timestamp()
    SET r.lastupdated = {gcp_update_tag}
    """)
    for list_type in "transformed_allow_list", "transformed_deny_list":
        if list_type == "transformed_allow_list":
            label = "ALLOWED_BY"
        else:
            label = "DENIED_BY"
        for rule in fw[list_type]:
            # It is possible for sourceRanges to not be specified for this rule
            # If sourceRanges is not specified then the rule must specify sourceTags.
            # Since an IP range cannot have a tag applied to it, it is ok if we don't ingest this rule.
            for ip_range in fw.get("sourceRanges", []):
                neo4j_session.run(
                    template.safe_substitute(fw_rule_relationship_label=label),
                    FwPartialUri=fw["id"],
                    RuleId=rule["ruleid"],
                    Protocol=rule["protocol"],
                    FromPort=rule.get("fromport"),
                    ToPort=rule.get("toport"),
                    Range=ip_range,
                    gcp_update_tag=gcp_update_tag,
                )