Validate CI module tags before delivery preparation

This commit is contained in:
2026-11-01 19:27:56 +00:00
parent 9376bafaa2
commit 078db6cbcb
4 changed files with 83 additions and 4 deletions

View File

@@ -0,0 +1,60 @@
package main
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"go.maximumdirect.net/releasekit/cmd/releasekit/internal/cli"
)
func TestCIDeliveryRejectsModuleTagMismatchBeforePreparation(t *testing.T) {
for _, binary := range []bool{false, true} {
name := "page-only"
if binary {
name = "binary"
}
t.Run(name, func(t *testing.T) {
repository := newDeliveryBuildRepository(t)
writeRepositoryFile(t, repository, "child/go.mod", "module example.com/tagged-app/child\n\ngo 1.26.0\n")
writeRepositoryFile(t, repository, "child/docs/releases/v1.2.3.md", "# Example Product v1.2.3\n\nChild release.\n")
cliGitRun(t, repository, "add", "child")
cliGitRun(t, repository, "commit", "-m", "add child module")
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Errorf("mismatched module tag reached forge: %s", r.URL.Path)
http.Error(w, "unexpected request", http.StatusInternalServerError)
}))
defer server.Close()
settings := cli.Settings{
Product: "Example Product", ModuleDir: "child",
Delivery: &cli.DeliverySettings{Forge: "gitea", BaseURL: server.URL, Owner: "owner", Repository: "example"},
}
if binary {
settings.Build = &cli.BuildSettings{MainPackage: ".", BinaryName: "helper", Targets: []string{"linux/amd64"}}
}
writeDeliveryProfile(t, repository, settings)
commit := pushTaggedCLIRepository(t, repository)
t.Setenv("RELEASEKIT_GITEA_TOKEN", "fixture-token")
shimDir := t.TempDir()
marker := filepath.Join(shimDir, "go-invoked")
if err := os.WriteFile(filepath.Join(shimDir, "go"), []byte("#!/bin/sh\n: > \"$RELEASEKIT_GO_MARKER\"\nexit 99\n"), 0o700); err != nil {
t.Fatal(err)
}
t.Setenv("RELEASEKIT_GO_MARKER", marker)
t.Setenv("PATH", shimDir+string(os.PathListSeparator)+os.Getenv("PATH"))
var stdout, stderr bytes.Buffer
status := run(context.Background(), []string{"ci-deliver", "--repo", repository, "--prepared", "--commit", commit, "--expected-module", "child", "v1.2.3"}, &stdout, &stderr)
if status != 1 || !strings.Contains(stderr.String(), `expected delivery tag "v1.2.3"`) || !strings.Contains(stderr.String(), `selected module tag "child/v1.2.3"`) {
t.Fatalf("status=%d stderr=%q, want module tag mismatch", status, stderr.String())
}
if _, err := os.Stat(marker); !os.IsNotExist(err) {
t.Fatalf("dependency/build work ran before tag comparison: %v", err)
}
})
}
}

View File

@@ -291,6 +291,15 @@ func runCIDelivery(ctx context.Context, invocation cli.Invocation, stdout, stder
fmt.Fprintf(stderr, "profile module selection: %v\n", err)
return 2
}
identity, err := releaseidentity.FromCommitted(ctx, invocation.Repository, settings.ModuleDir, invocation.Version, invocation.Commit)
if err != nil {
fmt.Fprintf(stderr, "resolve CI release identity: %v\n", err)
return 1
}
if invocation.ExpectedTag != identity.Tag {
fmt.Fprintf(stderr, "expected delivery tag %q does not match selected module tag %q\n", invocation.ExpectedTag, identity.Tag)
return 1
}
destination, status := deliveryDestination(invocation.Repository, settings, stderr)
if status != 0 {
return status