feat(apply,scan): generate OpenVEX document inline via --vex#94
Merged
Mikola Lysenko (mikolalysenko) merged 5 commits intoMay 30, 2026
Merged
Conversation
Add an optional `--vex <path>` argument to `apply` and `scan`. On a
successful run, the command writes an OpenVEX 0.2.0 document to that path
using the same engine as the standalone `vex` command, so a single
invocation can both apply/scan patches and emit the attestation — the
natural shape for CI and bot workflows.
Core refactor: extract the product-resolve -> verify -> build -> serialize
-> write -> telemetry pipeline out of `vex::run` into reusable
`generate_vex` / `generate_vex_from_manifest_path` helpers (plain
VexBuildParams / VexWriteSummary / VexGenError types). The standalone `vex`
command now calls this helper with no behavior change.
Embedded contract:
- `--vex` is the trigger; `--vex-product` / `--vex-no-verify` /
`--vex-doc-id` / `--vex-compact` mirror the standalone knobs (namespaced
to avoid colliding with apply's --force vocabulary; reuse SOCKET_VEX_*).
- Always written to the file, never stdout, so it never races --json.
- Fail-the-command: a requested-but-failed VEX flips the exit code even
when the apply/scan itself succeeded, surfacing the error in the JSON
envelope (apply) / result (scan) with a stable code.
- Built from the post-run manifest, verified against on-disk state;
generated for real applies, --dry-run, and read-only scans alike.
- JSON success adds a top-level `vex` summary { path, statements, format }.
Tests: new e2e_embedded_vex.rs (apply parity, envelope field, fail path,
scan no-verify success, scan verify-failure error); parse-test coverage in
cli_parse_{apply,scan}; update CLI_CONTRACT.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an Unreleased "Added" changelog entry, document the `--vex` / `--vex-*` flags in the apply & scan README tables with examples, and add an "Inline VEX on apply / scan" subsection covering the fail-the-command contract and JSON summary surface. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `scripts/rollover-changelog.sh` and a post-publish `changelog-rollover` job. After every artifact publishes, the job promotes `## [Unreleased]` to `## [<version>] — <date>` and leaves a fresh empty `[Unreleased]` for the next cycle, then commits it back to the release branch (`[skip ci]`). The helper is idempotent and runs after publish, so it never fails the release: it's a no-op when a `## [<version>]` heading was written by hand or when `[Unreleased]` is empty, leaving the file byte-identical so there's nothing to commit. To make the new flow usable end-to-end, the pre-publish version-check now accepts a non-empty `[Unreleased]` section as valid release notes (in addition to an explicit `## [X.Y.Z]` heading), so maintainers can just add entries under `[Unreleased]` and let the rollover stamp them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wenxin Jiang (Wenxin-Jiang)
approved these changes
May 29, 2026
Empty commit to re-trigger the CI workflow — the previous push (a7ad4cf) did not fire a pull_request run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Audit GHA Workflows check (zizmor) flagged a High template-injection:
`${{ github.ref_name }}` expanded directly inside the push `run:` block can
inject attacker-controllable code via a crafted branch name. Pass workflow
contexts (`github.ref_name`, `needs.version.outputs.version`) through `env:`
and reference them as shell variables instead.
Verified clean with `zizmor .github --gh-token <tok> --min-severity medium`
(the exact CI invocation): "No findings to report."
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an optional
--vex <path>argument toapplyandscan. On a successful run the command writes an OpenVEX 0.2.0 document to that path using the same engine as the standalonevexcommand — so a single invocation can both apply/scan patches and emit the attestation, the natural shape for CI and bot workflows.How it works
vex::runinto reusablegenerate_vex/generate_vex_from_manifest_pathhelpers (plainVexBuildParams/VexWriteSummary/VexGenErrortypes). The standalonevexcommand now calls this helper — no behavior change (its e2e suite still passes unmodified).--vexis the trigger;--vex-product/--vex-no-verify/--vex-doc-id/--vex-compactmirror the standalone knobs (namespaced to avoid colliding with apply's--forcevocabulary; reuse theSOCKET_VEX_*env vars). Inert unless--vexis set.Contract
--jsonoutput.apply) / result (scan).--vex-no-verify). Generated for real applies,--dry-run, and read-only scans alike.vexsummary{ path, statements, format: "openvex-0.2.0" }.apply's no-manifest early no-op does not trigger VEX generation — nothing to attest.Release CI: automatic CHANGELOG rollover
Also wires a
changelog-rolloverjob +scripts/rollover-changelog.shhelper intorelease.yml. After every artifact publishes, it promotes## [Unreleased]to## [<version>] — <date>, leaves a fresh empty[Unreleased], and commits it back to the release branch ([skip ci]).## [<version>]heading was written by hand or when[Unreleased]is empty.[Unreleased]as valid release notes (in addition to an explicit heading), so maintainers can just add entries under[Unreleased]and let the rollover stamp them.Tests & docs
tests/e2e_embedded_vex.rs(5 tests): apply parity, JSON envelopevexfield, apply fail-the-command, scan--vex-no-verifysuccess, scan verify-failure error.cli_parse_{apply,scan}.rs; updated the in-process test fixtures for the new field.CLI_CONTRACT.md,README.md, andCHANGELOG.md(Unreleased) updated.Full CLI suite + new e2e tests pass with and without the
cargofeature; clippy clean. Rollover helper verified locally (promote, idempotency, existing-heading no-op, empty-Unreleased no-op).🤖 Generated with Claude Code