docs: embedd asciinema casts (#1154)

Signed-off-by: Fabian Kammel <fk@edgeless.systems>
Co-authored-by: Moritz Eckert <m1gh7ym0@gmail.com>
Co-authored-by: Thomas Tendyck <tt@edgeless.systems>
Co-authored-by: 3u13r <lc@edgeless.systems>
This commit is contained in:
Fabian Kammel 2023-03-11 00:13:32 +01:00 committed by GitHub
parent cb2d2b0b89
commit 566924caf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 3825 additions and 134 deletions

2
docs/screencasts/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
recordings
constellation

View file

@ -0,0 +1,61 @@
# Screencast / Asciinema
[Asciinema](https://github.com/asciinema/asciinema) is used to automatically generate
terminal session recordings for our documentation. To fully automate this we use scripts
that utilize [expect](https://linux.die.net/man/1/expect) to interface with different
CLI tools, and run them inside a [container](docker/Dockerfile).
## Usage
```sh
mkdir -P constellation
./generate-screencasts.sh
sudo chown -R $USER:$USER ./constellation
cd constellation && constellation iam destroy
cd .. && rm -rf ./constellation
```
This will:
+ build the container
+ run the expect based scripts
+ copy recordings into the assets folder of our docs
To replay the output you can use `asciinema play recordings/verify-cli.cast`.
Include the generated screencast into our docs using the [`AsciinemaWidget`](../src/components/AsciinemaWidget/index.js):
```md
import AsciinemaWidget from '../../src/components/AsciinemaWidget';
<AsciinemaWidget src="/constellation/assets/verify-cli.cast" fontSize={16} rows={20} cols={112} idleTimeLimit={3} preload={true} theme={'edgeless'} />
```
Then [re-build and locally host the docs](../README.md).
## Styling
There are three different locations were styling is applied:
1. **The prompt** is styled using [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code).
More explanation and the actual color codes can be found in [Dockerfile](docker/Dockerfile).
2. **Player dimensions** are passed to the [`AsciinemaWidget`](../src/components/AsciinemaWidget/index.js)
when it's [embedded in the docs](../docs/workflows/verify-cli.md#5). Check the `asciinema-player` for a
[full list of options](https://github.com/asciinema/asciinema-player#options).
1. **Everything else** is [styled via CSS](../src/css/custom.css). This includes the option to build a custom
[player theme](https://github.com/asciinema/asciinema-player/wiki/Custom-terminal-themes).
###
## GitHub README.md
The GitHub `README.md` doesn't support embedding the JavaScript `asciinema-player`, therefore we generate an
`svg` file for that use case.
```sh
# Make sure to install the converter.
# https://github.com/nbedos/termtosvg
pip3 install termtosvg
# Generate SVG. This takes ~10min, since it actually creates a cluster in GCP.
./generate-readme-svg.sh
```

View file

@ -0,0 +1,47 @@
FROM ubuntu:20.04
# Install requirements
RUN apt-get update && apt-get install -y software-properties-common &&\
apt-add-repository ppa:zanchey/asciinema && apt-get update &&\
apt-get install -y curl expect asciinema sudo unzip &&\
rm -rf /var/lib/apt/lists/*
RUN curl -sLO https://github.com/mikefarah/yq/releases/download/v4.30.8/yq_linux_amd64 &&\
sudo install yq_linux_amd64 /usr/local/bin/yq && rm yq_linux_amd64
RUN curl -sLO https://dl.k8s.io/release/v1.26.0/bin/linux/amd64/kubectl &&\
sudo install kubectl /usr/local/bin/kubectl && rm kubectl
RUN curl -sLO https://releases.hashicorp.com/terraform/1.3.8/terraform_1.3.8_linux_amd64.zip &&\
unzip terraform_1.3.8_linux_amd64.zip &&\
sudo install terraform /usr/local/bin/terraform && rm terraform terraform_1.3.8_linux_amd64.zip
RUN curl -fsSLO https://github.com/edgelesssys/constellation/releases/latest/download/constellation-linux-amd64 &&\
sudo install constellation-linux-amd64 /usr/local/bin/constellation &&\
rm constellation-linux-amd64
# As mount point for $HOME/.config/gcloud
RUN mkdir /root/.config
# Disable spinner when running Constellation CLI commands
ENV CONSTELL_NO_SPINNER=1
# Enable RGB colors in PS1
ENV TERM=xterm-256color
# Set width of terminal, default is ~80 and leads to broken lines for long lines,
# e.g., curl & cosign commands.
ENV COLUMNS=512
# For PS1 to work shell needs to specified
ENV SHELL=/bin/bash
# ANSI color codes are used to control PS1 prompt. We use "\033[38;2;<r>;<g>;<b>m"
# to control the foreground color with RBG colors [1]. Non-printable characters
# need to be escaped with additional \[ and \], see [2].
# [1]: https://stackoverflow.com/a/33206814/2306355
# [2]: https://stackoverflow.com/a/19501528/2306355
RUN echo 'export PS1="\[\033[38;2;139;4;221m\]$\[\033[0m\] "' >> /root/.bashrc
# Copy install scripts
COPY ./*.expect /scripts/
WORKDIR /constellation
ENTRYPOINT ["/usr/bin/expect", "-f"]
CMD ["/scripts/verify-cli.expect"]

View file

@ -0,0 +1,61 @@
#!/usr/bin/expect -f
# Note: Expects to be able to run 'sudo install' without a password
set timeout -1
set send_human {0.05 0 1 0.05 0.3}
set CTRLC \003
set record_name [lindex $argv 0];
proc expect_prompt {} {
# This matches the trailing 0m of our ANSI control sequence. See PS1 in Dockerfile.
expect "0m "
}
proc run_command {cmd} {
send -h "$cmd"
send "\r"
expect -timeout 1
}
# Start recording
spawn asciinema rec --overwrite /recordings/check-sbom.cast
send "\r"
expect_prompt
run_command "# Step 1: Install SLSA verifier"
expect_prompt
run_command "curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/latest/download/slsa-verifier-linux-amd64"
expect_prompt
run_command "sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier"
expect_prompt
run_command "# Step 2: Download Constellation SBOM and provenance"
expect_prompt
run_command "curl -sLO https://github.com/edgelesssys/constellation/releases/latest/download/constellation.spdx.sbom"
expect_prompt
run_command "curl -sLO https://github.com/edgelesssys/constellation/releases/latest/download/constellation.intoto.jsonl"
expect_prompt
run_command "# Step 3: Check integrity of SBOM"
expect_prompt
run_command "slsa-verifier verify-artifact constellation.spdx.sbom --provenance-path constellation.intoto.jsonl --source-uri github.com/edgelesssys/constellation"
expect_prompt
run_command "# Step 4: Install grype (security scanner)"
expect_prompt
run_command "curl -sLO https://github.com/anchore/grype/releases/download/v0.56.0/grype_0.56.0_linux_amd64.tar.gz"
expect_prompt
run_command "tar -xvzf grype_0.56.0_linux_amd64.tar.gz"
expect_prompt
run_command "sudo install grype /usr/local/bin/grype"
expect_prompt
run_command "grype --help"
expect_prompt
run_command "# Step 5: Check for vulnerabilities"
expect_prompt
run_command "grype constellation.spdx.sbom -o table -q"
expect_prompt
# Stop recording
send "exit"

View file

@ -0,0 +1,35 @@
#!/usr/bin/expect -f
# Note: Expects to be able to run 'sudo install' without a password
set timeout -1
set send_human {0.05 0 1 0.05 0.3}
set CTRLC \003
set CTRLX \030
set record_name [lindex $argv 0];
proc expect_prompt {} {
# This matches the trailing 0m of our ANSI control sequence. See PS1 in Dockerfile.
expect "0m "
}
proc run_command {cmd} {
send -h "$cmd"
send "\r"
expect -timeout 1
}
# Start recording
spawn asciinema rec --overwrite /recordings/configure-cluster.cast
send "\r"
expect_prompt
run_command "# Step 1: Create IAM configuration and Constellation configuration file"
expect_prompt
run_command "constellation iam create gcp --generate-config --projectID constellation-331613 --serviceAccountID constellation-demo --zone europe-west3-b"
expect -re "y\/n"
send "y"
send "\r"
expect_prompt
# Stop recording
send "exit"

View file

@ -0,0 +1,53 @@
#!/usr/bin/expect -f
# Note: Expects to be able to run 'sudo install' without a password
set timeout -1
set send_human {0.05 0 1 0.05 0.3}
set CTRLC \003
set CTRLX \030
set record_name [lindex $argv 0];
proc expect_prompt {} {
# This matches the trailing 0m of our ANSI control sequence. See PS1 in Dockerfile.
expect "0m "
}
proc run_command {cmd} {
send -h "$cmd"
send "\r"
expect -timeout 1
}
# Start recording
spawn asciinema rec --overwrite /recordings/create-cluster.cast
send "\r"
expect_prompt
run_command "# Step 1: Create cloud environment"
expect_prompt
run_command "constellation create --control-plane-nodes 3 --worker-nodes 2"
expect -re "y\/n"
send "y"
send "\r"
expect_prompt
run_command "# Step 2: Initialize Constellation"
expect_prompt
run_command "constellation init"
expect_prompt
run_command "# Wait for cluster to finish bootstrapping..."
expect_prompt
# Without a sleep we only see a single node, not 5.
run_command "sleep 300"
expect_prompt
run_command "# Step 3: Connect to Constellation"
expect_prompt
run_command "export KUBECONFIG=/constellation/constellation-admin.conf"
expect_prompt
run_command "kubectl get nodes"
expect_prompt
# Stop recording
send "exit"

View file

@ -0,0 +1,88 @@
#!/usr/bin/expect -f
# Note: Expects to be able to run 'sudo install' without a password
set timeout -1
set send_human {0.05 0 1 0.05 0.3}
set CTRLC \003
set CTRLX \030
set record_name [lindex $argv 0];
proc expect_prompt {} {
# This matches the trailing 0m of our ANSI control sequence. See PS1 in Dockerfile.
expect "0m "
}
proc run_command {cmd} {
send -h "$cmd"
send "\r"
expect -timeout 1
}
# Start recording
spawn asciinema rec --overwrite /recordings/github-readme.cast
send "\r"
expect_prompt
run_command "# Step 1: Create IAM configuration"
expect_prompt
run_command "constellation iam create gcp --generate-config --projectID constellation-331613 --serviceAccountID constellation-demo --zone europe-west3-b"
expect -re "y\/n"
send "y"
send "\r"
expect_prompt
# TODO: Delete step once #1149 released
run_command "# Step 2: Fill in configuration"
expect_prompt
run_command "yq '.provider.gcp.project = \"constellation-331613\"' -i constellation-conf.yaml"
expect_prompt
run_command "yq '.provider.gcp.zone = \"europe-west3-b\"' -i constellation-conf.yaml"
expect_prompt
run_command "yq '.provider.gcp.region = \"europe-west3\"' -i constellation-conf.yaml"
expect_prompt
run_command "cat constellation-conf.yaml | head -n15"
expect_prompt
run_command "# Step 3: Create cloud environment"
expect_prompt
run_command "constellation create --control-plane-nodes 3 --worker-nodes 2"
expect -re "y\/n"
send "y"
send "\r"
expect_prompt
run_command "# Step 4: Initialize Constellation"
expect_prompt
run_command "constellation init"
expect_prompt
run_command "# Wait for cluster to finish bootstrapping..."
expect_prompt
# Without a sleep we only see a single node, not 5.
run_command "sleep 300"
expect_prompt
run_command "# Step 5: Connect to Constellation"
expect_prompt
run_command "export KUBECONFIG=/constellation/constellation-admin.conf"
expect_prompt
run_command "kubectl get nodes"
run_command "# Step 6: Delete Constellation cluster"
expect_prompt
run_command "constellation terminate"
expect -re "y\/n"
send "y"
send "\r"
expect_prompt
run_command "# Step 7: Remove IAM resources"
expect_prompt
run_command "cd constellation-iam-terraform"
expect_prompt
run_command "terraform apply -destroy -auto-approve"
expect -timeout 25
run_command "# All resources are cleaned up."
# Stop recording
send "exit"

View file

@ -0,0 +1,40 @@
#!/usr/bin/expect -f
# Note: Expects to be able to run 'sudo install' without a password
set timeout -1
set send_human {0.05 0 1 0.05 0.3}
set CTRLC \003
set CTRLX \030
set record_name [lindex $argv 0];
proc expect_prompt {} {
# This matches the trailing 0m of our ANSI control sequence. See PS1 in Dockerfile.
expect "0m "
}
proc run_command {cmd} {
send -h "$cmd"
send "\r"
expect -timeout 1
}
# Start recording
spawn asciinema rec --overwrite /recordings/terminate-cluster.cast
send "\r"
expect_prompt
run_command "# Step 1: Delete Constellation cluster"
expect_prompt
run_command "constellation terminate"
expect -re "y\/n"
send "y"
send "\r"
expect_prompt
run_command "# Delete mastersecret to finalize deletion"
expect_prompt
run_command "rm constellation-mastersecret.json"
expect_prompt
# Stop recording
send "exit"

View file

@ -0,0 +1,54 @@
#!/usr/bin/expect -f
# Note: Expects to be able to run 'sudo install' without a password
set timeout -1
set send_human {0.05 0 1 0.05 0.3}
set CTRLC \003
set record_name [lindex $argv 0];
proc expect_prompt {} {
# This matches the trailing 0m of our ANSI control sequence. See PS1 in Dockerfile.
expect "0m "
}
proc run_command {cmd} {
send -h "$cmd"
send "\r"
expect -timeout 1
}
# Start recording
spawn asciinema rec --overwrite /recordings/verify-cli.cast
send "\r"
expect_prompt
run_command "# Step 1: Install SLSA verifier"
expect_prompt
run_command "curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/latest/download/slsa-verifier-linux-amd64"
expect_prompt
run_command "sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier"
expect_prompt
run_command "# Step 2: Download Constellation CLI and provenance"
expect_prompt
run_command "curl -sLO https://github.com/edgelesssys/constellation/releases/latest/download/constellation-linux-amd64"
expect_prompt
run_command "curl -sLO https://github.com/edgelesssys/constellation/releases/latest/download/constellation.intoto.jsonl"
expect_prompt
run_command "# Step 3: Verify provenance"
expect_prompt
run_command "slsa-verifier verify-artifact constellation-linux-amd64 --provenance-path constellation.intoto.jsonl --source-uri github.com/edgelesssys/constellation"
expect_prompt
run_command "# Step 4: Install the CLI"
expect_prompt
run_command "sudo install constellation-linux-amd64 /usr/local/bin/constellation"
expect_prompt
run_command "# Done! You can now use the verified CLI"
expect_prompt
run_command "constellation -h"
expect_prompt
# Stop recording
send "exit"

View file

@ -0,0 +1,32 @@
#!/usr/bin/env bash
#
# This script prepares the environment for expect scripts to be recorded in,
# executes all scripts, and copies the .cast files to our doc's asset folder.
#
# Note: A cluster is created in GCP. Therefore you are expected to be logged in
# via `gcloud` CLI. You credentials at $HOME/.config/gcloud are mounted into the
# screenrecordings container. A full script run takes ~20min.
#
docker build -t screenrecodings docker
# Create cast
docker run -it \
-v "${HOME}"/.config/gcloud:/root/.config/gcloud \
-v "$(pwd)"/recordings:/recordings \
-v "$(pwd)"/constellation:/constellation \
screenrecodings /scripts/github-readme.expect
# Fix meta data: width and height are always zero in Docker produced cast files.
# Header is the first lint of cast file in JSON format, we read, fix and write it.
head recordings/github-readme.cast -n 1 | yq e -M '.width = 95 | .height = 17' - > new_header.cast
# Then append everything, expect first line from original cast file.
tail -n+2 recordings/github-readme.cast >> new_header.cast
# Then render cast into svg using:
# https://github.com/nbedos/termtosvg
termtosvg render new_header.cast readme.svg -t window-frame.svg
# Copy and cleanup
cp readme.svg ../static/img/shell-windowframe.svg
rm readme.svg new_header.cast

View file

@ -0,0 +1,51 @@
#!/usr/bin/env bash
#
# This script prepares the environment for expect scripts to be recorded in,
# executes all scripts, and copies the .cast files to our doc's asset folder.
#
# Note: A cluster is created in GCP. Therefore you are expected to be logged in
# via `gcloud` CLI. You credentials at $HOME/.config/gcloud are mounted into the
# screenrecordings container. A full script run takes ~20min.
#
docker build -t screenrecodings docker
# Verify CLI
docker run -it -v "$(pwd)"/recordings:/recordings screenrecodings /scripts/verify-cli.expect
cp recordings/verify-cli.cast ../static/assets/verify-cli.cast
# Check SBOM
docker run -it -v "$(pwd)"/recordings:/recordings screenrecodings /scripts/check-sbom.expect
cp recordings/check-sbom.cast ../static/assets/check-sbom.cast
#
# Do not change the order of the following sections. A cluster is created,
# modified and finally destroyed. Otherwise resources might not get cleaned up.
#
# To get multiple recordings a dedicated script is used for each step.
# The Constellation working directory is shared via /constellation container folder.
#
# Create config
docker run -it \
-v "${HOME}"/.config/gcloud:/root/.config/gcloud \
-v "$(pwd)"/recordings:/recordings \
-v "$(pwd)"/constellation:/constellation \
screenrecodings /scripts/configure-cluster.expect
cp recordings/configure-cluster.cast ../static/assets/configure-cluster.cast
# Create cluster
docker run -it \
-v "${HOME}"/.config/gcloud:/root/.config/gcloud \
-v "$(pwd)"/recordings:/recordings \
-v "$(pwd)"/constellation:/constellation \
screenrecodings /scripts/create-cluster.expect
cp recordings/create-cluster.cast ../static/assets/create-cluster.cast
# Terminate cluster
docker run -it \
-v "${HOME}"/.config/gcloud:/root/.config/gcloud \
-v "$(pwd)"/recordings:/recordings \
-v "$(pwd)"/constellation:/constellation \
screenrecodings /scripts/terminate-cluster.expect
cp recordings/terminate-cluster.cast ../static/assets/terminate-cluster.cast

View file

@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="terminal" baseProfile="full" viewBox="0 0 703 404" width="703" version="1.1">
<defs>
<termtosvg:template_settings xmlns:termtosvg="https://github.com/nbedos/termtosvg">
<termtosvg:screen_geometry columns="82" rows="19"/>
<termtosvg:animation type="css"/>
</termtosvg:template_settings>
<style type="text/css" id="generated-style"></style>
<style type="text/css" id="user-style">
/* The colors defined below are the default 16 colors used for rendering text of the terminal. Adjust
them as needed.
gjm8 color theme (source: https://terminal.sexy/) */
/* customized colors 10, 11, and 14 */
.foreground {fill: #f8f8f2}
.background {fill: #272822}
.color0 {fill: #272822}
.color1 {fill: #f92672}
.color2 {fill: #a6e22e}
.color3 {fill: #f4bf75}
.color4 {fill: #66d9ef}
.color5 {fill: #ae81ff}
.color6 {fill: #a1efe4}
.color7 {fill: #f8f8f2}
.color8 {fill: #75715e}
.color9 {fill: #fd971f}
.color10 {fill: #8b04dd}
.color11 {fill: #dcaf3b}
.color12 {fill: #a59f85}
.color13 {fill: #f5f4f1}
.color14 {fill: #90ff99}
.color15 {fill: #f9f8f5}
</style>
</defs>
<rect id="terminalui" class="background" width="100%" height="100%" ry="4.5826941"/>
<circle cx="24" cy="23" r="7" class="color1"/>
<circle cx="44" cy="23" r="7" class="color3"/>
<circle cx="64" cy="23" r="7" class="color2"/>
<svg id="screen" width="656" height="323" x="23" y="50" viewBox="0 0 656 323" preserveAspectRatio="xMidYMin slice"></svg>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB