Commit Graph

8 Commits

Author SHA1 Message Date
Hongming Wang
009769e263 fix(security): chmod 600 macOS launchd plist containing CDP token (#296)
One-liner oversight from #295: the macOS install path wrote the plist
with the default umask (~0644), leaving CDP_PROXY_TOKEN world-readable
to any local user account. The Linux path already writes to a chmod
600 env-file — this brings macOS to parity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:20:48 -07:00
Hongming Wang
c0be9baab1 fix(security): token-auth on cdp-proxy to prevent LAN exposure (#293)
HIGH finding from security-auditor on PR #291 (merged tick-37). The
cdp-proxy bound to 0.0.0.0:9223 with no authentication, exposing
Chrome DevTools Protocol — full remote control of any tab, including
cookie/localStorage exfiltration — to anyone on the same WiFi/LAN.

Root cause: Docker Desktop on macOS routes host.docker.internal
through the VM network interface, not loopback. Binding to 127.0.0.1
would break the primary use case (containers reaching the host
Chrome). The design trade was "bind wide for reachability, accept LAN
exposure" — #293 makes that trade unacceptable.

Fix: bearer token auth on every HTTP + WebSocket request. The proxy
REFUSES TO START without a token — no unauth mode.

Three-file change:

1. cdp-proxy.cjs
   - Read token from CDP_PROXY_TOKEN env OR ~/.molecule-cdp-proxy-token
   - Fail loudly if neither is set (exit 1 with install-host-bridge.sh
     pointer)
   - Validate X-CDP-Proxy-Token header via crypto.timingSafeEqual on
     every HTTP request AND every WS upgrade
   - Strip the header before forwarding to Chrome (defense in depth —
     token never leaks into Chrome's request log)

2. install-host-bridge.sh
   - New ensure_token() function generates a 64-char hex token via
     openssl rand -hex 32 (fallback to /dev/urandom). Written to
     ~/.molecule-cdp-proxy-token with chmod 600.
   - macOS: token injected into launchd plist EnvironmentVariables
   - Linux: written to ~/.molecule-cdp-proxy.env (chmod 600) and
     referenced via systemd EnvironmentFile — avoids embedding the
     token in the often world-readable unit file
   - Install reuses existing token if present (16+ chars); uninstall
     preserves token file so a reinstall keeps the same token
   - Verify command now includes the token header
   - Documents container-side bind-mount pattern
     (-v ~/.molecule-cdp-proxy-token:/run/secrets/cdp-proxy-token:ro)

3. lib/connect.js
   - New loadProxyToken() with precedence: env var >
     /run/secrets/cdp-proxy-token > ~/.molecule-cdp-proxy-token
   - Attaches X-CDP-Proxy-Token header on both /json/version probe +
     final puppeteer.connect() call via headers: {} option
     (puppeteer-core v21+ supports this natively)
   - Host-direct fallback (CDP port 9222 on loopback) unchanged —
     Chrome's own port is loopback-only so it doesn't need the token

Attack surface now:
  - LAN attacker must also steal the token file from the user's home
    directory (requires shell access) OR the env var (requires
    launchd/systemd process inspection as the same user) — reduces to
    local-privilege-escalation territory
  - Containers on the same Docker network still have access (they
    mount the token by design) — intentional, any workspace-template
    install already runs inside the platform's trust boundary

Not fixing in this PR:
  - Rate limiting on /json/version (low priority — probe-and-mine is
    expensive even without)
  - IP allowlist on top of token auth (diminishing returns)
  - Rotating the token periodically (user can rm ~/.molecule-cdp-proxy-token
    and reinstall)

Closes #293.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:00:02 -07:00
airenostars
ff19c2ce26 feat(browser-automation): bundle host-bridge CDP proxy + connect helper
The plugin now ships everything a user needs to wire Chrome on their
host to workspaces inside Docker:

- host-bridge/cdp-proxy.cjs — rewrites the Host header so Chrome accepts
  DevTools Protocol connections from container-originated traffic, and
  forwards both HTTP (tab list, screenshots) and WebSocket upgrades.

- host-bridge/install-host-bridge.sh — one-command install on macOS
  (launchd user agent) or Linux (systemd --user unit). `uninstall`
  subcommand cleans up. No root required.

- skills/browser-automation/lib/connect.js — the mandatory helper
  consumers already use; re-exported here so the plugin is self-contained.

- SKILL.md — documents the one-time host setup and the existing
  defaultViewport:null + disconnect-not-close rules. The 2026-04-15
  social-media-poster incident (3h debug chasing phantom "sessions
  expired" errors on an 800x600 viewport) is captured inline.

Smoke-tested on macOS: install script registered the agent, proxy
listens on 0.0.0.0:9223, and a live workspace container
(ws-bee4d521-3d3) successfully reached Chrome via
host.docker.internal:9223.

This replaces ad-hoc per-user CDP proxies and makes the plugin
usable by any Molecule operator, not just the Reno Stars org.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:29:46 -07:00
Hongming Wang
45e4eb0be3 feat(plugin): split compliance-posture into 3 plugins (#256)
Closes #256. Per CEO direction, shipping three separate opt-in plugins
instead of one bundled "compliance-posture" — keeps installs granular
so a workspace that only wants CVE scanning doesn't carry OWASP policy
or append-only audit retention.

- plugins/molecule-compliance/        — wraps compliance.py (OWASP OA-01
  prompt injection + OA-03 excessive agency). Skill: owasp-agentic.
- plugins/molecule-audit/              — wraps audit.py (EU AI Act Art.
  12/13/17 append-only JSONL log, SIEM-friendly). Skill: ai-act-audit-log.
- plugins/molecule-security-scan/      — wraps security_scan.py (Snyk or
  pip-audit CVE gate on skill requirements.txt). Skill: skill-cve-gate.

Each plugin ships a manifest + one SKILL.md with:
- When to install / when to skip
- Configuration shape (config.yaml blocks)
- Anti-patterns to avoid
- Cross-references to the other two plugins so an operator can reason
  about the full compliance surface

All three wrap code that already exists in workspace-template/builtin_tools/
— no Python changes. Install per workspace via
POST /workspaces/:id/plugins {"source":"builtin://molecule-<name>"}.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:15:25 -07:00
Hongming Wang
18b94e0025 feat(plugin): molecule-hitl — opt-in HITL gates (#257)
Closes #257. Thin manifest + skill doc that activates the existing
builtin_tools/hitl.py primitives as a per-workspace opt-in plugin.

The Python implementation (@requires_approval decorator, pause_task /
resume_task tools, multi-channel notification, RBAC bypass roles) is
already in every runtime image — this plugin is the policy layer that
tells agents *when* to call them.

- plugins/molecule-hitl/plugin.yaml — runtimes: langgraph, claude_code,
  deepagents; skills: hitl-gates
- plugins/molecule-hitl/skills/hitl-gates/SKILL.md — documents the 5
  classes of action that need a gate (deployment / irreversible FS /
  public message / production mutation / cross-workspace destructive),
  decorator pattern, pause/resume pattern, config shape, 4 anti-patterns,
  5-step test plan

No Python code — all implementation already exists. Install per
workspace via POST /workspaces/:id/plugins.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:03:19 -07:00
Hongming Wang
90a513d1d0 feat(plugins): split guardrails into 12 modular plugins
Replaces the proposed monolithic molecule-guardrails plugin with 12
single-purpose plugins users can install à la carte. Powered by a
small extension to the AgentskillsAdaptor base class so any plugin can
ship hooks/, commands/, and a settings-fragment.json without writing a
custom adapter.

## Base adapter changes

workspace-template/plugins_registry/builtins.py + sdk/python/molecule_plugin/builtins.py
(both copies — drift-tested):
- New _install_claude_layer() helper called at the end of install()
- Conditionally copies hooks/ → /configs/.claude/hooks/ (preserving exec bit)
- Conditionally copies commands/*.md → /configs/.claude/commands/
- Conditionally merges settings-fragment.json into /configs/.claude/settings.json
  with ${CLAUDE_DIR} placeholder rewritten to the workspace's absolute install
  path. Existing user hooks are preserved (deep-merge by event name).
- All steps no-op when the plugin doesn't ship the corresponding files,
  so existing skill+rule plugins (molecule-dev, superpowers, ecc,
  browser-automation) are unchanged.

Drift test (tests/test_plugins_builtins_drift.py) still passes.

## 12 new plugins

Hook plugins (ambient enforcement):
- molecule-careful-bash       — refuses destructive bash; ships careful-mode skill
- molecule-freeze-scope       — locks edits via .claude/freeze
- molecule-audit-trail        — appends every Edit/Write to audit.jsonl
- molecule-session-context    — auto-loads cron-learnings at session start
- molecule-prompt-watchdog    — injects warnings on destructive prompt keywords

Skill plugins (on-demand):
- molecule-skill-code-review        — 16-criteria multi-axis review
- molecule-skill-cross-vendor-review — adversarial second-model review
- molecule-skill-llm-judge          — deliverable-vs-request scoring
- molecule-skill-update-docs        — post-merge doc sync
- molecule-skill-cron-learnings     — operational-memory JSONL format

Workflow plugins (slash commands):
- molecule-workflow-triage  — /triage full PR-triage cycle
- molecule-workflow-retro   — /retro + cron-retro skill, weekly retrospective

Each ships only what it needs — most have just plugin.yaml + skills/ or
hooks/ + adapter (one-line stub: `from plugins_registry.builtins import
AgentskillsAdaptor as Adaptor`). Total ~120 files but each plugin is
small and self-contained.

## Verification

- python3 -m molecule_plugin validate plugins/molecule-* → all 13 valid
  (12 new + pre-existing molecule-dev)
- End-to-end install smoke test on representative samples: hook plugin
  (molecule-careful-bash), skill-only plugin (molecule-skill-code-review),
  workflow plugin (molecule-workflow-triage). All produce expected
  /configs/ tree, settings.json paths rewritten, exec bits preserved,
  zero warnings.
- workspace-template pytest tests/test_plugins_builtins_drift.py → passes
  (SDK + runtime stay in sync).

## CLAUDE.md repo-doc updated

Lists all 12 new plugins under the existing Plugins section, organized
by category (hook / skill / workflow). Each entry one line, recommend-
together hints where dependencies make sense.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 12:20:04 -07:00
Hongming Wang
fa9342aa81 chore: structural cleanup — dead dirs, moves, gitignore
- Delete empty platform/plugins/ (dead remnant; plugins/ at repo root is
  the real registry; router.go comment updated)
- Gitignore local dev cruft: platform/workspace-configs-templates/,
  .agents/ (codex/gemini skill cache), backups/
- Untrack .agents/skills/ (keep local, stop tracking)
- Move examples/remote-agent/ → sdk/python/examples/remote-agent/
  (co-locate with the SDK it exercises); update refs in
  molecule_agent README + __init__ + PLAN.md + the demo's own README
- Move docs/superpowers/plans/ → plugins/superpowers/plans/
  (plans were written by the superpowers plugin's writing-plans
  subskill; belong with the plugin, not under docs)
- Add tests/README.md explaining the unit-tests-per-package +
  root-E2E split so new contributors don't ask
- Add docs/README.md explaining why site tooling lives under docs/
  rather than a separate docs-site/ (VitePress ergonomics)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:06:52 -07:00
Hongming Wang
24fec62d7f initial commit — Molecule AI platform
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1)
with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo.

Brand: Starfire → Molecule AI.
Slug: starfire / agent-molecule → molecule.
Env vars: STARFIRE_* → MOLECULE_*.
Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform.
Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent.
DB: agentmolecule → molecule.

History truncated; see public repo for prior commits and contributor
attribution. Verified green: go test -race ./... (platform), pytest
(workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:55:37 -07:00