Kubeasy LogoKubeasy

Contributing Guidelines

How to submit a high-quality challenge to the Kubeasy challenges repository.

Thank you for contributing to Kubeasy! This guide explains the process and standards for submitting challenges.

Before you start

Browse existing challenges

Check the challenges repository to:

  • Avoid duplicating existing challenges
  • Understand the current challenge structure and quality bar
  • Get inspiration from well-designed examples

Propose your idea first

Open a GitHub Issue before investing time building a challenge. Use the "Challenge Proposal" template at kubeasy-dev/challenges/issues and describe:

  • What Kubernetes concept it teaches
  • The challenge type (fix, build, or migrate)
  • The broken/initial scenario
  • Why it's a valuable learning experience
  • Estimated difficulty and time

This avoids duplicate work and ensures your idea aligns with Kubeasy's goals.

Contribution process

1. Fork and clone

# Fork the repository on GitHub, then:
git clone https://github.com/<your-username>/challenges.git
cd challenges

2. Create a branch

git checkout -b challenge/<challenge-slug>

Use the challenge slug as the branch name (e.g., challenge/rbac-service-account, challenge/network-policy-egress).

3. Build the challenge

Follow Challenge Structure and Creating Your First Challenge.

Your folder must contain:

<challenge-slug>/
├── challenge.yaml
├── manifests/
│   └── ...
├── policies/
│   └── protect.yaml
└── image/          # optional
    └── Dockerfile

4. Test thoroughly

See Testing Challenges for the full testing workflow.

Minimum requirements before submitting:

  • kubeasy dev lint passes
  • Broken state is reproducible
  • All validations fail before the fix
  • All validations pass after applying the fix
  • Kyverno policies prevent bypasses
  • Multiple valid solutions are accepted (where applicable)
  • Estimated time is accurate

5. Commit and push

git add <challenge-slug>/
git commit -m "feat: add <challenge-slug> challenge"
git push origin challenge/<challenge-slug>

6. Open a pull request

Use this template for your PR description:

## Challenge: <Challenge Title>

### What does this challenge teach?
Brief explanation of the Kubernetes concept and why it matters.

### Challenge type
fix | build | migrate

### Difficulty and estimated time
- Difficulty: easy | medium | hard
- Estimated time: X minutes

### Theme
resources-scaling | networking | rbac-security | volumes-secrets | monitoring-debugging

### Testing
- [x] Tested on fresh Kind cluster (`kubeasy dev test --clean`)
- [x] Broken state is reproducible
- [x] All validations fail before fix
- [x] All validations pass after fix
- [x] Kyverno policies prevent bypasses
- [x] Multiple valid solutions accepted
- [x] Objective titles don't reveal the solution
- [x] Estimated time is accurate

Quality standards

Design principles

One clear concept per challenge

A good challenge teaches one specific thing. If you find yourself adding RBAC and networking and storage issues, split them into separate challenges.

Realistic scenarios

Challenges should mirror real production incidents, not artificial puzzles.

GOOD: "A deployment fails because the ServiceAccount lacks permissions to read ConfigMaps"
BAD:  "Find the 3 typos in these YAML files"

Appropriate difficulty

DifficultyDescription
easySingle issue, clear error messages, common scenarios
mediumMultiple related issues, requires systematic debugging
hardComplex interactions, subtle issues, production-level

Mystery-preserving descriptions

Descriptions show symptoms, not causes. Objective titles check outcomes, not implementations.

Code quality

Manifests

  • Use stable, widely-available images (nginx, python, busybox, etc.)
  • Comment intentional bugs for your own reference (comments won't be seen by users in the repo, but help reviewers)
  • Keep resource usage minimal — challenges run on a shared local cluster
  • Avoid external dependencies (no calls to external APIs or services)

Objectives

Every objective should:

  • Have a generic title that doesn't reveal the solution
  • Validate an outcome, not a specific implementation
  • Accept all valid solutions, not just the one you designed for
# GOOD: generic title, outcome-based
- key: stable-operation
  title: "Stable Operation"
  description: "The pod runs without being killed"
  type: event
  spec:
    target:
      kind: Pod
      labelSelector:
        app: my-app
    forbiddenReasons:
      - "OOMKilled"

# BAD: reveals solution, checks implementation
- key: memory-check
  title: "Memory Limit Set to 256Mi"
  description: "Increase the memory limit"
  type: spec
  spec:
    target:
      kind: Deployment
      name: my-app
    checks:
      - path: "spec.template.spec.containers[0].resources.limits.memory"
        value: "256Mi"

Bypass protection

Every challenge must include Kyverno policies to prevent at minimum:

  • Swapping the container image for a working one
  • Deleting and recreating the resource to bypass its broken configuration
apiVersion: kyverno.io/v1
kind: Policy
metadata:
  name: protect-<challenge-slug>
  namespace: <challenge-slug>   # matches the challenge namespace (same as the slug)
spec:
  validationFailureAction: Enforce
  rules:
    - name: preserve-image
      match:
        resources:
          kinds: ["Deployment"]
          names: ["<deployment-name>"]
      validate:
        message: "Cannot change the container image"
        pattern:
          spec:
            template:
              spec:
                containers:
                  - image: "<original-image>"

Review process

Reviewers look for:

  1. Correctness — does the broken state deploy reliably? Do all objectives pass after applying the fix?
  2. Educational value — is the concept clearly taught? Is it appropriate for the stated difficulty?
  3. Quality — are manifests minimal and clean? Do objective titles avoid revealing solutions?
  4. Testing — has it been tested end-to-end on a fresh cluster?

Addressing feedback

# Make requested changes, then:
git add .
git commit -m "fix: address review feedback for <challenge-slug>"
git push origin challenge/<challenge-slug>

Respond to review comments in the PR — the updated diff will be reviewed automatically.

After merge

Once your challenge is merged to main, CI automatically:

  1. Packages it as an OCI artifact
  2. Publishes it to ghcr.io/kubeasy-dev/challenges/<slug>:latest
  3. Makes it available via kubeasy challenge start <slug>

If your challenge has an image/ directory, the custom Docker image is also built and published.

Get help

On this page