Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Agent Guidelines

This guide is for AI agents working on the Open Ecosystem Challenges repository.
For structural scaffolding, use `scripts/new-adventure.sh`. This document covers
everything that is easy to miss.

## Ground Rules

- **Never assume β€” always ask.** If intent is unclear, ask before implementing.
- **Propose before acting.** For anything structural (new files, renames, moving things),
outline the approach and get confirmation first.
- **Be critical.** If something seems inconsistent or wrong, flag it. Don't silently comply.
- **Read the docs in place.** Before working on an adventure, read the contributing guide
and relevant documentation in the repo. Don't rely on assumptions or memory β€” read the
actual files.

---

## Creating a New Adventure

Never create adventure files manually. The correct flow is:

1. An approved idea file must exist in `ideas/` before any implementation begins.
Never start building an adventure without one.
2. Run `scripts/new-adventure.sh` to scaffold the adventure structure from the idea file.
This ensures consistent structure across all adventures.

---

## Building Challenges

> Read [docs/contributing/adventures.md](./docs/contributing/adventures.md) first β€” it covers the full step-by-step process.
> The sections below capture things that are easy to miss on top of that guide.


### Theme consistency

Every technical element should have a thematic counterpart β€” label keys, error messages,
pod names, policy descriptions. Thematic flavor enhances the experience but must never
obscure what the player needs to understand technically.

When in doubt: combine both. A Roman-themed error message can still explain *why* the
policy exists.

### Intentional bugs

- Always work backwards from the solution. Implement the fully working state first,
verify it, then introduce bugs from there. Never design the buggy state first.
- One concept per bug β€” keep bugs focused and isolated.
- Keep challenge artifacts minimal. Only include what is directly relevant to the concept
being tested β€” anything extra distracts beginners. For example, a test workload should
not include security context fields or resource limits that aren't part of the challenge.

### verify.sh

- Always define an `OBJECTIVE` variable at the top that matches the wording in the docs exactly.
- Use inline YAML heredocs for test manifests β€” never reference files from `manifests/workloads/`
since those are player-editable. The verify script must be self-contained.
- Extend `lib/scripts/` with reusable helper functions rather than writing logic inline
in verify.sh. Keep verify.sh a clean list of check calls.
- Hints must be **directional, not prescriptive**:
- Bad: `"is the validationFailureAction set to Enforce?"`
- Good: `"what happens when a violation is detected?"`
- The hint should point players to *where* to look, not *what* to change.

### Devcontainer / post-start

- `post-create.sh`: install tools, set up the cluster, install dependencies.
- `post-start.sh`: deploy the initial challenge state (policies + workloads). The goal is
that players open their Codespace and the problem is immediately visible β€” not a blank
slate. The broken state should be the first thing they see.

### Makefile

Keep it minimal. For a typical challenge level:
- `make apply` β€” reset everything (delete known pods, re-apply policies, re-apply workloads)
- `make verify` β€” run verify.sh

Don't add targets that duplicate verify.sh logic or that give players shortcuts that
bypass learning.

### Shared scripts

`lib/scripts/loader.sh` sources all shared helper functions automatically. Always source
it at the top of verify.sh. Before writing any verification logic, check whether a helper
already exists in `lib/scripts/` β€” prefer extending the shared library over writing
inline logic.

### Pre-release checklist

When explicitly asked to review an adventure for release readiness, check:

- Deadline is filled in (not empty)
- Community thread link is not a `TODO`
- `Status: Coming Soon` is updated to reflect actual state
- Adventure has a real number assigned (not `00`, which is the placeholder for planned adventures)
- No `<!-- TODO -->` comments remain in any docs
- verify.sh hints have been reviewed β€” none give away the exact fix
- `OBJECTIVE` in verify.sh matches the `## 🎯 Objective` section in the docs

Only make changes to these when explicitly prompted to do so.

### Docs

- The `## 🎯 Objective` section in the docs and the `OBJECTIVE` variable in verify.sh
must match.
- `## 🧠 What You'll Learn` bullet points should link to the relevant docs pages.
- Hints in `verify.sh` must not appear in the docs β€” the docs describe *what* to achieve,
not *how* to fix it.
- The `## πŸ—οΈ Architecture` section should explicitly tell players which files to edit
and which to leave alone.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
16 changes: 16 additions & 0 deletions adventures/planned/00-lex-imperfecta/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# βš–οΈ Adventure 00: Lex Imperfecta

The Roman Republic has built a sophisticated legal system to protect its citizens β€” but the laws were written
in haste, and the exceptions were written too generously. Policies go unenforced, the wrong citizens are exempt, and
something has slipped through the gates unnoticed. As a newly appointed Praetor, your mission is to restore order before
chaos takes hold.

**Technologies:** Kyverno, Falco, Policy Reporter, Argo CD, Kubernetes

The entire **infrastructure is pre-provisioned in your Codespace**
**You don't need to set up anything locally. Just focus on solving the problem.**

## πŸš€ Ready to Start?

[Choose your level](https://dynatrace-oss.github.io/open-ecosystem-challenges/00-lex-imperfecta/) and begin
learning!
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "βš–οΈ Adventure 00 | 🟒 Beginner (The Twelve Tables)",
"image": "mcr.microsoft.com/devcontainers/base:bullseye",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/adventures/planned/00-lex-imperfecta/beginner",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"postCreateCommand": "bash /workspaces/${localWorkspaceFolderBasename}/.devcontainer/00-lex-imperfecta_01-beginner/post-create.sh",
"postStartCommand": "bash /workspaces/${localWorkspaceFolderBasename}/.devcontainer/00-lex-imperfecta_01-beginner/post-start.sh",
"customizations": {
"codespaces": {
"openFiles": [
"adventures/planned/00-lex-imperfecta/README.md"
],
"permissions": {
"codespaces": "write"
}
}
},
"forwardPorts": [],
"portsAttributes": {},
"otherPortsAttributes": {
"onAutoForward": "ignore"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"

# shellcheck disable=SC1091
source "$REPO_ROOT/lib/scripts/tracker.sh"
set_tracking_context "lex-imperfecta" "beginner"
track_codespace_created

"$REPO_ROOT/lib/shared/init.sh" --version v0.17.0
"$REPO_ROOT/lib/kubernetes/init.sh" \
--kind-version v0.31.0 \
--kubectl-version v1.35.0 \
--kubens-version v0.11.0 \
--k9s-version v0.50.18 \
--helm-version v4.1.4
"$REPO_ROOT/lib/kyverno/init.sh" --version 3.7.1 --cli-version v1.17.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
CHALLENGE_DIR="$REPO_ROOT/adventures/planned/00-lex-imperfecta/beginner"

echo "✨ Starting Lex Imperfecta - Beginner Level"

echo "βš–οΈ Applying policies..."
kubectl apply -f "$CHALLENGE_DIR/manifests/policies/"

echo "πŸ›οΈ Deploying pods..."
# Some pods may be blocked by the misconfigured policies β€” this is intentional.
# Run 'kubectl get pods' to see the current state and start investigating.
kubectl apply -f "$CHALLENGE_DIR/manifests/pods/" 2>&1 || true

# shellcheck disable=SC1091
source "$REPO_ROOT/lib/scripts/tracker.sh"
set_tracking_context "lex-imperfecta" "beginner"
track_codespace_initialized
31 changes: 31 additions & 0 deletions adventures/planned/00-lex-imperfecta/beginner/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.PHONY: help apply verify

help:
@echo "Lex Imperfecta - Beginner: Available Commands:"
@echo " make apply Apply policies and re-deploy all workloads"
@echo " make verify Run the verification script"

apply:
@kubectl delete pod compliant missing-labels privileged privileged-init-container --ignore-not-found > /dev/null 2>&1; true
@echo "Applied Policies:"; \
for f in manifests/policies/*.yaml; do \
name=$$(grep '^ name:' "$$f" | awk '{print $$2}'); \
kubectl apply -f "$$f" > /dev/null 2>&1 && echo " $$name"; \
done; \
echo ""
@echo "Applied Pods:"; \
blocked=""; \
for f in manifests/pods/*.yaml; do \
name=$$(grep '^ name:' "$$f" | awk '{print $$2}'); \
if kubectl apply -f "$$f" > /dev/null 2>&1; then \
echo " $$name"; \
else \
blocked="$$blocked $$name"; \
fi; \
done; \
echo ""; \
echo "Blocked Pods:"; \
for name in $$blocked; do echo " $$name"; done

verify:
@./verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: compliant
labels:
republic.rome/gens: forum-romanum
spec:
restartPolicy: Never
containers:
- name: app
image: busybox:stable
command: ["sleep", "infinity"]
securityContext:
privileged: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Pod
metadata:
name: missing-labels
spec:
restartPolicy: Never
containers:
- name: app
image: busybox:stable
command: ["sleep", "infinity"]
securityContext:
privileged: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: v1
kind: Pod
metadata:
name: privileged-init-container
labels:
republic.rome/gens: castra-praetoria
spec:
restartPolicy: Never
initContainers:
- name: init
image: busybox:stable
command: ["sh", "-c", "exit 0"]
securityContext:
privileged: true
containers:
- name: app
image: busybox:stable
command: ["sleep", "infinity"]
securityContext:
privileged: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: privileged
labels:
republic.rome/gens: castra-praetoria
spec:
restartPolicy: Never
containers:
- name: app
image: busybox:stable
command: ["sleep", "infinity"]
securityContext:
privileged: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: no-privileged-containers
annotations:
policies.kyverno.io/title: No Privileged Containers
policies.kyverno.io/category: Pod Security
policies.kyverno.io/severity: high
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
The Senate forbids unchecked power. Running containers with elevated privileges
grants access to all Linux kernel capabilities and host resources, bypassing
namespace isolation.
spec:
validationFailureAction: Enforce
background: true
rules:
- name: privileged-containers
match:
any:
- resources:
kinds:
- Pod
validate:
message: "The Senate forbids unchecked power: privileged containers seize full control of the host and are not permitted in the Republic."
# Privileged containers are forbidden β€” this applies to regular, ephemeral and init containers.
pattern:
spec:
"=(ephemeralContainers)":
- "=(securityContext)":
"=(privileged)": "false"
"=(initContainers)":
- "=(securityContext)":
"=(privileged)": "false"
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
annotations:
policies.kyverno.io/title: Require Labels
policies.kyverno.io/category: Best Practices
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod, Label
policies.kyverno.io/description: >-
Every citizen must declare their gens. Pods without the 'republic.rome/gens' label
are unregistered and cannot be admitted to the Republic's cluster.
spec:
validationFailureAction: Audit
background: true
rules:
- name: check-for-labels
match:
any:
- resources:
kinds:
- Pod
validate:
message: All workloads must declare their gens. Unregistered citizens are not permitted in the Republic.
pattern:
metadata:
labels:
republic.rome/gens: "?*"
Loading
Loading