Skip to content

Add CRA Compliance Track B: OSCAL 1.1.2 three-tier traceability#1271

Merged
spoorcc merged 8 commits into
mainfrom
claude/security-compliance-track-az9072
Jun 15, 2026
Merged

Add CRA Compliance Track B: OSCAL 1.1.2 three-tier traceability#1271
spoorcc merged 8 commits into
mainfrom
claude/security-compliance-track-az9072

Conversation

@spoorcc

@spoorcc spoorcc commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Maps all 13 CRA Annex I Part I essential requirements (ECR-a–m) through
prEN 40000-1-4 Security Objectives (SO.*) to dfetch controls (C-001–C-046).
Covers Part II vulnerability-handling requirements via prEN 40000-1-3.

New files:

  • security/cra_pren_4000014_oscal_catalog.json — prEN 40000-1-4 OSCAL 1.1.2
    Catalog derived from the CEN/CLC/JTC 13 WG 9 deep-dive session (March 2026,
    Angelo D'Amato, Vulnir B.V. / STAN4CR)
  • security/compliance_data.py — data classes and all compliance constants
  • security/compliance.py — OSCAL builder and RST renderer; run with
    python -m security.compliance --component ... --rst
  • security/dfetch.component-definition.json — generated OSCAL Component Definition
  • doc/explanation/compliance_track.rst — generated human-readable RST

Introduces four Track B controls:

  • C-043: release-gate CVE check on runtime dependencies (ECR-a)
  • C-044: data minimisation policy (ECR-g)
  • C-045: destination-path sensitivity warning (ECR-i)
  • C-046: exploit mitigation inventory (ECR-k)

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ

Summary by CodeRabbit

  • New Features
    • Introduced CRA Compliance Track B framework with traceability from essential requirements to security objectives
    • Added compliance-only coverage for new controls C-043 through C-046
    • Published machine-readable OSCAL 1.1.2 component-definition artifacts for Track B
  • Documentation
    • Added detailed compliance documentation, including applicability, implementation status, and gap analysis
    • Updated security guidance describing how the Track B artifacts are produced and used
  • Build/Release
    • Updated the release pipeline to generate and upload the OSCAL component-definition alongside the SBOM for each release

Maps all 13 CRA Annex I Part I essential requirements (ECR-a–m) through
prEN 40000-1-4 Security Objectives (SO.*) to dfetch controls (C-001–C-046).
Covers Part II vulnerability-handling requirements via prEN 40000-1-3.

New files:
- security/cra_pren_4000014_oscal_catalog.json — prEN 40000-1-4 OSCAL 1.1.2
  Catalog derived from the CEN/CLC/JTC 13 WG 9 deep-dive session (March 2026,
  Angelo D'Amato, Vulnir B.V. / STAN4CR)
- security/compliance_data.py — data classes and all compliance constants
- security/compliance.py — OSCAL builder and RST renderer; run with
  `python -m security.compliance --component ... --rst`
- security/dfetch.component-definition.json — generated OSCAL Component Definition
- doc/explanation/compliance_track.rst — generated human-readable RST

Introduces four Track B controls:
- C-043: release-gate CVE check on runtime dependencies (ECR-a)
- C-044: data minimisation policy (ECR-g)
- C-045: destination-path sensitivity warning (ECR-i)
- C-046: exploit mitigation inventory (ECR-k)

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@spoorcc, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 37 minutes and 40 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d943c57-f8ef-4352-8c5d-ed724cb6d5f7

📥 Commits

Reviewing files that changed from the base of the PR and between b7329d2 and 3f13262.

📒 Files selected for processing (7)
  • .github/workflows/python-publish.yml
  • CHANGELOG.rst
  • doc/explanation/compliance_track.rst
  • security/README.md
  • security/compliance.py
  • security/compliance_data.py
  • security/dfetch.component-definition.json

Walkthrough

Introduces CRA Compliance Track B for dfetch under OSCAL 1.1.2. A new static data module defines dataclasses and compliance mapping constants (ECR-a through ECR-m, controls C-043–C-046). A CLI generator script produces both OSCAL Component Definition JSON and a human-readable RST document from that data. Two OSCAL JSON artifacts and updated documentation are committed alongside.

Changes

CRA Compliance Track B

Layer / File(s) Summary
Compliance data schemas and static mapping constants
security/compliance_data.py
Defines Control, ApplicableStandard, SOImplementation, PartIIRequirement dataclasses and populates CLASSIFICATION_DECISION, STANDARDS, TRACK_B_CONTROLS (C-043–C-046), SO_IMPLEMENTATIONS (ECR-a through ECR-m), and PART_II_REQUIREMENTS (pii-01 through pii-07).
OSCAL and RST generator
security/compliance.py
Adds helper functions for deterministic UUID generation, catalog loading, Track A control merging, and deduplication; implements build_oscal_component_definition() producing OSCAL 1.1.2 Component Definition JSON and render_rst() producing the full RST document with all section renderers; exposes a CLI entrypoint with --component, --rst, and --version flags.
Committed OSCAL JSON artifacts
security/cra_pren_4000014_oscal_catalog.json, security/dfetch.component-definition.json
Adds the static prEN 40000-1-4 OSCAL catalog defining ECR groups (a)–(m) with nested security objectives and technical controls, and the generated dfetch component-definition mapping SO.* objectives to controls with implementation statuses, gaps, and narrative statements.
Documentation and changelog
doc/explanation/compliance_track.rst, doc/explanation/security.rst, security/README.md, CHANGELOG.rst, .github/workflows/python-publish.yml
Adds the generated compliance_track.rst covering classification, standards, Part I/II ECR tables, gap analysis for C-043–C-046, and the final merged control register; extends security.rst with a Track B subsection; updates security/README.md with regeneration instructions; records the 0.15.0 unreleased changelog entry; configures build workflow to generate and publish OSCAL component-definition artifact alongside SBOM.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • dfetch-org/dfetch#1171: Both PRs modify .github/workflows/python-publish.yml to change what gets generated and attached to GitHub Releases (the retrieved PR adds Python CycloneDX SBOM publishing, while this PR extends the release flow to also upload the generated OSCAL component definition alongside the SBOM).

Suggested labels

development, documentation, github_actions

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main addition: CRA Compliance Track B implementation with OSCAL 1.1.2 three-tier traceability mapping.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/security-compliance-track-az9072

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@security/compliance_data.py`:
- Around line 254-298: The control IDs referenced in the controls=[...] lists
within the SOImplementation entries in the compliance_data.py file (at lines
254-298, 390-399, and 531-540) do not match the authoritative control register
semantics, breaking ECR-to-SO-to-control traceability. Audit the authoritative
control register to determine the correct control IDs that should be assigned to
each SO_IMPLEMENTATIONS entry, then update all instances of the controls=[...]
parameter across all three affected sections to use the verified IDs.
Additionally, implement a generation-time consistency check (likely in the
register generation logic) that validates all referenced control IDs exist in
the authoritative register and have matching semantics, failing fast if any
mismatches are detected.

In `@security/compliance.py`:
- Around line 426-434: The C-045 security control description in the
compliance.py file contains a reference to dfetch/manifest/project.py for the
plaintext_warning() pattern implementation, but Track B control metadata
specifies the canonical location as dfetch/project/subproject.py. Update the
file path reference in the docstring from dfetch/manifest/project.py to
dfetch/project/subproject.py to maintain consistency with the official Track B
control metadata and ensure proper traceability of the planned C-045
implementation.
- Around line 459-465: The hardcoded text "Three CRA essential requirements" in
the _render_gap_analysis function does not match the actual number of gap
entries returned by _gap_entries(), which emits four controls (C-043–C-046).
Make the text data-driven by dynamically counting the entries from
_gap_entries() and using that count in the print statement, or update the
hardcoded number to four to keep the generated documentation consistent with the
actual data.
- Around line 64-71: The _load_track_a_controls function silently returns an
empty list when importing the pytm modules fails, which can produce incomplete
compliance artifacts without alerting users. Either remove the try-except block
to fail fast when the imports are required, or add an explicit degraded mode
flag that must be set to True before allowing the ImportError to be caught and
an empty list returned. This ensures that missing Track A controls are not
silently omitted from compliance output unless the caller has explicitly opted
into degraded mode operation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 51d86c6b-eaa6-40d9-ad71-20a484dae8d8

📥 Commits

Reviewing files that changed from the base of the PR and between e35c251 and 80a9892.

📒 Files selected for processing (8)
  • CHANGELOG.rst
  • doc/explanation/compliance_track.rst
  • doc/explanation/security.rst
  • security/README.md
  • security/compliance.py
  • security/compliance_data.py
  • security/cra_pren_4000014_oscal_catalog.json
  • security/dfetch.component-definition.json

Comment thread security/compliance_data.py
Comment thread security/compliance.py Outdated
Comment thread security/compliance.py Outdated
Comment thread security/compliance.py
- compliance.py: C-045 gap description now references
  dfetch/project/subproject.py (the planned implementation location) instead
  of dfetch/manifest/project.py (where plaintext_warning is defined) —
  aligns with the Track B control metadata

- compliance.py: replace hardcoded "Three CRA essential requirements"
  with a data-driven count derived from _gap_entries(), so the generated
  RST always matches the actual number of gap controls listed

- compliance.py: emit a stderr note when pytm is not installed and
  Track A controls are omitted from the control register, preventing
  a silently incomplete artifact

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
DataStoredConfidentiality: .dfetch_data.yaml plaintext storage is a conscious
choice — the developer workstation is a trusted boundary (as established in the
usage threat model), and C-036 ensures no credentials reach disk. The threat
model explicitly marks metadata_store.storesSensitiveData = False and
isDestEncryptedAtRest = False. Status: implemented.

DataTransmittedConfidentiality: plaintext transport (http://, git://, svn://)
is accepted for legacy source compatibility. C-009 warns the user before
proceeding (threat model: "Detection only — dfetch still proceeds"). C-005
provides content integrity for archives independent of transport. Status:
implemented.

ComAuth: HTTPS (C-003) and SSH (C-004) provide authenticity for the common
cases; plain git:// / svn:// are accepted with C-009 warning under the same
legacy-compatibility design decision. Status: implemented.

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
ECR-i (so-prevent-attack-propagation): path traversal outside the project
tree is prevented by C-001 (check_no_path_traversal). The residual risk of a
manifest declaring a sensitive dst: (e.g. .github/workflows/) is explicitly
accepted in the usage threat model under the 'Manifest under code review'
assumption. C-045 is removed — the gap does not exist.

ECR-m (so-secure-data-deletion): .dfetch_data.yaml contains only
non-sensitive metadata (credentials stripped by C-036); standard OS file
deletion is sufficient. No secure-wipe is needed.

C-045 removed from TRACK_B_CONTROLS and _gap_entries(); CHANGELOG updated.

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
claude added 2 commits June 15, 2026 19:45
Generate dfetch.component-definition.json during the build job using the
installed package version, upload as a CI artifact, and attach it to the
GitHub Release alongside the SBOM.

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
Uses actions/attest-build-provenance (same pinned SHA as build.yml) to
sign dfetch.component-definition.json via Sigstore. Verifiable with:

  gh attestation verify dfetch.component-definition.json \
    --repo dfetch-org/dfetch \
    --predicate-type https://slsa.dev/provenance/v1

No new permissions or egress endpoints needed — the build job already
has attestations: write, id-token: write, and Sigstore in the allowlist.

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
@spoorcc

spoorcc commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@spoorcc

spoorcc commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
doc/explanation/compliance_track.rst (2)

1-1: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Generated artifacts are not pre-commit-clean, causing CI failure.
Please commit the auto-fixes from pre-commit so the branch is mergeable.

  • doc/explanation/compliance_track.rst#L1-L1: regenerate and commit whitespace/EOF fixes (trailing-whitespace, end-of-file-fixer).
  • security/dfetch.component-definition.json#L1-L1: commit EOF normalization from end-of-file-fixer.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doc/explanation/compliance_track.rst` at line 1, The generated artifacts have
pre-commit hook violations that are blocking CI. In
doc/explanation/compliance_track.rst (line 1-1), regenerate the file and commit
the fixes for trailing-whitespace and end-of-file-fixer violations. In
security/dfetch.component-definition.json (line 1-1), commit the EOF
normalization fix from the end-of-file-fixer hook. Run pre-commit hooks locally
to auto-fix these issues, then stage and commit the cleaned artifacts to make
the branch mergeable.

Source: Pipeline failures


62-77: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Escape wildcard * literals to stop docutils parsing warnings.

The current text includes raw wildcard patterns (e.g., GEC-*, .github/workflows/*.yml) that docutils parses as malformed inline emphasis, matching the pipeline warnings. Please wrap those patterns in literals (...) or escape * so generated docs are warning-free.

Also applies to: 398-414

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doc/explanation/compliance_track.rst` around lines 62 - 77, Raw wildcard
patterns containing asterisks (such as GEC-*, SUM-*, AUM-*, SSM-*, SCM-*) in the
RST file are being interpreted by docutils as inline emphasis markup rather than
literal text, causing parsing warnings. Wrap all such wildcard patterns in
double backticks (literal markup in RST) throughout the document at lines 62-77
and lines 398-414 to ensure they are rendered as literal strings without
triggering emphasis parsing.

Source: Pipeline failures

♻️ Duplicate comments (2)
security/compliance.py (1)

66-74: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not treat every ImportError as “optional Track A unavailable.”

Line 69 currently swallows all ImportErrors and degrades to empty Track A controls. That also hides real breakages inside security.tm_supply_chain/security.tm_usage imports and can silently generate incomplete artifacts.

Suggested handling split
-    except ImportError:
+    except ModuleNotFoundError as exc:
+        if exc.name not in {"pytm", "security.tm_supply_chain", "security.tm_usage"}:
+            raise
         print(
             "Note: pytm not available — Track A controls omitted from control register.",
             file=sys.stderr,
         )
         return []
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@security/compliance.py` around lines 66 - 74, The current exception handling
in the try-except block around the importlib.import_module calls for
security.tm_supply_chain and security.tm_usage modules is too broad. It catches
all ImportError exceptions equally, which masks real import failures that occur
inside those modules. Instead, distinguish between ModuleNotFoundError (which
indicates pytm is not installed and should gracefully return empty Track A
controls) and other ImportError exceptions (which represent genuine breakages
inside the modules that should be propagated to fail fast). Modify the except
clause to specifically catch ModuleNotFoundError for the optional behavior, and
let other ImportError types propagate as real errors.
security/compliance_data.py (1)

243-250: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Control IDs C-009/C-040 still conflict with the published control-register semantics.

Line 245 maps C-040 to update notification and Lines 280/392/533 map C-009 to plaintext-transport detection, but the generated final register (doc/explanation/compliance_track.rst, Lines 395-398 and 471-474) defines those IDs as different controls. This breaks the core ECR → SO → control traceability contract and makes the OSCAL narrative non-auditable.

Also applies to: 280-286, 392-398, 531-539

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@security/compliance_data.py` around lines 243 - 250, The control ID mappings
in security/compliance_data.py conflict with the authoritative published
definitions in doc/explanation/compliance_track.rst, breaking traceability.
Verify the correct control IDs from the published register at lines 395-398 and
471-474 of doc/explanation/compliance_track.rst, then update all four affected
mapping locations in security/compliance_data.py: the controls list at line 245
(currently showing C-040 for update notification), line 280 (C-009 context),
line 392 (C-009 context), and line 533 (C-009 context) to use the control IDs
that match the published definitions, ensuring consistency across all four sites
so that the SO-to-control mappings align with the generated compliance register.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.rst`:
- Around line 9-10: The underline for the Release 0.14.0 section heading is too
short and does not match the width of the title. Extend the underline made of
equals signs to be the same length as the title "Release 0.14.0 (released
2026-06-14)" by adding more equals signs to Line 10 until the underline width
matches the title width exactly.

In `@security/compliance_data.py`:
- Around line 317-327: The description incorrectly claims that C-005 (an
integrity control using hashing) provides "content-level confidentiality
assurance" on Line 325, but integrity hashing does not provide confidentiality
or secrecy. Correct the description in the controls section to accurately
reflect that C-005 is an integrity control that verifies content has not been
tampered with, not a confidentiality control that prevents exposure of plaintext
data. Remove the claim about confidentiality assurance from the integrity hash,
as hashing cannot provide protection against content being readable over
plaintext transport. Either reword the justification to use only accurate
control properties, or acknowledge that the plaintext transport acceptance is a
residual gap without confidentiality protection.

---

Outside diff comments:
In `@doc/explanation/compliance_track.rst`:
- Line 1: The generated artifacts have pre-commit hook violations that are
blocking CI. In doc/explanation/compliance_track.rst (line 1-1), regenerate the
file and commit the fixes for trailing-whitespace and end-of-file-fixer
violations. In security/dfetch.component-definition.json (line 1-1), commit the
EOF normalization fix from the end-of-file-fixer hook. Run pre-commit hooks
locally to auto-fix these issues, then stage and commit the cleaned artifacts to
make the branch mergeable.
- Around line 62-77: Raw wildcard patterns containing asterisks (such as GEC-*,
SUM-*, AUM-*, SSM-*, SCM-*) in the RST file are being interpreted by docutils as
inline emphasis markup rather than literal text, causing parsing warnings. Wrap
all such wildcard patterns in double backticks (literal markup in RST)
throughout the document at lines 62-77 and lines 398-414 to ensure they are
rendered as literal strings without triggering emphasis parsing.

---

Duplicate comments:
In `@security/compliance_data.py`:
- Around line 243-250: The control ID mappings in security/compliance_data.py
conflict with the authoritative published definitions in
doc/explanation/compliance_track.rst, breaking traceability. Verify the correct
control IDs from the published register at lines 395-398 and 471-474 of
doc/explanation/compliance_track.rst, then update all four affected mapping
locations in security/compliance_data.py: the controls list at line 245
(currently showing C-040 for update notification), line 280 (C-009 context),
line 392 (C-009 context), and line 533 (C-009 context) to use the control IDs
that match the published definitions, ensuring consistency across all four sites
so that the SO-to-control mappings align with the generated compliance register.

In `@security/compliance.py`:
- Around line 66-74: The current exception handling in the try-except block
around the importlib.import_module calls for security.tm_supply_chain and
security.tm_usage modules is too broad. It catches all ImportError exceptions
equally, which masks real import failures that occur inside those modules.
Instead, distinguish between ModuleNotFoundError (which indicates pytm is not
installed and should gracefully return empty Track A controls) and other
ImportError exceptions (which represent genuine breakages inside the modules
that should be propagated to fail fast). Modify the except clause to
specifically catch ModuleNotFoundError for the optional behavior, and let other
ImportError types propagate as real errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8f7b8958-7e13-4397-99ea-bb6af05f16c3

📥 Commits

Reviewing files that changed from the base of the PR and between 80a9892 and b7329d2.

📒 Files selected for processing (6)
  • .github/workflows/python-publish.yml
  • CHANGELOG.rst
  • doc/explanation/compliance_track.rst
  • security/compliance.py
  • security/compliance_data.py
  • security/dfetch.component-definition.json

Comment thread CHANGELOG.rst Outdated
Comment thread security/compliance_data.py Outdated

@spoorcc spoorcc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Review — CRA Compliance Track B

What this does: Adds OSCAL 1.1.2 machine-readable compliance artifacts mapping CRA Annex I requirements through prEN 40000-1-4 Security Objectives to dfetch controls, with CI integration to generate and publish the Component Definition at release time. The voluntary alignment under Art. 13(5) and the Recital 18 classification are both correctly reasoned. The three-tier traceability model (ECR → SO → control) is methodologically sound.


CI / pipeline — clean

Both new action pins (attest-build-provenance@a2bbfa25…, download-artifact@3e5f45b2…) follow the commit-SHA pinning discipline already required by C-009. Version extraction via importlib.metadata is correct. No shell injection vectors in the new workflow steps. Attestation on the OSCAL artifact is a nice touch.


Findings

1. C-045 is missing — internal inconsistency (blocking)

The PR description, security.rst, and the PR title all describe C-045 ("destination-path sensitivity warning", ECR-i → SO.PreventAttackPropagation → LIM-2) as one of four Track B controls. It appears in doc/explanation/security.rst:

- **C-045** (destination-path sensitivity warning) — ECR-i / SO.PreventAttackPropagation → LIM-2

But C-045 is absent from TRACK_B_CONTROLS in compliance_data.py, absent from SO_IMPLEMENTATIONS, absent from the CHANGELOG entry, and absent from the generated compliance_track.rst. The committed OSCAL Component Definition therefore omits it too.

As-is, the artifacts produced by this PR are internally inconsistent with the PR description and the docs. Either implement C-045 or remove all references to it. If the intent is "planned, not yet defined", it needs the same treatment as C-043 and C-046 (defined in TRACK_B_CONTROLS with status="planned").


2. UUID namespace label is wrong

In security/compliance.py:

_UUID_NS = uuid.UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")  # uuid.NAMESPACE_URL

6ba7b810-… is uuid.NAMESPACE_DNS. uuid.NAMESPACE_URL is 6ba7b811-… (note the trailing 1). The comment is incorrect. Changing this to _UUID_NS = uuid.NAMESPACE_DNS removes the ambiguity entirely and avoids confusion for anyone auditing the UUID derivation.


3. Hard-coded default version is immediately stale

build_oscal_component_definition(version: str = "0.14.0") and the argparse --version default both hard-code 0.14.0. This PR targets 0.15.0, so the default is wrong the moment this merges. The CI publish step correctly passes --version "$VERSION", so production artifacts are safe — but calling the function directly (e.g. in tests, from the REPL, or during local development) silently produces Component Definitions tagged with the wrong version.

Consider replacing the default with a runtime lookup:

try:
    import importlib.metadata
    _DFETCH_VERSION = importlib.metadata.version("dfetch")
except importlib.metadata.PackageNotFoundError:
    _DFETCH_VERSION = "0.0.0"

4. Committed generated artifact will drift from CI output

security/dfetch.component-definition.json is both committed to the repo and regenerated in CI at release time. _build_metadata() embeds date.today(), so every run produces a different file. There is no CI check to detect divergence between the committed version and what the tool would generate today.

Options:

  • Add the file to .gitignore and rely solely on the release upload — removes the stale-artifact problem entirely.
  • Or add a --check flag that compares (excluding last-modified) and fail CI if the content has drifted.

Leaving it as-is means the committed file will be perpetually out of date after the first release that regenerates it.


5. No tests for new modules

security/compliance.py and security/compliance_data.py have no test coverage. A basic round-trip test — generate the Component Definition, parse the JSON, assert known control IDs and SO IDs are present — would catch regressions and validate OSCAL schema conformance. These artifacts are what downstream integrators rely on for their own conformity assessments; silent breakage here is higher-impact than a typical internal code path.


Summary

# Finding Severity
1 C-045 referenced in docs/PR but not implemented Blocking
2 UUID namespace comment wrong (NAMESPACE_DNSNAMESPACE_URL) Low
3 Default version 0.14.0 is stale as of this PR Low
4 Committed generated artifact has non-deterministic timestamp Low
5 No tests for compliance modules Low

The OSCAL mapping and compliance rationale are solid. Resolve finding 1 (and ideally 3) before merge.


Generated by Claude Code

… accuracy

- Narrow `except ImportError` to `except ModuleNotFoundError` in
  `_load_track_a_controls` so genuine import errors inside tm modules
  propagate rather than being silently swallowed
- Add `_rst_escape_star` helper that escapes standalone `*` characters
  (regex `(?<!\*)\*(?!\*)` → `\*`) without touching `**bold**` markup,
  eliminating docutils inline-emphasis warnings from generated RST
- Fix C-005 description in `so-data-transmitted-confidentiality`: hash
  verification does not provide confidentiality; corrected to state it
  verifies tamper-absence without encrypting content
- Fix CHANGELOG.rst underline length for Release 0.14.0 title
- Regenerate `compliance_track.rst` and `dfetch.component-definition.json`

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
Previously _load_track_a_controls silently returned [] on ModuleNotFoundError,
producing incomplete compliance artifacts with no user-visible error.

Now the function raises RuntimeError unless --track-b-only is explicitly
passed, making degraded mode opt-in rather than silent.  The CI publish
workflow passes --track-b-only since pytm is not installed in that environment.
Update security/README.md and the inline OSCAL Artifacts code block to include
--track-b-only in the regeneration command.

Fixes review thread PRRT_kwDOEh9FL86JrNyh.

https://claude.ai/code/session_01NriXcboJTd9MQG2Mz2kmzQ
@spoorcc spoorcc merged commit b0358cc into main Jun 15, 2026
36 checks passed
@spoorcc spoorcc deleted the claude/security-compliance-track-az9072 branch June 15, 2026 21:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants