Skip to content

Fix runner crash: align WASI_CONFIG wire format with controller#14

Merged
cardil merged 5 commits intomainfrom
bugfix/runner-env-config-type-mismatch
Mar 5, 2026
Merged

Fix runner crash: align WASI_CONFIG wire format with controller#14
cardil merged 5 commits intomainfrom
bugfix/runner-env-config-type-mismatch

Conversation

@cardil
Copy link
Owner

@cardil cardil commented Mar 4, 2026

Problem

Fixes #13

Runner crashed immediately on startup with:

Error: invalid type: map, expected a sequence at line 1 column 7

All pods ended up in CrashLoopBackOff.

Root Cause

Two type mismatches between the JSON produced by the controller and what the runner expected:

  1. env field: controller serializes as map[string]string (e.g. {"KEY":"VALUE"}), runner expected Vec<EnvVar> (an array of {name, value} objects) — direct crash cause
  2. volume mounts: controller serializes as "dirs" with hostPath/guestPath fields, runner expected "volumeMounts" with name/mountPath — silently dropped

Fix

  • runner/src/config.rs: changed env to HashMap<String, String>, replaced volume_mounts: Vec<VolumeMount> with dirs: Vec<DirConfig> using hostPath/guestPath
  • runner/src/server.rs: updated build_wasi_ctx() to iterate the map for env and dirs for mounts
  • runner/src/main.rs: updated diagnostic log line

Tests

Added a golden-file contract test that locks both sides to the same JSON schema:

  • pkg/reconciler/wasmmodule/testdata/wasi_config.golden.json — single source of truth for the wire format
  • pkg/reconciler/wasmmodule/wasmmodule_test.go — Go test: asserts buildRunnerConfig() output matches the golden file
  • runner/src/config.rs (test module) — Rust test: asserts the golden file parses into WasiConfig correctly

Assisted-by: 🤖 Claude Sonnet 4.6


Summary by cubic

Fixes runner crash on startup by aligning the WASI_CONFIG JSON with the controller; env is now a map and directory mounts use hostPath/guestPath. Pods start cleanly and dir mounts are applied.

  • Bug Fixes
    • Parse env as a map: {"KEY":"VALUE"} (HashMap<String,String}), not an array of EnvVar.
    • Replace volumeMounts with dirs using hostPath/guestPath/readOnly; update WASI context and startup logs.
    • Golden-file contract tests in Go and Rust; normalize JSON and improve errors; use CARGO_MANIFEST_DIR for a stable Rust golden path.
    • Export BuildRunnerConfig and update the reconciler to use it; fix test package naming and lints.

Written for commit 1667d10. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Redesigned WASI configuration: directory mounts expressed as host↔guest paths with read-only flags; environment as key/value map; clearer args and network fields.
  • Tests

    • Added golden-file backed tests to validate the produced WASI configuration serializes to the expected format.

env: map[string]string (not []EnvVar), dirs: hostPath/guestPath (not volumeMounts).
Add golden-file contract tests for both Go and Rust sides.

Fixes #13
@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2deb0c2f-760f-4a75-b02f-9082854c2b73

📥 Commits

Reviewing files that changed from the base of the PR and between 2858cf3 and 1667d10.

📒 Files selected for processing (1)
  • runner/src/config.rs

Walkthrough

Controller now emits WASI JSON with env as a map and dirs for preopened directories; added a golden JSON and unit test. Runner parsing, logging, and preopen logic updated to consume env as key/value pairs and dirs (host_path → guest_path, read_only).

Changes

Cohort / File(s) Summary
Test infrastructure
pkg/reconciler/wasmmodule/testdata/wasi_config.golden.json, pkg/reconciler/wasmmodule/wasmmodule_test.go
Add golden WASI JSON and a unit test asserting BuildRunnerConfig produces canonical JSON with args, env as an object, dirs entries, and network.
Controller: config builder
pkg/reconciler/wasmmodule/wasmmodule.go
Renamed private buildRunnerConfig → exported BuildRunnerConfig (visibility change) and updated call sites.
Runner: config shape
runner/src/config.rs
Change WasiConfig.env from Vec<EnvVar>HashMap<String,String>; replace volume_mounts with dirs: Vec<DirConfig>; remove EnvVar/VolumeMount; add DirConfig { host_path, guest_path, read_only }; add contract test for parsing golden JSON.
Runner: runtime behavior
runner/src/server.rs, runner/src/main.rs
Iterate env as (key,val) pairs; replace volume_mount handling with dirs (use host_pathguest_path, respect read_only); remove sub_path logic; update logging to reference dirs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  rect rgba(60,120,60,0.5)
    Controller->>Runner: Set WASI_CONFIG JSON (env: map, dirs[], args, network)
  end
  rect rgba(60,60,120,0.5)
    Runner->>ConfigParser: Parse WASI_CONFIG into WasiConfig
    ConfigParser->>EnvSetup: For each (key,val) set env
    ConfigParser->>DirsSetup: For each dir -> preopen guest_path from host_path (respect read_only)
    DirsSetup->>Filesystem: Check host_path exists
  end
  rect rgba(120,60,60,0.5)
    Runner->>Network: Apply network constraints
    Runner->>WasmProcess: Launch WASM with env, preopened dirs, args
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • 🥳 PoC works #5 — Adds golden JSON and tests and makes runner-side changes matching env-as-map and volume_mounts→dirs format.

Suggested labels

enhancement

Poem

🐇 I hopped through JSON, neat and quick,
Turned lists to maps and mapped each stick.
Host to guest, a tidy lane,
Golden file proves the gain.
Rabbit twitches — tests run clean!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: fixing a runner crash by aligning the WASI_CONFIG wire format between controller and runner components.
Linked Issues check ✅ Passed All code changes directly address issue #13 requirements: env type changed to HashMap, volume_mounts replaced with dirs using hostPath/guestPath, and golden-file contract tests added to lock wire format.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the wire-format mismatch. Function visibility change (buildRunnerConfig→BuildRunnerConfig) directly enables the golden-file test requirement.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/runner-env-config-type-mismatch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 5 files

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/reconciler/wasmmodule/wasmmodule_test.go (1)

32-33: Consider t.Parallel() for this isolated unit test.

This test has no shared mutable state and can run in parallel with the rest of the package tests.

💡 Proposed fix
 func TestBuildRunnerConfigMatchesGolden(t *testing.T) {
+	t.Parallel()
+
 	trueVal := true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/reconciler/wasmmodule/wasmmodule_test.go` around lines 32 - 33, The test
TestBuildRunnerConfigMatchesGolden can be run in parallel; add t.Parallel() at
the start of the test to enable parallel execution. Open the
TestBuildRunnerConfigMatchesGolden function and insert a call to t.Parallel()
(e.g., immediately after func TestBuildRunnerConfigMatchesGolden(t *testing.T)
{) so the isolated test runs concurrently with other tests; ensure this change
does not alter the existing trueVal or other local setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/reconciler/wasmmodule/wasmmodule_test.go`:
- Around line 79-80: The test currently discards errors from json.MarshalIndent
when creating gotJSON and wantJSON; update the test in wasmmodule_test.go to
check and handle those errors instead of ignoring them by capturing the error
return from json.MarshalIndent for both gotMap and wantMap (the variables
gotJSON and wantJSON) and calling t.Fatalf or t.Errorf with a descriptive
message on error; ensure the error messages include the marshal error so test
diagnostics remain helpful.

---

Nitpick comments:
In `@pkg/reconciler/wasmmodule/wasmmodule_test.go`:
- Around line 32-33: The test TestBuildRunnerConfigMatchesGolden can be run in
parallel; add t.Parallel() at the start of the test to enable parallel
execution. Open the TestBuildRunnerConfigMatchesGolden function and insert a
call to t.Parallel() (e.g., immediately after func
TestBuildRunnerConfigMatchesGolden(t *testing.T) {) so the isolated test runs
concurrently with other tests; ensure this change does not alter the existing
trueVal or other local setup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a36d770-7156-4dd3-a894-dc927aebfd67

📥 Commits

Reviewing files that changed from the base of the PR and between e7d29e8 and 92eeb8f.

📒 Files selected for processing (5)
  • pkg/reconciler/wasmmodule/testdata/wasi_config.golden.json
  • pkg/reconciler/wasmmodule/wasmmodule_test.go
  • runner/src/config.rs
  • runner/src/main.rs
  • runner/src/server.rs

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/reconciler/wasmmodule/wasmmodule_test.go`:
- Line 83: Add a blank line between the preceding error-checking block and the
second assignment to wantJSON to satisfy the wsl_v5 linter; specifically, in
wasmmodule_test.go insert an empty line before the statement that initializes
wantJSON, err := json.MarshalIndent(wantMap, "", "  ") so the wantJSON
assignment is visually separated from the prior if err != nil { ... } block.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 839979d6-d314-4512-9a1c-35102053f21f

📥 Commits

Reviewing files that changed from the base of the PR and between 92eeb8f and 3b92276.

📒 Files selected for processing (1)
  • pkg/reconciler/wasmmodule/wasmmodule_test.go

@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 6.56%. Comparing base (b312ce8) to head (1667d10).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
pkg/reconciler/wasmmodule/wasmmodule.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##            main     #14      +/-   ##
========================================
+ Coverage   1.71%   6.56%   +4.84%     
========================================
  Files         22      22              
  Lines        640     640              
========================================
+ Hits          11      42      +31     
+ Misses       629     593      -36     
- Partials       0       5       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cardil
Copy link
Owner Author

cardil commented Mar 5, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@runner/src/config.rs`:
- Around line 140-169: The test test_parse_golden_wasi_config uses a fragile
relative path when calling std::fs::read_to_string; change it to build the
absolute crate-root anchored path using CARGO_MANIFEST_DIR (e.g., use
concat!(env!("CARGO_MANIFEST_DIR"),
"/../pkg/reconciler/wasmmodule/testdata/wasi_config.golden.json") as the
argument to read_to_string) so the golden file is resolved correctly when the
test binary runs outside Cargo.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b9efa216-c974-4836-a744-d4ad2555e248

📥 Commits

Reviewing files that changed from the base of the PR and between 3b92276 and 2858cf3.

📒 Files selected for processing (4)
  • pkg/reconciler/wasmmodule/wasmmodule.go
  • pkg/reconciler/wasmmodule/wasmmodule_test.go
  • runner/src/config.rs
  • runner/src/server.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • runner/src/server.rs

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/reconciler/wasmmodule/wasmmodule.go (1)

213-216: ⚠️ Potential issue | 🟠 Major

allowIpNameLookup=false is lost on the wire due to omitempty on a boolean field.

At line 215, AllowIPNameLookup uses json:"allowIpNameLookup,omitempty". In Go's JSON marshalling, false values are omitted when omitempty is set. On the Rust runner side (line 90), the field has #[serde(default = "default_true")], so a missing field defaults to true. This makes it impossible to transmit an explicit false value.

💡 Proposed fix
 type RunnerNetworkConfig struct {
 	Inherit           bool     `json:"inherit,omitempty"`
-	AllowIPNameLookup bool     `json:"allowIpNameLookup,omitempty"`
+	AllowIPNameLookup bool     `json:"allowIpNameLookup"`
 	TCPBind           []string `json:"tcpBind,omitempty"`
 	TCPConnect        []string `json:"tcpConnect,omitempty"`
 	UDPBind           []string `json:"udpBind,omitempty"`
 	UDPConnect        []string `json:"udpConnect,omitempty"`
 	UDPOutgoing       []string `json:"udpOutgoing,omitempty"`
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/reconciler/wasmmodule/wasmmodule.go` around lines 213 - 216, The boolean
field AllowIPNameLookup on struct RunnerNetworkConfig is tagged with
`omitempty`, so false values are dropped during JSON marshaling and the Rust
runner's default (true) is used; remove `omitempty` from the `json` tag on
AllowIPNameLookup (i.e., change `json:"allowIpNameLookup,omitempty"` to
`json:"allowIpNameLookup"`) so explicit false is preserved across the wire and
the Rust side receives the intended value. Ensure you update any related
marshaling tests or usages that assumed omission behavior.
🧹 Nitpick comments (1)
pkg/reconciler/wasmmodule/wasmmodule_test.go (1)

54-57: Add a AllowIPNameLookup=false regression case.

The golden case only validates true. Add a second case with false to lock wire-format semantics for explicit DNS disable and prevent silent regressions.

🧪 Example follow-up test snippet
 func TestBuildRunnerConfigMatchesGolden(t *testing.T) {
 	t.Parallel()
@@
 	assertJSONEqual(t, got, string(goldenBytes))
+
+	t.Run("preserves allowIpNameLookup=false", func(t *testing.T) {
+		falseVal := false
+		module.Spec.Network.AllowIPNameLookup = &falseVal
+
+		got, err := wasmmodule.BuildRunnerConfig(module)
+		if err != nil {
+			t.Fatalf("BuildRunnerConfig() error: %v", err)
+		}
+
+		var gotMap map[string]any
+		if err := json.Unmarshal([]byte(got), &gotMap); err != nil {
+			t.Fatalf("unmarshal got: %v", err)
+		}
+		network, ok := gotMap["network"].(map[string]any)
+		if !ok {
+			t.Fatalf("network object missing in output JSON")
+		}
+		if v, ok := network["allowIpNameLookup"]; !ok || v != false {
+			t.Fatalf("expected allowIpNameLookup=false, got %v (present=%v)", v, ok)
+		}
+	})
 }

Also applies to: 74-75

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/reconciler/wasmmodule/wasmmodule_test.go` around lines 54 - 57, Add a
regression test case that sets NetworkSpec.AllowIPNameLookup to false (e.g.,
introduce a falseVal boolean and a second test entry alongside the existing
trueVal case) so the golden output validates both true and false wire-format
semantics; update the test table in wasmmodule_test.go to include this new case
using the same structure as the existing case (Network:
&api.NetworkSpec{Inherit:false, AllowIPNameLookup:&falseVal, TCP:...}) and
add/commit the corresponding golden/expected output for the false case to lock
the explicit-DNS-disable behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pkg/reconciler/wasmmodule/wasmmodule.go`:
- Around line 213-216: The boolean field AllowIPNameLookup on struct
RunnerNetworkConfig is tagged with `omitempty`, so false values are dropped
during JSON marshaling and the Rust runner's default (true) is used; remove
`omitempty` from the `json` tag on AllowIPNameLookup (i.e., change
`json:"allowIpNameLookup,omitempty"` to `json:"allowIpNameLookup"`) so explicit
false is preserved across the wire and the Rust side receives the intended
value. Ensure you update any related marshaling tests or usages that assumed
omission behavior.

---

Nitpick comments:
In `@pkg/reconciler/wasmmodule/wasmmodule_test.go`:
- Around line 54-57: Add a regression test case that sets
NetworkSpec.AllowIPNameLookup to false (e.g., introduce a falseVal boolean and a
second test entry alongside the existing trueVal case) so the golden output
validates both true and false wire-format semantics; update the test table in
wasmmodule_test.go to include this new case using the same structure as the
existing case (Network: &api.NetworkSpec{Inherit:false,
AllowIPNameLookup:&falseVal, TCP:...}) and add/commit the corresponding
golden/expected output for the false case to lock the explicit-DNS-disable
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ecfdd408-e067-490f-897f-998fce34a7fb

📥 Commits

Reviewing files that changed from the base of the PR and between 3b92276 and 2858cf3.

📒 Files selected for processing (4)
  • pkg/reconciler/wasmmodule/wasmmodule.go
  • pkg/reconciler/wasmmodule/wasmmodule_test.go
  • runner/src/config.rs
  • runner/src/server.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • runner/src/server.rs

@cardil cardil merged commit 3e351a3 into main Mar 5, 2026
20 checks passed
@cardil cardil deleted the bugfix/runner-env-config-type-mismatch branch March 5, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Runner crashes: env var config type mismatch between controller and runner

1 participant