checkout-action/action.yml
Michael Hanke e3f92a8464
feat: support fetch-depth input
This should be implementing the same semantics as the node.js based
action.
2026-08-18 14:48:08 +02:00

220 lines
12 KiB
YAML

name: checkout-action
description: GitHub Action for checking out a repository. (Simplified actions/checkout alternative that does not depend on Node.js.)
inputs:
token:
description: GitHub token for checking out a repository.
required: false
fetch-depth:
required: false
default: '1'
description: Number of commits to fetch. 0 indicates all history for all branches and tags.
# Note:
# - inputs.* should be manually mapped to INPUT_* due to https://github.com/actions/runner/issues/665
# - For context containing path, use GITHUB_*/RUNNER_* instead of github.*/runner.* due to https://github.com/actions/runner/issues/2185
runs:
using: composite
steps:
- run: |
# Checkout (non-Windows)
bail() {
printf '::error::checkout-action: %s\n' "$*"
exit 1
}
warn() {
printf '::warning::checkout-action: %s\n' "$*"
}
# Use binaries available at standard location to prevent path interception.
# On macOS and known Linux distributions:
# - /usr/bin/env and /bin/sh are always available.
# On macOS and known non-NixOS Linux distributions:
# - /bin/bash is available by default or when bash is installed by system package manager.
# - Required or optionally used tools are available in any of /bin:/usr/bin:/sbin:/usr/sbin
# by default or when installed by system package manager.
# Note that sed/awk (both not currently used in this action) are not always available by default,
# e.g.,:
# - no sed: nixos/nix, photon:1.0
# - no awk: opensuse/tumbleweed, nixos/nix, openmandriva/cooker, photon
# On NixOS:
# - bash and POSIX utilities are available at /run/current-system/sw/bin or /run/wrappers/bin.
# On nixos/nix image (which has no /etc/NIXOS), they are available at /root/.nix-profile/bin.
# - git is usually available at ~/.nix-profile/bin when installed by system package manager.
# See "Compatibility" section in README.md for partial list of tested distributions.
# git also uses binaries available at standard location by default:
# https://github.com/git/git/blob/v2.54.0/Makefile#L927-L935
# NB: Sync with resolve_path in src/*.sh and tools/ci/test-bash-func.sh.
resolve_path() {
for dir in /bin /usr/bin /sbin /usr/sbin; do
if [ -x "${dir}/$1" ]; then
printf '%s/%s\n' "${dir}" "$1"
return
fi
done
if [ -e /etc/NIXOS ] && [ -x /run/current-system/sw/bin/"$1" ]; then
printf '/run/current-system/sw/bin/%s\n' "$1"
elif [ -e /etc/NIXOS ] && [ -x /run/wrappers/bin/"$1" ]; then
printf '/run/wrappers/bin/%s\n' "$1"
elif [ -e /etc/nix ] && [ -x /root/.nix-profile/bin/"$1" ]; then
printf '/root/.nix-profile/bin/%s\n' "$1"
fi
}
# Install missing required tools from system package manager on Linux.
# See src/install-required-tools.sh for more.
if [ "${RUNNER_OS}" = 'Linux' ]; then
if ! command -v bash >/dev/null 2>&1 || ! command -v git >/dev/null 2>&1; then
/bin/sh "${GITHUB_ACTION_PATH:?}/src/install-required-tools.sh"
fi
fi
bash=$(resolve_path bash)
if [ -z "${bash}" ]; then
bash=$(command -v bash 2>/dev/null || :)
if [ -z "${bash}" ]; then
bail "this action requires bash"
elif [ -n "${HAS_TOKEN}" ]; then
bail "bash is unavailable at standard location; found ${bash}; aborting due to security reasons because 'token' input option is set"
else
warn "bash is unavailable at standard location; using ${bash}, but this may be blocked for security reasons in the future"
fi
fi
"${bash}" --noprofile --norc --posix "${GITHUB_ACTION_PATH:?}/src/main.sh"
# Unset environment variables that may unexpectedly affect sh/bash behavior.
# - Environment variables that may unexpectedly affect sh/bash behavior
# must be unset here.
# - Environment variables that also affect env command behavior must be
# replaced with harmless values in env field. e.g., LD_*, DYLD_*
# - For such environment variables for other commands, unset them in
# script as needed.
# We unset the followings here:
# - IFS, CDPATH, ENV, BASH_ENV, PS4, GLOBIGNORE, BASHOPTS, SHELLOPTS, FPATH:
# See:
# - https://github.com/sudo-project/sudo/blob/a40200a08a52515db4bc259c0153e7cd92f309ad/plugins/sudoers/env.c#L133
# - https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html#Invoked-with-unequal-effective-and-real-uid_002fgids
# - *builtin*, *[*, *printf*, *command*, *read*:
# Bash supports injecting function via environment variable:
# - Since CVE-2014-6271 fix: BASH_FUNC_func%%='() { ..; }'
# - Red Hat uses the different style in old versions (RHEL 5-7): BASH_FUNC_func()='() { ..; }'
# - Apple also uses the different style in old versions: __BASH_FUNC<func>()='() { ..; }'
# - Until CVE-2014-6271 fix: func='() { ..; }'
# This affects even when bash launched as /bin/sh (i.e., in POSIX mode).
# See tools/ci/test-bash-func.sh for known affected/unaffected builtins.
# We do the following to address this issue:
# - Unset all style of environment variables that may inject bash function
# for these builtins.
# The latter four are needed because builtin command may not be available
# in POSIX sh (i.e., scripts in action.yml and src/src/install-required-tools.sh,
# and credential helper in main.sh).
# Windows step removes all environment variables with value staring with '() {',
# and sudo does similar, but it is difficult to do the same thing correctly in
# a portable way. See tools/ci/test-list-bash-func-*.sh for details.
# - Use POSIX mode in bash scripts to reduce the number of affected builtins,
# and call affected builtins via "builtin" command.
# The uses of affected builtins are detected by tools/ci/test-bash-func.sh.
# NB: Sync with Windows step.
shell: '/usr/bin/env -u IFS -u CDPATH -u ENV -u BASH_ENV -u PS4 -u GLOBIGNORE -u BASHOPTS -u SHELLOPTS -u FPATH -u builtin -u BASH_FUNC_builtin%% -u BASH_FUNC_builtin() -u __BASH_FUNC<builtin>() -u [ -u BASH_FUNC_[%% -u BASH_FUNC_[() -u __BASH_FUNC<[>() -u printf -u BASH_FUNC_printf%% -u BASH_FUNC_printf() -u __BASH_FUNC<printf>() -u command -u BASH_FUNC_command%% -u BASH_FUNC_command() -u __BASH_FUNC<command>() -u read -u BASH_FUNC_read%% -u BASH_FUNC_read() -u __BASH_FUNC<read>() /bin/sh -eu {0}' # zizmor: ignore[misfeature] false positive
env:
# NB: Sync with Windows step.
INPUT_TOKEN: ${{ inputs.token }}
INPUT_FETCH_DEPTH: ${{ inputs.fetch-depth }}
# TODO: support in input options
INPUT_REPOSITORY: ${{ github.repository }}
INPUT_SERVER_URL: ${{ github.server_url }}
INPUT_SHA: ${{ github.sha }}
INPUT_REF: ${{ github.ref }}
HAS_TOKEN: ${{ inputs.token && '1' || '' }}
RUNNER_OS: ${{ runner.os }}
# Unset environment variables that may unexpectedly affect env/sh/bash/etc. behavior.
# Since these may also affect env command, they must be replaced with harmless values before it is called.
# for Linux
# Refs:
# - "Secure-execution mode" in https://man7.org/linux/man-pages/man8/ld.so.8.html
# - https://musl.libc.org/manual.html
LD_AUDIT: ''
LD_DEBUG: ''
LD_DEBUG_OUTPUT: ''
LD_DYNAMIC_WEAK: ''
LD_HWCAP_MASK: ''
LD_LIBRARY_PATH: ''
LD_ORIGIN_PATH: ''
LD_PRELOAD: ''
LD_PROFILE: ''
# for macOS
DYLD_INSERT_LIBRARIES: ''
DYLD_FRAMEWORK_PATH: ''
DYLD_LIBRARY_PATH: ''
DYLD_FALLBACK_FRAMEWORK_PATH: ''
DYLD_FALLBACK_LIBRARY_PATH: ''
DYLD_VERSIONED_FRAMEWORK_PATH: ''
DYLD_VERSIONED_LIBRARY_PATH: ''
if: runner.os != 'Windows'
# Use pwsh and retry on bash startup failure to work around windows-11-arm runner bug:
# https://github.com/actions/partner-runner-images/issues/169
- run: |
# Checkout (Windows)
Set-StrictMode -Version Latest
# Unset environment variables that may unexpectedly affect sh/bash behavior.
# See comment on shell field in action.yml for more.
# NB: Sync with it.
$remove_env = @('IFS','CDPATH','ENV','BASH_ENV','PS4','GLOBIGNORE','BASHOPTS','SHELLOPTS','FPATH')
foreach ($name in $remove_env) {
if (Test-Path -LiteralPath "Env:$name") { Remove-Item -LiteralPath "Env:\$name" }
}
# NB: Sync with tools/ci/test-bash-func-pwsh.ps1.
(Get-ChildItem Env:*) | ForEach-Object {
# -LiteralPath is important since BASH_FUNC_[%% is valid environment variable to override [.
if ($_.Value.StartsWith("() {")) { Remove-Item -LiteralPath "Env:\$($_.Key)" }
}
# Use binaries available at standard location to prevent path interception.
$bash = (Get-Command bash).Path
switch ($bash) {
"C:\Program Files\Git\bin\bash.exe" {} # default
"C:\msys64\usr\bin\bash.exe" {} # MSYS2
"C:\tools\cygwin\bin\bash.exe" {} # Cygwin
default {
if (Test-Path -LiteralPath "C:\Program Files\Git\bin\bash.exe") {
$bash = "C:\Program Files\Git\bin\bash.exe"
} elseif (Test-Path -LiteralPath "C:\msys64\usr\bin\bash.exe") {
$bash = "C:\msys64\usr\bin\bash.exe"
} elseif (Test-Path -LiteralPath "C:\tools\cygwin\bin\bash.exe") {
$bash = "C:\tools\cygwin\bin\bash.exe"
} elseif ("$bash" -eq "") {
Write-Output "::error::checkout-action: this action requires bash"
exit 1
} elseif ("$env:HAS_TOKEN" -ne "") {
Write-Output "::error::checkout-action: bash is unavailable at standard location; found $bash; aborting due to security reasons because 'token' input option is set"
exit 1
} else {
Write-Output "::warning::checkout-action: bash is unavailable at standard location; using $bash, but this may be blocked for security reasons in the future"
}
}
}
for ($i=1; $i -le 10; $i++) {
$prev_err_action = $ErrorActionPreference
$ErrorActionPreference = "Continue"
& "$bash" --noprofile --norc --posix "$env:GITHUB_ACTION_PATH\src\main.sh"
$code = $LASTEXITCODE
$ErrorActionPreference = "$prev_err_action"
if (Test-Path -LiteralPath "$env:USERPROFILE\.checkout-action-init") {
# If bash started successfully, src/main.sh creates init file.
Remove-Item -LiteralPath "$env:USERPROFILE\.checkout-action-init" -Force
exit $code
}
if ($i -lt 10) {
Write-Output "::warning::checkout-action: checkout failed due to bash startup failure (<https://github.com/actions/partner-runner-images/issues/169>); retrying..."
}
}
Write-Output "::error::checkout-action: checkout failed due to bash startup failure (<https://github.com/actions/partner-runner-images/issues/169>); this maybe resolved by re-running job"
exit 1
shell: pwsh
env:
# NB: Sync with non-Windows step.
INPUT_TOKEN: ${{ inputs.token }}
INPUT_FETCH_DEPTH: ${{ inputs.fetch-depth }}
# TODO: support in input options
INPUT_REPOSITORY: ${{ github.repository }}
INPUT_SERVER_URL: ${{ github.server_url }}
INPUT_SHA: ${{ github.sha }}
INPUT_REF: ${{ github.ref }}
HAS_TOKEN: ${{ inputs.token && '1' || '' }}
RUNNER_OS: ${{ runner.os }}
if: runner.os == 'Windows'