├── .travis.yml ├── bin ├── travis-sort-uniq-whitelist ├── travis-list-apt-whitelist-issues └── travis-download-deb-sources ├── CONTRIBUTING.md ├── Makefile ├── LICENSE ├── Vagrantfile ├── make_pr.sh └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: bash 2 | sudo: false 3 | env: 4 | - DISTRO=ubuntu-precise 5 | 6 | script: 7 | - diff -u "${DISTRO}" <(./bin/travis-sort-uniq-whitelist "${DISTRO}") 8 | - bash -n make_pr.sh 9 | -------------------------------------------------------------------------------- /bin/travis-sort-uniq-whitelist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | def main 4 | whitelist = ARGV.first 5 | abort 'Missing whitelist' if whitelist.nil? 6 | 7 | puts File.read(whitelist).split($/).map(&:strip).sort.uniq.reject(&:empty?).join($/) 8 | 0 9 | end 10 | 11 | exit(main) if $PROGRAM_NAME == __FILE__ 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Requesting APT package for Travis CI [apt addon](http://docs.travis-ci.com/user/apt/) 2 | 3 | This repository lists the APT packages you can install on the 4 | [container-based builds](http://docs.travis-ci.com/user/workers/container-based-infrastructure/). 5 | 6 | Be sure to read [Package approval process](README.md#package-approval-process) 7 | before opening an issue to make a request. 8 | The package you are looking for may already be available. 9 | 10 | Please note that we are very reluctant to accept pull requests into this repository. 11 | 12 | Thank you for your understanding. 13 | -------------------------------------------------------------------------------- /bin/travis-list-apt-whitelist-issues: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o pipefail 4 | set -o errexit 5 | 6 | curl -s 'https://api.github.com/search/issues?q=is:issue+is:open+APT+whitelist+repo:travis-ci/travis-ci' | \ 7 | jq '.items | 8 | .[] | 9 | { 10 | packages: .title[26:], 11 | body: .body, 12 | number: .number, 13 | commit_message: ([ 14 | "# (begin generated commit message)", 15 | (["Add", .title[26:], "to ubuntu-precise"] | join(" ")), 16 | "", 17 | (["Closes travis-ci/travis-ci", (.number | tostring)] | join("#")), 18 | "# (end generated commit message)" 19 | ] | join("\n")) 20 | }' 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /usr/bin/env bash 2 | 3 | DISTROS ?= ubuntu-precise 4 | DISTRO ?= ubuntu-precise 5 | PACKAGE ?= 6 | 7 | .PHONY: help 8 | help: 9 | @echo "Usage: make [args]" 10 | @echo 11 | @echo "Available targets:" 12 | @echo " sort - sort $(DISTROS) in place" 13 | @echo " add - add a package and sort, e.g. 'make add PACKAGE=foo DISTRO=ubuntu-precise'" 14 | @echo 15 | @echo "Defaults:" 16 | @echo " DISTRO='$(DISTRO)'" 17 | @echo " DISTROS='$(DISTROS)'" 18 | @echo " PACKAGE='$(PACKAGE)'" 19 | @echo " SHELL='$(SHELL)'" 20 | 21 | .PHONY: sort 22 | sort: $(DISTROS) 23 | for distro in $^ ; do ./bin/travis-sort-uniq-whitelist $$distro > _tmp && mv _tmp $$distro ; done 24 | 25 | .PHONY: add 26 | add: 27 | [[ $(PACKAGE) ]] && echo $(PACKAGE) >> $(DISTRO) ; $(MAKE) sort 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Travis CI 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | PROVISION_SCRIPTS = [ 2 | <<-EOF, 3 | export DEBIAN_FRONTEND=noninteractive 4 | 5 | apt-get update -y 6 | apt-get install -yq lvm2 xfsprogs 7 | EOF 8 | 9 | <<-EOF, 10 | if ! command -v docker ; then 11 | curl -sSL https://get.docker.io | bash 12 | fi 13 | EOF 14 | 15 | 'usermod -a -G docker vagrant', 16 | 'usermod -a -G docker ubuntu', 17 | 'docker pull quay.io/travisci/travis-ruby:latest', 18 | 19 | <<-EOF, 20 | if ! jq --version ; then 21 | curl -sSL -o /usr/local/bin/jq http://stedolan.github.io/jq/download/linux64/jq 22 | chmod 0755 /usr/local/bin/jq 23 | fi 24 | EOF 25 | 26 | <<-EOF, 27 | docker images | grep -q -E '^travis\\s+\\bruby\\b\\s+' || \\ 28 | docker tag quay.io/travisci/travis-ruby:latest travis:ruby 29 | EOF 30 | 31 | <<-EOF 32 | cp -v /vagrant/bin/travis-download-deb-sources /usr/local/bin/ 33 | chmod 0755 /usr/local/bin/travis-download-deb-sources 34 | EOF 35 | ] 36 | 37 | Vagrant.configure('2') do |config| 38 | config.vm.define 'trusty' do |trusty| 39 | trusty.vm.hostname = 'apt-package-whitelist-trusty' 40 | trusty.vm.box = 'ubuntu/trusty64' 41 | end 42 | 43 | config.vm.provider 'virtualbox' do |vbox| 44 | vbox.memory = 4096 45 | vbox.cpus = 2 46 | end 47 | 48 | PROVISION_SCRIPTS.each do |script| 49 | config.vm.provision 'shell', inline: <<-EOF, privileged: true 50 | set -o errexit 51 | set -o xtrace 52 | #{script} 53 | EOF 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /bin/travis-download-deb-sources: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | usage() { 6 | cat < 8 | 9 | Download the given package name inside the apt_packages container, starting the container if needed. 10 | EOF 11 | } 12 | 13 | start_apt_packages_container() { 14 | echo "---> Starting apt_packages container" 15 | docker run -v /var/tmp/shared:/var/tmp/shared -v /var/tmp/ssh:/home/travis/.ssh --name apt_packages -d travis:ruby || true 16 | sleep 10 17 | } 18 | 19 | PACKAGE_NAME="${1}" 20 | 21 | case "${PACKAGE_NAME}" in -h|--help|help|-?) usage ; exit 0 ;; esac 22 | [[ ${PACKAGE_NAME} ]] || { usage ; exit 1 ; } 23 | 24 | mkdir -p /var/tmp/shared/deb-sources /var/tmp/ssh 25 | 26 | if [[ ! -f /var/tmp/ssh/id_rsa.pub ]] ; then 27 | ssh-keygen -f /var/tmp/ssh/id_rsa -t rsa -b 2048 -N "" 28 | fi 29 | 30 | if [[ ! -s /var/tmp/ssh/authorized_keys ]] ; then 31 | cat /var/tmp/ssh/id_rsa.pub >> /var/tmp/ssh/authorized_keys 32 | fi 33 | 34 | chmod 0700 /var/tmp/ssh 35 | chmod 0644 /var/tmp/ssh/authorized_keys 36 | chmod 0600 /var/tmp/ssh/id_rsa* 37 | 38 | if [[ "$(docker ps -a | grep apt_packages)" ]] ; then 39 | echo "---> Found existing container named apt_packages, so removing" 40 | docker rm -f apt_packages || true 41 | fi 42 | 43 | start_apt_packages_container 44 | 45 | TMP_SCRIPT="/var/tmp/shared/download-deb-sources.$(date +%s)" 46 | 47 | CONTAINER_IP=$(docker inspect --format="{{.NetworkSettings.IPAddress}}" apt_packages) 48 | 49 | cat > "${TMP_SCRIPT}" <&2 64 | echo 65 | echo "---> The extracted ${PACKAGE_NAME} is in /var/tmp/shared/deb-sources" 66 | echo 67 | EOF 68 | 69 | chmod 0755 "${TMP_SCRIPT}" 70 | 71 | echo 72 | echo "---> Running ${TMP_SCRIPT} via ssh inside apt_packages container (travis@${CONTAINER_IP})" 73 | echo "---> HINT: The SSH password is 'travis'" 74 | echo 75 | exec ssh \ 76 | -i /var/tmp/ssh/id_rsa \ 77 | -o StrictHostKeyChecking=no \ 78 | -o UserKnownHostsFile=/dev/null \ 79 | travis@${CONTAINER_IP} sudo "${TMP_SCRIPT}" 80 | -------------------------------------------------------------------------------- /make_pr.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | ANSI_RED="\033[31;1m" 4 | ANSI_GREEN="\033[32;1m" 5 | ANSI_RESET="\033[0m" 6 | ANSI_CLEAR="\033[0K" 7 | 8 | EXIT_SUCCSS=0 9 | EXIT_SOURCE_NOT_FOUND=1 10 | EXIT_SOURCE_HAS_SETUID=2 11 | EXIT_NOTHING_TO_COMMIT=3 12 | 13 | DEFAULT_BRANCH=master 14 | 15 | create_pr=0 16 | has_setuid=0 17 | 18 | function notice() { 19 | msg=$1 20 | echo -e "\n${ANSI_GREEN}${msg}${ANSI_RESET}\n" 21 | } 22 | 23 | function warn() { 24 | msg=$1 25 | echo -e "\n${ANSI_RED}${msg}${ANSI_RESET}\n" 26 | } 27 | 28 | function usage() { 29 | echo "Usage: $0 [-y] repo issue_number [package [additional_packages …]]" 30 | } 31 | 32 | while getopts "sy" opt; do 33 | case "$opt" in 34 | s) 35 | has_setuid=1 36 | ;; 37 | y) 38 | create_pr=1 39 | ;; 40 | esac 41 | done 42 | 43 | shift $((OPTIND-1)) 44 | 45 | if [ $# -lt 2 ]; then 46 | usage 47 | exit 0 48 | fi 49 | 50 | ## Process arguments; nothing funcy 51 | 52 | ISSUE_REPO=$1 53 | shift 54 | ISSUE_NUMBER=$1 55 | shift 56 | 57 | PACKAGES=( $@ ) 58 | if [ -z "$PACKAGES" ]; then 59 | if [ -f $(dirname $0)/packages ]; then 60 | notice "Reading from $(dirname $0)/packages" 61 | PACKAGES=$(< $(dirname $0)/packages) 62 | else 63 | warn "Unable to determine packages to add" 64 | usage 65 | exit 1 66 | fi 67 | fi 68 | 69 | ISSUE_PACKAGE=$(echo $PACKAGES | cut -f1 -d' ') 70 | 71 | notice "Setting up PR with\nRepo: ${ISSUE_REPO}\nNUMBER: ${ISSUE_NUMBER}\nPackages: ${PACKAGES[*]}" 72 | 73 | BRANCH="test-${ISSUE_REPO}-${ISSUE_NUMBER}" 74 | notice "Setting up Git" 75 | 76 | if [ -z "`git config --get --global credential.helper`" ]; then 77 | notice "set up credential.helper" 78 | git config credential.helper "store --file=.git/credentials" 79 | echo "https://${GITHUB_OAUTH_TOKEN}:@github.com" > .git/credentials 2>/dev/null 80 | fi 81 | if [ -z "`git config --get --global user.email`" ]; then 82 | notice "set up user.email" 83 | git config --global user.email "contact@travis-ci.com" 84 | fi 85 | if [ -z "`git config --get --global user.name`" ]; then 86 | notice "set up user.name" 87 | git config --global user.name "Travis CI APT package tester" 88 | fi 89 | 90 | notice "Creating commit" 91 | git checkout $DEFAULT_BRANCH 92 | git checkout -b $BRANCH 93 | for p in ${PACKAGES[*]}; do 94 | notice "Adding ${p}" 95 | env PACKAGE=${p} make add > /dev/null 96 | done 97 | git add ubuntu-precise 98 | git commit -m "Add ${ISSUE_PACKAGE} to ubuntu-precise; resolves travis-ci/${ISSUE_REPO}#${ISSUE_NUMBER} 99 | 100 | Packages: ${PACKAGES}" 101 | 102 | COMMIT_EXIT_STATUS=$? 103 | if [ $COMMIT_EXIT_STATUS -gt 0 ]; then 104 | notice "Nothing to commit" 105 | exit $EXIT_NOTHING_TO_COMMIT 106 | fi 107 | 108 | notice "Pushing commit" 109 | 110 | if [ -z $GITHUB_OAUTH_TOKEN ]; then 111 | warn '$GITHUB_OAUTH_TOKEN not set' 112 | exit 1 113 | fi 114 | git push origin $BRANCH 115 | 116 | if [ $create_pr -le 0 ]; then 117 | # bail before creating a pr 118 | exit 0 119 | fi 120 | 121 | notice "Creating PR" 122 | COMMENT="Add packages: ${PACKAGES[*]}" 123 | if [ -n ${TRAVIS_BUILD_ID} ]; then 124 | COMMENT="${COMMENT}\n\nSee http://travis-ci.org/${TRAVIS_REPO_SLUG}/builds/${TRAVIS_BUILD_ID}." 125 | fi 126 | if [ ${has_setuid} -gt 0 ]; then 127 | COMMENT="\n\n***NOTE***\n\nsetuid/seteuid/setgid bits were found. Be sure to check the build result.\n\n${COMMENT}" 128 | fi 129 | curl -X POST -sS -H "Content-Type: application/json" -H "Authorization: token ${GITHUB_OAUTH_TOKEN}" \ 130 | -d "{\"title\":\"Pull request for ${ISSUE_PACKAGE}\",\"body\":\"Resolves travis-ci/${ISSUE_REPO}#${ISSUE_NUMBER}.\n${COMMENT}\",\"head\":\"${BRANCH}\",\"base\":\"master\"}" \ 131 | https://api.github.com/repos/travis-ci/apt-package-whitelist/pulls > pr_payload 132 | if [ $? -eq 0 -a ${has_setuid} -gt 0 ]; then 133 | curl -X POST -sS -H "Content-Type: application/json" -H "Authorization: token ${GITHUB_OAUTH_TOKEN}" \ 134 | -d "[\"textual-suid-present\"]" \ 135 | $(jq .issue_url pr_payload | cut -f2 -d\")/labels 136 | fi 137 | curl -X POST -sS -H "Content-Type: application/json" -H "Authorization: token ${GITHUB_OAUTH_TOKEN}" \ 138 | -d "[\"apt-whitelist-check-run\"]" \ 139 | https://api.github.com/repos/travis-ci/${ISSUE_REPO}/issues/${ISSUE_NUMBER}/labels 140 | 141 | git checkout $DEFAULT_BRANCH 142 | git branch -D $BRANCH 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # APT package whitelist 2 | 3 | This repo contains plain text files for the packages approved for installation in restricted build environments, 4 | specifically meant for use with the [`apt_packages` addon in 5 | travis-build](https://github.com/travis-ci/travis-build/blob/master/lib/travis/build/addons/apt_packages.rb). 6 | 7 | ## Package approval process 8 | 9 | CAUTION! 10 | 11 | **PLEASE READ CAREFULLY!** 12 | 13 | 0. Check the list of approved packages for your build environment (most likely [`ubuntu-precise`](./ubuntu-precise)). 14 | 0. If it's not in there, check for existing [issues](https://github.com/travis-ci/apt-package-whitelist/issues) 15 | and [pull requests](https://github.com/travis-ci/apt-package-whitelist/pulls) requesting the package you 16 | want, and if one doesn't exist please 17 | open an issue requesting the package you need in the [this 18 | repo](https://github.com/travis-ci/apt-package-whitelist/issues/new?title=APT+whitelist+request+for+___PACKAGE___) 19 | (and be sure to replace `__PACKAGE__` in the issue title). 20 | 21 | 0. Currently, we are in the process of automating request approval process. 22 | 1. This means that the issues' subject should follow exactly the one indicated. 23 | That is, there should be **exactly one package** per issue. 24 | The process would not work with multiple package requests in one issue. 25 | 1. If the source package defines multiple packages, those will be processed at once. 26 | In this case, list only one. 27 | 0. PRs are not accepted, since we have not run tests on them. 28 | 0. The automation process will test the source package as described below. 29 | 1. If no issues are found, a PR will be opened, and it will be merged shortly thereafter. 30 | 1. If no matching source packages is found, a comment indicating this is posted on the issue. 31 | This means that either the package name is incorrect, or that your request requires 32 | a package repository that is not currently listed in [APT source whitelist](https://github.com/travis-ci/apt-source-whitelist). 33 | 1. The command 34 | 35 | ```shell 36 | grep -R -i -H -C5 -E --color 'set(uid|euid|gid)' --exclude install-sh . 37 | ``` 38 | 39 | is run on the source package. 40 | If any file matches, a comment to this effect will be posted on the issue, prompting further examination. 41 | If no further problems are found in the further examination, it will be added to the list. 42 | 43 | ### nitty gritty details 44 | 45 | The approval process is mostly about ensuring the `.deb` installation hooks don't do anything malicious or goofy that 46 | would open up a container to potential attack from a neighbor. The primary concern is protecting Travis CI customers 47 | and their property :metal:. The steps go like this (for ubuntu precise), much of which is also available as the 48 | `travis-download-deb-sources` executable within the vagrant box: 49 | 50 | 0. Bring up the vagrant box: `vagrant up trusty` 51 | 0. SSH into the vagrant box: `vagrant ssh trusty` 52 | 0. Start the Travis Ruby container: `sudo -u ubuntu -i docker run -v /var/tmp:/var/tmp -d travis:ruby` 53 | 0. Get the container's IP address: `docker inspect ` 54 | 0. SSH into the container: `ssh travis@` (password=`travis`) 55 | 0. Freshen up the apt cache: `sudo apt-get update` 56 | 0. Move into the shared dir or sub directory, e.g.: `mkdir -p /var/tmp/deb-sources ; cd /var/tmp/deb-sources` 57 | 0. Grab the package sources: `apt-get source ` 58 | 0. Take a look at the package's extracted hooks: `cd /debian ; vim *pre* *post* *inst*` (see [inspecting packages](#inspecting-packages)) 59 | 0. If no malicious or goofy bits are found, :thumbsup: :shipit: 60 | 61 | #### `pre-commit` hook 62 | 63 | If you work with this repository, installing this `pre-commit` hook (in your local `~/.git/hooks/pre-commit`) 64 | will make your life so much easier: 65 | 66 | ```bash 67 | make sort 68 | git add ubuntu-{precise,trusty} 69 | ``` 70 | 71 | This ensures that the files we need are always sorted without duplicates or blank lines. 72 | 73 | ### The slightly simplified version: 74 | 75 | 0. Bring up the vagrant box: `vagrant up trusty` 76 | 0. SSH into the vagrant box: `vagrant ssh trusty` 77 | 0. Run the `travis-download-deb-sources` script for the package in question, e.g.: `sudo -u ubuntu -i travis-download-deb-sources git` 78 | 0. Proceed with inspecting the `debian/*pre*` and `debian/*post*` hook scripts. (see [inspecting packages](#inspecting-packages)) 79 | 80 | All together now, for `poppler-utils`: 81 | 82 | ``` bash 83 | # inside the vagrant box 84 | sudo -u ubuntu -i -- travis-download-deb-sources poppler-utils 85 | cd /var/tmp/shared/deb-sources/poppler-0.18.4/debian 86 | vi *{pre,post,inst}* 87 | ``` 88 | 89 | (If you don't have the `pre-commit` hook) 90 | ``` bash 91 | # either inside the vagrant box in /vagrant or outside in the repo top level 92 | make add PACKAGE=poppler-utils 93 | git commit -v 94 | ``` 95 | 96 | ### inspecting packages 97 | 98 | The big things to worry about are if any of the debian hook scripts are doing malicious or silly things, or if the 99 | package being installed depends on `setuid` or `setgid`. 100 | 101 | ``` bash 102 | # move into the `deb-sources` directory 103 | pushd /var/tmp/shared/deb-sources 104 | 105 | # look for `setuid`, `seteuid`, and `setgid` usage, except for mentions in `install-sh` 106 | grep -l -R -i -E 'set(uid|euid|gid)' . | grep -v -E '\binstall-sh\b' 107 | 108 | # if the above `grep` finds anything, take a closer look: 109 | vi $(grep -l -R -i -E 'set(uid|euid|gid)' . | grep -v -E '\binstall-sh\b') 110 | 111 | # move into the `debian` directory 112 | pushd $(find . -name debian | head -1) 113 | 114 | # take a look at the hook scripts and such 115 | shopt -s nullglob 116 | vi *{pre,post,inst}* 117 | ``` 118 | 119 | ### github API handy bits 120 | 121 | There is a helper script at `./bin/travis-list-apt-whitelist-issues` which may be used to query the open APT whitelist 122 | requests, as well as for automatic commit message formatting, e.g.: 123 | 124 | ``` bash 125 | # list everything 126 | ./bin/travis-list-apt-whitelist-issues 127 | 128 | # Show only the generated commit messages 129 | ./bin/travis-list-apt-whitelist-issues | jq -r .commit_message 130 | ``` 131 | 132 | ### @meatballhat's workflow 133 | 134 | First things first 135 | 136 | ``` bash 137 | shopt -s nullglob 138 | ``` 139 | 140 | Grab 1 or more packages 141 | 142 | ``` bash 143 | for pkg in abc def xyz ; do 144 | sudo -u ubuntu -- /usr/local/bin/travis-download-deb-sources "${pkg}" ; 145 | done 146 | ``` 147 | 148 | Edit any matches for `set(uid|euid|gid|egid)` 149 | 150 | ``` bash 151 | vim $(grep -l -R -i -E 'set(uid|euid|gid)' . | grep -v -E '\binstall-sh\b') 152 | ``` 153 | 154 | Edit any debian package files 155 | 156 | ``` bash 157 | for d in $(find . -name debian) ; do 158 | pushd $d && vim *{pre,post,inst}* ; popd ; 159 | done 160 | ``` 161 | 162 | If all clear, list all audited package names on one line 163 | 164 | ``` bash 165 | for d in $(find . -name debian) ; do 166 | pushd $d &>/dev/null && \ 167 | grep ^Package control | awk -F: '{ print $2 }' | xargs echo ; 168 | popd &>/dev/null ; 169 | done | xargs echo 170 | ``` 171 | 172 | Back outside of the Vagrant box, pass this list of packages for addition. Adding both the package name and its' `:i386` variant is not always necessary, but doesn't hurt. 173 | 174 | (If you don't have the `pre-commit` hook) 175 | 176 | ``` bash 177 | for pkg in abc def xyz ; do 178 | make add PACKAGE=$pkg 179 | make add PACKAGE=${pkg}:i386 180 | done 181 | ``` 182 | 183 | Grab the generated commit message 184 | 185 | ``` bash 186 | ./bin/travis-list-apt-whitelist-issues | jq -r '.commit_message' | grep -A2 abc 187 | ``` 188 | 189 | Commit and push, then restart all `travis-build` apps with a bit o' sleep 190 | 191 | ``` bash 192 | for app in $(hk apps | awk '/travis.*build-(prod|stag)/ { print $1 }') ; do 193 | hk restart -a ${app} ; 194 | sleep 5 ; 195 | done 196 | ``` 197 | --------------------------------------------------------------------------------