mirror of
https://github.com/block/buzz.git
synced 2026-10-28 21:11:48 +00:00
## Why The deletion engine already exposes a one-shot `buzz-admin deletions drain` command, but operators have no safe way to schedule it. A generic workload wrapper could expose arbitrary commands or inherit relay credentials, which would add a second control plane and widen the blast radius. ## What This PR adds an opt-in Kubernetes CronJob for the typed deletion drain command. It is stacked on #7818, which adds owner-request admission. ## How The chart keeps the job disabled by default. The CronJob uses `Forbid`, zero Kubernetes retries, bounded runtime and history, and only the database, Redis, and object-store settings required by the executor. PostgreSQL leases, checkpoints, and retry timing remain the sole durable retry authority. The closed `_operator-jobs.tpl` helper centralizes safe CronJob mechanics without creating an arbitrary command or environment registry. This leaves the touched system simpler than a general job framework would. ## Risk The deployment blast radius is low because the job is disabled by default. When enabled, it can run destructive deletion work that the database has already approved, so the chart limits concurrency, retries, credentials, and execution time. ## Testing Rendered every `deploy/charts/buzz/ci/*.yaml` fixture with `helm template`; all passed at `e68cb753bb6673aa1baa60046969bdb2d4738b62`. Ran the full independent Desktop, Tauri, and web lanes; all passed at `e68cb753bb6673aa1baa60046969bdb2d4738b62`. Flutter package resolution made no progress within three minutes, so the mobile lane is not claimed green. ## Bigger picture A later stack layer must inventory and approve admitted owner requests. Until then, this scheduler cannot make a new owner request destructive. Generated with Codex --------- Signed-off-by: tornquist <tornquist@squareup.com> Signed-off-by: Codex <noreply@openai.com> Signed-off-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz> Co-authored-by: Codex <noreply@openai.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
353 lines
13 KiB
JSON
353 lines
13 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"title": "Buzz Helm chart values",
|
|
"description": "Schema for values.yaml. Catches misconfiguration at `helm install` time before _validate.tpl runtime fails. Both layers are intentional: schema rejects malformed inputs; templates reject inconsistent combinations.",
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": {
|
|
"quickstart": {
|
|
"type": "boolean",
|
|
"description": "Master toggle for evaluation profile (enables postgresql + redis subcharts and chart-side autogen). Not GitOps-safe."
|
|
},
|
|
"image": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"repository": { "type": "string", "minLength": 1 },
|
|
"tag": { "type": "string" },
|
|
"digest": {
|
|
"type": "string",
|
|
"pattern": "^$|^sha256:[0-9a-f]{64}$",
|
|
"description": "Optional immutable OCI image digest. When set, the chart renders repository@digest and ignores tag."
|
|
},
|
|
"pullPolicy": { "type": "string", "enum": ["Always", "IfNotPresent", "Never"] },
|
|
"pullSecrets": {
|
|
"type": "array",
|
|
"items": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" } } }
|
|
}
|
|
},
|
|
"required": ["repository", "pullPolicy"]
|
|
},
|
|
"replicaCount": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"description": "Replica count for the relay Deployment. replicaCount > 1 requires Redis (for buzz-pubsub) — enforced by _validate.tpl. Git storage does NOT need ReadWriteMany: git state is object-store-backed and repo names live in Postgres, so ReadWriteOnce is fine per replica."
|
|
},
|
|
"relayUrl": {
|
|
"type": "string",
|
|
"pattern": "^(wss?://.+)?$",
|
|
"description": "Public wss:// URL clients connect to. Required (validated by _validate.tpl). Drives RELAY_URL, default mediaBaseUrl, default ingress host."
|
|
},
|
|
"mediaBaseUrl": {
|
|
"type": "string",
|
|
"pattern": "^(https?://.+)?$"
|
|
},
|
|
"ownerPubkey": {
|
|
"type": "string",
|
|
"pattern": "^([0-9a-f]{64})?$",
|
|
"description": "64-char lowercase hex Nostr pubkey of the relay operator. Required when relay.requireRelayMembership=true."
|
|
},
|
|
"secrets": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"existingSecret": { "type": "string", "description": "Name of an externally managed Secret. Production / GitOps path." },
|
|
"relayPrivateKey": { "type": "string" },
|
|
"gitHookHmacSecret": { "type": "string" }
|
|
}
|
|
},
|
|
"relay": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": {
|
|
"bindAddr": { "type": "string", "minLength": 1 },
|
|
"maxConnections": { "type": "integer", "minimum": 1 },
|
|
"maxConcurrentHandlers": { "type": "integer", "minimum": 1 },
|
|
"sendBuffer": { "type": "integer", "minimum": 1 },
|
|
"drainJitterMs": { "type": "integer", "minimum": 0 },
|
|
"requireAuthToken": { "type": "boolean" },
|
|
"requireRelayMembership": { "type": "boolean" },
|
|
"allowNipOaAuth": { "type": "boolean" },
|
|
"huddleAudioAvailable": {
|
|
"type": ["boolean", "null"],
|
|
"description": "Whether relay huddle audio is available. null means chart default: true for one replica, false for replicaCount > 1. Explicit true with replicaCount > 1 means the operator accepts/owns external multi-pod audio/SFU behavior."
|
|
},
|
|
"pubkeyAllowlist": { "type": "boolean" },
|
|
"corsOrigins": {
|
|
"type": "array",
|
|
"items": { "type": "string" }
|
|
},
|
|
"ephemeralTtlOverride": { "type": "integer", "minimum": 0 },
|
|
"command": {
|
|
"type": "array",
|
|
"items": { "type": "string" },
|
|
"description": "Optional relay container entrypoint override. Empty preserves the image default."
|
|
},
|
|
"args": {
|
|
"type": "array",
|
|
"items": { "type": "string" },
|
|
"description": "Optional relay container arguments override. Empty preserves the image default."
|
|
},
|
|
"extraVolumeMounts": {
|
|
"type": "array",
|
|
"items": { "type": "object" },
|
|
"description": "Raw Kubernetes volumeMount fragments appended to the relay container."
|
|
}
|
|
}
|
|
},
|
|
"extraInitContainers": {
|
|
"type": "array",
|
|
"items": { "type": "object" },
|
|
"description": "Raw Kubernetes init-container fragments appended to the relay Pod."
|
|
},
|
|
"extraVolumes": {
|
|
"type": "array",
|
|
"items": { "type": "object" },
|
|
"description": "Raw Kubernetes volume fragments appended to the relay Pod."
|
|
},
|
|
"service": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": {
|
|
"type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"] },
|
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
|
"healthPort": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
|
"metricsPort": { "type": "integer", "minimum": 1, "maximum": 65535 }
|
|
}
|
|
},
|
|
"serviceAccount": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"create": { "type": "boolean" },
|
|
"name": { "type": "string" },
|
|
"annotations": { "type": "object" }
|
|
}
|
|
},
|
|
"podDisruptionBudget": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"minAvailable": { "oneOf": [{ "type": "integer" }, { "type": "string" }] },
|
|
"maxUnavailable": { "oneOf": [{ "type": "integer" }, { "type": "string" }] }
|
|
}
|
|
},
|
|
"ingress": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"className": { "type": "string" },
|
|
"annotations": { "type": "object" },
|
|
"hosts": { "type": "array" },
|
|
"tls": { "type": "array" }
|
|
}
|
|
},
|
|
"httproute": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"parentRefs": { "type": "array" },
|
|
"hostnames": { "type": "array", "items": { "type": "string" } },
|
|
"rules": { "type": "array" }
|
|
}
|
|
},
|
|
"persistence": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"git": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"mountPath": { "type": "string", "minLength": 1 },
|
|
"storageClass": { "type": "string" },
|
|
"accessMode": { "type": "string", "enum": ["ReadWriteOnce", "ReadWriteMany", "ReadOnlyMany", "ReadWriteOncePod"] },
|
|
"size": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)?$" },
|
|
"annotations": { "type": "object" },
|
|
"existingClaim": { "type": "string" }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"postgresql": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": { "enabled": { "type": "boolean" } }
|
|
},
|
|
"externalPostgresql": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"url": { "type": "string", "pattern": "^(postgres(ql)?://.+)?$" }
|
|
}
|
|
},
|
|
"redis": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"properties": { "enabled": { "type": "boolean" } }
|
|
},
|
|
"externalRedis": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"url": { "type": "string", "pattern": "^(rediss?://.+)?$" }
|
|
}
|
|
},
|
|
"s3": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"endpoint": { "type": "string", "pattern": "^(https?://.+)?$" },
|
|
"bucket": { "type": "string", "minLength": 1 },
|
|
"region": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"description": "S3 region used for SigV4 signing by the relay and deletion operator. Defaults to us-east-1 for bundled MinIO/local deployments; set the provider region explicitly when it differs."
|
|
},
|
|
"addressingStyle": {
|
|
"type": "string",
|
|
"enum": ["path", "virtual"],
|
|
"description": "S3 URL style shared by media and Git/CAS clients. Defaults to path for bundled MinIO compatibility."
|
|
},
|
|
"accessKey": { "type": "string" },
|
|
"secretKey": { "type": "string" }
|
|
}
|
|
},
|
|
"storageAccounting": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"schedule": { "type": "string", "minLength": 1 },
|
|
"maxObjects": { "type": "integer", "minimum": 1 },
|
|
"activeDeadlineSeconds": { "type": "integer", "minimum": 1 },
|
|
"successfulJobsHistoryLimit": { "type": "integer", "minimum": 0 },
|
|
"failedJobsHistoryLimit": { "type": "integer", "minimum": 0 },
|
|
"relayMode": { "type": "string", "enum": ["inline", "external", "off"] },
|
|
"serviceAccountName": { "type": "string" },
|
|
"podLabels": { "type": "object" },
|
|
"podAnnotations": { "type": "object" },
|
|
"resources": { "type": "object" }
|
|
}
|
|
},
|
|
"operatorJobs": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"deletionDrain": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"schedule": { "type": "string", "minLength": 1 },
|
|
"activeDeadlineSeconds": { "type": "integer", "minimum": 1, "maximum": 86400 },
|
|
"successfulJobsHistoryLimit": { "type": "integer", "minimum": 0, "maximum": 10 },
|
|
"failedJobsHistoryLimit": { "type": "integer", "minimum": 0, "maximum": 10 },
|
|
"terminationGracePeriodSeconds": { "type": "integer", "minimum": 1, "maximum": 300 },
|
|
"serviceAccountName": { "type": "string" },
|
|
"podLabels": {
|
|
"type": "object",
|
|
"additionalProperties": { "type": "string" }
|
|
},
|
|
"podAnnotations": {
|
|
"type": "object",
|
|
"additionalProperties": { "type": "string" }
|
|
},
|
|
"resources": { "type": "object" }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"minio": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"image": { "type": "string", "minLength": 1 },
|
|
"mcImage": { "type": "string", "minLength": 1 },
|
|
"persistence": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"size": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)?$" }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"git": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"maxPackBytes": { "type": "integer", "minimum": 1 },
|
|
"packCachePath": { "type": "string", "minLength": 1 },
|
|
"packCacheMaxBytes": { "type": "integer", "minimum": 0 },
|
|
"packCacheMaxConcurrentPopulations": { "type": "integer", "minimum": 1 },
|
|
"packCacheVolumeSize": { "type": "string", "pattern": "^[0-9]+(\\.[0-9]+)?(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)?$" },
|
|
"maxReposPerPubkey": { "type": "integer", "minimum": 1 },
|
|
"maxConcurrentOps": { "type": "integer", "minimum": 1 }
|
|
}
|
|
},
|
|
"migrate": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"autoMigrate": { "type": "boolean" },
|
|
"preUpgradeJob": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"resources": { "type": "object" },
|
|
"backoffLimit": { "type": "integer", "minimum": 0 },
|
|
"activeDeadlineSeconds": { "type": "integer", "minimum": 1 }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"serviceMonitor": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"namespace": { "type": "string" },
|
|
"interval": { "type": "string" },
|
|
"scrapeTimeout": { "type": "string" },
|
|
"labels": { "type": "object" }
|
|
}
|
|
},
|
|
"pairingRelay": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"enabled": { "type": "boolean" },
|
|
"url": {
|
|
"type": "string",
|
|
"pattern": "^(wss?://.+)?$",
|
|
"description": "Public WebSocket URL advertised to clients for NIP-AB device pairing."
|
|
},
|
|
"replicaCount": { "type": "integer", "minimum": 1 },
|
|
"service": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"properties": {
|
|
"type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"] },
|
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
|
"annotations": { "type": "object" }
|
|
}
|
|
},
|
|
"podAnnotations": { "type": "object" },
|
|
"podLabels": { "type": "object" },
|
|
"resources": { "type": "object" }
|
|
}
|
|
},
|
|
"extraManifests": {
|
|
"type": "array"
|
|
}
|
|
}
|
|
}
|