Repository navigation
v0.10.0 "Verified Releases & Safe Gates"
Every release is now built from its tag with hash-locked tools and carries signed build provenance, and no output or CI gate treats an input OpenPulse did not fully read as clean. This release changes outputs and gates:
--fail-on(CLI and Action) now fails on a repository it could not read.openpulse attestemits evidence contract 2.1.0, where runs with no repository sayNOT_APPLICABLEcoverage.- A token file with two non-empty lines is refused.
Webhooks connect only to the address that passed the SSRF check. Verdicts and the frozen evaluation are unchanged. Read the upgrade notes before upgrading CI gates or contract consumers.
Upgrade notes
openpulse attestemits evidence contract 2.1.0, and runs with no repository sayNOT_APPLICABLEcoverage (#109, v0.10.0 item V3). Contracts from--watchlist,--sbom,--spdx,--lockfile,--manifestor--imagesruns saidinspection_coverage.status: COMPLETEalthough no repository was scanned; they now sayNOT_APPLICABLE. A consumer validating against the 2.0 schema must switch toschemas/evidence-contract/v2.1/schema.json, and one that switches on the status must accept the new value. Runs with--github-repoare unchanged. The Action'sinspection-coverageoutput can beNOT_APPLICABLE, which raises no warning. Hash and every other value are unchanged.--github-token-fileaccepts exactly one non-empty line, holding a visible-ASCII token (#138, v0.10.0 item V5). A leading blank line is now skipped instead of rejected. A file with two non-empty lines, which used the first and ignored the rest, is now refused, because it's ambiguous which line is the token. A token with a space, a control character or a non-ASCII character is refused with a clear message, instead of failing later inside the HTTP client. No message contains the token. The read goes through the shared bounded reader (core.bounded_io), so its size error now reads "is N bytes (limit 4096)".--fail-onnow fails on FAILED repository coverage (#101, v0.10.0 item V2).check --fail-on,attest --fail-onand the GitHub Action'sfail-onexited 0 when a--github-reposcan FAILED, so a CI gate could pass on a repository OpenPulse could not read. They now exit 1 (after writing every output, forattest), as--strictalready did, and say why. PARTIAL coverage is unchanged: it fails only--fail-on-partial. Without a gating flag, FAILED coverage stays report-only.- Webhook delivery ignores
HTTP(S)_PROXY(finding M5, v0.10.0 item V4, #242). A proxy resolves the webhook host itself, which would undo the DNS pinning below, so--webhookdelivery now connects directly. A host that can only reach the webhook through a proxy can no longer deliver.
Security
- DNS-pinned webhook transport (finding M5, v0.10.0 item V4, #242). The webhook SSRF check resolved the host, then httpx connected by hostname and resolved it again, so a resolver that answered with a public address first and
127.0.0.1or169.254.169.254second (DNS rebinding) steered delivery past the check. The host is now resolved once, every returned address is checked, and the connection goes to a validated IP while TLS SNI, certificate verification and theHostheader stay on the original hostname (a custom httpcore network backend under httpx's transport; no new dependency). IPv4-mapped (::ffff:a.b.c.d), 6to4 (2002::/16) and NAT64 (64:ff9b::/96,64:ff9b:1::/48) addresses are unwrapped first, and a refusal names the embedded IPv4 and its wrapping. The rest of the policy is unchanged: https only unless--webhook-allow-http, no redirects, capped response bodies, and no URL path in output.
Added
- A warning when the GitHub token file is readable by other users (#139, v0.10.0 item V5). On POSIX, if the file's mode grants group or other access (
mode & 0o077),check,digest,warnings,attestanddiscoverprintwarning: GitHub token file <path> is readable by other users; run chmod 600 <path>to stderr. The run continues; the warning prints the path, never the token. The README example now runschmod 600. - Attested releases (#111, v0.10.0 item V1). A
v*tag runs.github/workflows/release.yml.- Build:
scripts/build_release.pybuilds the sdist and wheel from the tagged tree. It uses setuptools' own PEP 517 hooks with the hash-locked setuptools from.github/ci-tools.lock, without build isolation, so no build tool is fetched at build time. - Refused builds: a tag that differs from the package version, and a locked setuptools below
[build-system].requires. - Checks before publishing: the wheel is smoke-tested in a clean venv from outside the checkout, and the deterministic SBOM is regenerated twice and compared.
- Provenance: every file gets Sigstore-signed SLSA build provenance (
actions/attest-build-provenance); verify withgh attestation verify <file> --repo IkarusAILabs/OpenPulse. - On the GitHub release: the sdist, wheel,
sbom.cdx.jsonandSHA256SUMS, attached without replacing files that are already there. - Permissions: each job gets only what it needs:
id-tokenonly for the job that signs,contents: writeonly for the job that attaches. - Not done: nothing is published to PyPI; that waits on owner decision 7.
- Build:
Fixed
- Digest, warnings and the webhook body now say when a repository was not fully read (#102, v0.10.0 item V3). With a FAILED or PARTIAL
--github-reposcan,openpulse digestandopenpulse warningsused to drop the inspection result. Their body read "Nothing upcoming or newly-effective within the warning window", with no hint that the repository was never read, andcheck --digest --webhookposted the same. All three now carry> ⚠️ Repository inspection coverage: <status> — <reasons>. Results are not a clean bill of health.in the rendered body (andcoverage_notein--output json), so it reaches the webhook too. Output is unchanged when coverage is COMPLETE or no repository is inspected. - The CI tools lock now satisfies the build floor. Dependabot raised
[build-system].requirestosetuptools>=84.2.1, while.github/ci-tools.lockstayed at 84.1.0. The lock now pins 84.2.1, with the hashes PyPI publishes, and a test fails if the two drift apart again.