6.2 KiB
Clavitor Edition System
Required reading before any work: 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)
# Self-hosted, no telemetry, Elastic 2
go build -o clavitor ./cmd/clavitor/
Commercial Edition
# 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.ShutdownContexteach 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
// 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
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.
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:
{
"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:
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
- Never remove the build tags — they're essential for the dual-license model.
- Always use
edition.Current— don't branch on build tags in application code. - Community is default — if someone builds without tags, they get OSS edition.
- Commercial config is optional — commercial builds work without telemetry (just logs).
- Telemetry is separate — the old
lib/telemetry.gostill exists for community opt-in.
Testing
# Test community
go test ./edition/...
# Test commercial
go test -tags commercial ./edition/...
# Build both
go build ./cmd/clavitor/ && go build -tags commercial ./cmd/clavitor/