cert-generator
Render a QC certificate from a bmc-sensor-audit
attestation.
Released — 0.1.0, tagged v0.1.0, Apache-2.0, on PyPI as
odm-cert-generator.
The distribution and the command differ, and the reason is worth one line.
PyPI ultranormalises a name by stripping its separators, so cert-generator
becomes certgenerator — which an unrelated project holds — and the upload is
refused as too similar to an existing project. So this publishes as
odm-cert-generator and installs a command still called cert-generator. A
certificate records the distribution name, because that is the one that
resolves on an index.
pip install odm-cert-generator
cert-generator render \
--attestation attestation.json \
--identity identity.json \
--coverage coverage.json \
--out-json certificate.json \
--out-pdf certificate.pdf
What it is for
The audit tool judges a machine and deliberately keeps the machine's identity out of everything it writes. A certificate has the opposite job: it has to name the unit. This renders one from the other, and holds the serial number on its own side of the line.
Two trust domains, split on purpose. The referee cannot leak what it never sees. The certificate can say what a certificate must.
The certificate never claims a flat pass
It will not print "100 % match". It prints the denominator:
6 invariant(s) checked over 3 entit(ies); 1 finding(s) recorded;
3 check(s) declined and therefore not judged
...and then a section headed Not part of this judgment, which is emitted even when every list in it is empty — because an absent section reads as nothing was left out, and that is a claim.
That section carries:
| the declines | each with the engine's machine-readable reason |
unattested |
problem types the engine would not attest |
unread_feeds |
data that was read and not used |
| the declaration diff | declared vs. present, when supplied — see below |
| the engine's boundary | quoted verbatim, not paraphrased |
A certificate showing what was not checked is one an incoming-inspection team can act on. The denominator is the point, not a concession.
The declaration diff is a second, optional input
attestation/1 records what the engine judged. It does not record what was
declared and never showed up. Run the audit tool against a board declaring four
sensors where one is absent and the artifact reads checked: {entities: 3} — three,
with nothing on it saying three of four.
So --coverage takes the JSON from bmc-sensor-audit coverage --json, which does
carry the diff. Supply it and the certificate states declared-vs-present and names
the absent sensor. Leave it out and the certificate says, on the page:
no declaration diff was supplied, so this certificate cannot state how many declared sensors were present; the attestation counts only entities that reached the engine
It is optional because requiring it would make a certificate impossible for anyone holding only an attestation. It is stated because the smaller denominator must not pass for the whole picture.
That coverage artifact is written for a CI log, not a customer. It names the
BMC by URL and the configuration by filesystem path. Both are dropped here before
anything is rendered; see tests/test_privacy.py.
The PDF is a projection of the JSON
No number appears in the PDF that is absent from the certificate JSON. The JSON is the record; the PDF is how it looks. Anyone holding both can check one against the other without trusting this code:
cert-generator verify --certificate certificate.json --pdf certificate.pdf
Shipped rather than kept in a CI script, for the same reason the audit tool ships its attestation validator: the person who receives the document is the one who needs to check it.
The suite checks the same property with poppler's pdftotext — a reader nobody
here wrote.
Identity goes one way
Identity flows into the certificate and never back toward the audit inputs. This
package does not construct walks, configurations or supplemental declarations, and
has no HTTP client. tests/test_boundary.py enforces it by parsing this package's
own imports, because a rule kept by review lasts exactly as long as the reviewer's
attention.
The only thing it may reach for in the audit tool is validate_attestation — the
tool's shipped validator, not a second copy of its rules. A shapeless artifact is
refused, not decorated.
Exit codes
The family's contract, not this tool's invention:
0 |
certificate written; nothing recorded against the unit |
1 |
certificate written; findings, or a declared sensor absent |
2 |
could not complete — nothing was judged |
Precedence is max, copied from the audit tool. A run that both found something
and failed to finish reports 2, because 2 is the statement about the
denominator and 1 would let a reader conclude the rest was checked.
A certificate is still written when the verdict is 1. A QC record for a unit that
failed is a valid document.
A certificate is not the pipeline's verdict
Two records run in parallel and neither contains the other. This one certifies what
the referee established about a unit: the attestation, the identity, and the
declaration diff when one is supplied. Conformance and fault injection are not in
it. Those meet in odm-qa-pipeline aggregate, which answers a different question —
did all four gates run, and what is the worst thing any of them found.
Worth stating because reading either as the other goes wrong in both directions: a clean certificate says nothing about whether the injection gate ran, and a clean pipeline verdict is not a document anyone can hand to a customer.
The identity block
{
"serial": "SN-A17-000482",
"work_order": "WO-2026-08-1174",
"station": "FCT-3",
"signer": "L. Okonkwo",
"part_number": "PN-88213-B",
"customer": "Example Hyperscale Inc.",
"line": "Kaohsiung 2"
}
The first four are required. The rest are optional and rendered when present. Nothing is inferred, and an unrecognised key is refused rather than dropped — a typo would otherwise vanish silently, and nobody reads a certificate looking for the field that is not on it.
Known limits, written down rather than implied
- Latin-1 only. The built-in PDF fonts cannot draw characters outside it. An identity field containing them is refused, not transliterated: a serial number silently rewritten is worse than a failed render. Shipping a Unicode font would lift this; it has not been done.
verifyneeds a PDF reader. poppler'spdftotextif it is onPATH, otherwisepip install 'odm-cert-generator[verify]'for pypdf. If neither is present the command exits2— not finding a reader is not a pass.- Nothing here re-audits the machine.
verifyproves the page matches the record. The record's authority comes from the attestation, and the attestation's from the engine. - One page. Automatic page breaks are off on purpose, so a certificate that overflows is visible as overflow rather than quietly paginated. A unit with very many findings will need the JSON.
Where it sits
arbiter-engine the invariant envelope
^ pinned >=0.1.6,<0.2
bmc-sensor-audit the referee: declaration diff, liveness, attestation
^ pinned >=0.1.0,<0.2
cert-generator this: identity, and the honest certificate
qa-orchestrator sits beside this one, injecting faults and checking the referee
caught them. odm-qa-pipeline composes all of them.
Licence
Apache-2.0.
Release files for odm-cert-generator 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| odm_cert_generator-0.1.0.tar.gz | 34.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| odm_cert_generator-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.4 kB
Release files / odm_cert_generator-0.1.0.tar.gz
| Download URL | odm_cert_generator-0.1.0.tar.gz |
|---|---|
| Size | 34.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc676417e6748b429a7007ec7f09d3e094acd48ff5b2e251acc01e7ea55f3cbb
|
|
BLAKE2b-256 checksum How to use checksums |
a63c05c5d20822a961b7c02ac4d944d6c51c13ebba10d52f386c8a3d9524c340
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.12
|
Release files / odm_cert_generator-0.1.0-py3-none-any.whl
| Download URL | odm_cert_generator-0.1.0-py3-none-any.whl |
|---|---|
| Size | 25.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3fcecea4f178aaa199b3ed174810dfd5ffad4796a72730a857026cb1420cdf7f
|
|
BLAKE2b-256 checksum How to use checksums |
6f9ba106f65f88f1727eac753cbf8c4f219c2e81c2cddebd8b7f0f2c4c94ac84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.12
|