Skip to content

test(flow-filter): carry the config oracle through to the NF, and widen the generators - #1687

Merged
daniel-noland merged 7 commits into
mainfrom
pr/daniel-noland/flow-filter-coverage
Aug 7, 2026
Merged

test(flow-filter): carry the config oracle through to the NF, and widen the generators#1687
daniel-noland merged 7 commits into
mainfrom
pr/daniel-noland/flow-filter-coverage

Conversation

@daniel-noland

@daniel-noland daniel-noland commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Fuzz tests for flow filter.

I don't love everything about these tests (I wish the typing in particular were cleaner), but this is the version which doesn't require refactors outside of the tests themselves.

Copilot AI review requested due to automatic review settings August 4, 2026 07:30
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds stricter overlay and ACL validation, expands ACL and flow-filter generators, and adds property tests for routing, filtering, NAT, IPv4/IPv6 parsing, packet shapes, and configuration-generation bypass.

Changes

Overlay and filter validation

Layer / File(s) Summary
Manifest IP-version validation
config/src/external/overlay/vpcpeering.rs, config/src/external/overlay/validation_tests.rs
Manifests reject mixed non-default IPv4 and IPv6 exposes. Default and IPv6-only exposes remain valid.
ACL rule lowering errors
acl-filter/src/context.rs, acl-filter/src/access.rs, acl-filter/Cargo.toml
ACL lowering reports incompatible prefix versions as configuration errors and propagates failures during table construction.
ACL generators and property tests
acl-filter/src/fuzz_gen.rs, acl-filter/src/fuzz.rs, acl-filter/src/lib.rs
Generated ACL configurations and probes exercise rule matching, defaults, precedence, unconfigured peerings, VNI mapping, and reference-to-DPDK equivalence.
Expose and probe generation
flow-filter/src/fuzz_gen.rs, config/src/external/overlay/vpc.rs
Generated exposes retain exclusions, conflicting stateful NAT converts to static NAT, and port-forwarding exposes produce protocol-specific probes.
Flow-filter oracle and packet validation
flow-filter/src/context/..., flow-filter/src/tests.rs, flow-filter/src/test_utils.rs, flow-filter/Cargo.toml, flow-filter/src/lib.rs
Property tests compare generated lookups with NF outcomes across packet formats, IPv4 and IPv6 protocols, NAT modes, routing, drops, flow keys, and newer configuration generations.

Possibly related PRs

Suggested reviewers: qmonnet, fredi-raspall

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly identifies the flow-filter fuzz tests covered by the changes.
Title check ✅ Passed The title accurately summarizes the primary flow-filter fuzzing changes, including the oracle and expanded generators.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@daniel-noland daniel-noland added dont-merge Do not merge this Pull Request ci:+vlab Enable VLAB tests labels Aug 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/flow-filter-coverage branch from d64d4ed to dab0fef Compare August 4, 2026 20:17
Copilot AI review requested due to automatic review settings August 4, 2026 20:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 4, 2026 21:39
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/flow-filter-coverage branch from dab0fef to 7ec284c Compare August 4, 2026 21:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/flow-filter-coverage branch from 7ec284c to b01461b Compare August 4, 2026 22:01
Copilot AI review requested due to automatic review settings August 4, 2026 22:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

flow-filter/src/tests.rs:1145

confidence: 8
tags: [logic]

`NfOutcome::Dropped` is documented as having “no destination stamped”, but `observed_outcome()` currently ignores `meta.dst_vpcd` for done packets, so this test won’t catch a regression where `dst_vpcd` is incorrectly set on filtered/not-ip packets. Adding an assertion here tightens the contract without changing the oracle shape.

fn observed_outcome(pkt: &Packet) -> NfOutcome {
if pkt.is_done() {
return NfOutcome::Dropped(pkt.get_done());
}

</details>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

daniel-noland and others added 4 commits August 4, 2026 22:00
Compare flowless packet metadata with the config routing oracle.
Extend generated probes and packet builders to cover all NAT modes and
IPv6 traffic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
Generate VLAN, IPv4, IPv6, extension, fragment, and transport headers.

Check each packet with the config oracle and require every shape.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
Generate not/not_as exclusions and require multi-length prefix fans.

Preserve static NAT address counts and port-forwarding probe hosts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
Cover IPv6 extension headers, portless packets, and newer flows.

Clarify which flow generations bypass the filter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
@daniel-noland
daniel-noland force-pushed the pr/daniel-noland/flow-filter-coverage branch from b01461b to ab42e83 Compare August 5, 2026 04:01
@daniel-noland daniel-noland removed the dont-merge Do not merge this Pull Request label Aug 5, 2026
@daniel-noland
daniel-noland marked this pull request as ready for review August 5, 2026 05:06
@daniel-noland
daniel-noland requested a review from a team as a code owner August 5, 2026 05:06

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
flow-filter/src/tests.rs (1)

1404-1418: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

BY_SHAPE indexing depends on an implicit discriminant contract.

BY_SHAPE[*shape as usize] on Line 1523 and BY_SHAPE[shape as usize] on Line 1583 assume that each variant's discriminant equals its position in Shape::ALL. The comment on Line 1405 records the requirement, but nothing enforces it. If a variant is inserted or reordered without updating ALL, the counters silently attribute packets to the wrong shape.

A debug assertion makes the contract self-checking.

♻️ Proposed self-check
     impl Shape {
         /// Every shape, in selector and counter order.
         const ALL: [Shape; 10] = [
             Shape::NoIp,
             Shape::V4Tcp,
             Shape::V4Udp,
             Shape::V4Icmp,
             Shape::VlanV4Tcp,
             Shape::V4AuthTcp,
             Shape::V6Tcp,
             Shape::V6Udp,
             Shape::V6HopByHopTcp,
             Shape::V6FragmentUdp,
         ];
+
+        /// `ALL` must be ordered by discriminant so `shape as usize` indexes the counters.
+        const _ORDER_CHECK: () = {
+            let mut i = 0;
+            while i < Self::ALL.len() {
+                assert!(Self::ALL[i] as usize == i, "Shape::ALL is out of order");
+                i += 1;
+            }
+        };
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@flow-filter/src/tests.rs` around lines 1404 - 1418, Add a debug assertion
near the Shape::ALL definition or before the BY_SHAPE indexing paths to verify
every Shape variant’s discriminant matches its position in Shape::ALL. Keep the
existing indexing behavior, but make mismatches fail during debug/test execution
rather than silently misattribute counters.
flow-filter/src/context/fuzz.rs (1)

382-397: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Each peering is inspected twice.

vpc_table().values() yields every VPC, and each VPC lists the peerings it takes part in. A peering between two VPCs therefore appears in both lists, so this loop visits the same expose set twice. fetch_max is idempotent, so the assertion result does not change. The extra traversal only costs generator time.

If the duplication is intentional, no change is needed. Otherwise iterate the peering table once.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@flow-filter/src/context/fuzz.rs` around lines 382 - 397, Update the traversal
around the VPC peering inspection to iterate the peering table once rather than
visiting each peering through every VPC in vpc_table().values(). Preserve the
existing expose, IP-set, prefix-length, and WIDEST_SPREAD calculation while
eliminating duplicate processing of the same peering.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@flow-filter/src/context/fuzz.rs`:
- Around line 382-397: Update the traversal around the VPC peering inspection to
iterate the peering table once rather than visiting each peering through every
VPC in vpc_table().values(). Preserve the existing expose, IP-set,
prefix-length, and WIDEST_SPREAD calculation while eliminating duplicate
processing of the same peering.

In `@flow-filter/src/tests.rs`:
- Around line 1404-1418: Add a debug assertion near the Shape::ALL definition or
before the BY_SHAPE indexing paths to verify every Shape variant’s discriminant
matches its position in Shape::ALL. Keep the existing indexing behavior, but
make mismatches fail during debug/test execution rather than silently
misattribute counters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9061116f-9ff1-4856-bde6-02850a4bea6a

📥 Commits

Reviewing files that changed from the base of the PR and between 5576f1f and ab42e83.

📒 Files selected for processing (8)
  • config/src/external/overlay/vpc.rs
  • flow-filter/Cargo.toml
  • flow-filter/src/context/fuzz.rs
  • flow-filter/src/context/mod.rs
  • flow-filter/src/fuzz_gen.rs
  • flow-filter/src/lib.rs
  • flow-filter/src/test_utils.rs
  • flow-filter/src/tests.rs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (2)

flow-filter/src/tests.rs:1583

confidence: 7
tags: [style]

`Shape::ALL.map(|shape| ... BY_SHAPE[shape as usize] ...)` has the same implicit-discriminant indexing assumption as above. Index `BY_SHAPE` by the array position instead, so `Shape` changes can’t desynchronize the counters.
    let by_shape =
        Shape::ALL.map(|shape| (shape, BY_SHAPE[shape as usize].load(Ordering::Relaxed)));
**flow-filter/src/tests.rs:1523**
* ```yaml
confidence: 7
tags: [style]

BY_SHAPE[*shape as usize] relies on the enum’s implicit discriminant values matching the intended indexing order; adding/reordering variants can silently break coverage accounting. Use an explicit match-to-index mapping so the compiler forces updates when Shape changes.

This issue also appears on line 1582 of the same file.

                BY_SHAPE[*shape as usize].fetch_add(1, Ordering::Relaxed);

@qmonnet

qmonnet commented Aug 5, 2026

Copy link
Copy Markdown
Member

Note: It may be worth waiting for the flow-filter fixes to make it first before merging this PR

@daniel-noland
daniel-noland added this pull request to the merge queue Aug 5, 2026
@qmonnet
qmonnet removed this pull request from the merge queue due to a manual request Aug 5, 2026
@qmonnet

qmonnet commented Aug 5, 2026

Copy link
Copy Markdown
Member

Removing from merge queue, I think it's worth waiting for the flow-filter fixes first (but open to discussion)

daniel-noland and others added 3 commits August 6, 2026 17:25
Generate valid ACL overlays and compare reference-table lookups with an
independent oracle over the validated config. Cover ordering, direction,
prefix cross-products, protocols, metadata, IP versions, and defaults.

Compare the same cases with rte_acl to cover backend encoding and priority.
Coverage counters prevent vacuous short runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
Expose validation checks one expose at a time, so a manifest could still
combine IPv4 and IPv6. Filters choose one table version per peering and
could omit rules for the other version.

Require one IP version across a manifest's non-default exposes. Add tests
for both expose orders, default exposes, and valid single-version manifests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
lower_rules previously dropped rules that did not match the selected table's
IP version. Return FailureApply instead so an invariant violation rejects
reconfiguration rather than silently omitting a rule.

Validated manifests prevent this case; the check is defense in depth.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Daniel Noland <daniel@githedgehog.com>
@qmonnet
qmonnet enabled auto-merge August 6, 2026 16:25
@qmonnet

qmonnet commented Aug 6, 2026

Copy link
Copy Markdown
Member

We agreed to merge the fuzz tests first

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@acl-filter/src/fuzz.rs`:
- Around line 161-181: Update Coverage::assert_reached and the fuzz probe
generation flow to make bucket coverage deterministic: add explicit iterations
or targeted ProbeSpec cases that exercise rule allows, rule denies, default
fallbacks, and unconfigured pairs, rather than relying on random ProbeSpec.stray
generation. Preserve the existing counters and assertions, but ensure each
bucket is reached before assert_reached performs its checks.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 725792c0-18ab-4c5e-b228-a65a459bc1a0

📥 Commits

Reviewing files that changed from the base of the PR and between ab42e83 and 1ab1345.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • acl-filter/Cargo.toml
  • acl-filter/src/access.rs
  • acl-filter/src/context.rs
  • acl-filter/src/fuzz.rs
  • acl-filter/src/fuzz_gen.rs
  • acl-filter/src/lib.rs
  • config/src/external/overlay/validation_tests.rs
  • config/src/external/overlay/vpcpeering.rs
  • flow-filter/src/fuzz_gen.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • flow-filter/src/fuzz_gen.rs

Comment thread acl-filter/src/fuzz.rs
Comment on lines +161 to +181
fn assert_reached(&self, label: &str) {
let (allows, denies) = (
self.rule_allows.load(Ordering::Relaxed),
self.rule_denies.load(Ordering::Relaxed),
);
let (defaults, unconfigured) = (
self.default_falls.load(Ordering::Relaxed),
self.unconfigured.load(Ordering::Relaxed),
);
eprintln!(
"{label} coverage: {allows} rule allows, {denies} rule denies, \
{defaults} default fallbacks, {unconfigured} unconfigured pairs"
);
assert!(allows >= 1, "{label}: no rule ever allowed a packet");
assert!(denies >= 1, "{label}: no rule ever denied a packet");
assert!(defaults >= 1, "{label}: never fell through to a default");
assert!(
unconfigured >= 1,
"{label}: never probed a pair with no ACL at all"
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1) Inspect the VpcTable container type and its values() iteration order.
fd -t f 'vpc.rs' | xargs rg -n -C6 'struct VpcTable|fn values|BTreeMap|HashMap|IndexMap'

# 2) Look for a configured bolero iteration bound in the workspace.
fd -t f -e toml -e sh -e yml -e yaml | xargs rg -n -i 'bolero|BOLERO_' 
rg -n 'with_iterations|check!\(\)' --type=rust

Repository: githedgehog/dataplane

Length of output: 14344


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- fuzz.rs target sections ---'
cat -n acl-filter/src/fuzz.rs | sed -n '1,210p;330,390p'
printf '%s\n' '--- VNI declarations and table construction ---'
rg -n -C8 'VNIS|vpc_table\(\)|generated_overlays_use_the_declared_vnis|Coverage|assert_reached|bolero::check|check!' acl-filter/src/fuzz.rs acl-filter/Cargo.toml Cargo.toml
printf '%s\n' '--- local Bolero configuration or test bounds ---'
rg -n -i -C3 'iterations|cases|timeout|bolero' .cargo Cargo.toml acl-filter/Cargo.toml 2>/dev/null || true

Repository: githedgehog/dataplane

Length of output: 22784


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- fuzz generator ---'
fd -t f -i '*fuzz*' acl-filter/src | sort
rg -n -C10 'pub const VNIS|const VNIS|struct OverlaySpec|impl OverlaySpec|fn build|vni\(' acl-filter/src/fuzz_gen.rs acl-filter/src
printf '%s\n' '--- dependency lock information ---'
rg -n -C4 'name = "bolero"|name = "bolero-generator"|name = "bolero-engine"' Cargo.lock
printf '%s\n' '--- Bolero usage and explicit run bounds ---'
rg -n -C3 'with_iterations|with_cases|iterations|cases|BOLERO' --glob '*.rs' --glob '*.toml' --glob '*.yml' --glob '*.yaml' --glob '*.sh' .

Repository: githedgehog/dataplane

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- OverlaySpec::build construction ---'
cat -n acl-filter/src/fuzz_gen.rs | sed -n '259,385p'
printf '%s\n' '--- Bolero lock and local documentation references ---'
sed -n '468,525p' Cargo.lock
rg -n -C5 'with_iterations|auto-iterations|BOLERO_MAX|BOLERO_ITERATIONS|default.*iteration' acl-filter k8s-intf concurrency --glob '*.rs' --glob '*.toml'

Repository: githedgehog/dataplane

Length of output: 9117


🌐 Web query:

Bolero 0.13.4 Rust check! default iterations with_type for_each

💡 Result:

In Bolero 0.13.4, the bolero::check! macro is used for property and fuzz testing [1][2]. Default Iterations: When using bolero::check!, the number of iterations is controlled by the underlying engine [3][4]. While Bolero does not explicitly document a single global "default" iteration count for all environments, you can manually configure the number of iterations for a test target by using the.with_iterations(n) method on the test target builder [5][3][4]. with_type: The.with_type:: method is used to configure the test to generate structured inputs of a specific type T [2]. For this to work, the type T must implement the generator::TypeGenerator trait [2]. This mode is commonly used when you need to test logic that requires complex or structured input rather than raw bytes [2]. for_each: The.for_each(|input| {... }) method is the terminal operation of the bolero::check! pipeline [2]. It accepts a closure that receives the generated input and contains the test logic or assertions to be executed for each generated case [2]. Example Usage: use bolero::check; check!.with_type::<(u8, u16)>.for_each(|(a, b)| { // Assertions and test logic here assert!(a as u32 + b as u32 <= 65535); }); For more granular control over input generation (such as constraints on collection lengths), you can use.with_generator instead of.with_type [2][6].

Citations:


🌐 Web query:

site:docs.rs/bolero/0.13.4 bolero TestTarget with_iterations default iterations DefaultEngine

💡 Result:

For bolero 0.13.4:

  • TestTarget::with_iterations(iterations) sets the number of generated test cases executed. (docs.rs)
  • With the default DefaultEngine/TestEngine, the iteration count comes from rng_cfg.iterations_or_default(). (docs.rs)
  • In fuzzing_random mode, omitting with_iterations changes the count to usize::MAX—effectively running until stopped. (docs.rs)
  • The docs do not expose a numeric default iteration count for normal test mode; use .with_iterations(n) when you need deterministic behavior.

Example:

bolero::check!()
    .with_iterations(10_000)
    .for_each(|input| {
        // test input
    });

Citations:


🌐 Web query:

github bolero 0.13.4 "auto-iterations" "with_iterations"

💡 Result:

The terms auto-iterations and with_iterations are associated with the Bolero library for the Rust programming language, which is a fuzz and property testing framework [1][2]. They are not related to the Bolero F# web framework [3][4]. In the Rust Bolero crate, with_iterations is a method used to configure the number of iterations executed during testing [5][6][7]. Specifically, it allows you to set a fixed number of iterations for a test target [5][7]. The term auto-iterations does not appear as a standard API method in the Bolero Rust documentation [5][6][2]. It is possible that it is either a misunderstanding of how the engine automatically handles iteration limits or refers to internal engine behavior. The Bolero engine is designed to handle execution, and configuration methods like with_iterations are provided to override or set specific constraints [6][7]. If you are seeing references to auto-iterations in the context of Bolero 0.13.4, it is likely related to how the testing engine manages its internal loop or automatic scaling of test inputs, rather than a user-facing configuration parameter [8][1].

Citations:


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- ProbeSpec and probe resolution ---'
rg -n -C12 'struct ProbeSpec|enum Stray|impl.*ProbeSpec|fn resolve|TypeGenerator for ProbeSpec|Anchor' acl-filter/src/fuzz_gen.rs
printf '%s\n' '--- generator defaults and distributions ---'
cat -n acl-filter/src/fuzz_gen.rs | sed -n '120,258p;430,562p'

Repository: githedgehog/dataplane

Length of output: 16676


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from pathlib import Path
import re

gen = Path("acl-filter/src/fuzz_gen.rs").read_text()
vpc = Path("config/src/external/overlay/vpc.rs").read_text()

vnis = re.search(r'pub\(crate\) const VNIS: \[u32; 3\] = \[([0-9, ]+)\]', gen).group(1)
names = re.findall(r'format!\("vpc\{}", index \+ 1\)', gen)
insert_loop = re.search(r'for \(i, id\) in VNIS\.iter\(\)\.enumerate\(\)', gen)
has_stray_option = "stray: Option<Stray>" in gen
stray_changes_vni = "Some(Stray::SrcVni)" in gen and "Some(Stray::DstVni)" in gen
uses_btree = "vpcs: BTreeMap<String, Vpc>" in vpc

assert vnis == "100, 200, 300"
assert names and insert_loop
assert uses_btree
assert has_stray_option and stray_changes_vni
print("VpcTable order: deterministic BTreeMap order matches vpc1/vpc2/vpc3 insertion keys.")
print("Coverage: no generator invariant guarantees all four outcome buckets.")
PY

Repository: githedgehog/dataplane

Length of output: 313


Make coverage checks deterministic. VpcTable uses a BTreeMap, and OverlaySpec::build inserts vpc1vpc3 for [100, 200, 300]; sorting is not needed. Coverage::assert_reached has no equivalent guarantee because ProbeSpec.stray is random and no generator invariant reaches all four buckets. Add explicit iterations and targeted coverage cases before asserting every bucket.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@acl-filter/src/fuzz.rs` around lines 161 - 181, Update
Coverage::assert_reached and the fuzz probe generation flow to make bucket
coverage deterministic: add explicit iterations or targeted ProbeSpec cases that
exercise rule allows, rule denies, default fallbacks, and unconfigured pairs,
rather than relying on random ProbeSpec.stray generation. Preserve the existing
counters and assertions, but ensure each bucket is reached before assert_reached
performs its checks.

@daniel-noland
daniel-noland disabled auto-merge August 7, 2026 06:42
@daniel-noland
daniel-noland enabled auto-merge August 7, 2026 06:42
auto-merge was automatically disabled August 7, 2026 06:49

Pull request was closed

@daniel-noland daniel-noland reopened this Aug 7, 2026
@daniel-noland
daniel-noland enabled auto-merge August 7, 2026 06:56
@daniel-noland
daniel-noland added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 14968ca Aug 7, 2026
52 of 56 checks passed
@daniel-noland
daniel-noland deleted the pr/daniel-noland/flow-filter-coverage branch August 7, 2026 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:+vlab Enable VLAB tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants