From 9b27b415d3cfb1a609a9b5ca44e1a7fae7e45eab Mon Sep 17 00:00:00 2001 From: dmadisetti Date: Fri, 17 Apr 2026 11:30:28 -0700 Subject: [PATCH] chore: repo health --- .github/ISSUE_TEMPLATE/bug_report.yaml | 63 +++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 ++ .github/ISSUE_TEMPLATE/feature_request.yaml | 46 +++++++ .github/pull_request_template.md | 17 +++ .pre-commit-config.yaml | 23 ++++ CLAUDE.md | 145 ++++++++++++++++++++ CONTRIBUTING.md | 100 +++++++++++++- SECURITY.md | 23 ++++ 8 files changed, 419 insertions(+), 6 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yaml create mode 100644 .github/pull_request_template.md create mode 100644 .pre-commit-config.yaml create mode 100644 CLAUDE.md create mode 100644 SECURITY.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..3fb72a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,63 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/github-issue-forms.json +name: "🐞 Bug report" +description: Report an issue with the marimo-operator or kubectl-marimo plugin +labels: [bug] +body: + - type: markdown + attributes: + value: | + Thank you for filing this bug report! + + **Tip:** You can check the operator version and logs quickly with: + ```bash + kubectl logs -n marimo-operator-system -l control-plane=controller-manager --tail=50 + kubectl describe marimo + ``` + + - type: textarea + id: bug-description + attributes: + label: Describe the bug + description: What went wrong? Include any error messages or stack traces. + placeholder: | + Running `kubectl marimo edit notebook.py` fails with: + ... + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Steps to reproduce + description: The smallest set of steps or YAML that triggers the bug. + placeholder: | + 1. Apply this MarimoNotebook CR: + ```yaml + apiVersion: marimo.io/v1alpha1 + kind: MarimoNotebook + ... + ``` + 2. Run `kubectl get marimos` + 3. See error... + validations: + required: false + + - type: textarea + id: env + attributes: + label: Environment + value: | + - **operator version** (image tag or `kubectl get deployment -n marimo-operator-system`): + - **kubectl-marimo version** (`kubectl-marimo --version`): + - **Kubernetes version** (`kubectl version --short`): + - **Cloud / cluster type** (e.g. CKS, GKE, kind): + - **OS**: + validations: + required: true + + - type: checkboxes + id: will-submit-pr + attributes: + label: Will you submit a PR? + options: + - label: "Yes, I'd like to fix this" diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..57cbac1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Discord Chat + url: https://marimo.io/discord?ref=issues + about: Ask questions and chat with the marimo community. + - name: GitHub Discussions + url: https://github.com/marimo-team/marimo-operator/discussions + about: Use Discussions for questions, ideas, and general conversation. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000..a9f7aa1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,46 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/refs/heads/master/src/schemas/json/github-issue-forms.json +name: "🚀 Feature request" +description: Propose a new feature or improvement for the marimo-operator +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to propose a new feature! + + - type: textarea + id: problem + attributes: + label: Problem / motivation + description: What are you trying to do that is currently difficult or impossible? + placeholder: I'm trying to ... but I can't because ... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Describe the feature or behavior you'd like to see. Include example YAML or CLI usage if applicable. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Any workarounds or alternative approaches you've tried? + + - type: textarea + id: context + attributes: + label: Additional context + description: Screenshots, links, prior art, or anything else that helps explain the request. + + - type: checkboxes + id: will-submit-pr + attributes: + label: Are you willing to submit a PR? + description: Please confirm with the team before starting work on a large feature. + options: + - label: "Yes, I'd like to implement this" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..b3d84a4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,17 @@ +## Summary + + + +Closes # + +## Checklist + +- [ ] Any AI-generated code has been reviewed line-by-line by the human PR author. +- [ ] Tests have been added or updated for the changes (where applicable). +- [ ] `make lint` and `make test` pass locally (operator). +- [ ] `uv run pytest` and `uv run ty check kubectl_marimo` pass locally (plugin). +- [ ] If CRD fields changed, `make manifests` has been run and generated files are committed. +- [ ] Documentation updated where relevant. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..f4cccc9 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-merge-conflict + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.11.6 + hooks: + - id: ruff + args: [--fix] + files: ^plugin/ + - id: ruff-format + files: ^plugin/ + + - repo: https://github.com/dnephin/pre-commit-golang + rev: v0.5.1 + hooks: + - id: go-fmt + - id: go-vet diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c59c026 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,145 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build & Test Commands + +### Operator (Go) + +```bash +make test # Unit tests with coverage +make test-e2e # E2E tests on Kind cluster (creates cluster automatically) +make fmt # go fmt +make vet # go vet +make lint # golangci-lint +make lint-fix # Auto-fix lint issues +make build # Build manager binary to bin/manager +make manifests # Regenerate CRD YAML and RBAC from types +make generate # Regenerate DeepCopy methods +make build-installer # Regenerate deploy/install.yaml +``` + +### Plugin (Python) + +```bash +cd plugin +uv sync --dev # Install dev dependencies +uv run pytest tests -v # Run all tests +uv run pytest tests/test_deploy.py # Run single test file +uv run ty check kubectl_marimo # Static type checking +``` + +## Architecture + +marimo-operator is a Kubernetes operator (Go, controller-runtime) that manages `MarimoNotebook` custom resources, plus a Python kubectl plugin (`kubectl-marimo`) for deploying individual local notebooks. + +### Operator (Go) + +For each `MarimoNotebook` CR the controller creates: +- **PVC** — persistent storage, **intentionally has no owner reference** (not GC'd on CR delete; requires explicit `--delete-pvc`) +- **Pod** — init container clones `spec.source` git repo into `/data`, then marimo container serves from there; sidecars share the same PVC volume +- **Service** — exposes marimo port (default 2718) and any sidecar `exposePort`s + +Pod updates use a **recreate** strategy (delete + recreate); init container skips clone if `/data` already has content, preserving edits across restarts. + +Key files: +- `api/v1alpha1/marimonotebook_types.go` — CRD schema (all spec fields with defaults) +- `internal/controller/marimonotebook_controller.go` — reconciliation loop +- `pkg/resources/pod.go` — Pod construction (init container, sidecars, mounts) +- `pkg/config/images.go` — configurable default images via env vars + +Configurable default images (set as env vars on the operator deployment): + +| Env Var | Default | Purpose | +|---------|---------|---------| +| `DEFAULT_INIT_IMAGE` | `busybox:1.36` | copy-content init container | +| `GIT_IMAGE` | `alpine/git:latest` | git clone | +| `ALPINE_IMAGE` | `alpine:latest` | sshfs/rsync sidecars | +| `S3FS_IMAGE` | `ghcr.io/marimo-team/marimo-operator/s3fs:latest` | cw:// mounts | +| `S3_ENDPOINT` | `https://cwobject.com` | CoreWeave S3 endpoint | + +### Plugin (Python) + +`kubectl-marimo` reads local `.py`/`.md` notebooks, uploads content to a ConfigMap, creates the `MarimoNotebook` CR, then port-forwards for interactive access. State is tracked in swap files (`.notebook.py.marimo`). + +Key files: +- `plugin/kubectl_marimo/deploy.py` — orchestrates edit/run flows +- `plugin/kubectl_marimo/resources.py` — builds MarimoNotebook CR from frontmatter +- `plugin/kubectl_marimo/formats/` — parsers for `.py` (inline TOML) and `.md` (YAML frontmatter) +- `plugin/kubectl_marimo/swap.py` — tracks deployed notebooks for sync/delete + +Notebook configuration is embedded in frontmatter: + +```python +# /// script +# dependencies = ["marimo", "torch"] +# +# [tool.marimo.k8s] +# storage = "5Gi" +# +# [tool.marimo.k8s.resources] +# limits."nvidia.com/gpu" = 1 +# /// +``` + +## CoreWeave (CKS) Specifics + +### GPU Workloads + +Use `podOverrides.nodeSelector` to target GPU node pools: + +```yaml +spec: + resources: + limits: + nvidia.com/gpu: 2 + podOverrides: + nodeSelector: + compute.coreweave.com/node-pool: gpu-node-pool +``` + +Or via notebook frontmatter: +```python +# [tool.marimo.k8s.resources] +# limits."nvidia.com/gpu" = 2 +``` + +See `plugin/nccl-all-reduce.yaml` for a multi-GPU NCCL all-reduce benchmark example. + +### CoreWeave Object Storage (`cw://`) + +`cw://` mounts attach CoreWeave S3 buckets via an s3fs sidecar (FUSE). The plugin auto-creates the `cw-credentials` secret from `~/.s3cfg`. + +**Setup:** +```bash +# 1. Create access policy, bucket, and token via cwic +cwic cwobject policy create -f cw-policy.json +cwic cwobject mb my-bucket +cwic cwobject token create --name marimo-s3 --duration Permanent + +# 2. Configure ~/.s3cfg +cat > ~/.s3cfg << EOF +[default] +access_key = CWXXXXXXXXXX +secret_key = cwXXXXXXXXXXXX +host_base = cwobject.com +host_bucket = %(bucket)s.cwobject.com +use_https = True +EOF + +# 3. Deploy with mount (auto-creates cw-credentials secret) +kubectl marimo edit --source=cw://my-bucket notebook.py +``` + +Credentials are read from `~/.s3cfg` sections in priority order: `[namespace]` > `[marimo]` > `[default]`. This allows per-namespace credentials in multi-tenant clusters. + +For LOTA-optimized access from GPU nodes, override the S3 endpoint: +```bash +kubectl set env deployment/marimo-operator-controller-manager \ + -n marimo-operator-system \ + S3_ENDPOINT=http://cwlota.com +``` + +Mounted buckets are accessible at `/home/marimo/notebooks/mounts/cw-0/` (cw-1/, cw-2/ for additional mounts). + +See `plugin/docs/cw-mounts.md` for full setup, multi-tenancy, and troubleshooting. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd499cf..845432b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,103 @@ -# Contributing +# Contributing to marimo-operator -## Development Setup +Thank you for your interest in contributing! + +## Prerequisites + +| Tool | Purpose | +|------|---------| +| [Go](https://go.dev) ≥ 1.22 | Operator development | +| [uv](https://docs.astral.sh/uv/) | Python plugin development | +| [kubectl](https://kubernetes.io/docs/tasks/tools/) | Cluster interaction | +| [kind](https://kind.sigs.k8s.io/) | Local Kubernetes cluster for e2e tests | +| [golangci-lint](https://golangci-lint.run/) | Go linting | + +## Development Workflow + +### Operator (Go) + +| Command | What it does | +|---------|-------------| +| `make test` | Run unit tests with coverage | +| `make test-e2e` | Run e2e tests on a Kind cluster (creates + tears down automatically) | +| `make fmt` | Run `go fmt` | +| `make vet` | Run `go vet` | +| `make lint` | Run golangci-lint | +| `make lint-fix` | Auto-fix lint issues | +| `make build` | Build manager binary to `bin/manager` | +| `make manifests` | Regenerate CRD YAML and RBAC from type definitions | +| `make generate` | Regenerate DeepCopy methods | +| `make build-installer` | Regenerate `deploy/install.yaml` | +| `make run` | Run controller locally against current kubeconfig | + +```bash +# Run a single test +go test ./internal/controller/... -run TestReconcile -v + +# Run unit tests only (skip e2e) +make test +``` + +**Important:** After modifying types in `api/v1alpha1/`, always run `make manifests && make generate` and commit the generated files. + +### Plugin (Python) ```bash -git clone https://github.com/marimo-team/marimo-operator.git -cd marimo-operator/plugin +cd plugin uv sync --dev + +# Run all tests +uv run pytest tests -v + +# Run a single test file +uv run pytest tests/test_deploy.py -v + +# Type checking +uv run ty check kubectl_marimo ``` -## Running Tests +### Pre-commit Hooks + +Install once, then hooks run automatically on `git commit`: ```bash -uv run pytest +pip install pre-commit +pre-commit install +``` + +Run manually against all files: + +```bash +pre-commit run --all-files +``` + +## Project Structure + +``` +marimo-operator/ +├── api/v1alpha1/ # CRD type definitions (edit here, then make manifests) +├── internal/controller/ # Reconciliation logic +├── pkg/resources/ # Pod, Service, PVC, ConfigMap builders +├── pkg/config/ # Configurable default images +├── config/ # Kustomize overlays (CRD, RBAC, manager) +├── deploy/ # Generated install.yaml (do not edit by hand) +├── test/e2e/ # E2E tests (Ginkgo) +├── plugin/ # kubectl-marimo Python plugin +│ ├── kubectl_marimo/ # CLI source +│ └── tests/ # Plugin unit tests +└── examples/ # Example deployments ``` + +## Submitting a Pull Request + +1. Fork the repo and create a branch from `main`. +2. Make your changes and add tests for new behavior. +3. Ensure `make lint` and `make test` pass (operator) and `uv run pytest` passes (plugin). +4. If you modified CRD types, run `make manifests` and commit generated files. +5. Open a PR — the template will guide you through the checklist. + +Every bug fix should include a regression test that fails before the fix and passes after. + +## Release Process + +Releases are for maintainers only. Tags trigger the publish workflow which builds and pushes the operator image and publishes the plugin to PyPI. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..3481e9d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Supported Versions + +Only the latest release of `marimo-operator` receives security fixes. + +| Version | Supported | +| ------- | --------- | +| latest | ✅ | +| older | ❌ | + +## Reporting a Vulnerability + +**Please do not open a public GitHub issue for security vulnerabilities.** + +Report vulnerabilities via [GitHub's private security advisory feature](https://github.com/marimo-team/marimo-operator/security/advisories/new). + +We aim to: +- Acknowledge receipt within **3 business days** +- Triage and assess severity within **7 business days** +- Release a patch within **90 days** (sooner for critical issues) + +We appreciate responsible disclosure and will credit reporters in the release notes unless you prefer to remain anonymous.