cbp-action 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. cbp_action-0.1.7/LICENSE +21 -0
  2. cbp_action-0.1.7/PKG-INFO +400 -0
  3. cbp_action-0.1.7/README.md +384 -0
  4. cbp_action-0.1.7/pyproject.toml +36 -0
  5. cbp_action-0.1.7/setup.cfg +4 -0
  6. cbp_action-0.1.7/src/cbp/__init__.py +0 -0
  7. cbp_action-0.1.7/src/cbp/artifact_integrity.py +142 -0
  8. cbp_action-0.1.7/src/cbp/baseline.py +49 -0
  9. cbp_action-0.1.7/src/cbp/binary_gate.py +65 -0
  10. cbp_action-0.1.7/src/cbp/claims_gate.py +85 -0
  11. cbp_action-0.1.7/src/cbp/cli.py +148 -0
  12. cbp_action-0.1.7/src/cbp/comment_gate.py +69 -0
  13. cbp_action-0.1.7/src/cbp/config.py +139 -0
  14. cbp_action-0.1.7/src/cbp/coverage_gate.py +227 -0
  15. cbp_action-0.1.7/src/cbp/custom_rules.py +145 -0
  16. cbp_action-0.1.7/src/cbp/dependency_gate.py +76 -0
  17. cbp_action-0.1.7/src/cbp/docs_gate.py +28 -0
  18. cbp_action-0.1.7/src/cbp/encoding_gate.py +66 -0
  19. cbp_action-0.1.7/src/cbp/powershell_syntax.py +75 -0
  20. cbp_action-0.1.7/src/cbp/readers.py +64 -0
  21. cbp_action-0.1.7/src/cbp/regex_guard.py +71 -0
  22. cbp_action-0.1.7/src/cbp/sarif.py +79 -0
  23. cbp_action-0.1.7/src/cbp/source_hash.py +39 -0
  24. cbp_action-0.1.7/src/cbp/suppression.py +36 -0
  25. cbp_action-0.1.7/src/cbp/upgrade_gate.py +111 -0
  26. cbp_action-0.1.7/src/cbp/verify_release.py +66 -0
  27. cbp_action-0.1.7/src/cbp_action.egg-info/PKG-INFO +400 -0
  28. cbp_action-0.1.7/src/cbp_action.egg-info/SOURCES.txt +63 -0
  29. cbp_action-0.1.7/src/cbp_action.egg-info/dependency_links.txt +1 -0
  30. cbp_action-0.1.7/src/cbp_action.egg-info/entry_points.txt +2 -0
  31. cbp_action-0.1.7/src/cbp_action.egg-info/requires.txt +4 -0
  32. cbp_action-0.1.7/src/cbp_action.egg-info/top_level.txt +1 -0
  33. cbp_action-0.1.7/tests/test_artifact_integrity.py +29 -0
  34. cbp_action-0.1.7/tests/test_audit_rule_source_edges.py +208 -0
  35. cbp_action-0.1.7/tests/test_audit_rule_sources.py +119 -0
  36. cbp_action-0.1.7/tests/test_baseline.py +42 -0
  37. cbp_action-0.1.7/tests/test_claims_errors.py +17 -0
  38. cbp_action-0.1.7/tests/test_claims_text.py +38 -0
  39. cbp_action-0.1.7/tests/test_cli.py +74 -0
  40. cbp_action-0.1.7/tests/test_cli_all_disabled.py +15 -0
  41. cbp_action-0.1.7/tests/test_comment_suppression.py +35 -0
  42. cbp_action-0.1.7/tests/test_components.py +144 -0
  43. cbp_action-0.1.7/tests/test_config_migration.py +56 -0
  44. cbp_action-0.1.7/tests/test_coverage_adapters.py +38 -0
  45. cbp_action-0.1.7/tests/test_coverage_groups.py +44 -0
  46. cbp_action-0.1.7/tests/test_coverage_ratchet.py +43 -0
  47. cbp_action-0.1.7/tests/test_coverage_signature.py +41 -0
  48. cbp_action-0.1.7/tests/test_coverage_source_hash.py +37 -0
  49. cbp_action-0.1.7/tests/test_custom_rules.py +53 -0
  50. cbp_action-0.1.7/tests/test_custom_rules_more.py +82 -0
  51. cbp_action-0.1.7/tests/test_dependency_strict.py +46 -0
  52. cbp_action-0.1.7/tests/test_dogfood_manifest.py +43 -0
  53. cbp_action-0.1.7/tests/test_encoding_gate.py +35 -0
  54. cbp_action-0.1.7/tests/test_encoding_gate_extra.py +40 -0
  55. cbp_action-0.1.7/tests/test_gates.py +25 -0
  56. cbp_action-0.1.7/tests/test_powershell_syntax.py +22 -0
  57. cbp_action-0.1.7/tests/test_readers.py +58 -0
  58. cbp_action-0.1.7/tests/test_regex_guard.py +19 -0
  59. cbp_action-0.1.7/tests/test_release_body.py +72 -0
  60. cbp_action-0.1.7/tests/test_rule_seeds.py +128 -0
  61. cbp_action-0.1.7/tests/test_sarif.py +32 -0
  62. cbp_action-0.1.7/tests/test_suppression.py +15 -0
  63. cbp_action-0.1.7/tests/test_upgrade_gate.py +71 -0
  64. cbp_action-0.1.7/tests/test_verify_manifest_artifact.py +74 -0
  65. cbp_action-0.1.7/tests/test_verify_release.py +44 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cyber Butler contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,400 @@
