Fix release destination handling and verification example

This commit is contained in:
2026-09-28 01:42:06 +00:00
parent d750e7325c
commit a36ed3deba
4 changed files with 69 additions and 7 deletions

View File

@@ -180,10 +180,12 @@ Only when useful or requested, read back the remote tag or retrieve the exact
version into a new module without a local `replace` directive. These checks version into a new module without a local `replace` directive. These checks
are optional and non-gating. Do not poll CI or wait for module propagation. are optional and non-gating. Do not poll CI or wait for module propagation.
Private-host credentials must already be configured. For direct-origin Private-host credentials must already be configured. For direct-origin
verification, use a temporary consumer module and check the exact module path verification, set the version to the release just published (replace the sample
below), then use a temporary consumer module and check the exact module path
and version reported by `go list -m`: and version reported by `go list -m`:
```sh ```sh
release_version=v0.5.0
consumer_dir=$(mktemp -d) consumer_dir=$(mktemp -d)
( (
cd "$consumer_dir" cd "$consumer_dir"

View File

@@ -1,5 +1,25 @@
# Release Workflow Review Findings # Release Workflow Review Findings
Status: both findings addressed. The original findings below are retained as
review history until normal release-preparation retirement.
## Resolution and verification
- Publication, fetch, and recovery now use the same validated named `origin`.
Pushes retain exact refspecs and disabled implicit tags, and override the
remote's mirror default for that invocation only. No new gate was introduced.
- A disposable-Git regression failed against the original publisher and passes
with the fix for normal publication and lost main/tag push responses. It also
checks that broad push defaults do not publish or delete unrelated refs and
that the rewrite destination receives no refs.
- Optional consumer verification explicitly initializes the selected version.
Executing the documented block with a local Go stub verified the exact module
argument with both an initially unset and an initially stale version variable,
without network retrieval.
- Focused publication tests passed. Final validation passed: Bash syntax,
whitespace review, and the Go 1.25.14 release checker (race suite including
documentation links, full vet, and both Linux target builds).
Reviewed implementation through `3d0093e` against the release roadmap and Reviewed implementation through `3d0093e` against the release roadmap and
completed implementation plan. The ordinary Go 1.25.14 release checker passed completed implementation plan. The ordinary Go 1.25.14 release checker passed
(offline race suite, full vet, Linux amd64/arm64 builds), as did Bash syntax (offline race suite, full vet, Linux amd64/arm64 builds), as did Bash syntax

View File

@@ -108,7 +108,8 @@ func (f *releaseFixture) run(version, behavior, validatorAction string) (string,
if [ "${CONFIGKIT_GIT_BEHAVIOR-}" = main-unknown ] || [ "${CONFIGKIT_GIT_BEHAVIOR-}" = tag-unknown ]; then if [ "${CONFIGKIT_GIT_BEHAVIOR-}" = main-unknown ] || [ "${CONFIGKIT_GIT_BEHAVIOR-}" = tag-unknown ]; then
if [ "${1-}" = ls-remote ] && [ -f "$CONFIGKIT_GIT_MARKER" ]; then exit 37; fi if [ "${1-}" = ls-remote ] && [ -f "$CONFIGKIT_GIT_MARKER" ]; then exit 37; fi
fi fi
if [ "${1-}" = push ]; then case "$*" in
push\ *|-c\ remote.origin.mirror=false\ push\ *)
case "$*" in case "$*" in
*refs/heads/main*) *refs/heads/main*)
case "${CONFIGKIT_GIT_BEHAVIOR-}" in case "${CONFIGKIT_GIT_BEHAVIOR-}" in
@@ -126,7 +127,8 @@ if [ "${1-}" = push ]; then
tag-unknown) : > "$CONFIGKIT_GIT_MARKER"; exit 37 ;; tag-unknown) : > "$CONFIGKIT_GIT_MARKER"; exit 37 ;;
esac ;; esac ;;
esac esac
fi ;;
esac
exec "$CONFIGKIT_REAL_GIT" "$@" exec "$CONFIGKIT_REAL_GIT" "$@"
` `
if err := os.WriteFile(filepath.Join(bin, "git"), []byte(wrapper), 0700); err != nil { if err := os.WriteFile(filepath.Join(bin, "git"), []byte(wrapper), 0700); err != nil {
@@ -320,3 +322,38 @@ func TestReleasePublicationRecovery(t *testing.T) {
}) })
} }
} }
func TestReleasePublicationUsesValidatedDestination(t *testing.T) {
for _, behavior := range []string{"success", "main-lost", "tag-lost"} {
t.Run(behavior, func(t *testing.T) {
f := newReleaseFixture(t)
other := filepath.Join(t.TempDir(), "other.git")
f.git("init", "-q", "--bare", other)
f.git("remote", "set-url", "--push", "origin", f.remote)
f.git("config", "url."+other+".pushInsteadOf", f.remote)
// These defaults must not broaden the explicit release refspecs when
// publishing through the validated named remote.
f.git("config", "remote.origin.mirror", "true")
f.git("config", "remote.origin.push", "refs/heads/*:refs/heads/*")
f.git("branch", "unrelated", f.base)
f.git("tag", "-a", "-m", "Unrelated", "v0.8.0", f.base)
f.git("--git-dir="+f.remote, "update-ref", "refs/heads/keep", f.base)
out, err := f.run("v0.9.0", behavior, "")
if err != nil {
t.Fatalf("publish: %v\n%s", err, out)
}
if f.validations() != 1 || f.remoteRef("refs/heads/main") != f.candidate ||
f.remoteRef("refs/tags/v0.9.0") != f.git("rev-parse", "refs/tags/v0.9.0") {
t.Fatal("publication did not reach the validated destination")
}
if f.remoteRef("refs/heads/keep") != f.base ||
f.remoteRef("refs/heads/unrelated") != "" || f.remoteRef("refs/tags/v0.8.0") != "" {
t.Fatal("publication changed unrelated refs")
}
if refs := f.git("--git-dir="+other, "for-each-ref", "--format=%(refname)"); refs != "" {
t.Fatalf("publication reached the rewrite destination: %s", refs)
}
})
}
}

