feat(http): astrid:[email protected] — per-request control, streaming uploads, trailers#17
Merged
Conversation
validate-wit.sh collapsed every version of a package into one deps/astrid-<pkg> dir. wasm-tools treats a deps directory as a single package, so the first second-version (astrid:[email protected] alongside @1.0.0) made every validation fail with 'package identifier does not match previous package name'. Key each staged dep dir by the full name@version so coexisting versions resolve independently.
…loads, trailers Additive successor to astrid:[email protected] (frozen, untouched). Adds an all-optional request-options record (per-request connect/first-byte/between-bytes/total timeouts, redirect policy with mandatory per-hop airlock re-validation, response/decompression size caps, auto-decompress toggle, https-only, subresource integrity), response-meta on the buffered response (final URL, redirect count, timing, wire bytes), a streaming request body via the http-upload resource (mirrors wasi:http outgoing-body), and http-stream.trailers for gRPC-web. An empty request-options reproduces @1.0.0 exactly, so the host backs both from one impl. SSRF-sensitive knobs (custom DNS, resolve overrides, proxy, source binding, TLS-verification bypass) are excluded by construction. Design record: RFC #22 (host_abi).
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
Pull request overview
Adds the next additive HTTP host ABI version (astrid:[email protected]) and updates local WIT validation tooling/docs so both [email protected] and [email protected] can coexist and validate cleanly.
Changes:
- Introduces
host/[email protected]with per-request options, response metadata, streaming uploads, trailers, and new error codes. - Updates
scripts/validate-wit.shto stage eachname@versioninto its own deps subdirectory to avoid wasm-tools multi-version conflicts. - Documents the new HTTP ABI version in the README host ABI table.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
scripts/validate-wit.sh |
Stages each WIT version into a separate deps directory so wasm-tools can validate multi-version packages. |
README.md |
Adds host/[email protected] to the host ABI table with a feature summary. |
host/[email protected] |
Defines the new astrid:[email protected] contract: request options, response meta, streaming upload resource, trailers, and expanded error codes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Per Copilot review on PR #17: the header said every @1.0.0 type was carried forward unchanged, but http-response-data/http-stream/error-code are extended — reworded to state the request shape and function signatures are preserved while the surface is extended. Also hoist the staged dep-dir path into a local in validate-wit.sh (computed twice).
joshuajbouw
added a commit
to astrid-runtime/astrid
that referenced
this pull request
Jun 24, 2026
## Linked Issue Closes #1049 ## Summary Registers `astrid:[email protected]` in the wasmtime linker alongside the frozen `@1.0.0` and implements its host side, backing both versions from one shared implementation. Delivers the kernel half of the per-request-timeout work (#1012): caller-set per-request controls on the HTTP client, with the redirect/SSRF airlock strengthened to re-validate every hop. The contract landed in astrid-runtime/wit#17; this bumps the `wit` submodule to pick it up (which also carries the unrelated `astrid-bus:[email protected]` contract — a bus interface that doesn't touch the host linker). ## Changes - **Dual-version registration.** `bindings.rs` imports `astrid:http/[email protected]` into the kernel world; the single `Kernel::add_to_linker` auto-registers both versions (corrected the stale 'add a second call' doc comment). Both generate version-suffixed modules (`http1_0_0` / `http1_1_0`); `HostState` impls both versions' traits. - **`build.rs` multi-version WIT staging.** `astrid:http` is the first host package with two versions; wasmtime's bindgen (like `wasm-tools`) rejects two versions in one `deps/` dir, so each staged dep dir is now keyed by `name@version`. Regenerated `wit-staging/` accordingly (the committed-tree dirty-check gate is satisfied). - **`@1.1.0` host impl** (`host/http/{mod,backend,options,ssrf,tests}.rs`, split for the 1000-line cap): the `request-options` surface — four-phase timeouts, redirect policy, response/decompression caps, `auto-decompress`, `https-only`, SRI integrity — plus `response-meta` on every buffered response. The `@1.0.0` `http-request`/`http-stream-start` are thin shims reproducing prior behaviour exactly and delegating to the same backend. - **Security — per-hop redirect re-validation on both paths.** Redirects are followed MANUALLY by the host (reqwest never auto-follows), so every hop re-runs scheme + the async per-capsule allow-list gate + the egress airlock, strips `Authorization`/`Cookie` cross-origin, and blocks IP-literal targets. This closes a redirect-SSRF gap on the **streaming** path where the async gate previously ran only on the initial URL (the IP airlock already ran per hop). reqwest's sync redirect-policy machinery was removed. - **Deferred (honest stubs, not silent gaps):** `http-upload` streaming request body (returns a typed not-implemented error), response `trailers` (returns `none`), and un-stubbing the stream pollable/`body-stream`. Tracked as follow-ups. ## Verification - `cargo build --workspace`, `cargo clippy --workspace --all-features -- -D warnings` (0), `cargo test --workspace` (0 failures), `cargo fmt --all --check`: green. 33 `http` tests (verified locally), including end-to-end tests over the real backend: per-hop async-gate enforcement on the streaming path (`streaming_request_runs_async_gate_per_hop`), exempt-endpoint no-follow (buffered + streaming), IP-literal redirect blocking, scheme/integrity/credential-strip, and the `@1.0.0`-reproduction shim. - **Adversarial security review (on the diff):** confirmed every redirect hop — buffered and streaming — re-validates through the async gate before connecting; `max-response-bytes` is clamped to the host ceiling (a caller cannot raise the buffered cap); `check_scheme` blocks `file:`/`data:`/`ws:`; the release binary never reads the test-only SSRF bypass. - **One accepted behaviour refinement:** the `@1.0.0` shim returns `too-many-redirects` on >10-hop chains where old reqwest returned the last 3xx response — a pathological redirect-loop edge case where erroring is the more correct outcome. ## Checklist - [x] Linked to an issue - [x] CHANGELOG.md updated (entry under `[Unreleased]`)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
host/[email protected], the first additive successor in the host ABI.astrid:[email protected]stays frozen and untouched;@1.1.0is a self-contained superset the kernel registers alongside@1.0.0, so existing capsules are unaffected and new ones opt in package-by-package.Design record: RFC #22 (host_abi) — see the
### HTTP: per-request control and streaming uploadssection.What @1.1.0 adds
request-options(all-optional; an empty value reproduces@1.0.0exactly): four-phase timeouts (connect/first-byte/between-bytes/total), redirect policy (follow/error/manual) +max-redirects,max-response-bytes,max-decompressed-bytes,auto-decompress,https-only,integrity(SRI).response-metaon the buffered response — final URL after redirects, redirect count, elapsed ms, wire bytes.http-uploadresource (body-sink→output-stream,finish→ response stream); mirrors thewasi:httpoutgoing-body pattern.http-stream.trailersfor gRPC-web.error-codearms:redirect-blocked,too-many-redirects,integrity-mismatch,scheme-denied,decompression-bomb.http-request-opts/http-stream-start-opts/http-upload-start; the plain@1.0.0-shapedhttp-request/http-stream-startare carried forward (they equal the-optscalls with defaulted options).Security posture
The SSRF airlock owns DNS resolution and the connect path. Knobs that would let a guest influence either are excluded by construction — no field for custom resolvers,
resolve/resolve-to-addrs, proxy, source-address/interface binding, or TLS-verification bypass. Conversely@1.1.0strengthens the airlock: redirectfollowmust re-validate everyLocationhop and stripAuthorization/Cookiecross-origin (default policy for untrusted capsules iserror), andhttps-only/ scheme restriction / SRI / a decompressed-size ceiling are added as security-positive controls.Tooling
scripts/validate-wit.shcollapsed every version of a package into onedeps/astrid-<pkg>dir; since wasm-tools treats a deps dir as a single package, the first second-version broke all validation. Fixed to key each staged dep byname@version. First commit; isolated from the contract.Validation
scripts/validate-wit.shpasses all 14 host files (incl. both[email protected]and[email protected]). New file only — frozen-file discipline satisfied by construction.Follow-on (separate PRs, after this lands on main)
Per the pin rule (land on main first; squash rewrites SHAs): core registers
@1.1.0+ shared host impl with the@1.0.0shim → sdk-rust mirrors + adds theRequestoptions surface → capsule-openai-compat adopts it for fast-fail/v1/modelsdiscovery.