Consolidate artifact declarations

This commit is contained in:
2026-10-06 17:29:41 +00:00
parent 3e9b5c1b99
commit 0eec4a30ed
9 changed files with 175 additions and 76 deletions

View File

@@ -11,6 +11,7 @@ import (
"path/filepath"
"strings"
"gitea.maximumdirect.net/eric/ReleaseKit/internal/artifact"
"gitea.maximumdirect.net/eric/ReleaseKit/internal/versioncontract"
)
@@ -149,7 +150,7 @@ func validateBuildReceipt(receipt BuildReceipt, verifyFiles bool) error {
if !validCommitID(receipt.CandidateCommit) {
return errors.New("build receipt has invalid candidate commit")
}
if receipt.MainPackage == "" || !safeReceiptComponent(receipt.BinaryName) || receipt.Compiler == "" {
if receipt.MainPackage == "" || !artifact.ValidComponent(receipt.BinaryName) || receipt.Compiler == "" {
return errors.New("build receipt is missing build identity")
}
if len(receipt.Targets) == 0 || len(receipt.Artifacts) != len(receipt.Targets) {
@@ -157,21 +158,29 @@ func validateBuildReceipt(receipt BuildReceipt, verifyFiles bool) error {
}
seenTargets := make(map[ReceiptTarget]bool, len(receipt.Targets))
seenArtifacts := make(map[ReceiptTarget]bool, len(receipt.Artifacts))
targets := make([]artifact.Target, 0, len(receipt.Targets))
for _, target := range receipt.Targets {
if !safeReceiptComponent(target.OS) || !safeReceiptComponent(target.Arch) {
if !artifact.ValidComponent(target.OS) || !artifact.ValidComponent(target.Arch) {
return fmt.Errorf("build receipt has unsafe target %q/%q", target.OS, target.Arch)
}
if seenTargets[target] {
return fmt.Errorf("build receipt repeats target %s/%s", target.OS, target.Arch)
}
seenTargets[target] = true
targets = append(targets, artifact.Target{OS: target.OS, Arch: target.Arch})
}
declarations := artifact.ExpectedBuild(receipt.BinaryName, receipt.Version, targets)
wantByTarget := make(map[ReceiptTarget]string, len(declarations))
for _, declaration := range declarations {
target := ReceiptTarget{OS: declaration.Target.OS, Arch: declaration.Target.Arch}
wantByTarget[target] = declaration.Filename
}
for _, artifact := range receipt.Artifacts {
if !seenTargets[artifact.Target] || seenArtifacts[artifact.Target] {
return fmt.Errorf("build receipt has an unexpected artifact target %s/%s", artifact.Target.OS, artifact.Target.Arch)
}
seenArtifacts[artifact.Target] = true
wantName := receiptArtifactFilename(receipt.BinaryName, receipt.Version, artifact.Target)
wantName := wantByTarget[artifact.Target]
if artifact.Filename != wantName || filepath.Base(artifact.Filename) != artifact.Filename {
return fmt.Errorf("build receipt has invalid artifact filename %q", artifact.Filename)
}
@@ -215,34 +224,22 @@ func verifyReceiptArtifact(artifact ReceiptArtifact) error {
}
func normalizeReceiptTargets(targets []string) []ReceiptTarget {
seen := make(map[ReceiptTarget]bool, len(targets))
result := make([]ReceiptTarget, 0, len(targets))
parsed := make([]artifact.Target, 0, len(targets))
for _, value := range targets {
goos, goarch, ok := strings.Cut(value, "/")
if !ok {
continue
}
target := ReceiptTarget{OS: goos, Arch: goarch}
if !seen[target] {
seen[target] = true
result = append(result, target)
}
parsed = append(parsed, artifact.Target{OS: goos, Arch: goarch})
}
normalized := artifact.NormalizeTargets(parsed)
result := make([]ReceiptTarget, 0, len(normalized))
for _, target := range normalized {
result = append(result, ReceiptTarget{OS: target.OS, Arch: target.Arch})
}
return result
}
func receiptArtifactFilename(binaryName, version string, target ReceiptTarget) string {
filename := fmt.Sprintf("%s-%s-%s-%s", binaryName, version, target.OS, target.Arch)
if target.OS == "windows" {
filename += ".exe"
}
return filename
}
func safeReceiptComponent(value string) bool {
return value != "" && !strings.ContainsAny(value, "/\\\r\n")
}
func validCommitID(value string) bool {
if len(value) != 40 && len(value) != 64 {
return false