IFC-2271 IPAM find closes matched prefix for IP/prefix#8611
IFC-2271 IPAM find closes matched prefix for IP/prefix#8611
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a parent-prefix lookup for IP/CIDR search queries. Introduces 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Merging this PR will improve performance by 38.22%
Performance Changes
Comparing |
| return result.data["InfrahubSearchAnywhere"] | ||
|
|
||
|
|
||
| async def test_search_parent_prefix_ipv4(db: InfrahubDatabase, ip_dataset_01: dict[str, Any], branch: Branch) -> None: |
There was a problem hiding this comment.
These tests are testing multiple things within the same test functions, but this helps in saving time during tests. I tried having more simple/individual tests but testing time increased by 25% for this file.
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
dev/specs/infp-431-ipam-closest-prefix/plan.md (1)
8-8: Tighten wording in the summary sentence.“exact same code path” can be shortened to “same code path” for cleaner phrasing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dev/specs/infp-431-ipam-closest-prefix/plan.md` at line 8, Update the summary sentence in the plan to tighten wording by replacing “exact same code path” with “same code path”; ensure the sentence still notes the feature is additive and references the new IPParentPrefixLookupQuery (which adapts IPPrefixReconcileQuery) and the “Parent Prefixes” section for Cmd+K search results.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/infrahub/core/query/ipam.py`:
- Around line 156-188: The query currently selects candidate AttributeIPNetwork
rows and walks back to parent_prefix without resolving branch-effective
relations, which can return stale ancestor values or detached prefixes; refactor
the block (the cypher built around ip_prefix_attribute_kind, ip_prefix_kind,
AttributeIPNetwork and parent_prefix) to follow the
IPPrefixReconcileQuery.get_new_parent_query() pattern: first shortlist
candidates using the index (binary_address IN $possible_prefix_list /
possible_prefix_and_length_list), then for each candidate resolve the latest
active HAS_VALUE relation and the latest active ip_namespace__ip_prefix /
IS_PART_OF (namespace link) relation using branch-level ordering and
head(collect(...)) logic to get branch-effective values, re-apply the prefixlen
matching test against those resolved active values, and only then RETURN
parent_prefix.uuid / kind / prefixlen so the returned parent_prefix is validated
as active on the current branch.
In `@backend/infrahub/graphql/queries/search.py`:
- Around line 142-143: The resolver currently uses the original input `q` for
text-search branches even when `_try_parse_ip_or_prefix(q)` returns a
canonicalized `parsed_ip` (e.g., turning host-bit CIDRs into network form), so
the exact prefix is lost from results; update the code in `search.py` to
replace/assign `q = parsed_ip` (or otherwise canonicalize the search string to
the parsed value) immediately after `_try_parse_ip_or_prefix(q)` succeeds,
before executing the `NodeGetListByAttributeValueQuery` / `NodeManager.query`
text-search branches, and add a regression test that calls the resolver with a
host-bit CIDR input (like `10.1.2.45/24`) asserting the normalized `10.1.2.0/24`
appears in `edges`.
In `@dev/specs/infp-431-ipam-closest-prefix/data-model.md`:
- Around line 43-55: The example IPParentPrefixResult.from_db accesses a nested
"parent_prefix" node but the actual query returns flat labels parent_prefix_uuid
and parent_prefix_kind; update the from_db implementation in
IPParentPrefixResult to read result.get("parent_prefix_uuid") and
result.get("parent_prefix_kind") (keeping the same field names prefix_id and
prefix_kind) so the dataclass aligns with the QueryResult produced by
IPParentPrefixLookupQuery.
In `@dev/specs/infp-431-ipam-closest-prefix/plan.md`:
- Around line 43-51: Update the structure section to use repository-relative
paths by changing the top entry from "specs/infp-431-ipam-closest-prefix/" to
"dev/specs/infp-431-ipam-closest-prefix/" and ensure any other listed entries
follow the same "dev/..." prefix convention; also make the Markdown guideline
reference consistent by keeping the exact quoted path
"dev/guidelines/markdown.md" in the comment so readers can follow the guideline
exactly.
In `@dev/specs/infp-431-ipam-closest-prefix/tasks.md`:
- Around line 3-5: Update the inconsistent root paths so all spec references
point to the repository's actual location under dev/specs; replace occurrences
of "specs/infp-431-ipam-closest-prefix/" with
"dev/specs/infp-431-ipam-closest-prefix/" in this file (including the header
Input line and the structure/prerequisites block listing plan.md, spec.md,
research.md, data-model.md, contracts/), and also fix the same pattern in the
other affected lines (mentions around lines 43-51) to ensure all Markdown links
and the referenced guideline rule remain valid.
---
Nitpick comments:
In `@dev/specs/infp-431-ipam-closest-prefix/plan.md`:
- Line 8: Update the summary sentence in the plan to tighten wording by
replacing “exact same code path” with “same code path”; ensure the sentence
still notes the feature is additive and references the new
IPParentPrefixLookupQuery (which adapts IPPrefixReconcileQuery) and the “Parent
Prefixes” section for Cmd+K search results.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ad547a7a-f8a0-4137-8d78-0d311bb99a61
📒 Files selected for processing (16)
backend/infrahub/core/query/ipam.pybackend/infrahub/graphql/queries/search.pybackend/tests/component/graphql/queries/test_search.pybackend/tests/unit/graphql/queries/__init__.pybackend/tests/unit/graphql/queries/test_search.pychangelog/+ifc2271.added.mddev/specs/infp-431-ipam-closest-prefix/contracts/graphql-schema.mddev/specs/infp-431-ipam-closest-prefix/data-model.mddev/specs/infp-431-ipam-closest-prefix/plan.mddev/specs/infp-431-ipam-closest-prefix/quickstart.mddev/specs/infp-431-ipam-closest-prefix/research.mddev/specs/infp-431-ipam-closest-prefix/spec.mddev/specs/infp-431-ipam-closest-prefix/tasks.mdfrontend/app/src/shared/api/graphql/graphql-cache.d.tsfrontend/app/src/shared/api/graphql/graphql-env.d.tsschema/schema.graphql
Also add a regression test cover this scenario.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
backend/infrahub/core/query/ipam.py (1)
177-211:⚠️ Potential issue | 🟠 MajorRequire a branch-effective namespace path before accepting
maybe_parent.This block revalidates the node and its latest
prefixvalue, but it still never proves thatmaybe_parentis currently attached through an activeip_namespace__ip_prefixrelation on this branch. A prefix detached from every namespace will still pass here and leak intoparent_prefixes. Please mirror theparent_in_namespacestep used byIPPrefixReconcileQuery.get_new_parent_query()before returning the candidate.As per coding guidelines "Read dev/knowledge/backend/database-schema.md when writing or modifying Cypher queries to understand vertex/edge types, properties, and temporal branching rules".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/infrahub/core/query/ipam.py` around lines 177 - 211, The query must require that maybe_parent has a branch-effective ip_namespace__ip_prefix relation before accepting it; add a CALL block (mirroring IPPrefixReconcileQuery.get_new_parent_query) that OPTIONAL MATCHes (maybe_parent)-[r:ip_namespace__ip_prefix]->(ns:Namespace) with the same %(branch_filter)s, computes r.status = "active" as is_active, ORDER BY r.branch_level DESC, r.from DESC, r.status ASC and RETURN head(collect(is_active)) = TRUE AS node_in_namespace, then filter WHERE node_in_namespace = TRUE before continuing to the prefix-resolution CALL that produces allowed_av so detached prefixes cannot be included in parent_prefixes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@backend/infrahub/core/query/ipam.py`:
- Around line 177-211: The query must require that maybe_parent has a
branch-effective ip_namespace__ip_prefix relation before accepting it; add a
CALL block (mirroring IPPrefixReconcileQuery.get_new_parent_query) that OPTIONAL
MATCHes (maybe_parent)-[r:ip_namespace__ip_prefix]->(ns:Namespace) with the same
%(branch_filter)s, computes r.status = "active" as is_active, ORDER BY
r.branch_level DESC, r.from DESC, r.status ASC and RETURN
head(collect(is_active)) = TRUE AS node_in_namespace, then filter WHERE
node_in_namespace = TRUE before continuing to the prefix-resolution CALL that
produces allowed_av so detached prefixes cannot be included in parent_prefixes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9cc97b21-2ef7-45f5-aabd-09b6b2ea9c5a
📒 Files selected for processing (2)
backend/infrahub/core/query/ipam.pybackend/tests/component/graphql/queries/test_search.py
There was a problem hiding this comment.
♻️ Duplicate comments (1)
backend/infrahub/core/query/ipam.py (1)
172-216:⚠️ Potential issue | 🟠 MajorRe-check active namespace membership before returning
maybe_parent.After Line 175,
maybe_parentis only validated againstIS_PART_OFand its branch-effectiveprefixvalue. If a branch deletes theip_namespace__ip_prefixlink but leaves the node/value active, this prefix still passes and leaks intoparent_prefixes. Please mirror theparent_in_namespacefiltering pattern already used inIPPrefixReconcileQuery.get_new_parent_query()before the finalRETURN.As per coding guidelines "Read dev/knowledge/backend/database-schema.md when writing or modifying Cypher queries to understand vertex/edge types, properties, and temporal branching rules".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/infrahub/core/query/ipam.py` around lines 172 - 216, The query returns maybe_parent without verifying branch-effective membership in the ip_namespace__ip_prefix relationship, allowing prefixes deleted on a branch to leak into parent_prefixes; mirror the parent_in_namespace filtering used in IPPrefixReconcileQuery.get_new_parent_query(): add a CALL block (or OPTIONAL MATCH) that finds (maybe_parent)-[r:ip_namespace__ip_prefix]->(:Namespace) (using the same %(branch_filter)s), order by r.branch_level, r.from, r.status, take head(collect(r)) and require that latest_r IS NOT NULL and latest_r.status = "active" before allowing maybe_parent through; place this check after the existing node_is_active and before the final RETURN so only branch-effective namespace-linked prefixes are returned.
🧹 Nitpick comments (1)
backend/tests/component/graphql/queries/test_search.py (1)
514-572: Add the host-bits regression case alongside these IPv4 checks.These cases cover plain addresses and canonical CIDRs, but not the split behavior that motivated the resolver change: a query like
10.10.1.1/24should still match the stored interface-style value inedgeswhileparent_prefixesare derived from the canonicalized network. Without that case, a future normalization ofqin the text-search branch can regress silently.Based on learnings "Normalizing
qfrom the parsed IP would cause text search to miss objects stored with host bits set. Only theIPParentPrefixLookupQueryuses the parsed/normalized form."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/tests/component/graphql/queries/test_search.py` around lines 514 - 572, Add a test case in test_search_parent_prefix_ipv4 that submits the host-bits query "10.10.1.1/24" via _search_with_parent_prefixes and asserts that edges still include the stored interface-style object (e.g. ip_dataset_01["address11"].id) while parent_prefixes are derived from the canonical network (i.e. include broader parents like ip_dataset_01["net140"].id, ip_dataset_01["net146"].id and/or ip_dataset_01["net240"].id) and explicitly exclude the exact /24 prefix (ip_dataset_01["net142"].id); add this right after the existing CIDR exact-match block so the test covers the host-bits regression for IPParentPrefixLookupQuery and ensures resolver normalization doesn’t hide host-bit-stored edges.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@backend/infrahub/core/query/ipam.py`:
- Around line 172-216: The query returns maybe_parent without verifying
branch-effective membership in the ip_namespace__ip_prefix relationship,
allowing prefixes deleted on a branch to leak into parent_prefixes; mirror the
parent_in_namespace filtering used in
IPPrefixReconcileQuery.get_new_parent_query(): add a CALL block (or OPTIONAL
MATCH) that finds (maybe_parent)-[r:ip_namespace__ip_prefix]->(:Namespace)
(using the same %(branch_filter)s), order by r.branch_level, r.from, r.status,
take head(collect(r)) and require that latest_r IS NOT NULL and latest_r.status
= "active" before allowing maybe_parent through; place this check after the
existing node_is_active and before the final RETURN so only branch-effective
namespace-linked prefixes are returned.
---
Nitpick comments:
In `@backend/tests/component/graphql/queries/test_search.py`:
- Around line 514-572: Add a test case in test_search_parent_prefix_ipv4 that
submits the host-bits query "10.10.1.1/24" via _search_with_parent_prefixes and
asserts that edges still include the stored interface-style object (e.g.
ip_dataset_01["address11"].id) while parent_prefixes are derived from the
canonical network (i.e. include broader parents like ip_dataset_01["net140"].id,
ip_dataset_01["net146"].id and/or ip_dataset_01["net240"].id) and explicitly
exclude the exact /24 prefix (ip_dataset_01["net142"].id); add this right after
the existing CIDR exact-match block so the test covers the host-bits regression
for IPParentPrefixLookupQuery and ensures resolver normalization doesn’t hide
host-bit-stored edges.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a2cf5bb7-0420-41c8-9044-71ff70346b65
📒 Files selected for processing (2)
backend/infrahub/core/query/ipam.pybackend/tests/component/graphql/queries/test_search.py
05d248c to
339b5d7
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (2)
backend/infrahub/core/query/ipam.py (1)
89-93: Consider addingfrom_dbclassmethod for consistency.Other similar frozen dataclasses in this file (
IPPrefixFreeData,IPv6PrefixFreeData,IPAddressFreeData, etc.) include afrom_db(cls, result: QueryResult)classmethod. Whileget_data()directly constructs instances, addingfrom_dbwould maintain consistency and allow reuse if the result structure changes.♻️ Suggested addition
`@dataclass`(frozen=True) class IPParentPrefixResult: prefix_id: str prefix_kind: str + + `@classmethod` + def from_db(cls, result: QueryResult) -> IPParentPrefixResult: + return cls( + prefix_id=result.get_as_type("parent_prefix_uuid", return_type=str), + prefix_kind=result.get_as_type("parent_prefix_kind", return_type=str), + )Then in
get_data():def get_data(self) -> list[IPParentPrefixResult]: - return [ - IPParentPrefixResult( - prefix_id=result.get_as_type("parent_prefix_uuid", return_type=str), - prefix_kind=result.get_as_type("parent_prefix_kind", return_type=str), - ) - for result in self.get_results() - ] + return [IPParentPrefixResult.from_db(result) for result in self.get_results()]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/infrahub/core/query/ipam.py` around lines 89 - 93, Add a from_db classmethod to the frozen dataclass IPParentPrefixResult that accepts a QueryResult (or similarly typed DB row) and returns an IPParentPrefixResult built from the row fields; implement it analogously to other dataclasses in this file (e.g., IPPrefixFreeData.from_db) mapping prefix_id and prefix_kind from the result, and update the get_data() call sites to construct instances via IPParentPrefixResult.from_db(result) to keep construction consistent and reusable.dev/specs/infp-431-ipam-closest-prefix/plan.md (1)
4-4: Use consistent repository-relative path.Line 4 references
/specs/infp-431-ipam-closest-prefix/spec.md, but this file is located atdev/specs/infp-431-ipam-closest-prefix/plan.md. For consistency with the actual file structure, update the path todev/specs/infp-431-ipam-closest-prefix/spec.md.📝 Proposed fix for path consistency
-**Input**: Feature specification from `/specs/infp-431-ipam-closest-prefix/spec.md` +**Input**: Feature specification from `dev/specs/infp-431-ipam-closest-prefix/spec.md`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dev/specs/infp-431-ipam-closest-prefix/plan.md` at line 4, Update the repository-relative path referenced in dev/specs/infp-431-ipam-closest-prefix/plan.md by replacing the incorrect "/specs/infp-431-ipam-closest-prefix/spec.md" string with the correct "dev/specs/infp-431-ipam-closest-prefix/spec.md" so the link matches the actual file location; ensure the updated path appears anywhere in plan.md where the old path string is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@backend/infrahub/core/query/ipam.py`:
- Around line 89-93: Add a from_db classmethod to the frozen dataclass
IPParentPrefixResult that accepts a QueryResult (or similarly typed DB row) and
returns an IPParentPrefixResult built from the row fields; implement it
analogously to other dataclasses in this file (e.g., IPPrefixFreeData.from_db)
mapping prefix_id and prefix_kind from the result, and update the get_data()
call sites to construct instances via IPParentPrefixResult.from_db(result) to
keep construction consistent and reusable.
In `@dev/specs/infp-431-ipam-closest-prefix/plan.md`:
- Line 4: Update the repository-relative path referenced in
dev/specs/infp-431-ipam-closest-prefix/plan.md by replacing the incorrect
"/specs/infp-431-ipam-closest-prefix/spec.md" string with the correct
"dev/specs/infp-431-ipam-closest-prefix/spec.md" so the link matches the actual
file location; ensure the updated path appears anywhere in plan.md where the old
path string is used.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 4819f071-6ff3-45b0-9b27-bc18e56f5ea8
📒 Files selected for processing (16)
backend/infrahub/core/query/ipam.pybackend/infrahub/graphql/queries/search.pybackend/tests/component/graphql/queries/test_search.pybackend/tests/unit/graphql/queries/__init__.pybackend/tests/unit/graphql/queries/test_search.pychangelog/+ifc2271.added.mddev/specs/infp-431-ipam-closest-prefix/contracts/graphql-schema.mddev/specs/infp-431-ipam-closest-prefix/data-model.mddev/specs/infp-431-ipam-closest-prefix/plan.mddev/specs/infp-431-ipam-closest-prefix/quickstart.mddev/specs/infp-431-ipam-closest-prefix/research.mddev/specs/infp-431-ipam-closest-prefix/spec.mddev/specs/infp-431-ipam-closest-prefix/tasks.mdfrontend/app/src/shared/api/graphql/graphql-cache.d.tsfrontend/app/src/shared/api/graphql/graphql-env.d.tsschema/schema.graphql
🚧 Files skipped from review as they are similar to previous changes (7)
- dev/specs/infp-431-ipam-closest-prefix/spec.md
- backend/tests/unit/graphql/queries/test_search.py
- dev/specs/infp-431-ipam-closest-prefix/research.md
- changelog/+ifc2271.added.md
- dev/specs/infp-431-ipam-closest-prefix/data-model.md
- dev/specs/infp-431-ipam-closest-prefix/contracts/graphql-schema.md
- frontend/app/src/shared/api/graphql/graphql-cache.d.ts
339b5d7 to
c8fd931
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
backend/tests/component/graphql/queries/test_search.py (1)
514-573: Add a host-bit CIDR regression case.These IPv4 assertions never exercise the
10.10.1.1/24input that motivated keeping rawqforedgeswhile only normalizing the parent-prefix lookup. Without that case, a future refactor can break the exact-match edge behavior without failing this suite.Suggested addition
+ # Host-bit CIDR keeps the exact stored IP object in edges while parent lookup uses the normalized /24 + data = await _search_with_parent_prefixes(gql_params=gql_params, query="10.10.1.1/24") + assert data["parent_prefixes"] is not None + edge_ids = {e["node"]["id"] for e in data["edges"]} + assert ip_dataset_01["address11"].id in edge_ids + parent_ids = {pp["node"]["id"] for pp in data["parent_prefixes"]} + assert ip_dataset_01["net143"].id not in parent_ids + assert ip_dataset_01["net140"].id in parent_idsBased on learnings, "IP address objects can be stored with host bits set (e.g.,
10.10.1.1/24as a copy-pasted interface address). The search resolver intentionally keeps the original query stringqfor text-search branches ... Only theIPParentPrefixLookupQueryuses the parsed/normalized form."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/tests/component/graphql/queries/test_search.py` around lines 514 - 573, Add a regression case in test_search_parent_prefix_ipv4 that queries the host-bit CIDR "10.10.1.1/24" (use the existing helper _search_with_parent_prefixes) and assert that edges include the exact /24 prefix (ip_dataset_01["net142"].id) while parent_prefixes excludes that exact match but still contains the broader parents (e.g., ip_dataset_01["net140"].id and ip_dataset_01["net146"].id); place the new assertions near the other CIDR/exact-match checks in the same test so the behavior of edges (using raw q) vs IPParentPrefixLookupQuery normalization is validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dev/specs/infp-431-ipam-closest-prefix/plan.md`:
- Around line 28-30: Update the table wording to avoid contradiction by
explicitly stating that there are no persistence/database schema changes: change
the Line referencing "No schema changes" to "No database/persistence schema
changes" and add a brief qualifier in the III row noting that the GraphQL API
contract is extended (new typed field parent_prefixes and IPParentPrefixResult)
but this does not alter the underlying DB schema; reference the existing symbols
BuiltinIPPrefix, AttributeIPNetwork, BuiltinIPNamespace, IPParentPrefixResult,
and parent_prefixes so reviewers can verify the distinction.
---
Nitpick comments:
In `@backend/tests/component/graphql/queries/test_search.py`:
- Around line 514-573: Add a regression case in test_search_parent_prefix_ipv4
that queries the host-bit CIDR "10.10.1.1/24" (use the existing helper
_search_with_parent_prefixes) and assert that edges include the exact /24 prefix
(ip_dataset_01["net142"].id) while parent_prefixes excludes that exact match but
still contains the broader parents (e.g., ip_dataset_01["net140"].id and
ip_dataset_01["net146"].id); place the new assertions near the other
CIDR/exact-match checks in the same test so the behavior of edges (using raw q)
vs IPParentPrefixLookupQuery normalization is validated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c181da0e-ad1a-414c-ab94-84fb1719eece
📒 Files selected for processing (16)
backend/infrahub/core/query/ipam.pybackend/infrahub/graphql/queries/search.pybackend/tests/component/graphql/queries/test_search.pybackend/tests/unit/graphql/queries/__init__.pybackend/tests/unit/graphql/queries/test_search.pychangelog/+ifc2271.added.mddev/specs/infp-431-ipam-closest-prefix/contracts/graphql-schema.mddev/specs/infp-431-ipam-closest-prefix/data-model.mddev/specs/infp-431-ipam-closest-prefix/plan.mddev/specs/infp-431-ipam-closest-prefix/quickstart.mddev/specs/infp-431-ipam-closest-prefix/research.mddev/specs/infp-431-ipam-closest-prefix/spec.mddev/specs/infp-431-ipam-closest-prefix/tasks.mdfrontend/app/src/shared/api/graphql/graphql-cache.d.tsfrontend/app/src/shared/api/graphql/graphql-env.d.tsschema/schema.graphql
✅ Files skipped from review due to trivial changes (1)
- dev/specs/infp-431-ipam-closest-prefix/tasks.md
🚧 Files skipped from review as they are similar to previous changes (5)
- dev/specs/infp-431-ipam-closest-prefix/spec.md
- backend/tests/unit/graphql/queries/test_search.py
- dev/specs/infp-431-ipam-closest-prefix/contracts/graphql-schema.md
- dev/specs/infp-431-ipam-closest-prefix/research.md
- changelog/+ifc2271.added.md
c8fd931 to
7d19a9d
Compare
Why
This PR adds a parent prefix lookup: when a valid IP address or CIDR prefix is entered, all containing parent prefixes are displayed in a dedicated "Parent Prefixes" section, ordered from most specific to least specific, across all namespaces.
Non-goals: this PR does not modify any existing search behavior. The feature is purely additive, non-IP queries follow the exact same code path as before.
What changed
IPParentPrefixLookupQueryCypher query class that adapts the binary prefix matching algorithm fromIPPrefixReconcileQuery, queries across all namespaces, returns results ordered byprefixlen DESC_try_parse_ip_or_prefix()helper that usesipaddressmodule to detect valid IP/CIDR inputNodeEdgesGraphQL type extended with nullableparent_prefixes: [NodeEdge!]fieldsearch_resolver()extended: after IPv6 normalization, detects IP/CIDR, runs the parent prefix lookup, always runs existing text search regardlessSuggested review order
backend/infrahub/core/query/ipam.pywith the newIPParentPrefixLookupQueryandIPParentPrefixResultbackend/infrahub/graphql/queries/search.pywith_try_parse_ip_or_prefix()helper and resolver changesbackend/tests/unit/graphql/queries/test_search.pyandbackend/tests/component/graphql/queries/test_search.pyHow to review
The Cypher query is the core logic, compare it withIPPrefixReconcileQuery` for the algorithm it adaptsparent_prefixesis only populated when the field is requestedRisky areas:
prefixlen <= prefix_and_length[1]condition (not=) is critical — multiple prefixes can share the same binary address with different prefix lengthsHow to test
Impact & rollout
parent_prefixesfield is nullable and additive. Clients that don't request it see no difference.binary_addressindex.Checklist
changelog/+ifc2271.added.md)dev/specs/infp-431-ipam-closest-prefix/)Summary by CodeRabbit
New Features
Schema
Tests
Documentation