diff --git a/.gitignore b/.gitignore index 697c693..d8b8728 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ dist pytaxonomies.egg-info *.swp *.pyc + +.ipynb_checkpoints diff --git a/notebooks/create_n_edit.ipynb b/notebooks/create_n_edit.ipynb new file mode 100644 index 0000000..8a27a96 --- /dev/null +++ b/notebooks/create_n_edit.ipynb @@ -0,0 +1,195 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create a new taxonomy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pytaxonomies import Taxonomy, Predicate, Entry\n", + "\n", + "new_taxonomy = Taxonomy()\n", + "\n", + "new_taxonomy.name = \"false-positive\"\n", + "new_taxonomy.description = \"This taxonomy aims to ballpark the expected amount of false positives.\"\n", + "new_taxonomy.version = 1\n", + "new_taxonomy.expanded = \"False positive\"\n", + "\n", + "risk_predicate = Predicate()\n", + "\n", + "risk_predicate.predicate = 'risk'\n", + "risk_predicate.expanded = 'Risk'\n", + "risk_predicate.description = 'Risk of having false positives in the tagged value.'\n", + "\n", + "low = Entry()\n", + "low.value = 'low'\n", + "low.expanded = 'Low'\n", + "low.description = 'The risk of having false positives in the tagged value is low.'\n", + "low.numerical_value = 25\n", + "\n", + "\n", + "medium = Entry()\n", + "medium.value = 'medium'\n", + "medium.expanded = 'Medium'\n", + "medium.description = 'The risk of having false positives in the tagged value is medium.'\n", + "medium.numerical_value = 50\n", + "\n", + "high = Entry()\n", + "high.value = 'high'\n", + "high.expanded = 'High'\n", + "high.description = 'The risk of having false positives in the tagged value is high.'\n", + "high.numerical_value = 75\n", + "\n", + "risk_predicate.entries = {}\n", + "risk_predicate.entries['low'] = low\n", + "risk_predicate.entries['medium'] = medium\n", + "risk_predicate.entries['high'] = high\n", + "\n", + "new_taxonomy.predicates = {}\n", + "new_taxonomy.predicates['risk'] = risk_predicate" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Add a taxonomy in the repository" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import json\n", + "\n", + "root_json = Path('..', 'pytaxonomies', 'data', 'misp-taxonomies')\n", + "\n", + "with open(root_json / 'MANIFEST.json', encoding='utf8') as m:\n", + " manifest = json.load(m)\n", + "\n", + "# Just a failsafe in case the new taxonomy needs to be modified\n", + "is_update = False\n", + "for t in manifest['taxonomies']:\n", + " if t['name'] == new_taxonomy.name:\n", + " is_update = True\n", + " t['version'] = new_taxonomy.version\n", + " t['description'] = new_taxonomy.description \n", + "\n", + "if not is_update:\n", + " manifest['taxonomies'].append({'version': new_taxonomy.version, 'name': new_taxonomy.name, 'description': new_taxonomy.description})\n", + "\n", + "with open(root_json / 'MANIFEST.json', 'w', encoding='utf8') as m:\n", + " json.dump(manifest, m, indent=2, ensure_ascii=False)\n", + " \n", + "\n", + "if not (root_json / new_taxonomy.name).exists():\n", + " (root_json / new_taxonomy.name).mkdir()\n", + "\n", + "with open(root_json / new_taxonomy.name / 'machinetag.json', 'w', encoding='utf8') as m:\n", + " json.dump(new_taxonomy.to_dict(), m, indent=2, ensure_ascii=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Edit a taxonomy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pytaxonomies import Taxonomies\n", + "\n", + "from pytaxonomies import Taxonomy, Predicate, Entry\n", + "\n", + "taxonomies = Taxonomies()\n", + "\n", + "edited_taxonomy = taxonomies[\"false-positive\"]\n", + "\n", + "edited_taxonomy.predicates['risk'].entries['low'].numerical_value = 20" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Save the edited taxonomy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import json\n", + "\n", + "root_json = Path('..', 'pytaxonomies', 'data', 'misp-taxonomies')\n", + "\n", + "with open(root_json / 'MANIFEST.json', encoding='utf8') as m:\n", + " manifest = json.load(m)\n", + " \n", + "# Just a failsafe in case the new taxonomy needs to be modified\n", + "is_update = False\n", + "for t in manifest['taxonomies']:\n", + " if t['name'] == edited_taxonomy.name:\n", + " is_update = True\n", + " t['version'] += 1\n", + " edited_taxonomy.version = t['version']\n", + " t['description'] = edited_taxonomy.description\n", + "\n", + "if not is_update:\n", + " raise Exception(f'Taxonomy {edited_taxonomy.name} does not exists in the manifest.')\n", + "\n", + "with open(root_json / 'MANIFEST.json', 'w', encoding='utf8') as m:\n", + " json.dump(manifest, m, indent=2, ensure_ascii=False)\n", + "\n", + "with open(root_json / edited_taxonomy.name / 'machinetag.json', 'w', encoding='utf8') as m:\n", + " json.dump(edited_taxonomy.to_dict(), m, indent=2, ensure_ascii=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/pytaxonomies/__init__.py b/pytaxonomies/__init__.py index 0a57f42..3a14dae 100644 --- a/pytaxonomies/__init__.py +++ b/pytaxonomies/__init__.py @@ -1 +1 @@ -from .api import Taxonomies, EncodeTaxonomies +from .api import Taxonomies, EncodeTaxonomies, Taxonomy, Predicate, Entry diff --git a/pytaxonomies/api.py b/pytaxonomies/api.py index fa6b099..37a110c 100644 --- a/pytaxonomies/api.py +++ b/pytaxonomies/api.py @@ -30,7 +30,14 @@ class EncodeTaxonomies(JSONEncoder): class Entry(): - def __init__(self, entry): + def __init__(self, entry=None): + if not entry: + # We're creating a new one + self.expanded = None + self.colour = None + self.description = None + self.numerical_value = None + return self.value = entry['value'] self.expanded = entry.get('expanded') self.colour = entry.get('colour') @@ -58,7 +65,16 @@ class Entry(): class Predicate(collections.Mapping): - def __init__(self, predicate, entries): + def __init__(self, predicate=None, entries=None): + if not predicate and not entries: + # We're creating a new one + self.expanded = None + self.description = None + self.colour = None + self.exclusive = None + self.numerical_value = None + self.entries = {} + return self.predicate = predicate['value'] self.expanded = predicate.get('expanded') self.description = predicate.get('description') @@ -107,7 +123,15 @@ class Predicate(collections.Mapping): class Taxonomy(collections.Mapping): - def __init__(self, taxonomy): + def __init__(self, taxonomy=None): + if not taxonomy: + # We're creating a new one + self.expanded = None + self.refs = None + self.type = None + self.exclusive = None + self.predicates = {} + return self.taxonomy = taxonomy self.name = self.taxonomy['namespace'] self.description = self.taxonomy['description'] diff --git a/pytaxonomies/data/misp-taxonomies b/pytaxonomies/data/misp-taxonomies index cc1910f..ca76147 160000 --- a/pytaxonomies/data/misp-taxonomies +++ b/pytaxonomies/data/misp-taxonomies @@ -1 +1 @@ -Subproject commit cc1910f1eef286f24fe2d5c3aefe88519d9d312c +Subproject commit ca76147d734b22fea663742886e97dfd8f654ee3