gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/tools/make_apt.sh (about) 1 #!/bin/bash 2 3 # Copyright 2018 The gVisor Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 if [[ "$#" -le 3 ]]; then 18 echo "usage: $0 <private-key> <suite> <root> <packages...>" 19 exit 1 20 fi 21 declare private_key 22 declare suite 23 declare root 24 private_key="$(readlink -e "$1")" 25 suite="$2" 26 root="$(readlink -m "$3")" 27 readonly private_key 28 readonly suite 29 readonly root 30 shift; shift; shift # For "$@" below. 31 32 # Ensure that we have the correct packages installed. 33 export DEBIAN_FRONTEND=noninteractive 34 function apt_install() { 35 while true; do 36 sudo -E apt-get update && 37 sudo -E apt-get install -y "$@" && 38 true 39 result="${?}" 40 case $result in 41 0) 42 break 43 ;; 44 100) 45 # 100 is the error code that apt-get returns. 46 ;; 47 *) 48 exit $result 49 ;; 50 esac 51 done 52 } 53 dpkg-sig --help >/dev/null 2>&1 || apt_install dpkg-sig 54 apt-ftparchive --help >/dev/null 2>&1 || apt_install apt-utils 55 xz --help >/dev/null 2>&1 || apt_install xz-utils 56 57 # Verbose from this point. 58 set -xeo pipefail 59 60 # Create a directory for the release. 61 declare -r release="${root}/dists/${suite}" 62 mkdir -p "${release}" 63 64 # Create a temporary keyring, and ensure it is cleaned up. 65 # Using separate homedir allows us to install apt repositories multiple times 66 # using the same key. This is a limitation in GnuPG pre-2.1. 67 declare keyring 68 declare homedir 69 declare gpg_opts 70 keyring="$(mktemp /tmp/keyringXXXXXX.gpg)" 71 homedir="$(mktemp -d /tmp/homedirXXXXXX)" 72 gpg_opts=("--no-default-keyring" "--secret-keyring" "${keyring}" "--homedir" "${homedir}") 73 readonly keyring 74 readonly homedir 75 readonly gpg_opts 76 cleanup() { 77 rm -rf "${keyring}" "${homedir}" 78 } 79 trap cleanup EXIT 80 81 # We attempt the import twice because the first one will fail if the public key 82 # is not found. This isn't actually a failure for us, because we don't require 83 # the public key (this may be stored separately). The second import will succeed 84 # because, in reality, the first import succeeded and it's a no-op. 85 declare keyid 86 keyid=$( 87 (gpg "${gpg_opts[@]}" --import "${private_key}" 2>&1 || 88 gpg "${gpg_opts[@]}" --import "${private_key}" 2>&1) | 89 grep "secret key imported" | 90 head -1 | 91 cut -d':' -f2 | 92 awk '{print $2;}') 93 readonly keyid 94 95 # Copy the packages into the pool. 96 for pkg in "$@"; do 97 if ! [[ -f "${pkg}" ]]; then 98 continue 99 fi 100 ext=${pkg##*.} 101 if [[ "${ext}" != "deb" ]]; then 102 continue 103 fi 104 105 # Extract package information. 106 name=$(basename "${pkg}" ".${ext}") 107 arch=$(dpkg --info "${pkg}" | grep 'Architecture:' | cut -d':' -f2) 108 version=$(dpkg --info "${pkg}" | grep 'Version:' | cut -d':' -f2) 109 arch=${arch// /} # Trim whitespace. 110 version=${version// /} # Ditto. 111 destdir="${root}/pool/${version}/binary-${arch}" 112 113 # Copy & sign the package, only if not in the pool already. 114 mkdir -p "${destdir}" 115 if ! [[ -f "${destdir}/${name}.deb" ]]; then 116 # Copy the file. 117 cp -a -L "$(dirname "${pkg}")/${name}.deb" "${destdir}" 118 chmod 0644 "${destdir}"/"${name}".deb 119 # Sign a package only if it isn't signed yet. 120 # We use [*] here to expand the gpg_opts array into a single shell-word. 121 dpkg-sig -g "${gpg_opts[*]}" --verify "${destdir}/${name}.deb" || 122 dpkg-sig -g "${gpg_opts[*]}" --sign builder -k "${keyid}" "${destdir}/${name}.deb" 123 fi 124 if [[ -f "$(dirname "${pkg}")/${name}.changes" ]] && ! [[ -f "${destdir}/${name}.changes" ]]; then 125 # Copy the changes file. 126 cp -a -L "$(dirname "${pkg}")/${name}.changes" "${destdir}" 127 chmod 0644 "${destdir}"/"${name}".changes 128 fi 129 done 130 131 # Build the package list. 132 declare arches=() 133 for dir in "${root}"/pool/*/binary-*; do 134 name=$(basename "${dir}") 135 arch=${name##binary-} 136 arches+=("${arch}") 137 repo_packages="${release}"/main/"${name}" 138 mkdir -p "${repo_packages}" 139 (cd "${root}" && apt-ftparchive packages "${dir##${root}/}" > "${repo_packages}"/Packages) 140 if ! [[ -s "${repo_packages}"/Packages ]]; then 141 echo "Packages file is size zero." >&2 142 exit 1 143 fi 144 (cd "${repo_packages}" && cat Packages | gzip > Packages.gz) 145 (cd "${repo_packages}" && cat Packages | xz > Packages.xz) 146 done 147 148 # Build the release list. 149 cat > "${release}"/apt.conf <<EOF 150 APT { 151 FTPArchive { 152 Release { 153 Architectures "${arches[@]}"; 154 Suite "${suite}"; 155 Components "main"; 156 Origin "Google"; 157 }; 158 }; 159 }; 160 EOF 161 (cd "${release}" && apt-ftparchive -c=apt.conf release . > Release) 162 rm "${release}"/apt.conf 163 164 # Sign the release. 165 declare -r digest_opts=("--digest-algo" "SHA512" "--cert-digest-algo" "SHA512") 166 (cd "${release}" && rm -f Release.gpg InRelease) 167 (cd "${release}" && gpg "${gpg_opts[@]}" --clearsign "${digest_opts[@]}" -o InRelease Release) 168 (cd "${release}" && gpg "${gpg_opts[@]}" -abs "${digest_opts[@]}" -o Release.gpg Release)