diff --git a/docs/compatibility.md b/docs/compatibility.md index 6cf6cb7f..142ca390 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -682,7 +682,7 @@ Pre conditions use the status and action-scoped environment available when prepa ### Checkout action -**🟡 Supported subset.** The final v1.2.0, v2.8.0, and v3.7.0 release commits are admitted exactly. Resolved commits in the v4-and-later range of the static [`actions/checkout` upstream `main` snapshot](https://github.com/actions/checkout/tree/f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a) are also admitted. The following known releases remain admitted even when their commits aren't reachable from that snapshot: +**🟡 Supported subset.** Immutable commits captured from frozen upstream tags, `main`, `master`, and `releases/v1` through `releases/v6` snapshots are admitted. The snapshot includes historical development and release commits across v1 through v7. These known releases identify the principal contracts: | Release | Commit | | --- | --- | @@ -695,34 +695,38 @@ Pre conditions use the status and action-scoped environment available when prepa | v7.0.0 corpus pin | [`9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0`](https://github.com/actions/checkout/tree/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) | | v7.0.1 | [`3d3c42e5aac5ba805825da76410c181273ba90b1`](https://github.com/actions/checkout/tree/3d3c42e5aac5ba805825da76410c181273ba90b1) | -Mutable refs work only while they resolve to the upstream `main` snapshot or a known release above. Every admitted commit uses the native adapter; the upstream JavaScript doesn't run. Each admitted release accepts only the inputs it declares, so earlier releases reject later inputs. Other pre-v3.7.0 commits and unknown commits are unsupported. Compilation emits `W_CHECKOUT_LEGACY_RELEASE` for v1.2.0 and v2.8.0 to nudge an upgrade to v4 or later. Maintainers can update the v4-and-later snapshot with `go generate ./internal/action/integration`; this doesn't widen release admission. +Mutable refs work only while they resolve to a commit in the frozen snapshots. Every admitted commit uses the native adapter; the upstream JavaScript doesn't run. Each commit retains the inputs, full-history default, and outputs declared by its upstream contract. For example, early v2 commits reject later v2 inputs, and v4.0 and v4.1 commits don't expose the `ref` and `commit` outputs. Commits absent from the snapshots and manifests with unsupported output contracts remain unsupported. Compilation emits `W_CHECKOUT_LEGACY_RELEASE` for v1.2.0 and v2.8.0 to nudge an upgrade to v4 or later. + +Maintainers can refresh the frozen refs and per-commit profiles with `go generate ./internal/action/integration`. Regeneration admits only commits reachable from the selected upstream tags and branches at that time; it doesn't blanket-admit future commits. The adapter checks out a detached commit or static branch from the event repository at the workspace root or a clean top-level directory. It uses Buildkite repository-provider Git credentials when the job provides them; otherwise, it fetches anonymously. Credentials are scoped to each fetch command and verified submodule fetch command and are never persisted. +An explicit input is accepted only when the snapshotted manifest for that commit declares it. The following value restrictions then apply: + | Input | Supported values | | --- | --- | | `repository` | Omitted, or the event `owner/repo`. | | `ref` | Omitted, empty, a lowercase 40-hex commit, or a static branch in the event repository. A direct `github.sha` or `needs..outputs.` expression must resolve at runtime to the exact event SHA. | | `token` | Omitted only. | -| `ssh-key`, `ssh-known-hosts` | v2.8.0 and later: omitted or empty. v1.2.0: omitted. | -| `ssh-strict` | v2.8.0 and later: omitted or `true`. v1.2.0: omitted. | -| `ssh-user` | v4 and later: omitted or `git`. Earlier releases: omitted. | -| `persist-credentials` | v2.8.0 and later: omitted or `false`. v1.2.0: omitted. | +| `ssh-key`, `ssh-known-hosts` | When declared by the commit: omitted or empty. Otherwise omitted. | +| `ssh-strict` | When declared by the commit: omitted or `true`. Otherwise omitted. | +| `ssh-user` | When declared by the commit: omitted or `git`. Otherwise omitted. | +| `persist-credentials` | When declared by the commit: omitted or `false`. Otherwise omitted. | | `path` | Omitted, empty, or one clean non-`.git` top-level workspace directory. | | `clean` | Omitted or `true`; the root workspace or selected path must be empty or absent. | -| `filter` | v4 and later: omitted or empty. Earlier releases: omitted. | -| `sparse-checkout` | v3.7.0 and later: omitted or empty. Earlier releases: omitted. | -| `sparse-checkout-cone-mode` | v3.7.0 and later: omitted or `true`. Earlier releases: omitted. | -| `fetch-depth` | Omitted or a nonnegative integer; `0` fetches full history. v1.2.0 fetches full history when omitted. | -| `fetch-tags` | v3.7.0 and later: omitted, `true`, or `false`. Earlier releases: omitted. | -| `show-progress` | v4 and later: omitted, `true`, or `false`. Earlier releases: omitted. | +| `filter` | When declared by the commit: omitted or empty. Otherwise omitted. | +| `sparse-checkout` | When declared by the commit: omitted or empty. Otherwise omitted. | +| `sparse-checkout-cone-mode` | When declared by the commit: omitted or `true`. Otherwise omitted. | +| `fetch-depth` | Omitted or a nonnegative integer; `0` fetches full history. Historical runner-plugin commits fetch full history when omitted. | +| `fetch-tags` | When declared by the commit: omitted, `true`, or `false`. Otherwise omitted. | +| `show-progress` | When declared by the commit: omitted, `true`, or `false`. Otherwise omitted. | | `lfs` | Omitted or `false`. | | `submodules` | Omitted, `false`, `true`, or `recursive`; whitespace is trimmed and casing is ignored. | -| `set-safe-directory` | v2.8.0 and later: omitted or `true`. v1.2.0: omitted. | -| `github-server-url` | v3.7.0 and later: omitted, empty, or `https://github.com`. Earlier releases: omitted. | -| `allow-unsafe-pr-checkout` | v2.8.0 and later: omitted or `false`. v1.2.0: omitted. | +| `set-safe-directory` | When declared by the commit: omitted or `true`. Otherwise omitted. | +| `github-server-url` | When declared by the commit: omitted, empty, or `https://github.com`. Otherwise omitted. | +| `allow-unsafe-pr-checkout` | When declared by the commit: omitted or `false`. Otherwise omitted. | -The `ref` and `commit` outputs are unavailable for v1.2.0, v2.8.0, and v3.7.0. Upstream added them in v4.2.0. +The `ref` and `commit` outputs are available only for commits whose action manifest declares them. Upstream added both outputs in v4.2.0. The `false` value and omission do not run submodule commands. The `true` value runs native Git for direct children, and `recursive` includes nested children. Relative URLs and `fetch-depth` follow native Git behavior. Public and private GitHub submodules are supported under the job's repository access; external HTTPS submodules are anonymous. `git@github.com:` URLs are rewritten to HTTPS. Other SSH and non-HTTPS transports are unsupported. diff --git a/internal/action/integration/checkout.go b/internal/action/integration/checkout.go index 42c1e09c..390a0a1c 100644 --- a/internal/action/integration/checkout.go +++ b/internal/action/integration/checkout.go @@ -1,4 +1,4 @@ -//go:generate ../../../scripts/update-checkout-main-commits +//go:generate go run ./cmd/generate-checkout-profiles package integration @@ -12,10 +12,8 @@ import ( ) const ( - // CheckoutV1Commit through CheckoutV7Commit are the current audited release - // implementations. CheckoutV1Commit, CheckoutV2Commit, and CheckoutV3Commit - // are the final v1, v2, and v3 releases and are admitted exactly rather - // than extending the v4-and-later main-branch snapshot. + // CheckoutV1Commit through CheckoutV7Commit identify principal release + // contracts within the broader frozen upstream snapshots. // CheckoutV7InitialCommit is retained because it is pinned by the OSS // compatibility corpus; its later v7.0.1 changes do not affect the adapter's // bounded exact-event-SHA operation. @@ -40,47 +38,31 @@ var checkoutCommits = map[string]string{ CheckoutV7Commit: "v7.0.1", } -// checkoutInputIntroduced records the earliest admitted release generation -// declaring each version-gated input. Inputs absent from this map are declared -// by every admitted release. -var checkoutInputIntroduced = map[string]int{ - "ssh-key": 2, - "ssh-known-hosts": 2, - "ssh-strict": 2, - "persist-credentials": 2, - "set-safe-directory": 2, - "allow-unsafe-pr-checkout": 2, - "fetch-tags": 3, - "sparse-checkout": 3, - "sparse-checkout-cone-mode": 3, - "github-server-url": 3, - "filter": 4, - "show-progress": 4, - "ssh-user": 4, +// checkoutContract records the adapter-visible contract declared by one +// immutable upstream action manifest. +type checkoutContract struct { + // inputs is a sorted, comma-separated set of names declared by the + // immutable upstream action manifest. + inputs string + fullHistory bool + refOutput, commitOutput bool } -func checkoutGeneration(commit string) int { - switch commit { - case CheckoutV1Commit: - return 1 - case CheckoutV2Commit: - return 2 - case CheckoutV3Commit: - return 3 - } - return 4 +func (c checkoutContract) declaresInput(name string) bool { + return strings.Contains(","+c.inputs+",", ","+name+",") } // CheckoutSupportsOutputs reports whether the admitted release declares the // ref and commit outputs, added upstream in v4.2.0. func CheckoutSupportsOutputs(commit string) bool { - return checkoutGeneration(commit) >= 4 + contract, ok := checkoutCommitContracts[commit] + return ok && contract.refOutput && contract.commitOutput } // CheckoutDefaultsToFullHistory reports whether the admitted release fetched // full history when fetch-depth was omitted, as v1's runner plugin did. func CheckoutDefaultsToFullHistory(commit string) bool { - return commit == CheckoutV1Commit + return checkoutCommitContracts[commit].fullHistory } // LegacyCheckoutRelease reports the admitted release label for the v1 and v2 @@ -92,15 +74,12 @@ func LegacyCheckoutRelease(commit string) (string, bool) { return "", false } -// validateCheckoutCommit admits known releases and a static snapshot of -// commits reachable from upstream main. Mutable references are resolved before -// this check, so changes after the snapshot are rejected until regeneration. +// validateCheckoutCommit admits commits with contracts captured from frozen +// upstream release and main snapshots. Mutable references are resolved before +// this check, so changes after the snapshots are rejected until regeneration. func validateCheckoutCommit(commit string) error { - if _, ok := checkoutCommits[commit]; ok { - return nil - } - if _, ok := checkoutMainCommits[commit]; !ok { - supported := append(sortedCheckoutCommits(), "upstream main snapshot ("+checkoutMainSnapshotCommit+")") + if _, ok := checkoutCommitContracts[commit]; !ok { + supported := append(sortedCheckoutCommits(), "frozen upstream release and main snapshots (main "+checkoutMainSnapshotCommit+")") return versionError("actions/checkout", "native adapter", commit, supported) } return nil @@ -118,9 +97,12 @@ func sortedCheckoutCommits() []string { // ValidateCheckoutInputs enforces the release-specific input contract // implemented by the tokenless event-repository checkout adapter. func ValidateCheckoutInputs(commit string, inputs map[string]string, repository, sha string) error { + contract, ok := checkoutCommitContracts[commit] + if !ok { + return versionError("actions/checkout", "native adapter", commit, append(sortedCheckoutCommits(), "frozen upstream release and main snapshots (main "+checkoutMainSnapshotCommit+")")) + } names := sortedNames(inputs) seen := make(map[string]bool, len(names)) - generation := checkoutGeneration(commit) for _, name := range names { value := inputs[name] normalized := strings.ToLower(name) @@ -128,7 +110,7 @@ func ValidateCheckoutInputs(commit string, inputs map[string]string, repository, return fmt.Errorf("duplicate case-insensitive input %q is unsupported", name) } seen[normalized] = true - if checkoutInputIntroduced[normalized] > generation { + if !contract.declaresInput(normalized) { return fmt.Errorf("explicit input %q is unsupported by this actions/checkout release", name) } switch normalized { diff --git a/internal/action/integration/checkout_main_commits_generated.go b/internal/action/integration/checkout_main_commits_generated.go deleted file mode 100644 index 1bc0b016..00000000 --- a/internal/action/integration/checkout_main_commits_generated.go +++ /dev/null @@ -1,103 +0,0 @@ -// Code generated by scripts/update-checkout-main-commits; DO NOT EDIT. - -package integration - -const checkoutMainSnapshotCommit = "f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a" - -var checkoutMainCommits = map[string]struct{}{ - "009b9ae9e446ad8d9b8c809870b0fbcc5e03573e": {}, - "033fa0dc0b82693d8986f1016a0ec2c5e7d9cbb1": {}, - "064fe7f3312418007dea2b49a19844a9ee378f49": {}, - "069c6959146423d11cd0184e6accf28f9d45f06e": {}, - "08c6903cd8c0fde910a37f88322edcfb5dd907a8": {}, - "08eba0b27e820071cde6df949e0beb9ba4906955": {}, - "09d2acae674a48949e3602304ab46fd20ae0c42f": {}, - "0ad4b8fadaa221de15dcec353f45205ec38ea70b": {}, - "0c366fd6a839edf440554fa01a7085ccba70ac98": {}, - "0f9f3aa320cb53abeb534aeb54048075d9697a0e": {}, - "1044a6dea927916f2c38ba5aeffbc0a847b1221a": {}, - "11bd71901bbe5b1630ceea73d27597364c9af683": {}, - "12cd2235efa0937479335606d7c3ac9f6c0973b1": {}, - "130a169078a413d3a5246a393625e8e742f387f6": {}, - "163217dfcd28294438ea1c1c149cfaf66eec283e": {}, - "1af3b93b6815bc44a9784bd300feb67ff0d1eeb3": {}, - "1cce3390c2bfda521930d01229c073c7ff920824": {}, - "1d96c772d19495a3b5c517cd2bc0cb401ea0529f": {}, - "24ed1a352802348c9e4e8d13de9177fb95b537ba": {}, - "2650dbd060003e3b5ae211e4358852f336b682a7": {}, - "28802689a136bfcdb721715abd713740beecbe07": {}, - "2d7d9f7ff5b310f983d059b68785b3c74d8b8edd": {}, - "37b082107ba410260a3aaddf93122e04801ce631": {}, - "3b9b8c884f6b4bb4d5be2779c26374abadae0871": {}, - "3d3c42e5aac5ba805825da76410c181273ba90b1": {}, - "3df4ab11eba7bda6032a0b82a6bb43b11571feac": {}, - "3f603f6d5e9f40714f97b2f017aa0df2a443192a": {}, - "43045ae669be728bd34ed56fcd1a230c0dc4d8e2": {}, - "44c2b7a8a4ea60a981eaca3cf939b5f4305c123b": {}, - "473055ba18d6d2da209cd46110aadb9275e3194e": {}, - "4f1f4aec02e41874fa0262ea8ff5172d7978ad1e": {}, - "537c7ef99cef6e5ddb5e7ff5d16d14510503801d": {}, - "556e4c3cb0b8b54b734286d5439adadcb0a8cb92": {}, - "5de26ee9b11f6ffa02406edecc0e750256af18b1": {}, - "62661c4e71a304b2823ed026347b8d34c3eac541": {}, - "631c7dc4f80f88219c5ee78fee08c6b62fac8da1": {}, - "631c942040754b6e095e929c1677c07e10ed4f87": {}, - "692973e3d937129bcbf40652eb9f2f61becf3332": {}, - "6b42224f41ee5dfe5395e27c8b2746f1f9955030": {}, - "6ccd57f4c5d15bdc2fef309bd9fb6cc9db2ef1c6": {}, - "6d193bf28034eafb982f37bd894289fe649468fc": {}, - "71cf2267d89c5cb81562390fa70a37fa40b1305e": {}, - "72f2cec99f417b1a1c5e2e88945068983b7965f9": {}, - "79102f25032f3f70eb9d8386b1451cf1ef55902d": {}, - "7cdaf2fbc075e6f3b9ca94cfd6cec5adc8a75622": {}, - "7d09575332117a40b46e5e020664df234cd416f3": {}, - "8410ad0602e1e429cee44a835ae9f77f654a6694": {}, - "8459bc0c7e3759cdf591f513d9f141a95fef0a8f": {}, - "8530928916aaef40f59e6f221989ccb31f5759e7": {}, - "85e6279cec87321a52edac9c87bce653a07cf6c2": {}, - "8ade135a41bc03ea155e62e844d188df1ea18608": {}, - "8b5e8b768746b50394015010d25e690bfab9dfbc": {}, - "8e8c483db84b4bee98b60c0593521ed34d9990e8": {}, - "8eb1f6a495037164bea451156472f35fdd6bafc0": {}, - "8edcb1bdb4e267140fa742c62e395cd74f332709": {}, - "900f2210b1d28bbbd0bd22d17926b9e224e8f231": {}, - "97a652b80035363df47baee5031ec8670b8878ac": {}, - "9839dc14a02ddc6b6995e69eb3ecb98132fc8b6b": {}, - "9a9194f87191a7e9055e3e9b95b8cfb13023bb08": {}, - "9b4c13b0bfa31b4514c14f74b5a166c2708f43c6": {}, - "9bb56186c3b09b4f86b1c65136769dd318469633": {}, - "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0": {}, - "9c1e94e0ad997d618b6113a2171b055037589028": {}, - "9f265659d3bb64ab1440b03b12f4d47a24320917": {}, - "a5ac7e51b41094c92402da3b24376905380afc29": {}, - "aadec899646c8e0f34c52d9219c2faac36626b55": {}, - "b17fe1e4d59a9d1d95a7aead5e6fcd13e50939a5": {}, - "b1ec3021b8fa02164da82ca1557d017d83b0e179": {}, - "b32f140b0c872d58512e0a66172253c302617b90": {}, - "b4ffde65f46336ab88eb53be808477a3936bae11": {}, - "b6849436894e144dbce29d7d7fda2ae3bf9d8365": {}, - "b80ff79f1755d06ba70441c368a6fe801f5f3a62": {}, - "b9e0990d219a03df7633c93f6f005a8fecbcab22": {}, - "ba097532fb203f7e88c9c3c0b899b49469908a92": {}, - "c2d88d3ecc89a9ef08eebf45d9637801dcee7eb5": {}, - "c533a0a4cfc4962971818edcfac47a2899e69799": {}, - "cbb722410c2e876e24abbe8de2cc27693e501dcb": {}, - "cd7d8d697e10461458bc61a30d094dc601a8b017": {}, - "d632683dd7b4114ad314bca15554477dd762a938": {}, - "d914b262ffc244530a203ab40decab34c3abf34d": {}, - "db0cee9a514becbbd4a101a5fbbbf47865ee316c": {}, - "dd960bd3c3f080561a1810e32349ac211ecec7d4": {}, - "de0fac2e4500dabe0009e67214ff5f5447ce83dd": {}, - "de5a000abf73b6f4965bd1bcdf8f8d94a56ea815": {}, - "df0bcddf6d6823307c716b56a7ef9c3b25078874": {}, - "df4cb1c069e1874edd31b4311f1884172cec0e10": {}, - "e3d2460bbb42d7710191569f88069044cfb9d8cf": {}, - "e8cb398be4a550817e382abf69e4c12c76fce1f2": {}, - "e8d4307400f9427dba7cb98e488d6ab85f1cec5f": {}, - "eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871": {}, - "f0282184c7ce73ab54c7e4ab5a617122602e575f": {}, - "f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a": {}, - "f9e715a95fcd1f9253f77dd28f11e88d2d6460c7": {}, - "fd084cde189b7b76ec305d52e27be545a0172823": {}, - "ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493": {}, -} diff --git a/internal/action/integration/checkout_profiles_generated.go b/internal/action/integration/checkout_profiles_generated.go new file mode 100644 index 00000000..d00598f8 --- /dev/null +++ b/internal/action/integration/checkout_profiles_generated.go @@ -0,0 +1,292 @@ +// Code generated by internal/action/integration/cmd/generate-checkout-profiles; DO NOT EDIT. + +package integration + +const checkoutMainSnapshotCommit = "f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a" + +var checkoutSnapshotTips = map[string]string{ + "main": "f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a", + "master": "61b9e3751b92087fd0b06925ba6dd6314e06f089", + "releases/v1": "0b496e91ec7ae4428c3ed2eeb4c3a40df431f2cc", + "releases/v2": "0717577d45739eb3c851188b29f50ed6c0b2194e", + "releases/v3": "a37ce9120846195fa4ece8f58b268e6043cb2f26", + "releases/v4": "11d5960a326750d5838078e36cf38b85af677262", + "releases/v5": "fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09", + "releases/v6": "d23441a48e516b6c34aea4fa41551a30e30af803", +} + +var ( + checkoutProfile01 = checkoutContract{inputs: "allow-unsafe-pr-checkout,clean,fetch-depth,fetch-tags,filter,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,show-progress,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,ssh-user,submodules,token", fullHistory: false, refOutput: true, commitOutput: true} + checkoutProfile02 = checkoutContract{inputs: "allow-unsafe-pr-checkout,clean,fetch-depth,fetch-tags,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile03 = checkoutContract{inputs: "allow-unsafe-pr-checkout,clean,fetch-depth,lfs,path,persist-credentials,ref,repository,set-safe-directory,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile04 = checkoutContract{inputs: "clean,fetch-depth,fetch-tags,filter,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,show-progress,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,ssh-user,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile05 = checkoutContract{inputs: "clean,fetch-depth,fetch-tags,filter,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,show-progress,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,ssh-user,submodules,token", fullHistory: false, refOutput: true, commitOutput: true} + checkoutProfile06 = checkoutContract{inputs: "clean,fetch-depth,fetch-tags,filter,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,show-progress,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile07 = checkoutContract{inputs: "clean,fetch-depth,fetch-tags,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,show-progress,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile08 = checkoutContract{inputs: "clean,fetch-depth,fetch-tags,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile09 = checkoutContract{inputs: "clean,fetch-depth,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,sparse-checkout,sparse-checkout-cone-mode,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile10 = checkoutContract{inputs: "clean,fetch-depth,github-server-url,lfs,path,persist-credentials,ref,repository,set-safe-directory,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile11 = checkoutContract{inputs: "clean,fetch-depth,lfs,path,persist-credentials,ref,repository,set-safe-directory,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile12 = checkoutContract{inputs: "clean,fetch-depth,lfs,path,persist-credentials,ref,repository,ssh-key,ssh-known-hosts,ssh-strict,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile13 = checkoutContract{inputs: "clean,fetch-depth,lfs,path,persist-credentials,ref,repository,submodules,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile14 = checkoutContract{inputs: "clean,fetch-depth,lfs,path,persist-credentials,ref,repository,token", fullHistory: false, refOutput: false, commitOutput: false} + checkoutProfile15 = checkoutContract{inputs: "clean,fetch-depth,lfs,path,ref,repository,submodules,token", fullHistory: true, refOutput: false, commitOutput: false} + checkoutProfile16 = checkoutContract{inputs: "clean,fetch-depth,lfs,path,ref,repository,token", fullHistory: false, refOutput: false, commitOutput: false} +) + +var checkoutCommitContracts = map[string]checkoutContract{ + "009b9ae9e446ad8d9b8c809870b0fbcc5e03573e": checkoutProfile05, + "00a3be89340a3ce8d704f82f44a5e7f9e3a84dfe": checkoutProfile12, + "01a434328acfaec94cbfc1cd07b3373e4693d132": checkoutProfile16, + "01aecccf739ca6ff86c0539fbc67a7a5007bbc81": checkoutProfile12, + "0299a0d2b67d48224ce047d03c69693b37fe77fe": checkoutProfile12, + "033fa0dc0b82693d8986f1016a0ec2c5e7d9cbb1": checkoutProfile05, + "06218e4404b044c23590a921fa858fb632a41afe": checkoutProfile14, + "064fe7f3312418007dea2b49a19844a9ee378f49": checkoutProfile05, + "069c6959146423d11cd0184e6accf28f9d45f06e": checkoutProfile05, + "0717577d45739eb3c851188b29f50ed6c0b2194e": checkoutProfile03, + "08c6903cd8c0fde910a37f88322edcfb5dd907a8": checkoutProfile05, + "08eba0b27e820071cde6df949e0beb9ba4906955": checkoutProfile05, + "090d9c9dfda6bb13508d978c6be93801de84f967": checkoutProfile14, + "0963d3b35f4826b619c2436e1bdce37c147daeaf": checkoutProfile15, + "096e9277500008410ac4dd98a7bb0d9052330de8": checkoutProfile14, + "09d2acae674a48949e3602304ab46fd20ae0c42f": checkoutProfile05, + "0ad4b8fadaa221de15dcec353f45205ec38ea70b": checkoutProfile04, + "0b496e91ec7ae4428c3ed2eeb4c3a40df431f2cc": checkoutProfile15, + "0c366fd6a839edf440554fa01a7085ccba70ac98": checkoutProfile05, + "0f9f3aa320cb53abeb534aeb54048075d9697a0e": checkoutProfile01, + "0ffe6f9c5599e73776da5b7f113e994bc0a76ede": checkoutProfile11, + "1044a6dea927916f2c38ba5aeffbc0a847b1221a": checkoutProfile01, + "11bd71901bbe5b1630ceea73d27597364c9af683": checkoutProfile05, + "11d5960a326750d5838078e36cf38b85af677262": checkoutProfile01, + "12cd2235efa0937479335606d7c3ac9f6c0973b1": checkoutProfile01, + "130a169078a413d3a5246a393625e8e742f387f6": checkoutProfile01, + "1433f62caac9c18949f9a498f6f28c05388ea443": checkoutProfile12, + "163217dfcd28294438ea1c1c149cfaf66eec283e": checkoutProfile05, + "1af3b93b6815bc44a9784bd300feb67ff0d1eeb3": checkoutProfile05, + "1cce3390c2bfda521930d01229c073c7ff920824": checkoutProfile05, + "1d96c772d19495a3b5c517cd2bc0cb401ea0529f": checkoutProfile04, + "1e204e9a9253d643386038d443f96446fa156a97": checkoutProfile12, + "1e31de5234b9f8995739874a8ce0492dc87873e2": checkoutProfile07, + "1f9a0c22da41e6ebfa534300ef656657ea2c6707": checkoutProfile10, + "2036a08e25fa78bbd946711a407b529a0a1204bf": checkoutProfile12, + "204620207c9669dc859681b83d09302c7deb97ce": checkoutProfile14, + "21dc310f1948a06cc989491cb1b4a86777f22918": checkoutProfile12, + "230611dbd0eb52da1e1f4f7bc8bb0c3a339fc8b7": checkoutProfile12, + "24cb9080177205b6e8c946b17badbe402adc938f": checkoutProfile10, + "24ed1a352802348c9e4e8d13de9177fb95b537ba": checkoutProfile04, + "2541b1294d2704b0964813337f33b291d3f8596b": checkoutProfile11, + "25a956c84d5dd820d28caab9f86b8d183aeeff3d": checkoutProfile12, + "262cdb5f1c2e469ea6a6810758c890b43e82bd2c": checkoutProfile03, + "2650dbd060003e3b5ae211e4358852f336b682a7": checkoutProfile06, + "26d48e8ea150211a9bc3b1f0c20448599687d926": checkoutProfile10, + "27135e314dd1818f797af1db9dae03a9f045786b": checkoutProfile10, + "28802689a136bfcdb721715abd713740beecbe07": checkoutProfile01, + "28c7f3d2b5162b5ddd3dfd9a45aa55eaf396478b": checkoutProfile12, + "299dd5064ede81803aeb1ce63fee4e150d9ae5f1": checkoutProfile14, + "2bd2911be9963da3ff84b7b09a28872059aa0564": checkoutProfile12, + "2d1c1198e79c30cca5c3957b1e3b65ce95b5356e": checkoutProfile12, + "2d7d9f7ff5b310f983d059b68785b3c74d8b8edd": checkoutProfile04, + "2ff2fbdea48a8f5da77a31e7dd5ecb46c017ffc3": checkoutProfile12, + "34e114876b0b11c390a56381ad16ebd13914f8d5": checkoutProfile05, + "3537747199ad29df25693bc607e99df5d7726ffd": checkoutProfile14, + "37b082107ba410260a3aaddf93122e04801ce631": checkoutProfile04, + "3b9b8c884f6b4bb4d5be2779c26374abadae0871": checkoutProfile05, + "3ba5ee6fac7e0e30e2ea884e236f282d3a775891": checkoutProfile10, + "3d3c42e5aac5ba805825da76410c181273ba90b1": checkoutProfile01, + "3d677ac575eac4b370e52131024fa99ee754def1": checkoutProfile12, + "3df4ab11eba7bda6032a0b82a6bb43b11571feac": checkoutProfile07, + "3df79e0276f4013ea6ed57534f3478cd2b1ef8c0": checkoutProfile15, + "3f603f6d5e9f40714f97b2f017aa0df2a443192a": checkoutProfile04, + "3fc17f8645e9648158a6d23b033ab5f62df29f3c": checkoutProfile12, + "40a16ebeed7da831425b665e600750cb36b38d06": checkoutProfile10, + "422dc4567157f4d62b665a8a288310365b1d194b": checkoutProfile13, + "43045ae669be728bd34ed56fcd1a230c0dc4d8e2": checkoutProfile04, + "442567ba5761652b13c5c842a2f959ac9da6be57": checkoutProfile12, + "44c2b7a8a4ea60a981eaca3cf939b5f4305c123b": checkoutProfile04, + "453ee27fca95fa9e03a24c1969a92c82e1a9b15e": checkoutProfile12, + "473055ba18d6d2da209cd46110aadb9275e3194e": checkoutProfile06, + "47fbe2df0ad0e27efb67a70beac3555f192b062f": checkoutProfile10, + "4817b449b0ed7c775a0bcecaa398041ab5d09b51": checkoutProfile16, + "4f1f4aec02e41874fa0262ea8ff5172d7978ad1e": checkoutProfile01, + "50fbc622fc4ef5163becd7fab6573eac35f8462e": checkoutProfile15, + "5126516654c75f76bca1de45dd82a3006d8890f9": checkoutProfile12, + "537c7ef99cef6e5ddb5e7ff5d16d14510503801d": checkoutProfile01, + "53bed0742eb3f0455187c7c7042d27f51b856f02": checkoutProfile15, + "556e4c3cb0b8b54b734286d5439adadcb0a8cb92": checkoutProfile06, + "56c00a7b1f53d3094df328ad4c2cd2b2d385c569": checkoutProfile12, + "574281d34cf49767d4b75b691c4c4f4655e0c93f": checkoutProfile12, + "58070a9fc3a91197fc9cbf24841ea31a2ab19980": checkoutProfile12, + "58246fdaeb114bc8d7e5ba1c0dd4504aa481f1c6": checkoutProfile02, + "5881116d181dc80f3ed5f395296a5579ee6fc6a4": checkoutProfile16, + "592cf69a223b04e75ddf345919130b91010eb2a6": checkoutProfile12, + "5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f": checkoutProfile12, + "5c3ccc22eb2c950a0fa5bc7c47190d8e3f7e681a": checkoutProfile10, + "5de26ee9b11f6ffa02406edecc0e750256af18b1": checkoutProfile01, + "6026fb2ad3aa556d78b517cf65c8c1f832075860": checkoutProfile01, + "61b9e3751b92087fd0b06925ba6dd6314e06f089": checkoutProfile12, + "61fd8fd0c7a28ab9f73c23c595edbd0550bf0e78": checkoutProfile14, + "62661c4e71a304b2823ed026347b8d34c3eac541": checkoutProfile01, + "631c7dc4f80f88219c5ee78fee08c6b62fac8da1": checkoutProfile05, + "631c942040754b6e095e929c1677c07e10ed4f87": checkoutProfile01, + "65865e15a14a3de9378a18a026ce6548b17a39ed": checkoutProfile12, + "689bf84be4a745196a5c809a6afb12708ee43c3c": checkoutProfile16, + "692973e3d937129bcbf40652eb9f2f61becf3332": checkoutProfile04, + "6a84743051be17cee477b0a26bd866b5dba996e4": checkoutProfile10, + "6b42224f41ee5dfe5395e27c8b2746f1f9955030": checkoutProfile05, + "6ccd57f4c5d15bdc2fef309bd9fb6cc9db2ef1c6": checkoutProfile04, + "6d193bf28034eafb982f37bd894289fe649468fc": checkoutProfile05, + "6e6328ef28ba9c951379a07c83913e2acc8bc9a0": checkoutProfile15, + "71cf2267d89c5cb81562390fa70a37fa40b1305e": checkoutProfile05, + "722adc63f1aa60a57ec37892e133b1d319cae598": checkoutProfile14, + "72f2cec99f417b1a1c5e2e88945068983b7965f9": checkoutProfile07, + "7523e237893f02412c876c5511929ce0c74c348d": checkoutProfile12, + "755da8c3cf115ac066823e79a1e1788f8940201b": checkoutProfile10, + "7739b9ba2efcda9dde65ad1e3c2dbe65b41dfba7": checkoutProfile08, + "77904fd4316d60fc138fe2b8286ca220f763853e": checkoutProfile14, + "7884fcad6b5d53d10323aee724dc68d8b9096a2e": checkoutProfile11, + "79102f25032f3f70eb9d8386b1451cf1ef55902d": checkoutProfile01, + "7990b10a0ca6be1ddd27e4d84e6dbbe788d86662": checkoutProfile16, + "7b187184d12a8f064f797aeb51e4873c109637c7": checkoutProfile10, + "7cdaf2fbc075e6f3b9ca94cfd6cec5adc8a75622": checkoutProfile06, + "7d09575332117a40b46e5e020664df234cd416f3": checkoutProfile01, + "7f00b66d06eed909da8e56729955e53d186d95ed": checkoutProfile12, + "7f0669ca1fd955c0e0fd85ee8d5b8d16978be97e": checkoutProfile15, + "80602fafba6e982172195b721791020f4f17a227": checkoutProfile13, + "8230315d06ad95c617244d2f265d237a1682d445": checkoutProfile10, + "826ba42d6c06e4d78b1b33478af7b54277e60b52": checkoutProfile12, + "83b7061638ee4956cf7545a6f7efe594e5ad0247": checkoutProfile10, + "8410ad0602e1e429cee44a835ae9f77f654a6694": checkoutProfile06, + "8459bc0c7e3759cdf591f513d9f141a95fef0a8f": checkoutProfile04, + "8461dbfed36a8af202384a5b1ee0f7f1bf947821": checkoutProfile16, + "8530928916aaef40f59e6f221989ccb31f5759e7": checkoutProfile06, + "85b1f35505da871133b65f059e96210c65650a8b": checkoutProfile12, + "85e47d1a2bef5be8023f6dce02e0e8451938924f": checkoutProfile12, + "85e6279cec87321a52edac9c87bce653a07cf6c2": checkoutProfile05, + "86f86b36ef15e6570752e7175f451a512eac206b": checkoutProfile12, + "885641592076c27bfb56c028cd5612cdad63e16d": checkoutProfile10, + "8ade135a41bc03ea155e62e844d188df1ea18608": checkoutProfile06, + "8b5e8b768746b50394015010d25e690bfab9dfbc": checkoutProfile07, + "8e5e7e5ab8b370d6c329ec480221332ada57f0ab": checkoutProfile10, + "8e8c483db84b4bee98b60c0593521ed34d9990e8": checkoutProfile05, + "8eb1f6a495037164bea451156472f35fdd6bafc0": checkoutProfile06, + "8edcb1bdb4e267140fa742c62e395cd74f332709": checkoutProfile05, + "8f4b7f84864484a7bf31766abe9204da3cbe65b3": checkoutProfile10, + "8f9e05e482293f862823fcca12d9eddfb3723131": checkoutProfile12, + "900f2210b1d28bbbd0bd22d17926b9e224e8f231": checkoutProfile05, + "93cb6efe18208431cddfb8368fd83d5badbf9bfd": checkoutProfile05, + "93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8": checkoutProfile10, + "94c2de77cccf605d74201a8aec6dd8fc0717ad66": checkoutProfile12, + "94d077c24971944d312dd9197c1bdfba62b39878": checkoutProfile15, + "96f53100ba2a5449eb71d2e6604bbcd94b9449b5": checkoutProfile09, + "97a652b80035363df47baee5031ec8670b8878ac": checkoutProfile08, + "97b30c411cc8e273e8f90d632b8e53d2604a90ca": checkoutProfile12, + "9839dc14a02ddc6b6995e69eb3ecb98132fc8b6b": checkoutProfile04, + "9a3a9ade8222dcdf9d3c77710b10df47ee7c7c89": checkoutProfile12, + "9a9194f87191a7e9055e3e9b95b8cfb13023bb08": checkoutProfile04, + "9b4c13b0bfa31b4514c14f74b5a166c2708f43c6": checkoutProfile04, + "9bb56186c3b09b4f86b1c65136769dd318469633": checkoutProfile06, + "9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0": checkoutProfile01, + "9c1e94e0ad997d618b6113a2171b055037589028": checkoutProfile04, + "9f265659d3bb64ab1440b03b12f4d47a24320917": checkoutProfile05, + "a12a3943b4bdde767164f792f33f40b04645d846": checkoutProfile12, + "a14471d838f6a7ce15cab8740f25e337c51e7cad": checkoutProfile15, + "a37ce9120846195fa4ece8f58b268e6043cb2f26": checkoutProfile02, + "a4b69b48862e969425d8dc115dcb965f288ea29b": checkoutProfile12, + "a572f640b07e96fc5837b3adfa0e5a2ddd8dae21": checkoutProfile16, + "a5ac7e51b41094c92402da3b24376905380afc29": checkoutProfile04, + "a6747255bd19d7a757dbdda8c654a9f84db19839": checkoutProfile14, + "a81bbbf8298c0fa03ea29cdc473d45769f953675": checkoutProfile12, + "aabbfeb2ce60b5bd82389903509092c4648a9713": checkoutProfile12, + "aadec899646c8e0f34c52d9219c2faac36626b55": checkoutProfile06, + "ac455590d1debd05854e62f352cf7a59e27328bc": checkoutProfile12, + "ac593985615ec2ede58e132d2e21d2b1cbd6127c": checkoutProfile10, + "add3486cc3b55d4a5e11c8045058cef96538edc7": checkoutProfile12, + "ae525b22625099736a2909d0eb22ec50cbe398fc": checkoutProfile14, + "af513c7a016048ae468971c52ed77d9562c7c819": checkoutProfile15, + "afe4af09a72596f47d806ee5f8b2674ec07fdc73": checkoutProfile12, + "b17fe1e4d59a9d1d95a7aead5e6fcd13e50939a5": checkoutProfile04, + "b1ec3021b8fa02164da82ca1557d017d83b0e179": checkoutProfile04, + "b2e6b7ed13bcde9d37c9e3e6967cd3ecfd2807ad": checkoutProfile12, + "b2eb13baee0ef6ef21737c8cf4a6a32f4e002442": checkoutProfile11, + "b32f140b0c872d58512e0a66172253c302617b90": checkoutProfile06, + "b4483adec309c0d01a5435c5e24eb40de5773ad9": checkoutProfile12, + "b4626ce19ce1106186ddf9bb20e706842f11a7c3": checkoutProfile13, + "b4b537b06a577732e04b29acc7294f645c135da0": checkoutProfile15, + "b4ffde65f46336ab88eb53be808477a3936bae11": checkoutProfile06, + "b6849436894e144dbce29d7d7fda2ae3bf9d8365": checkoutProfile05, + "b80ff79f1755d06ba70441c368a6fe801f5f3a62": checkoutProfile04, + "b9e0990d219a03df7633c93f6f005a8fecbcab22": checkoutProfile01, + "ba097532fb203f7e88c9c3c0b899b49469908a92": checkoutProfile01, + "bc50a995b88ec9334cb2f3b1c49502d9834ed2c5": checkoutProfile14, + "be0f44845645e415725af198163a96fea9e54334": checkoutProfile12, + "be6c44d969b1b004a9e0f7853e9cc9977ea0f7f0": checkoutProfile12, + "bf085276cecdb0cc76fbbe0687a5a0e786646936": checkoutProfile10, + "bf4af63534d79cb0712d8c86d8f2404844fa5a79": checkoutProfile15, + "c170eefc2657d93cc91397be50a299bff978a052": checkoutProfile14, + "c2d88d3ecc89a9ef08eebf45d9637801dcee7eb5": checkoutProfile05, + "c49af7ca1f339b07a5baac8c8bfc49a5248f31d3": checkoutProfile12, + "c533a0a4cfc4962971818edcfac47a2899e69799": checkoutProfile06, + "c85684db76ba6ef08713c10cf4befe3318887415": checkoutProfile14, + "c85c95e3d7251135ab7dc9ce3241c5835cc595a9": checkoutProfile09, + "c915c33a16f01166c17c4e35fe1d4085a2d71adb": checkoutProfile01, + "c952173edf28a2bd22e1a4926590c1ac39630461": checkoutProfile12, + "cab31617d857bf9e70dc35fd9e4dafe350794082": checkoutProfile16, + "cacfc4155de4db33162bcb6c82700751fda6bd91": checkoutProfile15, + "cbb722410c2e876e24abbe8de2cc27693e501dcb": checkoutProfile05, + "cc70598ce853d5d678b2440190cb18368e5cee8c": checkoutProfile16, + "cd6a9fd49371476d813e892956e2e920fcc3fb7e": checkoutProfile10, + "cd7d8d697e10461458bc61a30d094dc601a8b017": checkoutProfile06, + "d106d4669b3bfcb17f11f83f98e1cab478e9f635": checkoutProfile09, + "d23441a48e516b6c34aea4fa41551a30e30af803": checkoutProfile01, + "d50f8ea76748df49594d9b109b614f3b4db63c71": checkoutProfile12, + "d632683dd7b4114ad314bca15554477dd762a938": checkoutProfile05, + "d914b262ffc244530a203ab40decab34c3abf34d": checkoutProfile01, + "dac8cc78a1c612c854c383833b39e5a3f357b1f5": checkoutProfile12, + "db0cee9a514becbbd4a101a5fbbbf47865ee316c": checkoutProfile05, + "db41740e12847bb616a339b75eb9414e711417df": checkoutProfile14, + "dc323e67f16fb5f7663d20ff7941f27f5809e9b6": checkoutProfile11, + "dcd71f646680f2efd8db4afa5ad64fdcba30e748": checkoutProfile12, + "dd960bd3c3f080561a1810e32349ac211ecec7d4": checkoutProfile04, + "de0fac2e4500dabe0009e67214ff5f5447ce83dd": checkoutProfile05, + "de5a000abf73b6f4965bd1bcdf8f8d94a56ea815": checkoutProfile05, + "df0bcddf6d6823307c716b56a7ef9c3b25078874": checkoutProfile06, + "df4cb1c069e1874edd31b4311f1884172cec0e10": checkoutProfile05, + "df86c829ebbc4e80aa9885a4762d84e11e0eeacb": checkoutProfile12, + "dfd70d4a2dece5f4a1af8dc99e1508a16e916b60": checkoutProfile14, + "e2f20e631ae6d7dd3b768f56a5d2af784dd54791": checkoutProfile11, + "e347bba93bdcadab0b55e4b333254f9bb40bdb0c": checkoutProfile16, + "e3bc06d98631ce7e0e3db6bd158fafe028709e9f": checkoutProfile12, + "e3d2460bbb42d7710191569f88069044cfb9d8cf": checkoutProfile05, + "e52d022eb52c224e5f2201beb687a66849e3b200": checkoutProfile12, + "e6d535c99c374d0c3f6d8cd8086a57b43c6c700a": checkoutProfile10, + "e8bd1dffb6451bb0d84dbcd3ed059daca1371180": checkoutProfile15, + "e8cb398be4a550817e382abf69e4c12c76fce1f2": checkoutProfile01, + "e8d4307400f9427dba7cb98e488d6ab85f1cec5f": checkoutProfile01, + "eb35239ec22e9029a5be28f8c41e67452f615f0f": checkoutProfile10, + "eb8a193c1dbf4bbb2053320cef52bacc1a485839": checkoutProfile12, + "ec3a7ce113134d7a93b817d10a8272cb61118579": checkoutProfile12, + "eccf386318b560bdd401913a9fe3cca56dc369d6": checkoutProfile12, + "ee0669bd1cc54295c223e0bb666b733df41de1c5": checkoutProfile11, + "eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871": checkoutProfile05, + "f0282184c7ce73ab54c7e4ab5a617122602e575f": checkoutProfile01, + "f095bcc56b7c2baf48f3ac70d6d6782f4f553222": checkoutProfile10, + "f2190623701cfebaaf26554b39e1e29cc4a1f2fb": checkoutProfile14, + "f25a3a9f25bd5f4c5d77189cab02ff357b5aedeb": checkoutProfile12, + "f43a0e5ff2bd294095638e18286ca9a3d1956744": checkoutProfile08, + "f466b96953a8e78166c9b97a44a70220f1a3e77e": checkoutProfile14, + "f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a": checkoutProfile01, + "f67ee5d6224ccd5af1909d53ea1faa5efb91db29": checkoutProfile11, + "f6ce2afa7079cb075a124c93c79d61779d845782": checkoutProfile15, + "f858c22e963bc60bc9d01c3d105c52a45a7deb6e": checkoutProfile14, + "f90c7b395dac7c5a277c1a6d93d5057c1cddb74e": checkoutProfile14, + "f93ca50bde35f63a65c67fc94cc8821ead20e631": checkoutProfile01, + "f95f2a38561736d1542cb9fbf736eea3d00ab5a6": checkoutProfile14, + "f9e715a95fcd1f9253f77dd28f11e88d2d6460c7": checkoutProfile01, + "fb6f360df236bd2026c7963cf88c8ddf20b4f0e2": checkoutProfile12, + "fbb30c60ab3f94a2c03755a7fb875120c137bef7": checkoutProfile12, + "fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09": checkoutProfile01, + "fd084cde189b7b76ec305d52e27be545a0172823": checkoutProfile04, + "fd47087372161c6f2a7b96d2ef87e944d89023ed": checkoutProfile12, + "ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493": checkoutProfile05, +} diff --git a/internal/action/integration/checkout_test.go b/internal/action/integration/checkout_test.go index c4a21700..006faf88 100644 --- a/internal/action/integration/checkout_test.go +++ b/internal/action/integration/checkout_test.go @@ -6,24 +6,55 @@ import ( ) func TestCheckoutCommitAdmission(t *testing.T) { - for _, commit := range []string{CheckoutV1Commit, CheckoutV2Commit, CheckoutV3Commit, CheckoutV4Commit, CheckoutV5Commit, CheckoutV6Commit, CheckoutV7InitialCommit, CheckoutV7Commit} { + for _, commit := range []string{ + CheckoutV1Commit, CheckoutV2Commit, CheckoutV3Commit, CheckoutV4Commit, + CheckoutV5Commit, CheckoutV6Commit, CheckoutV7InitialCommit, CheckoutV7Commit, + "af513c7a016048ae468971c52ed77d9562c7c819", // v1.0.0 + "722adc63f1aa60a57ec37892e133b1d319cae598", // v2.0.0 + "a12a3943b4bdde767164f792f33f40b04645d846", // v3.0.0 + "f43a0e5ff2bd294095638e18286ca9a3d1956744", // v3.6.0 + "1e31de5234b9f8995739874a8ce0492dc87873e2", // v4.0.0 + } { if err := validateCheckoutCommit(commit); err != nil { - t.Fatalf("audited commit %s rejected: %v", commit, err) + t.Fatalf("snapshotted commit %s rejected: %v", commit, err) } } if err := validateCheckoutCommit("de0fac2e4500dabe0009e67214ff5f5447ce83dd"); err != nil { t.Fatalf("upstream main commit rejected: %v", err) } - for _, commit := range []string{ - "f43a0e5ff2bd294095638e18286ca9a3d1956744", // v3.6.0 is an ancestor of upstream main. - strings.Repeat("0", 40), - } { + for _, commit := range []string{strings.Repeat("0", 40)} { if err := validateCheckoutCommit(commit); err == nil || !strings.Contains(err.Error(), "does not admit") || !strings.Contains(err.Error(), CheckoutV7Commit) || !strings.Contains(err.Error(), checkoutMainSnapshotCommit) { t.Fatalf("unrecognized checkout commit %s error = %v", commit, err) } } } +func TestCheckoutSnapshotContracts(t *testing.T) { + if len(checkoutCommitContracts) < 254 { + t.Fatalf("snapshotted checkout commits = %d, want at least 254", len(checkoutCommitContracts)) + } + for branch, tip := range checkoutSnapshotTips { + if _, ok := checkoutCommitContracts[tip]; !ok { + t.Errorf("snapshot branch %s tip %s has no admitted contract", branch, tip) + } + } + for commit, contract := range checkoutCommitContracts { + if contract.inputs == "" { + t.Errorf("snapshotted commit %s has no declared inputs", commit) + } + names := strings.Split(contract.inputs, ",") + for i, name := range names { + if name != strings.ToLower(name) || i > 0 && names[i-1] >= name { + t.Errorf("snapshotted commit %s has noncanonical inputs %q", commit, contract.inputs) + break + } + } + if contract.refOutput != contract.commitOutput { + t.Errorf("snapshotted commit %s declares only one checkout output", commit) + } + } +} + func TestValidateCheckoutInputs(t *testing.T) { repository, sha := "buildkite/buildkite-gha", strings.Repeat("a", 40) for _, inputs := range []map[string]string{ @@ -136,3 +167,32 @@ func TestValidateCheckoutLegacyInputsRejectLaterContracts(t *testing.T) { }) } } + +func TestValidateCheckoutInputsUsesPerCommitContract(t *testing.T) { + repository, sha := "buildkite/buildkite-gha", strings.Repeat("a", 40) + for _, test := range []struct { + name, commit, input string + wantAccepted bool + }{ + {name: "v2.0 before submodules", commit: "722adc63f1aa60a57ec37892e133b1d319cae598", input: "submodules"}, + {name: "v2.3.4 with submodules", commit: "5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f", input: "submodules", wantAccepted: true}, + {name: "v3.0 before fetch-tags", commit: "a12a3943b4bdde767164f792f33f40b04645d846", input: "fetch-tags"}, + {name: "v3.7 with fetch-tags", commit: CheckoutV3Commit, input: "fetch-tags", wantAccepted: true}, + {name: "v4.0 before filter", commit: "1e31de5234b9f8995739874a8ce0492dc87873e2", input: "filter"}, + {name: "v4.2 with filter", commit: "d632683dd7b4114ad314bca15554477dd762a938", input: "filter", wantAccepted: true}, + } { + t.Run(test.name, func(t *testing.T) { + value := "false" + if test.input == "filter" { + value = "" + } + err := ValidateCheckoutInputs(test.commit, map[string]string{test.input: value}, repository, sha) + if test.wantAccepted && err != nil { + t.Fatalf("ValidateCheckoutInputs() = %v", err) + } + if !test.wantAccepted && (err == nil || !strings.Contains(err.Error(), "unsupported by this actions/checkout release")) { + t.Fatalf("ValidateCheckoutInputs() = %v, want contract rejection", err) + } + }) + } +} diff --git a/internal/action/integration/cmd/generate-checkout-profiles/main.go b/internal/action/integration/cmd/generate-checkout-profiles/main.go new file mode 100644 index 00000000..4b9b1b13 --- /dev/null +++ b/internal/action/integration/cmd/generate-checkout-profiles/main.go @@ -0,0 +1,175 @@ +package main + +import ( + "bytes" + "fmt" + "go/format" + "os" + "os/exec" + "path/filepath" + "sort" + "strings" + + "go.yaml.in/yaml/v4" +) + +const repository = "https://github.com/actions/checkout.git" + +var snapshotBranches = []string{"main", "master", "releases/v1", "releases/v2", "releases/v3", "releases/v4", "releases/v5", "releases/v6"} + +type actionManifest struct { + Inputs map[string]yaml.Node `yaml:"inputs"` + Outputs map[string]yaml.Node `yaml:"outputs"` + Runs struct { + Plugin string `yaml:"plugin"` + } `yaml:"runs"` +} + +type contract struct { + Inputs string + FullHistory bool + RefOutput bool + CommitOutput bool +} + +func main() { + output := "checkout_profiles_generated.go" + if len(os.Args) > 2 { + fatalf("usage: go run ./cmd/generate-checkout-profiles [output]") + } + if len(os.Args) == 2 { + output = os.Args[1] + } + + checkout, err := os.MkdirTemp("", "buildkite-gha-checkout-profiles-") + if err != nil { + fatalf("create temporary checkout: %v", err) + } + defer func() { _ = os.RemoveAll(checkout) }() + run(checkout, "git", "init", "--quiet") + run(checkout, "git", "remote", "add", "origin", repository) + refspecs := []string{"--quiet", "--no-tags", "origin", "+refs/tags/*:refs/tags/*"} + for _, branch := range snapshotBranches { + refspecs = append(refspecs, "+refs/heads/"+branch+":refs/remotes/origin/"+branch) + } + run(checkout, "git", append([]string{"fetch"}, refspecs...)...) + + tips := make(map[string]string, len(snapshotBranches)) + for _, branch := range snapshotBranches { + tips[branch] = gitOutput(checkout, "rev-parse", "refs/remotes/origin/"+branch+"^{commit}") + } + commits := strings.Fields(gitOutput(checkout, "rev-list", "--all")) + contracts := make(map[string]contract) + for _, commit := range commits { + source, err := exec.Command("git", "-C", checkout, "show", commit+":action.yml").Output() + if err != nil { + source, err = exec.Command("git", "-C", checkout, "show", commit+":action.yaml").Output() + } + if err != nil { + continue + } + var manifest actionManifest + if yaml.Unmarshal(source, &manifest) != nil { + continue + } + outputs := sortedKeys(manifest.Outputs) + if len(outputs) != 0 && (len(outputs) != 2 || outputs[0] != "commit" || outputs[1] != "ref") { + continue + } + inputs := sortedKeys(manifest.Inputs) + contracts[commit] = contract{ + Inputs: strings.Join(inputs, ","), + FullHistory: manifest.Runs.Plugin != "", + RefOutput: contains(outputs, "ref"), + CommitOutput: contains(outputs, "commit"), + } + } + + profilesByContract := map[contract]string{} + uniqueContracts := make([]contract, 0) + for _, profile := range contracts { + if _, ok := profilesByContract[profile]; ok { + continue + } + uniqueContracts = append(uniqueContracts, profile) + profilesByContract[profile] = "" + } + sort.Slice(uniqueContracts, func(i, j int) bool { + return contractKey(uniqueContracts[i]) < contractKey(uniqueContracts[j]) + }) + for i, profile := range uniqueContracts { + profilesByContract[profile] = fmt.Sprintf("checkoutProfile%02d", i+1) + } + + var generated bytes.Buffer + fmt.Fprintln(&generated, "// Code generated by internal/action/integration/cmd/generate-checkout-profiles; DO NOT EDIT.") + fmt.Fprintln(&generated, "\npackage integration") + fmt.Fprintf(&generated, "\nconst checkoutMainSnapshotCommit = %q\n", tips["main"]) + fmt.Fprintln(&generated, "\nvar checkoutSnapshotTips = map[string]string{") + for _, branch := range snapshotBranches { + fmt.Fprintf(&generated, "\t%q: %q,\n", branch, tips[branch]) + } + fmt.Fprintln(&generated, "}") + fmt.Fprintln(&generated, "\nvar (") + for _, profile := range uniqueContracts { + fmt.Fprintf(&generated, "\t%s = checkoutContract{inputs: %q, fullHistory: %t, refOutput: %t, commitOutput: %t}\n", + profilesByContract[profile], profile.Inputs, profile.FullHistory, profile.RefOutput, profile.CommitOutput) + } + fmt.Fprintln(&generated, ")") + fmt.Fprintln(&generated, "\nvar checkoutCommitContracts = map[string]checkoutContract{") + commitKeys := sortedKeys(contracts) + for _, commit := range commitKeys { + fmt.Fprintf(&generated, "\t%q: %s,\n", commit, profilesByContract[contracts[commit]]) + } + fmt.Fprintln(&generated, "}") + + formatted, err := format.Source(generated.Bytes()) + if err != nil { + fatalf("format generated source: %v", err) + } + if err := os.WriteFile(filepath.Clean(output), formatted, 0o644); err != nil { + fatalf("write generated source: %v", err) + } +} + +func sortedKeys[T any](values map[string]T) []string { + keys := make([]string, 0, len(values)) + for key := range values { + keys = append(keys, strings.ToLower(key)) + } + sort.Strings(keys) + return keys +} + +func contains(values []string, target string) bool { + index := sort.SearchStrings(values, target) + return index < len(values) && values[index] == target +} + +func contractKey(profile contract) string { + return fmt.Sprintf("%s\x00%t\x00%t\x00%t", profile.Inputs, profile.FullHistory, profile.RefOutput, profile.CommitOutput) +} + +func gitOutput(directory string, args ...string) string { + command := exec.Command("git", append([]string{"-C", directory}, args...)...) + output, err := command.Output() + if err != nil { + fatalf("git %s: %v", strings.Join(args, " "), err) + } + return strings.TrimSpace(string(output)) +} + +func run(directory, name string, args ...string) { + command := exec.Command(name, args...) + command.Dir = directory + command.Stdout = os.Stdout + command.Stderr = os.Stderr + if err := command.Run(); err != nil { + fatalf("%s %s: %v", name, strings.Join(args, " "), err) + } +} + +func fatalf(format string, args ...any) { + fmt.Fprintf(os.Stderr, format+"\n", args...) + os.Exit(1) +} diff --git a/internal/compiler/actions_test.go b/internal/compiler/actions_test.go index 28cbd762..437db16e 100644 --- a/internal/compiler/actions_test.go +++ b/internal/compiler/actions_test.go @@ -1247,9 +1247,14 @@ func TestCheckoutAdapterInputBoundary(t *testing.T) { func TestCheckoutAdapterCommitBoundary(t *testing.T) { workspace, remote := t.TempDir(), t.TempDir() for version, commit := range map[string]string{ + "v1.0.0": "af513c7a016048ae468971c52ed77d9562c7c819", "v1.2.0": actionintegration.CheckoutV1Commit, + "v2.0.0": "722adc63f1aa60a57ec37892e133b1d319cae598", "v2.8.0": actionintegration.CheckoutV2Commit, + "v3.0.0": "a12a3943b4bdde767164f792f33f40b04645d846", + "v3.6.0": "f43a0e5ff2bd294095638e18286ca9a3d1956744", "v3.7.0": actionintegration.CheckoutV3Commit, + "v4.0.0": "1e31de5234b9f8995739874a8ce0492dc87873e2", "v4": actionintegration.CheckoutV4Commit, "v5": actionintegration.CheckoutV5Commit, "v6": actionintegration.CheckoutV6Commit, diff --git a/internal/runtime/checkout_test.go b/internal/runtime/checkout_test.go index d98737a1..a2c61448 100644 --- a/internal/runtime/checkout_test.go +++ b/internal/runtime/checkout_test.go @@ -376,7 +376,10 @@ func TestCheckoutOutputsMatchReleaseContract(t *testing.T) { {name: "v1.2.0", commit: actionintegration.CheckoutV1Commit, want: map[string]string{}}, {name: "v2.8.0", commit: actionintegration.CheckoutV2Commit, want: map[string]string{}}, {name: "v3.7.0", commit: actionintegration.CheckoutV3Commit, want: map[string]string{}}, - {name: "v4 and later", commit: actionintegration.CheckoutV4Commit, want: map[string]string{"ref": "refs/heads/main", "commit": strings.Repeat("a", 40)}}, + {name: "v4.0.0 before outputs", commit: "1e31de5234b9f8995739874a8ce0492dc87873e2", want: map[string]string{}}, + {name: "v4.1.7 before outputs", commit: "692973e3d937129bcbf40652eb9f2f61becf3332", want: map[string]string{}}, + {name: "v4.2.0 with outputs", commit: "d632683dd7b4114ad314bca15554477dd762a938", want: map[string]string{"ref": "refs/heads/main", "commit": strings.Repeat("a", 40)}}, + {name: "current v4", commit: actionintegration.CheckoutV4Commit, want: map[string]string{"ref": "refs/heads/main", "commit": strings.Repeat("a", 40)}}, } { t.Run(test.name, func(t *testing.T) { outputs := map[string]string{} @@ -395,6 +398,8 @@ func TestCheckoutInputsWithReleaseDefaults(t *testing.T) { inputs map[string]string want map[string]string }{ + {name: "v1.0 defaults to full history", commit: "af513c7a016048ae468971c52ed77d9562c7c819", inputs: nil, want: map[string]string{"fetch-depth": "0"}}, + {name: "v1.1 defaults to full history", commit: "0b496e91ec7ae4428c3ed2eeb4c3a40df431f2cc", inputs: nil, want: map[string]string{"fetch-depth": "0"}}, {name: "v1 defaults to full history", commit: actionintegration.CheckoutV1Commit, inputs: nil, want: map[string]string{"fetch-depth": "0"}}, {name: "v1 keeps explicit depth", commit: actionintegration.CheckoutV1Commit, inputs: map[string]string{"Fetch-Depth": "5"}, want: map[string]string{"Fetch-Depth": "5"}}, {name: "v2 keeps shallow default", commit: actionintegration.CheckoutV2Commit, inputs: nil, want: nil}, diff --git a/mise.toml b/mise.toml index 77523104..548b49b9 100644 --- a/mise.toml +++ b/mise.toml @@ -34,7 +34,7 @@ run = "echo '--- Lint Go'; golangci-lint run" [tasks."lint:shell"] description = "Lint shell scripts" -run = "echo '--- Lint shell'; shellcheck -x .buildkite/upload-examples.sh scripts/ci-buildkite-release scripts/compare-example scripts/compatibility-gaps scripts/starter-workflows-corpus scripts/update-checkout-main-commits scripts/validate-public-workflow-corpus scripts/verify-source-checkout scripts/hosted-docker-probe scripts/container-runtime-probe scripts/verify-summary-annotation scripts/verify-workflow-annotations scripts/verify-upload-artifact scripts/verify-artifact-roundtrip scripts/release scripts/release-test scripts/smoke-local testdata/actions/docker/entrypoint.sh testdata/container-runtime/.github/actions/docker/entrypoint.sh" +run = "echo '--- Lint shell'; shellcheck -x .buildkite/upload-examples.sh scripts/ci-buildkite-release scripts/compare-example scripts/compatibility-gaps scripts/starter-workflows-corpus scripts/validate-public-workflow-corpus scripts/verify-source-checkout scripts/hosted-docker-probe scripts/container-runtime-probe scripts/verify-summary-annotation scripts/verify-workflow-annotations scripts/verify-upload-artifact scripts/verify-artifact-roundtrip scripts/release scripts/release-test scripts/smoke-local testdata/actions/docker/entrypoint.sh testdata/container-runtime/.github/actions/docker/entrypoint.sh" [tasks.lint] description = "Lint Go code and shell scripts" diff --git a/scripts/update-checkout-main-commits b/scripts/update-checkout-main-commits deleted file mode 100755 index 79b93a6f..00000000 --- a/scripts/update-checkout-main-commits +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -repository=https://github.com/actions/checkout.git -v4_boundary_commit=f43a0e5ff2bd294095638e18286ca9a3d1956744 -requested_commit=${1:-} -output=${2:-checkout_main_commits_generated.go} -checkout=$(mktemp -d) -trap 'rm -rf "$checkout"' EXIT - -git -C "$checkout" init --quiet -git -C "$checkout" remote add origin "$repository" -git -C "$checkout" fetch --quiet --filter=blob:none origin main -main_commit=$(git -C "$checkout" rev-parse FETCH_HEAD) - -if [[ -n "$requested_commit" ]] && ! git -C "$checkout" cat-file -e "$requested_commit^{commit}" 2>/dev/null; then - git -C "$checkout" fetch --quiet --filter=blob:none origin "$requested_commit" -fi -snapshot_commit=$(git -C "$checkout" rev-parse "${requested_commit:-$main_commit}^{commit}") -if ! git -C "$checkout" merge-base --is-ancestor "$snapshot_commit" "$main_commit"; then - echo "$snapshot_commit is not reachable from actions/checkout upstream main" >&2 - exit 1 -fi -if ! git -C "$checkout" merge-base --is-ancestor "$v4_boundary_commit" "$snapshot_commit"; then - echo "$snapshot_commit predates the actions/checkout v4 development boundary" >&2 - exit 1 -fi - -{ - cat <"$output" - -gofmt -w "$output"