Skip to content

feat(dns): derive reverse-DNS zones from network prefixes#2769

Merged
chet merged 1 commit into
NVIDIA:mainfrom
chet:gh-issue-2766
Jun 22, 2026
Merged

feat(dns): derive reverse-DNS zones from network prefixes#2769
chet merged 1 commit into
NVIDIA:mainfrom
chet:gh-issue-2766

Conversation

@chet

@chet chet commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

A network's reverse-DNS zone is a pure function of its prefix (10.0.0.0/160.10.in-addr.arpa), and every network already carries its prefix. So this derives each reverse zone from the network and creates it in the same transaction the network is created — at config init and at runtime — rather than having anyone author it by hand. Reverse zones track networks (static and dynamic) automatically.

  • cidr_to_reverse_zone(prefix) (api-db dns) — the forward inverse of arpa_qname_to_ip; None for prefixes that are not octet/nibble aligned (RFC 2317 classless is out of scope).
  • ensure_reverse_zone(prefix, txn) — creates the arpa domain idempotently (several segments can share one zone), skips non-aligned prefixes.
  • Hook in network_segment::save — the chokepoint both create_initial_networks (config seed) and the runtime create handler route through. The arpa domain registers the zone; PTR records within it resolve via the existing address-keyed lookup (the merged PTR train).

Tests: a cidr_to_reverse_zone table (IPv4/IPv6 aligned + rejected non-aligned), and a DB test that ensure_reverse_zone is idempotent and skips non-aligned prefixes.

Follow-ups (out of scope here): the internal linknet-allocation path (network_segment/allocate.rs) bypasses save, so its segments don't get reverse zones — linknets are point-to-point internals that likely don't want reverse DNS, but worth a deliberate call; and dropping a reverse zone on network deletion when nothing else maps to it.

Implements #2766. Part of the #2630 reverse-DNS epic.

@chet chet requested a review from a team as a code owner June 22, 2026 20:32
@chet

chet commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai PTAL, thanks!

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Network segments now automatically ensure reverse-DNS (PTR) zones for each configured, aligned network prefix, improving out-of-the-box DNS resolution.
    • Reverse zone names are derived from IPv4/IPv6 CIDRs, with creation handled in an idempotent way.
  • Bug Fixes

    • Save-time failures now correctly propagate if reverse-DNS zone creation cannot be completed.
  • Tests

    • Added coverage for IPv4/IPv6 reverse-zone derivation, idempotent creation in a single transaction, and skipping unaligned prefixes.

Walkthrough

The PR introduces cidr_to_reverse_zone and ensure_reverse_zone in the DNS database module to derive and idempotently persist in-addr.arpa/ip6.arpa reverse zones for aligned CIDR prefixes. The network segment save handler is updated to invoke ensure_reverse_zone for each configured prefix within the existing transaction, propagating zone-creation errors identically to other persistence-time failures.

Changes

Reverse-DNS Zone Derivation and Persistence

Layer / File(s) Summary
CIDR-to-reverse-zone derivation and idempotent persistence
crates/api-db/src/dns/mod.rs
Adds IpNetwork, NewDomain, PgConnection, and DatabaseResult imports; implements cidr_to_reverse_zone converting aligned IPv4/IPv6 prefixes to in-addr.arpa/ip6.arpa zone names (returning None for non-aligned prefixes); implements ensure_reverse_zone for idempotent domain record insertion, skipping unaligned prefixes; extends unit tests for zone-name derivation, idempotent creation, and non-aligned prefix behavior.
Network segment save handler wiring
crates/api-core/src/handlers/network_segment.rs
Adds a loop inside the save transaction over network_segment.prefixes that calls db::dns::ensure_reverse_zone for each prefix, propagating errors identically to other persistence-time failures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely captures the primary change: deriving reverse-DNS zones from network prefixes. It is specific, clear, and directly reflects the main objective of the pull request.
Description check ✅ Passed The description provides comprehensive context on the rationale, implementation details, testing strategy, and explicit scoping decisions. It is directly related to the changeset and offers sufficient clarity on the feature's design and limitations.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== PR Files ==="
gh pr view 2769 --repo NVIDIA/infra-controller --json files --jq '.files[].path'

echo ""
echo "=== PR Diff ==="
gh pr diff 2769 --repo NVIDIA/infra-controller

Length of output: 6716


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== domain module in api-db ==="
fd -t f 'mod.rs' --search-path crates/api-db/src/dns/domain/ 2>/dev/null | head -5
fd -t f '*.rs' --search-path crates/api-db/src/dns/ 2>/dev/null

echo ""
echo "=== domain persist and find_by_name ==="
rg -n "pub async fn persist|pub async fn find_by_name|ON CONFLICT|on_conflict|INSERT INTO" crates/api-db/src/dns/ -A 8

echo ""
echo "=== NewDomain definition ==="
rg -n "struct NewDomain|impl NewDomain|fn new" crates/ --type rust -B 2 -A 10 | grep -A 10 "NewDomain"

echo ""
echo "=== network_segment save context around the hook ==="
sed -n '340,420p' crates/api-core/src/handlers/network_segment.rs

echo ""
echo "=== DatabaseResult type alias ==="
rg -n "pub type DatabaseResult|type DatabaseResult" crates/api-db/src/ -A 2

echo ""
echo "=== domain mod.rs full content ==="
cat crates/api-db/src/dns/domain/mod.rs 2>/dev/null || rg -rn "." crates/api-db/src/dns/domain/ 2>/dev/null | head -150

Length of output: 1246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find dns-related rust files ==="
fd -t f '*.rs' | xargs grep -l "fn persist\|fn find_by_name\|NewDomain" 2>/dev/null | head -20

echo ""
echo "=== domain persist implementation ==="
rg -n "async fn persist" --type rust -A 15

echo ""
echo "=== find_by_name implementation ==="
rg -n "async fn find_by_name" --type rust -A 15

echo ""
echo "=== ON CONFLICT in dns-related SQL ==="
rg -n "ON CONFLICT|on_conflict" --type rust -B 2 -A 5 | head -60

echo ""
echo "=== NewDomain struct ==="
rg -n "struct NewDomain" --type rust -A 15

echo ""
echo "=== network_segment save lines 340-430 ==="
rg -n "." crates/api-core/src/handlers/network_segment.rs | sed -n '340,430p'

echo ""
echo "=== dns module tree ==="
fd -t f '*.rs' | grep dns | sort

Length of output: 1342


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== dns module files ==="
fd -e rs | grep -i dns | sort

echo ""
echo "=== domain persist implementation ==="
rg -n "async fn persist" --type rust -A 15

echo ""
echo "=== find_by_name implementation ==="
rg -n "async fn find_by_name" --type rust -A 15

echo ""
echo "=== ON CONFLICT usage ==="
rg -n "ON CONFLICT|on_conflict" --type rust -B 2 -A 5 | head -80

echo ""
echo "=== NewDomain struct ==="
rg -n "struct NewDomain" --type rust -A 15

echo ""
echo "=== network_segment save handler (lines 340-430) ==="
awk 'NR>=340 && NR<=430' crates/api-core/src/handlers/network_segment.rs

echo ""
echo "=== DatabaseResult type ==="
rg -n "DatabaseResult" --type rust | head -10

Length of output: 93380



@chet — thorough and well-structured change. The core design is sound; a few observations follow.


1. TOCTOU race condition in ensure_reverse_zone (high priority)

crates/api-db/src/dns/mod.rs

if domain::find_by_name(&mut *txn, &zone).await?.is_empty() {
    domain::persist(NewDomain::new(zone), txn).await?;
}

The read-then-conditional-write pattern is not atomic across concurrent transactions. If two network segments that map to the same reverse zone (e.g., 10.0.0.0/24 and 10.0.1.0/24 both map to 0.10.in-addr.arpa for a /16) are created simultaneously, both transactions can pass the is_empty() gate and both call domain::persist, which executes a bare INSERT INTO domains … RETURNING * with no conflict clause. Depending on whether domains.name carries a DB-level unique constraint, this either silently creates duplicate zone rows (a data integrity bug) or surfaces an unhandled unique constraint violation (a noisy 500).

The idiomatic fix for this pattern in the codebase — see dhcp_entry, explored_endpoints, machine_validation — is INSERT … ON CONFLICT DO NOTHING. The cleanest resolution is to expose a dedicated upsert path in domain:

// crates/api-db/src/dns/domain.rs
pub async fn ensure(value: NewDomain, txn: &mut PgConnection) -> DatabaseResult<()> {
    validate_domain_name(&value.name)?;
    let metadata_id = super::domain_metadata::DbMetadata::create_default(txn).await?;
    let query = "INSERT INTO domains (name, soa, domain_metadata_id)
                 VALUES ($1, $2, $3)
                 ON CONFLICT (name) DO NOTHING";
    sqlx::query(query)
        .bind(&value.name)
        .bind(sqlx::types::Json(&value.soa))
        .bind(metadata_id)
        .execute(txn)
        .await
        .map_err(|e| DatabaseError::query(query, e))?;
    Ok(())
}

And ensure_reverse_zone collapses to:

pub async fn ensure_reverse_zone(prefix: IpNetwork, txn: &mut PgConnection) -> DatabaseResult<()> {
    let Some(zone) = cidr_to_reverse_zone(prefix) else {
        tracing::debug!(%prefix, "no reverse zone: prefix is not octet/nibble aligned");
        return Ok(());
    };
    tracing::info!(zone = %zone, %prefix, "ensuring reverse-DNS zone for network prefix");
    domain::ensure(NewDomain::new(zone), txn).await
}

This also eliminates the orphaned domain_metadata row risk that the two-step path carries under concurrent aborts.


2. /32 and /128 host-prefix zones (design question)

cidr_to_reverse_zone accepts /32 (and by extension /128):

"192.0.2.1/32" => Some("1.2.0.192.in-addr.arpa".to_string()),

A single-host reverse zone is RFC-valid but unusual: no address other than the host itself can ever resolve within it. Depending on whether /32 prefixes appear as real network segment prefixes in this system (vs. only in loopbacks or linknet ends), this may or may not be intentional. Worth an explicit call in the doc comment either way.


3. Missing IPv6 path in the DB integration test (medium priority)

ensure_reverse_zone_creates_idempotently only exercises the IPv4 path (10.0.0.0/16). An IPv6 case (e.g., fd00::/48) would guard against nibble-order regressions in cidr_to_reverse_zone at the DB level and increase confidence in the full stack:

let v6_prefix: ipnetwork::IpNetwork = "fd00::/48".parse().unwrap();
super::ensure_reverse_zone(v6_prefix, txn.as_mut()).await.unwrap();
super::ensure_reverse_zone(v6_prefix, txn.as_mut()).await.unwrap();
let v6_zones = super::domain::find_by_name(txn.as_mut(), "0.0.0.0.d.f.ip6.arpa").await.unwrap();
assert_eq!(v6_zones.len(), 1, "IPv6 reverse zone created exactly once");

4. Weak assertion for the non-aligned case in the DB test (minor)

super::ensure_reverse_zone(unaligned, txn.as_mut()).await.unwrap();
assert!(super::cidr_to_reverse_zone(unaligned).is_none()); // pure-function check only

The second assertion validates the pure function in isolation but does not confirm that nothing was actually written to the database. A stronger assertion:

let zones = super::domain::find_by_name(txn.as_mut(), /* any arpa name */)
    .await
    .unwrap();
assert!(zones.is_empty(), "non-aligned prefix must not create a zone");

The IPv6 nibble computation and the arpa_qname_to_ip inverse relationship are correct — manually traced against all test vectors. The hook placement in network_segment::save is the right chokepoint. The follow-ups (linknet path, zone deletion) are clearly scoped out.

@coderabbitai coderabbitai Bot 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.

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 `@crates/api-db/src/dns/mod.rs`:
- Around line 125-134: The ensure_reverse_zone function has a race condition
where concurrent transactions can both see an empty result from
domain::find_by_name and then both attempt to call domain::persist, causing one
to fail with a unique constraint violation. Fix this by either catching the
unique constraint violation error from the domain::persist call and treating it
as success (since another transaction created the same domain concurrently), or
refactor domain::persist to support an upsert pattern using ON CONFLICT DO
NOTHING to atomically handle the insert-or-ignore scenario. This ensures the
function maintains its idempotency contract under concurrent access.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 51b07489-e102-4ee6-a961-b3694212ad3d

📥 Commits

Reviewing files that changed from the base of the PR and between 2c774c9 and d66f076.

📒 Files selected for processing (2)
  • crates/api-core/src/handlers/network_segment.rs
  • crates/api-db/src/dns/mod.rs

Comment thread crates/api-db/src/dns/mod.rs
A network's reverse-DNS zone is a pure function of its prefix -- `10.0.0.0/16` is `0.10.in-addr.arpa` -- and every network already carries its prefix. So rather than have anyone author reverse zones by hand, this derives each zone from the network and creates it in the same transaction the network is created, at config init and at runtime alike. Reverse zones now track networks, static and dynamic, on their own.

`cidr_to_reverse_zone` (the forward inverse of `arpa_qname_to_ip`) turns a prefix into its arpa zone name; `ensure_reverse_zone` creates the domain idempotently -- several segments can share a zone -- and skips prefixes that are not octet/nibble aligned (RFC 2317 classless is out of scope). The hook sits in `network_segment::save`, the chokepoint both the config seed (`create_initial_networks`) and the runtime create handler route through. The arpa domain registers the zone; PTR records within it already resolve through the address-keyed lookup.

Tests cover the derivation (IPv4/IPv6 aligned prefixes and rejected non-aligned ones) and an idempotent, skip-on-non-aligned `ensure_reverse_zone` against the database.

This supports NVIDIA#2766.

Signed-off-by: Chet Nichols III <chetn@nvidia.com>
@chet

chet commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai Thanks for the eyes. Declining the concurrency hardening -- this race can't occur here. network_prefixes are globally non-overlapping (EXCLUDE USING gist (prefix inet_ops WITH &&), surfaced as network_prefixes_prefix_excl), and a reverse zone maps 1:1 to a prefix, so two segments can't hold prefixes for the same zone; a duplicate prefix fails in network_segment::save before ensure_reverse_zone is reached -- even concurrently, the gist exclusion serializes the conflicting inserts. (domains.name isn't unique either -- that constraint was dropped in 20221107190608 -- so the unique violation wouldn't happen regardless.) The find-then-create guards against duplicating a zone an earlier same-prefix segment left behind, not concurrency; I corrected the doc comment to say so. PTAL.

@chet

chet commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

@chet — the explanation is airtight. The GIST exclusion (inet_ops WITH &&) on network_prefixes enforces that no two overlapping prefixes coexist; since cidr_to_reverse_zone is injective over non-overlapping aligned prefixes, any two transactions that would produce the same reverse zone must be competing on the same (or overlapping) prefix — a conflict already serialized at the DB level before ensure_reverse_zone is reached. The absence of a unique constraint on domains.name further confirms the original violation scenario was unreachable. Withdrawing the TOCTOU concern. Thank you for the thorough explanation and the corrected doc comment.


✏️ Learnings added
Learnt from: chet
URL: https://github.com/NVIDIA/infra-controller/pull/2769

Timestamp: 2026-06-22T20:43:36.436Z
Learning: In the NVIDIA/infra-controller repository, `network_prefixes` carries a GIST exclusion constraint (`EXCLUDE USING gist (prefix inet_ops WITH &&)`, surface name `network_prefixes_prefix_excl`) that prevents any two overlapping prefixes from coexisting. Because `cidr_to_reverse_zone` is injective over non-overlapping, octet/nibble-aligned prefixes, two concurrent transactions cannot map to the same reverse DNS zone unless they compete on the same prefix — a conflict already serialized by the GIST exclusion. Additionally, `domains.name` has no unique constraint (it was dropped in migration `20221107190608`), so a DB-level unique-violation on zone names is not possible. The find-then-create pattern in `ensure_reverse_zone` guards only against re-creating an orphaned zone left by a previously deleted segment, not against concurrency.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot 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.

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 `@crates/api-db/src/dns/mod.rs`:
- Around line 186-191: The test currently only verifies that
cidr_to_reverse_zone returns None for unaligned prefixes, but does not verify
that ensure_reverse_zone actually performs a no-op on the database. Add
assertions to verify database behavior by querying the domain count before and
after the ensure_reverse_zone call using sqlx::query_scalar to fetch a single
scalar count value, then assert that both counts are identical to confirm the
unaligned prefix insertion was skipped in the database.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: dd944f71-bb79-4baf-9fa9-35d1bcadfb77

📥 Commits

Reviewing files that changed from the base of the PR and between 767c1a7 and 70fb349.

📒 Files selected for processing (2)
  • crates/api-core/src/handlers/network_segment.rs
  • crates/api-db/src/dns/mod.rs

Comment thread crates/api-db/src/dns/mod.rs

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
crates/api-db/src/dns/mod.rs (1)

170-192: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add an IPv6 integration case to ensure_reverse_zone persistence test.

Line 172-Line 184 validates idempotent persistence only for IPv4; an IPv6 case should be included so DB-path regressions in ip6.arpa creation are caught by integration tests too.

Suggested test tightening
 #[crate::sqlx_test]
 async fn ensure_reverse_zone_creates_idempotently(pool: sqlx::PgPool) {
     let mut txn = pool.begin().await.unwrap();
-    let prefix: ipnetwork::IpNetwork = "10.0.0.0/16".parse().unwrap();
-
-    // First call creates the zone; the second is a no-op.
-    super::ensure_reverse_zone(prefix, txn.as_mut())
-        .await
-        .unwrap();
-    super::ensure_reverse_zone(prefix, txn.as_mut())
-        .await
-        .unwrap();
-    let zones = super::domain::find_by_name(txn.as_mut(), "0.10.in-addr.arpa")
-        .await
-        .unwrap();
-    assert_eq!(zones.len(), 1, "reverse zone created exactly once");
+    for (prefix, expected_zone) in [
+        ("10.0.0.0/16", "0.10.in-addr.arpa"),
+        ("fd00::/48", "0.0.d.f.ip6.arpa"),
+    ] {
+        let prefix: ipnetwork::IpNetwork = prefix.parse().unwrap();
+        super::ensure_reverse_zone(prefix, txn.as_mut())
+            .await
+            .unwrap();
+        super::ensure_reverse_zone(prefix, txn.as_mut())
+            .await
+            .unwrap();
+        let zones = super::domain::find_by_name(txn.as_mut(), expected_zone)
+            .await
+            .unwrap();
+        assert_eq!(zones.len(), 1, "reverse zone created exactly once for {prefix}");
+    }

As per coding guidelines, “Prefer table-driven tests…” and “Reach for a table whenever two or more tests call the same operation with different inputs.”

🤖 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 `@crates/api-db/src/dns/mod.rs` around lines 170 - 192, The test
`ensure_reverse_zone_creates_idempotently` currently only validates IPv4 address
handling; it needs to include IPv6 test cases to ensure `ip6.arpa` zone creation
is properly tested for regressions. Refactor the test to use a table-driven test
approach by creating a test data table containing multiple test cases (both IPv4
and IPv6 prefixes with their expected reverse zone names), then iterate through
each case within the test body to validate that `ensure_reverse_zone` creates
zones idempotently for both IPv4 and IPv6 address families.

Source: Coding guidelines

🤖 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 `@crates/api-db/src/dns/mod.rs`:
- Around line 170-192: The test `ensure_reverse_zone_creates_idempotently`
currently only validates IPv4 address handling; it needs to include IPv6 test
cases to ensure `ip6.arpa` zone creation is properly tested for regressions.
Refactor the test to use a table-driven test approach by creating a test data
table containing multiple test cases (both IPv4 and IPv6 prefixes with their
expected reverse zone names), then iterate through each case within the test
body to validate that `ensure_reverse_zone` creates zones idempotently for both
IPv4 and IPv6 address families.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fd4fb5d5-5ab8-449b-930a-23976abb5074

📥 Commits

Reviewing files that changed from the base of the PR and between 767c1a7 and 70fb349.

📒 Files selected for processing (2)
  • crates/api-core/src/handlers/network_segment.rs
  • crates/api-db/src/dns/mod.rs

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
boot-artifacts-aarch64 3 0 0 3 0 0
boot-artifacts-x86_64 3 0 0 3 0 0
forge-admin-cli-x86_64 264 6 23 99 6 130
machine-validation-runner 714 34 183 266 35 196
machine_validation 714 34 183 266 35 196
nvmetal-carbide 714 34 183 266 35 196
TOTAL 2412 108 572 903 111 718

Per-CVE detail lives in the per-service grype-* artifacts (JSON + SARIF). Severity counts only — no CVE IDs published here.

@chet chet merged commit 7560697 into NVIDIA:main Jun 22, 2026
55 checks passed
@chet chet deleted the gh-issue-2766 branch June 22, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants