[LTP] [PATCH v3 1/2] doc: generate CVE catalog documentation
Andrea Cervesato
andrea.cervesato@suse.com
Tue Apr 28 09:14:31 CEST 2026
Hi!
The idea is good, a few comments on the implementation tho:
> Add a Sphinx builder hook to parse runtest/cve and generate a
> comprehensive CVE catalog in a single documentation file.
>
> The implementation:
> - Parses runtest/cve to extract CVE IDs, test names, and options
> - Generates a single CVE catalog file (_static/cves.rst) containing:
Please use just 'cve.rst' instead of 'cves.rst'. The plural is not
providing any info here.
> +def generate_cve_catalog(_):
> + """
> + Generate CVE catalog in a single file. Parse runtest/cve file and
> + generate documentation with links to CVE databases and test sources.
> + Similar to test_catalog, creates a single _static/cves.rst file with
> + all CVE information.
> + """
> + output = '_static/cves.rst'
> + runtest_cve = '../runtest/cve'
> +
> + # Parse runtest/cve file
> + cve_data = {}
> + cve_pattern = re.compile(r'^(cve-(\d{4})-\d+)\s+(\S+)(?:\s+(.*))?$')
Do we need a regexp for this? The runtest file is well defining the
following structure:
<cve-id> <binary> <arg0> <arg1> ..
We only need to split lines which are not starting with # char,
considering space as separator.
> +
> + try:
> + with open(runtest_cve, 'r', encoding='utf-8') as f:
> + for line in f:
> + line = line.strip()
> + if not line or line.startswith('#'):
> + continue
> +
> + match = cve_pattern.match(line)
> + if match:
> + cve_id = match.group(1).upper()
> + year = match.group(2)
> + test_name = match.group(3)
> + options = match.group(4) if match.group(4) else ''
> +
> + cve_data[cve_id] = {
> + 'cve_id': cve_id,
> + 'year': year,
> + 'test_name': test_name,
> + 'options': options,
> + }
> + except FileNotFoundError:
> + logger = sphinx.util.logging.getLogger(__name__)
> + msg = f"Can't find runtest/cve file ({runtest_cve})"
> + logger.warning(msg)
> + return
> +
> + # Generate single CVE catalog file
> + total_cves = len(cve_data)
> + text = [
> + '.. warning::',
> + ' The following CVE catalog has been generated from the',
> + ' runtest/cve file and includes all CVE reproducers in LTP.',
> + '',
> + f'LTP includes reproducers for {total_cves} known CVEs. These '
> + 'tests help verify',
> + 'that systems are patched against known vulnerabilities.',
> + '',
> + ]
> +
> + # Load metadata to check which tests have documentation
> + metadata = None
> + metadata_file = '../metadata/ltp.json'
> + try:
> + with open(metadata_file, 'r', encoding='utf-8') as data:
> + metadata = json.load(data)
> + except FileNotFoundError:
> + pass
> +
> + # Add CVEs in descending order (newest first)
> + for cve_id, cve_info in sorted(cve_data.items(), reverse=True):
> + cve_url = f"https://cve.mitre.org/cgi-bin/cvename.cgi?name={cve_id}"
> + test_name = cve_info["test_name"]
> +
> + # Only create cross-reference if test exists in metadata
> + if metadata and test_name in metadata.get('tests', {}):
> + # Create anchor using the correct document path prefix
> + test_anchor = f"users/test_catalog:{test_name}"
> + test_link = f":ref:`{test_name} <{test_anchor}>`"
> + else:
> + # If test not in metadata, just use plain text formatting
> + test_link = f"``{test_name}``"
> +
> + # Create section header with CVE ID and test name
> + section_title = f'{cve_id} ({test_name})'
> + text.extend([
> + section_title,
> + len(section_title) * '-',
> + '',
> + f'**CVE Reference:** `{cve_id} <{cve_url}>`_',
> + '',
> + f'**Test Name:** {test_link}',
> + '',
> + ])
> +
> + if cve_info['options']:
> + text.extend([
> + f'**Test Options:** ``{cve_info["options"]}``',
> + '',
> + ])
> +
> + # Build test command on a single line to avoid RST formatting issues
> + test_cmd = f'``{test_name}'
> + if cve_info['options']:
> + test_cmd += f' {cve_info["options"]}'
> + test_cmd += '``'
> +
> + text.extend([
> + f'This test reproduces the vulnerability described in {cve_id}.',
> + 'The test verifies that the system is properly patched against',
> + 'this known security vulnerability.',
> + '',
> + f'* **CVE Year:** {cve_info["year"]}',
> + f'* **Test Command:** {test_cmd}',
> + '',
> + '.. raw:: html',
> + '',
> + ' <hr>',
> + '',
> + ])
All this text is redundant and occupying space for no reason.
Also I'm not sure about this approach, now we have tests list duplication
inside the documentation.
What about generating only a simple reference table? There are only 3
information we need: CVE ID, test binary, year.
| ID | Test name | Year |
-------------------------
| .. | .. | .. |
etc..
There's no need to have a direct link to the CVE, since we already pointing
CVE to the Test catalog anyway.
--
Andrea Cervesato
SUSE QE Automation Engineer Linux
andrea.cervesato@suse.com
More information about the ltp
mailing list