|
19 | 19 | Datastore, |
20 | 20 | ExternalEntity, |
21 | 21 | Process, |
22 | | - Server, |
23 | 22 | ) |
24 | 23 |
|
25 | 24 | # ── Threat model metadata ──────────────────────────────────────────────────── |
|
134 | 133 | "Invokes Git and SVN as subprocesses (shell=False, list args). " |
135 | 134 | "Extracts archives with decompression-bomb limits and path-traversal checks." |
136 | 135 | ) |
137 | | -dfetch_cli.controls.validatesInput = True # StrictYAML + SAFE_STR regex |
138 | | -dfetch_cli.controls.sanitizesInput = True # check_no_path_traversal realpath-based |
139 | | -dfetch_cli.controls.usesParameterizedInput = True # shell=False, list-based subprocesses |
140 | | -dfetch_cli.controls.checksInputBounds = True # 500MB / 10k-member archive limits |
141 | | -dfetch_cli.controls.isHardened = True # BatchMode=yes, --non-interactive, type checks |
142 | | -dfetch_cli.controls.providesIntegrity = True # hmac.compare_digest SHA-256/384/512 |
| 136 | +dfetch_cli.controls.validatesInput = True # StrictYAML + SAFE_STR regex |
| 137 | +dfetch_cli.controls.sanitizesInput = True # check_no_path_traversal realpath-based |
| 138 | +dfetch_cli.controls.usesParameterizedInput = ( |
| 139 | + True # shell=False, list-based subprocesses |
| 140 | +) |
| 141 | +dfetch_cli.controls.checksInputBounds = True # 500MB / 10k-member archive limits |
| 142 | +dfetch_cli.controls.isHardened = True # BatchMode=yes, --non-interactive, type checks |
| 143 | +dfetch_cli.controls.providesIntegrity = True # hmac.compare_digest SHA-256/384/512 |
143 | 144 |
|
144 | 145 | gh_actions_workflow = Process("GitHub Actions Workflow") |
145 | 146 | gh_actions_workflow.inBoundary = boundary_github |
|
149 | 150 | "All actions pinned by commit SHA. " |
150 | 151 | "harden-runner used in every workflow (egress: audit only)." |
151 | 152 | ) |
152 | | -gh_actions_workflow.controls.isHardened = True # SHA-pinned actions, persist-credentials:false |
153 | | -gh_actions_workflow.controls.providesIntegrity = True # CodeQL + Scorecard + dependency-review |
| 153 | +gh_actions_workflow.controls.isHardened = ( |
| 154 | + True # SHA-pinned actions, persist-credentials:false |
| 155 | +) |
| 156 | +gh_actions_workflow.controls.providesIntegrity = ( |
| 157 | + True # CodeQL + Scorecard + dependency-review |
| 158 | +) |
154 | 159 | gh_actions_workflow.controls.hasAccessControl = True # minimal permissions per workflow |
155 | 160 |
|
156 | 161 | python_build = Process("Python Build (wheel / sdist)") |
|
182 | 187 | manifest_store.isSQL = False |
183 | 188 | manifest_store.classification = Classification.SENSITIVE |
184 | 189 | manifest_store.controls.isEncryptedAtRest = False |
185 | | -manifest_store.controls.validatesInput = True # StrictYAML validation on read |
| 190 | +manifest_store.controls.validatesInput = True # StrictYAML validation on read |
186 | 191 |
|
187 | 192 | fetched_source = Datastore("PA-02: Fetched Source Code") |
188 | 193 | fetched_source.inBoundary = boundary_dev_env |
|
209 | 214 | "authenticity relies entirely on transport security (TLS/SSH)." |
210 | 215 | ) |
211 | 216 | integrity_hash_record.storesSensitiveData = False |
212 | | -integrity_hash_record.hasWriteAccess = False |
| 217 | +integrity_hash_record.hasWriteAccess = ( |
| 218 | + True # developers and processes write this field in dfetch.yaml |
| 219 | +) |
213 | 220 | integrity_hash_record.classification = Classification.SENSITIVE |
214 | 221 | integrity_hash_record.controls.providesIntegrity = True |
215 | 222 |
|
|
222 | 229 | "Compromise of the PyPI account or registry affects every consumer." |
223 | 230 | ) |
224 | 231 | pypi_package.storesSensitiveData = False |
225 | | -pypi_package.hasWriteAccess = False |
| 232 | +pypi_package.hasWriteAccess = ( |
| 233 | + True # publish pipeline writes new releases to this package |
| 234 | +) |
226 | 235 | pypi_package.classification = Classification.SENSITIVE |
227 | 236 | pypi_package.controls.usesCodeSigning = False # no Sigstore/cosign signing |
228 | 237 |
|
|
244 | 253 | # SA-01 … SA-10: assets that enable primary assets; their loss degrades |
245 | 254 | # security or availability of primary assets. |
246 | 255 |
|
| 256 | +# SA-01: dfetch Process — modelled as dfetch_cli (Process above) |
| 257 | +# The running Python interpreter dispatching all commands. Subprocess |
| 258 | +# injection or dependency confusion could compromise build-time execution. |
| 259 | +# Classification: Restricted. |
| 260 | + |
247 | 261 | vcs_credentials = Data( |
248 | 262 | "SA-02: VCS Credentials", |
249 | 263 | description=( |
|
382 | 396 | # EA-03: GitHub Repository — modelled as gh_repository (ExternalEntity above) |
383 | 397 | # EA-04: GitHub Actions Infrastructure — modelled as gh_actions_runner (ExternalEntity above) |
384 | 398 | # EA-05: PyPI / TestPyPI — modelled as pypi (ExternalEntity above) |
| 399 | +# EA-06: Developer Workstation / CI Runner — modelled as developer / gh_actions_runner (Actors/ExternalEntity above) |
| 400 | +# EA-07: Consumer Build System — modelled as consumer_build (ExternalEntity above) |
| 401 | +# EA-08: Network Transport — modelled as boundary_network (Boundary above); symbol: network_transport |
385 | 402 |
|
386 | 403 | # ── DATA FLOWS ─────────────────────────────────────────────────────────────── |
387 | 404 | # |
|
402 | 419 | "no protocol enforcement in manifest schema." |
403 | 420 | ) |
404 | 421 | df03.protocol = "HTTPS / SSH / svn" |
405 | | -df03.controls.isEncrypted = True # for HTTPS/SSH paths; NOT for svn:// or http:// |
406 | | -df03.controls.isHardened = True # BatchMode=yes, --non-interactive |
| 422 | +df03.controls.isEncrypted = True # for HTTPS/SSH paths; NOT for svn:// or http:// |
| 423 | +df03.controls.isHardened = True # BatchMode=yes, --non-interactive |
407 | 424 |
|
408 | 425 | df04 = Dataflow(remote_git_svn, dfetch_cli, "DF-04: VCS content (inbound, untrusted)") |
409 | 426 | df04.description = ( |
|
431 | 448 | ) |
432 | 449 | df06.protocol = "HTTP or HTTPS" |
433 | 450 | df06.controls.providesIntegrity = False # hash is optional; may be absent |
434 | | -df06.controls.isEncrypted = False # http:// allowed |
| 451 | +df06.controls.isEncrypted = False # http:// allowed |
435 | 452 |
|
436 | 453 | df07 = Dataflow(dfetch_cli, fetched_source, "DF-07: Write vendored files") |
437 | 454 | df07.description = ( |
|
453 | 470 | "RISK: patch files are not integrity-verified (no hash in manifest schema). " |
454 | 471 | "patch-ng path safety depends on its own internal implementation." |
455 | 472 | ) |
456 | | -df10.controls.validatesInput = False # no integrity hash on patch files |
| 473 | +df10.controls.validatesInput = False # no integrity hash on patch files |
457 | 474 |
|
458 | 475 | df11 = Dataflow(contributor, gh_repository, "DF-11: Submit pull request") |
459 | 476 | df11.description = ( |
|
0 commit comments