-
Notifications
You must be signed in to change notification settings - Fork 42
/
release.sh
executable file
·198 lines (164 loc) · 6.53 KB
/
release.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/bin/sh
##############################################
# release.sh #
# Automate rolling new trust store releases. #
##############################################
# Environment variables used by this script (note that sensible defaults
# will be used where applicable).
# - EXPIRATION_WINDOW: the minimum time certificates must be valid for
# in order to be included in the new release. The default is 0h, which
# includes all currently validate certificates. This must be parsable by
# Go's time package.
# - NOPUSH: do not push the release branch upstream.
# - ALLOW_SKIP_PR: allows the script to complete successfully without
# creating a release if there are no changes to the bundles. The
# intended use for this is the scheduled cronjob, we only want to
# create a release and PR if there are changes
# - TRUST_CONFIG_PATH: the path to a cfssl-trust configuration file. The
# default is to not specify a configuration file; the cfssl-trust program
# will check for one in the standard places.
# - TRUST_DATABASE_PATH: the path to the cfssl-trust cert database. This
# must either be specified here or in a configuration file.
# Fail on errors and undefined expansions; print what is being executed
# at every step.
set -eux
die () {
echo "$@" > /dev/stderr
exit 1
}
##########################
# PROLOGUE: release prep #
##########################
# Make sure we're in the git toplevel.
# If the path to a config file or certificate database are present as
# environment variables, then use those as flags to the cfssl-trust
# program.
CONFIG_PATH="${TRUST_CONFIG_PATH:-}"
if [ -n "${CONFIG_PATH}" ]
then
CONFIG_PATH="-f ${CONFIG_PATH}"
fi
DATABASE_PATH="${TRUST_DATABASE_PATH:-./cert.db}"
if [ -n "${DATABASE_PATH}" ]
then
DATABASE_PATH="-d ${DATABASE_PATH}"
fi
# The expiration window defaults to including all currently
# valid certificates.
EXPIRATION_WINDOW="${EXPIRATION_WINDOW:-0h}"
# We need to verify that we have the right tooling in place:
# cfssl-trust to perform the release, and certdump to produce
# a human-readable output of the trust stores.
check_for_tool () {
command -v $1 2>&1 > /dev/null
if [ $? -ne 0 ]
then
echo "Required tool $1 wasn't found." > /dev/stderr
die "Path is ${PATH}."
fi
}
prologue () {
check_for_tool cfssl-trust
check_for_tool certdump
check_for_tool mktemp
# This release script expects to be run from the repo's top level.
cd "$(git rev-parse --show-toplevel)" || exit 1
}
###########
# RELEASE #
###########
release () {
if [ "$(basename $(pwd))" != "cfssl_trust" ]
then
die "release.sh should be called from the cfssl_trust repository."
elif [ "$(pwd)" != "$(git rev-parse --show-toplevel)" ]
then
die "release.sh should be called from the git toplevel ($(git rev-parse --show-toplevel), cwd=$(pwd))."
fi
echo "Rolling trust store release at $(date +'%FT%T%z')."
## Step 1: roll the intermediate store.
#
# NB: the variables shouldn't be quoted in the command line invocations.
# The shell will interpret these as empty arguments. The most common
# symptom of this would be seeing the error "time: invalid duration" ---
# Go's time.ParseDuration function can't handle empty strings.
echo "$ cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -b int release ${EXPIRATION_WINDOW}"
cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -b int release ${EXPIRATION_WINDOW}
# After the intermediate store is rolled, we'll need to collect the
# new version number. cfssl-trust reports these in reverse
# chronological order, so we can grab the first one and remove the
# leading dash. This will serve as our release branch in git.
LATEST_RELEASE="$(cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} releases | awk ' NR==1 { print $2 }')"
## Step 2: roll the root store.
#
# The same caveats from step 1 apply
echo "$ cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -b ca release ${EXPIRATION_WINDOW}"
cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -b ca release ${EXPIRATION_WINDOW}
# Step 3: add any additional roots or intermediates.
if [ -n "${NEW_ROOTS:-}" ]
then
echo "Adding new roots:"
certdump ${NEW_ROOTS}
cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -b ca -r ${LATEST_RELEASE} import ${NEW_ROOTS}
fi
if [ -n "${NEW_INTERMEDIATES:-}" ]
then
echo "Adding new intermediates:"
certdump ${NEW_INTERMEDIATES}
cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -b int -r ${LATEST_RELEASE} import ${NEW_INTERMEDIATES}
fi
# Add the database changes to the release git branch.
git add cert.db
## Step 4: write the trust stores to disk.
#
# They also should be added to the release git branch.
echo "$ cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -r ${LATEST_RELEASE} -b int bundle int-bundle.crt"
cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -r ${LATEST_RELEASE} -b int bundle int-bundle.crt
echo "$ cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -r ${LATEST_RELEASE} -b ca bundle ca-bundle.crt"
cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} -r ${LATEST_RELEASE} -b ca bundle ca-bundle.crt
## Step 5: Silent early exit if no changes
#
# if we are allowing the script to silently complete without a release, we want see
# any changes to bundles and if not, exit with the "No_Changes" code for the caller
if [ "${ALLOW_SKIP_PR}" = "true" ] && [ -z "`git diff int-bundle.crt ca-bundle.crt | cat`" ]
then
echo "No_Changes"
exit 0
fi
git add int-bundle.crt ca-bundle.crt
## Step 6: update the human-readable trust store lists.
#
# These lists should also be added to git.
echo "$ certdump ca-bundle.crt > certdata/ca-bundle.txt"
certdump ca-bundle.crt > certdata/ca-bundle.txt
echo "$ certdump int-bundle.crt > certdata/int-bundle.txt"
certdump int-bundle.crt > certdata/int-bundle.txt
git add certdata/ca-bundle.txt certdata/int-bundle.txt
echo "$ git status --porcelain -uno"
git status --porcelain -uno
}
####################################
# execute: does the actual release #
####################################
execute () {
TEMPFILE="$(mktemp)" || exit
release | tee "$TEMPFILE"
# If we note that there are no changes from the release command, exit early
if grep -q No_Changes "$TEMPFILE";
then
exit 0
fi
LATEST_RELEASE="$(cfssl-trust ${DATABASE_PATH} ${CONFIG_PATH} releases | awk ' NR==1 { print $2 }')"
git checkout -b release/${LATEST_RELEASE}
printf "Trust store release ${LATEST_RELEASE}\n\n$(cat ${TEMPFILE})" | git commit -F-
rm ${TEMPFILE}
git tag trust-store-${LATEST_RELEASE}
if [ -n "${NOPUSH:-}" ]
then
exit 0
fi
git push --set-upstream origin release/${LATEST_RELEASE}
git push origin trust-store-${LATEST_RELEASE}
}
prologue
execute