cbm-attach
For release engineers who already run CBE/CBP gates and need a defensible sidecar attachment decision.
Problem: a release can be "green" while the optional CBM artifact was never
built, was built from a different hash, or was attached with a stale manifest.
cbm-attach consumes the existing evidence, verifies the canonical hashes and
the build-once wheel, and emits a machine-readable report plus a human-readable
body fragment. It never re-runs CBE/CBP and is not a gate in their needs
graph.
Start:
pip install cbm-attach==0.2.0 # stable; 0.2.1 is the current candidate
cbm-attach --help
If you need the exact build-once artifact, install the released wheel:
pip install https://github.com/JunxiangPan/cbm/releases/download/v0.2.0/cbm_attach-0.2.0-py3-none-any.whl
cbm-attach --help
From a checkout:
python -m pip install -e .
cbm-attach --help
The import package remains cbm_attach; the distribution and CLI are
cbm-attach.
Current status: 0.2.1 stable release candidate; 0.2.0 and 0.1.1 remain available
CBM v0.1.1 is a sidecar attachment tool, not a complete product certification and not an A-F live E2E proof. GitHub Release:
https://github.com/JunxiangPan/cbm/releases/tag/v0.1.1
v0.1.0 remains published and unchanged. PyPI upload is blocked pending a trusted publisher/credentials; use the exact wheel above until then.
- B1 CONTRACT_ACTIVE — contract-v1.7.1 §5.1 active; identity tests retained.
- 0.1.1 changes — Apache-2.0 license, canonical evidence-hash trust root,
cbm-attachdistribution/console script, uploader failure tests, in-toto Statement, generic evidence adapters. - B3 FIELD_LEVEL_COMPLETE — CBP 1.2.2 object manifest, base scope, artifact/evidence hashes.
- B4 UPLOADED_VERIFIED — object artifact repository matched; fail-closed boundaries retained.
- B5 FIXED — CBS body generator emits
CBM: NOT_UPLOADED+EVIDENCE_ABSENT.
PyPI: PUBLISHED — https://pypi.org/project/cbm-attach/0.1.1/
139 offline/static tests pass. The source is Apache-2.0. No A-F live E2E
or full-product certification is claimed. Evidence lives in
audit/v1.2.0-rc/.
Trust root
CBE and CBP evidence_sha256 values are recomputed from canonical JSON before
the gate decides; a format-valid but wrong hash exits 3
EVIDENCE_HASH_MISMATCH. CBM's own report is sealed the same way. Raw-byte
report hashes remain separate from canonical evidence hashes.
in-toto and generic evidence
verify and upload write an in-toto v1 Statement next to the CBM report
(cbm-report.statement.json by default, or --statement PATH). Its
predicateType is https://cbm.dev/attachment/v1; the existing
cbm-report.json is preserved inside the predicate.
For non-CBM subjects, cbm_attach.evidence exposes EvidenceInput,
load_evidence() and identity_errors_for(subject_package_id=..., producers=...).
This is an adapter layer; the four-piece CBE/CBP/CBM path is unchanged.
Zip-bundle
0.2.0 accepts CBS-style .zip bundles in addition to wheels. The bundle must
be listed in RELEASE_ASSETS.sha256; the report records artifact_type and
the bundle manifest SHA256. This does not replace CBS/CBP signing.
Optional semantic-verdict/v1 (0.2.1 candidate)
CBM can verify and copy an external semantic-verdict/v1 as a standalone
attachment. It does not run a semantic model, does not import CBF/CBP/CBE, and
does not change the 0.1.1/0.2.0 sidecar report contract.
cbm-attach verify-semantic --verdict semantic-verdict.json
cbm-attach attach-semantic --verdict semantic-verdict.json --output-dir semantic-out
Non-goals
- CBM does not run CBE or CBP, and does not re-compute their gates.
- CBM does not prove code security.
- CBM does not rebuild the package. It verifies the build-once artifact and
refuses an artifact that is not listed in
WHEEL_SHA256andRELEASE_ASSETS.sha256. CBM 0.1.0 supportsartifact_type=wheelonly; a zip-bundle is rejected as an input error. - CBM does not write the whole CBS Release body. It emits one marker-delimited fragment; the CBS body generator merges it.
Two-axis status
| Situation | cbm_gate_status |
upload_status |
exit |
|---|---|---|---|
| not claimed, no failure | NOT_UPLOADED |
NOT_UPLOADED |
0 |
| CBE/CBP FAIL blocks upload | FAIL |
NOT_UPLOADED |
3 |
| own hash/upload verification failure | FAIL |
NOT_UPLOADED or UPLOADED_UNVERIFIED |
3 |
| infrastructure failure | SKIPPED_INFRA |
NOT_UPLOADED |
3 |
| missing/invalid input | PRECONDITION_FAIL |
NOT_UPLOADED |
2 |
| skip ratio above 20% | FAIL |
NOT_UPLOADED |
4 |
| uploaded and digest verified | PASS |
UPLOADED_VERIFIED |
0 |
The Release body labels the attachment from upload_status, so a gate failure
is still shown as NOT_UPLOADED without being laundered into PASS.
Commands
# verify: consume reports, enforce the gate, write report/body/decision
python -m cbm_attach verify \
--version v0.1.0 --tag v0.1.0 --release-tag v1.7.0 \
--declared-attached true --upload-target github-release \
--cbe-report cbe.json --cbp-report cbp.json --build-once-dir build-once \
--output cbm-evidence/cbm-report.json \
--body cbm-evidence/cbm-body.md \
--decision cbm-evidence/cbm-decision.json
# upload: re-verify the build-once artifact, then upload idempotently
python -m cbm_attach upload \
--report cbm-evidence/cbm-report.json \
--decision cbm-evidence/cbm-decision.json \
--build-once-dir build-once \
--upload-target github-release \
--repository owner/repo --release-tag v1.7.0 \
--output cbm-evidence/cbm-report.final.json \
--body cbm-evidence/cbm-body.final.md
# finalize: choose the best report, regenerate the body fragment
python -m cbm_attach finalize \
--input cbm-evidence --output cbm-evidence-out/cbm-report.json \
--body cbm-evidence-out/cbm-body.md --declared-attached true
verify --fetch and upload --fetch download run artifacts through gh api.
artifact_repository must hold all three run artifacts (CBM build-once, CBE
report, CBP manifest); split repositories need an input extension in a later
version. Cross-repository download needs a token with actions:read on the
artifact repository; cross-repository release upload needs contents:write on
the release repository. Use a scoped GitHub App/PAT, not a broad personal token.
GitHub artifact downloads are repository-bound. The v1.7 release train must
upload the CBM build-once artifact, CBE report and CBP manifest to the same
artifact_repository. If CBE/CBP upload in their own repositories, CBM cannot
download them; verify --fetch will exit 2 with MISSING_BUILD_ONCE_ARTIFACT,
MISSING_CBE_REPORT or MISSING_CBP_REPORT. This is a release-train
orchestration requirement, not something CBM can fix alone. It should be added
to CONTRACT.md §11.
Audited on 2026-11-08: the checked-in CBS mock train
(reusable-v17-release.yml) uploads only v17-mock-artifact in the CBS repo
and has no CBM job; CBP ci.yml uploads quality-manifest-${run_id} in the
CBP repo. The artifacts are not co-located, so the same-repo contract is
not implemented yet; this is blocker B4, and it must be solved together
with B3 (CBP P0-06), not separately. CBM v0.1.0 takes one
artifact_repository; split repos need a copy step or a v0.2.0 input
extension. Required names:
cbm-build-once, cbe-report, cbp-quality-manifest (the actual CBP artifact
may be quality-manifest-<run_id>; pass it as cbp_report_artifact). See
docs/INTEGRATION_REQUIREMENTS.md.
CBM 0.1.0 supports artifact_type=wheel only. A CBS artifact_type=zip-bundle
requires CBM 0.2.0. CBM does not sign and does not consume CBS's
update-manifest.sig; that is a CBS release asset and must be listed in CBS's
own RELEASE_ASSETS.sha256 per §11. CBM reads only the CBM build-once
artifact's manifest.
Workflow integration (v0.1.0)
The reusable workflow is .github/workflows/cbm-attach.yml. It has three jobs:
verifyconsumes CBE/CBP reports, enforces the gate, and writes a draftcbm-evidence/cbm-report.jsonpluscbm-evidence/cbm-body.md.uploadruns only whenneeds.verify.result == 'success'andneeds.verify.outputs.decision == 'UPLOAD'; it re-verifies the build-once artifact, uploads it, and writescbm-evidence/cbm-report.final.jsonpluscbm-evidence/cbm-body.final.md.needs.verify.resultisfailurefor exit 2/3/4, so missing input, gate failure and skip-over-threshold all skip upload.finalizeruns withif: ${{ !cancelled() }}, checks out the CBM tooling independently of verify's artifact, recovers every evidence artifact, and writescbm-evidence-out/cbm-report.jsonpluscbm-evidence-out/cbm-body.md(a marker-delimited fragment). A checkout or GitHub API outage can still prevent finalize from writing evidence. In that case CBS body generator supplies theCBM: NOT_UPLOADED+EVIDENCE_ABSENTrecord. CBS v1.7.0-integrationfa1740fimplements this; B5 is fixed and the test is flipped. Seedocs/V17_BLOCKERS.mdanddocs/CBS_BODY_REQUIREMENT.md.
The CBS body generator must consume the finalized cbm-evidence-out
artifact, not the verify draft. The verify draft says NOT_UPLOADED because the
upload has not happened yet; that is honest, but it is not the final attachment
status.
CBM does not edit the CBS Release body in v0.1.0. The fragment includes
<!-- CBM:START --> / <!-- CBM:END --> so the CBS generator can merge one
block idempotently. If a future asynchronous step updates the body, it must do a
latest-body read-modify-write, replace exactly the marker block, retry on
conflict, and never touch the body when the upload failed. body.py already
provides replace_marker_block for that future path.
If finalize finds no report at all, it writes
cbm_gate_status=SKIPPED_INFRA, reason=EVIDENCE_ABSENT (detail
WORKFLOW_FAILED_BEFORE_EVIDENCE) and upload_status=NOT_UPLOADED; it never
writes PASS. If the verify or upload job
failed after writing UPLOAD_PENDING, finalize turns that stale pending
report into FAIL / UPLOAD_FAILED (or EVIDENCE_INVALID for a
PASS-without-upload contradiction).
Evidence hashes
cbe_report_hash and cbp_report_hash are SHA-256 over the raw bytes of
the report that CBM read. They are not the report's evidence_sha256 field and
they are not a canonicalised JSON hash. evidence_sha256 on the CBM report is
the SHA-256 of the canonical JSON of the report without that field.
Tests
python -m pytest
139 tests pass: exit-code mapping, gate-before-upload (including a mock uploader that records calls), NOT_UPLOADED body rendering, hashes, workflow static audit, schema/report lockstep, and a mock end-to-end verify/upload/finalize flow. These are offline/static tests, not real E2E.
tests/test_known_fail_silent.py is now the flipped B5 regression test: it
asserts the fixed CBS output (CBM: NOT_UPLOADED + EVIDENCE_ABSENT, no
- none) and the exact phrase when CBM is declared attached. It still checks the
probe's missing/import/unexpected modes; a missing CBS checkout skips with
SKIP_REASON=CBS_BODY_GENERATOR_NOT_FOUND, and an unimportable file fails with
FAIL_REASON=CBS_BODY_GENERATOR_UNIMPORTABLE.
139 passed = 139 normal tests; no KNOWN_FAIL_SILENT canary remains. Do not
reintroduce the old - none assertion as an accepted state.
Probe CLI:
python tools/check_b5.py --check-upstream
| Output | Exit | Meaning |
|---|---|---|
STATUS=B5_MAYBE_FIXED |
0 | expected fixed state; B5 test is green |
STATUS=KNOWN_FAIL_SILENT |
0 | old/failed CBS behavior; B5 test fails as a regression |
SKIP_REASON=CBS_BODY_GENERATOR_NOT_FOUND |
0 | CBS checkout missing; test skips |
FAIL_REASON=CBS_BODY_GENERATOR_UNIMPORTABLE |
3 | CBS file exists but import/build fails; test fails |
FAIL_REASON=UNEXPECTED_OUTPUT |
2 | output is neither old defect nor fixed; inspect |
Open contract points
- §5.1 report identity. CBE/CBP reports currently use
package_idambiguously. CBM requirespackage_id == "cbm"and treats a producer name there asREPORT_IDENTITY_MISMATCH(exit 3, no upload). - §5.2 CBP body hash scope. CBM requires
release_body_hashandbody_hash_scope: "base"in the CBP quality manifest; missing or"full"exits 2.
The proposals are in
docs/CONTRACT_PROPOSAL_5.1.md; the full
blocker list is docs/V17_BLOCKERS.md. They are
change-control inputs for the CBS/CBP owners; this repository does not edit the
frozen contract. CBM 0.1.0 sidecar upload is verified; B3 field-level and B5
are complete; full product/A-F live E2E is not claimed.
CBF privacy gate (Phase 0)
CBF is not integrated yet. Status: PENDING_CBF_0.1.0; there is no CBF
PASS for this project or its releases. The cbf-privacy-gate CI job name is
reserved as a name only; no workflow file is added in Phase 0. No
continue-on-error / if: false bypass exists. See docs/CBF_ADOPTION.md.
CBF evidence is an optional attachment; it does not change the CBM 0.1.1/0.2.0 sidecar contract and CBM does not import or require CBF. After adoption, GitHub push / Release / PyPI / cloud-AI / local-AI use requires CBF PASS. CBF 0.1.0 is not released yet, so no CBF PASS exists. Until then, do not describe the project as CBF-compatible or CBF-passed.
CBF status
CBF 0.1.0 has not been released. This project is not CBF-integrated and has no CBF PASS. Phase 0 preparation is recorded in docs/CBF_ADOPTION.md; no runtime dependency, no import, and no CBF-certified release exists yet.
Metadata
Release files for cbm-attach 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cbm_attach-0.2.1.tar.gz | 59.1 kB | With provenance | Details for cbm_attach-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cbm_attach-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for cbm_attach-0.2.1-py3-none-any.whl |
Total release size: 101.0 kB
Release files / cbm_attach-0.2.1.tar.gz
| Download URL | cbm_attach-0.2.1.tar.gz |
|---|---|
| Size | 59.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4ba27e7b864989c07775bc354efda6c3c57687b59993a2c9e8c682c42476b1a
|
|
BLAKE2b-256 checksum How to use checksums |
bbce417e5dcdc9936bd9d4db86adba41244f1c1e7dfda553cbe51197e6d3f4a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logRelease files / cbm_attach-0.2.1-py3-none-any.whl
| Download URL | cbm_attach-0.2.1-py3-none-any.whl |
|---|---|
| Size | 41.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b84b90a8c884e3ed8495dc5ca4c9061545e36752c3a20d26bbd5fac89551847f
|
|
BLAKE2b-256 checksum How to use checksums |
3551aca8e52d39a37c05abb649c0debf2213d20890e379c9660a87e842132c47
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logSecurity for cbm-attach 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for cbm_attach-0.2.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.