molecule-core/workspace-server/migrations
Molecule AI Core-BE ada1008012
Some checks failed
sop-tier-check / tier-check (pull_request) Failing after 5s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 5s
feat(plugins): plugin drift detector + queue + admin apply endpoint (#123)
## Summary

Adds the version-subscription drift detection and operator-apply workflow for
per-workspace plugin tracking (core#113).

## Components

**Migration** (`20260510000000_plugin_drift_queue`):
- Adds `installed_sha` column to `workspace_plugins` — records the commit SHA
  installed so the drift sweeper can compare against upstream.
- Creates `plugin_update_queue` table with status: pending | applied | dismissed.
- Adds partial unique index to prevent duplicate pending rows per
  (workspace_id, plugin_name).

**GithubResolver** (`github.go`):
- `LastFetchSHA` field + `LastSHA()` getter — populated by `Fetch` after a
  successful shallow clone (captured before `.git` is stripped). Used by the
  install pipeline to seed `installed_sha`.
- `ResolveRef(ctx, spec)` method — resolves a plugin spec to its full commit
  SHA using `git fetch --depth=1 + git rev-parse`. Used by the drift sweeper
  to get the current upstream SHA for a tracked ref (tag:vX.Y.Z, tag:latest,
  sha:…, or bare branch).

**Drift sweeper** (`plugins/drift_sweeper.go`):
- Periodic sweep every 1h: SELECTs rows where `tracked_ref != 'none' AND
  installed_sha IS NOT NULL`, resolves upstream SHA, queues drift if different.
- `ListPendingUpdates()` — reads pending queue rows for the admin endpoint.
- `ApplyDriftUpdate()` — marks entry applied (idempotent).
- ctx.Err() guard on ticker arm to avoid post-shutdown work.

**Install pipeline** (`plugins_install_pipeline.go`, `plugins_tracking.go`,
`plugins_install.go`):
- `stageResult.InstalledSHA` field — carries the SHA from Fetch to the DB.
- `recordWorkspacePluginInstall` now accepts and stores `installed_sha`.
- `deleteWorkspacePluginRow` — removes tracking row on uninstall so a stale
  SHA doesn't prevent the next install from creating a fresh row.
- Both Docker and EIC uninstall paths call `deleteWorkspacePluginRow`.

**Admin endpoints** (`handlers/admin_plugin_drift.go`):
- `GET /admin/plugin-updates-pending` — list all pending drift entries.
- `POST /admin/plugin-updates/:id/apply` — re-installs plugin from source_raw
  (re-fetching the same tracked ref), records the new SHA, marks entry applied,
  triggers workspace restart. Idempotent (already-applied returns 200).

**Router wiring** (`router.go`, `cmd/server/main.go`):
- Plugin registry created in main.go and shared between PluginsHandler and drift
  sweeper.
- `router.Setup` accepts optional `pluginResolver` param.
- `PluginsHandler.Sources()` export for the sweeper wiring pattern.

## Tests

- `plugins/github_test.go` — `ResolveRef` coverage (invalid spec, git error,
  not-found mapping, no-panic for all ref shapes).
- `plugins/drift_sweeper_test.go` — `ResolveRef` happy path, stub resolver
  interface compliance.
- `handlers/admin_plugin_drift_test.go` — ListPending (empty, non-empty, DB
  error), Apply (not found, already applied, already dismissed, workspace_plugins
  missing).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 00:39:50 +00:00
..
001_workspaces.sql
002_agents.sql
003_events.sql
004_secrets.sql
005_canvas_layouts.sql
006_workspace_config_memory.sql
007_approvals.sql
008_agent_memories.sql
009_activity_logs.sql
010_workspace_awareness.sql
011_workspace_runtime.sql
012_global_secrets.sql
013_workspace_dir.sql
014_indexes.sql
015_workspace_schedules.sql
016_workspace_channels.sql
017_memories_fts_namespace.down.sql
017_memories_fts_namespace.up.sql
018_secrets_encryption_version.down.sql
018_secrets_encryption_version.up.sql
019_workspace_access.down.sql
019_workspace_access.up.sql
020_workspace_auth_tokens.down.sql
020_workspace_auth_tokens.up.sql
021_delegation_idempotency.down.sql
021_delegation_idempotency.up.sql
022_workspace_schedules_source.down.sql
022_workspace_schedules_source.up.sql
023_workspace_memory_version.down.sql
023_workspace_memory_version.up.sql
024_channel_budget.down.sql
024_channel_budget.up.sql
025_workspace_token_usage.down.sql
025_workspace_token_usage.up.sql
026_org_plugin_allowlist.down.sql
026_org_plugin_allowlist.up.sql
027_workspace_budget.down.sql
027_workspace_budget.up.sql
028_workspace_artifacts.down.sql
028_workspace_artifacts.up.sql
029_workspace_hibernation.down.sql
029_workspace_hibernation.up.sql
030_audit_events.down.sql
030_audit_events.up.sql
031_memories_pgvector.down.sql
031_memories_pgvector.up.sql
032_schedule_consecutive_empty.down.sql
032_schedule_consecutive_empty.up.sql
033_strip_crlf_cron_prompts.up.sql
034_workspaces_last_outbound_at.up.sql feat(platform): track last_outbound_at for silent-workspace detection (closes #817) 2026-04-18 13:04:54 -07:00
035_org_api_tokens.down.sql feat(auth): organization-scoped API keys for admin access 2026-04-20 14:01:41 -07:00
035_org_api_tokens.up.sql feat(auth): organization-scoped API keys for admin access 2026-04-20 14:01:41 -07:00
036_org_api_tokens_org_id.down.sql fix(auth): F1094 — requireCallerOwnsOrg reads org_id not created_by (#1234) 2026-04-21 02:47:12 +00:00
036_org_api_tokens_org_id.up.sql fix(auth): F1094 — requireCallerOwnsOrg reads org_id not created_by (#1234) 2026-04-21 02:47:12 +00:00
037_max_concurrent_tasks.down.sql fix: CWE-78 rm scope, go vet failures, delegation idempotency 2026-04-21 18:22:30 +00:00
037_max_concurrent_tasks.up.sql fix: CWE-78 rm scope, go vet failures, delegation idempotency 2026-04-21 18:22:30 +00:00
038_workspace_instance_id.down.sql feat(workspace): persist CP-returned EC2 instance_id on provision 2026-04-21 17:56:15 -07:00
038_workspace_instance_id.up.sql feat(workspace): persist CP-returned EC2 instance_id on provision 2026-04-21 17:56:15 -07:00
039_activity_tool_trace.down.sql feat: add tool_trace to activity_logs for platform-level agent observability 2026-04-22 15:17:14 -07:00
039_activity_tool_trace.up.sql feat: add tool_trace to activity_logs for platform-level agent observability 2026-04-22 15:17:14 -07:00
040_platform_instructions.down.sql feat: platform instructions system with global/team/workspace scope 2026-04-22 15:17:14 -07:00
040_platform_instructions.up.sql fix(review): address code review blockers on tool-trace + instructions 2026-04-22 16:18:06 -07:00
042_a2a_queue.down.sql feat(a2a): queue-on-busy — Phase 1 of priority queue (#1870) 2026-04-23 14:09:29 -07:00
042_a2a_queue.up.sql feat(a2a): queue-on-busy — Phase 1 of priority queue (#1870) 2026-04-23 14:09:29 -07:00
043_workspace_status_enum.down.sql chore: second-pass review polish — symmetry + clearer test fixtures 2026-04-25 08:48:30 -07:00
043_workspace_status_enum.up.sql fix: review-driven hardening of wedge detector + idle timeout + progress feed 2026-04-25 08:43:10 -07:00
044_platform_inbound_secret.down.sql feat(wsauth): platform→workspace inbound secret (RFC #2312, PR-A) 2026-04-29 14:09:33 -07:00
044_platform_inbound_secret.up.sql feat(wsauth): platform→workspace inbound secret (RFC #2312, PR-A) 2026-04-29 14:09:33 -07:00
045_workspaces_delivery_mode.down.sql feat(workspaces): delivery_mode column + poll-mode register flow (#2339 PR 1) 2026-04-29 21:47:14 -07:00
045_workspaces_delivery_mode.up.sql feat(workspaces): delivery_mode column + poll-mode register flow (#2339 PR 1) 2026-04-29 21:47:14 -07:00
046_workspace_status_awaiting_agent.down.sql fix(workspaces): add missing 'awaiting_agent' + 'hibernating' to workspace_status enum 2026-04-30 08:52:05 -07:00
046_workspace_status_awaiting_agent.up.sql fix(workspaces): add missing 'awaiting_agent' + 'hibernating' to workspace_status enum 2026-04-30 08:52:05 -07:00
047_runtime_image_pins.down.sql feat(provisioner): digest-pin workspace images via runtime_image_pins (#2272 layer 1) 2026-05-03 02:30:00 -07:00
047_runtime_image_pins.up.sql feat(provisioner): digest-pin workspace images via runtime_image_pins (#2272 layer 1) 2026-05-03 02:30:00 -07:00
048_activity_logs_peer_indexes.down.sql feat(db): add per-peer btree indexes on activity_logs for chat_history scale (#2478) 2026-05-03 11:34:35 -07:00
048_activity_logs_peer_indexes.up.sql feat(db): add per-peer btree indexes on activity_logs for chat_history scale (#2478) 2026-05-03 11:34:35 -07:00
049_delegations.down.sql feat(delegations): durable per-task ledger + audit-write helper (RFC #2829 PR-1) 2026-05-04 20:43:06 -07:00
049_delegations.up.sql feat(delegations): durable per-task ledger + audit-write helper (RFC #2829 PR-1) 2026-05-04 20:43:06 -07:00
20260417000000_workflow_checkpoints.down.sql
20260417000000_workflow_checkpoints.up.sql
20260505100000_pending_uploads.down.sql feat(rfc): poll-mode chat upload — phase 1 platform staging layer 2026-05-05 04:22:24 -07:00
20260505100000_pending_uploads.up.sql feat(rfc): poll-mode chat upload — phase 1 platform staging layer 2026-05-05 04:22:24 -07:00
20260505200000_pending_uploads_acked_index.down.sql feat(poll-upload): phase 5a — atomic batch insert + acked-index + mime hardening 2026-05-05 11:10:13 -07:00
20260505200000_pending_uploads_acked_index.up.sql feat(poll-upload): phase 5a — atomic batch insert + acked-index + mime hardening 2026-05-05 11:10:13 -07:00
20260506000000_workspaces_unique_parent_name.down.sql fix(workspace-server): close TOCTOU race on workspaces(parent_id, name) (#2872 Critical 1) 2026-05-05 21:43:49 -07:00
20260506000000_workspaces_unique_parent_name.up.sql fix(workspace-server): close TOCTOU race on workspaces(parent_id, name) (#2872 Critical 1) 2026-05-05 21:43:49 -07:00
20260508160000_workspace_plugins_tracking.down.sql feat(plugins): workspace_plugins tracking table — version-subscription foundation 2026-05-08 08:52:35 -07:00
20260508160000_workspace_plugins_tracking.up.sql feat(plugins): workspace_plugins tracking table — version-subscription foundation 2026-05-08 08:52:35 -07:00
20260508170000_workspaces_update_tier.down.sql feat(workspaces): update_tier column for canary vs production fan-out 2026-05-08 08:55:19 -07:00
20260508170000_workspaces_update_tier.up.sql feat(workspaces): update_tier column for canary vs production fan-out 2026-05-08 08:55:19 -07:00
20260510000000_plugin_drift_queue.down.sql feat(plugins): plugin drift detector + queue + admin apply endpoint (#123) 2026-05-10 00:39:50 +00:00
20260510000000_plugin_drift_queue.up.sql feat(plugins): plugin drift detector + queue + admin apply endpoint (#123) 2026-05-10 00:39:50 +00:00