forked from molecule-ai/molecule-core
## 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> |
||
|---|---|---|
| .. | ||
| 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 | ||
| 035_org_api_tokens.down.sql | ||
| 035_org_api_tokens.up.sql | ||
| 036_org_api_tokens_org_id.down.sql | ||
| 036_org_api_tokens_org_id.up.sql | ||
| 037_max_concurrent_tasks.down.sql | ||
| 037_max_concurrent_tasks.up.sql | ||
| 038_workspace_instance_id.down.sql | ||
| 038_workspace_instance_id.up.sql | ||
| 039_activity_tool_trace.down.sql | ||
| 039_activity_tool_trace.up.sql | ||
| 040_platform_instructions.down.sql | ||
| 040_platform_instructions.up.sql | ||
| 042_a2a_queue.down.sql | ||
| 042_a2a_queue.up.sql | ||
| 043_workspace_status_enum.down.sql | ||
| 043_workspace_status_enum.up.sql | ||
| 044_platform_inbound_secret.down.sql | ||
| 044_platform_inbound_secret.up.sql | ||
| 045_workspaces_delivery_mode.down.sql | ||
| 045_workspaces_delivery_mode.up.sql | ||
| 046_workspace_status_awaiting_agent.down.sql | ||
| 046_workspace_status_awaiting_agent.up.sql | ||
| 047_runtime_image_pins.down.sql | ||
| 047_runtime_image_pins.up.sql | ||
| 048_activity_logs_peer_indexes.down.sql | ||
| 048_activity_logs_peer_indexes.up.sql | ||
| 049_delegations.down.sql | ||
| 049_delegations.up.sql | ||
| 20260417000000_workflow_checkpoints.down.sql | ||
| 20260417000000_workflow_checkpoints.up.sql | ||
| 20260505100000_pending_uploads.down.sql | ||
| 20260505100000_pending_uploads.up.sql | ||
| 20260505200000_pending_uploads_acked_index.down.sql | ||
| 20260505200000_pending_uploads_acked_index.up.sql | ||
| 20260506000000_workspaces_unique_parent_name.down.sql | ||
| 20260506000000_workspaces_unique_parent_name.up.sql | ||
| 20260508160000_workspace_plugins_tracking.down.sql | ||
| 20260508160000_workspace_plugins_tracking.up.sql | ||
| 20260508170000_workspaces_update_tier.down.sql | ||
| 20260508170000_workspaces_update_tier.up.sql | ||
| 20260510000000_plugin_drift_queue.down.sql | ||
| 20260510000000_plugin_drift_queue.up.sql | ||