Commit Graph

4500 Commits

Author SHA1 Message Date
rabbitblood
90d68ca039 feat(template): engineers pick up issues proactively (CEO 2026-04-16 directive)
CEO directive verbatim: *"devs should pick up issues and declare that its
assigned to them, PM and leaders regularly check in. dont just rely on
outside reviewer"*.

Adds `idle_prompt` + `idle_interval_seconds: 600` to Frontend Engineer,
Backend Engineer, and DevOps Engineer. Each engineer now polls open GH
issues matching its specialty, claims unassigned ones via `gh issue edit
--add-assignee @me`, leaves a public comment declaring the pickup, and
commits memory to prevent double-pickup on the next tick.

Previously engineers were reactive-only per the #159 orchestrator/worker
split. The CEO is correcting that: devs should be a true self-organizing
unit, not a work-queue that only advances when an outside reviewer
dispatches.

## Per-role specialty filters

| Role | Labels it claims |
|---|---|
| Frontend Engineer | canvas, a11y, ux, typescript, frontend, bug, security |
| Backend Engineer | security, platform, go, database, bug |
| DevOps Engineer | docker, ci, deployment, infra, devops, bug |

Priority order within each role: security > bug > feature.

## Self-review gates

Each engineer's idle_prompt includes the self-review chain:
- Frontend: molecule-skill-code-review + molecule-skill-llm-judge
- Backend: molecule-skill-code-review + molecule-security-scan + molecule-skill-llm-judge
- DevOps: molecule-skill-code-review + molecule-freeze-scope + molecule-hitl for risky ops

These plugins were wired into engineer roles by #280, #303, #310, #322 —
the idle_prompt makes them the PRIMARY quality gate instead of a nice-to-
have before PR. Matches the "team self-regulates, don't rely on outside
reviewer" spirit.

## Hard rules (same shape as researcher idle_prompts from #216/#321)

- Max 1 claim per tick (1 `gh issue edit --add-assignee` call)
- Never take someone else's assigned issue
- Under 90 seconds wall-clock for the claim + plan step
- Don't double-pick: check `task-assigned:<role>` memory first
- No busy-work fabrication: write "<role>-idle HH:MM — no work" if nothing matches

## What this does NOT change

- Leaders' orchestrator pulses still dispatch (#159) — this is the TAIL
  pickup, not the primary dispatch path. Dev Lead still prioritizes via
  its own pulse.
