Skip to content

Commit 101a624

Browse files
committed
chore: add cargo-deny, fuzz targets compile, spatial+provenance benchmarks
Extends the CI suite to the remaining static-analysis gates and rounds out benchmark coverage to all 8 modalities. cargo-deny: - Added [advisories] ignore list for the 5 transitive-only advisories in the burn ML stack (bincode/core2/paste/rustls-pemfile/lru). Each entry is documented with the upstream chain so we can prune them after a burn upgrade clears the corresponding crate. - Set [bans] allow-wildcard-paths = true so workspace path deps don't trip the wildcard guard. - Added "CDLA-Permissive-2.0" to license allow-list (webpki-root-certs). - Dropped unused "Unicode-DFS-2016" and "OpenSSL" entries. - Added publish = false to all 17 rust-core crates so cargo-deny knows the wildcard-path exemption applies (publishable crates can't have path deps). - Added MPL-2.0 license + publish = false to verisimdb-benchmarks (cargo-deny was flagging it as unlicensed). Benchmarks: - New bench_spatial_operations: index_point, search_radius_5km, nearest_10 against a 1000-point pre-populated store. First run produced ~1.4 µs index, ~46 µs radius search, ~195 µs k=10 nearest. - New bench_provenance_operations: record_event_append, verify_chain_1000 (full SHA-256 hash-chain verification of 1000 records), search_by_actor. ~3.3 µs append, ~2.8 ms chain verify, ~32 µs actor search. - All 8 modalities now have dedicated benchmark coverage. Fuzz targets (both crates): - fuzz/Cargo.toml was missing the uuid dep its target uses - rust-core/fuzz/ was missing a [workspace] table, so cargo-check from the parent workspace failed to locate it - fuzz_vql_parser.rs referenced verisim_api::vql::parse() which doesn't exist; switched to ::tokenize() (made public, was private) - .gitignore now covers fuzz/target/ and rust-core/fuzz/target/ GitHub Actions additions to rust-ci.yml: - deny: cargo deny check advisories bans licenses sources - fuzz-compile: matrix over both fuzz manifests, cargo check each https://claude.ai/code/session_01GeiWCLLoZmPdnjMMcy2buu
1 parent ebc19eb commit 101a624

28 files changed

Lines changed: 17562 additions & 9 deletions

File tree

.github/workflows/rust-ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ jobs:
7171
with:
7272
token: ${{ secrets.GITHUB_TOKEN }}
7373

74+
deny:
75+
name: cargo deny
76+
runs-on: ubuntu-latest
77+
steps:
78+
- uses: actions/checkout@v4
79+
- uses: EmbarkStudios/cargo-deny-action@v2
80+
with:
81+
command: check advisories bans licenses sources
82+
7483
bench-compile:
7584
name: benchmarks compile
7685
runs-on: ubuntu-latest
@@ -79,3 +88,17 @@ jobs:
7988
- uses: dtolnay/rust-toolchain@stable
8089
- uses: Swatinem/rust-cache@v2
8190
- run: cargo bench --no-run
91+
92+
fuzz-compile:
93+
name: fuzz targets compile
94+
runs-on: ubuntu-latest
95+
strategy:
96+
matrix:
97+
manifest:
98+
- fuzz/Cargo.toml
99+
- rust-core/fuzz/Cargo.toml
100+
steps:
101+
- uses: actions/checkout@v4
102+
- uses: dtolnay/rust-toolchain@stable
103+
- uses: Swatinem/rust-cache@v2
104+
- run: cargo check --manifest-path ${{ matrix.manifest }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,7 @@ temp/
110110

111111
# Crash recovery artifacts
112112
ai-cli-crash-capture/
113+
114+
# Fuzz harness build artifacts
115+
fuzz/target/
116+
rust-core/fuzz/target/

benches/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
name = "verisimdb-benchmarks"
55
version = "0.1.0"
66
edition = "2021"
7+
license = "MPL-2.0"
78
publish = false
89

910
[[bench]]

benches/modality_benchmarks.rs

Lines changed: 151 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use verisim_octad::{
1313
InMemoryOctadStore, OctadConfig, OctadDocumentInput, OctadInput, OctadSemanticInput,
1414
OctadSnapshot, OctadStore, OctadVectorInput,
1515
};
16-
use verisim_provenance::InMemoryProvenanceStore;
16+
use verisim_provenance::{InMemoryProvenanceStore, ProvenanceEventType, ProvenanceStore};
1717
use verisim_semantic::{InMemorySemanticStore, ProofBlob, ProofType, SemanticStore, SemanticType};
18-
use verisim_spatial::InMemorySpatialStore;
18+
use verisim_spatial::{Coordinates, GeometryType, InMemorySpatialStore, SpatialData, SpatialStore};
1919
use verisim_temporal::{InMemoryVersionStore, TemporalStore};
2020
use verisim_tensor::{InMemoryTensorStore, ReduceOp, Tensor, TensorStore};
2121
use verisim_vector::{DistanceMetric, Embedding, HnswConfig, HnswVectorStore, VectorStore};
@@ -597,6 +597,148 @@ fn bench_temporal_operations(c: &mut Criterion) {
597597
group.finish();
598598
}
599599

600+
// ============================================================================
601+
// Spatial Store Benchmarks
602+
// ============================================================================
603+
604+
fn bench_spatial_operations(c: &mut Criterion) {
605+
let rt = Runtime::new().unwrap();
606+
let mut group = c.benchmark_group("spatial");
607+
608+
// Index throughput. Use a small deterministic walk that stays inside
609+
// [-90, 90] / [-180, 180] no matter how many iterations criterion runs.
610+
group.bench_function("index_point", |b| {
611+
let store = InMemorySpatialStore::new();
612+
let mut counter = 0u64;
613+
b.to_async(&rt).iter(|| {
614+
counter = counter.wrapping_add(1);
615+
let entity_id = format!("spatial-{}", counter);
616+
// Lattice walk: 360x180 cells centred on (0, 0); cycles forever.
617+
let lat = ((counter % 180) as f64) - 90.0 + 0.5;
618+
let lon = (((counter / 180) % 360) as f64) - 180.0 + 0.5;
619+
let data = SpatialData {
620+
coordinates: Coordinates::new(lat, lon, None).unwrap(),
621+
geometry_type: GeometryType::Point,
622+
srid: 4326,
623+
properties: HashMap::new(),
624+
};
625+
let store_ref = &store;
626+
async move {
627+
store_ref.index(&entity_id, data).await.unwrap();
628+
black_box(())
629+
}
630+
});
631+
});
632+
633+
// Pre-populate 1000 points (clustered around London) for query bench
634+
let query_store = InMemorySpatialStore::new();
635+
rt.block_on(async {
636+
for i in 0..1000 {
637+
let lat = 51.5074 + ((i as f64) - 500.0) * 0.001;
638+
let lon = -0.1278 + ((i as f64) - 500.0) * 0.001;
639+
let data = SpatialData {
640+
coordinates: Coordinates::new(lat, lon, None).unwrap(),
641+
geometry_type: GeometryType::Point,
642+
srid: 4326,
643+
properties: HashMap::new(),
644+
};
645+
query_store.index(&format!("p-{}", i), data).await.unwrap();
646+
}
647+
});
648+
let centre = Coordinates::new(51.5074, -0.1278, None).unwrap();
649+
650+
group.bench_function("search_radius_5km", |b| {
651+
b.to_async(&rt).iter(|| async {
652+
black_box(query_store.search_radius(&centre, 5.0, 100).await.unwrap())
653+
});
654+
});
655+
656+
group.bench_function("nearest_10", |b| {
657+
b.to_async(&rt)
658+
.iter(|| async { black_box(query_store.nearest(&centre, 10).await.unwrap()) });
659+
});
660+
661+
group.finish();
662+
}
663+
664+
// ============================================================================
665+
// Provenance Store Benchmarks
666+
// ============================================================================
667+
668+
fn bench_provenance_operations(c: &mut Criterion) {
669+
let rt = Runtime::new().unwrap();
670+
let mut group = c.benchmark_group("provenance");
671+
672+
// Hash-chain append throughput on a long chain
673+
group.bench_function("record_event_append", |b| {
674+
let store = InMemoryProvenanceStore::new();
675+
let entity = "chain-entity";
676+
// Seed with a genesis record
677+
rt.block_on(async {
678+
store
679+
.record_event(
680+
entity,
681+
ProvenanceEventType::Created,
682+
"bench",
683+
None,
684+
"genesis",
685+
)
686+
.await
687+
.unwrap();
688+
});
689+
b.to_async(&rt).iter(|| {
690+
let store_ref = &store;
691+
async move {
692+
store_ref
693+
.record_event(
694+
entity,
695+
ProvenanceEventType::Modified,
696+
"bench",
697+
None,
698+
"tick",
699+
)
700+
.await
701+
.unwrap();
702+
black_box(())
703+
}
704+
});
705+
});
706+
707+
// Build a 1000-event chain for verify + lookup benches
708+
let chain_store = InMemoryProvenanceStore::new();
709+
rt.block_on(async {
710+
chain_store
711+
.record_event("e-1", ProvenanceEventType::Created, "actor-0", None, "init")
712+
.await
713+
.unwrap();
714+
for i in 1..1000 {
715+
chain_store
716+
.record_event(
717+
"e-1",
718+
ProvenanceEventType::Modified,
719+
&format!("actor-{}", i % 10),
720+
None,
721+
"edit",
722+
)
723+
.await
724+
.unwrap();
725+
}
726+
});
727+
728+
group.bench_function("verify_chain_1000", |b| {
729+
b.to_async(&rt)
730+
.iter(|| async { black_box(chain_store.verify_chain("e-1").await.unwrap()) });
731+
});
732+
733+
group.bench_function("search_by_actor", |b| {
734+
b.to_async(&rt).iter(|| async {
735+
black_box(chain_store.search_by_actor("actor-3").await.unwrap())
736+
});
737+
});
738+
739+
group.finish();
740+
}
741+
600742
// ============================================================================
601743
// Benchmark Groups
602744
// ============================================================================
@@ -623,6 +765,10 @@ criterion_group!(semantic_benches, bench_semantic_operations);
623765

624766
criterion_group!(temporal_benches, bench_temporal_operations);
625767

768+
criterion_group!(spatial_benches, bench_spatial_operations);
769+
770+
criterion_group!(provenance_benches, bench_provenance_operations);
771+
626772
criterion_main!(
627773
document_benches,
628774
vector_benches,
@@ -632,5 +778,7 @@ criterion_main!(
632778
cross_modal_benches,
633779
tensor_benches,
634780
semantic_benches,
635-
temporal_benches
781+
temporal_benches,
782+
spatial_benches,
783+
provenance_benches
636784
);

deny.toml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55
[advisories]
66
db-path = "~/.cargo/advisory-db"
77
db-urls = ["https://github.com/rustsec/advisory-db"]
8-
# Allow known transitive dep vulnerability (lru 0.12.5, LOW severity)
9-
ignore = ["RUSTSEC-2026-0002"]
8+
# Transitive deps in the `burn` ML stack we cannot fix downstream.
9+
# Each entry is reviewed when bumping burn; remove once upstream migrates.
10+
ignore = [
11+
"RUSTSEC-2024-0436", # paste (unmaintained) — burn-wgpu → cubecl-cpu → tracel-llvm
12+
"RUSTSEC-2025-0134", # rustls-pemfile (unmaintained) — axum-server
13+
"RUSTSEC-2025-0141", # bincode (unmaintained) — burn-core
14+
"RUSTSEC-2026-0002", # lru (unsound IterMut) — transitive
15+
"RUSTSEC-2026-0105", # core2 (unmaintained + yanked) — rav1e → ravif → image → burn-dataset
16+
]
1017

1118
[licenses]
1219
allow = [
@@ -19,15 +26,18 @@ allow = [
1926
"Zlib",
2027
"BSL-1.0",
2128
"Unicode-3.0",
22-
"Unicode-DFS-2016",
23-
"OpenSSL",
2429
"MPL-2.0",
30+
"CDLA-Permissive-2.0", # webpki-root-certs
2531
]
2632
confidence-threshold = 0.8
2733

2834
[bans]
2935
multiple-versions = "warn"
36+
# Workspace path deps appear as wildcards because they have no
37+
# version constraint; that's fine because they only resolve to the
38+
# in-tree crates. External wildcard deps remain forbidden.
3039
wildcards = "deny"
40+
allow-wildcard-paths = true
3141
deny = []
3242

3343
[sources]

0 commit comments

Comments
 (0)