Coolify v4's POST/PATCH /applications/{uuid}/envs only accepts key,
value, is_preview, is_literal, is_multiline, is_shown_once. Sending
is_build_time triggers a 422 "This field is not allowed." — it's now
a derived read-only flag (is_buildtime) computed from Dockerfile ARG
usage. Breaks agents trying to upsert env vars.
Three-layer fix so this can't regress:
- lib/coolify.ts: COOLIFY_ENV_WRITE_FIELDS whitelist enforced at the
network boundary, regardless of caller shape
- app/api/workspaces/[slug]/apps/[uuid]/envs: stops forwarding the
field; returns a deprecation warning when callers send it; GET
reads both is_buildtime and is_build_time for version parity
- app/api/mcp/route.ts: same treatment in the MCP dispatcher;
AI_CAPABILITIES.md doc corrected
Also bundles (not related to the above):
- Workspace API keys are now revealable from settings. New
key_encrypted column stores AES-256-GCM(VIBN_SECRETS_KEY, token).
POST /api/workspaces/[slug]/keys/[keyId]/reveal returns plaintext
for session principals only; API-key principals cannot reveal
siblings. Legacy keys stay valid for auth but can't reveal.
- P5.3 Object storage: lib/gcp/storage.ts + lib/workspace-gcs.ts
idempotently provision a per-workspace GCS bucket, service
account, IAM binding and HMAC key. New POST /api/workspaces/
[slug]/storage/buckets endpoint. Migration script + smoke test
included. Proven end-to-end against prod master-ai-484822.
Made-with: Cursor
Ship Phases 1–3 of the multi-tenant AI access plan so an AI agent can
act on a Vibn workspace with one bearer token and zero admin reach.
Phase 1 — Gitea bot per workspace
- Add gitea_bot_username / gitea_bot_user_id / gitea_bot_token_encrypted
columns to vibn_workspaces (migrate route).
- New lib/auth/secret-box.ts (AES-256-GCM, VIBN_SECRETS_KEY) for PAT at rest.
- Extend lib/gitea.ts with createUser, createAccessTokenFor (Sudo PAT),
createOrgTeam, addOrgTeamMember, ensureOrgTeamMembership.
- ensureWorkspaceProvisioned now mints a vibn-bot-<slug> user, adds it to
a Writers team (write perms only) on the workspace's org, and stores
its PAT encrypted.
- GET /api/workspaces/[slug]/gitea-credentials returns a workspace-scoped
bot PAT + clone URL template; session or vibn_sk_ bearer auth.
Phase 2 — Tenant-safe Coolify proxy + real MCP
- lib/coolify.ts: projectUuidOf, listApplicationsInProject,
getApplicationInProject, TenantError, env CRUD, deployments list.
- Workspace-scoped REST endpoints (all filtered by coolify_project_uuid):
GET/POST /api/workspaces/[slug]/apps/[uuid](/deploy|/envs|/deployments),
GET /api/workspaces/[slug]/deployments/[deploymentUuid]/logs.
- Full rewrite of /api/mcp off legacy Firebase onto Postgres vibn_sk_
keys, exposing workspace.describe, gitea.credentials, projects.*,
apps.* (list/get/deploy/deployments, envs.list/upsert/delete).
Phase 3 — Settings UI AI bundle
- GET /api/workspaces/[slug]/bootstrap.sh: curl|sh installer that writes
.cursor/rules, .cursor/mcp.json and appends VIBN_* to .env.local.
Embeds the caller's vibn_sk_ token when invoked with bearer auth.
- WorkspaceKeysPanel: single AiAccessBundleCard with system-prompt block,
one-line bootstrap, Reveal-bot-PAT button, collapsible manual-setup
fallback. Minted-key modal also shows the bootstrap one-liner.
Ops prerequisites:
- Set VIBN_SECRETS_KEY (>=16 chars) on the frontend.
- Run /api/admin/migrate to add the three bot columns.
- GITEA_API_TOKEN must be a site-admin token (needed for admin/users
+ Sudo PAT mint); otherwise provision_status lands on 'partial'.
Made-with: Cursor