Go SDK
Zero-dependency Go client for Bella Baxter. Works with stdlib, Gin, Echo, Fiber, and any Go application.
Installation
go get github.com/cosmic-chimps/bella-baxter-goQuick Start
package main
import (
"fmt"
"os"
"github.com/cosmic-chimps/bella-baxter-go/bellabaxter"
)
func main() {
client := bellabaxter.NewClient(bellabaxter.ClientOptions{
BaxterURL: os.Getenv("BELLA_BAXTER_URL"),
APIKey: os.Getenv("BELLA_BAXTER_API_KEY"),
})
secrets, err := client.GetAllSecrets(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(secrets["DATABASE_URL"])
}Framework Integrations
stdlib / chi
// main.go — load before starting the server
secrets, _ := client.GetAllSecrets(ctx)
config := Config{DatabaseURL: secrets["DATABASE_URL"]}
srv := NewServer(config)
srv.ListenAndServe(":8080")Gin
// Use the BellaMiddleware to make secrets available in handlers
r.Use(bellabaxter.GinMiddleware(client))
r.GET("/health", func(c *gin.Context) {
secrets := bellabaxter.SecretsFromContext(c)
c.JSON(200, gin.H{"db": secrets["DATABASE_URL"]})
})Zero-Knowledge Encryption (ZKE)
With ZKE you supply a persistent device key. The server audits which host fetched each secret, the SDK can cache the wrapped DEK, and under ZKE enforcement it is what lets the app read at all: a secrets request that presents no registered key is refused with a 403.
Supplying the key is all it takes. The client then presents it as X-E2E-Public-Key on every secrets request and decrypts the response with it. You do not need EnableE2EE; that option is only for end-to-end encryption without a device key, using an ephemeral key per client.
Generate your device key once:
bella auth setup # stores it owner-only under ~/.config/bella-cli; copy the printed PEMUse it in your app:
client, err := bellabaxter.New(bellabaxter.Options{
BaxterURL: os.Getenv("BELLA_BAXTER_URL"),
ApiKey: os.Getenv("BELLA_BAXTER_API_KEY"),
// Optional — New reads BELLA_BAXTER_PRIVATE_KEY itself when this is empty.
// PEM or bare base64 PKCS#8 DER.
PrivateKeyPEM: os.Getenv("BELLA_BAXTER_PRIVATE_KEY"),
OnWrappedDEK: func(project, env, wrappedDEK string, leaseExpires *time.Time) {
log.Printf("DEK for %s/%s expires %v", project, env, leaseExpires)
},
})Or just set the environment variable — New() reads BELLA_BAXTER_PRIVATE_KEY automatically:
export BELLA_BAXTER_PRIVATE_KEY="$(cat ~/.bella/device-key.pem)"bella sdk run injects that variable for you once the device is set up.
- A key that is set but unreadable is an error.
Newreturns one namingBELLA_BAXTER_PRIVATE_KEY(orOptions.PrivateKeyPEM) and never continues with a throwaway key in its place. - Opting out:
DisableE2EE: truekeeps the key off the wire.Newlogs one warning through the standardlogpackage when a key is supplied anyway, because under enforcement every read will then be refused. Setting bothEnableE2EEandDisableE2EEis an error. - No key: the SDK behaves as before. Secrets responses are plaintext over TLS unless you set
EnableE2EE: true, which uses an ephemeral key per client.
Typed Secrets
bella secrets generate goGenerates an AppSecrets struct with compile-time checking. The same pattern as Gin middleware but fully typed.
All Samples
| Sample | Pattern | Link |
|---|---|---|
01-dotenv-file | bella pull → godotenv | GitHub |
02-process-inject | bella run -- go run . | GitHub |
03-stdlib | SDK in main(), Config struct | GitHub |
04-gin | SDK as Gin middleware | GitHub |
05-typed-secrets | Generated AppSecrets struct | GitHub |