Commit 653b90a91d

653b90a91d22b8290b57626d398ff5cb8efbbf37

parent: 4187ceff35

Verified · cmc

cmc <hello@cleberg.net> · 2026-08-07 02:13 UTC

Stamp catalog provenance and remove copyrighted control text

- Catalog carries a SHA-256 of its file; reports record the tool version
  and per-framework catalog version + hash
- Paraphrase the AICPA Trust Services Criteria titles into own-words labels
  (identifiers kept) and add copyright disclaimers to all catalogs
- Add MAPPING.md documenting sources, the NIST 177-control derivation, and
  review status
- Add ruff + pytest CI

Layout: unified · split

.github/workflows/ci.yml added +26
@@ -0,0 +1,26 @@
1name: CI
2
3on:
4 push:
5 pull_request:
6
7jobs:
8 test:
9 runs-on: ubuntu-latest
10 strategy:
11 matrix:
12 python-version: ["3.10", "3.12"]
13 steps:
14 - uses: actions/checkout@v5
15 - name: Set up Python ${{ matrix.python-version }}
16 uses: actions/setup-python@v6
17 with:
18 python-version: ${{ matrix.python-version }}
19 - name: Install
20 run: |
21 python -m pip install --upgrade pip
22 pip install -e ".[dev]"
23 - name: Ruff
24 run: ruff check .
25 - name: Tests
26 run: pytest -q
MAPPING.md added +62
@@ -0,0 +1,62 @@
1# Control catalogs — provenance and rationale
2
3`control-coverage` measures how much of a framework an evidence corpus addresses.
4The **denominator** is a framework catalog: the complete list of controls the
5framework defines. This document records where those catalogs come from, how they
6are versioned, and the limits of what they claim.
7
8## What these catalogs are — and are not
9
10- They enumerate control **identifiers** (e.g. `SOC2:CC6.1`, `ISO:A.5.17`,
11 `NIST:AC-2`) plus a short title used as a display label.
12- They are **not** the normative control text. For authoritative wording, consult
13 the source standard.
14- Mapping a control to an evidence signal is the **maintainers' interpretation**.
15 It is not reviewed or endorsed by the AICPA, ISO/IEC, or NIST.
16- Coverage is a measure of **evidence**, not of compliance. A control counted as
17 "addressed" means the corpus contains a signal relevant to it — not that the
18 control operates effectively. That judgment belongs to the organization and its
19 auditor.
20
21## Sources and revisions
22
23| Framework | Catalog file | Revision used | Scope |
24|---|---|---|---|
25| SOC 2 | `catalogs/soc2.yaml` | Trust Services Criteria 2017 (2022 revised points of focus) | All five categories: Security (Common Criteria), Availability, Confidentiality, Processing Integrity, Privacy |
26| ISO/IEC 27001 | `catalogs/iso27001.yaml` | 27001:2022 Annex A | All 93 Annex A controls, four themes |
27| NIST SP 800-53 | `catalogs/nist80053.yaml` | Rev. 5 / SP 800-53B **Moderate** baseline | 177 base controls (see below) |
28
29### How the NIST count is 177
30
31The NIST catalog is the base controls selected in the **SP 800-53B Moderate**
32impact baseline, across the 18 baseline-applicable families. Control
33**enhancements** (e.g. `AC-2(1)`) are not enumerated — coverage is measured at the
34base-control level. The Program Management (PM) family is organization-wide and
35not baseline-allocated; the Privacy (PT) family is selected via the separate
36privacy baseline. That selection is 177 base controls.
37
38## Versioning and traceability
39
40- Each catalog carries a `version` field, and every report stamps the catalog
41 `version` **and a SHA-256 of the catalog file** into its output (`tool` and
42 `frameworks[].sha256` in JSON; the header line in Markdown/HTML).
43- This lets an auditor tie any coverage result back to the exact denominator that
44 produced it, and re-perform against it.
45- Change the control set or a title and the SHA-256 changes; bump `version` on any
46 substantive change.
47
48## Authorship and review
49
50- **Author:** the audit-labs maintainer.
51- **Review status:** maintainer self-review. These catalogs have **not** been
52 through independent professional review; treat them accordingly and validate
53 against the source standards before relying on them in an engagement.
54- **Effective date:** 2026-08.
55
56## Copyright
57
58- **SOC 2 / Trust Services Criteria** — copyright AICPA. Only identifiers are
59 reproduced; titles are our own short-form paraphrases, not the criteria text.
60- **ISO/IEC 27001:2022** — copyright ISO/IEC. Only Annex A identifiers and short
61 titles are reproduced; normative text and guidance are not.
62- **NIST SP 800-53** — U.S. Government work in the public domain.
control_coverage/catalog.py +5 −1
@@ -15,6 +15,7 @@ Control codes are written ``FRAMEWORK:ID`` (for example ``SOC2:CC6.1``,
15 15
16from __future__ import annotations 16from __future__ import annotations
17 17
18import hashlib
18from dataclasses import dataclass 19from dataclasses import dataclass
19from pathlib import Path 20from pathlib import Path
20 21
@@ -60,6 +61,7 @@ class Catalog:
60 coverage: str # "complete" or "partial" 61 coverage: str # "complete" or "partial"
61 source: str 62 source: str
62 controls: list[Control] 63 controls: list[Control]
64 sha256: str = "" # digest of the catalog file, so coverage ties to a mapping
63 65
64 @property 66 @property
65 def complete(self) -> bool: 67 def complete(self) -> bool:
@@ -86,7 +88,8 @@ def _resolve(name: str) -> Path:
86def load(name: str) -> Catalog: 88def load(name: str) -> Catalog:
87 """Load a bundled catalog by framework name, short code, or alias.""" 89 """Load a bundled catalog by framework name, short code, or alias."""
88 path = _resolve(name) 90 path = _resolve(name)
89 raw = yaml.safe_load(path.read_text(encoding="utf-8")) 91 text = path.read_text(encoding="utf-8")
92 raw = yaml.safe_load(text)
90 framework = raw["framework"] 93 framework = raw["framework"]
91 controls = [ 94 controls = [
92 Control( 95 Control(
@@ -104,6 +107,7 @@ def load(name: str) -> Catalog:
104 coverage=raw.get("coverage", "partial"), 107 coverage=raw.get("coverage", "partial"),
105 source=raw.get("source", ""), 108 source=raw.get("source", ""),
106 controls=controls, 109 controls=controls,
110 sha256=hashlib.sha256(text.encode("utf-8")).hexdigest(),
107 ) 111 )
108 112
109 113
control_coverage/catalogs/iso27001.yaml +8 −1
@@ -2,11 +2,18 @@
2# 2#
3# This is exactly the list a Statement of Applicability enumerates. A control's 3# This is exactly the list a Statement of Applicability enumerates. A control's
4# full code is "ISO:<id>", matching the codes audit-report rulesets cite. 4# full code is "ISO:<id>", matching the codes audit-report rulesets cite.
5#
6# COPYRIGHT: ISO/IEC 27001:2022 is copyright ISO/IEC. Only the Annex A control
7# identifiers (e.g. A.5.17) and their short titles are reproduced here as labels;
8# the normative control text and implementation guidance are not. For the
9# authoritative wording, obtain the standard from ISO. These control-to-signal
10# mappings are the maintainers' interpretation and are not reviewed or endorsed
11# by ISO/IEC. See ../../MAPPING.md.
5framework: ISO 12framework: ISO
6name: ISO/IEC 27001:2022 Annex A 13name: ISO/IEC 27001:2022 Annex A
7version: "2022" 14version: "2022"
8coverage: complete 15coverage: complete
9source: ISO/IEC 27001:2022 Annex A 16source: ISO/IEC 27001:2022 Annex A (identifiers and short titles only)
10controls: 17controls:
11 # A.5 — Organizational controls 18 # A.5 — Organizational controls
12 - {id: A.5.1, family: Organizational, title: "Policies for information security."} 19 - {id: A.5.1, family: Organizational, title: "Policies for information security."}
control_coverage/catalogs/nist80053.yaml +4
@@ -6,6 +6,10 @@
6# management (PM) family is org-wide and not baseline-allocated; the privacy (PT) 6# management (PM) family is org-wide and not baseline-allocated; the privacy (PT)
7# family is selected via the separate privacy baseline. A control's full code is 7# family is selected via the separate privacy baseline. A control's full code is
8# "NIST:<id>". 8# "NIST:<id>".
9#
10# COPYRIGHT: NIST SP 800-53 is a U.S. Government work in the public domain. The
11# control-to-signal mappings, however, are the maintainers' interpretation and
12# are not reviewed or endorsed by NIST. See ../../MAPPING.md.
9framework: NIST 13framework: NIST
10name: NIST SP 800-53 Rev. 5 (Moderate baseline) 14name: NIST SP 800-53 Rev. 5 (Moderate baseline)
11version: "Rev. 5" 15version: "Rev. 5"
control_coverage/catalogs/soc2.yaml +72 −64
@@ -1,85 +1,93 @@
1# SOC 2 — Trust Services Criteria (AICPA, 2017 with 2022 revised points of focus). 1# SOC 2 — Trust Services Criteria (AICPA, 2017 with 2022 revised points of focus).
2# 2#
3# The full Common Criteria (the "Security" category every SOC 2 report covers) 3# The full Common Criteria (the "Security" category every SOC 2 report covers)
4# plus the Availability category. A control's full code is "SOC2:<id>", matching 4# plus the Availability, Confidentiality, Processing Integrity, and Privacy
5# the codes audit-report rulesets cite. 5# categories. A control's full code is "SOC2:<id>", matching the codes
6# audit-report rulesets cite.
7#
8# COPYRIGHT: The Trust Services Criteria are copyright AICPA. The `title` fields
9# below are our own short-form paraphrases used as labels — not the normative
10# criteria text. Only the criterion identifiers (e.g. CC6.1) are reproduced. For
11# the authoritative wording and points of focus, consult the AICPA TSC. These
12# control-to-signal mappings are the maintainers' interpretation and are not
13# reviewed or endorsed by the AICPA. See ../../MAPPING.md.
6framework: SOC2 14framework: SOC2
7name: SOC 2 (Trust Services Criteria) 15name: SOC 2 (Trust Services Criteria)
8version: "2017 (rev. 2022)" 16version: "2017 (rev. 2022)"
9coverage: complete 17coverage: complete
10source: AICPA Trust Services Criteria 18source: AICPA Trust Services Criteria (identifiers only; titles paraphrased)
11controls: 19controls:
12 # CC1 — Control Environment 20 # CC1 — Control Environment
13 - {id: CC1.1, family: Control Environment, title: "The entity demonstrates a commitment to integrity and ethical values."} 21 - {id: CC1.1, family: Control Environment, title: "Commitment to integrity and ethical values"}
14 - {id: CC1.2, family: Control Environment, title: "The board of directors demonstrates independence and exercises oversight of internal control."} 22 - {id: CC1.2, family: Control Environment, title: "Board independence and internal-control oversight"}
15 - {id: CC1.3, family: Control Environment, title: "Management establishes structures, reporting lines, and appropriate authorities and responsibilities."} 23 - {id: CC1.3, family: Control Environment, title: "Structures, reporting lines, and authorities established"}
16 - {id: CC1.4, family: Control Environment, title: "The entity demonstrates a commitment to attract, develop, and retain competent individuals."} 24 - {id: CC1.4, family: Control Environment, title: "Commitment to attracting and retaining competent people"}
17 - {id: CC1.5, family: Control Environment, title: "The entity holds individuals accountable for their internal control responsibilities."} 25 - {id: CC1.5, family: Control Environment, title: "Accountability for internal-control responsibilities"}
18 # CC2 — Communication and Information 26 # CC2 — Communication and Information
19 - {id: CC2.1, family: Communication and Information, title: "The entity obtains or generates relevant, quality information to support internal control."} 27 - {id: CC2.1, family: Communication and Information, title: "Relevant, quality information supporting internal control"}
20 - {id: CC2.2, family: Communication and Information, title: "The entity internally communicates information, including objectives and responsibilities for internal control."} 28 - {id: CC2.2, family: Communication and Information, title: "Internal communication of control objectives and duties"}
21 - {id: CC2.3, family: Communication and Information, title: "The entity communicates with external parties about matters affecting internal control."} 29 - {id: CC2.3, family: Communication and Information, title: "External communication on internal-control matters"}
22 # CC3 — Risk Assessment 30 # CC3 — Risk Assessment
23 - {id: CC3.1, family: Risk Assessment, title: "The entity specifies objectives with sufficient clarity to enable identification of risks."} 31 - {id: CC3.1, family: Risk Assessment, title: "Objectives specified clearly enough to identify risk"}
24 - {id: CC3.2, family: Risk Assessment, title: "The entity identifies and analyzes risks to the achievement of its objectives."} 32 - {id: CC3.2, family: Risk Assessment, title: "Identification and analysis of risks to objectives"}
25 - {id: CC3.3, family: Risk Assessment, title: "The entity considers the potential for fraud in assessing risks."} 33 - {id: CC3.3, family: Risk Assessment, title: "Fraud potential considered in risk assessment"}
26 - {id: CC3.4, family: Risk Assessment, title: "The entity identifies and assesses changes that could significantly affect internal control."} 34 - {id: CC3.4, family: Risk Assessment, title: "Assessment of changes affecting internal control"}
27 # CC4 — Monitoring Activities 35 # CC4 — Monitoring Activities
28 - {id: CC4.1, family: Monitoring Activities, title: "The entity selects, develops, and performs ongoing and separate evaluations of internal control."} 36 - {id: CC4.1, family: Monitoring Activities, title: "Ongoing and separate evaluations of internal control"}
29 - {id: CC4.2, family: Monitoring Activities, title: "The entity evaluates and communicates internal control deficiencies in a timely manner."} 37 - {id: CC4.2, family: Monitoring Activities, title: "Timely evaluation and reporting of control deficiencies"}
30 # CC5 — Control Activities 38 # CC5 — Control Activities
31 - {id: CC5.1, family: Control Activities, title: "The entity selects and develops control activities that mitigate risks to acceptable levels."} 39 - {id: CC5.1, family: Control Activities, title: "Control activities selected to mitigate risk"}
32 - {id: CC5.2, family: Control Activities, title: "The entity selects and develops general control activities over technology."} 40 - {id: CC5.2, family: Control Activities, title: "General technology controls developed"}
33 - {id: CC5.3, family: Control Activities, title: "The entity deploys control activities through policies and procedures."} 41 - {id: CC5.3, family: Control Activities, title: "Control activities deployed via policies and procedures"}
34 # CC6 — Logical and Physical Access Controls 42 # CC6 — Logical and Physical Access Controls
35 - {id: CC6.1, family: Logical and Physical Access Controls, title: "The entity implements logical access security software, infrastructure, and architectures over protected assets."} 43 - {id: CC6.1, family: Logical and Physical Access Controls, title: "Logical access security over protected assets"}
36 - {id: CC6.2, family: Logical and Physical Access Controls, title: "The entity registers and authorizes new users before granting access, and removes access when appropriate."} 44 - {id: CC6.2, family: Logical and Physical Access Controls, title: "User registration, authorization, and deprovisioning"}
37 - {id: CC6.3, family: Logical and Physical Access Controls, title: "The entity authorizes, modifies, or removes access based on roles and least privilege."} 45 - {id: CC6.3, family: Logical and Physical Access Controls, title: "Role- and least-privilege-based access management"}
38 - {id: CC6.4, family: Logical and Physical Access Controls, title: "The entity restricts physical access to facilities and protected information assets."} 46 - {id: CC6.4, family: Logical and Physical Access Controls, title: "Physical access restricted to facilities and assets"}
39 - {id: CC6.5, family: Logical and Physical Access Controls, title: "The entity discontinues logical and physical protections over assets only after the ability to read data has been removed."} 47 - {id: CC6.5, family: Logical and Physical Access Controls, title: "Protections removed only after data made unreadable"}
40 - {id: CC6.6, family: Logical and Physical Access Controls, title: "The entity implements logical access security measures against threats from outside its system boundaries."} 48 - {id: CC6.6, family: Logical and Physical Access Controls, title: "Perimeter defenses against external threats"}
41 - {id: CC6.7, family: Logical and Physical Access Controls, title: "The entity restricts the transmission, movement, and removal of information to authorized users and processes."} 49 - {id: CC6.7, family: Logical and Physical Access Controls, title: "Restricted transmission and removal of information"}
42 - {id: CC6.8, family: Logical and Physical Access Controls, title: "The entity implements controls to prevent or detect and act upon unauthorized or malicious software."} 50 - {id: CC6.8, family: Logical and Physical Access Controls, title: "Prevention and detection of unauthorized software"}
43 # CC7 — System Operations 51 # CC7 — System Operations
44 - {id: CC7.1, family: System Operations, title: "The entity uses detection and monitoring procedures to identify configuration changes and new vulnerabilities."} 52 - {id: CC7.1, family: System Operations, title: "Detection of configuration changes and vulnerabilities"}
45 - {id: CC7.2, family: System Operations, title: "The entity monitors system components for anomalies indicative of malicious acts or errors."} 53 - {id: CC7.2, family: System Operations, title: "Monitoring for anomalies indicating malicious acts"}
46 - {id: CC7.3, family: System Operations, title: "The entity evaluates security events to determine whether they could or did result in a failure to meet objectives."} 54 - {id: CC7.3, family: System Operations, title: "Evaluation of security events against objectives"}
47 - {id: CC7.4, family: System Operations, title: "The entity responds to identified security incidents through a defined program."} 55 - {id: CC7.4, family: System Operations, title: "Defined security-incident response program"}
48 - {id: CC7.5, family: System Operations, title: "The entity identifies, develops, and implements activities to recover from security incidents."} 56 - {id: CC7.5, family: System Operations, title: "Recovery from security incidents"}
49 # CC8 — Change Management 57 # CC8 — Change Management
50 - {id: CC8.1, family: Change Management, title: "The entity authorizes, designs, develops, tests, approves, and implements changes to infrastructure, data, and software."} 58 - {id: CC8.1, family: Change Management, title: "Change management across infrastructure, data, and software"}
51 # CC9 — Risk Mitigation 59 # CC9 — Risk Mitigation
52 - {id: CC9.1, family: Risk Mitigation, title: "The entity identifies, selects, and develops risk mitigation activities for disruptions."} 60 - {id: CC9.1, family: Risk Mitigation, title: "Risk-mitigation activities for business disruptions"}
53 - {id: CC9.2, family: Risk Mitigation, title: "The entity assesses and manages risks associated with vendors and business partners."} 61 - {id: CC9.2, family: Risk Mitigation, title: "Vendor and business-partner risk management"}
54 # Availability category 62 # Availability category
55 - {id: A1.1, family: Availability, title: "The entity maintains, monitors, and evaluates current processing capacity to meet demand."} 63 - {id: A1.1, family: Availability, title: "Processing-capacity monitoring against demand"}
56 - {id: A1.2, family: Availability, title: "The entity authorizes, designs, and implements environmental protections, backup, and recovery infrastructure."} 64 - {id: A1.2, family: Availability, title: "Environmental protections, backup, and recovery infrastructure"}
57 - {id: A1.3, family: Availability, title: "The entity tests recovery plan procedures supporting system recovery."} 65 - {id: A1.3, family: Availability, title: "Recovery-plan testing"}
58 # Confidentiality category 66 # Confidentiality category
59 - {id: C1.1, family: Confidentiality, title: "The entity identifies and maintains confidential information to meet its objectives related to confidentiality."} 67 - {id: C1.1, family: Confidentiality, title: "Identification and safeguarding of confidential information"}
60 - {id: C1.2, family: Confidentiality, title: "The entity disposes of confidential information to meet its objectives related to confidentiality."} 68 - {id: C1.2, family: Confidentiality, title: "Disposal of confidential information"}
61 # Processing Integrity category 69 # Processing Integrity category
62 - {id: PI1.1, family: Processing Integrity, title: "The entity obtains or generates, uses, and communicates relevant, quality information about processing objectives, including product and service specifications."} 70 - {id: PI1.1, family: Processing Integrity, title: "Quality information about processing objectives and specs"}
63 - {id: PI1.2, family: Processing Integrity, title: "The entity implements policies and procedures over system inputs, including controls over completeness and accuracy, to meet its objectives."} 71 - {id: PI1.2, family: Processing Integrity, title: "Input controls for completeness and accuracy"}
64 - {id: PI1.3, family: Processing Integrity, title: "The entity implements policies and procedures over system processing to result in products, services, and reporting that meet its objectives."} 72 - {id: PI1.3, family: Processing Integrity, title: "Processing controls producing objective-meeting output"}
65 - {id: PI1.4, family: Processing Integrity, title: "The entity implements policies and procedures to make available or deliver output completely, accurately, and in a timely manner to meet its objectives."} 73 - {id: PI1.4, family: Processing Integrity, title: "Output delivered completely, accurately, and on time"}
66 - {id: PI1.5, family: Processing Integrity, title: "The entity implements policies and procedures to store inputs, items in processing, and outputs completely, accurately, and in a timely manner to meet its objectives."} 74 - {id: PI1.5, family: Processing Integrity, title: "Storage of inputs, work in process, and outputs"}
67 # Privacy category 75 # Privacy category
68 - {id: P1.1, family: Privacy, title: "The entity provides notice to data subjects about its privacy practices to meet its objectives related to privacy."} 76 - {id: P1.1, family: Privacy, title: "Notice of privacy practices to data subjects"}
69 - {id: P2.1, family: Privacy, title: "The entity communicates choices about the collection, use, retention, disclosure, and disposal of personal information, and obtains consent, to meet its privacy objectives."} 77 - {id: P2.1, family: Privacy, title: "Choice and consent over personal-information handling"}
70 - {id: P3.1, family: Privacy, title: "Personal information is collected consistent with the entity's objectives related to privacy."} 78 - {id: P3.1, family: Privacy, title: "Collection consistent with privacy objectives"}
71 - {id: P3.2, family: Privacy, title: "For information requiring explicit consent, the entity communicates the need for and obtains consent prior to collection of personal information."} 79 - {id: P3.2, family: Privacy, title: "Explicit consent obtained before collection where required"}
72 - {id: P4.1, family: Privacy, title: "The entity limits the use of personal information to the purposes identified in its objectives related to privacy."} 80 - {id: P4.1, family: Privacy, title: "Use of personal information limited to stated purposes"}
73 - {id: P4.2, family: Privacy, title: "The entity retains personal information consistent with its objectives related to privacy."} 81 - {id: P4.2, family: Privacy, title: "Retention of personal information per objectives"}
74 - {id: P4.3, family: Privacy, title: "The entity securely disposes of personal information to meet its objectives related to privacy."} 82 - {id: P4.3, family: Privacy, title: "Secure disposal of personal information"}
75 - {id: P5.1, family: Privacy, title: "The entity grants data subjects the ability to access their stored personal information for review and, upon request, provides copies, to meet its privacy objectives."} 83 - {id: P5.1, family: Privacy, title: "Data-subject access to their personal information"}
76 - {id: P5.2, family: Privacy, title: "The entity corrects, amends, or appends personal information based on data subject input and communicates it to third parties, to meet its privacy objectives."} 84 - {id: P5.2, family: Privacy, title: "Correction and amendment of personal information"}
77 - {id: P6.1, family: Privacy, title: "The entity discloses personal information to third parties only with the explicit consent of data subjects and consistent with its privacy objectives."} 85 - {id: P6.1, family: Privacy, title: "Third-party disclosure only with consent"}
78 - {id: P6.2, family: Privacy, title: "The entity creates and retains a complete, accurate, and timely record of authorized disclosures of personal information."} 86 - {id: P6.2, family: Privacy, title: "Record of authorized disclosures"}
79 - {id: P6.3, family: Privacy, title: "The entity creates and retains a complete, accurate, and timely record of detected or reported unauthorized disclosures of personal information."} 87 - {id: P6.3, family: Privacy, title: "Record of unauthorized disclosures"}
80 - {id: P6.4, family: Privacy, title: "The entity obtains privacy commitments from vendors and other third parties who have access to personal information, to meet its privacy objectives."} 88 - {id: P6.4, family: Privacy, title: "Privacy commitments obtained from vendors and third parties"}
81 - {id: P6.5, family: Privacy, title: "The entity obtains commitments from vendors and third parties to notify it of actual or suspected unauthorized disclosures of personal information."} 89 - {id: P6.5, family: Privacy, title: "Vendor commitments to notify of unauthorized disclosure"}
82 - {id: P6.6, family: Privacy, title: "The entity provides notification of breaches and incidents of unauthorized disclosure of personal information to affected data subjects, regulators, and others."} 90 - {id: P6.6, family: Privacy, title: "Breach notification to affected parties and regulators"}
83 - {id: P6.7, family: Privacy, title: "The entity provides data subjects with an accounting of the personal information held and disclosures made, upon request."} 91 - {id: P6.7, family: Privacy, title: "Accounting of personal information and disclosures on request"}
84 - {id: P7.1, family: Privacy, title: "The entity collects and maintains accurate, up-to-date, complete, and relevant personal information to meet its privacy objectives."} 92 - {id: P7.1, family: Privacy, title: "Accuracy and currency of personal information"}
85 - {id: P8.1, family: Privacy, title: "The entity implements a process for receiving, addressing, resolving, and communicating the resolution of privacy inquiries, complaints, and disputes."} 93 - {id: P8.1, family: Privacy, title: "Handling of privacy inquiries, complaints, and disputes"}
control_coverage/reporters/html.py +7 −1
@@ -9,6 +9,7 @@ from __future__ import annotations
9from html import escape 9from html import escape
10from typing import TYPE_CHECKING 10from typing import TYPE_CHECKING
11 11
12from .. import __version__
12from ..coverage import ( 13from ..coverage import (
13 ASSERTED, 14 ASSERTED,
14 FAILING, 15 FAILING,
@@ -214,7 +215,11 @@ def _blind_spots(report: CoverageReport) -> str:
214 215
215def render(report: CoverageReport) -> str: 216def render(report: CoverageReport) -> str:
216 title = report.subject or "Evidence corpus" 217 title = report.subject or "Evidence corpus"
217 frameworks = ", ".join(fc.catalog.framework for fc in report.frameworks) 218 frameworks = ", ".join(
219 f"{fc.catalog.framework} {fc.catalog.version} "
220 f"(sha256:{fc.catalog.sha256[:12]})"
221 for fc in report.frameworks
222 )
218 body = [ 223 body = [
219 "<!doctype html><html lang='en'><head><meta charset='utf-8'>", 224 "<!doctype html><html lang='en'><head><meta charset='utf-8'>",
220 "<meta name='viewport' content='width=device-width, initial-scale=1'>", 225 "<meta name='viewport' content='width=device-width, initial-scale=1'>",
@@ -223,6 +228,7 @@ def render(report: CoverageReport) -> str:
223 f"<h1>Control Coverage — {escape(title)}</h1>", 228 f"<h1>Control Coverage — {escape(title)}</h1>",
224 ( 229 (
225 f'<p class="meta">Generated {escape(report.generated_at)} · ' 230 f'<p class="meta">Generated {escape(report.generated_at)} · '
231 f"Tool control-coverage {escape(__version__)} · "
226 f"{report.source_count} evidence source(s) · frameworks: {escape(frameworks)}</p>" 232 f"{report.source_count} evidence source(s) · frameworks: {escape(frameworks)}</p>"
227 ), 233 ),
228 ( 234 (
control_coverage/reporters/json.py +4
@@ -9,6 +9,8 @@ from __future__ import annotations
9import json as _json 9import json as _json
10from typing import TYPE_CHECKING 10from typing import TYPE_CHECKING
11 11
12from .. import __version__
13
12if TYPE_CHECKING: 14if TYPE_CHECKING:
13 from ..coverage import CoverageReport 15 from ..coverage import CoverageReport
14 16
@@ -18,11 +20,13 @@ def to_dict(report: CoverageReport) -> dict:
18 "subject": report.subject, 20 "subject": report.subject,
19 "generated_at": report.generated_at, 21 "generated_at": report.generated_at,
20 "source_count": report.source_count, 22 "source_count": report.source_count,
23 "tool": {"name": "control-coverage", "version": __version__},
21 "frameworks": [ 24 "frameworks": [
22 { 25 {
23 "framework": fc.catalog.framework, 26 "framework": fc.catalog.framework,
24 "name": fc.catalog.name, 27 "name": fc.catalog.name,
25 "version": fc.catalog.version, 28 "version": fc.catalog.version,
29 "sha256": fc.catalog.sha256,
26 "catalog_coverage": fc.catalog.coverage, 30 "catalog_coverage": fc.catalog.coverage,
27 "in_scope": fc.in_scope, 31 "in_scope": fc.in_scope,
28 "addressed": fc.addressed, 32 "addressed": fc.addressed,
control_coverage/reporters/markdown.py +6 −1
@@ -4,6 +4,7 @@ from __future__ import annotations
4 4
5from typing import TYPE_CHECKING 5from typing import TYPE_CHECKING
6 6
7from .. import __version__
7from ..coverage import ( 8from ..coverage import (
8 ASSERTED, 9 ASSERTED,
9 FAILING, 10 FAILING,
@@ -108,8 +109,12 @@ def render(report: CoverageReport) -> str:
108 out.append(f"# Control Coverage — {title}") 109 out.append(f"# Control Coverage — {title}")
109 out.append("") 110 out.append("")
110 out.append(f"- **Generated:** {report.generated_at}") 111 out.append(f"- **Generated:** {report.generated_at}")
112 out.append(f"- **Tool:** control-coverage {__version__}")
111 out.append(f"- **Corpus:** {report.source_count} evidence source(s)") 113 out.append(f"- **Corpus:** {report.source_count} evidence source(s)")
112 frameworks = ", ".join(fc.catalog.framework for fc in report.frameworks) 114 frameworks = ", ".join(
115 f"{fc.catalog.framework} {fc.catalog.version} (`sha256:{fc.catalog.sha256[:12]}`)"
116 for fc in report.frameworks
117 )
113 out.append(f"- **Frameworks:** {frameworks}") 118 out.append(f"- **Frameworks:** {frameworks}")
114 out.append("") 119 out.append("")
115 out.append( 120 out.append(
tests/test_reporters.py +9
@@ -34,6 +34,15 @@ def test_json_is_valid_and_structured():
34 assert "unaddressed" in states 34 assert "unaddressed" in states
35 35
36 36
37def test_json_stamps_tool_and_catalog_provenance():
38 from control_coverage import __version__
39
40 doc = _json.loads(reporters.render(_report(), "json"))
41 assert doc["tool"] == {"name": "control-coverage", "version": __version__}
42 soc2 = doc["frameworks"][0]
43 assert len(soc2["sha256"]) == 64 # full SHA-256 hex digest of the catalog file
44
45
37def test_html_is_self_contained(): 46def test_html_is_self_contained():
38 html = reporters.render(_report(), "html") 47 html = reporters.render(_report(), "html")
39 assert html.startswith("<!doctype html>") 48 assert html.startswith("<!doctype html>")