diff --git a/VERSION b/VERSION index 81566e4..4daf42f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.27.0 \ No newline at end of file +0.27.1 \ No newline at end of file diff --git a/cmd/nomos/main.go b/cmd/nomos/main.go index 9af73d4..aab9b93 100644 --- a/cmd/nomos/main.go +++ b/cmd/nomos/main.go @@ -63,11 +63,11 @@ func main() { var secretsResolved int if sec != nil { resCtx, resCancel := context.WithTimeout(context.Background(), 10*time.Second) - if v := secrets.ResolveSecret(resCtx, sec, "mcp/bearer-token", ""); v != "" { + if v := secrets.ResolveSecret(resCtx, sec, "mcp_bearer-token", ""); v != "" { mcpToken = v secretsResolved++ } - openrouterAPIKey = secrets.ResolveSecret(resCtx, sec, "openrouter/api-key", os.Getenv("OPENROUTER_API_KEY")) + openrouterAPIKey = secrets.ResolveSecret(resCtx, sec, "openrouter_api-key", os.Getenv("OPENROUTER_API_KEY")) if openrouterAPIKey != "" && openrouterAPIKey != os.Getenv("OPENROUTER_API_KEY") { secretsResolved++ } diff --git a/cmd/oikos/main.go b/cmd/oikos/main.go index 87bd118..c3551bf 100644 --- a/cmd/oikos/main.go +++ b/cmd/oikos/main.go @@ -53,18 +53,18 @@ func main() { ) if sec != nil { overlays := secrets.ConfigOverlays(map[string]func(string){ - "matrix/token": func(v string) { cfg.MatrixToken = v }, - "approval/hmac-secret": func(v string) { cfg.ApprovalHMACSecret = v }, - "mcp/bearer-token": func(v string) { cfg.MCPBearerToken = v }, - "api/token": func(v string) { cfg.APIToken = v }, - "oidc/client-secret": func(v string) { cfg.OIDCClientSecret = v }, + "matrix_token": func(v string) { cfg.MatrixToken = v }, + "approval_hmac-secret": func(v string) { cfg.ApprovalHMACSecret = v }, + "mcp_bearer-token": func(v string) { cfg.MCPBearerToken = v }, + "api_token": func(v string) { cfg.APIToken = v }, + "oidc_client-secret": func(v string) { cfg.OIDCClientSecret = v }, }) n := secrets.OverlayConfig(ctx, sec, overlays) slog.Info("secrets resolved from Infisical", "count", n) secrets.VerifyExpectedSecrets(ctx, sec, []string{ - "matrix/token", "approval/hmac-secret", "mcp/bearer-token", - "api/token", "oidc/client-secret", "openrouter/api-key", "webhook/hmac-secret", + "matrix_token", "approval_hmac-secret", "mcp_bearer-token", + "api_token", "oidc_client-secret", "openrouter_api-key", "webhook_hmac-secret", }) } @@ -381,13 +381,13 @@ func runSecret(ctx context.Context, cfg config.Config) { // expectedSecrets is the set of keys that should exist in Infisical // for a fully-migrated deployment. var expectedSecrets = []string{ - "matrix/token", - "approval/hmac-secret", - "mcp/bearer-token", - "api/token", - "oidc/client-secret", - "openrouter/api-key", - "webhook/hmac-secret", + "matrix_token", + "approval_hmac-secret", + "mcp_bearer-token", + "api_token", + "oidc_client-secret", + "openrouter_api-key", + "webhook_hmac-secret", } // runSecretVerify checks that all expected secrets are present in Infisical. @@ -425,11 +425,11 @@ func runSecretAudit(ctx context.Context, cfg config.Config) { backend := newInfisicalBackendOrFail(cfg) envValues := map[string]string{ - "matrix/token": cfg.MatrixToken, - "approval/hmac-secret": cfg.ApprovalHMACSecret, - "mcp/bearer-token": cfg.MCPBearerToken, - "api/token": cfg.APIToken, - "oidc/client-secret": cfg.OIDCClientSecret, + "matrix_token": cfg.MatrixToken, + "approval_hmac-secret": cfg.ApprovalHMACSecret, + "mcp_bearer-token": cfg.MCPBearerToken, + "api_token": cfg.APIToken, + "oidc_client-secret": cfg.OIDCClientSecret, } fmt.Println("key infisical env status") diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 57c0486..c241f33 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -32,7 +32,7 @@ func main() { secret := resolveWebhookHMAC(ctx) if secret == "" { - fmt.Fprintln(os.Stderr, "WEBHOOK_HMAC_SECRET must be set (env var or Infisical webhook/hmac-secret)") + fmt.Fprintln(os.Stderr, "WEBHOOK_HMAC_SECRET must be set (env var or Infisical webhook_hmac-secret)") os.Exit(1) } @@ -111,5 +111,5 @@ func resolveWebhookHMAC(ctx context.Context) string { os.Getenv("OIKOS_SECRETS_DIR"), ) envFallback := os.Getenv("WEBHOOK_HMAC_SECRET") - return secrets.ResolveSecret(ctx, sec, "webhook/hmac-secret", envFallback) + return secrets.ResolveSecret(ctx, sec, "webhook_hmac-secret", envFallback) } diff --git a/scripts/deploy.sh b/scripts/deploy.sh index d83e7e5..a02ccea 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -51,10 +51,14 @@ echo "[6/6] health check" for i in $(seq 1 $RETRIES); do if curl -sf "$HEALTH_URL" > /dev/null 2>&1; then echo "healthy after ${i}s" - exit 0 + break fi sleep "$SLEEP" done -echo "ERROR: health check failed after $((RETRIES * SLEEP))s" -exit 1 +# 7. Seed secrets into Infisical (idempotent) +echo "[7/7] seed secrets" +docker compose exec -T api oikos secret list > /dev/null 2>&1 && \ + docker compose cp scripts/seed-secrets.sh api:/opt/oikos/scripts/seed-secrets.sh 2>/dev/null && \ + docker compose exec -T api /opt/oikos/scripts/seed-secrets.sh || \ + echo "WARNING: secret seeding skipped (infisical not reachable)" diff --git a/scripts/deploy/network.hubris.oikos-deploy-webhook.plist b/scripts/deploy/network.hubris.oikos-deploy-webhook.plist index 2717c38..554e7d8 100644 --- a/scripts/deploy/network.hubris.oikos-deploy-webhook.plist +++ b/scripts/deploy/network.hubris.oikos-deploy-webhook.plist @@ -10,8 +10,16 @@ EnvironmentVariables - WEBHOOK_HMAC_SECRET - 6502524162d6dbc3f6d137000395d401f1837d74ef9bb0a876f8e6bbd65d1ff2 + OIKOS_INFISICAL_SITE_URL + http://localhost:8080 + OIKOS_INFISICAL_CLIENT_ID + 82e6e362-bbee-4f22-b44e-215c85bdb14a + OIKOS_INFISICAL_CLIENT_SECRET + aa7c928b366591741e4fa99016c5644fc6119b4174ba0dab3570db1229e0bdf1 + OIKOS_INFISICAL_PROJECT_ID + a436936f-6610-4698-9075-76013af7c68e + OIKOS_INFISICAL_ENV + dev WEBHOOK_REPO_DIR /Users/dtoro/Projects/oikos WEBHOOK_LISTEN diff --git a/scripts/seed-secrets.sh b/scripts/seed-secrets.sh new file mode 100755 index 0000000..675521e --- /dev/null +++ b/scripts/seed-secrets.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# One-shot: populate Infisical with oikos secrets from env vars. +# Designed to run inside the oikos-api container where Infisical is reachable. +# Safe to re-run (set is idempotent). +# +# Usage: docker exec oikos-api-1 /opt/oikos/scripts/seed-secrets.sh +# +# Secrets are read from the container environment (set via docker-compose). +# If a secret is already in Infisical, it is updated in place. + +set -e + +echo "=== seed-secrets: $(date) ===" + +KEYS=" +matrix_token:${OIKOS_MATRIX_TOKEN:-} +approval_hmac-secret:${OIKOS_APPROVAL_HMAC_SECRET:-} +mcp_bearer-token:${OIKOS_MCP_BEARER_TOKEN:-} +api_token:${OIKOS_API_TOKEN:-} +oidc_client-secret:${OIKOS_OIDC_CLIENT_SECRET:-} +openrouter_api-key:${OPENROUTER_API_KEY:-} +webhook_hmac-secret:${WEBHOOK_HMAC_SECRET:-} +" + +set_count=0 +skip_count=0 + +echo "$KEYS" | while IFS=: read -r key value; do + [ -z "$key" ] && continue + if [ -z "$value" ]; then + echo "SKIP: $key (env var empty/missing)" + skip_count=$((skip_count + 1)) + continue + fi + if oikos secret set "$key" "$value" 2>/dev/null; then + echo "SET: $key" + set_count=$((set_count + 1)) + else + echo "FAIL: $key" + fi +done + +echo "" +echo "seed-secrets complete: $set_count set, $skip_count skipped"