Compare commits

...

37 Commits

Author SHA1 Message Date
fullstack-engineer a60033dc16 test(handlers): add missing DB-error tests for Record and SessionSearch
E2E API Smoke Test / E2E API Smoke Test (pull_request) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Blocked by required conditions
Harness Replays / Harness Replays (pull_request) Blocked by required conditions
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Waiting to run
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Waiting to run
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Waiting to run
publish-runtime-autobump / bump-and-tag (pull_request) Waiting to run
MCP Stdio Transport Regression / MCP stdio with regular-file stdout (pull_request) Successful in 3m8s
publish-runtime-autobump / pr-validate (pull_request) Successful in 1m22s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 2m11s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m41s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 3m6s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Failing after 1m59s
audit-force-merge / audit (pull_request) Waiting to run
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Blocked by required conditions
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 34s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 43s
CI / Detect changes (pull_request) Successful in 1m13s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 24s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m16s
Harness Replays / detect-changes (pull_request) Successful in 53s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m57s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 38s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 58s
qa-review / approved (pull_request) Failing after 48s
gate-check-v3 / gate-check (pull_request) Failing after 55s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m51s
security-review / approved (pull_request) Failing after 41s
sop-tier-check / tier-check (pull_request) Successful in 40s
CI / Python Lint & Test (pull_request) Successful in 8m14s
CI / Canvas (Next.js) (pull_request) Successful in 19m47s
CI / Platform (Go) (pull_request) Successful in 21m16s
CI / all-required (pull_request) Successful in 21m27s
CI / Canvas Deploy Reminder (pull_request) Successful in 8s
sop-checklist / all-items-acked (pull_request) [info tier:low] acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, l
- TestDelegationRecord_DBInsertFails: verifies 500 on activity_logs insert failure
- TestSessionSearch_DBError: verifies 500 on WITH query failure

Both are regression coverage for error paths that lacked test coverage.

🤖 Generated with [Claude Code](https://claude.ai/claude-code)
2026-05-15 07:38:15 +00:00
app-fe 5dc1e462de fix(external-workspace): pin molecule-ai-workspace-runtime>=0.1.999 in OpenClaw snippet (#1143)
Block internal-flavored paths / Block forbidden paths (push) Successful in 17s
publish-workspace-server-image / Production auto-deploy (push) Blocked by required conditions
CI / Shellcheck (E2E scripts) (push) Successful in 35s
Handlers Postgres Integration / detect-changes (push) Successful in 25s
Harness Replays / detect-changes (push) Successful in 22s
CI / Detect changes (push) Successful in 58s
E2E API Smoke Test / detect-changes (push) Successful in 59s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 21s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m1s
Harness Replays / Harness Replays (push) Successful in 13s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 1m11s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 53s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 4m7s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 6m36s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 7m11s
CI / Python Lint & Test (push) Successful in 8m23s
publish-workspace-server-image / build-and-push (push) Successful in 13m9s
CI / Canvas (Next.js) (push) Successful in 21m39s
CI / Platform (Go) (push) Successful in 23m7s
CI / all-required (push) Successful in 27m51s
CI / Canvas Deploy Reminder (push) Successful in 13s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Has started running
Runtime Pin Compatibility / PyPI-latest install + import smoke (push) Has started running
Railway pin audit (drift detection) / Audit Railway env vars for drift-prone pins (push) Has started running
main-red-watchdog / watchdog (push) Has started running
gate-check-v3 / gate-check (push) Has started running
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Has started running
ci-required-drift / drift (push) Has started running
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 28s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 1m0s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 5m52s
gitea-merge-queue / queue (push) Successful in 27s
status-reaper / reap (push) Successful in 3m26s
fix(external-workspace): pin molecule-ai-workspace-runtime>=0.1.999 in OpenClaw snippet

Ensures the molecule-mcp console script (heartbeat + register-on-startup) is present on install. Older versions only ship a2a_mcp_server which does not heartbeat, causing workspaces to go OFFLINE within 60s.

Closes openclaw keepalive regression.
Co-authored-by: Molecule AI App-FE <app-fe@agents.moleculesai.app>
Co-committed-by: Molecule AI App-FE <app-fe@agents.moleculesai.app>
2026-05-15 07:35:57 +00:00
devops-engineer ec96a8f600 Merge pull request 'fix(ci): throttle SOP refire workflow fan-out' (#1134) from fix/ci-sop-refire-concurrency into main
Block internal-flavored paths / Block forbidden paths (push) Successful in 12s
Handlers Postgres Integration / detect-changes (push) Successful in 15s
CI / Shellcheck (E2E scripts) (push) Successful in 27s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (push) Successful in 19s
CI / Detect changes (push) Successful in 46s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 18s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 47s
E2E API Smoke Test / detect-changes (push) Successful in 54s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 13s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 49s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 11s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (push) Successful in 1m43s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (push) Successful in 3m6s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 3m1s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 6m19s
CI / Python Lint & Test (push) Successful in 7m26s
publish-workspace-server-image / build-and-push (push) Successful in 11m8s
CI / Canvas (Next.js) (push) Successful in 19m19s
CI / Canvas Deploy Reminder (push) Successful in 8s
CI / Platform (Go) (push) Successful in 21m11s
CI / all-required (push) Successful in 21m44s
publish-workspace-server-image / Production auto-deploy (push) Successful in 9m57s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 23s
E2E Staging SaaS (full lifecycle) / pr-validate (push) Successful in 1m4s
main-red-watchdog / watchdog (push) Successful in 58s
gate-check-v3 / gate-check (push) Successful in 1m24s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 35s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (push) Failing after 15m54s
ci-required-drift / drift (push) Successful in 1m58s
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 5s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 4m54s
E2E Staging External Runtime / E2E Staging External Runtime (push) Successful in 5m32s
gitea-merge-queue / queue (push) Successful in 31s
status-reaper / reap (push) Successful in 2m51s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 5m55s
2026-05-15 05:57:38 +00:00
claude-ceo-assistant 3198a3ee5d fix(ci): throttle SOP refire workflow fan-out
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 29s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 1m21s
CI / Detect changes (pull_request) Successful in 1m29s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m8s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 55s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 25s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 21s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 37s
gate-check-v3 / gate-check (pull_request) Successful in 38s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 1m10s
sop-checklist / all-items-acked (pull_request) Successful in 23s
sop-tier-check / tier-check (pull_request) Successful in 19s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 14s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 12s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 15s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m49s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 58s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 2m38s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m55s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m59s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m54s
CI / Python Lint & Test (pull_request) Successful in 7m53s
qa-review / approved (pull_request) Approved by core-qa review #3561
security-review / approved (pull_request) Approved by core-security review #3562
CI / Platform (Go) (pull_request) Successful in 13m43s
CI / Canvas (Next.js) (pull_request) Successful in 14m23s
CI / Canvas Deploy Reminder (pull_request) Successful in 7s
CI / all-required (pull_request) Successful in 14m35s
audit-force-merge / audit (pull_request) Successful in 18s
2026-05-14 22:39:05 -07:00
hongming-codex-laptop 85b93feacc ci: prevent advisory workflow timeout flakes
Block internal-flavored paths / Block forbidden paths (push) Successful in 15s
CI / Detect changes (push) Successful in 27s
CI / Shellcheck (E2E scripts) (push) Successful in 36s
Handlers Postgres Integration / detect-changes (push) Successful in 16s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (push) Successful in 16s
E2E API Smoke Test / detect-changes (push) Successful in 31s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 41s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 23s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 50s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 13s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 11s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (push) Successful in 1m53s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (push) Successful in 2m26s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 3m2s
CI / Python Lint & Test (push) Successful in 7m33s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 6m59s
publish-workspace-server-image / build-and-push (push) Successful in 12m40s
dev-lead/test orchestrator test
CI / Canvas (Next.js) (push) Successful in 18m53s
CI / Platform (Go) (push) Successful in 21m52s
CI / Canvas Deploy Reminder (push) Successful in 6s
CI / all-required (push) Successful in 21m53s
publish-workspace-server-image / Production auto-deploy (push) Successful in 6m15s
lint-bp-context-emit-match / lint-bp-context-emit-match (push) Successful in 2m13s
MCP Stdio Transport Regression / MCP stdio with regular-file stdout (push) Successful in 1m32s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 42s
SECRET_PATTERNS drift lint / Detect SECRET_PATTERNS drift (push) Failing after 14m9s
ci-required-drift / drift (push) Successful in 2m7s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Has started running
main-red-watchdog / watchdog (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
gate-check-v3 / gate-check (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 6s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 13s
gitea-merge-queue / queue (push) Successful in 10s
status-reaper / reap (push) Successful in 1m28s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 5m16s
2026-05-14 20:00:19 -07:00
hongming-codex-laptop da2fefa398 ci: harden scheduled gate check against list timeouts
Handlers Postgres Integration / Handlers Postgres Integration (push) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (push) Successful in 28s
CI / Shellcheck (E2E scripts) (push) Successful in 1m1s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (push) Successful in 32s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 37s
CI / Detect changes (push) Successful in 2m24s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 2m16s
E2E API Smoke Test / detect-changes (push) Successful in 2m18s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (push) Successful in 2m12s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 1m44s
CI / Python Lint & Test (push) Successful in 8m40s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 22s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 20s
Handlers Postgres Integration / detect-changes (push) Failing after 10m24s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (push) Failing after 10m19s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 36s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 2m58s
publish-workspace-server-image / build-and-push (push) Successful in 13m23s
CI / Canvas (Next.js) (push) Successful in 19m24s
CI / Canvas Deploy Reminder (push) Successful in 12s
CI / Platform (Go) (push) Successful in 21m49s
CI / all-required (push) Successful in 21m50s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 5m6s
publish-workspace-server-image / Production auto-deploy (push) Successful in 6m4s
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 16s
gitea-merge-queue / queue (push) Successful in 33s
status-reaper / reap (push) Successful in 2m23s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 5m22s
2026-05-14 19:31:31 -07:00
hongming-codex-laptop 8f4c00ba05 ci: rearm after runner disk gc
CI / Canvas Deploy Reminder (push) Blocked by required conditions
E2E API Smoke Test / E2E API Smoke Test (push) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (push) Blocked by required conditions
publish-workspace-server-image / Production auto-deploy (push) Blocked by required conditions
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (push) Successful in 25s
CI / Shellcheck (E2E scripts) (push) Successful in 43s
CI / Detect changes (push) Successful in 1m16s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m9s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 22s
E2E API Smoke Test / detect-changes (push) Successful in 1m20s
Handlers Postgres Integration / detect-changes (push) Successful in 58s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 50s
CI / Python Lint & Test (push) Successful in 8m9s
publish-workspace-server-image / build-and-push (push) Successful in 13m23s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 1m10s
CI / Platform (Go) (push) Has been cancelled
CI / Canvas (Next.js) (push) Has been cancelled
CI / all-required (push) Has been cancelled
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Has started running
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 31s
ci-required-drift / drift (push) Successful in 2m47s
gate-check-v3 / gate-check (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
2026-05-14 19:06:22 -07:00
hongming-codex-laptop 106baadf2b ci: fix platform staticcheck lint
Block internal-flavored paths / Block forbidden paths (push) Successful in 26s
CI / Detect changes (push) Successful in 1m5s
CI / Shellcheck (E2E scripts) (push) Successful in 50s
Harness Replays / detect-changes (push) Successful in 28s
E2E API Smoke Test / detect-changes (push) Successful in 54s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 23s
Handlers Postgres Integration / detect-changes (push) Successful in 1m8s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 48s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m9s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 24s
ci-required-drift / drift (push) Successful in 2m22s
CI / Python Lint & Test (push) Successful in 7m52s
publish-workspace-server-image / build-and-push (push) Successful in 10m3s
CI / Canvas (Next.js) (push) Successful in 18m10s
Harness Replays / Harness Replays (push) Successful in 13s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 20s
CI / Platform (Go) (push) Successful in 19m30s
CI / all-required (push) Successful in 19m25s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 2m49s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Failing after 4m12s
Handlers Postgres Integration / Handlers Postgres Integration (push) Failing after 5m31s
publish-workspace-server-image / Production auto-deploy (push) Successful in 2m22s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 21s
CI / Canvas Deploy Reminder (push) Successful in 11s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Has started running
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 16s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 4m57s
main-red-watchdog / watchdog (push) Successful in 1m18s
2026-05-14 18:12:21 -07:00
hongming-codex-laptop 6b80dca1f4 fix: preserve Claude Code provider registry in generated configs
CI / Canvas Deploy Reminder (push) Blocked by required conditions
publish-workspace-server-image / Production auto-deploy (push) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (push) Successful in 18s
CI / Shellcheck (E2E scripts) (push) Successful in 37s
CI / Detect changes (push) Successful in 1m6s
Harness Replays / detect-changes (push) Successful in 17s
E2E Staging SaaS (full lifecycle) / pr-validate (push) Successful in 1m3s
E2E API Smoke Test / detect-changes (push) Successful in 1m9s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m12s
Handlers Postgres Integration / detect-changes (push) Successful in 57s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 19s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 52s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (push) Successful in 5m42s
CI / Python Lint & Test (push) Successful in 7m49s
publish-workspace-server-image / build-and-push (push) Successful in 9m37s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 23s
CI / Canvas (Next.js) (push) Successful in 17m28s
CI / Platform (Go) (push) Failing after 17m53s
Harness Replays / Harness Replays (push) Successful in 8s
CI / all-required (push) Failing after 17m19s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 10s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 2m31s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 2m57s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 5m20s
main-red-watchdog / watchdog (push) Successful in 1m11s
gate-check-v3 / gate-check (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
2026-05-14 17:33:22 -07:00
hongming-codex-laptop 2f5b145c58 ci: rerun core pipeline after runner recovery
Block internal-flavored paths / Block forbidden paths (push) Successful in 15s
CI / Shellcheck (E2E scripts) (push) Successful in 33s
CI / Detect changes (push) Successful in 45s
E2E API Smoke Test / detect-changes (push) Successful in 58s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 19s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m0s
Handlers Postgres Integration / detect-changes (push) Successful in 51s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 51s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 13s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 19s
CI / Python Lint & Test (push) Successful in 7m34s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 19s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 3m17s
publish-workspace-server-image / build-and-push (push) Successful in 11m39s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 7m22s
CI / Canvas (Next.js) (push) Successful in 19m50s
CI / Platform (Go) (push) Failing after 21m20s
CI / all-required (push) Failing after 21m54s
publish-workspace-server-image / Production auto-deploy (push) Failing after 35s
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 12s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Has started running
CI / Canvas Deploy Reminder (push) Successful in 8s
main-red-watchdog / watchdog (push) Successful in 1m0s
gate-check-v3 / gate-check (push) Successful in 12s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 45s
ci-required-drift / drift (push) Successful in 1m32s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 5m24s
2026-05-14 16:40:30 -07:00
hongming-codex-laptop 420ac2f00d ci: update instructions handler test expectations
CI / Canvas Deploy Reminder (push) Blocked by required conditions
publish-workspace-server-image / build-and-push (push) Waiting to run
publish-workspace-server-image / Production auto-deploy (push) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (push) Successful in 30s
CI / Detect changes (push) Successful in 1m7s
CI / Shellcheck (E2E scripts) (push) Successful in 40s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m4s
E2E API Smoke Test / detect-changes (push) Successful in 1m15s
Harness Replays / detect-changes (push) Successful in 22s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 23s
Handlers Postgres Integration / detect-changes (push) Successful in 1m42s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 1m0s
status-reaper / reap (push) Has started running
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 17s
Harness Replays / Harness Replays (push) Successful in 10s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 10s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 2m8s
CI / Python Lint & Test (push) Successful in 7m36s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 5m12s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 5m3s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 2m59s
CI / Canvas (Next.js) (push) Has been cancelled
CI / Platform (Go) (push) Has been cancelled
CI / all-required (push) Has been cancelled
Handlers Postgres Integration / Handlers Postgres Integration (push) Has been cancelled
gitea-merge-queue / queue (push) Successful in 22s
2026-05-14 16:25:55 -07:00
devops-engineer 8fced20267 fix: limit CP template config transport
Block internal-flavored paths / Block forbidden paths (push) Successful in 31s
CI / Detect changes (push) Successful in 58s
CI / Shellcheck (E2E scripts) (push) Successful in 42s
E2E API Smoke Test / detect-changes (push) Successful in 36s
Harness Replays / detect-changes (push) Successful in 19s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 45s
Handlers Postgres Integration / detect-changes (push) Successful in 49s
E2E Staging SaaS (full lifecycle) / pr-validate (push) Successful in 1m4s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 27s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 57s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (push) Successful in 5m22s
Harness Replays / Harness Replays (push) Successful in 29s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 36s
CI / Python Lint & Test (push) Successful in 7m45s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 3m39s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 3m40s
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 38s
publish-workspace-server-image / build-and-push (push) Successful in 11m58s
Handlers Postgres Integration / Handlers Postgres Integration (push) Successful in 6m57s
CI / Canvas (Next.js) (push) Successful in 17m14s
CI / Canvas Deploy Reminder (push) Successful in 7s
CI / Platform (Go) (push) Failing after 17m57s
publish-workspace-server-image / Production auto-deploy (push) Failing after 2m37s
CI / all-required (push) Failing after 17m57s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 4m57s
main-red-watchdog / watchdog (push) Successful in 57s
gate-check-v3 / gate-check (push) Successful in 24s
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 2s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 11s
ci-required-drift / drift (push) Successful in 1m0s
status-reaper / reap (push) Has started running
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 5m4s
gitea-merge-queue / queue (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
2026-05-14 15:37:44 -07:00
devops-engineer 7b3e3fc189 ci: fix handlers instruction test compile
publish-workspace-server-image / Production auto-deploy (push) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (push) Successful in 10s
CI / Detect changes (push) Successful in 18s
CI / Shellcheck (E2E scripts) (push) Successful in 18s
Harness Replays / detect-changes (push) Successful in 10s
E2E API Smoke Test / detect-changes (push) Successful in 19s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 21s
Handlers Postgres Integration / detect-changes (push) Successful in 20s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 10s
gitea-merge-queue / queue (push) Successful in 13s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 19s
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 31s
Harness Replays / Harness Replays (push) Successful in 9s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 12s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 2m48s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 3m40s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Successful in 5m19s
CI / Python Lint & Test (push) Successful in 7m34s
CI / Platform (Go) (push) Has been cancelled
CI / all-required (push) Has been cancelled
CI / Canvas Deploy Reminder (push) Has been cancelled
status-reaper / reap (push) Successful in 3m34s
Handlers Postgres Integration / Handlers Postgres Integration (push) Has been cancelled
publish-workspace-server-image / build-and-push (push) Has been cancelled
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 7m34s
CI / Canvas (Next.js) (push) Failing after 9m4s
2026-05-14 15:25:09 -07:00
devops-engineer 51a0fd2688 Merge pull request #1047 from molecule-ai/fix/saas-t4-cp-config-seed
Block internal-flavored paths / Block forbidden paths (push) Successful in 9s
CI / Detect changes (push) Successful in 16s
CI / Shellcheck (E2E scripts) (push) Successful in 21s
E2E API Smoke Test / detect-changes (push) Successful in 17s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 18s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (push) Successful in 15s
Harness Replays / detect-changes (push) Successful in 16s
Handlers Postgres Integration / detect-changes (push) Successful in 37s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 18s
E2E Staging SaaS (full lifecycle) / pr-validate (push) Successful in 44s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 34s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (push) Successful in 1m38s
main-red-watchdog / watchdog (push) Successful in 48s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (push) Successful in 2m9s
Harness Replays / Harness Replays (push) Successful in 7s
gate-check-v3 / gate-check (push) Successful in 1m38s
E2E API Smoke Test / E2E API Smoke Test (push) Successful in 2m16s
E2E Staging External Runtime / E2E Staging External Runtime (push) Successful in 5m14s
publish-canvas-image / Build & push canvas image (push) Successful in 5m19s
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Has started running
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Successful in 2m49s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (push) Successful in 5m58s
Sweep stale Cloudflare DNS records / Sweep CF orphans (push) Successful in 29s
CI / Python Lint & Test (push) Successful in 7m19s
Handlers Postgres Integration / Handlers Postgres Integration (push) Failing after 5m6s
publish-workspace-server-image / build-and-push (push) Successful in 9m53s
ci-required-drift / drift (push) Successful in 2m13s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Successful in 9m4s
CI / Platform (Go) (push) Failing after 13m1s
publish-workspace-server-image / Production auto-deploy (push) Failing after 1m58s
CI / all-required (push) Failing after 13m27s
gitea-merge-queue / queue (push) Successful in 25s
CI / Canvas (Next.js) (push) Successful in 16m36s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Successful in 6m4s
CI / Canvas Deploy Reminder (push) Successful in 4s
status-reaper / reap (push) Successful in 3m25s
# Conflicts:
#	.gitea/ci-refire
#	workspace-server/internal/provisioner/cp_provisioner.go
2026-05-14 15:00:11 -07:00
infra-lead d4bf57392e chore: second CI retrigger attempt
E2E API Smoke Test / E2E API Smoke Test (pull_request) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Blocked by required conditions
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Waiting to run
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Waiting to run
Handlers Postgres Integration / detect-changes (pull_request) Waiting to run
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Blocked by required conditions
Harness Replays / detect-changes (pull_request) Waiting to run
Harness Replays / Harness Replays (pull_request) Blocked by required conditions
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Waiting to run
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Waiting to run
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Waiting to run
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Waiting to run
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Waiting to run
lint-required-no-paths / lint-required-no-paths (pull_request) Waiting to run
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Waiting to run
publish-runtime-autobump / pr-validate (pull_request) Waiting to run
publish-runtime-autobump / bump-and-tag (pull_request) Waiting to run
Runtime PR-Built Compatibility / detect-changes (pull_request) Waiting to run
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Blocked by required conditions
Secret scan / Scan diff for credential-shaped strings (pull_request) Waiting to run
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Waiting to run
gate-check-v3 / gate-check (pull_request) Waiting to run
sop-tier-check / tier-check (pull_request) Waiting to run
sop-checklist / all-items-acked (pull_request) acked: 7/7
qa-review / approved (pull_request) Refired via /qa-recheck by hongming-codex-laptop
security-review / approved (pull_request) Refired via /security-recheck by hongming-codex-laptop
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 24s
CI / Shellcheck (E2E scripts) (pull_request) Has been cancelled
CI / Python Lint & Test (pull_request) Has been cancelled
CI / Detect changes (pull_request) Has been cancelled
CI / Canvas Deploy Reminder (pull_request) Has been cancelled
CI / Platform (Go) (pull_request) Has been cancelled
MCP Stdio Transport Regression / MCP stdio with regular-file stdout (pull_request) Has been cancelled
CI / all-required (pull_request) Has been cancelled
CI / Canvas (Next.js) (pull_request) Has been cancelled
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Has been cancelled
E2E API Smoke Test / detect-changes (pull_request) Has been cancelled
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Has been cancelled
Refs: mc#1047 CI hang - second push
2026-05-14 21:47:39 +00:00
devops-engineer 369578e96a Merge pull request 'fix(provisioner): skip symlinks in collectCPConfigFiles WalkDir (OFFSEC-010)' (#1075) from fix/offsec-010-clean into main
CI / Platform (Go) (push) Blocked by required conditions
CI / Canvas (Next.js) (push) Blocked by required conditions
CI / Shellcheck (E2E scripts) (push) Blocked by required conditions
CI / Canvas Deploy Reminder (push) Blocked by required conditions
CI / Python Lint & Test (push) Blocked by required conditions
CI / all-required (push) Blocked by required conditions
E2E API Smoke Test / E2E API Smoke Test (push) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (push) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (push) Blocked by required conditions
Harness Replays / Harness Replays (push) Blocked by required conditions
publish-workspace-server-image / Production auto-deploy (push) Blocked by required conditions
Runtime PR-Built Compatibility / PR-built wheel + import smoke (push) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (push) Successful in 26s
CI / Detect changes (push) Successful in 1m30s
E2E API Smoke Test / detect-changes (push) Successful in 1m18s
E2E Staging Canvas (Playwright) / detect-changes (push) Successful in 1m4s
Harness Replays / detect-changes (push) Successful in 21s
E2E Staging SaaS (full lifecycle) / pr-validate (push) Successful in 58s
Secret scan / Scan diff for credential-shaped strings (push) Successful in 20s
Handlers Postgres Integration / detect-changes (push) Successful in 1m8s
Runtime PR-Built Compatibility / detect-changes (push) Successful in 1m12s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (push) Has been cancelled
publish-workspace-server-image / build-and-push (push) Has been cancelled
Sweep stale Cloudflare Tunnels / Sweep CF tunnels (push) Successful in 35s
Continuous synthetic E2E (staging) / Synthetic E2E against staging (push) Has started running
Sweep stale e2e-* orgs (staging) / Sweep e2e orgs (push) Successful in 9s
Staging SaaS smoke (every 30 min) / Staging SaaS smoke (push) Compensated by status-reaper (workflow has no push: trigger; Gitea 1.22.6 hardcoded-suffix bug — see .gitea/scripts/status-reaper.py)
2026-05-14 21:36:33 +00:00
infra-lead c704e96117 chore: retrigger CI pipeline — all-required aggregator stalled
E2E API Smoke Test / E2E API Smoke Test (pull_request) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Blocked by required conditions
Harness Replays / Harness Replays (pull_request) Blocked by required conditions
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 37s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 34s
E2E API Smoke Test / detect-changes (pull_request) Successful in 44s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 45s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 39s
Harness Replays / detect-changes (pull_request) Successful in 22s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 1m1s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 21s
MCP Stdio Transport Regression / MCP stdio with regular-file stdout (pull_request) Successful in 1m40s
CI / Platform (Go) (pull_request) Failing after 1m51s
publish-runtime-autobump / bump-and-tag (pull_request) Has been skipped
CI / Canvas (Next.js) (pull_request) Failing after 1m59s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Failing after 2m3s
CI / Python Lint & Test (pull_request) Failing after 2m6s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Failing after 2m11s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Failing after 1m33s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Failing after 1m36s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 27s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Failing after 1m42s
publish-runtime-autobump / pr-validate (pull_request) Successful in 1m2s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Failing after 1m38s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 51s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m37s
qa-review / approved (pull_request) Successful in 29s
gate-check-v3 / gate-check (pull_request) Successful in 32s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Failing after 1m36s
sop-checklist / all-items-acked (pull_request) Successful in 27s
security-review / approved (pull_request) Successful in 32s
sop-tier-check / tier-check (pull_request) Has been cancelled
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Has been cancelled
Retry trigger per infra-lead investigation.
Refs: mc#1047 CI hang
2026-05-14 21:33:15 +00:00
hongming-codex-laptop a86e3c7048 ci: avoid needs unblock bug for required checks
E2E API Smoke Test / E2E API Smoke Test (pull_request) Blocked by required conditions
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Blocked by required conditions
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Blocked by required conditions
Harness Replays / Harness Replays (pull_request) Blocked by required conditions
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Blocked by required conditions
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 9s
CI / Detect changes (pull_request) Successful in 16s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 18s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E API Smoke Test / detect-changes (pull_request) Successful in 32s
MCP Stdio Transport Regression / MCP stdio with regular-file stdout (pull_request) Successful in 1m30s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 44s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 58s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 24s
Harness Replays / detect-changes (pull_request) Successful in 36s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 50s
publish-runtime-autobump / bump-and-tag (pull_request) Has been skipped
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 32s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 13s
publish-runtime-autobump / pr-validate (pull_request) Successful in 56s
CI / Canvas (Next.js) (pull_request) Failing after 2m52s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Python Lint & Test (pull_request) Failing after 2m31s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m46s
CI / all-required (pull_request) Failing after 2m33s
gate-check-v3 / gate-check (pull_request) Successful in 18s
qa-review / approved (pull_request) Successful in 13s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Failing after 2m27s
security-review / approved (pull_request) Successful in 10s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Failing after 1m46s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m33s
sop-checklist / all-items-acked (pull_request) Successful in 15s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Failing after 1m48s
sop-tier-check / tier-check (pull_request) Successful in 17s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Failing after 1m42s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m47s
CI / Platform (Go) (pull_request) Failing after 3m42s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Failing after 1m10s
2026-05-14 14:31:49 -07:00
infra-sre f33c5bd65e ci: re-trigger fresh run after ci.yml fix
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 22s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 44s
E2E API Smoke Test / detect-changes (pull_request) Successful in 41s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 44s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 27s
Harness Replays / detect-changes (pull_request) Successful in 44s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 1m7s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 54s
publish-runtime-autobump / bump-and-tag (pull_request) Has been skipped
MCP Stdio Transport Regression / MCP stdio with regular-file stdout (pull_request) Successful in 1m45s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 35s
publish-runtime-autobump / pr-validate (pull_request) Successful in 1m9s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 57s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m38s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m21s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m51s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 2m30s
gate-check-v3 / gate-check (pull_request) Successful in 59s
qa-review / approved (pull_request) Successful in 40s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m51s
security-review / approved (pull_request) Successful in 38s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m36s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) Successful in 34s
sop-tier-check / tier-check (pull_request) Successful in 38s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m35s
CI / all-required (pull_request) Failing after 15m54s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 17s
CI / Canvas (Next.js) (pull_request) Failing after 2m6s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Platform (Go) (pull_request) Failing after 2m16s
CI / Python Lint & Test (pull_request) Failing after 2m9s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Failing after 2m5s
Harness Replays / Harness Replays (pull_request) Successful in 14s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 1m28s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 3m6s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Failing after 2m3s
2026-05-14 21:03:38 +00:00
hongming-codex-laptop 3c1a46b067 fix(ci): retry all-required status polling timeouts
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 32s
CI / Detect changes (pull_request) Successful in 1m27s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m29s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m4s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 1m11s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 1m0s
Harness Replays / detect-changes (pull_request) Successful in 39s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 19s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m26s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 2m19s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m40s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m39s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 28s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m30s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 1m1s
sop-checklist / na-declarations (pull_request) N/A: qa-review
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m44s
security-review / approved (pull_request) Successful in 26s
gate-check-v3 / gate-check (pull_request) Successful in 32s
sop-checklist / all-items-acked (pull_request) Successful in 23s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m45s
sop-tier-check / tier-check (pull_request) Successful in 33s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 1s
CI / Python Lint & Test (pull_request) Successful in 2s
Harness Replays / Harness Replays (pull_request) Successful in 12s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m13s
qa-review / approved (pull_request) Refired via /qa-recheck by hongming
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5m20s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8m38s
CI / Platform (Go) (pull_request) Successful in 16m11s
CI / Canvas (Next.js) (pull_request) Successful in 17m7s
CI / all-required (pull_request) Failing after 26m22s
CI / Canvas Deploy Reminder (pull_request) Successful in 7s
2026-05-14 13:38:23 -07:00
hongming-codex-laptop 3868143c01 ci: retrigger after reopening PR with symlink test
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 11s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 16s
E2E API Smoke Test / detect-changes (pull_request) Successful in 16s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 16s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 18s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 12s
Harness Replays / detect-changes (pull_request) Successful in 17s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 37s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 15s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 40s
qa-review / approved (pull_request) Successful in 23s
sop-checklist / na-declarations (pull_request) N/A: qa-review
gate-check-v3 / gate-check (pull_request) Successful in 34s
sop-checklist / all-items-acked (pull_request) Successful in 21s
security-review / approved (pull_request) Successful in 22s
sop-tier-check / tier-check (pull_request) Successful in 19s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m16s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m35s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m26s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m40s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 1m53s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m51s
CI / all-required (pull_request) Failing after 4m26s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 11s
CI / Python Lint & Test (pull_request) Successful in 16s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m14s
Harness Replays / Harness Replays (pull_request) Successful in 11s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 12s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m21s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 6m7s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 10m5s
CI / Platform (Go) (pull_request) Failing after 16m14s
CI / Canvas (Next.js) (pull_request) Failing after 16m18s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
2026-05-14 13:23:42 -07:00
hongming-codex-laptop f3e979b78c test(handlers): cover ListFiles symlink skip
audit-force-merge / audit (pull_request) Has been skipped
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 9s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 16s
E2E API Smoke Test / detect-changes (pull_request) Successful in 21s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 11s
Harness Replays / detect-changes (pull_request) Successful in 17s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 23s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 23s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 17s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 39s
qa-review / approved (pull_request) Successful in 24s
security-review / approved (pull_request) Successful in 26s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 30s
sop-checklist / all-items-acked (pull_request) Successful in 21s
gate-check-v3 / gate-check (pull_request) Successful in 35s
sop-tier-check / tier-check (pull_request) Successful in 18s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m19s
CI / all-required (pull_request) Failing after 1m45s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Failing after 1m45s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Failing after 1m40s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Failing after 1m40s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m43s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m49s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m52s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 9s
CI / Python Lint & Test (pull_request) Successful in 11s
Harness Replays / Harness Replays (pull_request) Successful in 8s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 11s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m29s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 6m25s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 9m31s
CI / Platform (Go) (pull_request) Failing after 17m17s
CI / Canvas (Next.js) (pull_request) Failing after 17m30s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
2026-05-14 13:17:16 -07:00
infra-sre 4ed6e36ef1 fix(handlers): skip symlinks in ListFiles WalkDir callback (OFFSEC-010)
sop-checklist / na-declarations (pull_request) N/A: qa-review
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 18s
CI / Detect changes (pull_request) Successful in 1m2s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 46s
E2E API Smoke Test / detect-changes (pull_request) Successful in 58s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m4s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 16s
Harness Replays / detect-changes (pull_request) Successful in 27s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 1m4s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 48s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 20s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m25s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m35s
qa-review / approved (pull_request) Successful in 16s
security-review / approved (pull_request) Successful in 19s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m11s
gate-check-v3 / gate-check (pull_request) Successful in 34s
sop-checklist / all-items-acked (pull_request) Successful in 21s
sop-tier-check / tier-check (pull_request) Successful in 26s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m18s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m13s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 2m35s
CI / all-required (pull_request) Failing after 5m26s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m28s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 3s
CI / Python Lint & Test (pull_request) Successful in 4s
Harness Replays / Harness Replays (pull_request) Successful in 16s
CI / Platform (Go) (pull_request) Failing after 1m16s
CI / Canvas (Next.js) (pull_request) Failing after 1m25s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E API Smoke Test / E2E API Smoke Test (pull_request) Failing after 1m32s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 1m37s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 6s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 2m3s
2026-05-14 20:12:33 +00:00
infra-sre 2d7232cf41 verify(workspace): confirm OFFSEC-010 symlink guard in collectCPConfigFiles WalkDir
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 12s
CI / Detect changes (pull_request) Successful in 24s
E2E API Smoke Test / detect-changes (pull_request) Successful in 30s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 37s
Harness Replays / detect-changes (pull_request) Successful in 25s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 16s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 42s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 41s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 39s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
gate-check-v3 / gate-check (pull_request) Successful in 7s
qa-review / approved (pull_request) Failing after 5s
security-review / approved (pull_request) Failing after 5s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m42s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m15s
sop-checklist / all-items-acked (pull_request) Successful in 10s
sop-tier-check / tier-check (pull_request) Successful in 11s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 1m47s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m27s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m44s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m56s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m48s
CI / Python Lint & Test (pull_request) Successful in 12s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 13s
Harness Replays / Harness Replays (pull_request) Successful in 8s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 16s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m39s
CI / all-required (pull_request) Failing after 15m6s
CI / Platform (Go) (pull_request) Failing after 4m12s
CI / Canvas (Next.js) (pull_request) Failing after 4m20s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 3m52s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 3m23s
2026-05-14 20:10:08 +00:00
hongming-codex-laptop 2686b09449 ci: retrigger after reopening PR
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 58s
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m2s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m2s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 56s
Harness Replays / detect-changes (pull_request) Successful in 27s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 17s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 53s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 21s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 44s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m16s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m30s
security-review / approved (pull_request) Successful in 8s
gate-check-v3 / gate-check (pull_request) Successful in 24s
qa-review / approved (pull_request) Successful in 13s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 2m5s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) Successful in 14s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m7s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 9s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 2m21s
sop-tier-check / tier-check (pull_request) Successful in 25s
CI / Python Lint & Test (pull_request) Successful in 8s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m16s
Harness Replays / Harness Replays (pull_request) Successful in 7s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 11s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m47s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m39s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 3m54s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8m34s
CI / Platform (Go) (pull_request) Successful in 12m35s
CI / Canvas (Next.js) (pull_request) Successful in 13m30s
CI / all-required (pull_request) Successful in 17m19s
CI / Canvas Deploy Reminder (pull_request) Successful in 3s
2026-05-14 13:03:49 -07:00
hongming-codex-laptop 25982862f7 fix(ci): make all-required poll required statuses
Block internal-flavored paths / Block forbidden paths (pull_request) Failing after 23s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 50s
E2E API Smoke Test / detect-changes (pull_request) Successful in 52s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m2s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 55s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 17s
Harness Replays / detect-changes (pull_request) Successful in 27s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 1m5s
Secret scan / Scan diff for credential-shaped strings (pull_request) Failing after 20s
qa-review / approved (pull_request) Successful in 17s
security-review / approved (pull_request) Successful in 19s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 42s
gate-check-v3 / gate-check (pull_request) Successful in 24s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) Successful in 12s
sop-tier-check / tier-check (pull_request) Successful in 13s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 6s
CI / Python Lint & Test (pull_request) Successful in 4s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m44s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m20s
Harness Replays / Harness Replays (pull_request) Successful in 4s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m36s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m54s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 2m6s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m0s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 7s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m33s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m35s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m10s
CI / Platform (Go) (pull_request) Failing after 5m26s
CI / Canvas (Next.js) (pull_request) Failing after 5m41s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 5m27s
CI / all-required (pull_request) Failing after 4s
2026-05-14 13:00:02 -07:00
hongming-codex-laptop 4ce3bfa3aa fix(ci): keep PR aggregate independent of deploy reminder
sop-checklist / na-declarations (pull_request) N/A: qa-review
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 31s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m10s
CI / Detect changes (pull_request) Successful in 1m12s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 53s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 49s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 50s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 17s
Harness Replays / detect-changes (pull_request) Successful in 23s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 45s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 18s
qa-review / approved (pull_request) Successful in 13s
security-review / approved (pull_request) Successful in 14s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m22s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m53s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m37s
audit-force-merge / audit (pull_request) Has been skipped
CI / Shellcheck (E2E scripts) (pull_request) Successful in 16s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 2m11s
CI / Python Lint & Test (pull_request) Successful in 16s
Harness Replays / Harness Replays (pull_request) Successful in 11s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 2m17s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 14s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m22s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m31s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m31s
sop-checklist / all-items-acked (pull_request) Successful in 13s
sop-tier-check / tier-check (pull_request) Successful in 15s
gate-check-v3 / gate-check (pull_request) Successful in 20s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 1m38s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 9m2s
CI / Platform (Go) (pull_request) Successful in 10m10s
CI / Canvas (Next.js) (pull_request) Successful in 12m29s
CI / Canvas Deploy Reminder (pull_request) Successful in 5s
CI / all-required (pull_request) Successful in 11s
2026-05-14 12:45:31 -07:00
hongming-codex-laptop c9f53a2a28 fix(ci): let canvas deploy reminder satisfy PR aggregate
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 28s
CI / Detect changes (pull_request) Successful in 1m9s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E API Smoke Test / detect-changes (pull_request) Successful in 1m24s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 1m4s
Harness Replays / detect-changes (pull_request) Successful in 20s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 51s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 14s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 44s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 27s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 13s
qa-review / approved (pull_request) Successful in 12s
gate-check-v3 / gate-check (pull_request) Successful in 15s
sop-checklist / na-declarations (pull_request) N/A: qa-review
security-review / approved (pull_request) Successful in 10s
sop-checklist / all-items-acked (pull_request) Successful in 10s
sop-tier-check / tier-check (pull_request) Successful in 11s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m31s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m15s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m47s
lint-mask-pr-atomicity / lint-mask-pr-atomicity (pull_request) Successful in 1m58s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m40s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m58s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 9s
CI / Python Lint & Test (pull_request) Successful in 11s
Harness Replays / Harness Replays (pull_request) Successful in 12s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 13s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m37s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m45s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 7m3s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 10m0s
CI / Canvas (Next.js) (pull_request) Successful in 18m39s
CI / Platform (Go) (pull_request) Successful in 19m21s
CI / Canvas Deploy Reminder (pull_request) Successful in 6s
CI / all-required (pull_request) Successful in 4s
2026-05-14 12:26:03 -07:00
hongming-codex-laptop 7b84d09de2 test: cover template symlink skip
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 43s
Harness Replays / detect-changes (pull_request) Successful in 24s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 47s
E2E API Smoke Test / detect-changes (pull_request) Successful in 51s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 45s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 23s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 55s
qa-review / approved (pull_request) Successful in 19s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 47s
gate-check-v3 / gate-check (pull_request) Successful in 36s
security-review / approved (pull_request) Refired via /security-recheck by hongming
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-tier-check / tier-check (pull_request) Successful in 22s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 10s
sop-checklist / all-items-acked (pull_request) Successful in 23s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m20s
Harness Replays / Harness Replays (pull_request) Successful in 10s
CI / Python Lint & Test (pull_request) Successful in 11s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 7s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m22s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 6m0s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5m10s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 9m35s
CI / Canvas (Next.js) (pull_request) Successful in 17m16s
CI / Platform (Go) (pull_request) Successful in 18m51s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 13s
2026-05-14 11:57:56 -07:00
infra-lead eb67db9d7f [infra-lead-agent] fix(provisioner): skip symlinks in template WalkDir (OFFSEC-010)
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 12s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 26s
E2E API Smoke Test / detect-changes (pull_request) Successful in 23s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 25s
Harness Replays / detect-changes (pull_request) Successful in 14s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 40s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 25s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 21s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 34s
qa-review / approved (pull_request) Failing after 27s
security-review / approved (pull_request) Failing after 24s
gate-check-v3 / gate-check (pull_request) Successful in 41s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) Successful in 24s
sop-tier-check / tier-check (pull_request) Successful in 23s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 6s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m14s
CI / Python Lint & Test (pull_request) Successful in 13s
Harness Replays / Harness Replays (pull_request) Successful in 8s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 11s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m19s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m19s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m45s
CI / Platform (Go) (pull_request) Failing after 8m30s
CI / Canvas (Next.js) (pull_request) Failing after 8m44s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 8m38s
CI / all-required (pull_request) Failing after 4s
filepath.WalkDir follows symlinks, which could bypass the path traversal
guard in addFile() if a symlink inside the template directory points
outside it (e.g. a symlink to ../../../etc/passwd).

Fix: add an explicit symlink check after the walkErr guard that returns
nil (skip) when d.Type()&os.ModeSymlink != 0.

The existing IsRegular() check catches non-regular non-symlink files
(devices, sockets) but symlinks are regular files (they point to
something), so they need explicit skipping.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 18:51:25 +00:00
hongming 77e511f905 ci: refire CI run
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 23s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 59s
E2E API Smoke Test / detect-changes (pull_request) Successful in 55s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 57s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 54s
Harness Replays / detect-changes (pull_request) Successful in 21s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 51s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 20s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 40s
qa-review / approved (pull_request) Successful in 21s
gate-check-v3 / gate-check (pull_request) Successful in 31s
sop-checklist / na-declarations (pull_request) N/A: qa-review
security-review / approved (pull_request) Successful in 20s
sop-checklist / all-items-acked (pull_request) Successful in 19s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m22s
sop-tier-check / tier-check (pull_request) Successful in 20s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 6s
CI / Python Lint & Test (pull_request) Successful in 6s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m27s
Harness Replays / Harness Replays (pull_request) Successful in 11s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 8s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m9s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m21s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 9m19s
CI / Canvas (Next.js) (pull_request) Successful in 14m56s
CI / Platform (Go) (pull_request) Successful in 15m8s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 5s
2026-05-14 18:30:17 +00:00
fullstack-engineer 1a4d012383 fix(provisioner): skip symlinks in CopyTemplateToContainer Walk (OFFSEC-010)
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 24s
CI / Detect changes (pull_request) Successful in 56s
E2E API Smoke Test / detect-changes (pull_request) Successful in 35s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 44s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 46s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 43s
Harness Replays / detect-changes (pull_request) Successful in 13s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 15s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 35s
qa-review / approved (pull_request) Failing after 17s
gate-check-v3 / gate-check (pull_request) Successful in 26s
security-review / approved (pull_request) Failing after 16s
sop-checklist / all-items-acked (pull_request) Successful in 18s
sop-tier-check / tier-check (pull_request) Successful in 16s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m12s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 7s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Failing after 2m10s
CI / Python Lint & Test (pull_request) Successful in 8s
CI / Platform (Go) (pull_request) Failing after 24s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m48s
Harness Replays / Harness Replays (pull_request) Successful in 6s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 8s
CI / Canvas (Next.js) (pull_request) Failing after 5m54s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 3m15s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 2m27s
CI / all-required (pull_request) Failing after 5s
filepath.Walk follows symlinks by default. A malicious org template
containing a symlink (e.g. template/.ssh → /root/.ssh) could escape
the intended directory and include arbitrary host files in the tar
archive copied into workspace containers.

Fix: skip symlinks in the Walk callback. Broken template symlinks
are a silent no-op rather than an error, matching the security-
first posture (no escalation on unexpected input).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 18:26:47 +00:00
hongming 146009af51 ci: refire CI run
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 18s
CI / Detect changes (pull_request) Successful in 36s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E API Smoke Test / detect-changes (pull_request) Successful in 30s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 34s
Harness Replays / detect-changes (pull_request) Successful in 17s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 37s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 42s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 14s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 38s
gate-check-v3 / gate-check (pull_request) Successful in 34s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m15s
sop-tier-check / tier-check (pull_request) Successful in 22s
qa-review / approved (pull_request) Refired via /qa-recheck by hongming
security-review / approved (pull_request) Refired via /security-recheck by hongming
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m53s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 8s
CI / Python Lint & Test (pull_request) Successful in 7s
Harness Replays / Harness Replays (pull_request) Successful in 5s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 11s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m53s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) acked: 7/7
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m20s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 10m39s
CI / Platform (Go) (pull_request) Successful in 14m2s
CI / Canvas (Next.js) (pull_request) Successful in 14m46s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 9s
2026-05-14 18:01:28 +00:00
hongming 3a902747c3 ci: refire CI run
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
CI / Detect changes (pull_request) Successful in 35s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
E2E API Smoke Test / detect-changes (pull_request) Successful in 28s
Harness Replays / detect-changes (pull_request) Successful in 13s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 27s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 35s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 42s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 22s
qa-review / approved (pull_request) Failing after 23s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 40s
gate-check-v3 / gate-check (pull_request) Successful in 33s
security-review / approved (pull_request) Failing after 18s
sop-checklist / all-items-acked (pull_request) Successful in 21s
sop-tier-check / tier-check (pull_request) Successful in 17s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m16s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m26s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 5s
CI / Python Lint & Test (pull_request) Successful in 6s
Harness Replays / Harness Replays (pull_request) Successful in 7s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 9s
CI / Canvas (Next.js) (pull_request) Failing after 40s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Platform (Go) (pull_request) Failing after 47s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Failing after 55s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 1m1s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 1m5s
CI / all-required (pull_request) Failing after 6s
2026-05-14 18:01:08 +00:00
hongming a50ed4169a ci: refire CI [skip review]
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 19s
E2E API Smoke Test / detect-changes (pull_request) Successful in 42s
CI / Detect changes (pull_request) Successful in 43s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 36s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
Harness Replays / detect-changes (pull_request) Successful in 22s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 45s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 44s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 14s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 42s
qa-review / approved (pull_request) Failing after 21s
gate-check-v3 / gate-check (pull_request) Failing after 33s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m18s
security-review / approved (pull_request) Failing after 17s
sop-checklist / all-items-acked (pull_request) Successful in 20s
sop-tier-check / tier-check (pull_request) Successful in 14s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m20s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 5s
CI / Python Lint & Test (pull_request) Successful in 7s
Harness Replays / Harness Replays (pull_request) Successful in 6s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 11s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m6s
CI / Platform (Go) (pull_request) Failing after 3m40s
CI / Canvas (Next.js) (pull_request) Failing after 3m57s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Failing after 3m34s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Failing after 4m6s
CI / all-required (pull_request) Failing after 6s
2026-05-14 18:00:03 +00:00
hongming-codex-laptop 7a768060e3 ci: rerun after runner disk cleanup
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 17s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
CI / Detect changes (pull_request) Successful in 48s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 41s
E2E API Smoke Test / detect-changes (pull_request) Successful in 51s
Harness Replays / detect-changes (pull_request) Successful in 15s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 16s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 47s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 41s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) Successful in 21s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 40s
sop-tier-check / tier-check (pull_request) Successful in 15s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 7s
CI / Python Lint & Test (pull_request) Successful in 8s
Harness Replays / Harness Replays (pull_request) Successful in 6s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m14s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 6s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m0s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m23s
qa-review / approved (pull_request) Refired via /qa-recheck by hongming
security-review / approved (pull_request) Refired via /security-recheck by hongming
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m49s
gate-check-v3 / gate-check (pull_request) Manual refire after stale request-changes dismissal; gate clear
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8m14s
CI / Platform (Go) (pull_request) Successful in 15m13s
CI / Canvas (Next.js) (pull_request) Successful in 15m18s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 5s
2026-05-14 10:45:43 -07:00
hongming-codex-laptop 7a614f2e3b fix: harden saas workspace provisioning config
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been skipped
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 9s
Harness Replays / detect-changes (pull_request) Successful in 14s
CI / Detect changes (pull_request) Successful in 29s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 29s
E2E API Smoke Test / detect-changes (pull_request) Successful in 32s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 36s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 47s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 26s
security-review / approved (pull_request) Failing after 25s
Harness Replays / Harness Replays (pull_request) Successful in 6s
qa-review / approved (pull_request) Failing after 26s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 44s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 5s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 8s
CI / Python Lint & Test (pull_request) Successful in 8s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m22s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m26s
gate-check-v3 / gate-check (pull_request) Successful in 13s
sop-tier-check / tier-check (pull_request) Successful in 18s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m18s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 4m38s
CI / Canvas (Next.js) (pull_request) Failing after 6m32s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Platform (Go) (pull_request) Failing after 6m47s
CI / all-required (pull_request) Failing after 2s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8m54s
sop-checklist / na-declarations (pull_request) N/A: qa-review
sop-checklist / all-items-acked (pull_request) acked: 7/7
2026-05-14 10:26:27 -07:00
24 changed files with 642 additions and 170 deletions
+131 -120
View File
@@ -133,7 +133,6 @@ jobs:
# the name match works on PRs that don't touch workspace-server/).
platform-build:
name: Platform (Go)
needs: changes
runs-on: ubuntu-latest
# mc#774 (closed 2026-05-14): Phase 4 flip of the platform-build job.
# Phase 4 (#656) originally flipped this to continue-on-error: false based on
@@ -154,29 +153,29 @@ jobs:
run:
working-directory: workspace-server
steps:
- if: needs.changes.outputs.platform != 'true'
- if: false
working-directory: .
run: echo "No platform/** changes — skipping real build steps; this job always runs to satisfy the required-check name on branch protection."
- if: needs.changes.outputs.platform == 'true'
- if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- if: needs.changes.outputs.platform == 'true'
- if: always()
uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: 'stable'
- if: needs.changes.outputs.platform == 'true'
- if: always()
run: go mod download
- if: needs.changes.outputs.platform == 'true'
- if: always()
run: go build ./cmd/server
# CLI (molecli) moved to standalone repo: git.moleculesai.app/molecule-ai/molecule-cli
- if: needs.changes.outputs.platform == 'true'
- if: always()
run: go vet ./...
- if: needs.changes.outputs.platform == 'true'
- if: always()
name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2
- if: needs.changes.outputs.platform == 'true'
- if: always()
name: Run golangci-lint
run: $(go env GOPATH)/bin/golangci-lint run --timeout 3m ./...
- if: needs.changes.outputs.platform == 'true'
- if: always()
name: Diagnostic — per-package verbose 60s
run: |
set +e
@@ -192,7 +191,7 @@ jobs:
echo "::endgroup::"
# mc#774: pre-existing continue-on-error mask; root-fix and remove, do not renew silently.
continue-on-error: true
- if: needs.changes.outputs.platform == 'true'
- if: always()
name: Run tests with race detection and coverage
# Explicit timeout: cold runner cache causes OOM kills at ~4m39s on the
# full ./... suite with race detection + coverage. A 10m per-step timeout
@@ -200,7 +199,7 @@ jobs:
# instead of OOM-killing. The job-level timeout (15m) is a backstop.
run: go test -race -timeout 10m -coverprofile=coverage.out ./...
- if: needs.changes.outputs.platform == 'true'
- if: always()
name: Per-file coverage report
# Advisory — lists every source file with its coverage so reviewers
# can see at-a-glance where gaps are. Sorted ascending so the worst
@@ -214,7 +213,7 @@ jobs:
END {for (f in s) printf "%6.1f%% %s\n", s[f]/c[f], f}' \
| sort -n
- if: needs.changes.outputs.platform == 'true'
- if: always()
name: Check coverage thresholds
# Enforces two gates from #1823 Layer 1:
# 1. Total floor (25% — ratchet plan in COVERAGE_FLOOR.md).
@@ -302,7 +301,6 @@ jobs:
# siblings — verified empirically on PR #2314).
canvas-build:
name: Canvas (Next.js)
needs: changes
runs-on: ubuntu-latest
timeout-minutes: 20
# Phase 4 (RFC #219 §1): confirmed green on main 2026-05-12.
@@ -311,20 +309,20 @@ jobs:
run:
working-directory: canvas
steps:
- if: needs.changes.outputs.canvas != 'true'
- if: false
working-directory: .
run: echo "No canvas/** changes — skipping real build steps; this job always runs to satisfy the required-check name on branch protection."
- if: needs.changes.outputs.canvas == 'true'
- if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- if: needs.changes.outputs.canvas == 'true'
- if: always()
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '22'
- if: needs.changes.outputs.canvas == 'true'
- if: always()
run: rm -f package-lock.json && npm install
- if: needs.changes.outputs.canvas == 'true'
- if: always()
run: npm run build
- if: needs.changes.outputs.canvas == 'true'
- if: always()
name: Run tests with coverage
# Coverage instrumentation is configured in canvas/vitest.config.ts
# (provider: v8, reporters: text + html + json-summary). Step 2 of
@@ -333,7 +331,7 @@ jobs:
# tracked in #1815) after the team sees what current coverage is.
run: npx vitest run --coverage
- name: Upload coverage summary as artifact
if: needs.changes.outputs.canvas == 'true' && always()
if: always()
# Pinned to v3 for Gitea act_runner v0.6 compatibility — v4+ uses
# the GHES 3.10+ artifact protocol that Gitea 1.22.x does NOT
# implement, surfacing as `GHESNotSupportedError: @actions/artifact
@@ -350,16 +348,15 @@ jobs:
# Shellcheck (E2E scripts) — required check, always runs.
shellcheck:
name: Shellcheck (E2E scripts)
needs: changes
runs-on: ubuntu-latest
# Phase 4 (RFC #219 §1): confirmed green on main 2026-05-12.
continue-on-error: false
steps:
- if: needs.changes.outputs.scripts != 'true'
- if: false
run: echo "No tests/e2e/ or infra/scripts/ changes — skipping real shellcheck; this job always runs to satisfy the required-check name on branch protection."
- if: needs.changes.outputs.scripts == 'true'
- if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- if: needs.changes.outputs.scripts == 'true'
- if: always()
name: Run shellcheck on tests/e2e/*.sh and infra/scripts/*.sh
# shellcheck is pre-installed on ubuntu-latest runners (via apt).
# infra/scripts/ is included because setup.sh + nuke.sh gate the
@@ -370,16 +367,16 @@ jobs:
find tests/e2e infra/scripts -type f -name '*.sh' -print0 \
| xargs -0 shellcheck --severity=warning
- if: needs.changes.outputs.scripts == 'true'
- if: always()
name: Lint cleanup-trap hygiene (RFC #2873)
run: bash tests/e2e/lint_cleanup_traps.sh
- if: needs.changes.outputs.scripts == 'true'
- if: always()
name: Run E2E bash unit tests (no live infra)
run: |
bash tests/e2e/test_model_slug.sh
- if: needs.changes.outputs.scripts == 'true'
- if: always()
name: Test ECR promote-tenant-image script (mock-driven, no live infra)
# Covers scripts/promote-tenant-image.sh — the codified
# :staging-latest → :latest ECR promote + tenant fleet redeploy
@@ -389,7 +386,7 @@ jobs:
run: |
bash scripts/test-promote-tenant-image.sh
- if: needs.changes.outputs.scripts == 'true'
- if: always()
name: Shellcheck promote-tenant-image script
# scripts/ is excluded from the bulk shellcheck pass above (legacy
# SC3040/SC3043 cleanup pending). Run shellcheck explicitly on
@@ -403,18 +400,15 @@ jobs:
canvas-deploy-reminder:
name: Canvas Deploy Reminder
runs-on: ubuntu-latest
# mc#774 root-fix: added job-level `if:` so ci-required-drift.py's
# ci_job_names() detects this as github.ref-gated and skips it from F1.
# The step-level exit 0 handles the "not main push" case; the job-level
# `if:` makes the gating explicit so the drift script sees it.
# continue-on-error removed (was mc#774 mask): step exits 0 when not applicable.
needs: [changes, canvas-build]
if: ${{ github.ref == 'refs/heads/main' }}
# This job must run on PRs because all-required needs it. The step exits
# 0 when it is not a main push, giving branch protection a green no-op
# instead of a skipped/missing required dependency.
needs: canvas-build
steps:
- name: Write deploy reminder to step summary
env:
COMMIT_SHA: ${{ github.sha }}
CANVAS_CHANGED: ${{ needs.changes.outputs.canvas }}
CANVAS_CHANGED: "true"
EVENT_NAME: ${{ github.event_name }}
REF_NAME: ${{ github.ref }}
# github.server_url resolves via the workflow-level env override
@@ -459,7 +453,6 @@ jobs:
# Python Lint & Test — required check, always runs.
python-lint:
name: Python Lint & Test
needs: changes
runs-on: ubuntu-latest
# Phase 4 (RFC #219 §1): confirmed green on main 2026-05-12.
continue-on-error: false
@@ -469,25 +462,25 @@ jobs:
run:
working-directory: workspace
steps:
- if: needs.changes.outputs.python != 'true'
- if: false
working-directory: .
run: echo "No workspace/** changes — skipping real lint+test; this job always runs to satisfy the required-check name on branch protection."
- if: needs.changes.outputs.python == 'true'
- if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- if: needs.changes.outputs.python == 'true'
- if: always()
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'
cache: pip
cache-dependency-path: workspace/requirements.txt
- if: needs.changes.outputs.python == 'true'
- if: always()
run: pip install -r requirements.txt pytest pytest-asyncio pytest-cov sqlalchemy>=2.0.0
# Coverage flags + fail-under floor moved into workspace/pytest.ini
# (issue #1817) so local `pytest` and CI use identical config.
- if: needs.changes.outputs.python == 'true'
- if: always()
run: python -m pytest --tb=short
- if: needs.changes.outputs.python == 'true'
- if: always()
name: Per-file critical-path coverage (MCP / inbox / auth)
# MCP-critical Python files have a per-file floor on top of the
# 86% total floor in pytest.ini. See issue #2790 for full rationale.
@@ -552,86 +545,104 @@ jobs:
# red silently merged through. See internal#286 for the three concrete
# tonight-of-2026-05-11 incidents that prompted the emergency bump.
#
# Three properties of this job each close a failure mode:
# This job deliberately has no `needs:`. Gitea 1.22/act_runner can mark a
# job-level `if: always()` + `needs:` sentinel as skipped before upstream
# jobs settle, leaving branch protection with a permanent pending
# `CI / all-required` context. Instead, this independent sentinel polls the
# required commit-status contexts for this SHA and fails if any fail, skip,
# or never emit.
#
# 1. `if: always()` — runs even when an upstream fails. Without it the
# sentinel is `skipped` and protection treats that as missing → merge
# ungated.
# canvas-deploy-reminder is intentionally NOT included in all-required.needs.
# It is an informational main-push reminder, not a PR quality gate. Keeping
# it in this dependency list lets a skipped reminder skip the required
# sentinel before the `always()` guard can emit a branch-protection status.
#
# 2. Assertion is `result == "success"` per dep, NOT `!= "failure"`.
# A `skipped` upstream (job gated by `if:` evaluating false, matrix
# entry that couldn't run) must NOT silently pass through.
# `skipped`-as-green is exactly the failure mode this gate closes.
#
# 3. `needs:` is the canonical list of "what counts as required."
# status_check_contexts will reference only `ci/all-required` (Step 5
# follow-up — branch-protection PATCH is Owners-tier per
# `feedback_never_admin_merge_bypass`, separate PR); a new job is
# added simply by listing it in `needs:` here.
# `.gitea/workflows/ci-required-drift.yml` files a [ci-drift] issue
# hourly if this list diverges from status_check_contexts or from
# audit-force-merge.yml's REQUIRED_CHECKS env (RFC §4 + §6).
#
# canvas-deploy-reminder IS now included in all-required.needs (mc#958 root-fix):
# added job-level `if: github.ref == 'refs/heads/main'` so ci-required-drift.py's
# ci_job_names() detects it as github.ref-gated and skips it from F1.
# The step-level `if: ... || REF_NAME != refs/heads/main` exits 0 when not main,
# so the job succeeds (not skipped) on non-main pushes — sentinel treats as green.
#
# Phase 3 (RFC #219 §1) safety: underlying build jobs carry
# continue-on-error: true so their failures are masked to null (2026-05-12: re-enabled mc#774 interim)
# (Gitea suppresses status reporting for CoE jobs). This sentinel
# runs with continue-on-error: false so it always reports its
# result to the API — without this, the required-status entry
# (CI / all-required (pull_request)) is never created, which
# blocks PR merges. When Phase 3 ends, flip underlying jobs to
# continue-on-error: false; this sentinel can then be flipped to
# continue-on-error: true if a Phase-4 regression requires it.
continue-on-error: false
runs-on: ubuntu-latest
timeout-minutes: 1
needs:
- changes
- platform-build
- canvas-build
- shellcheck
- python-lint
- canvas-deploy-reminder
if: ${{ always() }}
timeout-minutes: 45
steps:
- name: Assert every required dependency succeeded
- name: Wait for required CI contexts
env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
API_ROOT: ${{ github.server_url }}/api/v1
REPOSITORY: ${{ github.repository }}
COMMIT_SHA: ${{ github.sha }}
EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail
# `needs.*.result` is one of: success | failure | cancelled | skipped | null.
# We assert success per dep (not != failure) — see RFC §2 reasoning above.
# Null results are skipped: they come from Phase 3 (continue-on-error: true
# suppresses status) or from jobs still in-flight. The sentinel succeeds
# rather than blocking PRs on Phase 3 noise.
results='${{ toJSON(needs) }}'
echo "$results"
echo "$results" | python3 -c '
import json, sys
ns = json.load(sys.stdin)
# Phase 3 masked: jobs with continue-on-error: true may report "failure"
# Remove when mc#774 handler test failures are resolved.
PHASE3_MASKED = {"platform-build"}
# Exclude null (Phase 3 suppressed / in-flight) from the bad list.
bad = [(k, v.get("result")) for k, v in ns.items()
if v.get("result") not in ("success", None, "cancelled", "skipped") and k not in PHASE3_MASKED]
if bad:
print(f"FAIL: jobs not green:", file=sys.stderr)
for k, r in bad:
print(f" - {k}: {r}", file=sys.stderr)
sys.exit(1)
pending = [(k, v.get("result")) for k, v in ns.items()
if v.get("result") is None]
cancelled = [(k, v.get("result")) for k, v in ns.items()
if v.get("result") == "cancelled"]
if pending:
print(f"WARN: {len(pending)} job(s) still in-flight (result=null): " +
", ".join(k for k, _ in pending), file=sys.stderr)
if cancelled:
print(f"INFO: {len(cancelled)} job(s) masked by continue-on-error: " +
", ".join(k for k, _ in cancelled), file=sys.stderr)
print(f"OK: all {len(ns)} required jobs succeeded (or Phase-3 suppressed)")
'
python3 - <<'PY'
import json
import os
import sys
import time
import urllib.error
import urllib.request
token = os.environ["GITEA_TOKEN"]
api_root = os.environ["API_ROOT"].rstrip("/")
repo = os.environ["REPOSITORY"]
sha = os.environ["COMMIT_SHA"]
event = os.environ["EVENT_NAME"]
required = [
f"CI / Detect changes ({event})",
f"CI / Platform (Go) ({event})",
f"CI / Canvas (Next.js) ({event})",
f"CI / Shellcheck (E2E scripts) ({event})",
f"CI / Python Lint & Test ({event})",
]
terminal_bad = {"failure", "error"}
deadline = time.time() + 40 * 60
last_summary = None
def fetch_statuses():
statuses = []
for page in range(1, 6):
url = f"{api_root}/repos/{repo}/commits/{sha}/statuses?page={page}&limit=100"
req = urllib.request.Request(url, headers={"Authorization": f"token {token}"})
with urllib.request.urlopen(req, timeout=10) as resp:
chunk = json.load(resp)
if not chunk:
break
statuses.extend(chunk)
latest = {}
for item in statuses:
ctx = item.get("context")
if not ctx:
continue
prev = latest.get(ctx)
if prev is None or (item.get("updated_at") or item.get("created_at") or "") >= (prev.get("updated_at") or prev.get("created_at") or ""):
latest[ctx] = item
return latest
while True:
try:
latest = fetch_statuses()
except (TimeoutError, OSError, urllib.error.URLError) as exc:
if time.time() >= deadline:
print(f"FAIL: status polling did not recover before deadline: {exc}", file=sys.stderr)
sys.exit(1)
print(f"WARN: status poll failed, retrying: {exc}", flush=True)
time.sleep(15)
continue
states = {ctx: (latest.get(ctx) or {}).get("status") or (latest.get(ctx) or {}).get("state") or "missing" for ctx in required}
summary = ", ".join(f"{ctx}={state}" for ctx, state in states.items())
if summary != last_summary:
print(summary, flush=True)
last_summary = summary
bad = {ctx: state for ctx, state in states.items() if state in terminal_bad}
if bad:
print("FAIL: required CI context failed:", file=sys.stderr)
for ctx, state in bad.items():
desc = (latest.get(ctx) or {}).get("description") or ""
print(f" - {ctx}: {state} {desc}", file=sys.stderr)
sys.exit(1)
if all(state == "success" for state in states.values()):
print(f"OK: all {len(required)} required CI contexts succeeded")
sys.exit(0)
if time.time() >= deadline:
print("FAIL: timed out waiting for required CI contexts:", file=sys.stderr)
for ctx, state in states.items():
print(f" - {ctx}: {state}", file=sys.stderr)
sys.exit(1)
time.sleep(15)
PY
+27 -11
View File
@@ -83,25 +83,41 @@ jobs:
REPO: ${{ github.repository }}
run: |
set -euo pipefail
# Fetch all open PRs and run gate-check on each
# socket.setdefaulttimeout(15): defence-in-depth for missing SOP_TIER_CHECK_TOKEN.
# gate_check.py uses timeout=15 on every urlopen call; this catches the
# inline Python polling loop too (issue #603).
# Fetch all open PRs and run gate-check on each. This scheduled
# refresher is advisory; a transient Gitea list timeout must not turn
# main red. PR-specific gate-check runs still use normal failure
# semantics.
pr_numbers=$(python3 <<'PY'
import json
import os
import socket
import sys
import time
import urllib.error
import urllib.request
socket.setdefaulttimeout(15)
socket.setdefaulttimeout(30)
token = os.environ["GITEA_TOKEN"]
repo = os.environ["REPO"]
req = urllib.request.Request(
f"https://git.moleculesai.app/api/v1/repos/{repo}/pulls?state=open&limit=100",
headers={"Authorization": f"token {token}", "Accept": "application/json"},
)
with urllib.request.urlopen(req) as r:
prs = json.loads(r.read())
url = f"https://git.moleculesai.app/api/v1/repos/{repo}/pulls?state=open&limit=100"
last_error = None
for attempt in range(1, 4):
req = urllib.request.Request(
url,
headers={"Authorization": f"token {token}", "Accept": "application/json"},
)
try:
with urllib.request.urlopen(req, timeout=30) as r:
prs = json.loads(r.read())
break
except (TimeoutError, OSError, urllib.error.URLError, urllib.error.HTTPError) as exc:
last_error = exc
print(f"warning: PR list fetch attempt {attempt}/3 failed: {exc}", file=sys.stderr)
if attempt < 3:
time.sleep(2 * attempt)
else:
print(f"warning: skipped scheduled gate-check refresh; failed to list open PRs after 3 attempts: {last_error}", file=sys.stderr)
raise SystemExit(0)
for pr in prs:
print(pr["number"])
PY
@@ -86,7 +86,11 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
# A full-history checkout can exceed the runner's quiet/startup
# window before the path filter emits logs. Fetch the common push
# case cheaply; the script below fetches the exact BASE SHA if it is
# not present in the shallow checkout.
fetch-depth: 2
- id: filter
# Inline replacement for dorny/paths-filter — see e2e-api.yml.
run: |
@@ -93,7 +93,7 @@ jobs:
lint:
name: lint-continue-on-error-tracking
runs-on: ubuntu-latest
timeout-minutes: 10
timeout-minutes: 20
# Phase 3 (RFC #219 §1): surface masked defects without blocking
# PRs. Pre-existing continue-on-error: true directives on main
# all violate this lint at first — intentional. Flip to false
@@ -18,6 +18,10 @@ permissions:
pull-requests: read
statuses: write
concurrency:
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.event.issue.number || github.ref }}
cancel-in-progress: true
jobs:
dispatch:
runs-on: ubuntu-latest
+1 -1
View File
@@ -70,7 +70,7 @@ name: sop-checklist
# Cancel any in-progress runs for the same PR to prevent
# stale runs from overwriting newer status contexts.
concurrency:
group: ${{ github.repository }}-${{ github.event.pull_request.number }}
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.event.pull_request.number || github.event.issue.number || github.ref }}
cancel-in-progress: true
# bp-required: yes ← emits sop-checklist / all-items-acked (pull_request)
+4
View File
@@ -61,6 +61,10 @@ on:
pull_request_review:
types: [submitted, dismissed, edited]
concurrency:
group: ${{ github.repository }}-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
tier-check:
runs-on: ubuntu-latest
+6 -4
View File
@@ -12,6 +12,7 @@ import { useEffect, useState } from "react";
import { api } from "@/lib/api";
import { type Template } from "@/lib/deploy-preflight";
import { isSaaSTenant } from "@/lib/tenant";
import { tierCode } from "./palette";
import { MOBILE_FONT_MONO, MOBILE_FONT_SANS, type MobilePalette, usePalette } from "./palette";
@@ -26,6 +27,7 @@ const TIER_LABEL: Record<"T1" | "T2" | "T3" | "T4", string> = {
export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => void }) {
const p = usePalette(dark);
const isSaaS = isSaaSTenant();
const [templates, setTemplates] = useState<Template[]>([]);
const [loadingTemplates, setLoadingTemplates] = useState(true);
const [tplId, setTplId] = useState<string | null>(null);
@@ -43,7 +45,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v
setTemplates(list);
if (list.length > 0) {
setTplId(list[0].id);
setTier(tierCode(list[0].tier));
setTier(isSaaS ? "T4" : tierCode(list[0].tier));
}
})
.catch(() => {
@@ -55,7 +57,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v
return () => {
cancelled = true;
};
}, []);
}, [isSaaS]);
const handleSpawn = async () => {
if (busy || !tplId) return;
@@ -67,7 +69,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v
await api.post<{ id: string }>("/workspaces", {
name: (name.trim() || chosen.name),
template: chosen.id,
tier: Number(tier.slice(1)),
tier: isSaaS ? 4 : Number(tier.slice(1)),
canvas: {
x: Math.random() * 400 + 100,
y: Math.random() * 300 + 100,
@@ -203,7 +205,7 @@ export function MobileSpawn({ dark, onClose }: { dark: boolean; onClose: () => v
>
{templates.map((t) => {
const on = tplId === t.id;
const tCode = tierCode(t.tier);
const tCode = isSaaS ? "T4" : tierCode(t.tier);
return (
<button
key={t.id}
+2 -1
View File
@@ -8,6 +8,7 @@ import {
type PreflightResult,
type Template,
} from "@/lib/deploy-preflight";
import { isSaaSTenant } from "@/lib/tenant";
import { MissingKeysModal } from "@/components/MissingKeysModal";
/**
@@ -105,7 +106,7 @@ export function useTemplateDeploy(
const ws = await api.post<{ id: string }>("/workspaces", {
name: template.name,
template: template.id,
tier: template.tier,
tier: isSaaSTenant() ? 4 : template.tier,
canvas: coords,
...(model ? { model } : {}),
});
@@ -63,6 +63,31 @@ func TestSessionSearchReturnsActivityAndMemory(t *testing.T) {
}
}
func TestSessionSearch_DBError(t *testing.T) {
mock := setupTestDB(t)
setupTestRedis(t)
broadcaster := newTestBroadcaster()
handler := NewActivityHandler(broadcaster)
mock.ExpectQuery("WITH session_items AS").
WillReturnError(context.DeadlineExceeded)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request = httptest.NewRequest("GET", "/workspaces/ws-123/session-search?q=test", bytes.NewBufferString(""))
c.Request.Header.Set("Content-Type", "application/json")
c.Params = gin.Params{{Key: "id", Value: "ws-123"}}
handler.SessionSearch(c)
if w.Code != http.StatusInternalServerError {
t.Errorf("expected 500 on DB error, got %d", w.Code)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unmet sqlmock expectations: %v", err)
}
}
// ---------- Activity List source filter ----------
func TestActivityList_SourceCanvas(t *testing.T) {
@@ -543,6 +543,33 @@ func TestDelegationRecord_RejectsInvalidUUID(t *testing.T) {
}
}
func TestDelegationRecord_DBInsertFails(t *testing.T) {
mock := setupTestDB(t)
setupTestRedis(t)
broadcaster := newTestBroadcaster()
wh := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir())
h := NewDelegationHandler(wh, broadcaster)
mock.ExpectExec("INSERT INTO activity_logs").
WillReturnError(fmt.Errorf("connection refused"))
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Params = gin.Params{{Key: "id", Value: "550e8400-e29b-41d4-a716-446655440000"}}
body := `{"target_id":"550e8400-e29b-41d4-a716-446655440001","task":"hello","delegation_id":"del-xyz"}`
c.Request = httptest.NewRequest("POST", "/delegations/record", bytes.NewBufferString(body))
c.Request.Header.Set("Content-Type", "application/json")
h.Record(c)
if w.Code != http.StatusInternalServerError {
t.Errorf("expected 500 on DB insert failure, got %d", w.Code)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unmet expectations: %v", err)
}
}
func TestDelegationUpdateStatus_CompletedInsertsResultRow(t *testing.T) {
mock := setupTestDB(t)
setupTestRedis(t)
@@ -646,8 +646,12 @@ const externalOpenClawTemplate = `# OpenClaw MCP config — outbound tool path.
# external machine today, pair with the Python SDK tab.
# 1. Install openclaw CLI + the workspace runtime wheel:
# The version pin (>=0.1.999) ensures the "molecule-mcp" console
# script is present — it is what keeps the workspace ALIVE on canvas
# (register-on-startup + 20s heartbeat). Older versions only ship
# a2a_mcp_server which does not heartbeat.
npm install -g openclaw@latest
pip install molecule-ai-workspace-runtime
pip install "molecule-ai-workspace-runtime>=0.1.999"
# 2. Onboard openclaw against your model provider (one-time setup).
# --non-interactive needs an explicit --provider + --model so it
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"regexp"
@@ -85,8 +86,11 @@ func TestInstructionsList_ByWorkspaceID(t *testing.T) {
if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil {
t.Fatalf("invalid JSON: %v", err)
}
if len(result) != 0 {
t.Fatalf("expected 0 instructions, got %d", len(result))
if len(result) != 2 {
t.Fatalf("expected 2 instructions, got %d", len(result))
}
if result[0].Scope != "global" || result[1].Scope != "workspace" {
t.Fatalf("expected global then workspace instructions, got %#v", result)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet expectations: %v", err)
@@ -215,8 +219,8 @@ func TestInstructionsHandler_Create_Success(t *testing.T) {
if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil {
t.Fatalf("response not valid JSON: %v", err)
}
if out["id"] != "new-inst-1" {
t.Errorf("expected id new-inst-1, got %s", out["id"])
if out["id"] != "new-inst-id" {
t.Errorf("expected id new-inst-id, got %s", out["id"])
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unmet expectations: %v", err)
@@ -287,7 +287,7 @@ func TestRenderCategoryRoutingYAML_StableOrdering(t *testing.T) {
if ai <= 0 || zi <= 0 || mi <= 0 {
t.Fatalf("could not locate all keys in output: %s", out)
}
if !(ai < mi && mi < zi) {
if ai >= mi || mi >= zi {
t.Errorf("keys not sorted: alpha=%d middle=%d zebra=%d, output:\n%s", ai, mi, zi, out)
}
}
@@ -186,11 +186,16 @@ func (h *TemplatesHandler) List(c *gin.Context) {
model = raw.RuntimeConfig.Model
}
tier := raw.Tier
if h.wh != nil && h.wh.IsSaaS() {
tier = h.wh.DefaultTier()
}
templates = append(templates, templateSummary{
ID: id,
Name: raw.Name,
Description: raw.Description,
Tier: raw.Tier,
Tier: tier,
Runtime: raw.Runtime,
Model: model,
Models: raw.RuntimeConfig.Models,
@@ -340,6 +345,11 @@ func (h *TemplatesHandler) ListFiles(c *gin.Context) {
if err != nil || path == walkRoot {
return nil
}
// Skip symlinks to prevent path traversal via malicious symlinks
// inside the workspace config directory (OFFSEC-010).
if info.Mode()&os.ModeSymlink != 0 {
return nil
}
rel, _ := filepath.Rel(walkRoot, path)
// Enforce depth limit
if strings.Count(rel, string(filepath.Separator))+1 > depth {
@@ -847,6 +847,58 @@ func TestListFiles_FallbackToHost_WithTemplate(t *testing.T) {
}
}
func TestListFiles_FallbackToHost_SkipsSymlinks(t *testing.T) {
mock := setupTestDB(t)
setupTestRedis(t)
tmpDir := t.TempDir()
tmplDir := filepath.Join(tmpDir, "test-agent")
if err := os.MkdirAll(tmplDir, 0755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmplDir, "config.yaml"), []byte("name: Test Agent\n"), 0644); err != nil {
t.Fatal(err)
}
secret := filepath.Join(t.TempDir(), "secret.txt")
if err := os.WriteFile(secret, []byte("do-not-list"), 0600); err != nil {
t.Fatal(err)
}
if err := os.Symlink(secret, filepath.Join(tmplDir, "leaked-secret")); err != nil {
t.Fatal(err)
}
handler := NewTemplatesHandler(tmpDir, nil, nil)
mock.ExpectQuery(`SELECT name, COALESCE\(instance_id, ''\), COALESCE\(runtime, ''\) FROM workspaces WHERE id =`).
WithArgs("ws-tmpl").
WillReturnRows(sqlmock.NewRows([]string{"name", "instance_id", "runtime"}).AddRow("Test Agent", "", ""))
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Params = gin.Params{{Key: "id", Value: "ws-tmpl"}}
c.Request = httptest.NewRequest("GET", "/workspaces/ws-tmpl/files", nil)
handler.ListFiles(c)
if w.Code != http.StatusOK {
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
}
var resp []map[string]interface{}
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatal(err)
}
for _, file := range resp {
if file["path"] == "leaked-secret" {
t.Fatalf("symlink should not be listed: %#v", resp)
}
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unmet sqlmock expectations: %v", err)
}
}
// ==================== GET /workspaces/:id/files/*path ====================
func TestReadFile_PathTraversal(t *testing.T) {
@@ -1200,4 +1252,3 @@ func TestCWE78_DeleteFile_TraversalVariants(t *testing.T) {
})
}
}
@@ -161,15 +161,14 @@ func (h *WorkspaceHandler) Create(c *gin.Context) {
id := uuid.New().String()
awarenessNamespace := workspaceAwarenessNamespace(id)
if payload.Tier == 0 {
// SaaS-aware default. SaaS → T4 (full host access; each
// workspace runs on its own sibling EC2 so the tier boundary
// is a Docker resource limit on the only container present —
// no neighbour to protect from). Self-hosted → T3 (read-write
// workspace mount + Docker daemon access, most templates'
// baseline). Lower tiers (T1 sandboxed, T2 standard) remain
// explicit opt-ins for low-trust agents. Matches the canvas
// CreateWorkspaceDialog defaults so the API and the UI agree.
if h.IsSaaS() {
// SaaS hard gate: every hosted workspace gets its own sibling
// EC2 instance, so T4 is the only meaningful runtime boundary.
// Do not trust stale clients/templates that still send T1/T2/T3.
payload.Tier = 4
} else if payload.Tier == 0 {
// Self-hosted default remains T3. Lower tiers (T1 sandboxed,
// T2 standard) stay explicit opt-ins for low-trust local agents.
payload.Tier = h.DefaultTier()
}
@@ -15,6 +15,7 @@ import (
"github.com/Molecule-AI/molecule-monorepo/platform/internal/models"
"github.com/Molecule-AI/molecule-monorepo/platform/internal/provisioner"
"github.com/Molecule-AI/molecule-monorepo/platform/internal/wsauth"
"gopkg.in/yaml.v3"
)
// logProvisionPanic is the deferred recover at the top of every provision
@@ -472,9 +473,10 @@ func configDirName(workspaceID string) string {
// runtime means bumping both this list and the Docker image tags.
// knownRuntimes is populated from manifest.json at service init (see
// runtime_registry.go). The package init order is:
// 1. var knownRuntimes = fallbackRuntimes
// 2. init() calls initKnownRuntimes() which replaces it if
// manifest.json is readable.
// 1. var knownRuntimes = fallbackRuntimes
// 2. init() calls initKnownRuntimes() which replaces it if
// manifest.json is readable.
//
// The fallback matters for unit tests that don't mount the manifest.
//
// "external" is a first-class runtime that intentionally does NOT
@@ -539,6 +541,9 @@ func (h *WorkspaceHandler) ensureDefaultConfig(workspaceID string, payload model
// org_import.go; consolidating prevents silent drift.
model = models.DefaultModel(runtime)
}
if runtime == "claude-code" {
model = normalizeClaudeCodeModel(model)
}
// Sanitize name/role/model for YAML safety — always double-quote so
// a crafted value with a newline or colon can't terminate the scalar
@@ -554,6 +559,11 @@ func (h *WorkspaceHandler) ensureDefaultConfig(workspaceID string, payload model
quoteModel := yamlQuote(model)
configYAML := fmt.Sprintf("name: %s\ndescription: %s\nversion: 1.0.0\ntier: %d\nruntime: %s\n",
quoteName, quoteRole, payload.Tier, runtime)
if runtime == "claude-code" {
if providersYAML := h.defaultTemplateProvidersYAML(runtime); providersYAML != "" {
configYAML += providersYAML + "\n"
}
}
// Model always at top level — config.py reads raw["model"] for all runtimes.
configYAML += fmt.Sprintf("model: %s\n", quoteModel)
@@ -563,7 +573,11 @@ func (h *WorkspaceHandler) ensureDefaultConfig(workspaceID string, payload model
// and preflight already validates that the env vars are present before
// the agent loop starts. Hardcoding token names here caused #1028
// (expired CLAUDE_CODE_OAUTH_TOKEN baked into config.yaml).
configYAML += "runtime_config:\n timeout: 0\n"
configYAML += "runtime_config:\n"
if runtime == "claude-code" {
configYAML += fmt.Sprintf(" model: %s\n", quoteModel)
}
configYAML += " timeout: 0\n"
files["config.yaml"] = []byte(configYAML)
@@ -571,6 +585,60 @@ func (h *WorkspaceHandler) ensureDefaultConfig(workspaceID string, payload model
return files
}
func normalizeClaudeCodeModel(model string) string {
model = strings.TrimSpace(model)
if before, after, ok := strings.Cut(model, "/"); ok && before != "" && after != "" {
return after
}
return model
}
func (h *WorkspaceHandler) defaultTemplateProvidersYAML(runtime string) string {
if h.configsDir == "" {
return ""
}
templateName := runtime + "-default"
templatePath, err := resolveInsideRoot(h.configsDir, templateName)
if err != nil {
log.Printf("Provisioner: default template providers skipped for runtime %s: %v", runtime, err)
return ""
}
data, err := os.ReadFile(filepath.Join(templatePath, "config.yaml"))
if err != nil {
return ""
}
var root yaml.Node
if err := yaml.Unmarshal(data, &root); err != nil {
log.Printf("Provisioner: default template providers skipped for runtime %s: invalid YAML: %v", runtime, err)
return ""
}
if len(root.Content) == 0 || root.Content[0].Kind != yaml.MappingNode {
return ""
}
mapping := root.Content[0]
for i := 0; i+1 < len(mapping.Content); i += 2 {
if mapping.Content[i].Value != "providers" {
continue
}
out := yaml.Node{
Kind: yaml.MappingNode,
Content: []*yaml.Node{
{Kind: yaml.ScalarNode, Value: "providers"},
mapping.Content[i+1],
},
}
encoded, err := yaml.Marshal(&out)
if err != nil {
log.Printf("Provisioner: default template providers skipped for runtime %s: marshal failed: %v", runtime, err)
return ""
}
return strings.TrimRight(string(encoded), "\n")
}
return ""
}
// deriveProviderFromModelSlug maps a hermes-agent model slug prefix to
// its provider name — a Go translation of the case statement in
// workspace-configs-templates/hermes/scripts/derive-provider.sh that we
@@ -261,6 +261,67 @@ func TestEnsureDefaultConfig_ClaudeCode(t *testing.T) {
}
}
func TestEnsureDefaultConfig_ClaudeCodeCopiesProviderRegistry(t *testing.T) {
broadcaster := newTestBroadcaster()
configsDir := t.TempDir()
templateDir := filepath.Join(configsDir, "claude-code-default")
if err := os.MkdirAll(templateDir, 0o755); err != nil {
t.Fatalf("mkdir template: %v", err)
}
if err := os.WriteFile(filepath.Join(templateDir, "config.yaml"), []byte(`
name: Claude Code Agent
runtime: claude-code
providers:
- name: anthropic-oauth
auth_mode: oauth
model_aliases: [sonnet]
auth_env: [CLAUDE_CODE_OAUTH_TOKEN]
- name: minimax
auth_mode: third_party_anthropic_compat
model_prefixes: [minimax-]
base_url: https://api.minimax.io/anthropic
auth_env: [MINIMAX_API_KEY, ANTHROPIC_AUTH_TOKEN]
runtime_config:
model: sonnet
`), 0o644); err != nil {
t.Fatalf("write template: %v", err)
}
handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", configsDir)
files := handler.ensureDefaultConfig("ws-code-123", models.CreateWorkspacePayload{
Name: "Code Agent",
Tier: 4,
Runtime: "claude-code",
Model: "minimax/MiniMax-M2.7",
})
var parsed struct {
Model string `yaml:"model"`
Providers []struct {
Name string `yaml:"name"`
ModelPrefixes []string `yaml:"model_prefixes"`
} `yaml:"providers"`
RuntimeConfig struct {
Model string `yaml:"model"`
} `yaml:"runtime_config"`
}
if err := yaml.Unmarshal(files["config.yaml"], &parsed); err != nil {
t.Fatalf("generated YAML invalid: %v\n%s", err, files["config.yaml"])
}
if parsed.Model != "MiniMax-M2.7" {
t.Fatalf("top-level model = %q, want MiniMax-M2.7\n%s", parsed.Model, files["config.yaml"])
}
if parsed.RuntimeConfig.Model != "MiniMax-M2.7" {
t.Fatalf("runtime_config.model = %q, want MiniMax-M2.7\n%s", parsed.RuntimeConfig.Model, files["config.yaml"])
}
if len(parsed.Providers) != 2 {
t.Fatalf("providers len = %d, want 2\n%s", len(parsed.Providers), files["config.yaml"])
}
if parsed.Providers[1].Name != "minimax" || len(parsed.Providers[1].ModelPrefixes) != 1 || parsed.Providers[1].ModelPrefixes[0] != "minimax-" {
t.Fatalf("minimax provider registry not preserved: %+v\n%s", parsed.Providers, files["config.yaml"])
}
}
func TestEnsureDefaultConfig_CustomModel(t *testing.T) {
broadcaster := newTestBroadcaster()
handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir())
@@ -410,6 +410,44 @@ func TestWorkspaceCreate_DefaultsApplied(t *testing.T) {
}
}
func TestWorkspaceCreate_SaaSHardForcesTier4(t *testing.T) {
mock := setupTestDB(t)
setupTestRedis(t)
broadcaster := newTestBroadcaster()
handler := NewWorkspaceHandler(broadcaster, nil, "http://localhost:8080", t.TempDir())
handler.SetCPProvisioner(&trackingCPProv{})
mock.ExpectBegin()
mock.ExpectExec("INSERT INTO workspaces").
WithArgs(sqlmock.AnyArg(), "SaaS External Agent", nil, 4, "external", sqlmock.AnyArg(), (*string)(nil), nil, "none", (*int64)(nil), models.DefaultMaxConcurrentTasks, "push").
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectCommit()
mock.ExpectExec("INSERT INTO canvas_layouts").
WithArgs(sqlmock.AnyArg(), float64(0), float64(0)).
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectExec("INSERT INTO structure_events").
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectExec("UPDATE workspaces SET url").
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectExec("INSERT INTO structure_events").
WillReturnResult(sqlmock.NewResult(0, 1))
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
body := `{"name":"SaaS External Agent","runtime":"external","external":true,"url":"https://example.com/agent","tier":2}`
c.Request = httptest.NewRequest("POST", "/workspaces", bytes.NewBufferString(body))
c.Request.Header.Set("Content-Type", "application/json")
handler.Create(c)
if w.Code != http.StatusCreated {
t.Errorf("expected status 201, got %d: %s", w.Code, w.Body.String())
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unmet sqlmock expectations: %v", err)
}
}
// TestWorkspaceCreate_WithSecrets_Persists asserts that secrets in the create
// payload are written to workspace_secrets inside the same transaction as the
// workspace row, and that the handler returns 201.
@@ -158,6 +158,7 @@ type cpProvisionRequest struct {
Tier int `json:"tier"`
PlatformURL string `json:"platform_url"`
Env map[string]string `json:"env"`
ConfigFiles map[string]string `json:"config_files,omitempty"`
}
type cpProvisionResponse struct {
@@ -181,6 +182,11 @@ func (p *CPProvisioner) Start(ctx context.Context, cfg WorkspaceConfig) (string,
}
env["ADMIN_TOKEN"] = p.adminToken
}
configFiles, err := collectCPConfigFiles(cfg)
if err != nil {
return "", fmt.Errorf("cp provisioner: collect config files: %w", err)
}
req := cpProvisionRequest{
OrgID: p.orgID,
WorkspaceID: cfg.WorkspaceID,
@@ -188,6 +194,7 @@ func (p *CPProvisioner) Start(ctx context.Context, cfg WorkspaceConfig) (string,
Tier: cfg.Tier,
PlatformURL: cfg.PlatformURL,
Env: env,
ConfigFiles: configFiles,
}
body, err := json.Marshal(req)
@@ -241,6 +248,11 @@ func (p *CPProvisioner) Start(ctx context.Context, cfg WorkspaceConfig) (string,
const cpConfigFilesMaxBytes = 12 << 10
func isCPTemplateConfigFile(name string) bool {
name = filepath.ToSlash(filepath.Clean(name))
return name == "config.yaml" || strings.HasPrefix(name, "prompts/")
}
func collectCPConfigFiles(cfg WorkspaceConfig) (map[string]string, error) {
files := make(map[string]string)
total := 0
@@ -294,6 +306,9 @@ func collectCPConfigFiles(cfg WorkspaceConfig) (map[string]string, error) {
if err != nil {
return err
}
if !isCPTemplateConfigFile(rel) {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return err
@@ -314,6 +329,7 @@ func collectCPConfigFiles(cfg WorkspaceConfig) (map[string]string, error) {
}
return files, nil
}
// Stop terminates the workspace's EC2 instance via the control plane.
//
// Looks up the actual EC2 instance_id from the workspaces table before
@@ -468,7 +484,9 @@ func (p *CPProvisioner) IsRunning(ctx context.Context, workspaceID string) (bool
// Don't leak the body — upstream errors may echo headers.
return true, fmt.Errorf("cp provisioner: status: unexpected %d", resp.StatusCode)
}
var result struct{ State string `json:"state"` }
var result struct {
State string `json:"state"`
}
// Cap body read at 64 KiB for parity with Start — a misconfigured
// or compromised CP streaming a huge body could otherwise exhaust
// memory in this hot path (called reactively per-request from
@@ -1,11 +1,15 @@
package provisioner
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
@@ -213,6 +217,59 @@ func TestStart_HappyPath(t *testing.T) {
}
}
func TestStart_SendsTemplateAndGeneratedConfigFiles(t *testing.T) {
tmpl := t.TempDir()
if err := os.WriteFile(filepath.Join(tmpl, "config.yaml"), []byte("name: template\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpl, "adapter.py"), bytes.Repeat([]byte("x"), cpConfigFilesMaxBytes), 0o600); err != nil {
t.Fatal(err)
}
if err := os.Mkdir(filepath.Join(tmpl, "prompts"), 0o700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(tmpl, "prompts", "system.md"), []byte("hello"), 0o600); err != nil {
t.Fatal(err)
}
var body cpProvisionRequest
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
t.Errorf("decode request: %v", err)
}
w.WriteHeader(http.StatusCreated)
_, _ = io.WriteString(w, `{"instance_id":"i-abc123","state":"pending"}`)
}))
defer srv.Close()
p := &CPProvisioner{baseURL: srv.URL, orgID: "org-1", httpClient: srv.Client()}
_, err := p.Start(context.Background(), WorkspaceConfig{
WorkspaceID: "ws-1",
Runtime: "claude-code",
Tier: 4,
PlatformURL: "http://tenant",
TemplatePath: tmpl,
ConfigFiles: map[string][]byte{
"config.yaml": []byte("name: generated\n"),
},
})
if err != nil {
t.Fatalf("Start: %v", err)
}
wantConfig := base64.StdEncoding.EncodeToString([]byte("name: generated\n"))
if got := body.ConfigFiles["config.yaml"]; got != wantConfig {
t.Errorf("config.yaml payload = %q, want generated override %q", got, wantConfig)
}
wantPrompt := base64.StdEncoding.EncodeToString([]byte("hello"))
if got := body.ConfigFiles["prompts/system.md"]; got != wantPrompt {
t.Errorf("prompt payload = %q, want %q", got, wantPrompt)
}
if _, ok := body.ConfigFiles["adapter.py"]; ok {
t.Error("non-config template file adapter.py must not be sent to CP")
}
}
// TestStart_Non201ReturnsStructuredError — when CP returns 401 with a
// structured {"error":"..."} body, Start surfaces that error message.
// Verifies the defense against log-leaking raw upstream bodies.
@@ -416,9 +473,9 @@ func TestStop_4xxResponseSurfacesError(t *testing.T) {
func TestStop_2xxVariantsAllSucceed(t *testing.T) {
primeInstanceIDLookup(t, map[string]string{"ws-1": "i-ok"})
for _, code := range []int{
http.StatusOK, // 200
http.StatusAccepted, // 202
http.StatusNoContent, // 204
http.StatusOK, // 200
http.StatusAccepted, // 202
http.StatusNoContent, // 204
} {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(code)
@@ -486,11 +543,11 @@ func TestIsRunning_ParsesStateField(t *testing.T) {
_, _ = io.WriteString(w, `{"state":"`+state+`"}`)
}))
p := &CPProvisioner{
baseURL: srv.URL,
orgID: "org-1",
baseURL: srv.URL,
orgID: "org-1",
sharedSecret: "s3cret",
adminToken: "tok-xyz",
httpClient: srv.Client(),
httpClient: srv.Client(),
}
got, err := p.IsRunning(context.Background(), "ws-1")
srv.Close()
@@ -773,6 +773,15 @@ func ApplyTierConfig(hostCfg *container.HostConfig, cfg WorkspaceConfig, configM
// CopyTemplateToContainer copies files from a host directory into /configs in the container.
func (p *Provisioner) CopyTemplateToContainer(ctx context.Context, containerID, templatePath string) error {
buf, err := buildTemplateTar(templatePath)
if err != nil {
return err
}
return p.cli.CopyToContainer(ctx, containerID, "/configs", buf, container.CopyToContainerOptions{})
}
func buildTemplateTar(templatePath string) (*bytes.Buffer, error) {
// Resolve symlinks at the root before walking. filepath.Walk does
// NOT follow a symlink that IS the root — it Lstats the path, sees
// a symlink (non-directory), and emits exactly one entry without
@@ -795,6 +804,15 @@ func (p *Provisioner) CopyTemplateToContainer(ctx context.Context, containerID,
if err != nil {
return err
}
// OFFSEC-010: skip symlinks to prevent path traversal via malicious
// template symlinks (e.g. template/.ssh → /root/.ssh). filepath.Walk
// follows symlinks by default, so without this guard a crafted symlink
// inside the template directory could escape to include arbitrary host
// files in the tar archive. We intentionally skip rather than error so
// a broken symlink in an org template is a silent no-op.
if info.Mode()&os.ModeSymlink != 0 {
return nil
}
rel, err := filepath.Rel(templatePath, path)
if err != nil {
return err
@@ -835,13 +853,13 @@ func (p *Provisioner) CopyTemplateToContainer(ctx context.Context, containerID,
return nil
})
if err != nil {
return fmt.Errorf("failed to create tar from %s: %w", templatePath, err)
return nil, fmt.Errorf("failed to create tar from %s: %w", templatePath, err)
}
if err := tw.Close(); err != nil {
return fmt.Errorf("failed to close tar writer: %w", err)
return nil, fmt.Errorf("failed to close tar writer: %w", err)
}
return p.cli.CopyToContainer(ctx, containerID, "/configs", &buf, container.CopyToContainerOptions{})
return &buf, nil
}
// WriteFilesToContainer writes in-memory files into /configs in the container.
@@ -1,7 +1,9 @@
package provisioner
import (
"archive/tar"
"errors"
"io"
"os"
"path/filepath"
"strings"
@@ -80,6 +82,54 @@ func TestStartSeedsConfigsBeforeContainerStart(t *testing.T) {
}
}
func TestBuildTemplateTar_SkipsSymlinks(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(filepath.Join(dir, "config.yaml"), []byte("name: safe\n"), 0644); err != nil {
t.Fatalf("write config: %v", err)
}
outside := filepath.Join(t.TempDir(), "secret.txt")
if err := os.WriteFile(outside, []byte("do-not-copy\n"), 0644); err != nil {
t.Fatalf("write outside target: %v", err)
}
if err := os.Symlink(outside, filepath.Join(dir, "linked-secret.txt")); err != nil {
t.Fatalf("create symlink: %v", err)
}
buf, err := buildTemplateTar(dir)
if err != nil {
t.Fatalf("buildTemplateTar: %v", err)
}
names := map[string]string{}
tr := tar.NewReader(buf)
for {
hdr, err := tr.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
t.Fatalf("read tar: %v", err)
}
body, err := io.ReadAll(tr)
if err != nil {
t.Fatalf("read body for %s: %v", hdr.Name, err)
}
names[hdr.Name] = string(body)
}
if got := names["config.yaml"]; got != "name: safe\n" {
t.Fatalf("config.yaml body = %q, want safe config", got)
}
if _, ok := names["linked-secret.txt"]; ok {
t.Fatalf("symlink entry was copied into template tar: %#v", names)
}
for name, body := range names {
if strings.Contains(body, "do-not-copy") {
t.Fatalf("symlink target leaked through %s: %q", name, body)
}
}
}
// baseHostConfig returns a fresh HostConfig with typical pre-tier binds,
// mimicking what Start() builds before calling ApplyTierConfig.
func baseHostConfig(pluginsPath string) *container.HostConfig {