aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Janovsky2025-03-10 08:12:53 +0100
committerAdam Janovsky2025-03-10 08:12:53 +0100
commit66d4cae9fe932d4d341cf8b09e9709ade8c6effa (patch)
tree04e27392c5e496a793870b35bcae625c396b2869
parentc0288b91aaf6222d618b4b068b2fb78f75e3aa4a (diff)
parent035fc93d285608cf4fbb56539866bfc7352976cf (diff)
downloadsec-certs-66d4cae9fe932d4d341cf8b09e9709ade8c6effa.tar.gz
sec-certs-66d4cae9fe932d4d341cf8b09e9709ade8c6effa.tar.zst
sec-certs-66d4cae9fe932d4d341cf8b09e9709ade8c6effa.zip
merge main
-rw-r--r--.github/workflows/cron.yml1
-rw-r--r--notebooks/cc/llm_annotation.ipynb775
-rw-r--r--notebooks/cc/llm_annotation_prompt.txt26
-rw-r--r--pyproject.toml4
-rw-r--r--requirements/all_requirements.txt119
-rw-r--r--requirements/dev_requirements.txt44
-rw-r--r--requirements/nlp_requirements.txt100
-rw-r--r--requirements/requirements.txt18
-rw-r--r--requirements/test_requirements.txt23
-rw-r--r--src/sec_certs/constants.py2
-rw-r--r--src/sec_certs/dataset/auxiliary_dataset_handling.py2
-rw-r--r--src/sec_certs/dataset/cc.py16
-rw-r--r--src/sec_certs/dataset/fips.py10
-rw-r--r--src/sec_certs/dataset/protection_profile.py2
-rw-r--r--src/sec_certs/heuristics/cc.py2
-rw-r--r--src/sec_certs/heuristics/common.py2
-rw-r--r--src/sec_certs/heuristics/fips.py2
-rw-r--r--src/sec_certs/model/references_nlp/evaluation.py2
-rw-r--r--src/sec_certs/model/references_nlp/feature_extraction.py2
-rw-r--r--src/sec_certs/model/references_nlp/training.py2
-rw-r--r--src/sec_certs/sample/document_state.py2
-rw-r--r--src/sec_certs/serialization/pandas.py2
-rw-r--r--src/sec_certs/utils/cc_html_parsing.py2
-rw-r--r--src/sec_certs/utils/label_studio_utils.py2
-rw-r--r--src/sec_certs/utils/nvd_dataset_builder.py21
-rw-r--r--src/sec_certs/utils/plot_utils.py2
-rw-r--r--src/sec_certs/utils/profiling.py2
-rw-r--r--src/sec_certs/utils/tqdm.py2
28 files changed, 993 insertions, 196 deletions
diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml
index 426738a2..9640f86d 100644
--- a/.github/workflows/cron.yml
+++ b/.github/workflows/cron.yml
@@ -33,6 +33,7 @@ jobs:
python -m spacy download en_core_web_sm
- name: Run tests
run: pytest --cov=sec_certs -m "remote" tests
+ continue-on-error: true
- name: Code coverage upload
uses: codecov/codecov-action@v4
with:
diff --git a/notebooks/cc/llm_annotation.ipynb b/notebooks/cc/llm_annotation.ipynb
new file mode 100644
index 00000000..0888b920
--- /dev/null
+++ b/notebooks/cc/llm_annotation.ipynb
@@ -0,0 +1,775 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Annotating certificate references with LLMs\n",
+ "## Before you launch\n",
+ "1. Create a file `openai_api_key` in the root directory and paste your key there.\n",
+ "2. Make sure you have the CC dataset extracted into project `cc_data` in the project root directory.\n",
+ "## What is being done here\n",
+ "1. Obtain names, certificate IDs, digests, and old digests from the CCDataset.\n",
+ "2. Create an annotations dataframe based on the annotations in `src/sec_certs/data/reference_annotations/final/train.csv`.\n",
+ "3. Enrich the annotations dataframe with the raw texts in `cc_data/certs/reports/txt`.\n",
+ "4. Enrich the annotations dataframe with the old digests (the annotation dataframe uses old ones), target cert IDs, names and target names.\n",
+ "5. Call the OpenAI API with structured outputs to label the certificate reference based on instructions in `notebooks/llm_annotation_prompt.txt`\n",
+ "6. Analyze the metrics with a confusion matrix."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sec_certs.dataset.cc import CCDataset\n",
+ "from sec_certs.sample import CCCertificate\n",
+ "import pandas as pd\n",
+ "import csv\n",
+ "import os"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Method auxiliary_datasets_dir can only be called on backed dataset.\n",
+ "Method auxiliary_datasets_dir can only be called on backed dataset.\n",
+ "Method auxiliary_datasets_dir can only be called on backed dataset.\n",
+ "Method auxiliary_datasets_dir can only be called on backed dataset.\n",
+ "Method auxiliary_datasets_dir can only be called on backed dataset.\n",
+ "Method auxiliary_datasets_dir can only be called on backed dataset.\n"
+ ]
+ }
+ ],
+ "source": [
+ "if \"dgst_map.csv\" not in os.listdir():\n",
+ " # get dgst mappings\n",
+ " if os.path.exists(\"../../cc_data/dataset.json\"):\n",
+ " dset = CCDataset.from_json(\"../../cc_data/dataset.json\")\n",
+ " else:\n",
+ " dset = CCDataset.from_web()\n",
+ " data = [(row.name, row.heuristics.cert_id, row.dgst, row.old_dgst) for row in dset]\n",
+ " with open('dgst_map.csv', 'w', newline='') as file:\n",
+ " writer = csv.writer(file)\n",
+ " writer.writerow(['name', 'cert_id', 'dgst', 'old_dgst']) # Header\n",
+ " writer.writerows(data)\n",
+ "dgst_map_df = pd.read_csv(\"dgst_map.csv\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if not 'dset' in vars() and not 'dset' in globals():\n",
+ " dset = CCDataset.from_json(\"../../cc_data/dataset.json\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from sec_certs.model.references_nlp.segment_extractor import ReferenceSegmentExtractor"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "reports_path = '../../cc_data/certs/reports/txt'\n",
+ "if not os.path.exists(reports_path):\n",
+ " raise FileNotFoundError(f\"The reports directory {os.path.abspath(reports_path)} does not exist, make sure you have the CC dataset unpacked.\")\n",
+ "\n",
+ "reports_files = os.listdir(reports_path)\n",
+ "# print(reports_files)\n",
+ "def add_text_content(dgst: str):\n",
+ " if f\"{dgst}.txt\" not in reports_files:\n",
+ " return \"\"\n",
+ " return open(reports_path + \"/\" + dgst + \".txt\").read()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_annotations = pd.read_csv(\"../../src/sec_certs/data/reference_annotations/final/train.csv\") \\\n",
+ " .rename(columns={\"dgst\": \"old_dgst\", \"canonical_reference_keyword\": \"target_cert_id\"}) \\\n",
+ " .merge(dgst_map_df, on=\"old_dgst\") \\\n",
+ " .merge(dgst_map_df[[\"name\", \"cert_id\"]].rename(columns={\"name\": \"target_name\", \"cert_id\": \"target_cert_id\"}), on=\"target_cert_id\")\n",
+ "\n",
+ "## get fulltext\n",
+ "df_annotations[\"text_content\"] = df_annotations[\"dgst\"] \\\n",
+ " .apply(add_text_content)\n",
+ "\n",
+ "## get segments\n",
+ "if \"ref_segments.parquet\" not in os.listdir():\n",
+ " used_certs = []\n",
+ " for cert in dset:\n",
+ " if cert.dgst in df_annotations[\"dgst\"].values:\n",
+ " used_certs.append(cert)\n",
+ " extracted_refs = ReferenceSegmentExtractor()(used_certs)\n",
+ " extracted_refs.to_parquet(\"ref_segments.parquet\")\n",
+ "ref_segments = pd.read_parquet(\"ref_segments.parquet\")\n",
+ "\n",
+ "df_annotations = ref_segments.rename(columns={\"canonical_reference_keyword\": \"target_cert_id\"})[[\"dgst\", \"target_cert_id\", \"segments\", \"actual_reference_keywords\"]].merge(df_annotations, on=[\"dgst\", \"target_cert_id\"])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from enum import Enum\n",
+ "from pydantic import Field, BaseModel\n",
+ "from openai import AsyncOpenAI, RateLimitError\n",
+ "import asyncio\n",
+ "from openai.lib._pydantic import to_strict_json_schema\n",
+ "\n",
+ "class LabelType(Enum):\n",
+ " COMPONENT_USED = \"component_used\"\n",
+ " RE_EVALUATION = \"re-evaluation\"\n",
+ " EVALUATION_REUSED = \"evaluation_reused\"\n",
+ " PREVIOUS_VERSION = \"previous_version\"\n",
+ " COMPONENT_SHARED = \"component_shared\"\n",
+ " IRRELEVANT = \"irrelevant\"\n",
+ " NONE = \"none\"\n",
+ "\n",
+ "class SimplifiedLabelType(Enum):\n",
+ " COMPONENT_REUSE = \"component_reuse\"\n",
+ " PREDECESSOR = \"predecessor\" \n",
+ " NONE = \"none\"\n",
+ "\n",
+ "def convert_label_type(label: LabelType|str) -> SimplifiedLabelType:\n",
+ " if isinstance(label, LabelType):\n",
+ " label_value = label\n",
+ " else:\n",
+ " try:\n",
+ " label_value = LabelType(label)\n",
+ " except ValueError:\n",
+ " return SimplifiedLabelType.NONE\n",
+ " \n",
+ " if label_value in [LabelType.COMPONENT_USED, LabelType.EVALUATION_REUSED, LabelType.COMPONENT_SHARED]:\n",
+ " return SimplifiedLabelType.COMPONENT_REUSE\n",
+ " elif label_value in [LabelType.RE_EVALUATION, LabelType.PREVIOUS_VERSION]:\n",
+ " return SimplifiedLabelType.PREDECESSOR\n",
+ " return SimplifiedLabelType.NONE\n",
+ "\n",
+ "class LabelDetectionResult(BaseModel):\n",
+ " explanation: str = Field(description=\"Explain why this label was chosen.\")\n",
+ " label: LabelType = Field(description=\"Categorization of the relationship between the examined and referenced certificates.\")\n",
+ "\n",
+ "#label_detection_strict_schema = to_strict_json_schema(LabelDetectionResult)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "label\n",
+ "component_used 58\n",
+ "re-evaluation 16\n",
+ "evaluation_reused 11\n",
+ "previous_version 6\n",
+ "component_shared 5\n",
+ "irrelevant 2\n",
+ "Name: count, dtype: int64"
+ ]
+ },
+ "execution_count": 46,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_annotations.label.value_counts()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "label\n",
+ "component_reuse 74\n",
+ "predecessor 22\n",
+ "none 3\n",
+ "Name: count, dtype: int64"
+ ]
+ },
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_annotations.label.apply(convert_label_type).apply(lambda x: x.value).value_counts()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "API Key loaded: sk-proj-tco-...\n"
+ ]
+ }
+ ],
+ "source": [
+ "def load_api_key(filename: str) -> str:\n",
+ " try:\n",
+ " with open(filename, 'r') as file:\n",
+ " api_key = file.readline().strip()\n",
+ " return api_key\n",
+ " except FileNotFoundError:\n",
+ " raise Exception(f\"OpenAI API key not found at {filename}.\")\n",
+ "\n",
+ "api_key = load_api_key('../../openai_api_key')\n",
+ "openapi_model = \"gpt-4o-mini\"\n",
+ "print(f\"API Key loaded: {api_key[:12]}...\")\n",
+ "client = AsyncOpenAI(api_key=api_key)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from tqdm.asyncio import tqdm\n",
+ "import nest_asyncio # otherwise async tasks can't be called from a running event loop (jupyter)\n",
+ "nest_asyncio.apply()\n",
+ "import asyncio\n",
+ "\n",
+ "system_message = {\n",
+ " \"role\": \"system\",\n",
+ " \"content\": open(\"llm_annotation_prompt.txt\").read()\n",
+ "}\n",
+ "async def get_ai_label(text_content: str, name: str, target_name: str, cert_id: str, target_cert_id: str, verbose=False):\n",
+ " messages = [\n",
+ " system_message,\n",
+ " {\"role\": \"user\", \"content\": f\"\"\"\n",
+ " Task: Classify how certificate {cert_id} refers to certificate {target_cert_id}. Note that you are to classify ONLY this relationship, and not relationships to other mentioned certificates or their components. Refer to the instructions and examples in the system message.\n",
+ "\n",
+ " Target: {target_cert_id} ({target_name})\n",
+ " Reviewed: {cert_id} ({name})\n",
+ "\n",
+ " Text from the examined certificate {cert_id}:\n",
+ " '{text_content}'\n",
+ " \"\"\"}\n",
+ " ]\n",
+ " while True:\n",
+ " try:\n",
+ " completion = await client.beta.chat.completions.parse(\n",
+ " model=openapi_model,\n",
+ " messages=messages,\n",
+ " response_format=LabelDetectionResult\n",
+ " )\n",
+ " return completion.choices[0].message.parsed\n",
+ " except Exception as e:\n",
+ " wait_time = 60\n",
+ " if verbose:\n",
+ " print(f\"Error: {e}, retrying in {wait_time}s..\")\n",
+ " await asyncio.sleep(wait_time)\n",
+ "\n",
+ "async def process_row_async(text_content: str, name: str, target_name: str, cert_id: str, target_cert_id: str):\n",
+ " result = await get_ai_label(text_content, name, target_name, cert_id, target_cert_id)\n",
+ " return result.label.value, result.explanation\n",
+ "\n",
+ "async def process_dataframe_async_fulltext(df):\n",
+ " tasks = [process_row_async(\n",
+ " row[\"text_content\"], \n",
+ " row[\"name\"], \n",
+ " row[\"target_name\"],\n",
+ " row[\"cert_id\"],\n",
+ " row[\"target_cert_id\"]) for _, row in df.iterrows()]\n",
+ " results = []\n",
+ " for coro in tqdm(asyncio.as_completed(tasks), total=len(tasks)): # tracks actual completion\n",
+ " results.append(await coro)\n",
+ " return results\n",
+ "\n",
+ "async def process_dataframe_async_segments(df):\n",
+ " all_tasks = []\n",
+ " row_indices = []\n",
+ " \n",
+ " # flatten for async\n",
+ " for idx, row in df.iterrows():\n",
+ " segments = row[\"segments\"]\n",
+ " for segment in segments:\n",
+ " all_tasks.append(process_row_async(\n",
+ " segment,\n",
+ " row[\"name\"], \n",
+ " row[\"target_name\"],\n",
+ " row[\"cert_id\"],\n",
+ " row[\"target_cert_id\"]\n",
+ " ))\n",
+ " row_indices.append(idx)\n",
+ " \n",
+ " # async\n",
+ " results = []\n",
+ " for coro in tqdm(asyncio.as_completed(all_tasks), total=len(all_tasks)):\n",
+ " results.append(await coro)\n",
+ " \n",
+ " # reorganize and group\n",
+ " row_results = {}\n",
+ " for i, (label, explanation) in enumerate(results):\n",
+ " row_idx = row_indices[i]\n",
+ " if row_idx not in row_results:\n",
+ " row_results[row_idx] = {\"labels\": [], \"explanations\": []}\n",
+ " row_results[row_idx][\"labels\"].append(label)\n",
+ " row_results[row_idx][\"explanations\"].append(explanation)\n",
+ " \n",
+ " # vote on labels\n",
+ " final_results = []\n",
+ " for idx in sorted(row_results.keys()):\n",
+ " labels = row_results[idx][\"labels\"]\n",
+ " explanations = row_results[idx][\"explanations\"]\n",
+ " \n",
+ " if labels:\n",
+ " from collections import Counter\n",
+ " vote_results = Counter(labels)\n",
+ " final_label = vote_results.most_common(1)[0][0]\n",
+ " \n",
+ " # get explanation for the winning label\n",
+ " for i, label in enumerate(labels):\n",
+ " if label == final_label:\n",
+ " explanation = explanations[i]\n",
+ " break\n",
+ " else:\n",
+ " final_label = LabelType.NONE.value\n",
+ " explanation = \"No segments available for analysis\"\n",
+ " \n",
+ " final_results.append((final_label, explanation))\n",
+ " \n",
+ " return final_results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "100%|██████████| 406/406 [10:06<00:00, 1.49s/it] \n"
+ ]
+ }
+ ],
+ "source": [
+ "if \"llm_annotation_results_segments.parquet\" not in os.listdir():\n",
+ " results = asyncio.run(process_dataframe_async_segments(df_annotations))\n",
+ " df_annotations[\"gpt4omini_label\"], df_annotations[\"gpt4omini_reason\"] = zip(*results)\n",
+ " df_annotations.to_parquet(\"llm_annotation_results_segments.parquet\")\n",
+ "df_results = pd.read_parquet(\"llm_annotation_results_segments.parquet\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# running this cell costs about 0.15EUR with gpt4o-mini\n",
+ "\"\"\"\n",
+ "if \"llm_annotation_results.parquet\" not in os.listdir(): # delete the file if you want to re-run things\n",
+ " results = asyncio.run(process_dataframe_async(df_annotations))\n",
+ " df_annotations[\"gpt4omini_label\"], df_annotations[\"gpt4omini_reason\"] = zip(*results)\n",
+ " df_annotations.to_parquet(\"llm_annotation_results.parquet\")\n",
+ "df_results = pd.read_parquet(\"llm_annotation_results.parquet\")\n",
+ "\"\"\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 51,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "<div>\n",
+ "<style scoped>\n",
+ " .dataframe tbody tr th:only-of-type {\n",
+ " vertical-align: middle;\n",
+ " }\n",
+ "\n",
+ " .dataframe tbody tr th {\n",
+ " vertical-align: top;\n",
+ " }\n",
+ "\n",
+ " .dataframe thead th {\n",
+ " text-align: right;\n",
+ " }\n",
+ "</style>\n",
+ "<table border=\"1\" class=\"dataframe\">\n",
+ " <thead>\n",
+ " <tr style=\"text-align: right;\">\n",
+ " <th></th>\n",
+ " <th>target_cert_id</th>\n",
+ " <th>cert_id</th>\n",
+ " <th>name</th>\n",
+ " <th>target_name</th>\n",
+ " <th>label</th>\n",
+ " <th>comment</th>\n",
+ " <th>gpt4omini_label</th>\n",
+ " <th>gpt4omini_reason</th>\n",
+ " </tr>\n",
+ " </thead>\n",
+ " <tbody>\n",
+ " <tr>\n",
+ " <th>0</th>\n",
+ " <td>BSI-DSZ-CC-1040-2019</td>\n",
+ " <td>NSCIB-CC-0229284-CR</td>\n",
+ " <td>NXP eDoc Suite v3.5 on JCOP4 P71 - cryptovisio...</td>\n",
+ " <td>NXP Secure Smart Card Controller N7121 with IC...</td>\n",
+ " <td>component_used</td>\n",
+ " <td>None</td>\n",
+ " <td>re-evaluation</td>\n",
+ " <td>The text indicates that BSI-DSZ-CC-0961-2017 i...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>1</th>\n",
+ " <td>BSI-DSZ-CC-0827-V8-2020</td>\n",
+ " <td>BSI-DSZ-CC-1158-2020</td>\n",
+ " <td>Digital Tachograph DTCO 1381, Release 4.0e</td>\n",
+ " <td>Infineon Technologies Smart Card IC (Security ...</td>\n",
+ " <td>irrelevant</td>\n",
+ " <td>unclear</td>\n",
+ " <td>component_used</td>\n",
+ " <td>The relationship between ANSSI-CC-2018/18 and ...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>2</th>\n",
+ " <td>BSI-DSZ-CC-0782-2012</td>\n",
+ " <td>BSI-DSZ-CC-0879-2014</td>\n",
+ " <td>Infineon Security Controller M7893 B11 with op...</td>\n",
+ " <td>Infineon Security Controller M7892 B11 with op...</td>\n",
+ " <td>re-evaluation</td>\n",
+ " <td>None</td>\n",
+ " <td>component_used</td>\n",
+ " <td>The referenced certificate BSI-DSZ-CC-0891-V3-...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>3</th>\n",
+ " <td>BSI-DSZ-CC-0957-V2-2016</td>\n",
+ " <td>BSI-DSZ-CC-1035-2017</td>\n",
+ " <td>TCOS Secure Crypto Module Version 1.0 Release ...</td>\n",
+ " <td>TCOS Smart Meter Security Module Version 1.0 R...</td>\n",
+ " <td>evaluation_reused</td>\n",
+ " <td>unclear, mentions that this is a “re-evaluatio...</td>\n",
+ " <td>component_used</td>\n",
+ " <td>The certificate BSI-DSZ-CC-1040-2019 is refere...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>4</th>\n",
+ " <td>ANSSI-CC-2012/68</td>\n",
+ " <td>ANSSI-CC-2014/25</td>\n",
+ " <td>SOMA801STM - application BAC, version 1.0</td>\n",
+ " <td>Microcontrôleurs sécurisés SA23YR80/48 et SB23...</td>\n",
+ " <td>component_used</td>\n",
+ " <td>None</td>\n",
+ " <td>re-evaluation</td>\n",
+ " <td>The text indicates that BSI-DSZ-CC-0680-2010 i...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>...</th>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " <td>...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>94</th>\n",
+ " <td>ANSSI-CC-2018/40</td>\n",
+ " <td>ANSSI-CC-2020/71</td>\n",
+ " <td>S3FV9RR/S3FV9RQ/S3FV9RP/S3FV9RK 32-bit RISC Mi...</td>\n",
+ " <td>S3FV9RR/S3FV9RQ/S3FV9RP/S3FV9RK 32-bit RISC Mi...</td>\n",
+ " <td>previous_version</td>\n",
+ " <td>None</td>\n",
+ " <td>component_used</td>\n",
+ " <td>The examined certificate ANSSI-CC-2020/43 incl...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>95</th>\n",
+ " <td>BSI-DSZ-CC-0835-V2-2017</td>\n",
+ " <td>BSI-DSZ-CC-0836-V2-2017</td>\n",
+ " <td>TCOS Residence Permit Card Version 1.1 Release...</td>\n",
+ " <td>TCOS Residence Permit Card Version 1.1 Release...</td>\n",
+ " <td>component_shared</td>\n",
+ " <td>BAC, EAC thingy</td>\n",
+ " <td>re-evaluation</td>\n",
+ " <td>The evaluated certificate CSEC2014007 referenc...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>96</th>\n",
+ " <td>ANSSI-CC-2013/55</td>\n",
+ " <td>ANSSI-CC-2013/64</td>\n",
+ " <td>Carte à puce SLJ 52 Gxx yyy AL : application p...</td>\n",
+ " <td>Plateforme jTOP INFv#46 masquée sur composants...</td>\n",
+ " <td>component_used</td>\n",
+ " <td>None</td>\n",
+ " <td>none</td>\n",
+ " <td>The text from the examined certificate BSI-DSZ...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>97</th>\n",
+ " <td>ANSSI-CC-2018/52</td>\n",
+ " <td>ANSSI-CC-2018/55</td>\n",
+ " <td>P73N2M0B0.2C2</td>\n",
+ " <td>P73N2M0B0.202</td>\n",
+ " <td>component_used</td>\n",
+ " <td>None</td>\n",
+ " <td>component_used</td>\n",
+ " <td>The ANSSI-CC-2020/43 certificate makes a refer...</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>98</th>\n",
+ " <td>BSI-DSZ-CC-0410-2007</td>\n",
+ " <td>ANSSI-CC-2008/14</td>\n",
+ " <td>ID-One EPass 64 v2.0 with EAC ECC</td>\n",
+ " <td>NXP Secure Smart Card Controller P5CD080V0B, P...</td>\n",
+ " <td>component_used</td>\n",
+ " <td>None</td>\n",
+ " <td>previous_version</td>\n",
+ " <td>The certificate BSI-DSZ-CC-0911-2014 is refere...</td>\n",
+ " </tr>\n",
+ " </tbody>\n",
+ "</table>\n",
+ "<p>99 rows × 8 columns</p>\n",
+ "</div>"
+ ],
+ "text/plain": [
+ " target_cert_id cert_id \\\n",
+ "0 BSI-DSZ-CC-1040-2019 NSCIB-CC-0229284-CR \n",
+ "1 BSI-DSZ-CC-0827-V8-2020 BSI-DSZ-CC-1158-2020 \n",
+ "2 BSI-DSZ-CC-0782-2012 BSI-DSZ-CC-0879-2014 \n",
+ "3 BSI-DSZ-CC-0957-V2-2016 BSI-DSZ-CC-1035-2017 \n",
+ "4 ANSSI-CC-2012/68 ANSSI-CC-2014/25 \n",
+ ".. ... ... \n",
+ "94 ANSSI-CC-2018/40 ANSSI-CC-2020/71 \n",
+ "95 BSI-DSZ-CC-0835-V2-2017 BSI-DSZ-CC-0836-V2-2017 \n",
+ "96 ANSSI-CC-2013/55 ANSSI-CC-2013/64 \n",
+ "97 ANSSI-CC-2018/52 ANSSI-CC-2018/55 \n",
+ "98 BSI-DSZ-CC-0410-2007 ANSSI-CC-2008/14 \n",
+ "\n",
+ " name \\\n",
+ "0 NXP eDoc Suite v3.5 on JCOP4 P71 - cryptovisio... \n",
+ "1 Digital Tachograph DTCO 1381, Release 4.0e \n",
+ "2 Infineon Security Controller M7893 B11 with op... \n",
+ "3 TCOS Secure Crypto Module Version 1.0 Release ... \n",
+ "4 SOMA801STM - application BAC, version 1.0 \n",
+ ".. ... \n",
+ "94 S3FV9RR/S3FV9RQ/S3FV9RP/S3FV9RK 32-bit RISC Mi... \n",
+ "95 TCOS Residence Permit Card Version 1.1 Release... \n",
+ "96 Carte à puce SLJ 52 Gxx yyy AL : application p... \n",
+ "97 P73N2M0B0.2C2 \n",
+ "98 ID-One EPass 64 v2.0 with EAC ECC \n",
+ "\n",
+ " target_name label \\\n",
+ "0 NXP Secure Smart Card Controller N7121 with IC... component_used \n",
+ "1 Infineon Technologies Smart Card IC (Security ... irrelevant \n",
+ "2 Infineon Security Controller M7892 B11 with op... re-evaluation \n",
+ "3 TCOS Smart Meter Security Module Version 1.0 R... evaluation_reused \n",
+ "4 Microcontrôleurs sécurisés SA23YR80/48 et SB23... component_used \n",
+ ".. ... ... \n",
+ "94 S3FV9RR/S3FV9RQ/S3FV9RP/S3FV9RK 32-bit RISC Mi... previous_version \n",
+ "95 TCOS Residence Permit Card Version 1.1 Release... component_shared \n",
+ "96 Plateforme jTOP INFv#46 masquée sur composants... component_used \n",
+ "97 P73N2M0B0.202 component_used \n",
+ "98 NXP Secure Smart Card Controller P5CD080V0B, P... component_used \n",
+ "\n",
+ " comment gpt4omini_label \\\n",
+ "0 None re-evaluation \n",
+ "1 unclear component_used \n",
+ "2 None component_used \n",
+ "3 unclear, mentions that this is a “re-evaluatio... component_used \n",
+ "4 None re-evaluation \n",
+ ".. ... ... \n",
+ "94 None component_used \n",
+ "95 BAC, EAC thingy re-evaluation \n",
+ "96 None none \n",
+ "97 None component_used \n",
+ "98 None previous_version \n",
+ "\n",
+ " gpt4omini_reason \n",
+ "0 The text indicates that BSI-DSZ-CC-0961-2017 i... \n",
+ "1 The relationship between ANSSI-CC-2018/18 and ... \n",
+ "2 The referenced certificate BSI-DSZ-CC-0891-V3-... \n",
+ "3 The certificate BSI-DSZ-CC-1040-2019 is refere... \n",
+ "4 The text indicates that BSI-DSZ-CC-0680-2010 i... \n",
+ ".. ... \n",
+ "94 The examined certificate ANSSI-CC-2020/43 incl... \n",
+ "95 The evaluated certificate CSEC2014007 referenc... \n",
+ "96 The text from the examined certificate BSI-DSZ... \n",
+ "97 The ANSSI-CC-2020/43 certificate makes a refer... \n",
+ "98 The certificate BSI-DSZ-CC-0911-2014 is refere... \n",
+ "\n",
+ "[99 rows x 8 columns]"
+ ]
+ },
+ "execution_count": 51,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df_results[[\"target_cert_id\", \"cert_id\", \"name\", \"target_name\", \"label\", \"comment\", \"gpt4omini_label\", \"gpt4omini_reason\"]]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 52,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import seaborn as sns\n",
+ "from sklearn.metrics import f1_score\n",
+ "import matplotlib.pyplot as plt"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_results = df_results[(~df_results[\"label\"].isin([\"none\", \"irrelevant\", None]) & (~df_results[\"gpt4omini_label\"].isin([\"none\", \"irrelevant\"])))]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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NhZsREREpFJYsBERERGJnerVayzYiIiISLWwh42IiIhI5FSxYOMsUSIiIiKRYw8bERERqRRV7GFjwUZEREQqhQUbERERkdipXr3Ga9iIiIhItUgkknw9lBEUFIQffvgBBgYGsLCwQPv27REdHS23T/369XOdY9CgQUqdhwUbERERqZTvWbCFhoZi6NChOH/+PI4cOYLMzEw0bdoUycnJcvv1798fcXFxskdwcLBS5+GQKBEREVEeHTx4UO752rVrYWFhgcuXL6Nu3bqy7Xp6erCyssrzedjDRkRERColvz1s6enpePv2rdwjPT1doXO/efMGAGBqaiq3fePGjShZsiQqVqyIiRMnIiUlRanPxIKNiIiIVIskf4+goCAYGRnJPYKCgr552pycHIwaNQq1a9dGxYoVZdu7deuGv//+GydOnMDEiROxYcMGdO/eXbmPJJVKpUq9g0hAaVlCJyAqnt7xH5/CMrJyhI5QJNgaaxXasS37bcnX+2P/aJurR01bWxva2tpffd/gwYNx4MABnD59GqVKlfrifsePH0ejRo1w9+5dODk5KZSJ17BRkZKQlCF0hCLDuYGv0BGKhAu7ZwsdgahYKsyCLb/rsClSnH1q2LBh2Lt3L06dOvXVYg0AatSoAQAs2IiIiKj4+p4L50qlUgwfPhw7duzAyZMnUaZMmW++Jzw8HABgbW2t8HlYsBERERHl0dChQxESEoJdu3bBwMAAz549AwAYGRlBV1cXMTExCAkJQcuWLWFmZobIyEiMHj0adevWRaVKlRQ+Dws2IiIiUinfs4dt2bJlAN4vjvuxNWvWoFevXtDS0sLRo0excOFCJCcnw87ODh07dsSUKVOUOg8LNiIiIlIt3/HWVN+au2lnZ4fQ0NB8n4cFGxEREakU3vydiIiISORYsBERERGJnCoWbLzTAREREZHIsYeNiIiIVIvqdbCxYCMiIiLVoopDoizYiIiISKWwYCMiIiISORZsRERERCKnigUbZ4kSERERiRx72IiIiEi1qF4HGws2IiIiUi2qOCTKgo2IiIhUCgs2IiIiIpFTwXqNBRsRERGpFlXsYeMsUSIiIiKRYw8bERERqRQV7GBjwUZERESqRRWHRFmwERERkUpRwXqNBRsRERGpFjU11avYOOmABOPg4ICFCxcKHYOIiFSMRJK/hxixh00F1a9fH5UrV2Yx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",
+ "text/plain": [
+ "<Figure size 600x400 with 2 Axes>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Accuracy: 0.3636, F1 score: 0.3818\n"
+ ]
+ }
+ ],
+ "source": [
+ "conf_matrix = pd.crosstab(df_results[\"label\"], df_results[\"gpt4omini_label\"])\n",
+ "accuracy = (df_results[\"label\"] == df_results[\"gpt4omini_label\"]).mean()\n",
+ "f1 = f1_score(df_results[\"label\"], df_results[\"gpt4omini_label\"], average='weighted')\n",
+ "plt.figure(figsize=(6, 4))\n",
+ "sns.heatmap(conf_matrix, annot=True, cmap='Blues')\n",
+ "plt.title('Confusion Matrix')\n",
+ "plt.ylabel('True label')\n",
+ "plt.xlabel('Predicted label')\n",
+ "plt.show()\n",
+ "print(f\"Accuracy: {accuracy:.4f}, F1 score: {f1:.4f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df_results[\"label_simple\"] = df_results[\"label\"].apply(convert_label_type).apply(lambda x: x.value)\n",
+ "df_results[\"gpt4omini_label_simple\"] = df_results[\"gpt4omini_label\"].apply(convert_label_type).apply(lambda x: x.value)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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vGja8LvKE+XS09MxZswY2NrawtjYGJaWlkobERFRRSHlE+XKgspJferUqTh69CiWL18OuVyONWvWICQkBI6OjtiwYUNZxEhERFQmdGSyYm/qSOXh971792LDhg1o3749hg0bhrZt28LV1RXOzs7YtGkTBg8eXBZxEhER0Tuo3FN/8uQJatSoAeDV9fMnT54AANq0aYMTJ06UbnRERERlSNPuU1c5qdeoUQNJSUkAgDp16uDnn38G8KoH/98F3omIiNRZeT37vbyonNSHDRuGK1euAAC+/PJLLFu2DAYGBpg4cSKmTJlS6gESERGVFU3rqat8TX3ixImK/3t7e+PGjRu4ePEiXF1d0bBhw1INjoiIqCyp64S34irRfeoA4OzsDGdn59KIhYiIqFxpWE4vWlJfsmRJkRscN25csYMhIiKi4itSUl+4cGGRGpPJZEzqRERUYajrhLfiKlJSz5/tXlFc+X2e1CEQlblq1kZSh0BU4ak8W1zNlfiaOhERUUWllT11IiIiTcRV2oiIiDSEpiV1TbucQEREpLXYUyciIq2ladfUi9VTP3nyJD755BN4eHjg7t27AICNGzfi1KlTpRocERFRWdKRFX9TRyon9R07dqBLly4wNDTE5cuXkZWVBQB4+vQp5syZU+oBEhERlRVNe/a7ykl91qxZWLFiBVavXg09PT1FuaenJy5dulSqwREREZUlHZms2Js6UvmaelxcHNq1a1eg3NzcHKmpqaURExERUbnQtNniKr8fe3t7JCQkFCg/deoUatSoUSpBERERkepUTuojRozA+PHjce7cOchkMty7dw+bNm3C5MmT8cUXX5RFjERERGWivK6ph4WFoUWLFjA1NYWtrS369u2LuLg4pTrt27eHTCZT2kaNGqXSeVQefv/yyy+Rl5eHjh07IiMjA+3atYNcLsfkyZMxduxYVZsjIiKSTHldG4+MjISfnx9atGiBnJwcTJs2DZ07d8a1a9dgbGysqDdixAiEhoYqXhsZqbbGg8pJXSaT4auvvsKUKVOQkJCAtLQ0uLu7w8TERNWmiIiIJFVe891+//13pdfh4eGwtbXFxYsXleapGRkZwd7evtjnKfYcAX19fbi7u+O9995jQiciogqpJPepZ2Vl4dmzZ0pb/m3e7/L06VMAgJWVlVL5pk2bULlyZdSvXx+BgYHIyMhQ6f2o3FPv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",
+ "text/plain": [
+ "<Figure size 600x400 with 2 Axes>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Accuracy: 0.6136, F1 score: 0.6338\n"
+ ]
+ }
+ ],
+ "source": [
+ "conf_matrix = pd.crosstab(df_results[\"label_simple\"], df_results[\"gpt4omini_label_simple\"])\n",
+ "accuracy = (df_results[\"label_simple\"] == df_results[\"gpt4omini_label_simple\"]).mean()\n",
+ "f1 = f1_score(df_results[\"label_simple\"], df_results[\"gpt4omini_label_simple\"], average='weighted')\n",
+ "\n",
+ "plt.figure(figsize=(6, 4))\n",
+ "sns.heatmap(conf_matrix, annot=True, cmap='Blues')\n",
+ "plt.title('Confusion Matrix')\n",
+ "plt.ylabel('True label')\n",
+ "plt.xlabel('Predicted label')\n",
+ "plt.show()\n",
+ "print(f\"Accuracy: {accuracy:.4f}, F1 score: {f1:.4f}\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "venv",
+ "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.10.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/notebooks/cc/llm_annotation_prompt.txt b/notebooks/cc/llm_annotation_prompt.txt
new file mode 100644
index 00000000..64334f47
--- /dev/null
+++ b/notebooks/cc/llm_annotation_prompt.txt
@@ -0,0 +1,26 @@
+You are an expert in analyzing relationships between certificates.
+Your task is to classify the relationship between a referenced target certificate, given its name and code and an examined certificate, based on its full text, using the following taxonomy (labels):
+ - **component_used**: The referenced certificate is a component of the examined certificate (e.g., an IC used in a smartcard).
+ - **component_shared**: The referenced certificate shares components with the examined certificate.
+ - **evaluation_reused**: The evaluation results from the referenced certificate were reused in the examined certificate's evaluation. Lowest-priority, can be overriden by other categories.
+ - **re-evaluation**: The examined certificate is a re-evaluation of the referenced certificate.
+ - **previous_version**: The referenced certificate is an earlier version of the examined certificate, but re-certification is not explicitly mentioned. Refer to the target name and the name of the compared component. If the target is BOTH a previous version and its evaluation was reused, then the previous version label takes precedence over the evaluation reused label."
+ - **none**: No clear relationship applies.
+ - **irrelevant**: The reference is unrelated (e.g., typo, leftover from a template).
+
+**EXAMPLES**:
+ - previous_version: "The evaluators confirmed test results from previous certification procedure BSI-DSZ-CC-0322-2005 where they could repeat the tests of the developer..."
+ - previous_version: "L'évaluation s'appuie sur les résultats d'évaluation de la précédente version du produit certifiée le 30 juillet 2020 sous la référence ANSSI-CC-2020/74, voir |CER|."
+ - re-evaluation: "This is a re-certification based on BSI-DSZ-CC-0353-2006"
+ - re-evaluation: "Ce produit a été précédemment certifié sous la référence |CER-2014/76|. Le présent rapport d'évaluation a permis de prendre en compte une nouvelle alternative dans le cycle de vie du produit (voir & 1.2.5)"
+ - component_used: "The security IC hardware is a M7892 D11 or M7892 P11 device certified under BSI-DSZ-CC-0891-V4-2019 or BSI-DSZ-CC-1105-2020, respectively."
+ - component_used: "The TOE is KOMSCO JK41 V1.0 ADV on S3FT9PS which is composite product consisting of the following components: IC chips : Samsung S3FT9PS 16-bit RISC Microcontroller for Smart Card with optional Secure RSA and ECC Library including specific IC Dedicated Software (ANSSI-CC-2014/58), and..."
+ - component_used: The TOE includes Windows® 2000 security functions. The evaluation approach included the re-use of Windows® 2000 evaluation results. Reference is made to Common Criteria Certificate and Validation Report number CCEVS-VR-02-0025 Version 2.0, dated 25 October 2002."
+ - component_used: "L’évaluation s’appuie sur les résultats d’évaluation du produit « Application eTravel EAC v2.0 sur la carte à puce fermée MultiApp V3 masquée sur le composant M7820 A11 patch 1.5 » certifié le 3 février 2014 sous la référence [ANSSI-CC-2014/07] et sur les résultats d’évaluation du produit « Plateforme Java Card en configuration ouverte de la carte à puce MultiApp V3.1 masquée sur le composant P60D080PVC patch 1.4 » certifié le 22 décembre 2014 sous la référence [ANSSI-CC-2014/86]."
+ - evaluation_reused: "Cette évaluation a ainsi pris en compte les résultats de l’évaluation des micro-contrôleurs « M7794 A12 et G12 » au niveau EAL5 augmenté des composants ALC_DVS.2 et AVA_VAN.5, conforme au profil de protection [PP0035]. Ces microcontrôleurs ont été certifiés, le 12 juin 2015 sous la référence « BSI-DSZ-CC-0964-2015 ». Le niveau de résistance de ces microcontrôleurs a été confirmé le 7 avril 2017 [CERT_IC]."
+ - evaluation_reused: "Also, specific ALC related parts were re-used in the sense of AIS38 from BSI-DSZ-CC-0891-V2-2016 (Infineon Security Controller M7892 D11 and G12)."
+
+There are also bigger categories: "re-evaluation" and "previous version" go under the umbrella category of "predecessor" and "component_used", "component_shared", "evaluation_reused" all go under the umbrella category "component_reuse". "none" and "irrelevant" are not handled. This is not something you should however respond with, just general taxonomical information.
+
+Return a structured response with a `label` and an `explanation` field.
+Be concise but clear in your explanation. Refer to the more specific instructions will follow in the user's message. \ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 04f16dc1..aafd0575 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -94,7 +94,9 @@
"scikit-learn",
"sentence-transformers",
"nltk",
- "sqlite-vec"
+ "sqlite-vec",
+ "openai",
+ "pyarrow"
]
[project.urls]
diff --git a/requirements/all_requirements.txt b/requirements/all_requirements.txt
index 3e5b6fa8..98cffc93 100644
--- a/requirements/all_requirements.txt
+++ b/requirements/all_requirements.txt
@@ -2,7 +2,7 @@ accelerate==1.4.0
# via sentence-transformers
accessible-pygments==0.0.5
# via pydata-sphinx-theme
-aiohappyeyeballs==2.4.8
+aiohappyeyeballs==2.5.0
# via aiohttp
aiohttp==3.11.13
# via
@@ -16,10 +16,14 @@ alembic==1.15.1
# via optuna
annotated-types==0.7.0
# via pydantic
+anyio==4.8.0
+ # via
+ # httpx
+ # openai
+appnope==0.1.4
+ # via ipykernel
asttokens==3.0.0
# via stack-data
-async-timeout==5.0.1
- # via aiohttp
attrs==25.1.0
# via
# aiohttp
@@ -53,7 +57,10 @@ catalogue==2.0.10
catboost==1.2.7
# via sec-certs (../pyproject.toml)
certifi==2025.1.31
- # via requests
+ # via
+ # httpcore
+ # httpx
+ # requests
cffi==1.17.1
# via cryptography
cfgv==3.4.0
@@ -125,7 +132,9 @@ dill==0.3.8
distlib==0.3.9
# via virtualenv
distro==1.9.0
- # via tabula-py
+ # via
+ # openai
+ # tabula-py
docutils==0.21.2
# via
# myst-parser
@@ -133,10 +142,6 @@ docutils==0.21.2
# sphinx
evaluate==0.4.3
# via setfit
-exceptiongroup==1.2.2
- # via
- # ipython
- # pytest
executing==2.2.0
# via stack-data
fastjsonschema==2.21.1
@@ -164,12 +169,16 @@ gprof2dot==2024.6.6
# via pytest-profiling
graphviz==0.20.3
# via catboost
-greenlet==3.1.1
- # via sqlalchemy
+h11==0.14.0
+ # via httpcore
holoviews==1.20.1
# via umap-learn
html5lib==1.1
# via sec-certs (../pyproject.toml)
+httpcore==1.0.7
+ # via httpx
+httpx==0.28.1
+ # via openai
huggingface-hub==0.29.2
# via
# accelerate
@@ -179,10 +188,12 @@ huggingface-hub==0.29.2
# setfit
# tokenizers
# transformers
-identify==2.6.8
+identify==2.6.9
# via pre-commit
idna==3.10
# via
+ # anyio
+ # httpx
# requests
# yarl
imageio==2.37.0
@@ -199,23 +210,27 @@ ipykernel==6.29.5
# via
# myst-nb
# sec-certs (../pyproject.toml)
-ipython==8.33.0
+ipython==9.0.2
# via
# ipykernel
# ipywidgets
# myst-nb
# sec-certs (../pyproject.toml)
+ipython-pygments-lexers==1.1.1
+ # via ipython
ipywidgets==8.1.5
# via sec-certs (../pyproject.toml)
jedi==0.19.2
# via ipython
-jinja2==3.1.5
+jinja2==3.1.6
# via
# bokeh
# myst-parser
# spacy
# sphinx
# torch
+jiter==0.8.2
+ # via openai
joblib==1.4.2
# via
# nltk
@@ -319,7 +334,7 @@ myst-nb==1.2.0
# via sec-certs (../pyproject.toml)
myst-parser==4.0.1
# via myst-nb
-narwhals==1.29.0
+narwhals==1.29.1
# via plotly
nbclient==0.10.2
# via
@@ -375,40 +390,8 @@ numpy==1.26.4
# transformers
# umap-learn
# xarray
-nvidia-cublas-cu12==12.4.5.8
- # via
- # nvidia-cudnn-cu12
- # nvidia-cusolver-cu12
- # torch
-nvidia-cuda-cupti-cu12==12.4.127
- # via torch
-nvidia-cuda-nvrtc-cu12==12.4.127
- # via torch
-nvidia-cuda-runtime-cu12==12.4.127
- # via torch
-nvidia-cudnn-cu12==9.1.0.70
- # via torch
-nvidia-cufft-cu12==11.2.1.3
- # via torch
-nvidia-curand-cu12==10.3.5.147
- # via torch
-nvidia-cusolver-cu12==11.6.1.9
- # via torch
-nvidia-cusparse-cu12==12.3.1.170
- # via
- # nvidia-cusolver-cu12
- # torch
-nvidia-cusparselt-cu12==0.6.2
- # via torch
-nvidia-nccl-cu12==2.21.5
- # via torch
-nvidia-nvjitlink-cu12==12.4.127
- # via
- # nvidia-cusolver-cu12
- # nvidia-cusparse-cu12
- # torch
-nvidia-nvtx-cu12==12.4.127
- # via torch
+openai==1.65.5
+ # via sec-certs (../pyproject.toml)
optuna==4.2.1
# via sec-certs (../pyproject.toml)
packaging==24.2
@@ -520,7 +503,9 @@ ptyprocess==0.7.0
pure-eval==0.2.3
# via stack-data
pyarrow==19.0.1
- # via datasets
+ # via
+ # datasets
+ # sec-certs (../pyproject.toml)
pycparser==2.22
# via cffi
pyct==0.5.0
@@ -528,6 +513,7 @@ pyct==0.5.0
pydantic==2.10.6
# via
# confection
+ # openai
# pydantic-settings
# sec-certs (../pyproject.toml)
# spacy
@@ -543,6 +529,7 @@ pygments==2.19.1
# via
# accessible-pygments
# ipython
+ # ipython-pygments-lexers
# pydata-sphinx-theme
# rich
# sphinx
@@ -632,6 +619,8 @@ requests==2.32.3
# weasel
rich==13.9.4
# via typer
+roman-numerals-py==3.1.0
+ # via sphinx
rpds-py==0.23.1
# via
# jsonschema
@@ -684,6 +673,10 @@ six==1.17.0
# python-dateutil
smart-open==7.1.0
# via weasel
+sniffio==1.3.1
+ # via
+ # anyio
+ # openai
snowballstemmer==2.2.0
# via sphinx
soupsieve==2.6
@@ -694,7 +687,7 @@ spacy-legacy==3.0.12
# via spacy
spacy-loggers==1.0.5
# via spacy
-sphinx==8.1.3
+sphinx==8.2.3
# via
# myst-nb
# myst-parser
@@ -750,15 +743,6 @@ tifffile==2025.2.18
# via scikit-image
tokenizers==0.21.0
# via transformers
-tomli==2.2.1
- # via
- # build
- # coverage
- # mypy
- # pip-tools
- # pytest
- # setuptools-scm
- # sphinx
toolz==1.0.0
# via datashader
torch==2.6.0
@@ -776,6 +760,7 @@ tqdm==4.67.1
# evaluate
# huggingface-hub
# nltk
+ # openai
# optuna
# panel
# sec-certs (../pyproject.toml)
@@ -798,8 +783,6 @@ transformers==4.49.0
# via
# sentence-transformers
# setfit
-triton==3.2.0
- # via torch
typer==0.15.2
# via
# spacy
@@ -808,31 +791,29 @@ types-python-dateutil==2.9.0.20241206
# via sec-certs (../pyproject.toml)
types-pyyaml==6.0.12.20241230
# via sec-certs (../pyproject.toml)
-types-requests==2.32.0.20250301
+types-requests==2.32.0.20250306
# via sec-certs (../pyproject.toml)
typing-extensions==4.12.2
# via
# alembic
+ # anyio
# beautifulsoup4
- # cloudpathlib
# huggingface-hub
# ipython
- # multidict
# mypy
# myst-nb
+ # openai
# panel
# pydantic
# pydantic-core
# pydata-sphinx-theme
- # pypdf
# referencing
- # rich
# sqlalchemy
# torch
# typer
tzdata==2025.1
# via pandas
-tzlocal==5.3
+tzlocal==5.3.1
# via dateparser
uc-micro-py==1.0.3
# via linkify-it-py
@@ -842,7 +823,7 @@ urllib3==2.3.0
# via
# requests
# types-requests
-virtualenv==20.29.2
+virtualenv==20.29.3
# via pre-commit
wasabi==1.1.3
# via
diff --git a/requirements/dev_requirements.txt b/requirements/dev_requirements.txt
index 4032fcbc..273f28a7 100644
--- a/requirements/dev_requirements.txt
+++ b/requirements/dev_requirements.txt
@@ -1,6 +1,6 @@
accessible-pygments==0.0.5
# via pydata-sphinx-theme
-aiohappyeyeballs==2.4.8
+aiohappyeyeballs==2.5.0
# via aiohttp
aiohttp==3.11.13
# via
@@ -12,10 +12,10 @@ alabaster==1.0.0
# via sphinx
annotated-types==0.7.0
# via pydantic
+appnope==0.1.4
+ # via ipykernel
asttokens==3.0.0
# via stack-data
-async-timeout==5.0.1
- # via aiohttp
attrs==25.1.0
# via
# aiohttp
@@ -99,10 +99,6 @@ docutils==0.21.2
# myst-parser
# pydata-sphinx-theme
# sphinx
-exceptiongroup==1.2.2
- # via
- # ipython
- # pytest
executing==2.2.0
# via stack-data
fastjsonschema==2.21.1
@@ -124,13 +120,11 @@ fsspec[http]==2024.12.0
# huggingface-hub
gprof2dot==2024.6.6
# via pytest-profiling
-greenlet==3.1.1
- # via sqlalchemy
html5lib==1.1
# via sec-certs (../pyproject.toml)
huggingface-hub==0.29.2
# via datasets
-identify==2.6.8
+identify==2.6.9
# via pre-commit
idna==3.10
# via
@@ -148,17 +142,19 @@ ipykernel==6.29.5
# via
# myst-nb
# sec-certs (../pyproject.toml)
-ipython==8.33.0
+ipython==9.0.2
# via
# ipykernel
# ipywidgets
# myst-nb
# sec-certs (../pyproject.toml)
+ipython-pygments-lexers==1.1.1
+ # via ipython
ipywidgets==8.1.5
# via sec-certs (../pyproject.toml)
jedi==0.19.2
# via ipython
-jinja2==3.1.5
+jinja2==3.1.6
# via
# myst-parser
# spacy
@@ -359,6 +355,7 @@ pygments==2.19.1
# via
# accessible-pygments
# ipython
+ # ipython-pygments-lexers
# pydata-sphinx-theme
# rich
# sphinx
@@ -431,6 +428,8 @@ requests==2.32.3
# weasel
rich==13.9.4
# via typer
+roman-numerals-py==3.1.0
+ # via sphinx
rpds-py==0.23.1
# via
# jsonschema
@@ -468,7 +467,7 @@ spacy-legacy==3.0.12
# via spacy
spacy-loggers==1.0.5
# via spacy
-sphinx==8.1.3
+sphinx==8.2.3
# via
# myst-nb
# myst-parser
@@ -513,15 +512,6 @@ thinc==8.2.5
# via spacy
threadpoolctl==3.5.0
# via scikit-learn
-tomli==2.2.1
- # via
- # build
- # coverage
- # mypy
- # pip-tools
- # pytest
- # setuptools-scm
- # sphinx
tornado==6.4.2
# via
# ipykernel
@@ -551,34 +541,30 @@ types-python-dateutil==2.9.0.20241206
# via sec-certs (../pyproject.toml)
types-pyyaml==6.0.12.20241230
# via sec-certs (../pyproject.toml)
-types-requests==2.32.0.20250301
+types-requests==2.32.0.20250306
# via sec-certs (../pyproject.toml)
typing-extensions==4.12.2
# via
# beautifulsoup4
- # cloudpathlib
# huggingface-hub
# ipython
- # multidict
# mypy
# myst-nb
# pydantic
# pydantic-core
# pydata-sphinx-theme
- # pypdf
# referencing
- # rich
# sqlalchemy
# typer
tzdata==2025.1
# via pandas
-tzlocal==5.3
+tzlocal==5.3.1
# via dateparser
urllib3==2.3.0
# via
# requests
# types-requests
-virtualenv==20.29.2
+virtualenv==20.29.3
# via pre-commit
wasabi==1.1.3
# via
diff --git a/requirements/nlp_requirements.txt b/requirements/nlp_requirements.txt
index d14aaeea..9aca9b20 100644
--- a/requirements/nlp_requirements.txt
+++ b/requirements/nlp_requirements.txt
@@ -1,6 +1,6 @@
accelerate==1.4.0
# via sentence-transformers
-aiohappyeyeballs==2.4.8
+aiohappyeyeballs==2.5.0
# via aiohttp
aiohttp==3.11.13
# via
@@ -12,10 +12,14 @@ alembic==1.15.1
# via optuna
annotated-types==0.7.0
# via pydantic
+anyio==4.8.0
+ # via
+ # httpx
+ # openai
+appnope==0.1.4
+ # via ipykernel
asttokens==3.0.0
# via stack-data
-async-timeout==5.0.1
- # via aiohttp
attrs==25.1.0
# via
# aiohttp
@@ -40,7 +44,10 @@ catalogue==2.0.10
catboost==1.2.7
# via sec-certs (../pyproject.toml)
certifi==2025.1.31
- # via requests
+ # via
+ # httpcore
+ # httpx
+ # requests
cffi==1.17.1
# via cryptography
charset-normalizer==3.4.1
@@ -101,11 +108,11 @@ dill==0.3.8
# evaluate
# multiprocess
distro==1.9.0
- # via tabula-py
+ # via
+ # openai
+ # tabula-py
evaluate==0.4.3
# via setfit
-exceptiongroup==1.2.2
- # via ipython
executing==2.2.0
# via stack-data
filelock==3.17.0
@@ -128,12 +135,16 @@ fsspec[http]==2024.12.0
# torch
graphviz==0.20.3
# via catboost
-greenlet==3.1.1
- # via sqlalchemy
+h11==0.14.0
+ # via httpcore
holoviews==1.20.1
# via umap-learn
html5lib==1.1
# via sec-certs (../pyproject.toml)
+httpcore==1.0.7
+ # via httpx
+httpx==0.28.1
+ # via openai
huggingface-hub==0.29.2
# via
# accelerate
@@ -145,25 +156,31 @@ huggingface-hub==0.29.2
# transformers
idna==3.10
# via
+ # anyio
+ # httpx
# requests
# yarl
imageio==2.37.0
# via scikit-image
ipykernel==6.29.5
# via sec-certs (../pyproject.toml)
-ipython==8.33.0
+ipython==9.0.2
# via
# ipykernel
# ipywidgets
+ipython-pygments-lexers==1.1.1
+ # via ipython
ipywidgets==8.1.5
# via sec-certs (../pyproject.toml)
jedi==0.19.2
# via ipython
-jinja2==3.1.5
+jinja2==3.1.6
# via
# bokeh
# spacy
# torch
+jiter==0.8.2
+ # via openai
joblib==1.4.2
# via
# nltk
@@ -246,7 +263,7 @@ murmurhash==1.0.12
# preshed
# spacy
# thinc
-narwhals==1.29.0
+narwhals==1.29.1
# via plotly
nest-asyncio==1.6.0
# via ipykernel
@@ -291,40 +308,8 @@ numpy==1.26.4
# transformers
# umap-learn
# xarray
-nvidia-cublas-cu12==12.4.5.8
- # via
- # nvidia-cudnn-cu12
- # nvidia-cusolver-cu12
- # torch
-nvidia-cuda-cupti-cu12==12.4.127
- # via torch
-nvidia-cuda-nvrtc-cu12==12.4.127
- # via torch
-nvidia-cuda-runtime-cu12==12.4.127
- # via torch
-nvidia-cudnn-cu12==9.1.0.70
- # via torch
-nvidia-cufft-cu12==11.2.1.3
- # via torch
-nvidia-curand-cu12==10.3.5.147
- # via torch
-nvidia-cusolver-cu12==11.6.1.9
- # via torch
-nvidia-cusparse-cu12==12.3.1.170
- # via
- # nvidia-cusolver-cu12
- # torch
-nvidia-cusparselt-cu12==0.6.2
- # via torch
-nvidia-nccl-cu12==2.21.5
- # via torch
-nvidia-nvjitlink-cu12==12.4.127
- # via
- # nvidia-cusolver-cu12
- # nvidia-cusparse-cu12
- # torch
-nvidia-nvtx-cu12==12.4.127
- # via torch
+openai==1.65.5
+ # via sec-certs (../pyproject.toml)
optuna==4.2.1
# via sec-certs (../pyproject.toml)
packaging==24.2
@@ -422,7 +407,9 @@ ptyprocess==0.7.0
pure-eval==0.2.3
# via stack-data
pyarrow==19.0.1
- # via datasets
+ # via
+ # datasets
+ # sec-certs (../pyproject.toml)
pycparser==2.22
# via cffi
pyct==0.5.0
@@ -430,6 +417,7 @@ pyct==0.5.0
pydantic==2.10.6
# via
# confection
+ # openai
# pydantic-settings
# sec-certs (../pyproject.toml)
# spacy
@@ -442,6 +430,7 @@ pydantic-settings==2.8.1
pygments==2.19.1
# via
# ipython
+ # ipython-pygments-lexers
# rich
pynndescent==0.5.13
# via umap-learn
@@ -556,6 +545,10 @@ six==1.17.0
# python-dateutil
smart-open==7.1.0
# via weasel
+sniffio==1.3.1
+ # via
+ # anyio
+ # openai
soupsieve==2.6
# via beautifulsoup4
spacy==3.7.5
@@ -590,8 +583,6 @@ tifffile==2025.2.18
# via scikit-image
tokenizers==0.21.0
# via transformers
-tomli==2.2.1
- # via setuptools-scm
toolz==1.0.0
# via datashader
torch==2.6.0
@@ -609,6 +600,7 @@ tqdm==4.67.1
# evaluate
# huggingface-hub
# nltk
+ # openai
# optuna
# panel
# sec-certs (../pyproject.toml)
@@ -629,8 +621,6 @@ transformers==4.49.0
# via
# sentence-transformers
# setfit
-triton==3.2.0
- # via torch
typer==0.15.2
# via
# spacy
@@ -638,23 +628,21 @@ typer==0.15.2
typing-extensions==4.12.2
# via
# alembic
+ # anyio
# beautifulsoup4
- # cloudpathlib
# huggingface-hub
# ipython
- # multidict
+ # openai
# panel
# pydantic
# pydantic-core
- # pypdf
# referencing
- # rich
# sqlalchemy
# torch
# typer
tzdata==2025.1
# via pandas
-tzlocal==5.3
+tzlocal==5.3.1
# via dateparser
uc-micro-py==1.0.3
# via linkify-it-py
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index ff65b68e..4fb1f4ba 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -1,5 +1,7 @@
annotated-types==0.7.0
# via pydantic
+appnope==0.1.4
+ # via ipykernel
asttokens==3.0.0
# via stack-data
attrs==25.1.0
@@ -56,8 +58,6 @@ deprecated==1.2.18
# via pikepdf
distro==1.9.0
# via tabula-py
-exceptiongroup==1.2.2
- # via ipython
executing==2.2.0
# via stack-data
fonttools==4.56.0
@@ -68,15 +68,17 @@ idna==3.10
# via requests
ipykernel==6.29.5
# via sec-certs (../pyproject.toml)
-ipython==8.33.0
+ipython==9.0.2
# via
# ipykernel
# ipywidgets
+ipython-pygments-lexers==1.1.1
+ # via ipython
ipywidgets==8.1.5
# via sec-certs (../pyproject.toml)
jedi==0.19.2
# via ipython
-jinja2==3.1.5
+jinja2==3.1.6
# via spacy
joblib==1.4.2
# via scikit-learn
@@ -207,6 +209,7 @@ pydantic-settings==2.8.1
pygments==2.19.1
# via
# ipython
+ # ipython-pygments-lexers
# rich
pyparsing==3.2.1
# via matplotlib
@@ -296,8 +299,6 @@ thinc==8.2.5
# via spacy
threadpoolctl==3.5.0
# via scikit-learn
-tomli==2.2.1
- # via setuptools-scm
tornado==6.4.2
# via
# ipykernel
@@ -322,17 +323,14 @@ typer==0.15.2
typing-extensions==4.12.2
# via
# beautifulsoup4
- # cloudpathlib
# ipython
# pydantic
# pydantic-core
- # pypdf
# referencing
- # rich
# typer
tzdata==2025.1
# via pandas
-tzlocal==5.3
+tzlocal==5.3.1
# via dateparser
urllib3==2.3.0
# via requests
diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt
index 99448153..261272c9 100644
--- a/requirements/test_requirements.txt
+++ b/requirements/test_requirements.txt
@@ -1,5 +1,7 @@
annotated-types==0.7.0
# via pydantic
+appnope==0.1.4
+ # via ipykernel
asttokens==3.0.0
# via stack-data
attrs==25.1.0
@@ -60,10 +62,6 @@ deprecated==1.2.18
# via pikepdf
distro==1.9.0
# via tabula-py
-exceptiongroup==1.2.2
- # via
- # ipython
- # pytest
executing==2.2.0
# via stack-data
fonttools==4.56.0
@@ -76,15 +74,17 @@ iniconfig==2.0.0
# via pytest
ipykernel==6.29.5
# via sec-certs (../pyproject.toml)
-ipython==8.33.0
+ipython==9.0.2
# via
# ipykernel
# ipywidgets
+ipython-pygments-lexers==1.1.1
+ # via ipython
ipywidgets==8.1.5
# via sec-certs (../pyproject.toml)
jedi==0.19.2
# via ipython
-jinja2==3.1.5
+jinja2==3.1.6
# via spacy
joblib==1.4.2
# via scikit-learn
@@ -218,6 +218,7 @@ pydantic-settings==2.8.1
pygments==2.19.1
# via
# ipython
+ # ipython-pygments-lexers
# rich
pyparsing==3.2.1
# via matplotlib
@@ -313,11 +314,6 @@ thinc==8.2.5
# via spacy
threadpoolctl==3.5.0
# via scikit-learn
-tomli==2.2.1
- # via
- # coverage
- # pytest
- # setuptools-scm
tornado==6.4.2
# via
# ipykernel
@@ -342,17 +338,14 @@ typer==0.15.2
typing-extensions==4.12.2
# via
# beautifulsoup4
- # cloudpathlib
# ipython
# pydantic
# pydantic-core
- # pypdf
# referencing
- # rich
# typer
tzdata==2025.1
# via pandas
-tzlocal==5.3
+tzlocal==5.3.1
# via dateparser
urllib3==2.3.0
# via requests
diff --git a/src/sec_certs/constants.py b/src/sec_certs/constants.py
index 5626f999..fc3dd3a5 100644
--- a/src/sec_certs/constants.py
+++ b/src/sec_certs/constants.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import re
from typing import Final, Literal
diff --git a/src/sec_certs/dataset/auxiliary_dataset_handling.py b/src/sec_certs/dataset/auxiliary_dataset_handling.py
index cd67f929..0fc6de15 100644
--- a/src/sec_certs/dataset/auxiliary_dataset_handling.py
+++ b/src/sec_certs/dataset/auxiliary_dataset_handling.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import gzip
import itertools
import json
diff --git a/src/sec_certs/dataset/cc.py b/src/sec_certs/dataset/cc.py
index fa95f5cf..fdd0d48d 100644
--- a/src/sec_certs/dataset/cc.py
+++ b/src/sec_certs/dataset/cc.py
@@ -101,12 +101,16 @@ class CCDataset(Dataset[CCCertificate], ComplexSerializableType):
super().__init__(certs, root_dir, name, description, state, aux_handlers)
if aux_handlers is None:
self.aux_handlers = {
- CPEDatasetHandler: CPEDatasetHandler(self.auxiliary_datasets_dir),
- CVEDatasetHandler: CVEDatasetHandler(self.auxiliary_datasets_dir),
- CPEMatchDictHandler: CPEMatchDictHandler(self.auxiliary_datasets_dir),
- CCSchemeDatasetHandler: CCSchemeDatasetHandler(self.auxiliary_datasets_dir),
- ProtectionProfileDatasetHandler: ProtectionProfileDatasetHandler(self.auxiliary_datasets_dir),
- CCMaintenanceUpdateDatasetHandler: CCMaintenanceUpdateDatasetHandler(self.auxiliary_datasets_dir),
+ CPEDatasetHandler: CPEDatasetHandler(self.auxiliary_datasets_dir if self.is_backed else None),
+ CVEDatasetHandler: CVEDatasetHandler(self.auxiliary_datasets_dir if self.is_backed else None),
+ CPEMatchDictHandler: CPEMatchDictHandler(self.auxiliary_datasets_dir if self.is_backed else None),
+ CCSchemeDatasetHandler: CCSchemeDatasetHandler(self.auxiliary_datasets_dir if self.is_backed else None),
+ ProtectionProfileDatasetHandler: ProtectionProfileDatasetHandler(
+ self.auxiliary_datasets_dir if self.is_backed else None
+ ),
+ CCMaintenanceUpdateDatasetHandler: CCMaintenanceUpdateDatasetHandler(
+ self.auxiliary_datasets_dir if self.is_backed else None
+ ),
}
def to_pandas(self) -> pd.DataFrame:
diff --git a/src/sec_certs/dataset/fips.py b/src/sec_certs/dataset/fips.py
index a64ca3d7..0f756b0a 100644
--- a/src/sec_certs/dataset/fips.py
+++ b/src/sec_certs/dataset/fips.py
@@ -68,10 +68,12 @@ class FIPSDataset(Dataset[FIPSCertificate], ComplexSerializableType):
super().__init__(certs, root_dir, name, description, state, aux_handlers)
if aux_handlers is None:
self.aux_handlers = {
- CPEDatasetHandler: CPEDatasetHandler(self.auxiliary_datasets_dir),
- CVEDatasetHandler: CVEDatasetHandler(self.auxiliary_datasets_dir),
- FIPSAlgorithmDatasetHandler: FIPSAlgorithmDatasetHandler(self.auxiliary_datasets_dir),
- CPEMatchDictHandler: CPEMatchDictHandler(self.auxiliary_datasets_dir),
+ CPEDatasetHandler: CPEDatasetHandler(self.auxiliary_datasets_dir if self.is_backed else None),
+ CVEDatasetHandler: CVEDatasetHandler(self.auxiliary_datasets_dir if self.is_backed else None),
+ FIPSAlgorithmDatasetHandler: FIPSAlgorithmDatasetHandler(
+ self.auxiliary_datasets_dir if self.is_backed else None
+ ),
+ CPEMatchDictHandler: CPEMatchDictHandler(self.auxiliary_datasets_dir if self.is_backed else None),
}
LIST_OF_CERTS_HTML: Final[dict[str, str]] = {
diff --git a/src/sec_certs/dataset/protection_profile.py b/src/sec_certs/dataset/protection_profile.py
index 40113c87..d5b9363c 100644
--- a/src/sec_certs/dataset/protection_profile.py
+++ b/src/sec_certs/dataset/protection_profile.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import shutil
from pathlib import Path
from typing import ClassVar, Literal
diff --git a/src/sec_certs/heuristics/cc.py b/src/sec_certs/heuristics/cc.py
index 435c69ed..c881019d 100644
--- a/src/sec_certs/heuristics/cc.py
+++ b/src/sec_certs/heuristics/cc.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import re
from collections.abc import Iterable
diff --git a/src/sec_certs/heuristics/common.py b/src/sec_certs/heuristics/common.py
index 8a2b4769..21d5f514 100644
--- a/src/sec_certs/heuristics/common.py
+++ b/src/sec_certs/heuristics/common.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import itertools
import logging
import re
diff --git a/src/sec_certs/heuristics/fips.py b/src/sec_certs/heuristics/fips.py
index 4abecc4e..4b38c2d3 100644
--- a/src/sec_certs/heuristics/fips.py
+++ b/src/sec_certs/heuristics/fips.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from sec_certs.model.reference_finder import ReferenceFinder
diff --git a/src/sec_certs/model/references_nlp/evaluation.py b/src/sec_certs/model/references_nlp/evaluation.py
index ed3b2700..296de790 100644
--- a/src/sec_certs/model/references_nlp/evaluation.py
+++ b/src/sec_certs/model/references_nlp/evaluation.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from pathlib import Path
from typing import Literal
diff --git a/src/sec_certs/model/references_nlp/feature_extraction.py b/src/sec_certs/model/references_nlp/feature_extraction.py
index 996972d7..c8a04acf 100644
--- a/src/sec_certs/model/references_nlp/feature_extraction.py
+++ b/src/sec_certs/model/references_nlp/feature_extraction.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import itertools
import logging
import re
diff --git a/src/sec_certs/model/references_nlp/training.py b/src/sec_certs/model/references_nlp/training.py
index e0abe94f..8d3a7046 100644
--- a/src/sec_certs/model/references_nlp/training.py
+++ b/src/sec_certs/model/references_nlp/training.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
import os
diff --git a/src/sec_certs/sample/document_state.py b/src/sec_certs/sample/document_state.py
index a2cf1769..ef598c5e 100644
--- a/src/sec_certs/sample/document_state.py
+++ b/src/sec_certs/sample/document_state.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from dataclasses import dataclass
from pathlib import Path
diff --git a/src/sec_certs/serialization/pandas.py b/src/sec_certs/serialization/pandas.py
index dc0aae18..06aff355 100644
--- a/src/sec_certs/serialization/pandas.py
+++ b/src/sec_certs/serialization/pandas.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from abc import ABC, abstractmethod
diff --git a/src/sec_certs/utils/cc_html_parsing.py b/src/sec_certs/utils/cc_html_parsing.py
index 956353bf..2603b3ce 100644
--- a/src/sec_certs/utils/cc_html_parsing.py
+++ b/src/sec_certs/utils/cc_html_parsing.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import logging
from datetime import datetime
from typing import Any
diff --git a/src/sec_certs/utils/label_studio_utils.py b/src/sec_certs/utils/label_studio_utils.py
index 9c70b938..82d663be 100644
--- a/src/sec_certs/utils/label_studio_utils.py
+++ b/src/sec_certs/utils/label_studio_utils.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import json
import logging
from pathlib import Path
diff --git a/src/sec_certs/utils/nvd_dataset_builder.py b/src/sec_certs/utils/nvd_dataset_builder.py
index bffde677..102d78b1 100644
--- a/src/sec_certs/utils/nvd_dataset_builder.py
+++ b/src/sec_certs/utils/nvd_dataset_builder.py
@@ -5,6 +5,7 @@ import logging
import math
import random
import time
+import typing
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import datetime
@@ -16,13 +17,15 @@ import requests
from requests import RequestException, Response
from sec_certs import constants
-from sec_certs.dataset.cpe import CPEDataset, CPEMatchDict
-from sec_certs.dataset.cve import CVEDataset
+
+if typing.TYPE_CHECKING:
+ from sec_certs.dataset.cpe import CPEDataset, CPEMatchDict
+ from sec_certs.dataset.cve import CVEDataset
from sec_certs.utils.parallel_processing import process_parallel
logger = logging.getLogger(__name__)
-DatasetType = TypeVar("DatasetType", CPEDataset, CVEDataset, CPEMatchDict)
+DatasetType = TypeVar("DatasetType", "CPEDataset", "CVEDataset", "CPEMatchDict")
@dataclass
@@ -282,7 +285,7 @@ class NvdDatasetBuilder(Generic[DatasetType], ABC):
return self._process_responses(self._ok_responses, dataset_to_fill)
-class CpeNvdDatasetBuilder(NvdDatasetBuilder[CPEDataset]):
+class CpeNvdDatasetBuilder(NvdDatasetBuilder["CPEDataset"]):
_ENDPOINT: Final[str] = "CPE"
_ENDPOINT_URL: Final[str] = "https://services.nvd.nist.gov/rest/json/cpes/2.0"
_RESULTS_PER_PAGE: Final[int] = 10000
@@ -298,10 +301,12 @@ class CpeNvdDatasetBuilder(NvdDatasetBuilder[CPEDataset]):
@staticmethod
def _init_new_dataset() -> CPEDataset:
+ from sec_certs.dataset.cpe import CPEDataset
+
return CPEDataset()
-class CveNvdDatasetBuilder(NvdDatasetBuilder[CVEDataset]):
+class CveNvdDatasetBuilder(NvdDatasetBuilder["CVEDataset"]):
_ENDPOINT: Final[str] = "CVE"
_ENDPOINT_URL: Final[str] = "https://services.nvd.nist.gov/rest/json/cves/2.0"
_RESULTS_PER_PAGE: Final[int] = 2000
@@ -317,10 +322,12 @@ class CveNvdDatasetBuilder(NvdDatasetBuilder[CVEDataset]):
@staticmethod
def _init_new_dataset() -> CVEDataset:
+ from sec_certs.dataset.cve import CVEDataset
+
return CVEDataset()
-class CpeMatchNvdDatasetBuilder(NvdDatasetBuilder[CPEMatchDict]):
+class CpeMatchNvdDatasetBuilder(NvdDatasetBuilder["CPEMatchDict"]):
_ENDPOINT: Final[str] = "CPEMatch"
_ENDPOINT_URL: Final[str] = "https://services.nvd.nist.gov/rest/json/cpematch/2.0"
_RESULTS_PER_PAGE: Final[int] = 500
@@ -362,4 +369,6 @@ class CpeMatchNvdDatasetBuilder(NvdDatasetBuilder[CPEMatchDict]):
@staticmethod
def _init_new_dataset() -> CPEMatchDict:
+ from sec_certs.dataset.cpe import CPEMatchDict
+
return CPEMatchDict({"timestamp": datetime.fromtimestamp(0).isoformat(), "match_strings": {}})
diff --git a/src/sec_certs/utils/plot_utils.py b/src/sec_certs/utils/plot_utils.py
index eca79070..f289cc06 100644
--- a/src/sec_certs/utils/plot_utils.py
+++ b/src/sec_certs/utils/plot_utils.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from networkx import DiGraph
from pandas import DataFrame
diff --git a/src/sec_certs/utils/profiling.py b/src/sec_certs/utils/profiling.py
index 7da67070..4c7d0911 100644
--- a/src/sec_certs/utils/profiling.py
+++ b/src/sec_certs/utils/profiling.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import gc
from contextlib import contextmanager
from datetime import datetime
diff --git a/src/sec_certs/utils/tqdm.py b/src/sec_certs/utils/tqdm.py
index 0a23903f..c7c8958b 100644
--- a/src/sec_certs/utils/tqdm.py
+++ b/src/sec_certs/utils/tqdm.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from tqdm.auto import tqdm as tqdm_original
from sec_certs.configuration import config