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
6 changes: 5 additions & 1 deletion .github/scripts/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ async function loadChallenge(folder) {
difficulty: challenge.difficulty,
type: challenge.type || "fix",
estimatedTime: challenge.estimatedTime,
minRequiredVersion: challenge.minRequiredVersion,
initialSituation: challenge.initialSituation,
objectives: challenge.objectives || [],
};
Expand All @@ -98,7 +99,10 @@ async function syncChallenges(challenges) {

if (!response.ok) {
const error = await response.json();
throw new Error(`API error (${response.status}): ${error.error || 'Unknown error'}\n${error.details || ''}`);
const details = Array.isArray(error.details)
? error.details.map(i => ` - [${i.path?.join('.') || '?'}] ${i.message}`).join('\n')
: (error.details || '');
throw new Error(`API error (${response.status}): ${error.error || 'Unknown error'}${details ? '\n' + details : ''}`);
}

const result = await response.json();
Expand Down
15 changes: 10 additions & 5 deletions .github/scripts/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@

const Ajv2020 = require("ajv/dist/2020");

// Remote schema URL - single source of truth
const SCHEMA_URL = "https://kubeasy.dev/api/schemas/challenge";
// OpenAPI sync spec URL - single source of truth
const SCHEMA_URL = "https://kubeasy.dev/api/openapi/sync.json";

// Cache for the schema to avoid repeated fetches
let cachedSchema = null;

/**
* Fetches the challenge schema from the remote URL
* @returns {Promise<Object>} The JSON schema
* Fetches the challenge item schema from the OpenAPI sync spec.
* Extracts the challenge item definition from the sync endpoint request body.
* @returns {Promise<Object>} The JSON schema for a single challenge
*/
async function fetchRemoteSchema() {
if (cachedSchema) {
Expand All @@ -25,7 +26,11 @@ async function fetchRemoteSchema() {
if (!response.ok) {
throw new Error(`Failed to fetch schema: ${response.status} ${response.statusText}`);
}
cachedSchema = await response.json();
const openapi = await response.json();
cachedSchema = openapi
.paths["/api/admin/challenges/sync"]
.post.requestBody.content["application/json"]
.schema.properties.challenges.items;
return cachedSchema;
} catch (error) {
throw new Error(`Cannot fetch remote schema from ${SCHEMA_URL}: ${error.message}`);
Expand Down
4 changes: 1 addition & 3 deletions access-pending/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ theme: rbac-security
difficulty: hard
type: fix
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
A new application was deployed that needs to query the Kubernetes API during startup.
The pod status shows Running, but the Ready condition stays False.
kubectl describe pod shows the startup probe is failing repeatedly.
Looking at the logs, you see: "Error querying API: forbidden - User cannot list pods".
The application uses a ServiceAccount, but something about the permissions is wrong.
objective: |
Investigate why the application can't access the Kubernetes API.
Fix the configuration so the startup probe passes and the pod becomes Ready.

objectives:
- key: pod-ready-check
Expand Down
5 changes: 1 addition & 4 deletions env-config/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@ theme: volumes-secrets
difficulty: easy
type: build
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
A web application has been deployed to the namespace.
When you check the logs, you see: "ERROR: APP_NAME and APP_ENV not configured".
The application expects configuration via environment variables.
You need to provide these settings using Kubernetes ConfigMaps.
objective: |
Create a ConfigMap with the required configuration values.
Inject the ConfigMap values as environment variables in the deployment.
The application should start successfully with the configuration loaded.

objectives:
- key: app-configured
Expand Down
4 changes: 1 addition & 3 deletions expose-internally/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ theme: pods-containers
difficulty: easy
type: build
estimatedTime: 10
minRequiredVersion: 2.0.0
initialSituation: |
A web application is deployed and running in the namespace.
The pods are healthy and serving traffic on port 8080.
However, there's no way for other pods to reach this application.
You need to make it accessible using a Kubernetes Service.
objective: |
Create a Service to expose the web application internally.
Other pods in the cluster should be able to reach it using the service name.

objectives:
- key: service-reachable
Expand Down
5 changes: 1 addition & 4 deletions first-deployment/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@ theme: pods-containers
difficulty: easy
type: build
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
You've been given access to a Kubernetes namespace called "first-deployment".
The namespace is empty - no resources have been created yet.
Your task is to deploy a web application using a Deployment.
The application should use the nginx:1.25 image.
objective: |
Create a Deployment named "web-server" that runs the nginx:1.25 image.
The Deployment should have at least 1 replica.
The pods must be running and ready.

objectives:
- key: pods-ready
Expand Down
4 changes: 1 addition & 3 deletions first-job/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ theme: jobs-cronjobs
difficulty: easy
type: build
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
The team needs to run a one-time database migration script.
The script takes about 30 seconds to complete and outputs "Migration complete!" when done.
A namespace has been prepared for this task.
objective: |
Create a Kubernetes Job that runs the migration script to completion.
The Job should use the busybox image and simulate the migration with a sleep command.

objectives:
- key: job-complete
Expand Down
4 changes: 1 addition & 3 deletions grant-access/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ theme: rbac-security
difficulty: medium
type: build
estimatedTime: 20
minRequiredVersion: 2.0.0
initialSituation: |
A monitoring application needs to list pods in its namespace.
The app uses a dedicated ServiceAccount, but it has no permissions.
When the app tries to list pods, it gets "Forbidden" errors.
objective: |
Grant the ServiceAccount permission to list pods in its namespace.
The application should be able to query the Kubernetes API successfully.

objectives:
- key: pod-ready
Expand Down
4 changes: 1 addition & 3 deletions job-failed/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ theme: jobs-cronjobs
difficulty: medium
type: fix
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
A CronJob that processes data every night has been consistently failing.
Looking at the Job status, you see it has failed multiple times.
The pod runs for about 30 seconds, then gets terminated.
kubectl describe job shows "DeadlineExceeded" in the events.
The data processing script itself takes about 60 seconds to complete.
objective: |
Investigate why the job keeps getting terminated and fix the configuration.
The processing workflow must complete successfully.

objectives:
- key: job-completion-check
Expand Down
4 changes: 1 addition & 3 deletions missing-credentials/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ theme: volumes-secrets
difficulty: medium
type: fix
estimatedTime: 20
minRequiredVersion: 2.0.0
initialSituation: |
A new microservice was deployed that needs to connect to a PostgreSQL database.
The database credentials are stored in a Kubernetes Secret called "database-credentials".
Running kubectl get secret shows the Secret exists with the expected keys.
However, the pod keeps crashing with: "DATABASE_USER environment variable not set".
The Secret is there, but the pod isn't receiving the credentials properly.
objective: |
Fix the deployment configuration so the database credentials are properly injected.
The application expects: DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD as environment variables.

objectives:
- key: pod-ready-check
Expand Down
3 changes: 1 addition & 2 deletions partial-outage/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ theme: networking
difficulty: easy
type: fix
estimatedTime: 10
minRequiredVersion: 2.0.0
initialSituation: |
A frontend Deployment with 2 replicas and a backend Deployment with 1 replica are deployed in the same namespace.
A NetworkPolicy is defined, but users still report issues — possibly related to intra-cluster communication.
objective: Ensure the frontend can successfully communicate with the backend over HTTP, while keeping traffic restricted.

objectives:
- key: frontend-ready-check
title: "Frontend Ready"
Expand Down
4 changes: 1 addition & 3 deletions persistent-data/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ theme: volumes-secrets
difficulty: medium
type: build
estimatedTime: 20
minRequiredVersion: 2.0.0
initialSituation: |
A note-taking application is deployed but loses all notes when the pod restarts.
The application stores notes in /data/notes.txt.
Users are complaining that their notes keep disappearing.
objective: |
Add persistent storage so notes survive pod restarts.
The application should write to a persistent volume instead of ephemeral storage.

objectives:
- key: pod-ready
Expand Down
4 changes: 1 addition & 3 deletions pod-evicted/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ theme: resources-scaling
difficulty: easy
type: fix
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
A data processing application is deployed as a single pod.
The pod starts but keeps crashing after a few seconds.
It enters a CrashLoopBackOff state and keeps restarting.
The application code hasn't changed - it was working fine in the previous environment.
objective: |
Investigate why the pod keeps crashing and fix it so it runs stably.
The pod should stay running without being killed by the system.

objectives:
- key: pod-running-check
Expand Down
4 changes: 1 addition & 3 deletions privilege-denied/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ theme: rbac-security
difficulty: medium
type: fix
estimatedTime: 20
minRequiredVersion: 2.0.0
initialSituation: |
A legacy application was deployed and worked fine for months.
After a recent cluster update, the pod fails to start.
The container shows a cryptic error and never reaches the Running state.
The exact same image works on other clusters.
objective: |
Investigate why the pod is being blocked from starting.
Make the application run successfully in this cluster's security environment.

objectives:
- key: pod-ready-check
Expand Down
4 changes: 1 addition & 3 deletions probes-drift/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ theme: monitoring-debugging
difficulty: medium
type: fix
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
A notification service was deployed with health checks configured.
The container starts, begins initialization, but Kubernetes keeps restarting it in a loop.
There's no application error in the logs - it just keeps getting killed mid-startup.
objective: |
Stop the crash loop and get the service running.
The app is fine - something about how Kubernetes checks its health isn't right.

objectives:
- key: app-ready-check
Expand Down
4 changes: 1 addition & 3 deletions stuck-pending/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ theme: scheduling-affinity
difficulty: medium
type: fix
estimatedTime: 15
minRequiredVersion: 2.0.0
initialSituation: |
A new application was deployed but the pod stays in Pending state.
Running kubectl describe pod shows events about node selection.
The cluster has nodes with available resources.
Other pods in the namespace are running fine.
objective: |
Investigate why the pod can't be scheduled.
Fix the configuration so the pod starts running.

objectives:
- key: pod-scheduled
Expand Down
4 changes: 1 addition & 3 deletions tainted-out/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ theme: scheduling-affinity
difficulty: medium
type: fix
estimatedTime: 20
minRequiredVersion: 2.0.0
initialSituation: |
A critical application pod stays Pending indefinitely.
Running kubectl describe pod shows taint-related errors.
The node appears to have resources available.
Other system pods are running fine on the same node.
objective: |
Understand why this pod can't schedule and fix it.
The application should run on the available nodes.

objectives:
- key: pod-ready
Expand Down
4 changes: 1 addition & 3 deletions wrong-selector/challenge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ theme: pods-containers
difficulty: easy
type: fix
estimatedTime: 10
minRequiredVersion: 2.0.0
initialSituation: |
A web application was deployed with a Deployment and Service.
The pods are Running and healthy when checked directly.
However, the Service shows 0 endpoints.
Requests to the Service timeout with "no route to host".
objective: |
Make the Service route traffic to the pods.
The application should be reachable through the Service.

objectives:
- key: service-has-endpoints
Expand Down
Loading