Skip to main content

Project

Contributing

Golden rules, the PR bar and the review checklist.

CONTRIBUTING.md
On this page

Thanks for your interest in SnowOps Labs — the flight simulator for platform engineers. This project thrives on community-contributed scenarios, platform modules, documentation, and code. This guide explains how to contribute and what to expect.

New here? The highest-leverage place to start is content — a new scenario or incident. Start with Your First Scenario and look for issues labelled good first issue.

Code of Conduct

By participating you agree to our Code of Conduct.

Sign-off (DCO)

SnowOps Labs uses the Developer Certificate of Origin — a lightweight, no-paperwork way to certify you wrote (or have the right to submit) your contribution. Just add a Signed-off-by line to each commit by committing with -s:

git commit -s -m "your message"

The DCO check in CI verifies every commit in a PR is signed off. That's the only agreement required — no CLA, no bot account, no click-through.

What you can contribute

Type Where it lives Review owner
Scenarios scenarios/ scenario maintainers
Platform modules platform/<category>/<provider>/ platform maintainers
Incidents / learning / challenges incidents/, learn/, challenges/ scenario maintainers
Documentation docs/ docs maintainers
Engine / CLI / SDK src/cmd/, src/internal/, src/pkg/, src/engine/ lead maintainer (see GOVERNANCE.md)

Changes to the engine, the public SDK (pkg/), or the scenario schema require an RFC first — a short markdown PR under docs/rfcs/ that a maintainer approves before implementation. This keeps architectural direction coherent.

Development setup

Unlike end users (who download a released labctl binary — see the README Quickstart), contributors build labctl from source so they can test their changes. You need Go 1.24+ and Node 22+. The steps are identical on macOS, Linux, and Windows/WSL2 — on Windows run them inside your WSL2 distro, never native PowerShell.

# 1. Build the CLI, UI embedded (no committed binary). The Go module lives under
#    src/; the root make targets delegate there and the binary lands at bin/labctl.
make cli-build
 
# 2. Run the gates. All four test layers are mandatory — see docs/TESTING.md.
make test          # Go unit + shell (bats), race detector, coverage gate
make test-ui       # vitest component tests
make test-e2e      # playwright journeys
make lint          # gofmt, golangci-lint, gosec, govulncheck, shellcheck,
                   # shfmt, the portability gate, and TypeScript strict
 
# 3. Bring up a local cluster + platform to test changes end to end. Use the CLI
#    you just built — it drives the same loop end users run:
bin/labctl init                    # setup-tools + create cluster + install platform
bin/labctl scenario up observability-sre

New to the repo? Work through R00 — Environment & Build once; it verifies your setup and shows you each gate biting.

Before you start: the traps

Every one of these was learned by something failing silently on a real cluster, and each is an afternoon you do not have to lose:

  • Helmupgrade and uninstall both ignore CRDs; most of a StatefulSet spec is immutable: R05.
  • Metrics, logs and traces — empty-selector fallbacks, Tempo's real port, Promtail relabelling, k6's units: R13.
  • Writing a scenario — values ownership, chart pinning, checks that teach: scenario schema.

docs/AGENT-CONTEXT.md is the index: it says which single document answers which task, and lists every invariant in one place. It is written for AI agents, but it is the fastest orientation for a human too.

The golden rules (please read before a code/content PR)

  1. Cross-platform. Must run on macOS (Apple Silicon + Intel) and modern Linux. No GNU-only shell flags (grep -P, sed -i without a backup suffix, readlink -f, date -d), and no cgo — it breaks cross-compilation. make lint-shell enforces this automatically.
  2. Go orchestrates, scripts do the work. Don't move shell/helm/kubectl logic into Go.
  3. Declarative content. Scenarios, faults, learning paths and checks are YAML + scripts — never hardcoded in Go.
  4. Idempotent everything. helm upgrade --install, kubectl apply, safe re-activation. Interrupting an operation and re-running it must converge.
  5. Every operation is cancellable and durable. Anything that shells out goes through internal/run with a context, a timeout and a lock key. Never call exec.Command(...).Run() directly.
  6. Tests at every applicable layer. Go unit (table-driven, hermetic, ≥80%, cancellation covered), bats for scripts with logic, contract tests for endpoints and commands, Vitest + Playwright for UI. See docs/TESTING.md.
  7. Docs and runbook in the same PR. Update the relevant docs/, add or update the runbook, and write an ADR if you made a notable decision. Documentation is the source of truth here — the code is expected to match it, and make docs-check gates the links and the pages the website publishes.
  8. Comments say why, briefly. Three lines is a lot. No task, ticket or wave numbers in code — that history belongs in git and in ADRs.

Pull-request workflow

fork branch make your change run lint + tests commit with -s (DCO) →
open a PR CI green CODEOWNERS review maintainer merge
  • Keep PRs focused and small where possible.
  • Use Conventional Commits (feat:, fix:, docs:, ci:, chore:).
  • Fill out the PR template (what/why/how-tested).
  • CI must pass every gate: Go build/vet/test on macOS and Linux with the race detector, the per-package coverage gate, golangci-lint, gosec, govulncheck, a fuzz smoke run, bats, shellcheck, the portability gate, TypeScript strict, vitest, Playwright, the license scan, and content validation. None of them are advisory.
  • A maintainer or domain code owner reviews; the lead maintainer holds final merge authority on engine/SDK/schema changes (see GOVERNANCE.md).

Reporting bugs / requesting features

Use the issue templates. For security vulnerabilities, do not open a public issue — follow SECURITY.md.

Licensing of contributions

All contributions are licensed under Apache-2.0 (the same license as the project); your Signed-off-by line certifies you have the right to submit them under it (see DCO.md). New source files should carry an SPDX header:

// SPDX-License-Identifier: Apache-2.0

Thank you for helping build the open platform-engineering simulator. ✈️

The incident field notes

One real Kubernetes failure a week — the symptom, the commands that found it, and the fix. Written from actual lab runs, not from memory.

Signups aren't open yet — set NEXT_PUBLIC_NEWSLETTER_ENDPOINT to the Kit form endpoint to switch this on.

You'll get the Kubernetes Incident Response Field Guide, plus occasional emails about new scenarios, posts and paid offerings such as courses and workshops. Unsubscribe any time.