clavitor/clavis/clavis-vault/edition/CLAUDE.md

191 lines
6.2 KiB
Markdown

# Clavitor Edition System
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-vault (this subproject). You are **Sarah**. Commercial-only code MUST be behind build tags so community builds cannot accidentally activate it.
This directory implements build-time differentiation between **Community** (OSS) and **Commercial** (hosted) editions of Clavitor Vault.
## Architecture
```
edition/
├── edition.go # Interface definition (build-agnostic)
├── community.go # Community Edition (default, !commercial build tag)
└── commercial.go # Commercial Edition (commercial build tag)
```
## Build Instructions
### Community Edition (Default)
```bash
# Self-hosted, no telemetry, Elastic 2
go build -o clavitor ./cmd/clavitor/
```
### Commercial Edition
```bash
# Managed by clavitor.ai, telemetry enabled, SCIM/SIEM support
go build -tags commercial -o clavitor ./cmd/clavitor/
```
## Key Differences
| Feature | Community | Commercial |
|---------|-----------|------------|
| Telemetry | Manual opt-in via CLI flags | Enabled by default, centralized |
| Operator Alerts | Local logs only | POSTs to `/v1/alerts` endpoint |
| **Replication** | **Not available** | **Real-time sync to backup POPs (Calgary/Zurich)** |
| **Tarpit** | **Not available (simple 404)** | **30s connection drain (anti-scanner)** |
| Central Management | None | Multi-POP dashboard at clavitor.ai |
| SCIM/SIEM | No | Yes |
| **License** | Elastic License 2.0 | Commercial license |
## Commercial-Only Features
The following features are **only available in Commercial Edition** and do not exist in Community code:
### 1. Real-Time Replication to Backup POPs
**Build constraint:** `//go:build commercial`
Background replicator that:
- Polls `EntryListUnreplicated()` every 30 seconds
- POSTs encrypted entry blobs to backup POP (Calgary or Zurich)
- Automatic retry with exponential backoff (max 5 retries)
- Batching for efficiency (up to 100 entries per request)
- Conflict resolution: last-write-wins by timestamp
- Automatic failover: primary → backup POP switching
**Community behavior:** No replication code. `ReplicatedAt` field exists in DB schema (for future compatibility) but is never populated or read.
### 2. Multi-POP Failover
Commercial POPs register with the control plane. If primary POP fails, DNS routes to backup within 60 seconds.
### 3. Centralized Audit Log Aggregation
All operator alerts across all POPs feed into central dashboard at clavitor.ai.
### 4. Tarpit (Anti-Scanner Defense)
**Build constraint:** `//go:build commercial`
Commercial edition includes a "tarpit" handler for 404/405 responses that:
- Holds unrecognized requests for 30 seconds
- Drips one byte per second to keep connection alive
- Wastes scanner/bot resources (automated tools timeout waiting)
- Capped at 1000 concurrent connections (drops excess immediately)
- **Interruptible on shutdown** — checks `edition.ShutdownContext` each second
**Community behavior:** Simple 404/405 responses. Fast, user-friendly, immediate shutdown.
**Why this is commercial-only:**
- Self-hosted users (community) don't need anti-scanner defense
- Tarpit complicates shutdown (needs context cancellation)
- Enterprise (commercial) faces more automated attacks
## Usage in Code
### Sending Operator Alerts
```go
// Always use edition.Current.AlertOperator() instead of log.Printf
edition.Current.AlertOperator(ctx, "auth_error", "message", map[string]any{
"key": "value",
})
```
**Community behavior:** Logs to stderr with `OPERATOR ALERT [type]: message` prefix.
**Commercial behavior:** Logs locally + POSTs JSON to `{TelemetryHost}/v1/alerts`.
### Checking Edition
```go
if edition.Current.Name() == "commercial" {
// Commercial-only features
}
if edition.Current.IsTelemetryEnabled() {
// Telemetry is active (commercial always, community if configured)
}
```
### Commercial Configuration
Only valid for commercial builds. Community builds log a warning if called.
```go
edition.SetCommercialConfig(&edition.CommercialConfig{
TelemetryHost: "https://hq.clavitor.com",
TelemetryToken: "bearer-token",
TelemetryFreq: 300, // 5 minutes
POPRegion: "us-east-1",
})
// Start periodic telemetry reporting
ctx := context.Background()
edition.StartTelemetry(ctx)
```
## Environment Variables (Commercial)
| Variable | Purpose |
|----------|---------|
| `TELEMETRY_HOST` | Base URL for telemetry (e.g., `https://hq.clavitor.com`) |
| `TELEMETRY_TOKEN` | Bearer token for authentication |
| `TELEMETRY_FREQ` | Seconds between POSTs (default: 300) |
| `POP_REGION` | POP identifier for dashboards |
## Alert Endpoint (Commercial)
Commercial builds POST to:
```
POST {TelemetryHost}/v1/alerts
Authorization: Bearer {TelemetryToken}
Content-Type: application/json
```
Payload:
```json
{
"edition": "commercial",
"type": "auth_system_error",
"message": "Agent lookup failed",
"details": {"error": "..."},
"hostname": "pop-us-east-1-03",
"pop_region": "us-east-1",
"timestamp": "2026-04-02T00:11:45Z"
}
```
### Handling 404/Method Not Allowed
The router uses edition-specific handlers for unmatched routes:
```go
notFoundHandler := edition.Current.NotFoundHandler()
r.NotFound(notFoundHandler)
r.MethodNotAllowed(notFoundHandler)
```
**Community:** Returns simple 404. Fast shutdown, no resource waste.
**Commercial:** Tarpit handler holds connections for 30s (anti-scanner), but exits immediately on `edition.ShutdownContext` cancellation.
## Important Notes for Opus
1. **Never remove the build tags** — they're essential for the dual-license model.
2. **Always use `edition.Current`** — don't branch on build tags in application code.
3. **Community is default** — if someone builds without tags, they get OSS edition.
4. **Commercial config is optional** — commercial builds work without telemetry (just logs).
5. **Telemetry is separate** — the old `lib/telemetry.go` still exists for community opt-in.
## Testing
```bash
# Test community
go test ./edition/...
# Test commercial
go test -tags commercial ./edition/...
# Build both
go build ./cmd/clavitor/ && go build -tags commercial ./cmd/clavitor/
```