Skip to content

feat(binary-object): admit ordinary push_this #426

feat(binary-object): admit ordinary push_this

feat(binary-object): admit ordinary push_this #426

Workflow file for this run

name: Engine CI
on:
pull_request:
push:
branches: [main]
schedule:
- cron: "23 9 * * *"
- cron: "47 18 * * *"
workflow_dispatch:
inputs:
tier:
description: Validation tier to run
required: true
default: fast
type: choice
options:
- fast
- quickjs-differential
- test262-full
- test262-receipt
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: "1"
RUST_VERSION: "1.88.0"
jobs:
fast:
if: >-
github.event_name == 'pull_request' ||
github.event_name == 'push' ||
(github.event_name == 'workflow_dispatch' && inputs.tier == 'fast')
runs-on: ubuntu-latest
timeout-minutes: 300
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Install pinned Rust toolchain
run: |
rustup toolchain install "${RUST_VERSION}" --profile minimal --component rustfmt,clippy
rustup default "${RUST_VERSION}"
- name: Install gate dependencies
run: |
sudo apt-get update
sudo apt-get install --yes ripgrep
- name: Cache Cargo inputs
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-cargo-${{ env.RUST_VERSION }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-${{ env.RUST_VERSION }}-
- name: Check formatting and architecture gates
run: |
cargo fmt --all -- --check
./scripts/check-binary-object-boundary.sh
./scripts/check-no-test262-special-casing.sh
node scripts/check-test262-artifact-inventory.mjs
node scripts/check-bc5-pinned-atoms.mjs --self-test
node scripts/check-bc5-pinned-opcodes.mjs --self-test
node --check scripts/audit-negative-diagnostics.mjs
node --check scripts/test-negative-diagnostic-generator.mjs
node --check scripts/generate-test262-dynamic-import-a.mjs
node --check scripts/generate-test262-tla-core-a.mjs
node --check scripts/generate-test262-tla-b.mjs
node --check scripts/test-generate-test262-tla-b.mjs
node --check scripts/generate-test262-module-var-lexical-shadow-a.mjs
node --check scripts/generate-test262-module-local-binding-a.mjs
node --check scripts/generate-test262-module-import-attributes-a.mjs
node --check scripts/test-generate-test262-module-import-attributes-a.mjs
node --check scripts/generate-test262-module-json-a.mjs
node --check scripts/test-generate-test262-module-json-a.mjs
./scripts/check-oracle-registry.sh
./scripts/test-quickjs-fixtures.sh --validate
./scripts/test-quickjs-c-oracles.sh --validate
./scripts/test-quickjs-dynamic-import-trace.sh --validate
./scripts/check-test262-host-boundary.sh
./scripts/test-test262.sh --spec dev-support/test262/current.conf --check
./scripts/test-test262.sh --spec dev-support/test262/current.conf --runner-provenance
node scripts/current-test262-metrics.mjs --check-docs
./scripts/check-rust-only.sh
- name: Run fast engine tests
run: |
cargo test --locked --workspace --lib --bins
cargo test --locked -p quickjs-oxide --features test262-host --lib --bins
cargo test --locked --test cli
cargo test --locked --test oracle
cargo test --locked --features test262-host \
--test unsupported_diagnostics
cargo test --locked --features test262-host \
--test oracle test262_
./scripts/check-oracle-registry.sh --compiled
- name: Lint production targets
run: |
cargo clippy --locked --workspace --lib --bins -- -D warnings
cargo clippy --locked --test oracle -- -D warnings
cargo clippy --locked -p quickjs-oxide --features test262-host \
--lib --bins -- -D warnings
cargo clippy --locked -p quickjs-oxide --features test262-host \
--test unsupported_diagnostics --test oracle \
-- -D warnings
quickjs-differential:
if: >-
(github.event_name == 'schedule' && github.event.schedule == '23 9 * * *') ||
(github.event_name == 'workflow_dispatch' && inputs.tier == 'quickjs-differential')
runs-on: ubuntu-latest
timeout-minutes: 180
env:
QJS_ORACLE_CACHE: ${{ github.workspace }}-oracle-cache
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install pinned Rust toolchain
run: |
rustup toolchain install "${RUST_VERSION}" --profile minimal
rustup default "${RUST_VERSION}"
- name: Install oracle dependencies
run: |
sudo apt-get update
sudo apt-get install --yes build-essential curl git ripgrep xz-utils
- name: Restore authenticated input caches
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.cargo/registry
~/.cargo/git
${{ github.workspace }}-oracle-cache
key: >-
${{ runner.os }}-differential-${{ env.RUST_VERSION }}-${{
hashFiles('Cargo.lock', 'compat/upstream.toml',
'scripts/build-quickjs-oracle.sh', 'scripts/prepare-test262.sh') }}
restore-keys: |
${{ runner.os }}-differential-${{ env.RUST_VERSION }}-
- name: Run the pinned QuickJS differential corpus
run: |
oracle_source=$(./scripts/build-quickjs-oracle.sh --test262-oracles)
oracle="$oracle_source/qjs"
node scripts/check-bc5-pinned-atoms.mjs \
--source "$oracle_source/quickjs-atom.h"
node scripts/check-bc5-pinned-opcodes.mjs \
--source "$oracle_source/quickjs-opcode.h"
QJS_ORACLE_ARCHIVE_FIXTURE="$QJS_ORACLE_CACHE/quickjs-2026-06-04.tar.xz" \
./scripts/test-build-quickjs-oracle-cache.sh
QJS_ORACLE_ARCHIVE="$QJS_ORACLE_CACHE/quickjs-2026-06-04.tar.xz" \
./scripts/test-quickjs-dynamic-import-trace.sh
suite=$(./scripts/prepare-test262.sh)
node scripts/generate-test262-dynamic-import-a.mjs \
--suite "$suite" --check-current
node scripts/generate-test262-tla-core-a.mjs \
--suite "$suite" --check-current
node scripts/test-generate-test262-tla-b.mjs --suite "$suite"
node scripts/generate-test262-tla-b.mjs \
--suite "$suite" --check-current
node scripts/generate-test262-module-var-lexical-shadow-a.mjs \
--suite "$suite" \
--quickjs-runner "$oracle_source/run-test262" \
--quickjs-config "$oracle_source/test262.conf" \
--check-current
node scripts/generate-test262-module-local-binding-a.mjs \
--suite "$suite" \
--quickjs-runner "$oracle_source/run-test262" \
--quickjs-config "$oracle_source/test262.conf" \
--check-current
node scripts/audit-negative-diagnostics.mjs \
--contracts dev-support/test262/negative-diagnostics.tsv \
--rules dev-support/test262/negative-diagnostic-rules.tsv \
--suite "$suite" --qjs "$oracle"
node scripts/test-generate-test262-module-import-attributes-a.mjs \
--suite "$suite" \
--quickjs-runner "$oracle_source/run-test262" \
--quickjs-config "$oracle_source/test262.conf"
node scripts/generate-test262-module-import-attributes-a.mjs \
--suite "$suite" \
--quickjs-runner "$oracle_source/run-test262" \
--quickjs-config "$oracle_source/test262.conf" \
--check-current
node scripts/test-generate-test262-module-json-a.mjs \
--suite "$suite" \
--quickjs-runner "$oracle_source/run-test262" \
--quickjs-config "$oracle_source/test262.conf"
node scripts/generate-test262-module-json-a.mjs \
--suite "$suite" \
--quickjs-runner "$oracle_source/run-test262" \
--quickjs-config "$oracle_source/test262.conf" \
--check-current
cargo build --locked --bin qjs
node scripts/test-negative-diagnostic-generator.mjs \
--suite "$suite" --qjs "$oracle" --oxide ./target/debug/qjs
./scripts/test-quickjs-fixtures.sh --all --oxide ./target/debug/qjs
./scripts/test-quickjs-c-oracles.sh --check
QJS_ORACLE="$oracle" cargo test --locked --workspace --all-targets \
--features test262-host
test262-full:
if: >-
(github.event_name == 'schedule' && github.event.schedule == '47 18 * * *') ||
(github.event_name == 'workflow_dispatch' &&
(inputs.tier == 'test262-full' || inputs.tier == 'test262-receipt'))
runs-on: ubuntu-latest
timeout-minutes: 350
env:
QJS_ORACLE_CACHE: ${{ github.workspace }}-oracle-cache
TEST262_WORKERS: "2"
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Install pinned Rust toolchain
run: |
rustup toolchain install "${RUST_VERSION}" --profile minimal
rustup default "${RUST_VERSION}"
- name: Install Test262 dependencies
run: |
sudo apt-get update
sudo apt-get install --yes build-essential curl git ripgrep xz-utils
- name: Restore authenticated input caches
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.cargo/registry
~/.cargo/git
${{ github.workspace }}-oracle-cache
key: >-
${{ runner.os }}-test262-${{ env.RUST_VERSION }}-${{
hashFiles('Cargo.lock', 'compat/upstream.toml',
'scripts/build-quickjs-oracle.sh', 'scripts/prepare-test262.sh') }}
restore-keys: |
${{ runner.os }}-test262-${{ env.RUST_VERSION }}-
- name: Check the Test262 receipt boundary
run: ./scripts/check-binary-object-boundary.sh --scan-only .
- name: Run the complete frozen Test262 vector
env:
TEST262_RECEIPT_CAPTURE: >-
${{ github.event_name == 'workflow_dispatch' &&
inputs.tier == 'test262-receipt' }}
run: |
set -o pipefail
set +e
mkdir -p target
./scripts/test-test262.sh --spec dev-support/test262/current.conf --full \
2>&1 | tee target/test262-full.log
pipeline_status=("${PIPESTATUS[@]}")
set -e
test262_status=${pipeline_status[0]}
tee_status=${pipeline_status[1]}
if (( tee_status != 0 )); then
exit "$tee_status"
fi
if (( test262_status == 0 )); then
exit 0
fi
if [[ "$TEST262_RECEIPT_CAPTURE" != true ]] || (( test262_status != 1 )); then
exit "$test262_status"
fi
expected_error="error: full TSV receipt checksum drifted: $PWD/target/test262-full.tsv"
error_count=$(grep -c '^error:' target/test262-full.log || true)
expected_error_count=$(grep -Fxc "$expected_error" target/test262-full.log || true)
if [[ "$error_count" != 1 || "$expected_error_count" != 1 ]]; then
exit "$test262_status"
fi
node --input-type=module <<'NODE'
import { execFileSync } from "node:child_process";
import { createHash } from "node:crypto";
import { lstatSync, readFileSync, realpathSync } from "node:fs";
import { isAbsolute, relative, resolve, sep } from "node:path";
function fail(message) {
throw new Error(`receipt capture rejected: ${message}`);
}
function sha256(bytes) {
return createHash("sha256").update(bytes).digest("hex");
}
function lineCount(bytes, label) {
if (bytes.length === 0 || bytes.at(-1) !== 0x0a) {
fail(`${label} lacks a final newline`);
}
let count = 0;
for (const byte of bytes) if (byte === 0x0a) count += 1;
return count;
}
function utf8(bytes, label) {
const text = bytes.toString("utf8");
if (!Buffer.from(text, "utf8").equals(bytes)) {
fail(`${label} is not canonical UTF-8`);
}
return text;
}
function regular(path, label) {
const stat = lstatSync(path, { throwIfNoEntry: false });
if (
stat === undefined || !stat.isFile() || stat.isSymbolicLink() ||
stat.nlink !== 1
) {
fail(`${label} is not a single-link regular file`);
}
if (realpathSync(path) !== path) fail(`${label} path is not canonical`);
return readFileSync(path);
}
function parseSpec(bytes) {
const text = utf8(bytes, "current.conf");
lineCount(bytes, "current.conf");
const values = new Map();
for (const line of text.slice(0, -1).split("\n")) {
if (line === "" || line.startsWith("#")) continue;
const match = /^([a-z][a-z0-9_]*)=(.*)$/.exec(line);
if (match === null) {
fail(`malformed current.conf line: ${JSON.stringify(line)}`);
}
if (values.has(match[1])) fail(`duplicate current.conf key: ${match[1]}`);
values.set(match[1], match[2]);
}
return values;
}
function required(spec, key) {
const value = spec.get(key);
if (value === undefined || value === "") {
fail(`missing current.conf key: ${key}`);
}
return value;
}
function countOccurrences(text, needle) {
let count = 0;
let offset = 0;
while ((offset = text.indexOf(needle, offset)) !== -1) {
count += 1;
offset += needle.length;
}
return count;
}
function repositoryPath(root, path, label) {
if (
path === "" || isAbsolute(path) || path.includes("\\") ||
path.split("/").some((part) => part === "" || part === "." || part === "..")
) {
fail(`unsafe ${label} path`);
}
const absolute = resolve(root, ...path.split("/"));
const inside = relative(root, absolute);
if (
inside === "" || inside === ".." || inside.startsWith(`..${sep}`) ||
isAbsolute(inside)
) {
fail(`${label} escaped repository root`);
}
return absolute;
}
const root = realpathSync(process.env.GITHUB_WORKSPACE);
const specPath = resolve(root, "dev-support/test262/current.conf");
const tsvPath = resolve(root, "target/test262-full.tsv");
const jsonPath = resolve(root, "target/test262-full.jsonl");
const spec = parseSpec(regular(specPath, "current.conf"));
const shaPattern = /^[0-9a-f]{64}$/;
const countPattern = /^[1-9][0-9]*$/;
const baseline = required(spec, "engine_semantics_sha256");
const expectedTsvHash = required(spec, "full_tsv_sha256");
const expectedJsonHash = required(spec, "full_jsonl_sha256");
const expectedTsvLines = required(spec, "full_tsv_lines");
const expectedJsonLines = required(spec, "full_jsonl_lines");
const expectedToolHash = required(spec, "engine_fingerprint_tool_sha256");
const expectedToolLines = required(spec, "engine_fingerprint_tool_lines");
for (const [label, value] of [
["engine semantics", baseline],
["full TSV", expectedTsvHash],
["full JSONL", expectedJsonHash],
["fingerprint tool", expectedToolHash],
]) {
if (!shaPattern.test(value)) fail(`invalid ${label} SHA-256`);
}
for (const [label, value] of [
["full TSV", expectedTsvLines],
["full JSONL", expectedJsonLines],
["fingerprint tool", expectedToolLines],
]) {
if (!countPattern.test(value)) fail(`invalid ${label} line count`);
}
const toolPath = repositoryPath(
root,
required(spec, "engine_fingerprint_tool"),
"fingerprint tool",
);
const toolBytes = regular(toolPath, "fingerprint tool");
if (sha256(toolBytes) !== expectedToolHash) {
fail("fingerprint tool checksum drifted");
}
if (lineCount(toolBytes, "fingerprint tool") !== Number(expectedToolLines)) {
fail("fingerprint tool line count drifted");
}
const fingerprintOutput = execFileSync(process.execPath, [
toolPath,
"--root", root,
"--worktree",
"--files", required(spec, "engine_semantics_files"),
"--trees", required(spec, "engine_semantics_trees"),
], {
encoding: "utf8",
stdio: ["ignore", "pipe", "inherit"],
});
if (!/^[0-9a-f]{64}\n$/.test(fingerprintOutput)) {
fail("fingerprint tool output drifted");
}
const current = fingerprintOutput.trim();
if (current === baseline) {
fail("receipt capture requires a source-stale baseline");
}
const tsvBytes = regular(tsvPath, "full TSV receipt");
const jsonBytes = regular(jsonPath, "full JSONL receipt");
if (
lineCount(tsvBytes, "full TSV receipt") !== Number(expectedTsvLines) ||
lineCount(jsonBytes, "full JSONL receipt") !== Number(expectedJsonLines)
) {
fail("full receipt line count drifted");
}
const tsv = utf8(tsvBytes, "full TSV receipt");
const json = utf8(jsonBytes, "full JSONL receipt");
const tsvCurrent =
`# quickjs-oxide Test262 outcome vector v5 ` +
`engine_semantics_sha256=${current}\n`;
const tsvBaseline =
`# quickjs-oxide Test262 outcome vector v5 ` +
`engine_semantics_sha256=${baseline}\n`;
if (
!tsv.startsWith(tsvCurrent) || countOccurrences(tsv, current) !== 1 ||
countOccurrences(tsv, baseline) !== 0
) {
fail("full TSV fingerprint placement drifted");
}
const normalizedTsv = Buffer.from(
tsvBaseline + tsv.slice(tsvCurrent.length),
"utf8",
);
if (
sha256(tsvBytes) === expectedTsvHash ||
sha256(normalizedTsv) !== expectedTsvHash
) {
fail("full TSV differs by more than its engine fingerprint");
}
const firstNewline = json.indexOf("\n");
if (firstNewline === -1) fail("full JSONL metadata line is missing");
let metadata;
try {
metadata = JSON.parse(json.slice(0, firstNewline));
} catch {
fail("full JSONL metadata is invalid JSON");
}
if (
metadata.kind !== "metadata" ||
metadata.engine_semantics_sha256 !== current
) {
fail("full JSONL metadata fingerprint drifted");
}
const jsonCurrent = `\"engine_semantics_sha256\":\"${current}\"`;
const jsonBaseline = `\"engine_semantics_sha256\":\"${baseline}\"`;
if (
!json.slice(0, firstNewline).includes(jsonCurrent) ||
countOccurrences(json, current) !== 1 || countOccurrences(json, baseline) !== 0
) {
fail("full JSONL fingerprint placement drifted");
}
const normalizedJson = Buffer.from(
json.replace(jsonCurrent, jsonBaseline),
"utf8",
);
if (
sha256(jsonBytes) === expectedJsonHash ||
sha256(normalizedJson) !== expectedJsonHash
) {
fail("full JSONL differs by more than its engine fingerprint");
}
console.log(
"Current-source Test262 receipts differ only by engine fingerprint: " +
`${baseline} -> ${current}`,
);
NODE
- name: Upload complete Test262 receipts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test262-full-${{ github.sha }}
path: |
target/test262-full.tsv
target/test262-full.jsonl
target/test262-full.log
dev-support/test262/current.conf
dev-support/test262/negative-diagnostics.tsv
compat/upstream.toml
if-no-files-found: warn
retention-days: 30