- PR merging still goes through reviewer per `feedback_never_merge_prs.md`.
  This directive is about the QUALITY GATE (team self-review, peer review
  via Dev Lead's pulse) not about bypassing merge approval.
- Destructive/irreversible ops still need explicit human ack via
  molecule-hitl's @requires_approval decorator.

## Rollout plan

- Ship template change (this PR)
- After merge: rebuild workspace-template:claude-code, re-provision
  BE + FE + DevOps via apply_template=true, re-inject idle_prompt
  (platform doesn't auto-propagate org.yaml to live configs — tracked
  separately)
- Measure: 24h of activity_logs. Should see `a2a_receive` events every
  10 min per engineer, response bodies mentioning claim decisions or
  idle-clean states, and `gh issue edit` events showing up as assignees.

## Related
- `feedback_devs_pick_up_issues_leaders_check_in.md` — memory saved last cycle
- #159 orchestrator/worker split (leaders dispatch)
- #216 / #321 researcher idle_prompts (same pattern applied to researchers)
- `project_north_star_24_7.md` — team self-regulation is the north-star
2026-04-15 22:49:10 -07:00
Hongming Wang
829e4bf89b Merge pull request #369 from Molecule-AI/chore/eco-watch-2026-04-18
All CI green. Docs-only: adds AMD GAIA + ClawRun ecosystem survey entries.
2026-04-15 22:46:53 -07:00
Hongming Wang
4b467c37a8
Merge pull request #369 from Molecule-AI/chore/eco-watch-2026-04-18
All CI green. Docs-only: adds AMD GAIA + ClawRun ecosystem survey entries.
2026-04-15 22:46:53 -07:00
Research Lead
dff50f5927 chore(eco-watch): 2026-04-18 survey — AMD GAIA + ClawRun
Add two new entries to docs/ecosystem-watch.md:

- **AMD GAIA** (amd/gaia, ~1.2k , MIT, v0.17.2 April 10 2026):
  AMD-backed local-first agent framework with MCP client support,
  RAG, vision, and voice. Hardware-locked to Ryzen AI but signals
  local/privacy-first positioning. @tool decorator pattern worth
  borrowing for workspace adapters.

- **ClawRun** (clawrun-sh/clawrun, ~84 , Apache 2.0, 45 releases):
  Closest architectural match we've tracked — hosting/lifecycle layer
  with sandbox, heartbeat, snapshot/resume, channels, and cost
  tracking. Per-channel budget enforcement is a concrete gap in our
  workspace_channels. Filed #368.

HEAD at survey time: 8db86df

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:40:44 +00:00
Research Lead
3ed4038149 chore(eco-watch): 2026-04-18 survey — AMD GAIA + ClawRun
Add two new entries to docs/ecosystem-watch.md:

- **AMD GAIA** (amd/gaia, ~1.2k , MIT, v0.17.2 April 10 2026):
  AMD-backed local-first agent framework with MCP client support,
  RAG, vision, and voice. Hardware-locked to Ryzen AI but signals
  local/privacy-first positioning. @tool decorator pattern worth
  borrowing for workspace adapters.

- **ClawRun** (clawrun-sh/clawrun, ~84 , Apache 2.0, 45 releases):
  Closest architectural match we've tracked — hosting/lifecycle layer
  with sandbox, heartbeat, snapshot/resume, channels, and cost
  tracking. Per-channel budget enforcement is a concrete gap in our
  workspace_channels. Filed #368.

HEAD at survey time: a4a89a3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:40:44 +00:00
Hongming Wang
8db86df330 Merge pull request #363 from Molecule-AI/chore/eco-watch-2026-04-17
All CI green. Docs-only: adds GenericAgent + OpenSRE ecosystem survey entries.
2026-04-15 22:14:23 -07:00
Hongming Wang
a4a89a30c1
Merge pull request #363 from Molecule-AI/chore/eco-watch-2026-04-17
All CI green. Docs-only: adds GenericAgent + OpenSRE ecosystem survey entries.
2026-04-15 22:14:23 -07:00
Research Lead
04ceb95142 chore(eco-watch): 2026-04-17 survey — GenericAgent + OpenSRE
Add two new entries to docs/ecosystem-watch.md:

- **GenericAgent** (lsdefine/GenericAgent, ~2.1k , MIT, v1.0 January
  2026): self-evolving skill tree with a four-tier memory hierarchy
  (rules/indices/facts/skills/archives). Skill crystallisation at
  runtime is the automation of our install-time plugins model. Filed
  #361 to add named memory tiers to agent_memories.

- **OpenSRE** (Tracer-Cloud/opensre, ~900 , Apache 2.0): AI SRE
  agent toolkit with 40+ production DevOps integrations and MCP
  support. Filed #362 to evaluate its adapters as a Molecule AI
  DevOps workspace skill pack.

HEAD at survey time: 2e1fc8d

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:11:01 +00:00
Research Lead
fe6e3032a4 chore(eco-watch): 2026-04-17 survey — GenericAgent + OpenSRE
Add two new entries to docs/ecosystem-watch.md:

- **GenericAgent** (lsdefine/GenericAgent, ~2.1k , MIT, v1.0 January
  2026): self-evolving skill tree with a four-tier memory hierarchy
  (rules/indices/facts/skills/archives). Skill crystallisation at
  runtime is the automation of our install-time plugins model. Filed
  #361 to add named memory tiers to agent_memories.

- **OpenSRE** (Tracer-Cloud/opensre, ~900 , Apache 2.0): AI SRE
  agent toolkit with 40+ production DevOps integrations and MCP
  support. Filed #362 to evaluate its adapters as a Molecule AI
  DevOps workspace skill pack.

HEAD at survey time: 93fd546

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:11:01 +00:00
Hongming Wang
2e1fc8d832 Merge pull request #360 from Molecule-AI/chore/issue-358-wsauth-dead-constants
All CI green. Removes dead constants and stale comment left over from PR #357 grace-period test deletion (closes #358).
2026-04-15 22:05:37 -07:00
Hongming Wang
93fd5467e2
Merge pull request #360 from Molecule-AI/chore/issue-358-wsauth-dead-constants
All CI green. Removes dead constants and stale comment left over from PR #357 grace-period test deletion (closes #358).
2026-04-15 22:05:37 -07:00
PM Bot
409a249ca6 chore(test): remove dead constants from wsauth_middleware_test.go (#358)
PR #357 deleted the grace-period tests that used hasLiveTokenQuery and
workspaceExistsQuery, but the constants themselves (and the stale comment
describing the old HasAnyLiveToken-based dispatch) were not removed.

Remove both dead const declarations and update the header comment to
reflect the strict-enforcement contract introduced by #357.

Closes #358.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:02:11 +00:00
PM Bot
e257cd80d4 chore(test): remove dead constants from wsauth_middleware_test.go (#358)
PR #357 deleted the grace-period tests that used hasLiveTokenQuery and
workspaceExistsQuery, but the constants themselves (and the stale comment
describing the old HasAnyLiveToken-based dispatch) were not removed.

Remove both dead const declarations and update the header comment to
reflect the strict-enforcement contract introduced by #357.

Closes #358.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 05:02:11 +00:00
Hongming Wang
d09e72c5fd Merge pull request #357 from Molecule-AI/fix/issue-351-remove-tokenless-grace-period
All CI green. Merges strict WorkspaceAuth — removes tokenless grace period that enabled zombie workspace enumeration (#351).
2026-04-15 21:57:17 -07:00
Hongming Wang
4e514aa59a
Merge pull request #357 from Molecule-AI/fix/issue-351-remove-tokenless-grace-period
All CI green. Merges strict WorkspaceAuth — removes tokenless grace period that enabled zombie workspace enumeration (#351).
2026-04-15 21:57:17 -07:00
Hongming Wang
b2b0045913 fix(security): remove WorkspaceAuth tokenless grace period (#351)
Severity HIGH. #318 closed the fake-UUID fail-open for WorkspaceAuth
but left the grace period intact for *real* workspaces with no live
tokens. Zombie test-artifact workspaces from prior DAST runs still
exist in the DB with empty configs and no tokens, so they pass
WorkspaceExists=true but HasAnyLiveToken=false — and fell through the
grace period, leaking every global-secret key name to any
unauthenticated caller on the Docker network.

Phase 30.1 shipped months ago; every production workspace has gone
through multiple boot cycles and acquired a token since. The
"legacy workspaces grandfathered" window no longer serves legitimate
traffic. Removing it entirely is the cleanest fix — and does NOT
affect registration (which is on /registry/register, outside this
middleware's scope).

New contract (strict):

  every /workspaces/:id/* request MUST carry
  Authorization: Bearer <token-for-this-workspace>

Any missing/mismatched/revoked/wrong-workspace bearer → 401. No
existence check, no fallback. The wsauth.WorkspaceExists helper is
kept in the package for any future caller but no longer used here.

Tests:
- TestWorkspaceAuth_351_NoBearer_Returns401_NoDBCalls — new, covers
  fake UUID / zombie / pre-token in one sub-table. Asserts zero DB
  calls on missing bearer.
- Existing C4/C8 + #170 tests updated to drop the stale
  HasAnyLiveToken sqlmock expectations.
- Renamed TestWorkspaceAuth_Issue170_SecretDelete_FailOpen_NoTokens
  to _NoTokensStillRejected and flipped the assertion from 200 to 401.
- Dropped TestWorkspaceAuth_318_ExistsQueryError_Returns500 — the
  code path it covered no longer exists.

Full platform test sweep green.

Closes #351

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:52:44 -07:00
Hongming Wang
fa239217a0 fix(security): remove WorkspaceAuth tokenless grace period (#351)
Severity HIGH. #318 closed the fake-UUID fail-open for WorkspaceAuth
but left the grace period intact for *real* workspaces with no live
tokens. Zombie test-artifact workspaces from prior DAST runs still
exist in the DB with empty configs and no tokens, so they pass
WorkspaceExists=true but HasAnyLiveToken=false — and fell through the
grace period, leaking every global-secret key name to any
unauthenticated caller on the Docker network.

Phase 30.1 shipped months ago; every production workspace has gone
through multiple boot cycles and acquired a token since. The
"legacy workspaces grandfathered" window no longer serves legitimate
traffic. Removing it entirely is the cleanest fix — and does NOT
affect registration (which is on /registry/register, outside this
middleware's scope).

New contract (strict):

  every /workspaces/:id/* request MUST carry
  Authorization: Bearer <token-for-this-workspace>

Any missing/mismatched/revoked/wrong-workspace bearer → 401. No
existence check, no fallback. The wsauth.WorkspaceExists helper is
kept in the package for any future caller but no longer used here.

Tests:
- TestWorkspaceAuth_351_NoBearer_Returns401_NoDBCalls — new, covers
  fake UUID / zombie / pre-token in one sub-table. Asserts zero DB
  calls on missing bearer.
- Existing C4/C8 + #170 tests updated to drop the stale
  HasAnyLiveToken sqlmock expectations.
- Renamed TestWorkspaceAuth_Issue170_SecretDelete_FailOpen_NoTokens
  to _NoTokensStillRejected and flipped the assertion from 200 to 401.
- Dropped TestWorkspaceAuth_318_ExistsQueryError_Returns500 — the
  code path it covered no longer exists.

Full platform test sweep green.

Closes #351

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:52:44 -07:00
Hongming Wang
742d061787 Merge pull request #350 from Molecule-AI/chore/eco-watch-2026-04-16b
chore(eco-watch): 2026-04-16b survey — AgentScope + Plannotator
2026-04-15 21:47:50 -07:00
Hongming Wang
75146f4314
Merge pull request #350 from Molecule-AI/chore/eco-watch-2026-04-16b
chore(eco-watch): 2026-04-16b survey — AgentScope + Plannotator
2026-04-15 21:47:50 -07:00
Research Lead
93720565b0 chore(eco-watch): 2026-04-16b survey — AgentScope + Plannotator
Add two new entries to docs/ecosystem-watch.md:

- **AgentScope** (modelscope/agentscope, ~23.8k , Apache 2.0,
  v1.0.18 March 26 2026): Alibaba/ModelScope multi-agent framework
  with MCP support, MsgHub typed routing, and OpenTelemetry
  observability. No canvas or workspace lifecycle — framework-layer
  complement, not a platform competitor.

- **Plannotator** (backnotprop/plannotator, ~4.3k , Apache 2.0+MIT,
  v0.17.10 April 13 2026): Browser-based agent plan annotation tool
  with structured feedback types (delete/insert/replace/comment).
  Directly informs our hitl.py feedback schema. Filed #349 to add
  structured feedback types to resume_task.

HEAD at survey time: 0897f9e

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 04:40:51 +00:00
Research Lead
6be5d09764 chore(eco-watch): 2026-04-16b survey — AgentScope + Plannotator
Add two new entries to docs/ecosystem-watch.md:

- **AgentScope** (modelscope/agentscope, ~23.8k , Apache 2.0,
  v1.0.18 March 26 2026): Alibaba/ModelScope multi-agent framework
  with MCP support, MsgHub typed routing, and OpenTelemetry
  observability. No canvas or workspace lifecycle — framework-layer
  complement, not a platform competitor.

- **Plannotator** (backnotprop/plannotator, ~4.3k , Apache 2.0+MIT,
  v0.17.10 April 13 2026): Browser-based agent plan annotation tool
  with structured feedback types (delete/insert/replace/comment).
  Directly informs our hitl.py feedback schema. Filed #349 to add
  structured feedback types to resume_task.

HEAD at survey time: 4196876

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 04:40:51 +00:00
Hongming Wang
0897f9e59c Merge pull request #346 from Molecule-AI/chore/issue-342-auditor-prompt-drift
chore(auditor): close #319 + #337 prompt drift on Security Auditor (#342)
2026-04-15 21:31:06 -07:00
Hongming Wang
4196876c2b
Merge pull request #346 from Molecule-AI/chore/issue-342-auditor-prompt-drift
chore(auditor): close #319 + #337 prompt drift on Security Auditor (#342)
2026-04-15 21:31:06 -07:00
Hongming Wang
d8183e16cc Merge pull request #343 from Molecule-AI/fix/issue-337-webhook-secret-constant-time
fix(security): constant-time webhook_secret comparison (#337)
2026-04-15 21:31:02 -07:00
Hongming Wang
c5d40b861b
Merge pull request #343 from Molecule-AI/fix/issue-337-webhook-secret-constant-time
fix(security): constant-time webhook_secret comparison (#337)
2026-04-15 21:31:02 -07:00
Hongming Wang
c6a721fd56 Merge pull request #341 from Molecule-AI/fix/publish-platform-image-keychain-again
fix(ci): disable osxkeychain credsStore on self-hosted runner (#199 follow-up)
2026-04-15 21:30:59 -07:00
Hongming Wang
af3d9904e1
Merge pull request #341 from Molecule-AI/fix/publish-platform-image-keychain-again
fix(ci): disable osxkeychain credsStore on self-hosted runner (#199 follow-up)
2026-04-15 21:30:59 -07:00
Hongming Wang
c7477047c2 Merge pull request #338 from Molecule-AI/fix/issue-328-transcript-fail-closed
fix(security): /transcript fails closed when auth token missing (#328)
2026-04-15 21:30:56 -07:00
Hongming Wang
e7bde9a919
Merge pull request #338 from Molecule-AI/fix/issue-328-transcript-fail-closed
fix(security): /transcript fails closed when auth token missing (#328)
2026-04-15 21:30:56 -07:00
Hongming Wang
2da48dda13 chore(auditor): close #319 + #337 prompt drift on Security Auditor (#342)
Two recent platform-level security changes (#319 channel_config
encryption, #337 constant-time webhook_secret compare) were not
reflected in the Security Auditor's system prompt or the schedule cron
prompt. That meant the auditor wouldn't proactively look for the
*next* instance of either class — a new credential field added to
channel_config without being added to sensitiveFields, or a new
secret comparison using raw `!=`, would slip through until a human
happened to notice.

Updated two files:

1. org-templates/molecule-dev/security-auditor/system-prompt.md
   Added two bullets to "What You Check":
   - Secret comparisons must use subtle.ConstantTimeCompare /
     crypto.timingSafeEqual (cites #337 as the repo's recent instance)
   - Secret storage at rest: any new channel_config credential field
     must be added to sensitiveFields and exercised in both the
     Encrypt (write) and Decrypt (read) boundary helpers, and the
     ec1: prefix must never leak into API responses (cites #319)

2. org-templates/molecule-dev/org.yaml
   Same two checks added to the Security Auditor's 12-hour cron
   prompt's "MANUAL REVIEW of every changed file" section. Wording
   is concrete enough to paste into a grep: "flag any `!=` / `==` /
   bytes.Equal against a user-supplied value that gates auth".

Pure config / prompt — no code changes, no tests to write. YAML parse
verified, TestPlugins_UnionWithDefaults still passes.

Closes #342

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:24:34 -07:00
Hongming Wang
6b153ca3cb chore(auditor): close #319 + #337 prompt drift on Security Auditor (#342)
Two recent platform-level security changes (#319 channel_config
encryption, #337 constant-time webhook_secret compare) were not
reflected in the Security Auditor's system prompt or the schedule cron
prompt. That meant the auditor wouldn't proactively look for the
*next* instance of either class — a new credential field added to
channel_config without being added to sensitiveFields, or a new
secret comparison using raw `!=`, would slip through until a human
happened to notice.

Updated two files:

1. org-templates/molecule-dev/security-auditor/system-prompt.md
   Added two bullets to "What You Check":
   - Secret comparisons must use subtle.ConstantTimeCompare /
     crypto.timingSafeEqual (cites #337 as the repo's recent instance)
   - Secret storage at rest: any new channel_config credential field
     must be added to sensitiveFields and exercised in both the
     Encrypt (write) and Decrypt (read) boundary helpers, and the
     ec1: prefix must never leak into API responses (cites #319)

2. org-templates/molecule-dev/org.yaml
   Same two checks added to the Security Auditor's 12-hour cron
   prompt's "MANUAL REVIEW of every changed file" section. Wording
   is concrete enough to paste into a grep: "flag any `!=` / `==` /
   bytes.Equal against a user-supplied value that gates auth".

Pure config / prompt — no code changes, no tests to write. YAML parse
verified, TestPlugins_UnionWithDefaults still passes.

Closes #342

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:24:34 -07:00
Hongming Wang
7af8f33bcc fix(security): constant-time webhook_secret comparison (#337)
Severity LOW. The /webhooks/:type handler compared the Telegram
X-Telegram-Bot-Api-Secret-Token header against the decrypted
webhook_secret using Go's `!=` operator, which short-circuits on the
first mismatched byte. Under low-latency Docker-network conditions an
attacker could time response latency byte-by-byte and converge on the
real secret, then inject Telegram-formatted messages into any channel.

Fix: switch to crypto/subtle.ConstantTimeCompare, which runs in time
proportional to the length of the shorter input regardless of content
match. Same posture as the cdp-proxy token compare in host-bridge
(which already used timingSafeEqual).

Risk profile over the public internet is low (Telegram webhooks have
natural jitter that masks the signal), but the defensive pattern
matters for consistency across all secret comparisons.

Closes #337

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:23:12 -07:00
Hongming Wang
50819500f0 fix(security): constant-time webhook_secret comparison (#337)
Severity LOW. The /webhooks/:type handler compared the Telegram
X-Telegram-Bot-Api-Secret-Token header against the decrypted
webhook_secret using Go's `!=` operator, which short-circuits on the
first mismatched byte. Under low-latency Docker-network conditions an
attacker could time response latency byte-by-byte and converge on the
real secret, then inject Telegram-formatted messages into any channel.

Fix: switch to crypto/subtle.ConstantTimeCompare, which runs in time
proportional to the length of the shorter input regardless of content
match. Same posture as the cdp-proxy token compare in host-bridge
(which already used timingSafeEqual).

Risk profile over the public internet is low (Telegram webhooks have
natural jitter that masks the signal), but the defensive pattern
matters for consistency across all secret comparisons.

Closes #337

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:23:12 -07:00
Hongming Wang
94a9f92c50 fix(security): scope PausePollersForToken to requesting workspace (closes #329)
CI 5/6 pass (E2E cancel = run-supersession pattern). Dev Lead review 04:21:  Approved. Fixes cross-tenant token exposure: PausePollersForToken now scoped to requesting workspace_id via SQL WHERE clause. Closes #329.
2026-04-15 21:22:50 -07:00
Hongming Wang
a205c92428
fix(security): scope PausePollersForToken to requesting workspace (closes #329)
CI 5/6 pass (E2E cancel = run-supersession pattern). Dev Lead review 04:21:  Approved. Fixes cross-tenant token exposure: PausePollersForToken now scoped to requesting workspace_id via SQL WHERE clause. Closes #329.
2026-04-15 21:22:50 -07:00
Hongming Wang
9ea6fc23e0 chore(eco-watch): 2026-04-16 daily survey — Gemini CLI + open-multi-agent
CI fully green. Dev Lead review:  Approved. Docs-only: adds Gemini CLI and open-multi-agent entries to ecosystem-watch.md; files issues #332 (gemini-cli adapter) and #333 (PM goal-decomp skill).
2026-04-15 21:22:37 -07:00
Hongming Wang
12dc0ebdf2
chore(eco-watch): 2026-04-16 daily survey — Gemini CLI + open-multi-agent
CI fully green. Dev Lead review:  Approved. Docs-only: adds Gemini CLI and open-multi-agent entries to ecosystem-watch.md; files issues #332 (gemini-cli adapter) and #333 (PM goal-decomp skill).
2026-04-15 21:22:37 -07:00
Hongming Wang
aa2a283835 fix(ci): explicitly disable osxkeychain credsStore for self-hosted runner
#273 tried to fix the macOS Keychain -25308 error by pointing
DOCKER_CONFIG at a per-run temp dir with `{"auths": {}}`. That was
necessary but not sufficient: Docker on macOS inherits `osxkeychain` as
the default credsStore even when config.json doesn't declare one
(comes from Docker Desktop's bundled binding), so the login-action
still tried to call /usr/local/bin/docker-credential-osxkeychain which
fails with -25308 from the non-interactive launchd session.

Evidence: after #273, publish-platform-image still failed on every
main merge with:

  error saving credentials: error storing credentials - err: exit
  status 1, out: `User interaction is not allowed. (-25308)`

Fix: write a config.json that explicitly sets `credsStore: ""` and
clears `credHelpers`, forcing Docker to store creds in the inline
`auths` map of this disposable config.json instead of reaching for
the keychain. Also print config.json at diagnostic time so a future
regression surfaces in the log instead of at login.

No runtime / test impact — this only changes what the runner writes
to the workflow's temp DOCKER_CONFIG directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:20:06 -07:00
Hongming Wang
8ad8ae1077 fix(ci): explicitly disable osxkeychain credsStore for self-hosted runner
#273 tried to fix the macOS Keychain -25308 error by pointing
DOCKER_CONFIG at a per-run temp dir with `{"auths": {}}`. That was
necessary but not sufficient: Docker on macOS inherits `osxkeychain` as
the default credsStore even when config.json doesn't declare one
(comes from Docker Desktop's bundled binding), so the login-action
still tried to call /usr/local/bin/docker-credential-osxkeychain which
fails with -25308 from the non-interactive launchd session.

Evidence: after #273, publish-platform-image still failed on every
main merge with:

  error saving credentials: error storing credentials - err: exit
  status 1, out: `User interaction is not allowed. (-25308)`

Fix: write a config.json that explicitly sets `credsStore: ""` and
clears `credHelpers`, forcing Docker to store creds in the inline
`auths` map of this disposable config.json instead of reaching for
the keychain. Also print config.json at diagnostic time so a future
regression surfaces in the log instead of at login.

No runtime / test impact — this only changes what the runner writes
to the workflow's temp DOCKER_CONFIG directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:20:06 -07:00
Hongming Wang
0e46afa4b9 fix(security): hitl task-id ownership + wire fail_open_if_no_scanner in loader (closes #265, #268)
Security audit cycle 13: hitl.py LGTM (workspace-scoped task IDs). Loader.py fix applied (commit 0557f73): fail_open_if_no_scanner now read from config and forwarded to scan_skill_dependencies(); regression test added. CI 5/6 pass (E2E cancel = run-supersession pattern). Closes #265. Closes #268.
2026-04-15 21:18:52 -07:00
Hongming Wang
c11d8f3ec3
fix(security): hitl task-id ownership + wire fail_open_if_no_scanner in loader (closes #265, #268)
Security audit cycle 13: hitl.py LGTM (workspace-scoped task IDs). Loader.py fix applied (commit 0557f73): fail_open_if_no_scanner now read from config and forwarded to scan_skill_dependencies(); regression test added. CI 5/6 pass (E2E cancel = run-supersession pattern). Closes #265. Closes #268.
2026-04-15 21:18:52 -07:00
Hongming Wang
e1cdb5c9c6 fix(security): /transcript endpoint fails closed when auth token missing (#328)
Severity HIGH. The /transcript route in main.py used `if expected:`
around the bearer-token compare, so `get_token()` returning None (no
/configs/.auth_token on disk — bootstrap window, deleted file, OSError)
silently skipped the entire auth check. Any container on
molecule-monorepo-net could GET /transcript during the provisioning
window and walk away with the full session log (user messages, Claude
tool calls, assistant replies).

The platform's TranscriptHandler always has a valid token (it acquired
one at workspace registration), so tightening this gate has no
legitimate-caller impact. Only unauthenticated sniffers lose access,
which was never the intended contract of #287.

Fix:

1. Extracted the auth gate into `workspace-template/transcript_auth.py`
   — a 20-line module with no heavy imports so the security-critical
   code is unit-testable without standing up the full uvicorn/a2a/httpx
   stack (the former inline guard could only be tested end-to-end,
   which explains why the regression shipped in #287).

2. `transcript_authorized(expected, auth_header)` returns False when
   `expected` is None or empty — the #328 fix — and otherwise does
   strict equality against "Bearer <expected>".

3. main.py's inline handler calls the extracted function:
     if not _transcript_authorized(get_token(), auth_header):
         return 401

4. New tests/test_transcript_auth.py covers: None token, empty token,
   valid bearer, wrong bearer, missing header, case-sensitive prefix,
   whitespace fuzzing. All 7 pass.

Closes #328

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:17:37 -07:00
Hongming Wang
5eb08332ee fix(security): /transcript endpoint fails closed when auth token missing (#328)
Severity HIGH. The /transcript route in main.py used `if expected:`
around the bearer-token compare, so `get_token()` returning None (no
/configs/.auth_token on disk — bootstrap window, deleted file, OSError)
silently skipped the entire auth check. Any container on
molecule-monorepo-net could GET /transcript during the provisioning
window and walk away with the full session log (user messages, Claude
tool calls, assistant replies).

The platform's TranscriptHandler always has a valid token (it acquired
one at workspace registration), so tightening this gate has no
legitimate-caller impact. Only unauthenticated sniffers lose access,
which was never the intended contract of #287.

Fix:

1. Extracted the auth gate into `workspace-template/transcript_auth.py`
   — a 20-line module with no heavy imports so the security-critical
   code is unit-testable without standing up the full uvicorn/a2a/httpx
   stack (the former inline guard could only be tested end-to-end,
   which explains why the regression shipped in #287).

2. `transcript_authorized(expected, auth_header)` returns False when
   `expected` is None or empty — the #328 fix — and otherwise does
   strict equality against "Bearer <expected>".

3. main.py's inline handler calls the extracted function:
     if not _transcript_authorized(get_token(), auth_header):
         return 401

4. New tests/test_transcript_auth.py covers: None token, empty token,
   valid bearer, wrong bearer, missing header, case-sensitive prefix,
   whitespace fuzzing. All 7 pass.

Closes #328

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:17:37 -07:00
Hongming Wang
2eec33a279 chore(org): wire molecule-compliance + molecule-audit + molecule-freeze-scope (closes #322)
Config-only YAML. CI green on all 6 checks (E2E cancel = run-supersession pattern). Adds missing plugin wiring: Security Auditor→compliance+audit, Backend→compliance, QA→compliance, DevOps→freeze-scope. Closes #322.
2026-04-15 21:13:26 -07:00
Hongming Wang
d3a7e4c8f9
chore(org): wire molecule-compliance + molecule-audit + molecule-freeze-scope (closes #322)
Config-only YAML. CI green on all 6 checks (E2E cancel = run-supersession pattern). Adds missing plugin wiring: Security Auditor→compliance+audit, Backend→compliance, QA→compliance, DevOps→freeze-scope. Closes #322.
2026-04-15 21:13:26 -07:00
Hongming Wang
bf7614750a docs(glossary): add terminology disambiguation table (closes #320)
CI fully green (all 6 checks pass). Docs-only: adds docs/glossary.md, links from README.md and CLAUDE.md. Closes #320.
2026-04-15 21:13:04 -07:00
Hongming Wang
75dee70027
docs(glossary): add terminology disambiguation table (closes #320)
CI fully green (all 6 checks pass). Docs-only: adds docs/glossary.md, links from README.md and CLAUDE.md. Closes #320.
2026-04-15 21:13:04 -07:00
Hongming Wang
bf2022acf1 fix(security): encrypt channel_config bot_token at rest (closes #319)
CI fully green. Dev Lead code review:  clean, all read/write paths verified, tests cover round-trip + idempotency + legacy plaintext. Closes #319.
2026-04-15 21:09:34 -07:00
Hongming Wang
d85ee97472
fix(security): encrypt channel_config bot_token at rest (closes #319)
CI fully green. Dev Lead code review:  clean, all read/write paths verified, tests cover round-trip + idempotency + legacy plaintext. Closes #319.
2026-04-15 21:09:34 -07:00
Hongming Wang
027d2d213f fix(security): close WorkspaceAuth fail-open on non-existent workspace IDs (#318)
CI fully green. Security Audit cycle 15 LGTM. Closes #318. Closes #325.
2026-04-15 21:02:29 -07:00