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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ jobs:
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"
- name: Install just, wasm-tools, and wac
# wac-cli has no install-action manifest; the action falls back to
# cargo-binstall for it, which resolves releases through
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ design record.
| Recipe | Verifies |
| --- | --- |
| `just check` | fmt, clippy (all features), workspace tests (RFC 9001 vectors, profile/provider pinning, class-D key rejection), wasm build |
| `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), 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 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
2 changes: 2 additions & 0 deletions conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ JSPI — one suite, one composition, two engines.
| `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 |

Expand Down
37 changes: 37 additions & 0 deletions conformance/driver-ct/deltic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# conformance/driver-ct/deltic

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). 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
in-guest, the artifacts import only wasi 0.2 and test-context), so the
whole import surface is deltic's own `wasiShims()` + its runner-supplied
`test-context`. Tag scheduling reads the suite's embedded
`component-test:tags@0.1` inventory (it survives wac composition);
`--missing` mirrors `targets.toml` per target.

```sh
just conformance-ct::run-deltic # suite-plain -> deltic-deno
just conformance-ct::run-deltic-delegated # suite-delegated -> deltic-deno-delegated
```

The on-demand webcrypto composition (`suite-delegated-webcrypto`) runs
under deltic the same way — deltic's own repo smokes it
(`tools/smoke-tls`) — but like the wasmtime row it is not a standing
target here.

## Pinning

deltic is pinned to a release tag in `deno.json` (import-map URLs;
`deno.lock` carries the module-graph integrity, enforced with
`--frozen`) and `fetch-translator.ts` (TAG + sha256 for the
`deltic-translator-shim.wasm` release asset, cached under
`target/deltic/<tag>/`), cross-checked at run time. To bump: update the
tag in both files and the sha from the release's `SHA256SUMS`, delete
`deno.lock`, re-run `deno cache run.ts fetch-translator.ts` here, and
commit the diff.
12 changes: 12 additions & 0 deletions conformance/driver-ct/deltic/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"//": "The deltic release pin (TAG in fetch-translator.ts must match; its assertPinConsistency checks). @deltic/runtime/embedder is mapped because wasi-shims imports it by bare specifier internally.",
"imports": {
"@deltic/ct-runner": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/ct-runner/src/mod.ts",
"@deltic/runtime/embedder": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/embedder/mod.ts",
"@deltic/runtime/shim": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/runtime/src/shim/mod.ts",
"@deltic/wasi-shims": "https://raw.githubusercontent.com/lann/deltic/pre-83fff30/wasi-shims/src/mod.ts"
},
"tasks": {
"check": "deno check run.ts fetch-translator.ts"
}
}
66 changes: 66 additions & 0 deletions conformance/driver-ct/deltic/deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 86 additions & 0 deletions conformance/driver-ct/deltic/fetch-translator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Fetch (and cache) the deltic translator-shim wasm for the pinned release.
//
// deltic is a runtime linker: components are translated by a wasm build of
// its translator, shipped as a release asset so consumers need no Rust
// toolchain. This script downloads that asset once into target/deltic/,
// verifies it against the pinned sha256, and prints the cached path on
// stdout (the `conformance-ct::run-deltic*` recipes capture it).
//
// THE PIN lives here (TAG + TRANSLATOR_SHA256) and in the sibling
// deno.json's import-map URLs. `assertPinConsistency` fails loud if the
// two drift. Bumping: update TAG here and in deno.json, update
// TRANSLATOR_SHA256 from the release's SHA256SUMS, delete deno.lock, and
// re-run `deno cache run.ts fetch-translator.ts` in this directory to
// regenerate it (commit the diff).

const TAG = "pre-83fff30";
const TRANSLATOR_SHA256 =
"6d02b363785593595a789d083cda0aebb1de790726718ccf543198354fa3870c";
const ASSET = "deltic-translator-shim.wasm";

const HERE = new URL(".", import.meta.url);
const REPO_ROOT = new URL("../../../", HERE);
const CACHE_DIR = new URL(`target/deltic/${TAG}/`, REPO_ROOT);
const CACHED = new URL(ASSET, CACHE_DIR);
const RELEASE_URL =
`https://github.com/lann/deltic/releases/download/${TAG}/${ASSET}`;

async function sha256Hex(bytes: Uint8Array): Promise<string> {
const digest = await crypto.subtle.digest(
"SHA-256",
bytes as BufferSource,
);
return Array.from(new Uint8Array(digest))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}

/** The one-pin-everywhere gate: every raw.githubusercontent URL in the
* sibling import map must reference TAG. */
async function assertPinConsistency(): Promise<void> {
const denoJson = await Deno.readTextFile(new URL("deno.json", HERE));
const urls = denoJson.match(/https:\/\/raw\.githubusercontent\.com[^"]+/g) ?? [];
if (urls.length === 0) {
throw new Error("deno.json: no pinned deltic URLs found");
}
for (const url of urls) {
if (!url.includes(`/lann/deltic/${TAG}/`)) {
throw new Error(
`pin drift: deno.json pins ${url}\nbut fetch-translator.ts pins ${TAG}`,
);
}
}
}

async function main() {
await assertPinConsistency();

try {
const bytes = await Deno.readFile(CACHED);
if (await sha256Hex(bytes) === TRANSLATOR_SHA256) {
console.log(CACHED.pathname);
return;
}
console.error(`cached ${ASSET} has a stale digest; re-fetching`);
} catch {
// not cached yet
}

console.error(`fetching ${RELEASE_URL} …`);
const resp = await fetch(RELEASE_URL);
if (!resp.ok) {
throw new Error(`GET ${RELEASE_URL}: ${resp.status} ${resp.statusText}`);
}
const bytes = new Uint8Array(await resp.arrayBuffer());
const got = await sha256Hex(bytes);
if (got !== TRANSLATOR_SHA256) {
throw new Error(
`sha256 mismatch for ${ASSET}@${TAG}:\n want ${TRANSLATOR_SHA256}\n got ${got}`,
);
}
await Deno.mkdir(CACHE_DIR, { recursive: true });
await Deno.writeFile(CACHED, bytes);
console.log(CACHED.pathname);
}

await main();
Loading
Loading