Skip to content

refactor: use XDG_CACHE_HOME for default cache directory #5083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions cve_bin_tool/available_fix/debian_cve_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
from __future__ import annotations

from json import dump, load
from pathlib import Path
from time import time

from cve_bin_tool.cve_scanner import CVEData
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT
from cve_bin_tool.log import LOGGER
from cve_bin_tool.output_engine.util import ProductInfo, format_output
from cve_bin_tool.util import make_http_requests

JSON_URL = "https://security-tracker.debian.org/tracker/data/json"
DEB_CVE_JSON_PATH = (
Path("~").expanduser() / ".cache" / "cve-bin-tool" / "debian_cve_data.json"
)
DEB_CVE_JSON_PATH = DISK_LOCATION_DEFAULT / "debian_cve_data.json"

UBUNTU_DEBIAN_MAP = {
"hirsute": "bullseye",
Expand Down
3 changes: 2 additions & 1 deletion cve_bin_tool/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from cve_bin_tool.config import ConfigParser
from cve_bin_tool.config_generator import config_generator
from cve_bin_tool.cve_scanner import CVEScanner
from cve_bin_tool.cvedb import CVEDB, OLD_CACHE_DIR
from cve_bin_tool.cvedb import CVEDB
from cve_bin_tool.data_sources import (
DataSourceSupport,
curl_source,
Expand All @@ -53,6 +53,7 @@
purl2cpe_source,
redhat_source,
)
from cve_bin_tool.database_defaults import OLD_CACHE_DIR
from cve_bin_tool.error_handler import (
ERROR_CODES,
CVEDataMissing,
Expand Down
2 changes: 1 addition & 1 deletion cve_bin_tool/cve_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from rich.console import Console

from cve_bin_tool.cvedb import DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.database_defaults import DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.input_engine import TriageData
from cve_bin_tool.log import LOGGER
Expand Down
12 changes: 6 additions & 6 deletions cve_bin_tool/cvedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
osv_source,
purl2cpe_source,
)
from cve_bin_tool.database_defaults import (
DBNAME,
DISK_LOCATION_BACKUP,
DISK_LOCATION_DEFAULT,
OLD_CACHE_DIR,
)
from cve_bin_tool.error_handler import ERROR_CODES, CVEDBError, ErrorMode, SigningError
from cve_bin_tool.fetch_json_db import Fetch_JSON_DB
from cve_bin_tool.log import LOGGER
Expand All @@ -39,12 +45,6 @@

logging.basicConfig(level=logging.DEBUG)

# database defaults
DISK_LOCATION_DEFAULT = Path("~").expanduser() / ".cache" / "cve-bin-tool"
DISK_LOCATION_BACKUP = Path("~").expanduser() / ".cache" / "cve-bin-tool-backup"
DBNAME = "cve.db"
OLD_CACHE_DIR = Path("~") / ".cache" / "cvedb"

UNKNOWN_METRIC_ID = 0
EPSS_METRIC_ID = 1
CVSS_2_METRIC_ID = 2
Expand Down
10 changes: 0 additions & 10 deletions cve_bin_tool/data_sources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,12 @@

import sys
from abc import ABC, abstractmethod
from pathlib import Path

if sys.version_info >= (3, 9):
import importlib.resources as resources
else:
import importlib_resources as resources

USER_HOME = Path("~")

# database defaults
DISK_LOCATION_DEFAULT = str(USER_HOME.expanduser() / ".cache" / "cve-bin-tool")
DISK_LOCATION_BACKUP = str(USER_HOME.expanduser() / ".cache" / "cve-bin-tool-backup")
DBNAME = "cve.db"
OLD_CACHE_DIR = str(USER_HOME.expanduser() / ".cache" / "cvedb")
NVD_FILENAME_TEMPLATE = "nvdcve-1.1-{}.json.gz"


class Data_Source(ABC):
@abstractmethod
Expand Down
4 changes: 2 additions & 2 deletions cve_bin_tool/data_sources/curl_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import aiohttp

from cve_bin_tool.async_utils import FileIO, RateLimiter
from cve_bin_tool.data_sources import (
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import (
DISK_LOCATION_BACKUP,
DISK_LOCATION_DEFAULT,
Data_Source,
)
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.log import LOGGER
Expand Down
2 changes: 1 addition & 1 deletion cve_bin_tool/data_sources/epss_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import aiohttp

from cve_bin_tool.data_sources import DISK_LOCATION_BACKUP, DISK_LOCATION_DEFAULT
from cve_bin_tool.database_defaults import DISK_LOCATION_BACKUP, DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.version import HTTP_HEADERS

Expand Down
3 changes: 2 additions & 1 deletion cve_bin_tool/data_sources/gad_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from yaml.loader import SafeLoader

from cve_bin_tool.async_utils import FileIO, RateLimiter
from cve_bin_tool.data_sources import DISK_LOCATION_DEFAULT, Data_Source
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.log import LOGGER
from cve_bin_tool.version import HTTP_HEADERS
Expand Down
4 changes: 2 additions & 2 deletions cve_bin_tool/data_sources/nvd_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
from rich.progress import track

from cve_bin_tool.async_utils import FileIO, GzipFile, RateLimiter
from cve_bin_tool.data_sources import (
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import (
DBNAME,
DISK_LOCATION_BACKUP,
DISK_LOCATION_DEFAULT,
NVD_FILENAME_TEMPLATE,
Data_Source,
)
from cve_bin_tool.error_handler import (
AttemptedToWriteOutsideCachedir,
Expand Down
3 changes: 2 additions & 1 deletion cve_bin_tool/data_sources/osv_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from cvss import CVSS3

from cve_bin_tool.async_utils import FileIO, RateLimiter, aio_run_command
from cve_bin_tool.data_sources import DISK_LOCATION_DEFAULT, Data_Source
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.log import LOGGER
from cve_bin_tool.version import HTTP_HEADERS
Expand Down
3 changes: 2 additions & 1 deletion cve_bin_tool/data_sources/purl2cpe_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

import aiohttp

from cve_bin_tool.data_sources import DISK_LOCATION_DEFAULT, Data_Source
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.log import LOGGER
from cve_bin_tool.version import HTTP_HEADERS
Expand Down
3 changes: 2 additions & 1 deletion cve_bin_tool/data_sources/redhat_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
import aiohttp

from cve_bin_tool.async_utils import FileIO, RateLimiter
from cve_bin_tool.data_sources import DISK_LOCATION_DEFAULT, Data_Source
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.log import LOGGER
from cve_bin_tool.version import HTTP_HEADERS
Expand Down
3 changes: 2 additions & 1 deletion cve_bin_tool/data_sources/rsd_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
from cvss import CVSS2, CVSS3

from cve_bin_tool.async_utils import FileIO, RateLimiter
from cve_bin_tool.data_sources import DISK_LOCATION_DEFAULT, Data_Source
from cve_bin_tool.data_sources import Data_Source
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorMode
from cve_bin_tool.log import LOGGER
from cve_bin_tool.version import HTTP_HEADERS
Expand Down
12 changes: 12 additions & 0 deletions cve_bin_tool/database_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright (C) 2025 Intel Corporation
# SPDX-License-Identifier: GPL-3.0-or-later

import os
from pathlib import Path

CACHE_DIR = Path(os.environ.get("XDG_CACHE_HOME", Path.home() / ".cache"))
DISK_LOCATION_DEFAULT = CACHE_DIR / "cve-bin-tool"
DISK_LOCATION_BACKUP = CACHE_DIR / "cve-bin-tool-backup"
OLD_CACHE_DIR = Path.home() / ".cache" / "cvedb"
DBNAME = "cve.db"
NVD_FILENAME_TEMPLATE = "nvdcve-1.1-{}.json.gz"
3 changes: 2 additions & 1 deletion cve_bin_tool/helper_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from rich import print as rprint
from rich.console import Console

from cve_bin_tool.cvedb import CVEDB, DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.cvedb import CVEDB
from cve_bin_tool.database_defaults import DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.error_handler import ErrorHandler, ErrorMode, UnknownArchiveType
from cve_bin_tool.extractor import Extractor, TempDirExtractorContext
from cve_bin_tool.log import LOGGER
Expand Down
2 changes: 1 addition & 1 deletion cve_bin_tool/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from cve_bin_tool.cve_scanner import CVEScanner

from .cvedb import DISK_LOCATION_DEFAULT
from .database_defaults import DISK_LOCATION_DEFAULT
from .error_handler import (
ErrorHandler,
ErrorMode,
Expand Down
2 changes: 1 addition & 1 deletion cve_bin_tool/mismatch_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import yaml

from cve_bin_tool.cvedb import DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.database_defaults import DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.log import LOGGER

SQL_CREATE_TABLE = """
Expand Down
2 changes: 1 addition & 1 deletion cve_bin_tool/version_signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from datetime import datetime
from pathlib import Path

from cve_bin_tool.cvedb import DISK_LOCATION_DEFAULT
from cve_bin_tool.database_defaults import DISK_LOCATION_DEFAULT


class InvalidVersionSignatureTable(ValueError):
Expand Down
12 changes: 11 additions & 1 deletion doc/MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,21 @@ CVE binary tool is intended for use by developers wishing to track known vulnera

We usually assume that the people providing the binaries for scanning will be the same people who set up and control the environment in which they are run. For example, a normal use case would be an open source project scanning their own generated files as a build check. We don't really expect people to use this as a forensics tool on a compromised system. (Although if you use it that way, we'd love to hear how that worked for you!)

### Cache Directory Behavior

The CVE Binary Tool uses a local cache directory to store downloaded vulnerability data (e.g., NVD feeds).
By default, it follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).

- If the `XDG_CACHE_HOME` environment variable is set, the cache will be stored in: `$XDG_CACHE_HOME/cve-bin-tool`
- If `XDG_CACHE_HOME` is not set, the cache defaults to: `~/.cache/cve-bin-tool`

This allows users to customize where temporary vulnerability data is stored.

### Use user-level permissions with appropriate file system access

You should give cve-bin-tool minimal, user-level permissions. The user for cve-bin-tool will need access to the following things:

- Read/write access to a cache directory for storing and reading the vulnerability data (`~/.cache/cve-bin-tool/`).
- Read/write access to a cache directory for storing and reading the vulnerability data.
- Write access is only needed during data updates, which typically run once a day and can be scheduled separately.
- Read access to the file/directory to be scanned.
- Write access to the system temp directory if extracting files.
Expand Down
4 changes: 1 addition & 3 deletions mismatch/cli.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import argparse
import os
import sqlite3
from pathlib import Path

from cve_bin_tool.database_defaults import DBNAME, DISK_LOCATION_DEFAULT
from cve_bin_tool.mismatch_loader import run_mismatch_loader

DBNAME = "cve.db"
DISK_LOCATION_DEFAULT = Path("~").expanduser() / ".cache" / "cve-bin-tool"
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
data_dir = os.path.join(parent_dir, "mismatch_data")
dbpath = DISK_LOCATION_DEFAULT / DBNAME
Expand Down
56 changes: 56 additions & 0 deletions test/test_database_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import importlib
import platform
from pathlib import Path

import pytest


@pytest.fixture
def patch_env(mocker):
def _patch_env(xdg_cache_home=None):
patched_env = {}
if platform.system() == "Windows":
# On Windows, Path.home() internally depends on environment variables:
# - HOMEDRIVE and HOMEPATH (used together to construct the home path or just HOMEPATH)
# - or USERPROFILE (used directly if present)
# If these are missing and os.environ is cleared (e.g. in tests), Path.home() will raise:
# RuntimeError: Could not determine home directory.
patched_env["HOMEDRIVE"] = "C:"
patched_env["HOMEPATH"] = "\\Users\\testuser"
if xdg_cache_home:
patched_env["XDG_CACHE_HOME"] = str(xdg_cache_home)

mocker.patch.dict("os.environ", patched_env, clear=True)

return _patch_env


def test_cache_paths_with_xdg(patch_env, tmp_path):
patch_env(xdg_cache_home=tmp_path)

import cve_bin_tool.database_defaults as db_defaults

importlib.reload(db_defaults)

assert db_defaults.CACHE_DIR == tmp_path
assert db_defaults.DISK_LOCATION_DEFAULT == tmp_path / "cve-bin-tool"
assert db_defaults.DISK_LOCATION_BACKUP == tmp_path / "cve-bin-tool-backup"
assert db_defaults.OLD_CACHE_DIR == Path.home() / ".cache" / "cvedb"
assert db_defaults.DBNAME == "cve.db"
assert db_defaults.NVD_FILENAME_TEMPLATE.format("2024") == "nvdcve-1.1-2024.json.gz"


def test_cache_paths_fallback_to_home(patch_env):
patch_env() # No XDG_CACHE_HOME

import cve_bin_tool.database_defaults as db_defaults

importlib.reload(db_defaults)

expected_cache = Path.home() / ".cache"
assert db_defaults.CACHE_DIR == expected_cache
assert db_defaults.DISK_LOCATION_DEFAULT == expected_cache / "cve-bin-tool"
assert db_defaults.DISK_LOCATION_BACKUP == expected_cache / "cve-bin-tool-backup"
assert db_defaults.OLD_CACHE_DIR == Path.home() / ".cache" / "cvedb"
assert db_defaults.DBNAME == "cve.db"
assert db_defaults.NVD_FILENAME_TEMPLATE.format("2023") == "nvdcve-1.1-2023.json.gz"