Skip to content

Commit e34d3ff

Browse files
claudespoorcc
authored andcommitted
Fix four review findings: EA ordering, SA-01 label, line-number ref, security package
pyproject.toml: - Remove "security" and "security.*" from setuptools include list; the threat model is a source-checkout-only compliance tool and must not be bundled as a top-level namespace package in the distributed wheel. security/threat_model.py: - Declare gh_repository (EA-03) before gh_actions_runner (EA-04) to match numeric order in the RST asset register. - Rename gh_actions_runner label from "EA-04: GitHub Actions Runner" to "EA-04: GitHub Actions Infrastructure" to match doc/explanation/security.rst. - Rename dfetch_cli label from "SA-01: dfetch CLI" to "SA-01: dfetch Process" to match the Supporting Assets table in security.rst. doc/explanation/security.rst: - Remove hard-coded line number from path-traversal control entry; reference the function symbol check_no_path_traversal() and file only so the doc stays correct after refactors. https://claude.ai/code/session_01Rc28JtpAPWhJtA3YvS5kcr
1 parent 80b9f9b commit e34d3ff

3 files changed

Lines changed: 38 additions & 21 deletions

File tree

doc/explanation/security.rst

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ using the `pytm`_ framework. Regenerate analysis output with:
2525
python -m security.threat_model --dfd # Graphviz DFD (stdout)
2626
python -m security.threat_model --report # STRIDE findings report
2727
28+
.. note::
29+
30+
The ``security/`` package is intentionally excluded from built wheels and is
31+
**not** installed by ``pip install dfetch[security]``. These commands must
32+
be run from a source checkout with the repository root on ``PYTHONPATH`` (or
33+
simply from the repository root, where Python resolves the ``security``
34+
package automatically).
35+
2836
.. note::
2937

3038
The ``--seq`` and ``--dfd`` commands require **PlantUML** and **Graphviz**
@@ -399,10 +407,11 @@ with the security controls that are currently implemented.
399407
in ``ci.yml`` propagates secrets to test and docs workflows triggered
400408
on PR — a malicious workflow step could exfiltrate secrets.
401409
* - DF-12
402-
- GitHub Actions Runner → GitHub Repository
410+
- GitHub Repository → GitHub Actions Runner
403411
- HTTPS
404-
- CI checkout and build. ``persist-credentials: false`` on all checkout
405-
steps; all third-party actions pinned by commit SHA.
412+
- CI checkout and build. GitHub Actions checks out source from the
413+
repository into the runner. ``persist-credentials: false`` on all
414+
checkout steps; all third-party actions pinned by commit SHA.
406415
* - DF-13
407416
- GitHub Actions Runner → PyPI
408417
- HTTPS
@@ -439,7 +448,7 @@ The following controls are already in place and are reflected in the
439448
``pathlib.Path.resolve``), then rejects any path whose resolved prefix
440449
does not start with the resolved root. Applied to every file copy and
441450
post-extraction symlink.
442-
``dfetch/util/util.py`` — ``check_no_path_traversal`` at line 277
451+
``check_no_path_traversal()`` in ``dfetch/util/util.py``
443452
* - Decompression-bomb protection
444453
- SA-05, PA-02
445454
- Archives are rejected if uncompressed size exceeds 500 MB or the member

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ security = ["pytm==1.3.1"]
113113
dfetch = "dfetch.__main__:main"
114114

115115
[tool.setuptools.packages.find]
116-
include = ["dfetch", "dfetch.*", "security", "security.*"]
116+
include = ["dfetch", "dfetch.*"]
117117

118118
[tool.setuptools.package-data]
119119
dfetch = ["resources/*.yaml"]

security/threat_model.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,6 @@
9191
"hashes — the integrity.hash field is optional."
9292
)
9393

94-
gh_actions_runner = ExternalEntity("EA-04: GitHub Actions Runner")
95-
gh_actions_runner.inBoundary = boundary_github
96-
gh_actions_runner.description = (
97-
"Microsoft-operated ephemeral runner executing CI/CD workflows. "
98-
"Egress policy is 'audit' (not 'block') — exfiltration of secrets is possible "
99-
"if any workflow step is compromised."
100-
)
101-
10294
gh_repository = ExternalEntity("EA-03: GitHub Repository")
10395
gh_repository.inBoundary = boundary_github
10496
gh_repository.description = (
@@ -107,6 +99,14 @@
10799
"can modify repository state and trigger releases."
108100
)
109101