View File

@@ -36,7 +36,7 @@ check_unused_version() {
read_remote_ref() { read_remote_ref() {
local ref=$1 response result local ref=$1 response result
if response=$(git ls-remote --refs --exit-code "$remote_url" "$ref" 2>/dev/null); then if response=$(git ls-remote --refs --exit-code origin "$ref" 2>/dev/null); then
[[ "$response" == *$'\t'"$ref" ]] || return 3 [[ "$response" == *$'\t'"$ref" ]] || return 3
printf '%s\n' "${response%%$'\t'*}" printf '%s\n' "${response%%$'\t'*}"
else else
@@ -78,7 +78,7 @@ else
((result == 2)) && fail "authoritative main is absent" ((result == 2)) && fail "authoritative main is absent"
fail "cannot read authoritative main; publication status is unknown" fail "cannot read authoritative main; publication status is unknown"
fi fi
git fetch --no-tags "$remote_url" refs/heads/main >/dev/null || git fetch --no-tags origin refs/heads/main >/dev/null ||
fail "cannot fetch authoritative main" fail "cannot fetch authoritative main"
fetched_main=$(git rev-parse --verify FETCH_HEAD) || fail "cannot inspect fetched main" fetched_main=$(git rev-parse --verify FETCH_HEAD) || fail "cannot inspect fetched main"
git merge-base --is-ancestor "$fetched_main" "$candidate" || git merge-base --is-ancestor "$fetched_main" "$candidate" ||
@@ -88,7 +88,10 @@ git merge-base --is-ancestor "$fetched_main" "$candidate" ||
check_candidate "after validation" check_candidate "after validation"
check_unused_version check_unused_version
if git push --no-follow-tags "$remote_url" "$candidate:refs/heads/main"; then # Use the named remote whose resolved destinations were checked above: a literal
# URL can apply pushInsteadOf even when origin's explicit push URL does not.
# Disable mirror defaults as well as implicit tags; publish only our refspec.
if git -c remote.origin.mirror=false push --no-follow-tags origin "$candidate:refs/heads/main"; then
: :
else else
if observed_main=$(read_remote_ref refs/heads/main); then if observed_main=$(read_remote_ref refs/heads/main); then
@@ -113,7 +116,7 @@ tag_type=$(git cat-file -t "refs/tags/$version") ||
tag_oid=$(git rev-parse --verify "refs/tags/$version") || tag_oid=$(git rev-parse --verify "refs/tags/$version") ||
fail "main is at $candidate; cannot identify local tag $version" fail "main is at $candidate; cannot identify local tag $version"
if git push --no-follow-tags "$remote_url" "refs/tags/$version:refs/tags/$version"; then if git -c remote.origin.mirror=false push --no-follow-tags origin "refs/tags/$version:refs/tags/$version"; then
: :
else else
if observed_tag=$(read_remote_ref "refs/tags/$version"); then if observed_tag=$(read_remote_ref "refs/tags/$version"); then