| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "regexp" |
| 6 | "strings" |
| 7 | ) |
| 8 | |
| 9 | var artifactRe = regexp.MustCompile(`^#\s+(?:macOS|Windows|Linux)?:?\s*(Reasonix-[a-z]+-<arch>[^\s]*)\s+\((.*)\)`) |
| 10 | |
| 11 | var ciJobs = map[string]struct { |
| 12 | class class |
| 13 | owner string |
| 14 | }{ |
| 15 | "ci.yml/desktop": {classKeepBusiness, "aggregate gate, unchanged"}, |
| 16 | "ci.yml/desktop-frontend": {classKeepBusiness, "React gates unchanged"}, |
| 17 | "ci.yml/desktop-browser": {classKeepBusiness, "Playwright browser gates unchanged"}, |
| 18 | "ci.yml/desktop-browser-group": {classKeepBusiness, "Playwright browser gates split into bounded groups"}, |
| 19 | "ci.yml/desktop-prepare": {classKeepBusiness, "go run . -emit-contract drift gate; pnpm workspace root"}, |
| 20 | "ci.yml/desktop-go": {classKeepBusiness, "hostrpc + module tests; no WebKitGTK toolchain"}, |
| 21 | "ci.yml/desktop-go-race": {classKeepBusiness, "desktop module race sweep, split from desktop-go"}, |
| 22 | "ci.yml/desktop-macos": {classKeepBusiness, "Electron packaging smoke"}, |
| 23 | "ci.yml/desktop-windows": {classKeepBusiness, "Electron packaging smoke"}, |
| 24 | "ci.yml/desktop-windows-package": {classKeepBusiness, "Electron installer build, split from the test leg"}, |
| 25 | "ci.yml/desktop-windows-go": {classKeepBusiness, "fail-closed aggregate for Windows desktop Go partitions"}, |
| 26 | "ci.yml/desktop-windows-go-group": {classKeepBusiness, "isolated parallel Windows desktop Go test partitions"}, |
| 27 | "app-memory.yml/app-memory": {classKeepBusiness, "browser memory screening unchanged"}, |
| 28 | "app-memory.yml/prepare": {classKeepBusiness, "browser memory screening unchanged"}, |
| 29 | "app-memory.yml/shard": {classKeepBusiness, "browser memory screening unchanged"}, |
| 30 | "app-memory.yml/changes": {classKeepBusiness, "path filter unchanged"}, |
| 31 | "release-desktop.yml/resolve": {classKeepBusiness, "version/channel resolution unchanged"}, |
| 32 | "release-desktop.yml/orchestration-guard": {classKeepBusiness, "unchanged"}, |
| 33 | "release-desktop.yml/release-gate": {classKeepBusiness, "unchanged"}, |
| 34 | "release-desktop.yml/signing-contract": {classKeepBusiness, "payload list covers the Electron executables and native modules"}, |
| 35 | "release-desktop.yml/cache-guard": {classKeepBusiness, "unchanged"}, |
| 36 | "release-desktop.yml/build": {classKeepBusiness, "desktop-build.sh packages the Electron app with the same NSIS/nfpm/signing steps"}, |
| 37 | "release-desktop.yml/windows-build": {classKeepBusiness, "builds and smoke-tests unsigned x64 and ARM64 packages on native Windows runners before signing"}, |
| 38 | "release-desktop.yml/windows-sign": {classKeepBusiness, "Certum signs native-tested x64 and ARM64 payloads and rebuilt installers on x64"}, |
| 39 | "release-desktop.yml/windows-runtime-acceptance": {classKeepBusiness, "installs and starts the exact signed x64 and ARM64 installers on native runners"}, |
| 40 | "release-desktop.yml/mac-universal-intel": {classKeepBusiness, "validates the exact universal DMG from the build matrix on an Intel runner"}, |
| 41 | "release-desktop.yml/publish": {classKeepBusiness, "manifest, minisign and mirror unchanged"}, |
| 42 | "release-desktop.yml/attest-signing-contract": {classKeepBusiness, "attests the extended payload list"}, |
| 43 | "release-desktop.yml/mirror": {classKeepBusiness, "unchanged"}, |
| 44 | } |
| 45 | |
| 46 | var ciJobRe = regexp.MustCompile(`(?m)^ ([a-z][a-z0-9_-]*):$`) |
| 47 | |
| 48 | var ciTriggerKeys = map[string]bool{"push": true, "pull_request": true, "workflow_dispatch": true, "workflow_call": true, "schedule": true} |
| 49 | |
| 50 | func scanSources(root string, inv *inventory) error { |
| 51 | build, err := readFile(root, "scripts/desktop-build.sh") |
| 52 | if err != nil { |
| 53 | return err |
| 54 | } |
| 55 | for i, line := range strings.Split(build, "\n") { |
| 56 | m := artifactRe.FindStringSubmatch(line) |
| 57 | if m == nil { |
| 58 | continue |
| 59 | } |
| 60 | inv.add(entry{ |
| 61 | Kind: kindArtifact, |
| 62 | Name: m[1], |
| 63 | Detail: m[2], |
| 64 | Location: fmt.Sprintf("scripts/desktop-build.sh:%d", i+1), |
| 65 | Class: classKeepBusiness, |
| 66 | Owner: "same file name and installer identity; Electron payload inside", |
| 67 | }) |
| 68 | } |
| 69 | for _, workflow := range []string{"ci.yml", "app-memory.yml", "release-desktop.yml"} { |
| 70 | text, err := readFile(root, ".github/workflows/"+workflow) |
| 71 | if err != nil { |
| 72 | return err |
| 73 | } |
| 74 | for _, m := range ciJobRe.FindAllStringSubmatch(text, -1) { |
| 75 | job := m[1] |
| 76 | if ciTriggerKeys[job] || (workflow == "ci.yml" && !strings.HasPrefix(job, "desktop")) { |
| 77 | continue |
| 78 | } |
| 79 | key := workflow + "/" + job |
| 80 | e := entry{Kind: kindCIJob, Name: key, Location: ".github/workflows/" + workflow} |
| 81 | if rule, ok := ciJobs[key]; ok { |
| 82 | e.Class, e.Owner = rule.class, rule.owner |
| 83 | } |
| 84 | inv.add(e) |
| 85 | } |
| 86 | } |
| 87 | return nil |
| 88 | } |
| 89 |