102+
gh_actions_runner = ExternalEntity("EA-04: GitHub Actions Infrastructure")
103+
gh_actions_runner.inBoundary = boundary_github
104+
gh_actions_runner.description = (
105+
"Microsoft-operated ephemeral runner executing CI/CD workflows. "
106+
"Egress policy is 'audit' (not 'block') — exfiltration of secrets is possible "
107+
"if any workflow step is compromised."
108+
)
109+
110110
pypi = ExternalEntity("EA-05: PyPI / TestPyPI")
111111
pypi.inBoundary = boundary_pypi
112112
pypi.description = (
@@ -124,7 +124,7 @@
124124

125125
# ── Processes ────────────────────────────────────────────────────────────────
126126

127-
dfetch_cli = Process("SA-01: dfetch CLI")
127+
dfetch_cli = Process("SA-01: dfetch Process")
128128
dfetch_cli.inBoundary = boundary_dev_env
129129
dfetch_cli.description = (
130130
"Python CLI entry point dispatching to: update, check, diff, add, remove, "
@@ -320,7 +320,7 @@
320320
"RISK: 'secrets: inherit' in ci.yml propagates ALL secrets to test and docs workflows."
321321
)
322322
gh_workflows.storesSensitiveData = False
323-
gh_workflows.hasWriteAccess = True # PRs can modify .github/workflows/ definitions
323+
gh_workflows.hasWriteAccess = True # PRs can modify .github/workflows/ definitions
324324
gh_workflows.classification = Classification.RESTRICTED
325325
gh_workflows.controls.isHardened = True
326326

@@ -414,9 +414,11 @@
414414
)
415415
df03_tls.protocol = "HTTPS / SSH"
416416
df03_tls.controls.isEncrypted = True
417-
df03_tls.controls.isHardened = True # BatchMode=yes, --non-interactive
417+
df03_tls.controls.isHardened = True # BatchMode=yes, --non-interactive
418418

419-
df03_plain = Dataflow(dfetch_cli, remote_git_svn, "DF-03b: Fetch VCS content — svn:// / http://")
419+
df03_plain = Dataflow(
420+
dfetch_cli, remote_git_svn, "DF-03b: Fetch VCS content — svn:// / http://"
421+
)
420422
df03_plain.description = (
421423
"git fetch over http:// or SVN over svn:// (plain, non-TLS). "
422424
"dfetch accepts these protocols without enforcement — no TLS check in manifest "
@@ -428,7 +430,9 @@
428430
df03_plain.controls.isEncrypted = False
429431
df03_plain.controls.isHardened = False
430432

431-
df04_tls = Dataflow(remote_git_svn, dfetch_cli, "DF-04a: VCS content inbound — HTTPS/SSH")
433+
df04_tls = Dataflow(
434+
remote_git_svn, dfetch_cli, "DF-04a: VCS content inbound — HTTPS/SSH"
435+
)
432436
df04_tls.description = (
433437
"Repository tree and file content over HTTPS or SSH. Transport is encrypted. "
434438
"No end-to-end content hash for Git or SVN — authenticity relies on transport "
@@ -438,7 +442,9 @@
438442
df04_tls.controls.isEncrypted = True
439443
df04_tls.controls.providesIntegrity = False # no end-to-end hash for git/svn content
440444

441-
df04_plain = Dataflow(remote_git_svn, dfetch_cli, "DF-04b: VCS content inbound — svn:// / http://")
445+
df04_plain = Dataflow(
446+
remote_git_svn, dfetch_cli, "DF-04b: VCS content inbound — svn:// / http://"
447+
)
442448
df04_plain.description = (
443449
"Repository content over unencrypted http:// or svn://. "
444450
"A network-positioned attacker can substitute arbitrary content without detection "
@@ -472,7 +478,9 @@
472478
"check_no_path_traversal(). Symlinks validated post-extraction."
473479
)
474480
df07.controls.sanitizesInput = True
475-
df07.controls.providesIntegrity = True
481+
df07.controls.providesIntegrity = (
482+
False # integrity is conditional on hash presence (checked in DF-05/DF-06)
483+
)
476484

477485
df08 = Dataflow(dfetch_cli, metadata_store, "DF-08: Write dependency metadata")
478486
df08.description = "Writes .dfetch_data.yaml tracking remote_url, revision, hash."
@@ -498,7 +506,7 @@
498506
df11.protocol = "HTTPS"
499507
df11.controls.hasAccessControl = True
500508

501-
df12 = Dataflow(gh_actions_runner, gh_repository, "DF-12: CI checkout and build")
509+
df12 = Dataflow(gh_repository, gh_actions_runner, "DF-12: CI checkout and build")
502510
df12.description = (
503511
"GitHub Actions checks out source, installs deps, runs tests, lints, builds. "
504512
"persist-credentials:false on all checkout steps. "

0 commit comments

Comments
 (0)