feat: wire Infisical secret store into API server and MCP tools
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

- Wire secretsManager in NewHandler() — instantiate InfisicalBackend
  when OIKOS_INFISICAL_SITE_URL is set (previously always nil)
- Add get_secret, list_secrets, set_secret MCP tools with nil-backend
  graceful degradation
- Add oikos secret get|set|list CLI subcommands for Infisical
- Fix Set() bug: create-before-update so new keys are created;
  add Type: "shared" to Update so it finds the right secret;
  disable SDK cache so Get returns fresh data after Set
- Clean enrollment response: remove fake infisical_client_id/
  infisical_client_secret stubs, store age key in Infisical for real
This commit is contained in:
2026-08-05 23:03:27 +02:00
parent 38c472a118
commit e3449b24c1
12 changed files with 590 additions and 241 deletions

View File

@@ -31,14 +31,13 @@ type InfisicalConfig struct {
// NewInfisicalBackend creates an Infisical backend. Connects lazily on first Get.
func NewInfisicalBackend(cfg InfisicalConfig) *InfisicalBackend {
autoRefresh := true
cacheExpiry := 300 // 5 min cache
return &InfisicalBackend{
cfg: cfg,
client: infisical.NewInfisicalClient(context.Background(), infisical.Config{
SiteUrl: cfg.SiteURL,
AutoTokenRefresh: &autoRefresh,
CacheExpiryInSeconds: cacheExpiry,
CacheExpiryInSeconds: 0, // no caching — live reads over localhost
}),
}
}
@@ -130,22 +129,24 @@ func (b *InfisicalBackend) Set(ctx context.Context, key string, value string) er
return err
}
// Try update first, fall back to create
_, err := b.client.Secrets().Update(infisical.UpdateSecretOptions{
SecretKey: key,
NewSecretValue: value,
Environment: b.cfg.Env,
SecretPath: b.cfg.SecretPath,
ProjectID: b.cfg.ProjectID,
// Try create first (idempotent — upserts); fall back to update on conflict.
_, err := b.client.Secrets().Create(infisical.CreateSecretOptions{
SecretKey: key,
SecretValue: value,
Environment: b.cfg.Env,
SecretPath: b.cfg.SecretPath,
ProjectID: b.cfg.ProjectID,
Type: "shared",
})
if err != nil {
_, err = b.client.Secrets().Create(infisical.CreateSecretOptions{
SecretKey: key,
SecretValue: value,
Environment: b.cfg.Env,
SecretPath: b.cfg.SecretPath,
ProjectID: b.cfg.ProjectID,
Type: "shared",
// Create failed (key may already exist) — update instead.
_, err = b.client.Secrets().Update(infisical.UpdateSecretOptions{
SecretKey: key,
NewSecretValue: value,
Environment: b.cfg.Env,
SecretPath: b.cfg.SecretPath,
ProjectID: b.cfg.ProjectID,
Type: "shared",
})
}
return err