The base64 wrapper wasn't enough: DBSecretsManager scanned encrypted_value
into []byte, so the rqlite client applied base64 binary semantics on read and
the ciphertext never round-tripped — get_secret stayed empty. Mirror the
proven push-credentials store exactly: encrypt to a 'enc:'-prefixed base64
string via pkg/secrets and scan the column into a STRING for Decrypt. Text
round-trips cleanly through rqlite regardless of the BLOB column.
Second #837 root cause (the key-derivation fix was necessary but not
sufficient): DBSecretsManager stored the AES-GCM ciphertext as a raw []byte
parameter, but the rqlite client serializes []byte as base64 and reads it
back as that base64 TEXT — never the original bytes. So decrypt() always
received base64 ASCII instead of ciphertext and failed, making get_secret
return empty for every stored secret (exactly the reported symptom).
Encode the ciphertext to an explicit base64 string in Set and decode it in
Get (with a raw fallback), making the round-trip symmetric and
driver-independent. The test mock now emulates rqlite's blob->base64-text
behavior so it's a real regression guard.
- Add `raw_http_response` configuration to functions to allow verbatim HTTP responses
- Implement cluster-wide secrets encryption key generation and distribution for serverless functions
- Update documentation with UnifiedPush support for ntfy on Android/GrapheneOS