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
29 changes: 8 additions & 21 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ jobs:
- name: Validate Python tooling
run: |
python3 -m py_compile x.py tools/check_wave_corpus.py tools/case_manifest.py tools/populate_case_matrix.py tools/run_tests.py tools/test_contracts.py tools/test_case_manifest.py tools/test_test_contracts.py
python3 -m unittest tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_release_publish
python3 -m unittest tools.test_x tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_release_publish

- name: Run Rust tests
run: cargo test --locked --all-targets --verbose
Expand Down Expand Up @@ -913,33 +913,20 @@ jobs:
contents: write

steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- uses: actions/download-artifact@v4
with:
pattern: release-*
path: release-assets
merge-multiple: true

- name: Verify release assets
shell: bash
working-directory: release-assets
run: |
set -euo pipefail

test -f "wave-v${RELEASE_VERSION}-x86_64-linux-gnu.tar.gz"
test -f "wave-v${RELEASE_VERSION}-aarch64-linux-gnu.tar.gz"
test -f "wave-v${RELEASE_VERSION}-riscv64-linux-gnu.tar.gz"
test -f "wave-v${RELEASE_VERSION}-loongarch64-linux-gnu.tar.gz"
test -f "wave-v${RELEASE_VERSION}-x86_64-pc-windows-msvc.zip"
test -f "wave-v${RELEASE_VERSION}-aarch64-pc-windows-msvc.zip"
test -f "wave-v${RELEASE_VERSION}-aarch64-apple-darwin.tar.gz"
test -f "wave-v${RELEASE_VERSION}-x86_64-apple-darwin.tar.gz"

for archive in *.tar.gz *.zip; do
test -f "$archive.sha256"
done

