Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions generation/cosign/generate_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -euo pipefail

# This generates install.sh.
# Usage:
# $ ./generate_install.sh v3.0.4 > ../../src/cosign/install.sh

version="${1:?Error: first argument must be a git revision}"
cosign_installer_url="https://raw.githubusercontent.com/sigstore/cosign-installer/${version:?}/action.yml"

action_yaml=$(curl --no-progress-meter --fail "${cosign_installer_url:?}") || {
echo "Error: failed to download cosign-installer's Action YAML from ${cosign_installer_url:?}" >&2;
exit 1
}
action_yaml_sha256=$(sha256sum - <<<"$action_yaml" | awk '{print $1}')
default_version=$(yq -er '.inputs["cosign-release"].default' - <<<"$action_yaml")

# actions.yaml uses these placeholders:
# ${{ inputs.cosign-release }}
# ${{ inputs.install-dir }}
# ${{ inputs.use-sudo }}
# ${{ runner.arch }}
# ${{ runner.os }}

# shellcheck disable=SC2016
install_script=$(yq -er '
.runs.steps[0].run
| gsub("\\${{ *inputs.cosign-release *}}"; "${COSIGN_VERSION:?}")
| gsub("\\${{ *inputs.install-dir *}}"; "${INSTALL_DIR:?}")
| gsub("\\${{ *inputs.use-sudo *}}"; "${USE_SUDO:?}")
| gsub("\\${{ *runner.arch *}}"; "${GHACTIONS_ARCH:?}")
| gsub("\\${{ *runner.os *}}"; "${GHACTIONS_OS:?}")
| (match("\\${{ *[^} ]+ *}}")
| error("Actions placeholder remained after replacing known placeholders: \(.string)")
) // .
' - <<<"${action_yaml:?}")

cat<<<"\
$(head -n 1 <<<"${install_script:?}" `# shebang`)
#
# This install script was automatically extracted from the official
# cosign-installer GitHub Action:
# ${cosign_installer_url:?}
# sha256: ${action_yaml_sha256:?}
#
COSIGN_VERSION=\${VERSION:-${default_version:?}}
INSTALL_DIR=\${INSTALLDIR:?}
USE_SUDO=\${USESUDO:?}

declare -A GHACTIONS_ARCH_NAMES=([aarch64]=ARM64 [x86_64]=X64)
GHACTIONS_ARCH=\${GHACTIONS_ARCH_NAMES[\$(uname -m)]:-}
if [[ \$GHACTIONS_ARCH == \"\" ]]; then
echo \"Error: unsupported CPU architecture: \$(uname -m)\" >&2
exit 1
fi
GHACTIONS_OS=\$(uname -s)

. ensure_command.sh
ensure_command curl

$(tail -n +2 <<<"${install_script:?}")"
26 changes: 26 additions & 0 deletions src/cosign/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "Sigstore cosign",
"id": "cosign",
"version": "1.0.0",
"description": "Install Sigstore cosign ( https://www.sigstore.dev/ ), a signature verification & creation tool.",
"options": {
"version": {
"type": "string",
"proposals": ["v2.0.2"],
"default": "",
"description": "cosign release version to be installed"
},
"installDir": {
"type": "string",
"proposals": ["/usr/local/bin"],
"default": "/usr/local/bin",
"description": "Where to install the cosign binary"
},
"useSudo": {
"type": "boolean",
"default": false,
"description": "set to true if installDir location requires sudo to write"
}
},
"installsAfter": ["ghcr.io/devcontainers/features/common-utils"]
}
28 changes: 28 additions & 0 deletions src/cosign/ensure_command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ensure_apt_updated() {
if [ "${_apt_updated:-}" != "true" ]; then
apt-get update
_apt_updated=true
fi
}

ensure_command() {
command=${1:?}
package=${2:-$command}

if ! which "$command" >/dev/null; then
ensure_package "$package"
fi
}

ensure_package() {
package=${1:?}
if which apt-get >/dev/null; then
ensure_apt_updated
apt-get -y install "$package"
elif which apk >/dev/null; then
apk add "${package}"
else
echo "Unable to install $package, no supported package manager found" >&2
exit 1
fi
}
246 changes: 246 additions & 0 deletions src/cosign/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
#!/bin/bash
#
# This install script was automatically extracted from the official
# cosign-installer GitHub Action:
# https://raw.githubusercontent.com/sigstore/cosign-installer/v3.0.4/action.yml
# sha256: bc1c34cefc456b4eb4b8e96992d83462984138ad418b5500006ac0e978274b9f
#
COSIGN_VERSION=${VERSION:-v2.0.2}
INSTALL_DIR=${INSTALLDIR:?}
USE_SUDO=${USESUDO:?}

declare -A GHACTIONS_ARCH_NAMES=([aarch64]=ARM64 [x86_64]=X64)
GHACTIONS_ARCH=${GHACTIONS_ARCH_NAMES[$(uname -m)]:-}
if [[ $GHACTIONS_ARCH == "" ]]; then
echo "Error: unsupported CPU architecture: $(uname -m)" >&2
exit 1
fi
GHACTIONS_OS=$(uname -s)

. ensure_command.sh
ensure_command curl

# cosign install script
shopt -s expand_aliases
if [ -z "$NO_COLOR" ]; then
alias log_info="echo -e \"\033[1;32mINFO\033[0m:\""
alias log_error="echo -e \"\033[1;31mERROR\033[0m:\""
else
alias log_info="echo \"INFO:\""
alias log_error="echo \"ERROR:\""
fi
set -e

mkdir -p ${INSTALL_DIR:?}

if [[ ${COSIGN_VERSION:?} == "main" ]]; then
log_info "installing cosign via 'go install' from its main version"
GOBIN=$(go env GOPATH)/bin
go install github.com/sigstore/cosign/cmd/cosign@main
ln -s $GOBIN/cosign ${INSTALL_DIR:?}/cosign
exit 0
fi

shaprog() {
case ${GHACTIONS_OS:?} in
Linux)
sha256sum $1 | cut -d' ' -f1
;;
macOS)
shasum -a256 $1 | cut -d' ' -f1
;;
Windows)
powershell -command "(Get-FileHash $1 -Algorithm SHA256 | Select-Object -ExpandProperty Hash).ToLower()"
;;
*)
log_error "unsupported OS ${GHACTIONS_OS:?}"
exit 1
;;
esac
}

bootstrap_version='v2.0.2'
bootstrap_linux_amd64_sha='dc641173cbda29ba48580cdde3f80f7a734f3b558a25e5950a4b19f522678c70'
bootstrap_linux_arm_sha='686ef6160889e84e5710505345b5b55cef0873907d0ef5954c837d9d647cf169'
bootstrap_linux_arm64_sha='517e96f9d036c4b77db01132cacdbef21e4266e9ad3a93e67773c590ba54e26f'
bootstrap_darwin_amd64_sha='0f51cbe19a315b919e87042f0485331821722ecb7fce22cc1b880ed4833fc8b0'
bootstrap_darwin_arm64_sha='55242a52ebca43dfb133d0fe26e11546bfa4571addd6852d782c119d74deade1'
bootstrap_windows_amd64_sha='782fcc768fca4dea9eb7464032de4b3e602f8d605b71bae686762e7622faa9ca'
cosign_executable_name=cosign

trap "popd >/dev/null" EXIT

pushd ${INSTALL_DIR:?} > /dev/null

case ${GHACTIONS_OS:?} in
Linux)
case ${GHACTIONS_ARCH:?} in
X64)
bootstrap_filename='cosign-linux-amd64'
bootstrap_sha=${bootstrap_linux_amd64_sha}
desired_cosign_filename='cosign-linux-amd64'
# v0.6.0 had different filename structures from all other releases
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
desired_cosign_filename='cosign_linux_amd64'
desired_cosign_v060_signature='cosign_linux_amd64_0.6.0_linux_amd64.sig'
fi
;;

ARM)
bootstrap_filename='cosign-linux-arm'
bootstrap_sha=${bootstrap_linux_arm_sha}
desired_cosign_filename='cosign-linux-arm'
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
log_error "linux-arm build not available at v0.6.0"
exit 1
fi
;;

ARM64)
bootstrap_filename='cosign-linux-arm64'
bootstrap_sha=${bootstrap_linux_arm64_sha}
desired_cosign_filename='cosign-linux-arm64'
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
log_error "linux-arm64 build not available at v0.6.0"
exit 1
fi
;;

*)
log_error "unsupported architecture $arch"
exit 1
;;
esac
;;

macOS)
case ${GHACTIONS_ARCH:?} in
X64)
bootstrap_filename='cosign-darwin-amd64'
bootstrap_sha=${bootstrap_darwin_amd64_sha}
desired_cosign_filename='cosign-darwin-amd64'
# v0.6.0 had different filename structures from all other releases
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
desired_cosign_filename='cosign_darwin_amd64'
desired_cosign_v060_signature='cosign_darwin_amd64_0.6.0_darwin_amd64.sig'
fi
;;

ARM64)
bootstrap_filename='cosign-darwin-arm64'
bootstrap_sha=${bootstrap_darwin_arm64_sha}
desired_cosign_filename='cosign-darwin-arm64'
# v0.6.0 had different filename structures from all other releases
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
desired_cosign_filename='cosign_darwin_arm64'
desired_cosign_v060_signature='cosign_darwin_arm64_0.6.0_darwin_arm64.sig'
fi
;;

*)
log_error "unsupported architecture $arch"
exit 1
;;
esac
;;

Windows)
case ${GHACTIONS_ARCH:?} in
X64)
bootstrap_filename='cosign-windows-amd64.exe'
bootstrap_sha=${bootstrap_windows_amd64_sha}
desired_cosign_filename='cosign-windows-amd64.exe'
cosign_executable_name=cosign.exe
# v0.6.0 had different filename structures from all other releases
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
desired_cosign_filename='cosign_windows_amd64.exe'
desired_cosign_v060_signature='cosign_windows_amd64_0.6.0_windows_amd64.exe.sig'
fi
;;
*)
log_error "unsupported architecture $arch"
exit 1
;;
esac
;;
*)
log_error "unsupported architecture $arch"
exit 1
;;
esac

SUDO=
if [[ "${USE_SUDO:?}" == "true" ]] && command -v sudo >/dev/null; then
SUDO=sudo
fi

expected_bootstrap_version_digest=${bootstrap_sha}
log_info "Downloading bootstrap version '${bootstrap_version}' of cosign to verify version to be installed...\n https://storage.googleapis.com/cosign-releases/${bootstrap_version}/${bootstrap_filename}"
$SUDO curl -sL https://storage.googleapis.com/cosign-releases/${bootstrap_version}/${bootstrap_filename} -o ${cosign_executable_name}
shaBootstrap=$(shaprog ${cosign_executable_name});
if [[ $shaBootstrap != ${expected_bootstrap_version_digest} ]]; then
log_error "Unable to validate cosign version: '${COSIGN_VERSION:?}'"
exit 1
fi
$SUDO chmod +x ${cosign_executable_name}

# If the bootstrap and specified `cosign` releases are the same, we're done.
if [[ ${COSIGN_VERSION:?} == ${bootstrap_version} ]]; then
log_info "bootstrap version successfully verified and matches requested version so nothing else to do"
exit 0
fi

semver='^v([0-9]+\.){0,2}(\*|[0-9]+)(-?r?c?)(\.[0-9]+)$'
if [[ ${COSIGN_VERSION:?} =~ $semver ]]; then
log_info "Custom cosign version '${COSIGN_VERSION:?}' requested"
else
log_error "Unable to validate requested cosign version: '${COSIGN_VERSION:?}'"
exit 1
fi

# Download custom cosign
log_info "Downloading platform-specific version '${COSIGN_VERSION:?}' of cosign...\n https://storage.googleapis.com/cosign-releases/${COSIGN_VERSION:?}/${desired_cosign_filename}"
$SUDO curl -sL https://storage.googleapis.com/cosign-releases/${COSIGN_VERSION:?}/${desired_cosign_filename} -o cosign_${COSIGN_VERSION:?}
shaCustom=$(shaprog cosign_${COSIGN_VERSION:?});

# same hash means it is the same release
if [[ $shaCustom != $shaBootstrap ]]; then
if [[ ${COSIGN_VERSION:?} == 'v0.6.0' && ${GHACTIONS_OS:?} == 'Linux' ]]; then
# v0.6.0's linux release has a dependency on `libpcsclite1`
log_info "Installing libpcsclite1 package if necessary..."
set +e
sudo dpkg -s libpcsclite1
if [ $? -eq 0 ]; then
log_info "libpcsclite1 package is already installed"
else
log_info "libpcsclite1 package is not installed, installing it now."
sudo apt-get update -q -q
sudo apt-get install -yq libpcsclite1
fi
set -e
fi

if [[ ${COSIGN_VERSION:?} == 'v0.6.0' ]]; then
log_info "Downloading detached signature for platform-specific '${COSIGN_VERSION:?}' of cosign...\n https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION:?}/${desired_cosign_v060_signature}"
$SUDO curl -sL https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION:?}/${desired_cosign_v060_signature} -o ${desired_cosign_filename}.sig
else
log_info "Downloading detached signature for platform-specific '${COSIGN_VERSION:?}' of cosign...\n https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION:?}/${desired_cosign_filename}.sig"
$SUDO curl -sLO https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION:?}/${desired_cosign_filename}.sig
fi

if [[ ${COSIGN_VERSION:?} < 'v0.6.0' ]]; then
log_info "Downloading cosign public key '${COSIGN_VERSION:?}' of cosign...\n https://raw.githubusercontent.com/sigstore/cosign/${COSIGN_VERSION:?}/.github/workflows/cosign.pub"
RELEASE_COSIGN_PUB_KEY=https://raw.githubusercontent.com/sigstore/cosign/${COSIGN_VERSION:?}/.github/workflows/cosign.pub
else
log_info "Downloading cosign public key '${COSIGN_VERSION:?}' of cosign...\n https://raw.githubusercontent.com/sigstore/cosign/${COSIGN_VERSION:?}/release/release-cosign.pub"
RELEASE_COSIGN_PUB_KEY=https://raw.githubusercontent.com/sigstore/cosign/${COSIGN_VERSION:?}/release/release-cosign.pub
fi

log_info "Using bootstrap cosign to verify signature of desired cosign version"
./cosign verify-blob --insecure-ignore-tlog --key $RELEASE_COSIGN_PUB_KEY --signature ${desired_cosign_filename}.sig cosign_${COSIGN_VERSION:?}

$SUDO rm cosign
$SUDO mv cosign_${COSIGN_VERSION:?} ${cosign_executable_name}
$SUDO chmod +x ${cosign_executable_name}
log_info "Installation complete!"
fi
10 changes: 10 additions & 0 deletions test/cosign/scenarios.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"verify_self": {
"image": "ubuntu:focal",
"features": {
"cosign": {
"version": "v2.0.2"
}
}
}
}
9 changes: 9 additions & 0 deletions test/cosign/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -e

# https://github.com/devcontainers/cli/blob/main/docs/features/test.md
source dev-container-features-test-lib

check "cosign command available" cosign version

reportResults
Loading