Skip to content

feat(sdk): add graph traversal support for Infrahub 1.10+#1090

Open
minitriga wants to merge 3 commits into
developfrom
infp-531-graph-traversal
Open

feat(sdk): add graph traversal support for Infrahub 1.10+#1090
minitriga wants to merge 3 commits into
developfrom
infp-531-graph-traversal

Conversation

@minitriga

@minitriga minitriga commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds graph-traversal support to the SDK (requires Infrahub 1.10+), letting users discover how nodes are connected without knowing the relationship path in advance. Purely additive — no existing signatures change.

What's new

Three client methods, each with a sync equivalent:

  • traverse_paths(source, destination, ...) — find the shortest path(s) between two nodes.
  • path_exists(source, destination, ...) — boolean convenience wrapper for checks (requests a single path).
  • reachable_nodes(source, target_kinds, ...) — find every node of given kinds reachable from a source, with the path to each.

Ergonomics:

  • source/destination accept a node UUID string or an InfrahubNode instance.
  • Kind filters accept kind-name strings or generated protocol classes (mix freely).
  • Each result PathNode is a lightweight identity exposing .fetch() to resolve the full node (store-backed).
  • Calling against a pre-1.10 server raises a clear VersionNotSupportedError instead of an opaque GraphQL failure.

Implementation notes

  • New infrahub_sdk/graph_traversal/ package: typed pydantic result models (models.py) and GraphQL query strings + input builders (query.py). Pure logic is isolated so it's unit-tested without HTTP.
  • New VersionNotSupportedError exception.
  • Added to docs generation (tasks.py), a how-to guide, generated SDK reference, and a changelog fragment.

Testing

  • pytest tests/unit/sdk/test_graph_traversal.py — 23 passed (pure-logic builders/parsing + client methods mocked at the transport boundary, async + sync).
  • ruff check clean; lint-docs 0 errors.

🤖 Generated with Claude Code


Summary by cubic

Adds graph traversal to the Python SDK for Infrahub 1.10+, enabling shortest-path and dependency discovery across any relationships. Supports INFP-531 (Phase 1) by exposing traversal APIs the UI and GraphQL layer can use.

  • New Features

    • SDK: InfrahubClient.traverse_paths(), reachable_nodes(), and path_exists() (with sync equivalents) to find shortest paths, discover reachable nodes by kind, and check connectivity.
    • Ergonomics: accept node IDs or InfrahubNode; kind filters accept strings or protocol classes; results include PathNode.fetch() to resolve full nodes from the client store.
    • Compatibility: pre-1.10 servers raise VersionNotSupportedError with a clear message.
  • Bug Fixes

    • Include GraphQL operationName in requests for better tracing.
    • Tests: register traversal annotations in the async/sync signature parity map to fix parity check failures.

Written for commit 0415f11. Summary will update on new commits.

Review in cubic

Add traverse_paths(), path_exists(), and reachable_nodes() client methods
(with sync equivalents) for discovering how nodes are connected without
knowing the relationship path in advance.

- traverse_paths: shortest path(s) between a source and destination node
- path_exists: boolean convenience wrapper for checks
- reachable_nodes: nodes of given kinds reachable from a source

Source/destination accept node ids or InfrahubNode instances; kind filters
accept kind strings or protocol classes; each result PathNode exposes
.fetch() to resolve the full node (store-backed). Calling against a pre-1.10
server raises a clear VersionNotSupportedError.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@minitriga minitriga requested a review from a team as a code owner June 18, 2026 09:53
@github-actions github-actions Bot added the type/documentation Improvements or additions to documentation label Jun 18, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 18, 2026

Copy link
Copy Markdown

Deploying infrahub-sdk-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0415f11
Status: ✅  Deploy successful!
Preview URL: https://2d0b25d1.infrahub-sdk-python.pages.dev
Branch Preview URL: https://infp-531-graph-traversal.infrahub-sdk-python.pages.dev

View logs

@minitriga minitriga changed the base branch from stable to develop June 18, 2026 09:55

@cubic-dev-ai cubic-dev-ai 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.

3 issues found across 38 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="infrahub_sdk/schema/__init__.py">

<violation number="1">
P3: `_get_schema_name` accepts `CoreNodeBase` but then unconditionally reads `schema.save`, which can crash with `AttributeError`. Guard for `save` presence (or narrower subclass) so invalid inputs consistently raise `ValueError`.</violation>
</file>

<file name="infrahub_sdk/node/related_node.py">

<violation number="1">
P2: `hasattr(data, "_schema")` is too broad for node detection. It can accept non-node objects and defer failure to later peer access paths.</violation>
</file>

<file name="docs/docs/python-sdk/sdk_ref/infrahub_sdk/client.mdx">

<violation number="1" location="docs/docs/python-sdk/sdk_ref/infrahub_sdk/client.mdx:125">
P3: Public docs omit the new keyword-only traversal arguments, so the reference page misstates the API surface for graph traversal.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

@@ -119,6 +119,64 @@ count(self, kind: str | type[SchemaType], at: Timestamp | None = None, branch: s

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Public docs omit the new keyword-only traversal arguments, so the reference page misstates the API surface for graph traversal.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At docs/docs/python-sdk/sdk_ref/infrahub_sdk/client.mdx, line 125:

<comment>Public docs omit the new keyword-only traversal arguments, so the reference page misstates the API surface for graph traversal.</comment>

<file context>
@@ -119,6 +119,64 @@ count(self, kind: str | type[SchemaType], at: Timestamp | None = None, branch: s
+#### `traverse_paths`
+
+```python
+traverse_paths(self, source: str | InfrahubNode, destination: str | InfrahubNode) -> PathTraversalResult
+```
+
</file context>

minitriga and others added 2 commits June 18, 2026 11:20
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The async/sync signature parity test matches annotation strings against a
known-equivalence map. Add the new traversal parameter annotations
(str | InfrahubNode, list[str | type[SchemaType]] and its optional variant)
so traverse_paths/path_exists/reachable_nodes pass the parity check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.50649% with 10 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
infrahub_sdk/client.py 86.44% 8 Missing ⚠️
infrahub_sdk/graph_traversal/models.py 96.77% 1 Missing and 1 partial ⚠️
@@             Coverage Diff             @@
##           develop    #1090      +/-   ##
===========================================
- Coverage    82.32%   82.05%   -0.27%     
===========================================
  Files          135      138       +3     
  Lines        11992    11859     -133     
  Branches      1793     1783      -10     
===========================================
- Hits          9872     9731     -141     
- Misses        1571     1581      +10     
+ Partials       549      547       -2     
Flag Coverage Δ
integration-tests 41.12% <0.00%> (-1.44%) ⬇️
python-3.10 55.20% <47.40%> (-0.81%) ⬇️
python-3.11 55.19% <47.40%> (-0.84%) ⬇️
python-3.12 55.20% <47.40%> (-0.83%) ⬇️
python-3.13 55.19% <47.40%> (-0.84%) ⬇️
python-3.14 55.18% <47.40%> (-0.83%) ⬇️
python-filler-3.12 22.70% <46.10%> (+0.32%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
infrahub_sdk/exceptions.py 89.54% <100.00%> (+0.42%) ⬆️
infrahub_sdk/graph_traversal/__init__.py 100.00% <100.00%> (ø)
infrahub_sdk/graph_traversal/query.py 100.00% <100.00%> (ø)
infrahub_sdk/graph_traversal/models.py 96.77% <96.77%> (ø)
infrahub_sdk/client.py 75.43% <86.44%> (+0.76%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ajtmccarty ajtmccarty 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.

looks good. few small comments


### Constraining the traversal

All limits and filters are optional; when omitted, the server applies its own defaults. Unknown kinds (for example IP namespaces) are excluded by default and reported back in `result.excluded_kinds`.

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.

I don't know exactly what "Unknown kinds" means here. Any IP namespaces are excluded by default b/c they act as hubs and are generally not valuable in this kind of path tracing (although they can be re-included using included_kinds). other internal namespaces are also excluded by default: Builtin, Internal, Core, etc.


### Detecting truncated results

The server caps the number of paths/results. Compare `count` to your requested limit to know whether more may exist:

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.

the count is actually always the number of paths returned for either of the path traversal queries. it won't be a reliable method for determining if the max_targets was reached. that would require checking the UUIDs of the start objects for each path

``source`` accepts either a node UUID string or an ``InfrahubNode`` instance.
``target_kinds`` accepts kind-name strings and/or generated protocol classes.

Requires Infrahub 1.10 or later. See https://docs.infrahub.app for details.

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.

is this docs link actually helpful?

Comment thread infrahub_sdk/client.py
if isinstance(node, str):
return node
if node.id is None:
raise Error("Cannot use a node without an id as a traversal source or destination.")

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.

the function name is pretty generic but the error message is specific to path traversal. I think this method should raise some sort of NodeNotSaved error and then the path traversal caller can catch it and raise an error that mentions path traversal if necessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants