Skip to content

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

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

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

Conversation

@dshakes

@dshakes dshakes commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Part 10 of 10 of the GA next-gen stack (split from #254 so each AI review fits its budget). Base: ga/09-fork-identity. Merge in order with a merge commit (not squash) so the stack stays intact.

Full context, verification results 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 23, 2026
@github-actions github-actions Bot added the domain:infra Touches infra / CI / deploy / migrations label Oct 23, 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)

No Blocking findings.

Low: runtime_exec_e2e_test.go says the readiness wait is bounded at 60s, but each c.Exec(ctx, ...) uses the outer 3-minute test context. If an exec stream hangs, the loop will not check the 60s deadline until that call returns. Use a short per-attempt timeout context.

Low: main.go now honors HTTP_ADDR, but the startup log still always reports :8080 at line 850. This can mislead deploy/debugging when the bind address is overridden.

I did not find production correctness or security regressions in the PR diff. git diff --check passed; full tests were not runnable in this read-only workspace.

@github-actions

Copy link
Copy Markdown
Contributor

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

Audit Verdict: BLOCKED

Leading with one blocking CI failure, followed by correctness edge cases and configuration observations.


1. Blocking: CI Toolchain Mismatch

File: services/control-plane/go.mod (lines 3–5)

-go 1.25.0
+go 1.26.0

-toolchain go1.26.6
+toolchain go1.26.10
  • Impact: Broken required status check (sdlc-lint).
  • Root Cause: .github/workflows/sdlc-lint.yml (line 22) explicitly pins:
    env:
      GOTOOLCHAIN: go1.26.6 # pin to the same toolchain as the QA job
    When Go executes with a fixed GOTOOLCHAIN name older than the toolchain directive in go.mod (go1.26.6 < go1.26.10), the toolchain driver refuses to execute and immediately aborts:
    go: services/control-plane/go.mod requires go >= 1.26.10 (running go 1.26.6; GOTOOLCHAIN=go1.26.6)
    
  • Remediation: Either keep services/control-plane/go.mod pinned to toolchain go1.26.6 (matching all sibling Go modules: workflow-engine, scheduler, runtime-scheduler, gen/go), or bump GOTOOLCHAIN in .github/workflows/sdlc-lint.yml to go1.26.10.

2. Correctness & Edge Cases

A. Missing ctx.Err() check in test polling loop

File: services/control-plane/internal/handlers/runtime_exec_e2e_test.go (lines 89–100)

	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)
	}
  • Issue: While replacing the 3-second sleep with polling is a good fix for CI cold-start races, the loop does not check ctx.Err().
  • Edge Case: scheduleE2EVM takes ctx from TestRuntimeExecE2E_RealVM. If ctx is canceled or times out before the 60s wall-clock deadline, c.Exec fails immediately on every retry, but the loop continues sleeping and spinning until the full 60s wall clock expires instead of failing fast.
  • Remediation: Check if err := ctx.Err(); err != nil { t.Fatalf("context ended while waiting for vm %s: %v", vmID, err) } inside the loop or use a select with case <-ctx.Done():.

B. HTTP_ADDR logging and configuration drift

File: services/control-plane/cmd/server/main.go (lines 843, 850)

	httpServer := &http.Server{
		Addr:              envOrDefault("HTTP_ADDR", ":8080"),
		Handler:           tracedHTTP,
		ReadHeaderTimeout: 5 * time.Second,
	}

	httpErrCh := make(chan error, 1)
	go func() {
		logger.Info("HTTP health server starting", zap.String("addr", ":8080"))
...
  • Issue: If HTTP_ADDR is overridden (e.g. :8081 or 0.0.0.0:8080), logger.Info still logs hardcoded addr: ":8080".
  • Pattern Inconsistency: ListenAddr for gRPC and other service addresses are defined on config and parsed in loadConfig(). HTTP_ADDR bypasses config and is parsed ad-hoc.
  • Remediation: Move HTTPAddr into type config in loadConfig(), and log zap.String("addr", httpServer.Addr).

3. Non-Blocking / Verified Passing

  • Documentation & SVG Links:
    • apps/docs/app/sdk/page.tsx: /runtime/sandbox-lifecycle link target exists at apps/docs/app/runtime/sandbox-lifecycle/page.tsx.
    • docs/architecture/04b-microvm-productionization.md: Embedded SVGs (runtime-two-tier.svg, sandbox-lifecycle.svg) and links to ADR 0025 resolve.
    • sandbox-lifecycle.svg: XML is valid and properly entity-escaped (&#123;id&#125;).
    • apps/landing/app/runtime/page.tsx: Nav anchor #sandbox matches section id="sandbox"; all referenced icons (GitBranch, Check) and CSS styles (code-window, beam-line) exist.
  • Scheduler Cron Format:
    • services/scheduler/internal/cron/{evaluator.go,ticker.go}: Whitespace alignment only; no logic alterations.

@dshakes

dshakes commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the rewritten stack #265–#275 (same changes; history rewritten to drop a 43 MB build binary committed by mistake; part 11 #275 fixes the confirmed Codex audit findings raised on this stack).

@dshakes dshakes closed this Oct 23, 2026
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:infra Touches infra / CI / deploy / migrations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant