Security:
- Replace hardcoded Cloudflare account/zone/KV IDs in wrangler.toml
with placeholders; add wrangler.toml to .gitignore, ship .example
- Replace real EC2 IPs in docs with <EC2_IP> placeholders
- Redact partial CF API token prefix in retrospective
- Parameterize Langfuse dev credentials in docker-compose.infra.yml
- Replace Neon project ID in runbook with <neon-project-id>
Community:
- Add CONTRIBUTING.md (build, test, branch conventions, CI info)
- Add CODE_OF_CONDUCT.md (Contributor Covenant 2.1)
Cleanup:
- Replace personal runner username/machine name in CI + PLAN.md
- Replace personal tenant URL in MCP setup guide
- Replace personal author field in bundle-system doc
- Replace personal login in webhook test fixture
- Rewrite cryptominer incident reference as generic security remediation
- Remove private repo commit hashes from PLAN.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds role="button", tabIndex, aria-label="Select <name>", and keyboard
handlers (Enter/Space) to TeamMemberChip. Fixes 5 failing a11y tests
from issue #831. Updates eject button test to match existing label format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add supply_chain.go with VerifyManifestIntegrity (SHA256 content check)
- Add pinned-ref enforcement to GithubResolver.Fetch (rejects bare org/repo)
- Fix duplicate TestSlackAdapter_Type across channels_test.go and slack_test.go
- Fix sync.Once lock copy in audit_test.go resetAuditKeyCache
- Fix slack_test.go horizontal rule expectations to match implementation
- Existing tests updated with PLUGIN_ALLOW_UNPINNED=true for bare-ref specs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Second layer of the permanent CRLF fix. The Go provisioner now strips
\r\n → \n from shell, Python, and markdown files during the tar
copy into containers.
Three-layer CRLF defense:
1. Provisioner (this) — strips during template copy
2. Entrypoint.sh — strips at boot (safety net)
3. Runtime plugin installer (builtins.py) — strips during plugin install
Any one layer is sufficient. All three together make CRLF impossible.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full staging environment that mirrors production. Every infra change
ships to staging first before promotion. Gates Phase 33 (Tunnel) and
Phase 35 (security hardening).
Components: Railway staging env, Neon branch, staging DNS, tagged
Docker images, promotion workflow, automated smoke tests.
Also marks Phase 33 as migrating from Worker to Cloudflare Tunnel
(issue #933), prerequisite: staging.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HEAD~1 doesn't work for merge commits. Use github.event.before (the
previous main tip) for push events and github.event.pull_request.base.sha
for PRs. fetch-depth: 0 ensures both SHAs are available.
Fallback: if BASE is empty (new branch), run all jobs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds the final step (3/3) of the durable Temporal resume path:
Platform (Go):
- `Latest` handler: GET /workspaces/:id/checkpoints/latest returns the
most recently completed step across all workflows for the workspace,
ordered by completed_at DESC. Returns 404 when no checkpoints exist.
- Router: registers the new route BEFORE the wildcard :wfid route to
avoid shadowing; callerMismatch guard enforces workspace isolation.
- 4 new unit tests: 200, 500, 404 (ErrNoRows), and 403 (caller mismatch).
Workspace runtime (Python):
- `_fetch_latest_checkpoint()`: non-fatal async helper that GETs the
new endpoint and returns the parsed dict, or None on 404 / any error.
- `TemporalWorkflowWrapper.run()`: on startup, fetches the latest
checkpoint and prepends a synthetic [system, ...] entry to the
serialised AgentTaskInput.history so the agent is aware of its prior
crash state before receiving the current task.
- 4 new pytest tests: 404→None, 200→dict, exception→None (non-fatal
contract), and end-to-end injection into AgentTaskInput.history.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dorny/paths-filter uses Docker internally which doesn't work on the
self-hosted macOS arm64 runner — every CI run since the path filter
change has failed with no jobs.
Replace with a simple git diff against HEAD~1 that checks path prefixes.
Same behavior, no Docker dependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remote had the pre-fraud-audit MemPalace WATCH entry. Resolved by keeping
HEAD: BLOCKED/FRAUD verdict (SA audit 2026-04-18) plus the two new run-b
entries (chrome-devtools-mcp, craft-agents-oss).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two new entries from daily sweep (TR GitHub trending + CI social feeds):
- chrome-devtools-mcp (ChromeDevTools/chrome-devtools-mcp, 35.9k★): Official
Google Chrome DevTools MCP server — 29 tools for browser control, network
inspection, Lighthouse audits. Strong MCP adoption signal from Google.
GH #926 filed: add as bundled MCP server option in workspace templates.
- craft-agents-oss (lukilabs/craft-agents-oss, 4.3k★): Electron desktop app
on Claude Agent SDK — multi-session inbox, 3-tier permissions, MCP support.
Single-user desktop vs. Molecule's multi-tenant org-graph. UX reference for
approval queue / permission tier UI.
CI sweep clean (no additional findings). RevoClaw near-miss logged (outside
24h window, no public repo yet).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The @requires_approval decorator and request_approval() call executed the
approval gate correctly but never wrote the outcome to the activity log.
EU AI Act Article 14 requires documented evidence that HITL measures were
exercised — the missing log_event() calls meant GET /workspaces/:id/activity
could not surface HITL gate outcomes.
Add log_event() at both resolution points in the requires_approval wrapper:
- Denial: event_type="hitl", action="approve", outcome="denied", actor=decided_by
- Grant: event_type="hitl", action="approve", outcome="granted", actor=decided_by
Both calls follow the existing try/except pattern used for audit calls elsewhere
in hitl.py so a missing audit module never blocks the approval flow.
Tests: TestRequiresApproval.test_logs_hitl_denied_event and
test_logs_hitl_approved_event verify log_event is called with the correct
outcome on each resolution path.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full retrospective of the 2026-04-16/17 SaaS buildout session:
- What was done (infra migration, 40+ PRs, 5 issues, 4 docs, 1 new repo)
- What should NOT have been changed (wildcard DNS churn, AdminAuth shortcut)
- Security concerns (8 items, 2 CRITICAL)
- Workflow gaps (registration, boot time, CI)
- Tests needed (automated + manual + security)
Phase 35 in PLAN.md covers production hardening follow-ups.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add comment to .env.example explaining ANTHROPIC_API_KEY must be set
as a *global* secret (not just workspace-level) so SDK-direct workspaces
(e.g. molecule-hitl, hermes) receive it without 401 errors
- Add ANTHROPIC_API_KEY to saas-secrets.md secret map with context on
why global propagation matters
- Add full rotation procedure section (generate → PUT /settings/secrets
→ verify restart → revoke old key) with blast-radius note
Closes#894
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BroadcastToWorkspaceChannels now filters channel_type='slack'.
Telegram is CEO-only — explicit escalations via agent's outbound call,
never auto-posted from cron output. PM's routine pulses and agent
errors were spamming the CEO's Telegram.
PM's Telegram channel stays enabled for POLLING (inbound CEO messages)
but BroadcastToWorkspaceChannels skips it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Conflicts arose because PR #892 base commits (MemoryInspectorPanel creation,
A2A overlay) had already landed on main via a different merge path, and
last-tick merges (#876, #888) had modified Toolbar, SidePanel, and test
fixtures.
Resolution strategy:
- Toolbar.tsx, SidePanel.tsx, Canvas.a11y.test.tsx, Canvas.pan-to-node.test.tsx,
MemoryInspectorPanel.test.tsx: take main (strictly newer, already contains
the branch's A2A overlay content plus subsequent a11y/UX fixes)
- MemoryInspectorPanel.tsx: take main (543 lines with semantic search) + apply
sanitizeId() helper from #904 + update bodyId prefix to mem-body-
- DetailsTab.tsx: take main (has #875 Field/useId + #878 deleteButtonRef/focus)
+ apply alertdialog structure from #905 while preserving focus management
Mechanical conflict resolution by triage-agent; no logic changes beyond the
four a11y fixes already in the branch (#902-#905).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents agentskills.io v0.8.0 raw-drop hermes compatibility and
the before/after runtimes table for the five SKILL.md-only plugins.
Includes links to the companion draft PRs in each plugin repo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>