Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,15 @@ jobs:
uses: polymorph-components/polymorph-test/actions/setup@b4026866e481ead0738742e3b380601b605e5350
with:
js-locks: |
conformance/driver-ct/jco/package-lock.json
conformance/driver-ct/deltic/package-lock.json
- name: Set up Deno (the deltic-deno and deltic-browser legs; stock, no flags)
- name: Set up Node 24 (the jco-node legs; JSPI)
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
cache-dependency-path: conformance/driver-ct/jco/package-lock.json
- name: Set up Deno (the deltic-deno legs; stock, no flags)
uses: denoland/setup-deno@v2
with:
deno-version: "2.9.5"
Expand All @@ -123,8 +130,12 @@ jobs:
results: |
composed=conformance/driver-ct/results/composed.jsonl
composed-delegated=conformance/driver-ct/results/composed-delegated.jsonl
jco-node=conformance/driver-ct/results/jco-node.jsonl
jco-node-delegated=conformance/driver-ct/results/jco-node-delegated.jsonl
deltic-deno=conformance/driver-ct/results/deltic-deno.jsonl
deltic-deno-delegated=conformance/driver-ct/results/deltic-deno-delegated.jsonl
jco-browser=conformance/driver-ct/results/jco-browser.jsonl
jco-browser-delegated=conformance/driver-ct/results/jco-browser-delegated.jsonl
deltic-browser=conformance/driver-ct/results/deltic-browser.jsonl
deltic-browser-delegated=conformance/driver-ct/results/deltic-browser-delegated.jsonl
summary-title: Conformance matrix
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/target
/conformance/driver-ct/results/
/conformance/driver-ct/jco/node_modules/
/conformance/driver-ct/jco/generated/
conformance/driver-ct/deltic/node_modules/
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ design record.
| --- | --- |
| `just check` | fmt, clippy (all features), workspace tests (RFC 9001 vectors, profile/provider pinning, class-D key rejection), wasm build |
| `just ci` | every gating CI job's body, exactly as CI runs it — each CI job runs one gha:: job recipe (.github/justfile). The timing lab is schedule-only and excluded |
| `just conformance` | the cross-implementation conformance suite (see `conformance/README.md`): the shared guest suite composed with each delivery — the `tls` world's in-guest Ed25519 posture and the `tls-delegated` world with the fixture signer — run under the pinned component-test runner and, runtime-linked under deltic (release-pinned in `conformance/driver-ct/deltic/`), on stock Deno (the deltic-deno targets — no transpile, no engine flag) and in headless Chromium (the deltic-browser targets; CI or CONFORMANCE_BROWSER=1), with import-satisfaction and signer-reachability gates, validated against the committed case inventory (`tests.lock`) and target manifest, and diffed against the committed matrix. `just conformance-ct::run-webcrypto` (on demand: clones the sibling repo) adds the delegated posture over a real `polymorph:webcrypto` provider. jco-based targets (jco-node, transpiled under Node 24 JSPI; jco-browser) were removed — jco coverage is retained family-wide only in `polymorph:webcrypto` |
| `just conformance` | the cross-implementation conformance suite (see `conformance/README.md`): the shared guest suite composed with each delivery — the `tls` world's in-guest Ed25519 posture and the `tls-delegated` world with the fixture signer — run under the pinned component-test runner, transpiled under Node 24 JSPI (the jco-node targets), runtime-linked under deltic on stock Deno (the deltic-deno targets — no transpile, no engine flag; release-pinned in `conformance/driver-ct/deltic/`), and in headless Chromium (the jco-browser targets; CI or CONFORMANCE_BROWSER=1), with import-satisfaction and signer-reachability gates, validated against the committed case inventory (`tests.lock`) and target manifest, and diffed against the committed matrix. `just conformance-ct::run-webcrypto` (on demand: clones the sibling repo) adds the delegated posture over a real `polymorph:webcrypto` provider |
| `just smoke-quic` | QUIC over `wasi:sockets` UDP under Wasmtime |
| `just smoke-tls-virt` | both tls-virt deliveries against `openssl s_server` over real TCP (needs openssl + python3): the composed guest virtualizer (handle-address and import-satisfaction gates), and the wasmtime host provider on both sockets generations — wasip3 and `std::net`/0.2 guests — with handle-address and profile-cipher-suite gates plus plain-TCP passthrough-delegation legs |
| `just interop` | cross-implementation, over real transports, fresh Ed25519 private PKI per run: the composed TLS component against OpenSSL and Go peers over TCP in both directions (including the close_notify-vs-truncation and reset scenarios), and the noq leg against quic-go over UDP in both directions |
Expand Down
11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ futures = { version = "0.3", default-features = false, features = ["std", "async

# The conformance stack, pinned to one revision everywhere it appears:
# this rev, the `component-test`/`ct-runner` installs derived from
# Cargo.lock by `conformance/driver-ct/justfile`, and the
# `polymorph-test/actions/*@<rev>` refs in ci.yml (the actions fail on
# skew). To bump: `component-test pins bump <rev> --cargo-toml
# Cargo.toml --workflow .github/workflows/ci.yml`, then the follow-ups
# it prints.
# Cargo.lock by `conformance/driver-ct/justfile`, the jco package.json
# pin, and the `polymorph-test/actions/*@<rev>` refs in ci.yml (the
# actions fail on skew). To bump: `component-test pins bump <rev>
# --cargo-toml Cargo.toml --package-json
# conformance/driver-ct/jco/package.json --workflow
# .github/workflows/ci.yml`, then the follow-ups it prints.
component-test-sdk = { git = "https://github.com/polymorph-components/polymorph-test", rev = "b4026866e481ead0738742e3b380601b605e5350" }

aead = { version = "0.6", default-features = false, features = ["alloc"] }
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ two deliveries, and the QUIC compatibility layer exist; they pass a
cross-implementation [conformance suite](conformance/README.md) on the
[`polymorph:test`](https://github.com/polymorph-components/polymorph-test)
harness (one shared guest suite against every composed delivery, under
Wasmtime and, runtime-linked via deltic, under stock Deno and in
headless Chromium),
Wasmtime, under Node/jco via JSPI, and in headless Chromium),
cross-implementation interop against OpenSSL, Go `crypto/tls`, and
quic-go over real transports, and a scheduled dudect-style
[timing lab](timing-lab/README.md), with the performance tradeoff
Expand Down
24 changes: 11 additions & 13 deletions conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,39 @@ guest-ct/ the suite: cases on the polymorph:test contract, the
polymorph:tls surface imported as a consumer would;
tests.lock is the committed case inventory
driver-ct/ target manifest (targets.toml), the recipes
(justfile, module `conformance-ct`), the deltic
driver (deltic/), the committed matrix (matrix.md);
(justfile, module `conformance-ct`), the jco-node
driver (jco/), the committed matrix (matrix.md);
results/ is generated
```

`just conformance` (from the repository root) runs the standing
matrix: build, inventory check, the wasmtime and deltic targets under
matrix: build, inventory check, the wasmtime and Node targets under
the pinned tooling, aggregate, and the committed-matrix diff.

## Targets

A target is a composition, not a runtime configuration: the suite is
`wac plug`-ged with one TLS stack, and the resulting artifact imports
only wasi and `polymorph:test/test-context`. The wasmtime rows run
under the generic component-test host runner; the deltic rows run the
same artifacts runtime-linked (no transpile step) on stock Deno or
inside headless Chromium — one suite, one composition, multiple
engines.
under the generic component-test host runner; the jco rows transpile
the same artifacts (`-I async`, the lann/jco all-fixes pre-release
pinned in `driver-ct/jco/package.json`) and run them under Node 24
JSPI — one suite, one composition, two engines.

| Target | Composition |
| --- | --- |
| `composed` | the `tls` world build: in-guest Ed25519 signing only |
| `composed-delegated` | the `tls-delegated` world build ⊕ the fixture signer (`examples/test-signer`) |
| `composed-delegated-webcrypto` | as above, but the signer is the `examples/webcrypto-signer` shim over a real `polymorph:webcrypto` provider; on demand (`just conformance-ct::run-webcrypto`), declared `optional` |
| `jco-node` | the `composed` artifact, transpiled, under Node 24 JSPI |
| `jco-node-delegated` | the `composed-delegated` artifact, likewise |
| `deltic-deno` | the `composed` artifact runtime-linked under deltic on stock Deno (no transpile, no engine flag) |
| `deltic-deno-delegated` | the `composed-delegated` artifact, likewise |
| `jco-browser` | the `composed` artifact inside headless Chromium (the upstream page driver; gates in CI, locally `CONFORMANCE_BROWSER=1`; declared `optional`) |
| `jco-browser-delegated` | the `composed-delegated` artifact, likewise |
| `deltic-browser` | the `composed` artifact runtime-linked inside headless Chromium (gates in CI, locally `CONFORMANCE_BROWSER=1`; declared `optional`) |
| `deltic-browser-delegated` | the `composed-delegated` artifact, likewise |

jco-node and jco-browser targets ran the same compositions transpiled
under Node 24 JSPI and in headless Chromium via jco; they were removed
as jco support was retired from this repository (retained
family-wide only in `polymorph:webcrypto`), superseded by the deltic
targets above.

In-suite QUIC cases are
[#29](https://github.com/polymorph-components/polymorph-tls/issues/29).

Expand Down
4 changes: 2 additions & 2 deletions conformance/driver-ct/deltic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ The deltic leg of the conformance matrix: the composed artifacts
(`suite-plain`, `suite-delegated`) run **runtime-linked** under
[deltic](https://github.com/lann/deltic) on stock Deno — no transpile
step, no generated tree, no `--experimental-wasm-jspi` (the WIT
contract's async exports run on the callback ABI). Targets `deltic-deno`
and
contract's async exports run on the callback ABI). The deltic analogue
of `../jco/run-node.mjs`; targets `deltic-deno` and
`deltic-deno-delegated` in `../targets.toml`.

There is no SUT host module on this leg (the TLS delivery is fused
Expand Down
5 changes: 2 additions & 3 deletions conformance/driver-ct/deltic/run-browser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
// pinned deltic-embedder.mjs release asset and links the suite in the
// browser: no transpile step, no generated tree. This file is the frame:
// asset URL wiring, target configuration, and results-file writing —
// the browser sibling of ../deltic/run.ts, mirroring the frame the
// former jco-based run-browser.mjs used for its own run-node.mjs
// sibling before the jco legs were removed.
// the browser sibling of ../deltic/run.ts exactly as ../jco/run-browser.mjs
// is the browser sibling of ../jco/run-node.mjs.
//
// The artifacts import only wasi 0.2 and test-context, so there is no
// SUT host module on this leg and the stock upstream worker serves it
Expand Down
6 changes: 3 additions & 3 deletions conformance/driver-ct/deltic/run.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// The deltic leg of the conformance harness: runs a composed artifact
// (the shared suite fused with one TLS delivery) runtime-linked under
// deltic on stock Deno, and writes component-test results JSONL for the
// aggregate. Its frame mirrored the former jco-based run-node.mjs
// (removed with the jco legs) exactly:
// aggregate — the deltic analogue of ../jco/run-node.mjs, mirroring its
// frame exactly:
//
// run-node.mjs (removed) | this runner
// run-node.mjs | this runner
// --------------------------------------+---------------------------
// jco transpile + loadCoreModules | translator.translate(bytes)
// bindImports (preview2-shim, both | wasiShims() (track-keyed:
Expand Down
20 changes: 20 additions & 0 deletions conformance/driver-ct/jco/browser-imports.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// The browser worker's import-object module: loaded by the upstream
// browser-worker via URL (module workers cannot see import maps), so
// every specifier here is a server path — the harness core through the
// driver's self-mount, the wasi shims through this tree's
// node_modules, both served over the repository-root server.
import { bindImports } from "/__component-test/js/viewer/imports.mjs";
import * as cli from "./node_modules/@bytecodealliance/preview2-shim/dist/browser/cli.js";
import * as clocks from "./node_modules/@bytecodealliance/preview2-shim/dist/browser/clocks.js";
import * as io from "./node_modules/@bytecodealliance/preview2-shim/dist/browser/io.js";
import * as random from "./node_modules/@bytecodealliance/preview2-shim/dist/browser/random.js";
import * as filesystem from "./node_modules/@bytecodealliance/preview2-shim/dist/browser/filesystem.js";

/** The composed artifacts import only wasi 0.2 and test-context; wasi
* minors differ across the fused halves, so both spellings bind. */
export async function suiteImports() {
return bindImports({
wasi: { cli, clocks, io, random, filesystem },
wasiVersions: ["0.2.0", "0.2.6"],
});
}
87 changes: 87 additions & 0 deletions conformance/driver-ct/jco/jco-transpile.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/usr/bin/env node
// Vendored from polymorph-test (js/jco-transpile.mjs at 2436bb9, deleted
// there when that repo went jco-free): a thin CLI over
// @bytecodealliance/jco-transpile, covering the two jco
// commands the conformance consumers use: `transpile` (component to ES
// module) and `types` (host-side type definitions for a WIT world).
// jco-transpile is the transpilation half of jco, published without
// the componentization toolchain (componentize-js, weval) that the
// full jco CLI drags in and nothing here runs.
//
// The library is resolved from the invoking package's node_modules —
// each consumer pins its own toolchain version — so this bin must run
// with the consumer's package directory as the working directory,
// which is how package.json scripts invoke it.
//
// The option spellings match the jco CLI's, and the library applies
// the same defaults the CLI did (name derivation, the wasi-shim map
// entries, output-path prefixing), so the generated trees are
// bit-identical to `jco transpile` / `jco types` output for these
// invocations.

import { createRequire } from "node:module";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { parseArgs } from "node:util";

const require = createRequire(join(process.cwd(), "package.json"));
const { transpile, generateHostTypes, writeFiles } = await import(
pathToFileURL(require.resolve("@bytecodealliance/jco-transpile")).href
);

const [command, path, ...rest] = process.argv.slice(2);
const { values } = parseArgs({
args: rest,
options: {
name: { type: "string" },
"async-mode": { type: "string" },
instantiation: { type: "string", short: "I" },
map: { type: "string", multiple: true },
"world-name": { type: "string" },
"out-dir": { type: "string", short: "o" },
// Never answer an async-lowered import with a bare RETURNED status;
// required for componentize-js guests, whose lowering does not
// implement the returned-immediately case (see the option's doc in
// jco-transpile).
"no-eager-subtask-return": { type: "boolean" },
// `types` only: WIT `@unstable` gates to enable, like `jco types
// --feature` (repeatable).
feature: { type: "string", multiple: true },
},
});

switch (command) {
case "transpile": {
const map = Object.fromEntries(
(values.map ?? []).map((entry) => {
const eq = entry.indexOf("=");
if (eq === -1) {
throw new Error(`--map entry has no '=': ${entry}`);
}
return [entry.slice(0, eq), entry.slice(eq + 1)];
}),
);
const { files } = await transpile(path, {
name: values.name,
asyncMode: values["async-mode"],
instantiation: values.instantiation,
map,
outDir: values["out-dir"],
noEagerSubtaskReturn: values["no-eager-subtask-return"],
});
await writeFiles(files);
break;
}
case "types": {
const files = await generateHostTypes(path, {
worldName: values["world-name"],
asyncMode: values["async-mode"],
outDir: values["out-dir"],
features: values.feature,
});
await writeFiles(files);
break;
}
default:
throw new Error(`unknown command: ${command} (expected transpile or types)`);
}
Loading
Loading