1
+ Metadata-Version: 2.1
2
+ Name: cbp-action
3
+ Version: 0.1.7
4
+ Summary: Reusable repository quality gates for GitHub Actions and local CI
5
+ Author: CBP contributors
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Provides-Extra: test
14
+ Requires-Dist: pytest>=8.0; extra == "test"
15
+ Requires-Dist: coverage>=7.6; extra == "test"
16
+
17
+ # CBP — Release-evidence gate
18
+
19
+ > Prove the green build was not faked.
20
+
21
+ A reusable, self-hosted quality gate for repositories that do not want to
22
+ trust a green check without evidence.
23
+
24
+ CBP is intentionally small: Python standard library at runtime, JSON/TOML
25
+ configuration, and one CLI used by both GitHub Actions and local CI.
26
+
27
+ CBP is designed to evolve. As the CB ecosystem grows, CBP's rule engine will expand to cover different languages and frameworks.
28
+
29
+ Smooth upgrade is a promise. If you ship a breaking change without proper migration, CBP will break your pipeline.
30
+
31
+ CBP is designed for long-term stability. Upgrading CBP will not break your existing CI. New gates are opt-in by default, and legacy fields are auto-mapped.
32
+
33
+ The core 80% is language-neutral: encoding, documentation locks, release claims,
34
+ dependency policy, and provenance. The remaining 20% is supplied by configured
35
+ custom rules and evidence readers, so a React, Node.js, or future language
36
+ project can extend the gate without changing CBP source.
37
+
38
+ ## What it catches
39
+
40
+ | Gate | What it rejects |
41
+ |---|---|
42
+ | coverage | measured coverage below the configured floor, or missing allowlist entries |
43
+ | dependency | unpinned packages, missing SHA256 hashes, installers without `--require-hashes` |
44
+ | comments | public functions/classes without docstrings, missing `Args` names, generic boilerplate, `# Send ...`-style comments |
45
+ | docs | files whose SHA256 no longer matches the documentation manifest |
46
+ | binary | large binaries without `.build.json`/`.sbom.json`, or provenance hash/size mismatches |
47
+ | claims | release notes whose `QUALITY_COUNTS` do not match the generated manifest |
48
+ | encoding | tracked text files that are not strict UTF-8 or carry a BOM |
49
+ | custom | configured regex/literal rules in `custom_rules` (warn by default) |
50
+ | upgrade | configured upgrade script, old-config fixtures, and schema compatibility |
51
+
52
+ It is designed to make fake tests, fake coverage, dependency substitution,
53
+ copy-paste comments, and edited evidence fail closed.
54
+
55
+ `Coverage Gate` ensures code paths are executed, but it cannot guarantee that
56
+ assertions are semantically meaningful. CBP cannot validate the underlying
57
+ execution of `coverage.py`; it validates the artifact and its freshness. If you
58
+ need stronger provenance, enable `require-coverage-signature` with a
59
+ `coverage.json.sha256` sidecar generated by the same CI run.
60
+
61
+ ## GitHub Action
62
+
63
+ ```yaml
64
+ - uses: JunxiangPan/cbp-action@v0.1.7
65
+ with:
66
+ root: .
67
+ config: .cbp/config.json
68
+ coverage-json: coverage.json
69
+ coverage-allowlist: .cbp/coverage_allowlist.json
70
+ coverage-threshold: "80"
71
+ policy-coverage-threshold: "85"
72
+ dependency-lock: requirements.lock
73
+ install-command: installer/install.ps1
74
+ docs-manifest: .cbp/docs-manifest.json
75
+ binary-artifacts: artifacts
76
+ claims-manifest: quality-manifest.json
77
+ claims-notes: RELEASE_NOTES.md
78
+ enable-coverage: "true"
79
+ enable-dependency: "true"
80
+ enable-comments: "true"
81
+ enable-docs: "true"
82
+ enable-binary: "true"
83
+ enable-claims: "false"
84
+ mode: enforce
85
+ ```
86
+
87
+ The output is written to `$GITHUB_OUTPUT` as:
88
+
89
+ ```text
90
+ result=CBP_RESULT=PASS
91
+ ```
92
+
93
+ or `CBP_RESULT=FAIL`.
94
+
95
+ ### Inputs
96
+
97
+ | Input | Meaning |
98
+ |---|---|
99
+ | `root` | Repository root |
100
+ | `config` | Optional CBP JSON/TOML config |
101
+ | `coverage-json` | coverage.py JSON output |
102
+ | `coverage-signature` | optional `coverage.json.sha256` sidecar |
103
+ | `require-coverage-signature` | require the sidecar to match |
104
+ | `coverage-allowlist` | Allowlist JSON |
105
+ | `coverage-threshold` | Legacy single-group threshold |
106
+ | `policy-coverage-threshold` | Legacy policy threshold |
107
+ | `dependency-lock` | Hash-locked requirements file |
108
+ | `install-command` | Installer that enforces `--require-hashes` |
109
+ | `installer-core` | Deprecated alias for `install-command` |
110
+ | `docs-manifest` | Document SHA256 manifest |
111
+ | `binary-artifacts` | `.build.json` / `.sbom.json` directory |
112
+ | `package-zip` | Optional release ZIP |
113
+ | `claims-manifest` | Generated `quality-manifest.json` |
114
+ | `claims-notes` | Generated release notes |
115
+ | `release-body` | Checked-in GitHub Release body |
116
+ | `sarif-output` | Optional SARIF 2.1.0 output path |
117
+ | `enable-coverage` | Enable coverage gate |
118
+ | `enable-encoding` | Enable strict UTF-8 no-BOM gate |
119
+ | `enable-dependency` | Enable dependency gate |
120
+ | `enable-comments` | Enable comment gate |
121
+ | `enable-docs` | Enable docs gate |
122
+ | `enable-binary` | Enable binary gate |
123
+ | `enable-claims` | Enable claims gate |
124
+ | `enable-custom` | Enable config-driven custom rules |
125
+ | `enable-upgrade` | Enable upgrade compatibility checks |
126
+ | `mode` | `audit`, `warn`, or `enforce` |
127
+
128
+ ### Required path inputs
129
+
130
+ All path inputs are optional. A path is required only when its gate is enabled;
131
+ the gate fails closed with an explicit missing-path error if it is enabled
132
+ without the corresponding input.
133
+
134
+ ### Quick start
135
+
136
+ The canonical, copyable workflow is [`usage.yml`](usage.yml). It runs
137
+ coverage and then calls the Action with only the gates it enables.
138
+
139
+ ## Local CLI
140
+
141
+ ```bash
142
+ python -m pip install -e ".[test]"
143
+ python -m cbp.cli --root /path/to/repo --config .cbp/config.json
144
+ ```
145
+
146
+ `audit` mode reports failures but exits zero; `enforce` exits non-zero.
147
+
148
+ ```bash
149
+ python -m cbp.cli --root . --mode audit
150
+ python -m cbp.cli --root . --mode enforce
151
+ ```
152
+
153
+ ## Configuration
154
+
155
+ See [`schemas/config.schema.json`](schemas/config.schema.json).
156
+
157
+ ```json
158
+ {
159
+ "coverage_json": "coverage.json",
160
+ "coverage_allowlist": ".cbp/coverage_allowlist.json",
161
+ "target_files": ["src/example.py"],
162
+ "policy_file": "src/example.py",
163
+ "coverage_threshold": 80,
164
+ "policy_threshold": 85,
165
+ "comment_files": ["src/example.py"],
166
+ "enable_claims": false
167
+ }
168
+ ```
169
+
170
+ All paths are relative to `root`. Every gate can be disabled with its
171
+ `enable_*` field or the matching Action input.
172
+
173
+ ### Coverage groups
174
+
175
+ Coverage is configured as named groups. Each group can be `enforce` (a failure
176
+ fails the Action) or `warn` (reported but non-blocking). This supports gradual
177
+ adoption without a temporary lower global threshold.
178
+
179
+ ```json
180
+ {
181
+ "coverage_json": "coverage.json",
182
+ "coverage_allowlist": "coverage_allowlist.json",
183
+ "coverage_groups": [
184
+ {"name": "core", "files": ["src/core.py"], "threshold": 80, "mode": "enforce"},
185
+ {"name": "auditors", "files": ["src/audit_*.py"], "threshold": 0, "mode": "warn"},
186
+ {"name": "webui", "files": ["webui/**/*.py"], "threshold": 0, "mode": "warn"}
187
+ ]
188
+ }
189
+ ```
190
+
191
+ Suggested migration:
192
+
193
+ ```text
194
+ 1. Start every new group with mode "warn" and threshold 0.
195
+ 2. Add tests and raise the group threshold.
196
+ 3. When the group is stable, change mode to "enforce".
197
+ ```
198
+
199
+ `target_files`, `policy_file`, `coverage_threshold`, and
200
+ `policy_threshold` remain supported for single-group configurations.
201
+
202
+ ## Self-test
203
+
204
+ ```bash
205
+ cd cbp-action
206
+ python -m pip install -e ".[test]"
207
+ python -m coverage run --branch --source=src/cbp,tools -m pytest -q tests
208
+ python -m coverage json -o coverage.json
209
+ python -m cbp.cli --root . --mode enforce
210
+ ```
211
+
212
+ The package has no runtime dependencies outside the Python standard library.
213
+ `pytest` and `coverage` are optional test dependencies.
214
+
215
+ CBP is distributed through GitHub Actions and GitHub Releases only. It is not
216
+ published to PyPI; the top-level import package is `cbp` for the action runtime.
217
+
218
+ The manifest is checksum + run-id pinned. Release wheels also carry
219
+ GitHub OIDC build provenance from `actions/attest-build-provenance`. The
220
+ manifest itself is not a signature; the wheel attestation is the cryptographic
221
+ provenance layer.
222
+
223
+ `security_core` coverage is the coverage of the gate modules, config, CLI,
224
+ encoding gate, and rule auditor; it is not a separate binary-security metric.
225
+
226
+ ## Configuration compatibility
227
+
228
+ Every supported config should declare:
229
+
230
+ ```json
231
+ "schema_version": "0.1.7"
232
+ ```
233
+
234
+ Old `v0.1.0` configs that omit it are accepted and migrated in memory with a
235
+ `CBP_CONFIG_WARN` message. Legacy fields are mapped automatically:
236
+
237
+ ```text
238
+ installer_core -> install_command
239
+ broker_files -> target_files
240
+ measured_files -> target_files
241
+ ```
242
+
243
+ A future schema version newer than the running CBP is rejected rather than
244
+ silently misread.
245
+
246
+ Deprecation is a three-step process:
247
+
248
+ ```text
249
+ v0.1.7: documentation + DeprecationWarning, old behavior still works
250
+ v0.2.0: old behavior still works, but emits a mandatory warning
251
+ v1.0.0+: code may be removed only after the warning period
252
+ ```
253
+
254
+ New gates and fields are optional. A config with no `custom_rules`,
255
+ `evidence_readers`, `release_body`, or `coverage_signature` still runs.
256
+
257
+ ## Cross-language custom rules
258
+
259
+ Evidence readers are declared in `cbp.json` and selected by suffix or explicitly
260
+ by a rule. A reader is only a text decoder plus suffix/limit metadata; CBP does
261
+ not import or execute third-party code.
262
+
263
+ ```json
264
+ {
265
+ "evidence_readers": {
266
+ "javascript": {"suffixes": [".js", ".jsx", ".ts", ".tsx"], "encoding": "utf-8"},
267
+ "python": {"suffixes": [".py"], "encoding": "utf-8"}
268
+ },
269
+ "custom_rules": [
270
+ {
271
+ "name": "no-dangerous-html",
272
+ "pattern": "dangerouslySetInnerHTML",
273
+ "files": ["webui/**/*.jsx"],
274
+ "reader": "javascript",
275
+ "message": "Do not inject raw HTML.",
276
+ "mode": "warn"
277
+ },
278
+ {
279
+ "name": "no-node-eval",
280
+ "pattern": "\beval\s*\(",
281
+ "files": ["webui/**/*.js"],
282
+ "reader": "javascript",
283
+ "message": "Do not use eval().",
284
+ "mode": "warn"
285
+ }
286
+ ]
287
+ }
288
+ ```
289
+
290
+ Rules are regex or literal, support `ignore_case`, `multiline`, and `dotall`,
291
+ and default to `warn` so a new language cannot break another project's CI.
292
+
293
+ ## Verifying build provenance
294
+
295
+ The release wheel and the manifest evidence are covered by GitHub OIDC
296
+ attestation. Verify them from a checkout of the release repository:
297
+
298
+ ```bash
299
+ gh attestation verify cbp_action-0.1.7-py3-none-any.whl --repo JunxiangPan/cbp-action
300
+
301
+ gh attestation verify quality-manifest.json --repo JunxiangPan/cbp-action
302
+
303
+ gh attestation verify quality-manifest.json.sha256 --repo JunxiangPan/cbp-action
304
+ ```
305
+
306
+ CBP validates code execution paths, but cannot prove the semantic validity of
307
+ test assertions.
308
+
309
+ ## Baseline and source binding
310
+
311
+ Old repositories can adopt CBP without fixing historical findings immediately:
312
+
313
+ ```bash
314
+ python -m cbp.cli --root . --generate-baseline cbp-baseline.json
315
+ ```
316
+
317
+ The baseline suppresses only the exact recorded findings; a new finding is
318
+ still a failure. Inline suppression is also supported:
319
+
320
+ ```python
321
+ # cbp: ignore=CBP-CMT-001
322
+ ```
323
+
324
+ Coverage evidence now embeds `source_files_hash` inside `coverage.json`.
325
+ `Coverage Gate` recomputes the current measured-source hash and fails with:
326
+
327
+ ```text
328
+ coverage.json is stale; source files have changed
329
+ ```
330
+
331
+ A `touch coverage.json` no longer bypasses the check. Generate and stamp it with:
332
+
333
+ ```bash
334
+ python -m coverage json -o coverage.json
335
+ python tools/stamp_coverage.py --root . --coverage coverage.json
336
+ ```
337
+
338
+ ## Release body and errata
339
+
340
+ `docs/RELEASE_BODY.md` is the only accepted source for the GitHub Release body.
341
+ The release workflow publishes it with `--notes-file` and then runs:
342
+
343
+ ```bash
344
+ python -m cbp.cli --verify-release v0.1.7 --repository owner/repo
345
+ ```
346
+
347
+ The command fetches the live GitHub release body and compares its normalized
348
+ SHA256 with the checked-in file. If the body was edited in the GitHub web UI,
349
+ it exits non-zero with:
350
+
351
+ ```text
352
+ ERRATA release body mismatch ...
353
+ ```
354
+
355
+ CBP cannot prevent an owner from editing a release on GitHub. But if you do,
356
+ the evidence chain breaks. Always update `docs/RELEASE_BODY.md`, re-run CI, and
357
+ publish a new tag (or a patch release). If you must edit an old release, the
358
+ edit is only acceptable after the evidence is regenerated and checked in; a
359
+ silent web edit is an ERRATA, not a valid update.
360
+
361
+ This is the open-source release discipline: edits are allowed, silent edits are
362
+ not.
363
+
364
+ ### Protect tags
365
+
366
+ In GitHub, open **Settings -> Tags -> New rule** and protect released tags:
367
+
368
+ ```text
369
+ Tag pattern: v*
370
+ Allow deletions: off
371
+ Allow force pushes: off
372
+ ```
373
+
374
+ Tag protection prevents accidental re-pointing of a released tag. It does not
375
+ prevent editing a Release body; `verify-release` covers that gap.
376
+
377
+ ## Releasing
378
+
379
+ See [`RELEASING.md`](RELEASING.md) for the commit -> CI -> tag -> release order.
380
+
381
+ ## Status
382
+
383
+ v0.1.7 is a standalone release candidate. It does not import anything from
384
+ the host product's `quality/`, `checks/`, or `tools/` directories.
385
+
386
+ ### Coverage numbers in CI
387
+
388
+ CI coverage may differ from local by ±0.5% due to platform-specific line
389
+ coverage. The gate uses the CI value.
390
+ ## PyPI
391
+
392
+ See `docs/PYPI_TRUSTED_PUBLISHING.md`; publishing uses GitHub OIDC and does not store a PyPI token.
393
+
394
+ ## Prebuilt wheel
395
+
396
+ The action installs the checked-in `dist/cbp_action-0.1.7-py3-none-any.whl`; it does not build from source or contact the package index.
397
+
398
+ ## VM-only evidence
399
+
400
+ This release contains tests that require a real Administrator/VM environment (network, ACL, VHD, uninstall, soak). A green CI run is **not** sufficient release evidence; run the release profile chaos harness in a disposable VM and attach its real results.