Files
goclaw/CONTRIBUTING.md
T
viettranx 7ae9721c2b docs(contrib): tenant-scope guard rules for admin writes
Role checks are not tenant checks — a non-master tenant admin holds
RoleAdmin in their own tenant and passes role-only middleware by
design. CLAUDE.md gains a one-line directive pointing at CONTRIBUTING
for the full decision table + anti-patterns. CONTRIBUTING gains:

- Target-table decision table (global vs tenant-scoped) with the
  matching guard for each (requireMasterScope vs requireTenantAdmin).
- Shared predicate reference: store.IsMasterScope(ctx).
- Anti-pattern list for reviewers: writes to no-tenant_id tables
  without master-scope check, SQL tenant_id IS NULL arms on write
  paths, role-only admin gates, revoke/delete handlers that skip
  pre-fetch ownership verification.
2026-04-12 10:48:31 +07:00

4.7 KiB
Raw Blame History

Contributing to GoClaw

Branch Strategy

main (stable, protected — owner-only merge)
  └── dev (default target for all PRs)
        ├── feat/xxx
        ├── fix/xxx
        └── ...

Rules

  1. All PRs target devmain is frozen for stable releases
  2. Hotfixes — PR to main, then cherry-pick to dev
  3. Releases — owner merges devmain when stable
  4. Direct push to main — blocked (ruleset enforced)

Branch Naming

  • feat/description — new features
  • fix/description — bug fixes
  • hotfix/description — urgent production fixes (target main)
  • refactor/description — code improvements
  • docs/description — documentation changes

PR Guidelines

Before Submitting

go fix ./...                        # Apply Go upgrades
go build ./...                      # PG build check
go build -tags sqliteonly ./...     # Desktop build check
go vet ./...                        # Static analysis
go test -race ./...                 # Tests with race detector

For web UI changes:

cd ui/web && pnpm build

PR Review Criteria

Based on our automated review checklist:

  • Correctness: No logic errors, nil dereference, race conditions
  • Security: Parameterized SQL, no hardcoded secrets, input validation
  • Breaking changes: API contracts, DB migrations, config format
  • Tenant isolation: All queries scoped by tenant_id. Admin writes require the correct scope guard — see section below
  • i18n: User-facing strings in all 3 locales (en/vi/zh)
  • SQLite parity: Changes compile with -tags sqliteonly
  • Mobile UI: h-dvh not h-screen, 16px input fonts, safe areas

Tenant-Scope Guards

RoleAdmin checks role, not tenant. A non-master tenant admin holds RoleAdmin in their own tenant and passes role-only middleware. Pick the guard by the target table:

Target Example Guard
Global (no tenant_id column) builtin_tools, disk config, pip/npm/apk HTTP requireMasterScope · WS requireMasterScope(requireOwner(...))
Tenant-scoped (has tenant_id column) agents, skills, llm_providers requireTenantAdmin + store SQL WHERE tenant_id = $N

Shared predicate: store.IsMasterScope(ctx) (internal/store/context.go).

Anti-patterns flagged in review:

  • store.Update(...) on a no-tenant_id table without a master-scope check upstream
  • Write SQL with WHERE ... (tenant_id = $N OR tenant_id IS NULL) — the IS NULL arm lets tenants reach system rows
  • requireAuth(RoleAdmin) as the sole gate on a global-state write
  • Admin revoke/delete handlers that skip pre-fetch ownership verification (store SQL alone is not enough when it matches IS NULL arms)

Commit Messages

Use conventional commits:

feat: add user preferences API
fix: prevent race condition in session cleanup
docs: update API reference for v2 endpoints
refactor: extract provider retry logic

Workflow

Developer                    Reviewer                 Owner
    │                            │                      │
    ├─ create feat/xxx ──────────┤                      │
    ├─ PR → dev ─────────────────┤                      │
    │                            ├─ review + approve    │
    │                            ├─ CI passes ──────────┤
    │                            │                      ├─ merge to dev
    │                            │                      │
    │                            │        (when stable) ├─ PR dev → main
    │                            │                      ├─ merge → auto release
    │                            │                      │  (semantic-release)

Releases

Standard (automatic)

Merge devmain. go-semantic-release analyzes commit messages and auto-creates:

  • GitHub Release with version tag (vX.Y.Z)
  • Cross-platform binaries (linux/darwin × amd64/arm64)
  • Docker images (4 variants: latest, base, full, otel + web)
  • SHA256 checksums
  • Discord notification

Beta (manual tag)

Push a beta tag from dev to create a prerelease:

# Standard beta — builds Docker + Linux binaries
git tag v2.67.0-beta.1
git push origin v2.67.0-beta.1

# Desktop beta — builds macOS .dmg + Windows .exe
git tag lite-v1.2.0-beta.1
git push origin lite-v1.2.0-beta.1

Beta releases are marked as prerelease on GitHub and use :beta rolling Docker tag.

Desktop / Lite

Push a lite-v* tag to build desktop apps:

git tag lite-v1.1.0
git push origin lite-v1.1.0

Tags with -beta or -rc suffix automatically create prereleases.