cat ./*.sha256 > SHA256SUMS
sha256sum --check SHA256SUMS
run: python3 -m tools.check_release_assets --directory release-assets --version "$RELEASE_VERSION"

- name: Create GitHub release
shell: bash
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
- name: Validate Python tooling
run: |
python3 -m py_compile x.py tools/check_wave_corpus.py tools/case_manifest.py tools/populate_case_matrix.py tools/run_tests.py tools/test_contracts.py tools/test_case_manifest.py tools/test_test_contracts.py tools/process_tree.py tools/test_process_tree.py
python3 -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native tools.test_diagnose_windows_arm64 tools.test_runtime_selection
python3 -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native tools.test_diagnose_windows_arm64 tools.test_runtime_selection

- name: Test Windows ARM64 dependency archive validation
shell: pwsh
Expand Down Expand Up @@ -145,7 +145,7 @@ jobs:
- name: Validate Python tooling
run: |
python3 -m py_compile x.py tools/check_wave_corpus.py tools/case_manifest.py tools/populate_case_matrix.py tools/run_tests.py tools/test_contracts.py tools/test_case_manifest.py tools/test_test_contracts.py tools/process_tree.py tools/test_process_tree.py
python3 -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native
python3 -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native

- name: Build release compiler
run: cargo build --locked --release --verbose
Expand Down Expand Up @@ -352,7 +352,7 @@ jobs:
- name: Validate Python tooling
run: |
python3 -m py_compile x.py tools/check_wave_corpus.py tools/case_manifest.py tools/populate_case_matrix.py tools/run_tests.py tools/test_contracts.py tools/test_case_manifest.py tools/test_test_contracts.py tools/process_tree.py tools/test_process_tree.py
python3 -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native
python3 -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native

- name: Build release compiler
id: release_build
Expand Down Expand Up @@ -517,7 +517,7 @@ jobs:
- name: Validate Python tooling
run: |
python3 -m py_compile x.py tools/check_wave_corpus.py tools/case_manifest.py tools/populate_case_matrix.py tools/run_tests.py tools/test_contracts.py tools/test_case_manifest.py tools/test_test_contracts.py tools/process_tree.py tools/test_process_tree.py
python3 -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native
python3 -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native

- name: Build release compiler
run: cargo build --locked --release --verbose
Expand Down Expand Up @@ -587,7 +587,7 @@ jobs:
- name: Validate Python tooling
run: |
python3 -m py_compile x.py tools/check_wave_corpus.py tools/case_manifest.py tools/populate_case_matrix.py tools/run_tests.py tools/test_contracts.py tools/test_case_manifest.py tools/test_test_contracts.py tools/process_tree.py tools/test_process_tree.py
python3 -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native
python3 -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_case_manifest tools.test_test_contracts tools.test_process_tree tools.test_check_msvc_native

- name: Build release compiler
run: cargo build --locked --release --verbose
Expand Down Expand Up @@ -707,7 +707,7 @@ jobs:
- name: Validate Windows Python tooling
if: ${{ !cancelled() && steps.python_setup.outcome == 'success' }}
run: >-
python -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution
python -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution
tools.test_case_manifest tools.test_test_contracts tools.test_process_tree
- name: Check PE dependency failures and case runner selection
if: ${{ !cancelled() && steps.python_setup.outcome == 'success' }}
Expand Down Expand Up @@ -839,7 +839,7 @@ jobs:

- name: Check native Windows process supervision
if: ${{ !cancelled() && steps.python_setup.outcome == 'success' }}
run: python -m unittest tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_process_tree
run: python -m unittest tools.test_x tools.test_release_publish tools.test_release_gates tools.test_server_case tools.test_check_wave_corpus tools.test_runtime_cases tools.test_check_case_sources tools.test_case_execution tools.test_process_tree

- name: Run native ARM64 unit and frontend driver tests
if: ${{ !cancelled() && steps.native_build.outcome == 'success' }}
Expand Down
2 changes: 1 addition & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2668,7 +2668,7 @@ const wasi = new WASI({
});
const module = await WebAssembly.compile(await readFile(modulePath));
const instance = await WebAssembly.instantiate(module, wasi.getImportObject());
wasi.start(instance);
process.exitCode = wasi.start(instance);
"#;

fn build_execute_command(
Expand Down
41 changes: 41 additions & 0 deletions tests/codegen_regressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3085,6 +3085,47 @@ fun main() -> i32 {
);
}

#[test]
#[cfg(feature = "llvm-target-wasm")]
fn wasi_runner_preserves_explicit_process_exit_status() {
for tool in ["node", "wasm-ld"] {
if !Command::new(tool)
.arg("--version")
.output()
.is_ok_and(|output| output.status.success())
{
eprintln!("skipping WASI execution: {tool} unavailable");
return;
}
}
let dir = temp_case_dir("wasi-exit-status");
for status in [0, 7] {
let source = write_wave(
&dir,
"exit.wave",
&format!(
"extern(c, \"proc_exit\") fun exit(code: u32);\n\
fun main() -> i32 {{ exit({status}); return 0; }}\n"
),
);
let output = wavec_command()
.arg("build")
.arg(&source)
.args(["--target", "wasm32-wasip1", "--run", "--out-dir"])
.arg(dir.join("out"))
.output()
.unwrap();
assert_eq!(
output.status.code(),
Some(status),
"stdout: {}\nstderr: {}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
fs::remove_dir_all(dir).unwrap();
}

#[test]
#[cfg(feature = "llvm-target-wasm")]
fn webassembly_c_abi_and_wasi_import_contracts_are_explicit() {
Expand Down
37 changes: 32 additions & 5 deletions tools/check_freebsd_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@
"""

import argparse
import json
import os
from pathlib import Path
import re
import select
import shutil
import subprocess
import sys
import tempfile
import time

if __package__ in (None, ""):
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from tools.validation_reports import validate_report_path, write_report

ROOT = Path(__file__).resolve().parents[1]
ARCHES = {"amd64": "x86_64", "arm64": "aarch64", "riscv64": "riscv64"}
# Kernel device messages can interleave with init's prompt (even inside
Expand Down Expand Up @@ -101,22 +106,44 @@ def main():
parser.add_argument("--case-timeout", type=int, default=60)
args = parser.parse_args()
report_path = args.report_json or args.out_dir / "report.json"
report_path.parent.mkdir(parents=True, exist_ok=True)
# Guard failure reports too, before creating directories or launching tools.
try:
protected = report_inputs(args)
validate_report_path(report_path, protected)
except (OSError, ValueError) as error:
print(f"Unsafe report destination: {error}", file=sys.stderr)
return 1
report = {"schema_version": 1, "arch": args.arch, "status": "running",
"phase": "validation", "commands": [], "cases": []}
status = 0
try:
if min(args.command_timeout, args.boot_timeout, args.case_timeout) <= 0:
raise ValueError("timeouts must be positive")
execute(args, report)
report["status"] = "pass"
return 0
except (Exception, KeyboardInterrupt) as error:
report["status"] = "interrupted" if isinstance(error, KeyboardInterrupt) else "fail"
report["error"] = f"{type(error).__name__}: {error}"
print(report["error"], flush=True)
status = 1
try:
validate_report_path(report_path, protected)
write_report(report_path, report)
except (OSError, ValueError) as error:
print(f"Failed to write report: {error}", file=sys.stderr)
return 1
finally:
report_path.write_text(json.dumps(report, indent=2) + "\n")
return status


def report_inputs(args):
inputs = [p for p in (args.image, args.compiler, args.firmware, args.kernel) if p is not None]
# Include imported helper modules and std metadata, not just case entry points.
inputs.extend((ROOT / "tests/cases").rglob("*.wave"))
for directory in (ROOT / "std", ROOT / "tests/fixtures/freebsd_case_runtime"):
inputs.extend(p for p in directory.rglob("*") if p.is_file())
for tool in (args.clang, args.linker, "genisoimage", "qemu-img", f"qemu-system-{ARCHES[args.arch]}"):
inputs.append(Path(shutil.which(tool) or tool))
return inputs


def discover_cases(suite):
Expand Down
74 changes: 74 additions & 0 deletions tools/check_release_assets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MPL-2.0
"""Verify complete archive/checksum coverage before producing SHA256SUMS."""
import argparse
import hashlib
import os
from pathlib import Path
import re
import sys
import tempfile


ARCHIVE_TARGETS = (
"x86_64-linux-gnu", "aarch64-linux-gnu", "riscv64-linux-gnu", "loongarch64-linux-gnu",
"x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc",
"aarch64-apple-darwin", "x86_64-apple-darwin",
)


def verify(directory, version):
directory = Path(directory)
if not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?", version):
raise ValueError(f"invalid release version: {version!r}")
expected = {f"wave-v{version}-{target}" + (".zip" if "windows" in target else ".tar.gz")
for target in ARCHIVE_TARGETS}
archives = {p.name for p in directory.iterdir() if p.name.endswith((".tar.gz", ".zip"))}
sidecars = {p.name for p in directory.iterdir() if p.name.endswith(".sha256")}
for label, actual, required in (("archives", archives, expected),
("checksum files", sidecars, {name + ".sha256" for name in expected})):
if actual != required:
raise ValueError(f"release {label}: missing={sorted(required - actual)}, unexpected={sorted(actual - required)}")
records = []
for name in sorted(expected):
archive, sidecar = directory / name, directory / (name + ".sha256")
if archive.is_symlink() or sidecar.is_symlink() or not archive.is_file() or not sidecar.is_file():
raise ValueError(f"archive/checksum must be regular files: {name}")
lines = sidecar.read_text(encoding="ascii").splitlines()
match = re.fullmatch(r"([0-9a-fA-F]{64}) [ *](.+)", lines[0]) if len(lines) == 1 else None
if match is None or match[2] != name:
raise ValueError(f"{sidecar.name}: expected exactly one checksum record naming {name}")
digest = hashlib.sha256()
with archive.open("rb") as stream:
for block in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(block)
if digest.hexdigest() != match[1].lower():
raise ValueError(f"checksum mismatch: {name}")
records.append(f"{digest.hexdigest()} {name}\n")
# Never publish a partial manifest or follow an existing manifest symlink.
fd, temporary = tempfile.mkstemp(prefix=".SHA256SUMS-", dir=directory)
try:
with os.fdopen(fd, "w", encoding="ascii", newline="\n") as stream:
stream.writelines(records)
os.replace(temporary, directory / "SHA256SUMS")
finally:
Path(temporary).unlink(missing_ok=True)
return len(records)


def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--directory", type=Path, required=True)
parser.add_argument("--version", required=True)
options = parser.parse_args(argv)
try:
count = verify(options.directory, options.version)
except (OSError, ValueError) as error:
print(f"Release asset validation failed: {error}", file=sys.stderr)
return 1
print(f"Verified {count} release archives and checksum records")
return 0


if __name__ == "__main__":
raise SystemExit(main())
Loading
Loading