// Package releaseprovenance defines the reviewed, tag-bound upstream input // lock consumed by release metadata generation and the isolated signer. package releaseprovenance import ( "encoding/json" "errors" "fmt" "io" "net/url" "os" "regexp" "strings" "time" ) const SchemaVersion = 1 var ( semanticVersionPattern = regexp.MustCompile(`^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$`) blake3Pattern = regexp.MustCompile(`^blake3:[0-9a-f]{64}$`) commitPattern = regexp.MustCompile(`^[0-9a-f]{7,64}$`) ) type Sources struct { MPV string `json:"mpv"` UOSC string `json:"uosc"` ModernZ string `json:"modernz"` MPCQT string `json:"mpc_qt"` IINA string `json:"iina"` WindowsBuildTag string `json:"windows_build_tag"` WindowsTimestamp string `json:"windows_timestamp"` WindowsMPVCommit string `json:"windows_mpv_commit"` WindowsFFmpegHash string `json:"windows_ffmpeg_commit"` } type Artifact struct { ID string `json:"id"` URL string `json:"url"` // DownloadURL optionally serves the reviewed bytes from digest-addressed storage. DownloadURL string `json:"download_url,omitempty"` BLAKE3 string `json:"blake3"` Verification string `json:"verification"` Evidence string `json:"evidence"` } type Lock struct { SchemaVersion int `json:"schema_version"` ReleaseVersion string `json:"release_version"` ReviewedAt string `json:"reviewed_at"` Reviewer string `json:"reviewer"` Sources Sources `json:"sources"` Artifacts []Artifact `json:"artifacts"` byURL map[string]Artifact } func Load(path, expectedReleaseVersion string) (*Lock, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read release provenance lock: %w", err) } decoder := json.NewDecoder(strings.NewReader(string(data))) decoder.DisallowUnknownFields() var lock Lock if err := decoder.Decode(&lock); err != nil { return nil, fmt.Errorf("decode release provenance lock: %w", err) } var extra any if err := decoder.Decode(&extra); !errors.Is(err, io.EOF) { if err == nil { return nil, fmt.Errorf("decode release provenance lock: multiple JSON values") } return nil, fmt.Errorf("decode release provenance lock trailer: %w", err) } if err := lock.Validate(expectedReleaseVersion); err != nil { return nil, err } return &lock, nil } func (lock *Lock) Validate(expectedReleaseVersion string) error { var problems []string if lock.SchemaVersion != SchemaVersion { problems = append(problems, fmt.Sprintf("schema_version is %d, want %d", lock.SchemaVersion, SchemaVersion)) } if !semanticVersionPattern.MatchString(lock.ReleaseVersion) { problems = append(problems, fmt.Sprintf("release_version %q is not semantic", lock.ReleaseVersion)) } if expectedReleaseVersion != "" && lock.ReleaseVersion != strings.TrimPrefix(expectedReleaseVersion, "v") { problems = append(problems, fmt.Sprintf("release_version %q does not match tag version %q", lock.ReleaseVersion, strings.TrimPrefix(expectedReleaseVersion, "v"))) } if _, err := time.Parse(time.RFC3339, lock.ReviewedAt); err != nil { problems = append(problems, "reviewed_at is not RFC3339") } if strings.TrimSpace(lock.Reviewer) == "" { problems = append(problems, "reviewer is empty") } for name, version := range map[string]string{ "mpv": lock.Sources.MPV, "uosc": lock.Sources.UOSC, "modernz": lock.Sources.ModernZ, "mpc_qt": lock.Sources.MPCQT, "iina": lock.Sources.IINA, } { if strings.TrimSpace(version) == "" { problems = append(problems, name+" source version is empty") } } if lock.Sources.WindowsBuildTag == "" || len(lock.Sources.WindowsTimestamp) != 8 || !commitPattern.MatchString(lock.Sources.WindowsMPVCommit) || !commitPattern.MatchString(lock.Sources.WindowsFFmpegHash) { problems = append(problems, "Windows build tag/timestamp/commit evidence is incomplete") } if len(lock.Artifacts) == 0 { problems = append(problems, "artifacts is empty") } lock.byURL = make(map[string]Artifact, len(lock.Artifacts)) seenIDs := make(map[string]bool, len(lock.Artifacts)) for index, artifact := range lock.Artifacts { name := fmt.Sprintf("artifact %d", index) if strings.TrimSpace(artifact.ID) == "" || seenIDs[artifact.ID] { problems = append(problems, name+" has an empty or duplicate ID") } seenIDs[artifact.ID] = true parsed, err := url.Parse(artifact.URL) if err != nil || parsed.Scheme != "https" || parsed.Host == "" { problems = append(problems, name+" URL is not absolute HTTPS") } if _, duplicate := lock.byURL[artifact.URL]; duplicate { problems = append(problems, name+" duplicates another artifact URL") } lock.byURL[artifact.URL] = artifact if artifact.DownloadURL != "" { mirror, err := url.Parse(artifact.DownloadURL) if err != nil || mirror.Scheme != "https" || mirror.Host == "" || mirror.User != nil || mirror.RawQuery != "" || mirror.Fragment != "" || !strings.Contains(mirror.Path, "/"+strings.TrimPrefix(artifact.BLAKE3, "blake3:")+"/") { problems = append(problems, name+" download_url must be HTTPS with the reviewed BLAKE3 digest as a path segment") } } if !blake3Pattern.MatchString(artifact.BLAKE3) { problems = append(problems, name+" BLAKE3 digest is invalid") } if strings.TrimSpace(artifact.Verification) == "" || strings.TrimSpace(artifact.Evidence) == "" { problems = append(problems, name+" lacks verification/evidence") } } if len(problems) > 0 { return fmt.Errorf("release provenance validation failed:\n - %s", strings.Join(problems, "\n - ")) } return nil } func (lock *Lock) ArtifactForURL(artifactURL string) (Artifact, bool) { if lock == nil { return Artifact{}, false } if lock.byURL == nil { _ = lock.Validate(lock.ReleaseVersion) } artifact, ok := lock.byURL[artifactURL] return artifact, ok } func (lock *Lock) Versions() map[string]string { return map[string]string{ "mpv": lock.Sources.MPV, "uosc": lock.Sources.UOSC, "modernz": lock.Sources.ModernZ, "mpcqt": lock.Sources.MPCQT, "iina": lock.Sources.IINA, "win_full_tag": lock.Sources.WindowsBuildTag, "win_mpv_hash": lock.Sources.WindowsMPVCommit, "win_ffmpeg_hash": lock.Sources.WindowsFFmpegHash, } }