molecule-core/platform/internal/handlers
molecule-ai[bot] b1c976a54d
fix(github): refresh installation token when TTL < 10 min (#547) (#567)
Root cause: the github-app-auth plugin injects GH_TOKEN + GITHUB_TOKEN
into each workspace container's env at provision time (EnvMutator). Those
are GitHub App installation tokens with a fixed ~60 min TTL. The plugin
has an in-process cache that proactively refreshes 5 min before expiry —
but the workspace env is set once at container start and never updated.
Any workspace alive >60 min ends up with an expired token.

Fix (Option B — on-demand endpoint):

pkg/provisionhook:
  - Add TokenProvider interface: Token(ctx) (token, expiresAt, error)
    Lives in pkg/ (public) so the github-app-auth plugin can implement it.
  - Add Registry.FirstTokenProvider() — discovers the first mutator that
    also satisfies TokenProvider via interface assertion. Safe under
    concurrent reads (existing RWMutex).

platform/internal/handlers/github_token.go:
  - New GitHubTokenHandler serving GET /admin/github-installation-token
  - Delegates to the registered TokenProvider (plugin cache — always fresh)
  - 404 if no GitHub App configured, 500 + [github] prefix log on error
  - Never logs the token itself

platform/internal/handlers/workspace.go:
  - Add TokenRegistry() getter so the router can wire the handler without
    coupling to WorkspaceHandler internals

platform/internal/router/router.go:
  - Register GET /admin/github-installation-token under AdminAuth

workspace-template/:
  - scripts/molecule-git-token-helper.sh — git credential helper; calls
    the platform endpoint on every push/fetch; falls through to next
    helper (operator PAT) if platform unreachable
  - entrypoint.sh — configure the credential helper at startup

Why Option B over Option A (background goroutine):
  - The plugin already has its own cache refresh; nothing to refresh here.
  - Pushing env updates into running containers requires docker exec, which
    the architecture explicitly rejects (issue #547 "Alternatives").
  - Pull-based is stateless, trivially testable, zero extra goroutines.

Closes #547

Co-authored-by: Molecule AI DevOps Engineer <devops-engineer@agents.moleculesai.app>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 00:47:03 +00:00
..
a2a_proxy_test.go test: 100% coverage of extracted helpers + ConfirmDialog singleButton 2026-04-13 17:08:33 -07:00
a2a_proxy.go fix(provisioner): IsRunning conservative on daemon errors to stop restart cascade 2026-04-16 02:21:25 -07:00
activity_test.go test: 100% coverage of extracted helpers + ConfirmDialog singleButton 2026-04-13 17:08:33 -07:00
activity.go fix(security): #234 — sanitize source_id spoof log line via %q 2026-04-15 12:04:26 -07:00
admin_test_token_test.go feat(platform): GET /admin/workspaces/:id/test-token for E2E (#6) 2026-04-14 09:35:26 -07:00
admin_test_token.go feat(platform): GET /admin/workspaces/:id/test-token for E2E (#6) 2026-04-14 09:35:26 -07:00
agent_git_identity_test.go feat(provisioner): per-agent git identity via GIT_AUTHOR_* env vars 2026-04-16 00:45:26 -07:00
agent_git_identity.go feat(provisioner): per-agent git identity via GIT_AUTHOR_* env vars 2026-04-16 00:45:26 -07:00
agent_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
agent.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
approvals_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
approvals.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
bundle.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
channels_test.go feat(channels): per-channel message budget with 429 enforcement (#368) 2026-04-16 11:17:14 +00:00
channels.go feat(channels): per-channel message budget with 429 enforcement (#368) 2026-04-16 11:17:14 +00:00
config_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
config.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
container_files.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
delegation_test.go fix(platform): reject self-delegation to prevent _run_lock deadlock (#570) 2026-04-17 00:46:20 +00:00
delegation.go fix(platform): reject self-delegation to prevent _run_lock deadlock (#570) 2026-04-17 00:46:20 +00:00
discovery_test.go test: 100% coverage of extracted helpers + ConfirmDialog singleButton 2026-04-13 17:08:33 -07:00
discovery.go chore: quality pass — native dialogs, env sync, Go handler splits 2026-04-13 14:36:30 -07:00
events_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
events.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
github_token_test.go fix(github): refresh installation token when TTL < 10 min (#547) (#567) 2026-04-17 00:47:03 +00:00
github_token.go fix(github): refresh installation token when TTL < 10 min (#547) (#567) 2026-04-17 00:47:03 +00:00
handlers_additional_test.go fix(platform): persist secrets envelope from POST /workspaces payload (#568) 2026-04-17 00:46:17 +00:00
handlers_extended_test.go test(security): add #120 regression tests — PATCH auth + workspace existence guard 2026-04-15 08:40:06 +00:00
handlers_test.go fix(platform): persist secrets envelope from POST /workspaces payload (#568) 2026-04-17 00:46:17 +00:00
memories_test.go fix(memories): add hard cap of 50 on recall results (#377) 2026-04-16 11:12:35 +00:00
memories.go fix(memories): add hard cap of 50 on recall results (#377) 2026-04-16 11:12:35 +00:00
memory_test.go feat(memory): optimistic-locking via if_match_version on workspace_memory writes 2026-04-16 02:32:46 -07:00
memory.go feat(memory): optimistic-locking via if_match_version on workspace_memory writes 2026-04-16 02:32:46 -07:00
org_include_test.go feat(org-templates): Phase 4 — atomize each role to <role>/workspace.yaml 2026-04-16 03:09:56 -07:00
org_include.go feat(org-templates): Phase 4 — atomize each role to <role>/workspace.yaml 2026-04-16 03:09:56 -07:00
org_path_test.go fix(security): #103 — path-sanitize + admin-gate POST /org/import 2026-04-15 00:18:09 -07:00
org_prompt_ref_test.go feat(org-templates): Phase 1 — externalize prompt bodies to sibling files (#389) 2026-04-16 00:32:09 -07:00
org_test.go fix(org): use yaml.Marshal for category_routing + newline-guard block appends 2026-04-14 14:28:22 -07:00
org.go fix(platform): unblock org-template imports against modular workspace templates 2026-04-16 07:49:45 -07:00
plugins_install_pipeline_test.go test(handlers): add unit test suite for plugins_install_pipeline.go 2026-04-15 18:47:25 +00:00
plugins_install_pipeline.go refactor(platform): split 981-line plugins.go into per-domain modules 2026-04-13 18:01:59 -07:00
plugins_install.go refactor(platform): split 981-line plugins.go into per-domain modules 2026-04-13 18:01:59 -07:00
plugins_listing.go refactor(platform): split 981-line plugins.go into per-domain modules 2026-04-13 18:01:59 -07:00
plugins_sources.go refactor(platform): split 981-line plugins.go into per-domain modules 2026-04-13 18:01:59 -07:00
plugins_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
plugins.go refactor(platform): split 981-line plugins.go into per-domain modules 2026-04-13 18:01:59 -07:00
registry_test.go fix(security): registry DB errors must not leak raw driver messages (closes #435) 2026-04-16 10:34:35 +00:00
registry.go fix(security): registry DB errors must not leak raw driver messages (closes #435) 2026-04-16 10:34:35 +00:00
restart_context_test.go feat(platform): inject restart context system message (#19 Layer 1) 2026-04-14 12:41:01 -07:00
restart_context.go feat(platform): inject restart context system message (#19 Layer 1) 2026-04-14 12:41:01 -07:00
schedules_test.go fix(#249): add /schedules/health endpoint accessible to CanCommunicate peers (#400) 2026-04-16 00:45:30 -07:00
schedules.go fix(#249): add /schedules/health endpoint accessible to CanCommunicate peers (#400) 2026-04-16 00:45:30 -07:00
secrets_test.go fix(secrets): auto-restart workspaces on global secret change (#15) 2026-04-14 12:39:00 -07:00
secrets.go fix(secrets): auto-restart workspaces on global secret change (#15) 2026-04-14 12:39:00 -07:00
socket.go fix(security): Cycle 5 — auth middleware, injection hardening, skill sandbox 2026-04-14 04:44:42 +00:00
team_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
team.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
template_import_test.go fix(security): #221 — quote name as YAML scalar instead of stripping newlines 2026-04-15 11:58:16 -07:00
template_import.go fix(security): YAML-quote skill/prompt names in generateDefaultConfig + opaque file-write errors 2026-04-16 05:40:45 -07:00
templates_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
templates.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
terminal.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
tokens_test.go feat(platform): token management API + MCP setup + external agent guide 2026-04-16 08:37:42 -07:00
tokens.go fix: code review findings — dead code, DRY, rate limit, docs 2026-04-16 12:04:37 -07:00
traces_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
traces.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
transcript_test.go fix(security): forward Authorization header in transcript proxy (#405) (#380) 2026-04-15 23:38:07 -07:00
transcript.go fix(security): forward Authorization header in transcript proxy (#405) (#380) 2026-04-15 23:38:07 -07:00
viewport_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
viewport.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
webhooks_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
webhooks_workflow_test.go feat(webhooks): #101 — workflow_run event → DevOps A2A 2026-04-15 00:25:49 -07:00
webhooks.go feat(webhooks): #101 — workflow_run event → DevOps A2A 2026-04-15 00:25:49 -07:00
workspace_provision_test.go fix(auth): inject fresh bearer token into config volume on every provision (closes #418) 2026-04-16 05:26:10 -07:00
workspace_provision.go fix: code review findings — dead code, DRY, rate limit, docs 2026-04-16 12:04:37 -07:00
workspace_restart_test.go initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
workspace_restart.go fix(provisioner): rebuild_config flag on restart recovers from destroyed config volume (closes #239) 2026-04-16 10:34:25 +00:00
workspace_test.go fix(platform): persist secrets envelope from POST /workspaces payload (#568) 2026-04-17 00:46:17 +00:00
workspace.go fix(github): refresh installation token when TTL < 10 min (#547) (#567) 2026-04-17 00:47:03 +00:00