Skip to content

GA 10/11 · diagrams/landing/docs refresh, govulncheck-clean deps, exec e2e readiness poll - #285

Closed
dshakes wants to merge 5 commits into
ga3/09-fork-identityfrom
ga3/10-docs-diagrams-vuln
Closed

dshakes wants to merge 5 commits into
ga3/09-fork-identityfrom
ga3/10-docs-diagrams-vuln

Conversation

@dshakes

@dshakes dshakes commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Part 10 of 11 of the GA next-gen stack (supersedes #255–#275). History rewritten (range-limited, master untouched) to drop a 43 MB build binary committed by mistake; part 11 fixes every confirmed Codex cross-audit finding. Base: ga3/09-fork-identity. Merge in order with a merge commit (not squash).

Context, verification and needs-human list: #254 and docs/roadmap/2026-10-nextgen-sandbox-and-harness.md.

Commits in this part:

  • test(runtime): poll for exec-ability instead of a fixed 3s sleep in exec e2e
  • fix(deps): grpc 1.83.2, otel 1.45, x/net 0.60, toolchain go1.26.10 — govulncheck clean (16 advisories)
  • docs: tighten diagram labels that overflowed their boxes; tenant budget cap is shipped
  • docs: sandbox lifecycle, spawn contract and manager authz across diagrams, architecture docs, landing and docs site
  • chore: HTTP_ADDR override for side-by-side dev, gofmt scheduler cron, fix fork contract in roadmap

…rams, architecture docs, landing and docs site
…xec e2e

Spawn is dispatched asynchronously by the scheduler. The fixed sleep raced a
cold Docker start on a fresh CI runner: in run 39966075268 docker start was
still in flight at 3s (container in Created, no handle registered yet), so every
Exec got NotFound. The same service code passed CI on the next commit, which
changed only docs. Poll Exec("true") until it succeeds, bounded by the
scheduler's 60s dispatchSpawn timeout.
@compass-sdlc-bot compass-sdlc-bot Bot added the agent:reviewed-clean Reviewer found no Blocking issues this round label Oct 24, 2026
@github-actions github-actions Bot added the domain:core Core library / business logic label Oct 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🛡️ Vuln scan — ❌ vulnerable dependency found

      #122: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.http2requestBody.Close
      #123: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.http2requestBody.Read
      #124: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.http2requestBody.Read
      #125: internal/handlers/runtime.go:2034:16: handlers.RuntimeHandler.StreamLogs calls http.http2responseWriter.Flush
      #126: internal/handlers/runtime.go:2034:16: handlers.RuntimeHandler.StreamLogs calls http.http2responseWriter.Flush
      #127: internal/handlers/rest.go:2665:9: handlers.RESTHandler.GetWorkflow calls http.http2responseWriter.Write
      #128: internal/handlers/rest.go:2665:9: handlers.RESTHandler.GetWorkflow calls http.http2responseWriter.Write
      #129: internal/handlers/rest.go:2620:16: handlers.RESTHandler.GetWorkflow calls http.http2responseWriter.WriteHeader
      #130: internal/handlers/rest.go:2620:16: handlers.RESTHandler.GetWorkflow calls http.http2responseWriter.WriteHeader
      #131: internal/handlers/llm_proxy.go:3950:104: handlers.LlmProxyHandler.Transcribe calls multierr.multiError.Error, which eventually calls http.http2responseWriter.WriteString
      #132: internal/handlers/llm_proxy.go:3950:104: handlers.LlmProxyHandler.Transcribe calls multierr.multiError.Error, which eventually calls http.http2responseWriter.WriteString
      #133: internal/handlers/runtime.go:2033:14: handlers.RuntimeHandler.StreamLogs calls fmt.Fprintf, which eventually calls http.http2stickyErrWriter.Write
      #134: internal/handlers/runtime.go:2033:14: handlers.RuntimeHandler.StreamLogs calls fmt.Fprintf, which eventually calls http.http2stickyErrWriter.Write
      #135: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.http2transportResponseBody.Close
      #136: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.http2transportResponseBody.Close
      #137: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.http2transportResponseBody.Read
      #138: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.http2transportResponseBody.Read
      #139: internal/handlers/errand.go:686:52: handlers.ErrandHandler.ErrandTurn calls fmt.Sprint, which eventually calls http.http2writeData.String
      #140: internal/handlers/errand.go:686:52: handlers.ErrandHandler.ErrandTurn calls fmt.Sprint, which eventually calls http.http2writeData.String
      #141: internal/handlers/embed.go:64:22: handlers.LlmProxyHandler.EmbedText calls bytes.Buffer.ReadFrom, which calls http.loggingConn.Read
      #142: internal/handlers/embed.go:64:22: handlers.LlmProxyHandler.EmbedText calls bytes.Buffer.ReadFrom, which calls http.loggingConn.Read
      #143: internal/handlers/runtime.go:2033:14: handlers.RuntimeHandler.StreamLogs calls fmt.Fprintf, which calls http.loggingConn.Write
      #144: internal/handlers/runtime.go:2033:14: handlers.RuntimeHandler.StreamLogs calls fmt.Fprintf, which calls http.loggingConn.Write
      #145: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.maxBytesReader.Close
      #146: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.maxBytesReader.Close
      #147: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.maxBytesReader.Read
      #148: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.maxBytesReader.Read
      #149: internal/handlers/schedules.go:237:33: handlers.RESTHandler.UpdateSchedule calls time.LoadLocation, which eventually calls http.onceCloseListener.Close
      #150: internal/handlers/schedules.go:237:33: handlers.RESTHandler.UpdateSchedule calls time.LoadLocation, which eventually calls http.onceCloseListener.Close
      #151: internal/handlers/embed.go:64:22: handlers.LlmProxyHandler.EmbedText calls bytes.Buffer.ReadFrom, which calls http.persistConn.Read
      #152: internal/handlers/embed.go:64:22: handlers.LlmProxyHandler.EmbedText calls bytes.Buffer.ReadFrom, which calls http.persistConn.Read
      #153: internal/handlers/dl.go:289:17: handlers.DLHandler.Serve calls io.Copy, which eventually calls http.persistConnWriter.ReadFrom
      #154: internal/handlers/dl.go:289:17: handlers.DLHandler.Serve calls io.Copy, which eventually calls http.persistConnWriter.ReadFrom
      #155: internal/handlers/runtime.go:2033:14: handlers.RuntimeHandler.StreamLogs calls fmt.Fprintf, which eventually calls http.persistConnWriter.Write
      #156: internal/handlers/runtime.go:2033:14: handlers.RuntimeHandler.StreamLogs calls fmt.Fprintf, which eventually calls http.persistConnWriter.Write
      #157: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.readTrackingBody.Close
      #158: internal/handlers/llm_proxy.go:3822:2: handlers.LlmProxyHandler.OCR calls http.readTrackingBody.Close
      #159: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.readTrackingBody.Read
      #160: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.readTrackingBody.Read
      #161: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.readWriteCloserBody.Read
      #162: internal/handlers/llm_proxy.go:3825:27: handlers.LlmProxyHandler.OCR calls io.ReadAll, which calls http.readWriteCloserBody.Read
      #163: internal/handlers/runtime.go:2034:16: handlers.RuntimeHandler.StreamLogs calls http.response.Flush
      #164: internal/handlers/runtime.go:2034:16: handlers.RuntimeHandler.StreamLogs calls http.response.Flush
      #165: internal/handlers/dl.go:289:17: handlers.DLHandler.Serve calls io.Copy, which eventually calls http.response.ReadFrom
      #166: internal/handlers/dl.go:289:17: handlers.DLHandler.Serve calls io.Copy, which eventually calls http.response.ReadFrom
      #167: internal/handlers/rest.go:2665:9: handlers.RESTHandler.GetWorkflow calls http.response.Write
      #168: internal/handlers/rest.go:2665:9: handlers.RESTHandler.GetWorkflow calls http.response.Write
      #169: internal/handlers/rest.go:2620:16: handlers.RESTHandler.GetWorkflow calls http.response.WriteHeader
      #170: internal/handlers/rest.go:2620:16: handlers.RESTHandler.GetWorkflow calls http.response.WriteHeader
      #171: internal/handlers/llm_proxy.go:3950:104: handlers.LlmProxyHandler.Transcribe calls multierr.multiError.Error, which eventually calls http.response.WriteString
      #172: internal/handlers/llm_proxy.go:3950:104: handlers.LlmProxyHandler.Transcribe calls multierr.multiError.Error, which eventually calls http.response.WriteString
      #173: internal/handlers/llm_proxy.go:3950:104: handlers.LlmProxyHandler.Transcribe calls http.transportReadFromServerError.Error
      #174: internal/handlers/llm_proxy.go:3950:104: handlers.LlmProxyHandler.Transcribe calls http.transportReadFromServerError.Error

Vulnerability #11: GO-2026-6600
    Recognize yield as regexp preceder keyword in html/template
  More info: https://pkg.go.dev/vuln/GO-2026-6600
  Standard library
    Found in: html/template@go1.26.6
    Fixed in: html/template@go1.26.9
    Example traces found:
      #1: cmd/server/main.go:851:38: server.main calls http.Server.ListenAndServe, which eventually calls template.Template.Execute
      #2: cmd/server/main.go:851:38: server.main calls http.Server.ListenAndServe, which eventually calls template.Template.ExecuteTemplate

Vulnerability #12: GO-2026-6599
    Reset context tracking on consecutive template expressions in html/template
  More info: https://pkg.go.dev/vuln/GO-2026-6599
  Standard library
    Found in: html/template@go1.26.6
    Fixed in: html/template@go1.26.9
    Example traces found:
      #1: cmd/server/main.go:851:38: server.main calls http.Server.ListenAndServe, which eventually calls template.Template.Execute
      #2: cmd/server/main.go:851:38: server.main calls http.Server.ListenAndServe, which eventually calls template.Template.ExecuteTemplate

Your code is affected by 12 vulnerabilities from the Go standard library.
This scan also found 3 vulnerabilities in packages you import and 1
vulnerability in modules you require, but your code doesn't appear to call these
vulnerabilities.
Use '-show verbose' for more details.
make: *** [Makefile:270: audit] Error 3

@github-actions

Copy link
Copy Markdown
Contributor

🔎 Codex cross-audit (agent:audit)

Blocking

  • services/control-plane/go.mod bumps the module to toolchain go1.26.10, but required workflows still pin GOTOOLCHAIN=go1.26.6 in sdlc-lint.yml and sdlc-vuln.yml. With GOTOOLCHAIN set to an exact older toolchain, Go commands in those jobs can’t satisfy the module’s requested toolchain, so PR gates are likely to fail before lint/audit runs. Either keep toolchain go1.26.6 or update the workflow pins/comments together.

Non-Blocking

  • main.go now honors HTTP_ADDR, but the startup log still prints hard-coded :8080 at main.go. Not a runtime break, but it will mislead deploy/debug logs when HTTP_ADDR is overridden.

I didn’t find a correctness or security issue in the runtime exec polling change; it looks like a legitimate flake fix. I could not run Go tests fully because the environment is read-only and go could not create its module cache.

@github-actions

Copy link
Copy Markdown
Contributor

🔷 Gemini cross-audit (agent:audit-gemini)

Blocking

  1. Toolchain Pin Mismatch Breaks CI (sdlc-lint.yml)
    • Location: services/control-plane/go.mod:3-5 vs .github/workflows/sdlc-lint.yml:25
    • Issue: go.mod was updated to go 1.26.0 and toolchain go1.26.10. However, .github/workflows/sdlc-lint.yml hardcodes env: GOTOOLCHAIN: go1.26.6 with the explicit note # pin to the same toolchain as the QA job.
    • Impact: When GOTOOLCHAIN is set to an exact version (go1.26.6), Go forbids switching to a newer toolchain requested by go.mod (go1.26.10). Any go or golangci-lint execution on services/control-plane in CI will fail with:
      go: module requires toolchain go1.26.10, but GOTOOLCHAIN=go1.26.6 forbids switching
      
    • Monorepo Version Skew: services/workflow-engine, services/scheduler, and services/runtime-scheduler remain on go 1.25.0 and toolchain go1.26.6. Either keep services/control-plane/go.mod aligned with toolchain go1.26.6, or update the CI workflows (sdlc-lint.yml, sdlc-qa.yml) across the repo uniformly.

Correctness & Edge Cases

  1. Hardcoded Port in Startup Log on Custom HTTP_ADDR

    • Location: services/control-plane/cmd/server/main.go:843,849
    • Issue:
      httpServer := &http.Server{
          Addr:              envOrDefault("HTTP_ADDR", ":8080"),
          ...
      }
      ...
      logger.Info("HTTP health server starting", zap.String("addr", ":8080"))
    • Impact: If HTTP_ADDR is overridden (e.g. HTTP_ADDR=":8081" or HTTP_ADDR="0.0.0.0:8080"), the server listens on the configured address but logs "addr": ":8080", creating misleading observability in production.
    • Fix: Pass httpServer.Addr to the logger: zap.String("addr", httpServer.Addr).
    • Pattern Inconsistency: Unlike other network addresses (e.g. LISTEN_ADDR mapped to cfg.ListenAddr), HTTP_ADDR bypasses loadConfig() and is read ad-hoc in main(). Consider adding HTTPAddr to type config for consistency.
  2. Missing ctx.Err() Check in E2E Readiness Polling Loop

    • Location: services/control-plane/internal/handlers/runtime_exec_e2e_test.go:89-100
    • Issue:
      deadline := time.Now().Add(60 * time.Second)
      for {
          _, _, exit, err := c.Exec(ctx, node, vmID, "/bin/sh", []string{"-c", "true"})
          if err == nil && exit == 0 {
              return vmID, node
          }
          if time.Now().After(deadline) {
              t.Fatalf("vm %s never became exec-able within 60s: exit=%d err=%v", vmID, exit, err)
          }
          time.Sleep(250 * time.Millisecond)
      }
    • Impact: If the parent ctx is canceled or expires before the 60s deadline, c.Exec fails immediately on every iteration with context.Canceled or context.DeadlineExceeded. The loop will continue sleeping and re-executing until the wall-clock deadline triggers.
    • Fix: Check if ctx.Err() != nil { t.Fatalf("context canceled waiting for vm %s: %v", vmID, ctx.Err()) } before sleeping.

Non-Blocking / Verified Items

  • Docs & Landing Integration: apps/docs/app/sdk/page.tsx properly references /runtime/sandbox-lifecycle, which exists and renders. apps/landing/app/runtime/page.tsx correctly references #sandbox in Nav() and uses existing CSS utility classes (.code-window, .beam-line).
  • SVG Diagrams: docs/architecture/diagrams/sandbox-lifecycle.svg is valid XML/SVG with clean text coordinate bounding. Coordinates in runtime-two-tier.svg were appropriately shifted to prevent overlapping.
  • Scheduler Formatting: evaluator.go and ticker.go changes are struct alignment formatting nits.

@dshakes

dshakes commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the reordered parts #287–#292 (server-side pause/resume/fork now lands before the SDK/dashboard that call it; final tree identical).

@dshakes dshakes closed this Oct 24, 2026
@dshakes
dshakes deleted the ga3/10-docs-diagrams-vuln branch October 28, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:reviewed-clean Reviewer found no Blocking issues this round domain:core Core library / business logic

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant