Skip to content
Open
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
62 changes: 62 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# example-kvs bazel configuration.
#
# Two named build profiles, bound to the variant model in variants/:
#
# --config=dev — fastbuild, ASAN-friendly, default rustc flags.
# Mirrors the `dev` variant in variants/bindings.yaml.
# Use for engineering iteration.
#
# --config=prod — release-mode + LTO + single codegen-unit + panic=abort.
# Mirrors the `prod` variant in variants/bindings.yaml.
# These flags are the minimum that an ASIL-B safety case
# typically asks for on Rust builds:
# lto=fat single translation unit at link time
# codegen-units=1 deterministic, no parallelization noise
# panic=abort no unwinding (smaller, FuSa-compatible,
# eliminates the cleanup-path surface)
# opt-level=3 max speed (default for compilation_mode=opt)
# overflow-checks=on intentional — ASIL-B forbids silent UB on
# integer overflow; cost is a few % in tight
# loops, acceptable for safety builds
# strip=symbols smaller binary, debuginfo lives in a
# separate file (split-debuginfo in CI)
#
# `make verify VARIANT=prod` passes `--config=prod` through; same for `make bazel`.

# ── default settings ─────────────────────────────────────────────────
build --java_language_version=17
test --test_output=errors

# ── --config=dev (engineering builds) ────────────────────────────────
build:dev --compilation_mode=fastbuild

# ── --config=prod (safety flags compatible with bazel test) ──────────
# Used for `make verify VARIANT=prod` and any test-time invocation.
# panic=abort is INTENTIONALLY OMITTED here: Rust's #[test] harness
# requires unwinding to report failures and is incompatible with
# panic=abort outside nightly's -Zpanic_abort_tests. panic=abort lives
# in --config=prod_ship below for the actually-deployed binary.
build:prod --compilation_mode=opt
build:prod --@rules_rust//rust/settings:extra_rustc_flag=-Cembed-bitcode=yes
build:prod --@rules_rust//rust/settings:extra_rustc_flag=-Clto=fat
build:prod --@rules_rust//rust/settings:extra_rustc_flag=-Ccodegen-units=1
build:prod --@rules_rust//rust/settings:extra_rustc_flag=-Coverflow-checks=on
build:prod --@rules_rust//rust/settings:extra_rustc_flag=-Cstrip=symbols
# Mirror codegen-units=1 on exec-target crates (proc-macros,
# build-scripts) so the prod toolchain composes cleanly.
build:prod --@rules_rust//rust/settings:extra_exec_rustc_flag=-Ccodegen-units=1

# ── --config=prod_ship (the actually-deployed binary only) ───────────
# Extends --config=prod with panic=abort. Use for `bazel build` of
# shipping binaries, NEVER for `bazel test`. The deployed ASIL-B
# Rust binary should not carry the unwinding machinery — smaller
# code size, no cleanup-path semantics for the assessor to argue
# about.
#
# Typical use:
# bazel build --config=prod_ship //:kvs_component
build:prod_ship --config=prod
build:prod_ship --@rules_rust//rust/settings:extra_rustc_flag=-Cpanic=abort

# Per-user overrides (gitignored)
try-import %workspace%/user.bazelrc
4 changes: 4 additions & 0 deletions .cargo-shim/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Empty stub so cargo doesn't try to compile src/lib.rs (which depends
// on Bazel-generated `kvs_component_bindings` and cannot be built by
// plain cargo). The cargo-shim crate only exists for crate_universe's
// external-dep resolution; see /Cargo.toml header.
33 changes: 25 additions & 8 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# example-kvs CI — runs the two gates that work without spar/sigil
# installed: rivet validate (typed-artifact graph check) and the
# artifact-driven verification gate (tools/verify.py).
# example-kvs CI — single job that runs the three gates:
# 1. `rivet validate` typed-artifact graph check
# 2. `bazel build //...` AADL → WIT → wit-bindgen → WASM component
# 3. `python tools/verify.py` artifact-driven verification gate
# (drives bazel test per comp-req's verified-by entries)
#
# No untrusted input is used in any run: block; all commands are
# static make targets / pinned installs.
# Note: CI may go RED on purpose. The verify gate runs surface tests
# against the vendored eclipse-score rust_kvs sources. Some of those
# tests assert spec compliance the upstream impl does not enforce;
# when that's the case, the test FAILs and the gate FIREs. That is
# the LS-N demonstration vs. "green-CI-by-default" coverage-wedge
# reporting. See README.md "What this gate measures" for details.

name: validate

Expand All @@ -18,8 +24,8 @@ permissions:
contents: read

jobs:
validate-pinned:
name: rivet validate + artifact-driven verification gate
validate:
name: rivet + bazel + verify
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -34,8 +40,19 @@ jobs:
- name: Install PyYAML for verify.py
run: pip install pyyaml

- name: Set up bazelisk
uses: bazel-contrib/setup-bazel@0.9.1
with:
bazelisk-version: "1.x"

- name: rivet validate (typed-artifact graph check)
run: make validate

- name: artifact-driven verification gate
- name: bazel build (AADL → WIT → wit-bindgen → wasm component)
run: bazel build //...

- name: artifact-driven verification gate (real bazel test per artifact)
# verify.py shells out to `bazel test --test_arg=--exact …` per
# entry in each comp-req's verified-by list. Honest signal: red
# iff any comp-req has FAILED or MISSING evidence.
run: make verify
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@
*.swp
.DS_Store
/tmp-*/

# Bazel outputs
bazel-*
MODULE.bazel.lock
/target/

55 changes: 55 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Bazel build for the persistency::kvs WASM component.

The chain:
1. wit_library declares the KVS interface contract (arch/kvs.wit)
2. rust_wasm_component_bindgen generates Rust bindings from the WIT,
compiles src/lib.rs against those bindings, and produces a WASM
component artifact.
3. rust_wasm_component_test smoke-tests that the produced .wasm is
a well-formed component.

If src/lib.rs's `impl Guest for Component` doesn't match the WIT
signatures, the Rust compile fails — the binary contract is
enforced at build time, which is the central operational difference
from eclipse-score's interface-as-documentation approach.
"""

load("@rules_wasm_component//rust:defs.bzl",
"rust_wasm_component_bindgen",
"rust_wasm_component_test")
load("@rules_wasm_component//wit:defs.bzl", "wit_library")

package(default_visibility = ["//visibility:public"])

# ── 1. Declare the WIT interface ──────────────────────────────────────
# arch/kvs.wit declares `package pulseengine:kvs@0.1.0;` with the
# `kvs` interface and `kvs-component` world. This target makes the
# WIT available as a Bazel dependency.
wit_library(
name = "kvs_interface",
package_name = "pulseengine:kvs",
srcs = ["arch/kvs.wit"],
world = "kvs-component",
)

# ── 2. Generate bindings + compile the Rust impl ──────────────────────
# rust_wasm_component_bindgen runs wit-bindgen on :kvs_interface to
# generate the Rust trait `Guest`, then compiles src/lib.rs (which
# implements `Guest`) against those bindings, producing a WASM
# component at bazel-bin/kvs_component.wasm.
rust_wasm_component_bindgen(
name = "kvs_component",
srcs = ["src/lib.rs"],
profiles = ["release"],
validate_wit = False,
wit = ":kvs_interface",
deps = [
"//vendor/rust_kvs:rust_kvs",
],
)

# ── 3. Smoke-test the produced component ──────────────────────────────
rust_wasm_component_test(
name = "kvs_component_test",
component = ":kvs_component",
)
Loading
Loading