UpgradeCheck
Check content pack upgrade impacts and display changes. Packs argument is comma separated list of content pack names, or blank for all content packs to assess.
python · Content Testing
Source
import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 INDENT = "##### " def NewVersion(curver): parts = curver.split(".") parts[2] = str(int(parts[2]) + 1) return ".".join(parts) def NewMinVersion(curver): parts = curver.split(".") parts[2] = "0" parts[1] = str(int(parts[1]) + 1) return ".".join(parts) def NewMajVersion(curver): parts = curver.split(".") parts[2] = "0" parts[1] = "0" parts[0] = str(int(parts[0]) + 1) return ".".join(parts) def CleanMarkdown(text): return re.sub('["*","#","-", ":"]', "", text) def ChangeList(text): commits = text.split("\n") changes = [] for line in commits: if line != "" and line != "- ": changes.append(line.strip().replace("- ", "").replace("-", "")) return changes def CheckUpdates(packs, types, playbook, layout): pbupdated = False loupdated = False for p in packs: if p in types: if types[p]["playbook"] == playbook: pbupdated = True if types[p]["layout"] == layout: loupdated = True return pbupdated, loupdated def GetUpgradedPacks(): response = execute_command("core-api-get", {"uri": "/contentpacks/installed-expired", "body": ""})["response"] upgradePacks = {} changesPacks = {} for r in response: if "updateAvailable" in r and r["updateAvailable"]: packid = r["packID"] upgradePacks[packid] = r changes = "" breaking = "" newver = NewVersion(r["currentVersion"]) if newver in r["changelog"]: changes = r["changelog"][newver]["releaseNotes"] breaking = r["changelog"][newver]["breakingChangesNotes"] newver = NewMinVersion(r["currentVersion"]) if newver in r["changelog"]: changes = r["changelog"][newver]["releaseNotes"] breaking = r["changelog"][newver]["breakingChangesNotes"] newver = NewMajVersion(r["currentVersion"]) if newver in r["changelog"]: changes = r["changelog"][newver]["releaseNotes"] breaking = r["changelog"][newver]["breakingChangesNotes"] changesPacks[packid] = {"changes": changes, "breaking": breaking} return upgradePacks, changesPacks def FilterPacks(packs, upgradePacks, changesPacks): packlist = [p.lower().replace(" ", "") for p in packs.split(",")] if len(packlist) == 1 and packlist[0] == "": return upgradePacks, changesPacks newUpgrade = {} for packid, pack in upgradePacks.items(): if packid.lower().replace(" ", "") in packlist: newUpgrade[packid] = pack else: del changesPacks[packid] return newUpgrade, changesPacks def GetUpgradedIntegrations(packs): response = execute_command("core-api-post", {"uri": "/settings/integration/search", "body": {}})["response"] configs = response["configurations"] instances = response["instances"] integrations = {} integmap = {} for packid, p in packs.items(): integs = p["contentItems"].get("integration", []) if integs is not None: for i in integs: integmap[i["name"]] = packid for c in configs: instid = c["id"] if c["packName"] == "Palo Alto Networks Cortex XDR - Investigation and Response": instid = "Palo Alto Networks Cortex XDR - Investigation and Response" if instid in integmap: packid = integmap[instid] integrations[packid] = { "classifier": c.get("defaultClassifier", ""), "mapperin": c.get("defaultMapperIn", ""), "mapperout": c.get("defaultMapperOut", ""), "instance": "", } for i in instances: instid = i["brand"] name = i["name"] if instid == "Cortex XDR - IR": instid = "Palo Alto Networks Cortex XDR - Investigation and Response" if instid in integmap: packid = integmap[instid] integrations[packid]["instance"] = name return integrations def GetCustomPlaybooks(): response = execute_command( "core-api-post", {"uri": "/playbook/search", "body": {"query": "system:F AND hidden:F AND deprecated:F"}} )["response"]["playbooks"] playbooks = [] for r in response: playbooks.append(r) return playbooks def GetFieldKey(inoutfield): if type(inoutfield) is list: output = [] for item in inoutfield: if "key" in item: output.append(item["key"]) elif "contextPath" in item: output.append(item["contextPath"]) else: output.append(item) output = ",".join(output) else: output = re.sub('["$","{","}"]', "", inoutfield) return output def GetFieldsUsed(playbooks): usedfields: dict[str, list[str]] usedfields = {} regex = re.compile(r"\$\{incident\.[^}]+\}") for p in playbooks: name = p["name"] usedfields[name] = [] if p["inputs"] is not None: usedfields[name].append(GetFieldKey(p["inputs"])) if p["outputs"] is not None: usedfields[name].append(GetFieldKey(p["outputs"])) for _key, t in p["tasks"].items(): if "scriptArguments" in t: for m in regex.findall(json.dumps(t)): usedfields[name].append(GetFieldKey(m)) return usedfields def GetSubplaybooksUsed(playbooks): usedplaybooks = [] for p in playbooks: for _key, t in p["tasks"].items(): if t["type"] == "playbook" and "name" in p and "name" in t["task"]: usedplaybooks.append({"parent": p["name"], "child": t["task"]["name"]}) return usedplaybooks def GetAutomationsUsed(playbooks): automations = [] for p in playbooks: if len(p["scriptIds"]) != 0: for s in p["scriptIds"]: if "name" in p: automations.append({"playbook": p["name"], "scripts": s}) return automations def GetUpgradedScripts(packs, scripts): scriptdict = {} for _index, value in enumerate(scripts): scriptdict[value["scripts"]] = value upgscripts = [] for p in packs: response = execute_command("core-api-get", {"uri": f"/contentpacks/marketplace/{p}", "body": ""})["response"] automations = response["contentItems"]["automation"] if automations is not None: for a in automations: if a["name"] in scriptdict: s = scriptdict[a["name"]] upgscripts.append({"playbook": s["playbook"], "pack": p, "script": s["scripts"]}) return upgscripts def GetUpgradedIncidentTypes(packs): response = execute_command("core-api-get", {"uri": "/incidenttype", "body": ""})["response"] uptypes = {} custtypes = [] for r in response: pb = r.get("playbookId", "<none>") lo = r.get("layout", "<none>") if not r["system"]: custype = {"id": r["id"], "playbook": pb, "layout": lo, "packid": "<none>"} custtypes.append(custype) pi = r.get("packID", "<none>") if pi in packs: uptypes[pi] = {"playbook": pb, "layout": lo, "packid": pi} return (uptypes, custtypes) def BuildItem(pack, key): md = f"{key}:\n" items = pack["contentItems"][key] if items is not None: for i in items: if "name" in i: md += f"{i['name']}\n" if md != f"{key}:\n": return md return "" def ImpactMD(upgradePacks, integinstances, types, custypes, subplaybooks, upgradescripts, usedfields): md = "" md += "#### Custom_Playbooks:\n" md += f"{INDENT}Automations_Used:\n" md += "|Custom Playbook|Content Pack|Automation|\n" md += "|---|---|---|\n" for s in upgradescripts: md += f"| {s['playbook']} | {s['pack']} | {s['script']} |\n" md += f"{INDENT}Subplaybooks_Used:\n" md += "|Playbook|Sub-Playbook|\n" md += "|---|---|\n" for p in subplaybooks: md += f"| {p['parent']} | {p['child']} |\n" md += f"{INDENT}Fields_Used_Inputs_Outputs:\n" md += "|Playbook|Fields|\n" md += "|---|---|\n" for key, val in usedfields.items(): for f in val: md += f"| {key} | {f} |\n" md += "#### Custom_Incident_Types:\n" md += "|Incident Type|Object Type|Object|\n" md += "|---|---|---|\n" for c in custypes: if c["id"] != "Unclassified": pbupd, loupd = CheckUpdates(upgradePacks, types, c["playbook"], c["layout"]) if pbupd: md += f"| {c['id']} | Playbook | {c['playbook']} |\n" if loupd: md += f"| {c['id']} | Layout | {c['layout']} |\n" md += "#### Integration_Instances:\n" for _key, i in integinstances.items(): if i["instance"] != "": md += f"{INDENT}Instance: {i['instance']}\n" if i["classifier"] != "": md += f"Classifier: {i['classifier']}\n" if i["mapperin"] != "": md += f"Mapperin: {i['mapperin']}\n" if i["mapperout"] != "": md += f"Mapperout: {i['mapperout']}\n" return md def UpgradeMD(upgradePacks, changes): md = "" for p in upgradePacks: md += f"\n#### {p}:\n" newmd = BuildItem(upgradePacks[p], "incidentfield") if newmd != "": md += f"{INDENT} {newmd}" newmd = BuildItem(upgradePacks[p], "integration") if newmd != "": md += f"{INDENT} {newmd}" newmd = BuildItem(upgradePacks[p], "incidenttype") if newmd != "": md += f"{INDENT} {newmd}" newmd = BuildItem(upgradePacks[p], "playbook") if newmd != "": md += f"{INDENT} {newmd}" newmd = BuildItem(upgradePacks[p], "layoutscontainer") if newmd != "": md += f"{INDENT} {newmd}" newmd = BuildItem(upgradePacks[p], "automation") if newmd != "": md += f"{INDENT} {newmd}" md += f"{INDENT}changes:\n" chglist = ChangeList(CleanMarkdown(changes[p]["changes"])) if chglist is not None: for c in chglist: md += f"{c}\n" breaking = CleanMarkdown(changes[p]["breaking"]) if breaking.strip() != "": md += f"{INDENT}breaking:\n" md += f"{breaking}\n" return md def main(): try: packs = demisto.args().get("packs", "") upgradePacks, changesPacks = GetUpgradedPacks() upgradePacks, changesPacks = FilterPacks(packs, upgradePacks, changesPacks) upgradeIntegs = GetUpgradedIntegrations(upgradePacks) upgradeTypes, customTypes = GetUpgradedIncidentTypes(upgradePacks) playbooks = GetCustomPlaybooks() subplaybooks = GetSubplaybooksUsed(playbooks) scripts = GetAutomationsUsed(playbooks) fields = GetFieldsUsed(playbooks) upgradeScripts = GetUpgradedScripts(changesPacks, scripts) impact = ImpactMD(upgradePacks, upgradeIntegs, upgradeTypes, customTypes, subplaybooks, upgradeScripts, fields) demisto.executeCommand("setIncident", {"customFields": json.dumps({"contenttestingcontentimpacts": impact})}) details = UpgradeMD(upgradePacks, changesPacks) demisto.executeCommand("setIncident", {"customFields": json.dumps({"contenttestingcontentdetails": details})}) except Exception as ex: demisto.error(traceback.format_exc()) return_error(f"UpgradeCheck: Exception failed to execute. Error: {ex!s}") if __name__ in ("__main__", "__builtin__", "builtins"): main()
README
Check content pack upgrade impacts and display changes. Packs argument is comma separated list of content pack names, or blank for all content packs to assess.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
Inputs
| Argument Name | Description |
|---|---|
| packs | Comma separated list of packs that should be analyzed. |
Outputs
There are no outputs for this script.