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)