Skip to content

ci: ask the release's version question on the pull request - #57

Merged
HuggeK merged 1 commit into
srcfl:mainfrom
HuggeK:feat/channel-preflight
Jul 31, 2026
Merged

ci: ask the release's version question on the pull request#57
HuggeK merged 1 commit into
srcfl:mainfrom
HuggeK:feat/channel-preflight

Conversation

@HuggeK

@HuggeK HuggeK commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

The signed channel refuses to republish changed artifact bytes under a version it has already published — the rule that makes a version name a set of bytes an operator can pin. It was the one release check no pull request could run, because asking it needs the published channel, so it only ever ran from the release job on main.

That is how #53 merged with five green checks and took the release down with

error: nibe_local: changed artifact needs a higher version than 1.1.0

The repair (#55) then had to be a second pull request against a main that was already broken. This closes that window.

What runs now

A signed channel accepts this tree job on every pull request. It downloads the published drivers-beta manifest, rebuilds the artifacts in memory, and applies the release's rule.

Why this needs no secret, and works for forks

Nothing about the question involves signing. The published manifest is a public release asset; its signature verifies with FTW_DRIVER_SIGNING_PUBLIC_KEY, which is already sitting in plain text in the release workflow because it is a public key. The job signs nothing and reads no secret, so a pull request from a fork — which gets no secrets — runs it exactly like a branch pull request.

If drivers-beta has never been published, the job says so and passes: there are no versions to collide with.

The check has to agree with the release, or it is worse than nothing

_version_collisions is now the single statement of the rule. Both build_publication (while signing, on main) and check_publication (on a pull request) read it. A rule stated twice is a rule that drifts, and a preflight that drifts from the release gives false confidence.

test_check_versions_answers_what_the_release_would_answer pins that: same tree, same published manifest, both must reach the same verdict — pass and fail.

Verified against the live channel

Not just unit tests — I ran check_publication against the manifest the channel has actually published:

[main as published]  PASS -> {"published_commit": "7b8a18a…", "drivers": 80, "added": [], "changed": []}

[replay of #53: manifest-only ders edit, version left alone]  REFUSED ->
  the signed channel would refuse this tree:
    nibe_local: changed artifact needs a higher version than 1.1.1 (published)
      -- make bump-driver ID=nibe_local LEVEL=patch

The edit that broke main is caught before merge. test_check_versions_catches_a_manifest_only_edit is that same shape as a test: a manifest field corrected, no Lua touched, the published bytes moved anyway.

Other behaviour, and the tests for it
  • Reports every colliding driver, each with the command that fixes it. The release still stops at the first — it has nothing else to do; someone fixing a branch wants the list (test_check_versions_reports_every_colliding_driver).
  • A changed driver that took a version bump passes (test_check_versions_accepts_a_changed_driver_that_took_a_version).
  • A driver the channel has never published is reported as added, not as a collision (test_check_versions_reports_a_driver_the_channel_has_never_published).
  • A tampered manifest is still rejected — it is fetched over the network, so the signature has to hold (test_check_versions_rejects_a_manifest_the_signing_key_did_not_sign).

One sharp edge, stated in CONTRIBUTING

The comparison is against the published channel, not against main. So if main is itself unpublishable, this check fails on unrelated pull requests until main is fixed. That is the breakage surfacing rather than hiding, but it is worth knowing before it happens, so CONTRIBUTING.md says so — along with the command to ask the question locally, and the correction that this no longer fails only after a merge.

Test run

2969 passed locally. Fourteen failures are all pre-existing and reproduce on the unmodified base commit: ten need the lua55 interpreter the Makefile builds (plus one Windows path issue in test_blueprint.py), and four test_stable_promotion_* failures are a Windows CRLF artifact in manifest.payload.json. CI runs all of them on Linux.

tests/test_ftw_repository.py needs the package extra, which this machine does not have, so I ran it against an in-memory Ed25519 stand-in that keeps the properties the tests rely on — a signature verifies only under its own key, and any payload edit breaks it. Nothing about that stand-in is committed; CI runs the real thing.

The signed channel refuses to republish changed artifact bytes under a version
it has already published. That is the rule that makes a version name a set of
bytes an operator can pin, and it was the one release check no pull request
could run: asking it needs the published channel, so it only ever ran from the
release job on main. srcfl#53 merged with five green checks and took the release
down; the repair had to be a second pull request against a main that was
already broken.

Nothing about the question needs the signing key. The published manifest is a
public release asset, its signature verifies with the public key already in
the workflow, and the bytes a driver would publish as come from the tree. So
check-versions builds the artifacts in memory, signs nothing, and answers what
the release would answer -- on every pull request, forks included, since a
fork needs no secret to read a public asset.

_version_collisions is now the single statement of the rule. Both the release
and the check read it, because a rule stated twice drifts, and a check that
drifts from the release is worse than no check at all:
test_check_versions_answers_what_the_release_would_answer holds them to the
same verdict on the same tree.

The check reports every colliding driver rather than the first, each with the
bump_driver command that fixes it. The release still stops at one; it has
nothing else to do, and someone fixing a branch wants the list.

test_check_versions_catches_a_manifest_only_edit is srcfl#53 in the shape it
arrived in -- a manifest field corrected, no Lua touched, the published bytes
moved anyway. Verified against the live channel as well: the current main
passes, and replaying that edit is refused before a merge.

CONTRIBUTING no longer says this fails only after the merge, and carries the
command to ask it locally. It also states the one sharp edge: the comparison
is against the published channel, not against main, so a main that is itself
unpublishable fails this on unrelated pull requests until it is fixed.

Signed-off-by: Hugo Karlsson <48095810+HuggeK@users.noreply.github.com>
Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
@HuggeK
HuggeK marked this pull request as ready for review July 31, 2026 09:57
@HuggeK
HuggeK merged commit 6756599 into srcfl:main Jul 31, 2026
6 checks passed
HuggeK added a commit to HuggeK/device-drivers that referenced this pull request Jul 31, 2026
srcfl#57 landed the `signed channel accepts this tree` check on main, and both
branches wrote a CHANGELOG entry under the same `### Added` heading. The
resolution keeps both, `upstream_docs` first, and touches nothing else.

The check main gained is one this branch has to answer: it adds
`upstream_docs` to two manifests, and a manifest edit can move the signed
artifact's bytes. This field does not -- `_load_channel` copies `ders`,
`protocol` and the tested-device make and model into the artifact metadata
and leaves the rest behind -- so no driver version has to move. The check
says so rather than the branch claiming it.

Signed-off-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
HuggeK added a commit to HuggeK/device-drivers that referenced this pull request Jul 31, 2026
This branch was cut before srcfl#48, srcfl#57, srcfl#62 and srcfl#63 landed. Five files
conflicted; all five were additions on both sides and keep both:

  CHANGELOG.md          both wrote under the same ### Added heading
  spec/manifest-v2.md   Connectivity/Setup beside main's DER Types, and
                        the numbered validation list renumbered so the
                        upstream_docs rule survives
  manifests/myuplink.yaml  connectivity/setup from here, ders [heatpump]
                        and 1.1.1 from srcfl#63 -- the empty ders this branch
                        was written against no longer exists
  tools/generate_site.py   Reach labels beside the vendor-document labels
  index.yaml            regenerated rather than hand-merged

Also records V2.4 in the migration ledger. The branch adds two manifest
fields and updated the field table and validation rules, but never
recorded the version the way V2.3 did for upstream_docs.

The claim that neither field reaches the signed artifact is checked
rather than trusted: with all 80 manifests carrying connectivity,
stripping both fields back out moves no artifact digest, so no driver
needs a version bump.

Signed-off-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants