Skip to content

Commit 4c183e9

Browse files
jaylorchCopilot
andauthored
feat: Support Verus verification (microsoft#759)
Support for Verus verification. Also add a verus github workflow. Signed-off-by: Jay Lorch <jaylorch@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent f98865f commit 4c183e9

12 files changed

Lines changed: 621 additions & 25 deletions

File tree

.dir-locals.el

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
;;; Directory Local Variables -*- no-byte-compile: t; -*-
2+
;;; For more information see (info "(emacs) Directory Variables")
3+
4+
;; Regorus is a cargo-verus project (package.metadata.verus.verify = true), so
5+
;; verus-mode.el runs `cargo verus verify' rather than the raw `verus' binary.
6+
;; The cargo-verus path ignores `package.metadata.verus.ide.extra_args' and
7+
;; instead reads `verus-cargo-verus-arguments'. We set it here so that Verus is
8+
;; invoked with the `verus' Cargo feature enabled.
9+
;;
10+
;; Everything before `--' is passed to cargo-verus; everything after `--' is
11+
;; forwarded to the Verus binary. The `--' is required by verus-mode.el.
12+
((verus-mode . ((verus-cargo-verus-arguments . ("--features" "verus" "--")))))

.github/workflows/verus.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
#
3+
name: verus
4+
5+
on:
6+
push:
7+
branches: [ "main" ]
8+
pull_request:
9+
branches: [ "main" ]
10+
11+
env:
12+
CARGO_TERM_COLOR: always
13+
14+
# This workflow only checks out code, downloads a pinned Verus release asset,
15+
# and runs verification. It never writes to the repository, so restrict the
16+
# GITHUB_TOKEN to read-only access to repository contents.
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
verify:
22+
runs-on: ubuntu-latest
23+
24+
steps:
25+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
- name: Setup Rust toolchain
27+
uses: ./.github/actions/toolchains/rust
28+
with:
29+
components: ""
30+
- name: Cache cargo
31+
uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
32+
with:
33+
shared-key: ${{ runner.os }}-regorus-verus
34+
- name: Install Verus and run verification
35+
shell: bash
36+
run: |
37+
set -euxo pipefail
38+
asset_url=https://github.com/verus-lang/verus/releases/download/release%2F0.2026.07.12.0b42f4c/verus-0.2026.07.12.0b42f4c-x86-linux.zip
39+
asset_sha256=f6f4f5d08e07d3e1ad721d775bda5ba96b9dd0c73b48fc17f2e071866fbd01c0
40+
test -n "$asset_url"
41+
curl -fsSL "$asset_url" -o verus.zip
42+
43+
# Verify the download integrity before trusting/executing its contents.
44+
echo "${asset_sha256} verus.zip" | sha256sum --check --strict
45+
46+
unzip -q verus.zip -d verus-dist
47+
48+
# Search under an absolute path so that `find` yields absolute paths;
49+
# this keeps the PATH entries below valid regardless of the working
50+
# directory.
51+
verus_bin="$(find "$PWD/verus-dist" -type f -name verus -perm -u+x | head -n1)"
52+
cargo_verus_bin="$(find "$PWD/verus-dist" -type f -name cargo-verus -perm -u+x | head -n1)"
53+
version_json="$(find "$PWD/verus-dist" -type f -name version.json | head -n1)"
54+
test -n "$verus_bin"
55+
test -n "$cargo_verus_bin"
56+
test -n "$version_json"
57+
58+
# Verus is built against a specific Rust toolchain and refuses to run
59+
# against any other version. Read the required toolchain from the
60+
# release metadata so we track it automatically instead of hardcoding.
61+
required_toolchain="$(sed -n 's/.*"toolchain"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$version_json")"
62+
test -n "$required_toolchain"
63+
echo "Verus requires Rust toolchain: $required_toolchain"
64+
65+
# Install the exact toolchain Verus expects, including the extra
66+
# components (rustc-dev, llvm-tools) that Verus links against and that
67+
# are not part of the default rustup profile.
68+
rustup toolchain install "$required_toolchain" \
69+
--profile minimal \
70+
--component rustc-dev --component llvm-tools --component rustfmt
71+
72+
# Force cargo/rustc to resolve to the Verus toolchain for the commands
73+
# below, overriding any repository/directory toolchain override.
74+
export RUSTUP_TOOLCHAIN="$required_toolchain"
75+
76+
# Put cargo-verus on PATH for the commands below.
77+
export PATH="$(dirname "$cargo_verus_bin"):$(dirname "$verus_bin"):$PATH"
78+
cargo verus --help
79+
cargo fetch --locked
80+
cargo verus verify --locked --features verus

Cargo.lock

Lines changed: 85 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@ license = "MIT AND Apache-2.0 AND BSD-3-Clause"
1414
repository = "https://github.com/microsoft/regorus"
1515
keywords = ["interpreter", "no_std", "opa", "policy-as-code", "rego"]
1616

17+
# Support verification with Verus, a Rust verifier (https://github.com/verus-lang/verus)
18+
19+
[package.metadata.verus]
20+
verify = true
21+
1722
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1823

1924
[lib]
2025
doctest = false
2126

2227
[features]
2328
default = ["full-opa", "arc", "rvm"]
29+
verus = ["dep:vstd"]
2430

2531
arc = []
2632
ast = []
@@ -43,7 +49,7 @@ cache = ["dep:lru"]
4349
rvm = ["dep:postcard", "dep:indexmap"]
4450
semver = ["dep:semver"]
4551
allocator-memory-limits = ["std", "mimalloc", "mimalloc/allocator-memory-limits"]
46-
std = ["rand/std", "rand/std_rng", "serde_json/std", "indexmap?/std", "msvc_spectre_libs", "dep:parking_lot" ]
52+
std = ["rand/std", "rand/std_rng", "serde_json/std", "indexmap?/std", "msvc_spectre_libs", "dep:parking_lot", "vstd?/std" ]
4753
time = ["dep:chrono", "dep:chrono-tz"]
4854
uuid = ["dep:uuid"]
4955
urlquery = ["dep:url"]
@@ -134,6 +140,11 @@ mimalloc = { package = "regorus-mimalloc", path = "mimalloc", version = "2.2.7",
134140
indexmap = { version = "2.13.1", default-features = false, features = ["serde"], optional = true }
135141
postcard = { version = "1.1.3", default-features = false, features = ["alloc"], optional = true }
136142

143+
# Verus-related dependencies.
144+
# vstd is enabled via the `verus` feature. In no_std builds only the `alloc` feature is used;
145+
# the crate's `std` feature additionally enables `vstd/std` (matching vstd's default features).
146+
vstd = { version = "=0.0.0-2026-07-12-0122", optional = true, default-features = false, features = ["alloc"] }
147+
137148
[dev-dependencies]
138149
anyhow = "1.0.102"
139150
cfg-if = "1.0.0"
@@ -214,3 +225,7 @@ doctest=false
214225
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps
215226
all-features = true
216227
rustdoc-args = ["--cfg", "docsrs"]
228+
229+
[lints.rust]
230+
# Allow `verus_keep_ghost` configuration flag (used by Verus)
231+
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(verus_keep_ghost)'] }

bindings/csharp/Regorus.Tests/MemoryGrowthTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ public void Engine_create_eval_dispose_does_not_grow_working_set()
115115

116116
if (i % LogEvery == 0)
117117
{
118+
// Collect transient managed garbage so the working-set delta reflects
119+
// retained (leaked) memory rather than uncollected allocations. A real
120+
// native leak from a missed Dispose() would survive GC and still be caught.
121+
ForceFullGc();
118122
process.Refresh();
119123
var workingSet = process.WorkingSet64;
120124
var managed = GC.GetTotalMemory(false);
@@ -228,6 +232,10 @@ public void Rvm_rehydrate_execute_dispose_does_not_grow_working_set()
228232

229233
if (i % LogEvery == 0)
230234
{
235+
// Collect transient managed garbage so the working-set delta reflects
236+
// retained (leaked) memory rather than uncollected allocations. A real
237+
// native leak from a missed Dispose() would survive GC and still be caught.
238+
ForceFullGc();
231239
process.Refresh();
232240
var workingSet = process.WorkingSet64;
233241
var managed = GC.GetTotalMemory(false);

0 commit comments

Comments
 (0)