Verify releases use original Git objects
This commit is contained in:
@@ -18,6 +18,41 @@ import (
|
||||
releasekit "go.maximumdirect.net/releasekit"
|
||||
)
|
||||
|
||||
func TestBuildReplacementDerivedSourceIsNotEligibleForDelivery(t *testing.T) {
|
||||
repository := newTaggedDeliveryConsumer(t)
|
||||
original := buildGit(t, repository, "rev-parse", "HEAD")
|
||||
mainPath := filepath.Join(repository, "cmd/app/main.go")
|
||||
main, err := os.ReadFile(mainPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeBuildFixture(t, repository, "cmd/app/main.go", string(main)+"\n// replacement source\n")
|
||||
buildGit(t, repository, "add", "cmd/app/main.go")
|
||||
buildGit(t, repository, "commit", "-m", "Replacement source")
|
||||
replacement := buildGit(t, repository, "rev-parse", "HEAD")
|
||||
buildGit(t, repository, "reset", "--hard", original)
|
||||
buildGit(t, repository, "replace", original, replacement)
|
||||
buildGit(t, repository, "reset", "--hard", original)
|
||||
result, err := releasekit.Build(context.Background(), releasekit.BuildRequest{
|
||||
RepositoryDir: repository, Version: "v1.2.3", OutputDir: t.TempDir(),
|
||||
Spec: releasekit.BuildSpec{MainPackage: "./cmd/app", BinaryName: "fixture", Targets: []releasekit.Target{{OS: runtime.GOOS, Arch: runtime.GOARCH}}},
|
||||
})
|
||||
if err != nil || result.SourceVerified || len(result.Artifacts) != 1 || result.CandidateCommit != original {
|
||||
t.Fatalf("replacement build = %#v, error = %v", result, err)
|
||||
}
|
||||
buildGit(t, repository, "replace", "-d", original)
|
||||
buildGit(t, repository, "reset", "--hard", original)
|
||||
server, remote := newFacadeDeliveryServer(t, repository)
|
||||
defer server.Close()
|
||||
delivery, err := releasekit.Deliver(context.Background(), releasekit.DeliveryRequest{
|
||||
RepositoryDir: repository, Product: "Fixture", Version: "v1.2.3",
|
||||
Destination: facadeDeliveryDestination(server.URL), Prebuilt: &result,
|
||||
})
|
||||
if err == nil || delivery.State != releasekit.DeliveryNotAttempted || remote.snapshot().writes != 0 {
|
||||
t.Fatalf("delivery of replacement build = %#v, error = %v", delivery, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPreservesInvalidVersionAndDeclarationFailureEvidence(t *testing.T) {
|
||||
spec := releasekit.BuildSpec{MainPackage: "./cmd/app", BinaryName: "widget", Targets: []releasekit.Target{{OS: "linux", Arch: "amd64"}, {OS: "linux", Arch: "amd64"}}}
|
||||
invalid, err := releasekit.Build(context.Background(), releasekit.BuildRequest{
|
||||
|
||||
@@ -402,6 +402,29 @@ func TestDeliverPageOnlySkipsBuildAndHostedAssets(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliverUsesOriginalNoteWithBlobReplacement(t *testing.T) {
|
||||
repository := newTaggedDeliveryConsumer(t)
|
||||
original := buildGit(t, repository, "rev-parse", "HEAD:docs/releases/v1.2.3.md")
|
||||
replacementPath := filepath.Join(t.TempDir(), "note.md")
|
||||
if err := os.WriteFile(replacementPath, []byte("# Fixture v1.2.3\n\nReplacement note.\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
replacement := buildGit(t, repository, "hash-object", "-w", replacementPath)
|
||||
buildGit(t, repository, "replace", original, replacement)
|
||||
server, remote := newFacadeDeliveryServer(t, repository)
|
||||
defer server.Close()
|
||||
result, err := releasekit.Deliver(context.Background(), releasekit.DeliveryRequest{
|
||||
RepositoryDir: repository, Product: "Fixture", Version: "v1.2.3",
|
||||
Destination: facadeDeliveryDestination(server.URL),
|
||||
})
|
||||
if err != nil || result.State != releasekit.DeliveryComplete {
|
||||
t.Fatalf("delivery = %#v, error = %v", result, err)
|
||||
}
|
||||
if got := remote.snapshot().createdBody; got != "# Fixture v1.2.3\n\nDelivery fixture.\n" {
|
||||
t.Fatalf("delivered note = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeliverUsesCommittedModuleIdentityForSeparatePages(t *testing.T) {
|
||||
repository := newTwoModuleDeliveryConsumer(t)
|
||||
server, remote := newFacadeDeliveryServer(t, repository)
|
||||
@@ -817,6 +840,7 @@ type facadeDeliveryData struct {
|
||||
tag string
|
||||
version string
|
||||
noteBody string
|
||||
createdBody string
|
||||
pages map[string]bool
|
||||
requests int
|
||||
writes int
|
||||
@@ -876,6 +900,7 @@ func (state *facadeDeliveryServer) serveHTTP(w http.ResponseWriter, r *http.Requ
|
||||
if payload.Tag != data.tag || payload.Target != data.commit || payload.Name != "Fixture "+data.version {
|
||||
data.t.Errorf("release payload = %#v", payload)
|
||||
}
|
||||
data.createdBody = payload.Body
|
||||
data.pages[data.tag] = true
|
||||
state.writeRelease(w)
|
||||
case "/api/v1/repos/owner/example/releases/10/assets":
|
||||
|
||||
@@ -38,7 +38,7 @@ the agent policy; an intermediate compilation dependency is recorded accurately.
|
||||
| --- | --- | --- |
|
||||
| 1 | A01; publication assertion portion of A19 | Complete — regression failed before the fix and passed afterward; focused publication and reconciliation tests passed. |
|
||||
| 2 | A02, A12: common Git mechanics | Complete — focused Git, candidate, identity, and public build/publication/delivery tests passed; A02 regression evidence follows in Stage 3. |
|
||||
| 3 | A02: source identity regression evidence | Pending |
|
||||
| 3 | A02: source identity regression evidence | Complete — commit, tree, and blob replacement regressions and public publication, build, and delivery cases passed. |
|
||||
| 4 | A03: buffered command teardown | Pending |
|
||||
| 5 | A03, A18: piped lifetime and queued cancellation | Pending |
|
||||
| 6 | A04 | Pending |
|
||||
|
||||
@@ -142,3 +142,52 @@ func TestInspectTaggedSourceReportsDirtyCheckoutAndReadCommitFile(t *testing.T)
|
||||
t.Fatalf("dirty status = %q", source.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommittedReadsIgnoreReplacementObjects(t *testing.T) {
|
||||
for _, kind := range []string{"commit", "tree", "blob"} {
|
||||
t.Run(kind, func(t *testing.T) {
|
||||
fixture := newRemoteFixture(t)
|
||||
original := map[string]string{
|
||||
"commit": fixture.commit,
|
||||
"tree": gitText(t, fixture.work, "rev-parse", "HEAD^{tree}"),
|
||||
"blob": gitText(t, fixture.work, "rev-parse", "HEAD:source.txt"),
|
||||
}
|
||||
writeRepoFile(t, fixture.work, "source.txt", "replacement")
|
||||
gitRun(t, fixture.work, "add", "source.txt")
|
||||
gitRun(t, fixture.work, "commit", "-m", "Replacement")
|
||||
replacement := map[string]string{
|
||||
"commit": gitText(t, fixture.work, "rev-parse", "HEAD"),
|
||||
"tree": gitText(t, fixture.work, "rev-parse", "HEAD^{tree}"),
|
||||
"blob": gitText(t, fixture.work, "rev-parse", "HEAD:source.txt"),
|
||||
}
|
||||
gitRun(t, fixture.work, "reset", "--hard", fixture.commit)
|
||||
gitRun(t, fixture.work, "replace", original[kind], replacement[kind])
|
||||
|
||||
content, err := ReadCommitFile(t.Context(), fixture.work, fixture.commit, "source.txt")
|
||||
if err != nil || string(content) != "candidate" {
|
||||
t.Fatalf("committed content = %q, error = %v", content, err)
|
||||
}
|
||||
entries, err := ReadTree(t.Context(), fixture.work, fixture.commit)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var object string
|
||||
for _, entry := range entries {
|
||||
if entry.Path == "source.txt" {
|
||||
object = entry.ObjectID
|
||||
}
|
||||
}
|
||||
if object != original["blob"] {
|
||||
t.Fatalf("tree blob = %q, want %q", object, original["blob"])
|
||||
}
|
||||
reader := NewBlobReader(t.Context(), fixture.work)
|
||||
content, err = reader.Read(t.Context(), object)
|
||||
if err != nil || string(content) != "candidate" {
|
||||
t.Fatalf("batch content = %q, error = %v", content, err)
|
||||
}
|
||||
if err := reader.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ func TestCandidateOperationsDiscoverGoOnlyWhenLaterWorkNeedsIt(t *testing.T) {
|
||||
func TestPublishPushesOnlyTheCapturedAnnotatedTag(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
gitRun(t, repo.work, "config", "push.recurseSubmodules", "only")
|
||||
gitRun(t, repo.work, "replace", repo.unrelatedCommit, repo.commit)
|
||||
suiteRuns := filepath.Join(t.TempDir(), "suite-runs")
|
||||
t.Setenv("RELEASEKIT_FIXTURE_SUITE_RUNS", suiteRuns)
|
||||
refsBefore := gitText(t, repo.bare, "show-ref", "--heads", "--tags")
|
||||
@@ -162,6 +163,36 @@ func TestPublishPushesOnlyTheCapturedAnnotatedTag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishRejectsReplacementDerivedCheckout(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
writeFile(t, repo.work, "broken.go", "package fixture\nfunc broken(\n")
|
||||
gitRun(t, repo.work, "add", "broken.go")
|
||||
gitRun(t, repo.work, "commit", "-m", "Original source does not compile")
|
||||
original := gitText(t, repo.work, "rev-parse", "HEAD")
|
||||
gitRun(t, repo.work, "-c", "remote.origin.mirror=false", "push", "origin", "HEAD:refs/heads/main")
|
||||
writeFile(t, repo.work, "broken.go", "package fixture\nfunc valid() {}\n")
|
||||
writeFile(t, repo.work, "docs/releases/v1.2.3.md", "# Sample App v1.2.3\n\nReplacement note.\n")
|
||||
gitRun(t, repo.work, "add", "broken.go", "docs/releases/v1.2.3.md")
|
||||
gitRun(t, repo.work, "commit", "-m", "Replacement source")
|
||||
replacement := gitText(t, repo.work, "rev-parse", "HEAD")
|
||||
gitRun(t, repo.work, "reset", "--hard", original)
|
||||
gitRun(t, repo.work, "replace", original, replacement)
|
||||
gitRun(t, repo.work, "reset", "--hard", original)
|
||||
contents, err := os.ReadFile(filepath.Join(repo.work, "broken.go"))
|
||||
if err != nil || !strings.Contains(string(contents), "func valid") {
|
||||
t.Fatalf("replacement checkout = %q, error = %v", contents, err)
|
||||
}
|
||||
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
|
||||
RepositoryDir: repo.work, Product: "Sample App", Version: "v1.2.3",
|
||||
})
|
||||
if err == nil || !strings.Contains(err.Error(), "clean") || result.State != releasekit.PublicationNotAttempted {
|
||||
t.Fatalf("publication = %#v, error = %v; want dirty source rejection", result, err)
|
||||
}
|
||||
if err := exec.Command("git", "-C", repo.bare, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3").Run(); err == nil {
|
||||
t.Fatal("replacement-derived source was published")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishUsesSeparateFullTagsForModulesAtOneCommit(t *testing.T) {
|
||||
repo := newPublishFixture(t)
|
||||
firstDir, secondDir := "integrations/first", "integrations/second"
|
||||
|
||||
Reference in New Issue
Block a user