Don't on the left, fix on the right. Read before push, scan when something behaves strangely.
Credentials & secretsIn repo = leaked
Bake creds in custom images
Use the secrets: block; reference at runtime.
Keys in environment: on a resource
Visible in repo + learner debug log. Move to secrets:.
PAT in git clone https://<tok>@…
Lives in repo history forever. Use secrets:: git clone https://${GITHUB_TOKEN}@…
Base64 dockerconfigjson in setup
Equivalent to plaintext in git. Move to secrets:; decode at runtime.
Lifecycle & cleanupState that doesn't survive
Rely on nohup across challenges
Background jobs die at the challenge boundary. Run synchronously in the prior challenge’s setup.
Skip cleanup for costed resources
Orphaned tenants, accounts, keys accumulate. Always retrieve resource ID via agent variable get and delete.
Run certbot certonly at runtime
Hits LE rate limit (5/week). Use provision_ssl_certificate: true; read cert from GCP metadata.
Copy a vestigial container from an older config
Some legacy workshop configs carry containers that no longer serve a function (e.g., a defunct nginx-zones helper). Inflates resource allocation. Remove from new builds.
Comment, not command. set never executes; failures hidden. Drop the leading #.
set -eux pipefail
pipefail read as a positional parameter, ignored. Pipe failures pass. Add -o: set -euxo pipefail
Cloud & IAMSandbox provisioning
Reference INSTRUQT_AWS_* with no aws_accounts:
Variables come back empty; CLI fails with cryptic auth errors. Add the matching resource block.
roles: - roles/writer
Not a valid GCP IAM role. Use a real one: roles/storage.objectCreator, roles/storage.objectUser.
AuthoringBody and scripts
```python,run for bash content
Block executed as Python. Output is wrong, errors confuse. Match the language tag to what runs.
lolcat / cowsay / ponysay in scripts
ANSI escapes corrupt the debug log. Reserve for terminal cmd: only.
PatternsWrong tool, wrong technique
socat for iframe-blocking sites
TCP-level proxy can’t touch HTTP headers. Use Caddy/nginx with header_down, or custom_response_headers: on the service tab.
sleep N for readiness
Brittle to provisioning variance. Replace with until <readiness-check>; do sleep 10; done.
Notes
Pre-push scan. The first three categories — credentials, lifecycle, bash discipline — catch the highest-frequency issues. Worth a glance every push.
Diagnostic angle. When a setup hangs, mid-script output stops, or a check fails inexplicably, scan the bash discipline column first. The malformed #set shebang and set -eux pipefail traps both produce silent failures with no telltale error message.
Don’t fix in PR comments. A comment saying “remove the API key from environment: later” is too late — once it lands in a commit, the secret is in the history forever. Rotate the secret and rewrite history, or treat it as compromised.
Cleanup forgetfulness. Every provisioned external resource — managed serverless project, partner service account, LLM proxy key, GCP GPU VM, Auth0 user, managed-service trial org — needs a corresponding cleanup-{hostname} that retrieves the ID and deletes. Without it, orphaned resources accumulate quietly.