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 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
|
if ! test -e alice.pgp -a -e bob.pgp
then
echo "You seem to be in the wrong directory! (alice.pgp and bob.pgp not found)"
exit 1
fi
export GNUPGHOME=$(pwd)/gpg
export SEQUOIA_CERT_STORE=$(pwd)/gpg/pubring.cert.d
if test -d gpg
then
gpgconf --kill gpg-agent
rm -rf gpg
sleep 1
fi
mkdir gpg
chmod 700 gpg
for c in *.pgp
do
gpg --import $c
done
sleep 1
# Remove old output.
rm -f *[0-9]-*.txt
# Initialize the git repository.
rm -rf frob
mkdir frob
cd frob
git init
# sq --overwrite key generate --name Bob --email bob@example.org --own-key --without-password --expiration never --output bob.pgp --rev-cert /tmp/alice.rev
# vanity_gpg -c ed25519 -j8 -u "Alice" -p "^A11CE"
alice_fpr=A11CECD86FB6050466E6259C7993A17BA8537B3D
bob_fpr=B0B50C2B8C3558D225A3310C1A8FAB5E378DD32D
carol_fpr=CA501F894EBD6193655CB77C476D56394D4E67DC
declare -A trust_roots
set -e
context() {
name="$1"
case "$name" in
alice)
git config --local user.name "Alice"
git config --local user.email "alice@example.org"
git config --local gpg.gpgsign true
git config --local user.signingKey $alice_fpr
;;
bob)
git config --local user.name "Bob"
git config --local user.email "bob@example.org"
git config --local gpg.gpgsign true
git config --local user.signingKey $bob_fpr
;;
carol)
git config --local user.name "Carol"
git config --local user.email "carol@example.org"
git config --local gpg.gpgsign true
git config --local user.signingKey $carol_fpr
;;
dave)
git config --local user.name "Dave"
git config --local user.email "dave@some.org"
git config --local gpg.gpgsign false
git config --local --unset user.signingKey
;;
mallory)
git config --local user.name "Neal H. Walfield"
git config --local user.email "neal@sequoia-pgp.org"
if test -z "$neal_fpr"
then
git config --local gpg.gpgsign false
git config --local --unset user.signingKey || true
else
git config --local gpg.gpgsign true
git config --local user.signingKey "$neal_fpr"
fi
;;
*)
echo "\$1 should be the name"
exit 1
esac
trust_root=${trust_roots[$name]}
if test -z "$trust_root"
then
git config --local --unset sequoia.trustRoot || true
else
git config --local sequoia.trustRoot "$trust_root"
fi
PS4="$name\$ "
rm -f ~/.cache/sq-git.verification.cache
}
# The number of lines to add / delete with each commit. We rotate
# them to add variety, but to keep the output stable.
declare -a add
declare -a delete
add=( 21 9 32 40 )
delete=( 7 12 6 )
emacs() {
set +x
filename="$1"
if test -z "$filename"
then
echo filename not specified
exit 1
fi
touch "$filename"
if test "${delete[0]}" -gt 0
then
sed -i "1,${delete[0]}d" "$filename"
fi
{ for i in $(seq ${add[0]}); do echo $RANDOM; done } >> "$filename"
# Rotate
add=( "${add[@]:1}" "${add[0]}" )
delete=( "${delete[@]:1}" "${delete[0]}" )
set -x
}
save() {
filename="$1"
# - Remove set +x from output.
# - Remove stuttering due to PS4.
# - If the --cert FINGERPRINT argument comes at the end of a line,
# wrap it.
sed -e '/.*$ set +x/d' \
-e 's/^\(.\)\1\+\(.*$ \)/\1\2/' \
-e 's/^\(.\{33,\}\)\(--cert [0-9A-F]\{40\}\)/\1\\\n \2/g' \
| tee "$filename"
}
context "alice"
{
set -x
sq-git policy authorize alice --project-maintainer \
--cert $alice_fpr
git add openpgp-policy.toml
git commit -m "Add a signing policy."
} 2>&1 | save ../frob-10-alice-adds-a-signing-policy.txt
context "alice"
{
set -x
git config sequoia.trustRoot $(git rev-parse HEAD)
} 2>&1 | save ../frob-20-alice-sets-trust-root.txt
context "alice"
{
set -x
sq-git policy authorize bob --release-manager --cert $bob_fpr
git add openpgp-policy.toml
git commit -m "Authorize Bob to be a release manager."
} 2>&1 | save ../frob-30-alice-authorizes-bob.txt
context "alice"
{
set -x
sq-git log
} 2>&1 | save ../frob-40-alice-runs-git-log.txt
context "bob"
{
set -x
emacs main.rs
git add main.rs
git commit -m "Add a cool new feature."
sq-git log --trust-root HEAD^
} 2>&1 | save ../frob-50-bob-adds-a-commit.txt
context "dave"
DAVE_ROOT=$(git rev-parse HEAD)
echo $DAVE_ROOT | save ../frob-55-dave-trust-root.txt
trust_roots["dave"]=$DAVE_ROOT
{
set -x
git log -n1
git config sequoia.trustRoot $DAVE_ROOT
} 2>&1 | save ../frob-60-dave-sets-a-trust-root.txt
context "bob"
{
set -x
emacs main.rs
git add main.rs
git commit -m "Fix a corner case."
emacs main.rs
git add main.rs
git commit -m "Add support for ACME's frob."
} 2>&1 | save ../frob-70-bob-adds-a-commit.txt
context "dave"
{
set -x
sq-git log
} 2>&1 | save ../frob-80-dave-checks.txt
context "carol"
{
set -x
git switch -c carol/vroom main
emacs main.rs
git add main.rs
git commit -m "Use an O(log(n)) algorithm instead of one that takes O(n)."
} 2>&1 | save ../frob-90-carol-adds-a-commit.txt
CAROL_COMMIT=$(git rev-parse HEAD)
echo $CAROL_COMMIT | save ../frob-95-carol-commit-cherry-picked.txt
context "dave"
{
set +e; set -x
sq-git log
} 2>&1 | save ../frob-100-dave-checks-carols-commit.txt
context "carol"
{
set -x
git switch -c carol/make-carol-a-committer main
sq-git policy authorize carol --committer --cert $carol_fpr
git add openpgp-policy.toml
git commit -m "Authorize Carol to be a committer."
git cherry-pick $CAROL_COMMIT
sq-git log --trust-root HEAD^
} 2>&1 | save ../frob-110-carol-adds-herself-to-the-policy.txt
context "dave"
{
set +e; set -x
sq-git log
} 2>&1 | save ../frob-120-dave-checks-carols-new-commits.txt
git checkout main
context "bob"
{
set +e; set -x
git merge --no-ff carol/vroom -m "Merge Carol's change"
} 2>&1 | save ../frob-130-bob-merges-carols-commit.txt
context "bob"
{
set +e; set -x
git log --decorate --pretty=short --graph
} 2>&1 | save ../frob-140-git-log.txt
context "dave"
{
set +e; set -x
sq-git log
} 2>&1 | save ../frob-150-dave-checks-merge-commit.txt
context "bob"
{
set +e; set -x
git reset --hard $CAROL_COMMIT
git commit --amend --allow-empty --reuse-message=HEAD
} 2>&1 | save ../frob-160-bob-signs-carols-commit.txt
context "dave"
{
set +e; set -x
git log -n1
sq-git log
} 2>&1 | save ../frob-170-dave-checks-resign.txt
# Introduction.
cd ..
rm -rf intro
mkdir intro
cd intro
git init
context "mallory"
{
set -x
sq key generate --userid 'Neal H. Walfield <neal@sequoia-pgp.org>' --own-key --without-password
} 2>&1 \
| awk 'BEGIN { suppress = 0 }
/^Transferable Secret Key./ { print "..."; suppress = 1; exit }
{ if (suppress == 0) { print } }
/^[a-z]+$/ { suppress = 0; }' \
| save ../intro-10-neal-cert.txt
# Truncate sq key generate
neal_fpr=$(sq cert list neal@sequoia-pgp.org | awk -F-\ '/^ - [0-9A-F]{40,}/ { print $2 }')
if test -z "$neal_fpr"
then
echo Failed to extract fingerprint.
exit 1
fi
sq key export --cert "$neal_fpr" | gpg --import
sleep 1
sq pki link retract --cert "$neal_fpr" --all
context "mallory"
{
set -x
emacs main.rs
git add main.rs
git commit -m "Clean up the code."
} 2>&1 | save ../intro-20-neal-commit.txt
context "alice"
{
set -x
git log -n1 --pretty=short --show-signature
} 2>&1 | save ../intro-30-git-log.txt
# Stabilize the output.
cd ..
rewrite_commits() {
prefix=$1
if test -z "$prefix"
then
echo "No prefix"
exit 1
fi
shift
files=$@
if test -z "$files"
then
echo "No files"
exit 1
fi
got_all=$(sed -n -E '
# .* matches greedily so we need to be careful. The following loop
# surrounds the last commit hash on the current line (before the first
# \n in the pattern space) with \ns. If it made a substitution, it
# loops.
:split
s/^([^\n]*)(\b[0-9a-f]{40}\b)/\1\n\2\n/;
t split;
# If the pattern space is a commit hash, print it. Otherwise, remove
# everything up to and including the first new line character. If
# the pattern space is not empty, repeast.
:print
/^[0-9a-f]{40}/ P;
s/^[^\n]*(\n|$)//;
/./ b print
' $files)
echo $got_all
# We want to dedup, but if we do sort | uniq, then the order is not
# preserved.
declare -a got
declare -A dedup
for commit in $got_all
do
if ! test -z "${dedup[$commit]}"
then
continue
fi
dedup[$commit]=1
got+=( "$commit" )
done
commit_i=1
subs=""
for c in ${got[@]}
do
commit="$prefix$(printf '%03d%040d' $commit_i 0)";
let commit_i+=1
echo "$c -> $commit"
for i in $(seq 7 40)
do
subs+="s/\b${c:0:$i}\b/${commit:0:$i}/g;"
done
done
sed -E -e "${subs}" -i $files
}
# Use a one letter prefix for each scenario. Make sure the files are
# listed in order so that the commits are ordered correctly.
rewrite_commits a $(ls -1 intro-??-*.txt | sort)
rewrite_commits b $(ls -1 frob-??-*.txt | sort) $(ls -1 frob-???-*.txt | sort)
|