{"record":{"id":"adc1cddc17d95a10","repo":"JuliusBrussee/caveman","slug":"secretbox-production-requires-cave-kms-provider-s","errorCode":null,"errorMessage":"secretbox: production requires CAVE_KMS_PROVIDER=scaleway","messagePattern":"secretbox: production requires CAVE_KMS_PROVIDER=scaleway","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"shared/platform/secretbox/secretbox.go","lineNumber":64,"sourceCode":"\t\treturn nil, fmt.Errorf(\"%s must decode to exactly 32 bytes, got %d\", envKey, len(keyBytes))\n\t}\n\treturn keyBytes, nil\n}\n\n// Encrypt seals plaintext with AES-256-GCM and a fresh random nonce, returning\n// nonce(12) || ciphertext+tag as raw bytes.\nfunc Encrypt(plaintext []byte) ([]byte, error) {\n\tif useKMS() {\n\t\tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)\n\t\tdefer cancel()\n\t\twrapped, err := kms.Encrypt(ctx, plaintext)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"secretbox: KMS encrypt: %w\", err)\n\t\t}\n\t\treturn wrapped, nil\n\t}\n\tif runtimeenv.IsProduction() {\n\t\treturn nil, fmt.Errorf(\"secretbox: production requires CAVE_KMS_PROVIDER=scaleway\")\n\t}\n\tkeyBytes, err := loadKey()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tblock, err := aes.NewCipher(keyBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"aes cipher: %w\", err)\n\t}\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"aes-gcm: %w\", err)\n\t}\n\tnonce := make([]byte, gcm.NonceSize())\n\tif _, err := rand.Read(nonce); err != nil {\n\t\treturn nil, fmt.Errorf(\"nonce entropy: %w\", err)\n\t}\n\t// Seal appends the ciphertext+tag to nonce, so the returned slice is the","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/secretbox/secretbox.go#L46-L82","documentation":"secretbox.Encrypt refuses to use local AES-GCM key encryption when runtimeenv.IsProduction() is true, because a shared local key is not acceptable key management in production. The library mandates KMS envelope encryption via CAVE_KMS_PROVIDER=scaleway in production, and throws this sentinel error otherwise. It is a policy guard, not an operational failure.","triggerScenarios":"Calling secretbox.Encrypt in a process where runtimeenv.IsProduction() is true (production environment marker set) while useKMS() is false, i.e. CAVE_KMS_PROVIDER is unset or not 'scaleway'.","commonSituations":"Running a production build locally with a production env flag exported; Docker/K8s deployment missing the CAVE_KMS_PROVIDER=scaleway env var; typo like CAVE_KMS_PROVIDER=Scaleway handled elsewhere but provider simply not configured; staging-config accidentally applied to production.","solutions":["Set CAVE_KMS_PROVIDER=scaleway in the production environment before starting the process.","Ensure the Scaleway KMS credentials (access key, secret key, key ID) are also exported so kms.Encrypt can run.","If this is genuinely not production, fix the environment marker that makes runtimeenv.IsProduction() return true (e.g. CAVE_ENV/NODE_ENV-like variable).","Never bypass this in production; do not attempt to ship a local key instead."],"exampleFix":"// before\n// deployment manifest without KMS config -> secretbox: production requires CAVE_KMS_PROVIDER=scaleway\n\n// after (k8s env block)\nenv:\n  - name: CAVE_KMS_PROVIDER\n    value: \"scaleway\"\n  - name: CAVE_KMS_ACCESS_KEY\n    valueFrom:\n      secretKeyRef: { name: cave-kms, key: access-key }","handlingStrategy":"validation","validationCode":"func checkSecretboxConfig() error {\n    if runtimeenv.IsProduction() && os.Getenv(\"CAVE_KMS_PROVIDER\") != \"scaleway\" {\n        return errors.New(\"production requires CAVE_KMS_PROVIDER=scaleway\")\n    }\n    return nil\n}\n// call at process startup, before any encryption\nif err := checkSecretboxConfig(); err != nil { log.Fatal(err) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the full secretbox/KMS config in an init or health check that runs before any data path.","Encode CAVE_KMS_PROVIDER=scaleway in the production deployment template/manifest, not per-developer env files.","Add a CI check that renders the production config and asserts the KMS provider is set.","Document that local-key encryption is dev-only and must never be configured in prod."],"tags":["kms","encryption","configuration","production","go"],"backgroundTag":"missing-required-config","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}