Skip to content

gen-manifests.py can still silently DOWNGRADE a committed version when the checkout has no remote #4781

Closed

Description

@rbuergi

Found while treating untreated Copilot findings on merged pull requests (the 2026-09-19 sweep, #4779).
Copilot raised the headline on MeshWeaver.Manufacturing#45 and it was never answered; the headline
is now obsolete, but a residual survives in this canonical and was measured today.

What was fixed, and what was not

.github/scripts/gen-manifests.py's up-to-date check derives release from tags and rewrites when
existing["version"] != release. In a shallow or tag-incomplete checkout release_version() can
derive a lower patch, so the rewrite is a silent downgrade of a correct committed version —
the opposite of what the script's own --check-versions warns about.

Measured on a tag-less fixture:

  • At MeshWeaver.Manufacturing#45's own head, 1.2.1 was rewritten to 1.2.0 silently, at
    exit 0. That is the reported defect.
  • On main today that case is left alone. The headline is obsolete.
  • 🚨 But with no git remote at all, a content change still writes the derived number over a higher
    committed one.
    So the guard covers the tag-incomplete case and not the no-remote case, and a
    destructive rewrite is still reachable.

The satellite copies are byte-identical to this canonical in generate(), so this is one defect in
one file with five copies downstream — and it must be fixed here, not in a copy (#1426: the last time
this script was patched per-repo it reached five vintages).

Why it was not folded into #4779

#4779 is resolve-platform.py and its self-test; this is a different script with a different harness,
and the fix needs a fixture this sweep did not build — a checkout with no remote where the
committed version is ahead of anything derivable. Widening that PR to carry it would have put an
unbuilt control in a change whose whole claim is that every fix has one.

Note #4775 has just landed on a different defect in the same script (--resolve reporting
✓ … the merge can be committed when git could not answer), and #4777 carries the remaining
vintages — so this file is already being worked; this is the piece neither of those covers.

Acceptance

A control on each side, on a fixture with no git remote and a committed version ahead of the
derived one: the current code rewrites it downward, and after the change the run either leaves the
committed version alone or errors naming "tags missing" — never silently downgrades. Treating a
committed version that is AHEAD of the derived release as evidence that tags are missing is the shape
Copilot proposed and it reads correctly for both the tag-incomplete and the no-remote case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions