Skip to content

feat: WASI target support for func (build + deploy)#3560

Open
cardil wants to merge 25 commits intoknative:mainfrom
cardil:feature/wasi-integration
Open

feat: WASI target support for func (build + deploy)#3560
cardil wants to merge 25 commits intoknative:mainfrom
cardil:feature/wasi-integration

Conversation

@cardil
Copy link
Copy Markdown
Contributor

@cardil cardil commented Apr 1, 2026

Adds an alternative build/deployment mode for func that uses WASI modules instead of container images.

What it does

  • func create --runtime rust-wasi or func create --runtime go-wasi creates WASI function projects
  • func build compiles to wasm32-wasip2 and pushes OCI WASM artifacts to registry
  • func deploy creates WasmModule CRs (from knative-serving-wasm) with readiness polling
  • func list, func describe, func delete work with WasmModule resources
  • Builder/deployer auto-inferred from *-wasi runtime suffix
  • Compatibility validation prevents invalid runtime/builder/deployer combinations

Key components

  • pkg/wasm/ — Builder, deployer, lister, remover, describer, OCI artifact pusher
  • templates/rust-wasi/http/ — Rust WASI HTTP function template (wasi:http/proxy)
  • templates/go-wasi/http/ — Go WASI HTTP function template (TinyGo + WIT bindings)
  • pkg/functions/registry.go — Self-registering builder/deployer system with constraints
  • pkg/functions/compatibility.go — Runtime/builder/deployer compatibility validation
  • hack/cluster.sh — E2e cluster setup with knative-serving-wasm controller
  • E2e tests covering build, deploy, describe, delete for both runtimes

Supported runtimes

rust-wasi, go-wasi (others return "not yet implemented")

Dependencies

  • github.com/cardil/knative-serving-wasm v0.2.0 (WasmModule CRD types)
  • Requires cargo + wasm32-wasip2 target for Rust, tinygo for Go

Jira: SRVOCF-750

Assisted-by: 🤖 Claude Opus/Sonnet 4.6

Initial design proposal for WASI/WebAssembly support in func CLI.
Covers build pipeline, deploy pipeline, WasmModule CRD integration,
and func.yaml schema changes.

Assisted-by: 🤖 Claude Opus/Sonnet 4.5
- Remove explicit --builder/--deployer flags from diagram (auto-inferred)
- Replace 'Runtime Detection' with 'Runtime Selection' section
- Clarify runtime is chosen at func create time, not auto-detected

Assisted-by: 🤖 Claude Sonnet 4.5
Implements foundational WASM support infrastructure:

- Add github.com/cardil/knative-serving-wasm dependency
- Create pkg/wasm/ package with:
  - Constants for builder, deployer, and OCI media type
  - WASI runtime identifiers (rust-wasi, go-wasi, etc.)
  - IsWasiRuntime() helper function
  - Type aliases for WasmModule CRD network configuration
- Add Wasm constant to pkg/builders/builders.go
- Include unit tests with 83.3% coverage
- Fix trailing whitespace in design document

All tests pass (make test) and linting passes (make check).

Phase 1 focuses on core types and constants. Builder and Deployer
implementations will follow in subsequent phases.

Assisted-by: 🤖 Claude Opus/Sonnet 4.5
… checks

Self-registering builders and deployers via explicit Registry struct; WASI
runtimes auto-infer wasm builder/deployer; incompatible combinations rejected
at build/deploy time with wrapped ErrIncompatibility.

Assisted-by: 🤖 Claude Sonnet 4.5
- Add templates/rust-wasi/http/ with Cargo.toml, src/lib.rs, README.md
- Add templates/go-wasi/http/ with go.mod, function.go, function_test.go, README.md
- Fix yaml.Decoder EOF bug in repository.go: comment-only manifest.yaml is valid
- Update test expected lists to include go-wasi and rust-wasi runtimes
- Regenerate embedded FS

Assisted-by: 🤖 Claude Sonnet 4.6
Add build and deploy support for go-wasi and rust-wasi runtimes.

Builder dispatch (pkg/wasm/builder.go) routes to TinyGo (go-wasi) or
cargo (rust-wasi). TinyGo uses -no-debug to strip debug info (1.4MB→438KB).
OCI push packs .wasm as a wasm/wasi layer (pkg/wasm/oci.go).
Self-registration hooks builder and deployer into the registry.

Fix inference never running: builder/deployer were always non-empty due
to viper static defaults, making InferBuilder/InferDeployer dead code.
Track explicit origin (flag or func.yaml) via BuilderExplicit/DeployerExplicit
before Configure() overwrites with the static default.

Fix func.yaml pollution: inferred values (e.g. 'wasm') are not written
back to func.yaml. Restore the pre-Configure value before f.Write() when
inference was used. Traditional runtimes still persist 'pack'/'knative'.

e2e tests cover rust-wasi and go-wasi builds (renamed from e2e_wasm_test.go
to avoid the GOARCH=wasm Go build constraint on _wasm_ filenames).
First build uses --verbose; second build verifies func.yaml is not polluted.

Assisted-by: 🤖 Claude Sonnet 4.6
…enerator gitignore

- cmd/client.go: wire wasm remover, describer, lister in NewClient()
- pkg/wasm: rename API fields TcpSpec→TCPSpec, UdpSpec→UDPSpec,
  AllowIpNameLookup→AllowIPNameLookup (.Tcp→.TCP, .Udp→.UDP)
- bump github.com/cardil/knative-serving-wasm to latest (env var fix)
- generate/templates/main.go: respect .gitignore in embedded FS generator
  (pass trailing slash for dirs so 'target/' pattern matches correctly)
- pkg/filesystem/filesystem_test.go: apply same gitignore filtering to
  loadLocalFiles, initOSFS, initGitFS so they match the embedded FS
- regenerate zz_filesystem_generated.go (drops rust-wasi/http/target/)
- e2e: deployer tests, cluster.sh improvements
- docs: regenerated reference pages
- Remove types.go (unused type aliases)
- Rename types_test.go -> wasm_test.go (stale name)
- Convert deployer_test.go to package wasm_test (black-box)
- Export BuildNetworkSpec for external test access
- Add t.Parallel() to compatibility_test.go tests
- serving_wasm() uses stable kubectl apply from release manifest
- Add KnativeServingWasm to component-versions
- Deployer readiness polling mirrors Knative deployer pattern
- Pod watcher goroutine detects CrashLoopBackOff/ImagePullBackOff fast
- ServiceUnavailable treated as transient (not terminal)
- In-cluster registry (Deployment+NodePort) replaces external container
- Insecure registry ConfigMap for WASM runner pods
- Podman PID limit raised to 8192 (Knative+wasmtime needs >2048)
- E2e liveness checks with withContentMatch for WASI templates
- Update serving-wasm to v0.2.0 (insecure registries + terminal failures)

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
- Add pkg/wasm/wit.go: ProvisionWIT downloads WIT deps from OCI into
  wit/<key>/ using wasm-tools, compares wit/.versions to skip unchanged
  entries, writes per-subdir .gitignore to prevent accidental commits
- Add pkg/wasm/wit_test.go: unit tests for diffVersions, load/save
  versions, writeGitignore, and ProvisionWIT no-op cases
- Update pkg/wasm/builder.go: call ProvisionWIT before compiler when
  build.builderImages is non-empty
- Update pkg/wasm/builder_go.go: recursive+parallel hasGoGenerateDirective,
  run go generate when //go:generate found; add -wit-package/-wit-world
  boson tinygo flags when wit/ dir present
- Add templates/go-wasi/http/wit/world.wit: static source WIT world
  (package boson:function; world boson includes wasi:http/proxy@0.2.3)
- Rewrite templates/go-wasi/http/function.go: WIT bindings handler via
  wit-bindgen-go generated bindings; pure greet() helper for testability
- Rewrite templates/go-wasi/http/function_test.go: test greet() directly
- Update templates/go-wasi/http/go.mod: go 1.24, tool directive for
  go.bytecodealliance.org/cmd/wit-bindgen-go
- Add templates/go-wasi/http/.gitignore: ignore gen/ and module.wasm
- Update e2e/e2e_wasi_test.go: GoDeploy now expects success with liveness
- Update docs/design/wasi-integration.md: document WIT build pipeline

Assisted-by: 🤖 Claude Sonnet 4.6
Replace atomic.Int32 + manual done channel with sync.WaitGroup to
prevent double-close panic when goroutines finish between WalkDir
callbacks. Move semaphore release inside the acquired path to
prevent deadlock on context cancellation.

Add builder_go_test.go with unit tests for hasGoGenerateDirective
and fileHasGoGenerate, including stress tests exercising the
concurrent fan-out with the race detector.

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
….2.3

wit.go — rewrite WIT provisioning pipeline:
- Download OCI artifacts to temp dir, restructure into flat wit/deps/<pkg>/
- restructureWITDeps: main packages always overwrite, transitive deps
  skip existing dirs (prevents HTTP's stub cli.wit from clobbering full
  CLI package)
- Add copyFile helper; pre-allocate provisioned slice

builder_go.go — fix build pipeline:
- Add runGoModTidy before go generate (template ships without go.sum)
- Fix tinygo -o flag: use relative 'module.wasm' not absolute wasmPath
  (cmd.Dir=root makes -o relative to root, avoiding double-nesting)

manifest.yaml — add builderImages for WASI deps:
- cli: ghcr.io/webassembly/wasi/cli:0.2.3
- http: ghcr.io/webassembly/wasi/http:0.2.3

world.wit — define composite world for TinyGo:
- include wasi:http/proxy@0.2.3 (HTTP handler export)
- include wasi:cli/imports@0.2.3 (TinyGo runtime needs environment,
  filesystem, sockets beyond what proxy provides)

function.go — fix wit-bindgen-go code generation:
- go:generate flags: --world boson --out gen --package-root function/gen
- Fix cm API: Value() not Unwrap(), cm.None/cm.OK not types.None/Ok,
  intermediate vars for pointer receivers, cm.ToList for byte slices,
  ResourceDrop() not Drop()

builder_go_test.go — fix lint: check error returns in test helpers

Regenerated embedded FS and docs.

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
The versionsScriptTemplate was missing knative_serving_wasm_version.
The shell script had stale v0.1.0 while component-versions.json said
v0.2.0, causing the cluster to deploy a controller without
config-runner insecure registries support.

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
- Sort builderImages keys for deterministic iteration order
- Track direct deps to prevent transitive overrides
- Add __WASI_WIT_PROVIDER_MODE config in builderImages
- strict (default): byte-diff is fatal error
- forgiving: same-size skip, larger wins (with warnings)
- Enable forgiving mode for go-wasi template
- Detect auto-fetched vs user-vendored dep dirs

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
On systems with podman-docker installed, /usr/bin/docker is a shell
wrapper that exec's podman. The previous default (CONTAINER_ENGINE=docker)
caused the PID limit fix in cluster.sh to never fire, leading to PID
exhaustion and containerd crashes under WASM workloads.

Now common.sh detects the actual runtime via 'docker --version' output
and falls back to podman when docker is absent.

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
Assisted-by: 🤖 Claude Opus/Sonnet 4.6
- Add Args []string to RunSpec in pkg/functions/function.go
- Map f.Run.Args to spec.Args in pkg/wasm/deployer.go buildWasmModuleSpec
- Add TestDeploy_Args and TestDeploy_Args_Empty to deployer_test.go
- Regenerate schema/func_yaml-schema.json (adds args, NetworkSpec, TcpNetworkSpec, UdpNetworkSpec)
- Document run.args in docs/reference/func_yaml.md

Assisted-by: 🤖 Claude Sonnet 4.6
@knative-prow
Copy link
Copy Markdown

knative-prow bot commented Apr 1, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: cardil
Once this PR has been reviewed and has the lgtm label, please assign dprotaso for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow knative-prow bot requested review from dsimansk and jrangelramos April 1, 2026 18:16
@knative-prow knative-prow bot added the size/XXL 🤖 PR changes 1000+ lines, ignoring generated files. label Apr 1, 2026
@cardil
Copy link
Copy Markdown
Contributor Author

cardil commented Apr 1, 2026

/hold

This should all be already working, but I need to run a review of all the changes.

@knative-prow knative-prow bot added the do-not-merge/hold 🤖 PR should not merge because someone has issued a /hold command. label Apr 1, 2026
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
github.com/blang/semver/v4 v4.0.0
github.com/buildpacks/pack v0.38.2
github.com/cardil/knative-serving-wasm v0.2.0
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rely on my personal WASI runner.

TBD what to do with it...

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 1, 2026

Codecov Report

❌ Patch coverage is 57.44337% with 789 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.05%. Comparing base (67c3fd2) to head (cecff33).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
pkg/wasm/wit.go 16.25% 299 Missing and 5 partials ⚠️
pkg/wasm/deployer.go 64.58% 108 Missing and 17 partials ⚠️
pkg/wasm/builder_go.go 36.94% 96 Missing and 3 partials ⚠️
pkg/wasm/oci.go 55.76% 35 Missing and 11 partials ⚠️
pkg/wasm/builder_rust.go 52.94% 35 Missing and 5 partials ⚠️
pkg/functions/registry.go 81.81% 22 Missing and 8 partials ⚠️
pkg/wasm/remover.go 60.78% 16 Missing and 4 partials ⚠️
pkg/wasm/describer.go 70.96% 15 Missing and 3 partials ⚠️
pkg/wasm/builder.go 74.62% 14 Missing and 3 partials ⚠️
pkg/wasm/lister.go 69.81% 12 Missing and 4 partials ⚠️
... and 15 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3560      +/-   ##
==========================================
- Coverage   56.13%   54.05%   -2.09%     
==========================================
  Files         180      202      +22     
  Lines       20465    22220    +1755     
==========================================
+ Hits        11489    12010     +521     
- Misses       7781     9033    +1252     
+ Partials     1195     1177      -18     
Flag Coverage Δ
e2e 34.64% <22.24%> (-1.47%) ⬇️
e2e go 31.44% <22.45%> (-1.11%) ⬇️
e2e node 27.60% <21.54%> (-0.77%) ⬇️
e2e python 31.77% <22.45%> (-1.15%) ⬇️
e2e quarkus 27.71% <21.54%> (-0.78%) ⬇️
e2e rust 27.15% <20.35%> (-0.76%) ⬇️
e2e springboot 25.62% <19.22%> (-0.74%) ⬇️
e2e typescript 27.70% <21.54%> (-0.80%) ⬇️
e2e-wasi 22.12% <39.64%> (?)
integration ?
unit macos-14 42.53% <34.47%> (-0.84%) ⬇️
unit macos-latest 42.53% <34.47%> (-0.84%) ⬇️
unit ubuntu-24.04-arm 42.81% <35.38%> (-0.76%) ⬇️
unit ubuntu-latest 43.35% <34.47%> (-0.91%) ⬇️
unit windows-latest 42.55% <34.47%> (-0.83%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

cardil added 3 commits April 2, 2026 11:10
Use json.Decoder token parsing to verify key ordering from raw
JSON bytes instead of iterating a map (non-deterministic in Go).

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
The Knative Configuration may not have created its first Revision
yet during cold-start, reporting Ready=False with Reason=RevisionMissing.
This is a transient condition (like ServiceUnavailable) that resolves
once the backing ksvc boots. Treating it as terminal causes false
deploy failures in CI.

Assisted-by: 🤖 Claude Opus/Sonnet 4.6
@knative-prow-robot
Copy link
Copy Markdown

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@knative-prow-robot knative-prow-robot added the needs-rebase Cannot be merged due to conflicts with HEAD. label Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/hold 🤖 PR should not merge because someone has issued a /hold command. needs-rebase Cannot be merged due to conflicts with HEAD. size/XXL 🤖 PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants