Skip to content

feat(endpoints): add inodes introspection endpoint#1273

Open
Molter73 wants to merge 5 commits into
mainfrom
mauro/feat/inodes-introspection
Open

feat(endpoints): add inodes introspection endpoint#1273
Molter73 wants to merge 5 commits into
mainfrom
mauro/feat/inodes-introspection

Conversation

@Molter73

@Molter73 Molter73 commented Jul 23, 2026

Copy link
Copy Markdown
Member

Description

Adds an "/inodes" endpoint that returns the contents of the userspace inode map for inspection. This will be useful in tests that need to look into the internal state after operations that don't emit events or during development to validate what is currently being tracked.

The new endpoint is disabled by default and can be enabled with the new endpoint.introspection configuration value, that should gate any future introspection endpoints we decide to add in the future. This configuration value is not hotreloadable, it can only be set at start up, this is meant to make it harder for the endpoint to come online on production environments.

Fixes #1079

Checklist

  • Patch has a change log entry OR does not need one.
  • Investigated and inspected CI test results
  • Updated documentation accordingly

Automated testing

  • Added unit tests
  • Added integration tests
  • Added regression tests

If any of these don't apply, please comment below.

Testing Performed

The responses are formatted with jq for better visibility, the endpoint returns minified JSON.

Introspection endpoint enabled:

{
  "39:228583982": "/etc/sensitive-files/seq",
  "39:200442630": "/etc/sensitive-files/my-dir/something",
  "39:227290637": "/etc/sensitive-files/private/super-private/something",
  "39:196873539": "/etc/sensitive-files/test",
  "39:194573419": "/etc/sensitive-files/my-dir/nested/something",
  "39:194396170": "/etc/sensitive-files/my-dir",
  "39:228288758": "/etc/sensitive-files/mount",
  "39:217415897": "/etc/sensitive-files/other",
  "39:228583961": "/etc/sensitive-files/sequence",
  "39:202489561": "/etc/sensitive-files/something",
  "39:194573388": "/etc/sensitive-files/my-dir/nested",
  "39:227290085": "/etc/sensitive-files/private",
  "39:227290591": "/etc/sensitive-files/private/super-private",
  "39:227290457": "/etc/sensitive-files/private/something",
  "39:126382982": "/etc/sensitive-files"
}

Introspection endpoint disabled, metrics endpoint enabled:

curl: (22) The requested URL returned error: 503

No endpoint enabled:

curl: (7) Failed to connect to localhost port 9000 after 0 ms: Could not connect to server

Summary by CodeRabbit

  • New Features
    • Added optional endpoint introspection via the --introspection CLI option or FACT_ENDPOINT_INTROSPECTION environment variable (default: disabled; --no-introspection available).
    • Added a new GET /inodes endpoint that returns the current inode-to-path mapping as JSON when introspection is enabled.
  • Configuration
    • YAML endpoint configuration now supports endpoint.introspection (boolean), including type validation and environment-variable override precedence.
    • Endpoint hot reloading now preserves the existing introspection setting (changes to other endpoint fields won’t affect it).

Adds an "/inodes" endpoint that returns the contents of the userspace
inode map for inspection. This will be useful in tests that need to look
into the internal state after operations that don't emit events or
during development to validate what is currently being tracked.

The new endpoint is disabled by default and can be enabled with the new
`endpoint.introspection` configuration value, that should gate any
future introspection endpoints we decide to add in the future. This
configuration value is not hotreloadable, it can only be set at start
up, this is meant to make it harder for the endpoint to come online on
production environments.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Enterprise

Run ID: 3978a215-f959-4d69-aadd-89a72701222a

📥 Commits

Reviewing files that changed from the base of the PR and between 17b96c9 and 61ce645.

📒 Files selected for processing (1)
  • fact/src/config/reloader.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • fact/src/config/reloader.rs

📝 Walkthrough

Walkthrough

Changes

The PR adds configurable endpoint introspection, exposes a /inodes endpoint, connects endpoint requests to HostScanner through Tokio channels, and serializes the current inode-to-path mapping as JSON. Configuration parsing, environment overrides, defaults, updates, and reload behavior are covered by tests.

Inode introspection

Layer / File(s) Summary
Introspection configuration and reload behavior
fact/src/config/mod.rs, fact/src/config/reloader.rs, fact/src/config/tests.rs
Endpoint introspection is configurable through YAML, CLI flags, and environment variables, defaults to disabled, propagates through updates, and does not trigger endpoint subscriber reloads.
Introspection channel wiring
fact/src/lib.rs
A Tokio channel is created and connected from runtime startup through input setup to HostScanner, with its sender passed to the endpoint server.
Host-scanner inode serialization
fact/src/host_scanner.rs
HostScanner serializes inode keys as "{dev}:{inode}" JSON object keys and replies to introspection requests through oneshot channels.
Inodes endpoint and response handling
fact/src/endpoints.rs, CHANGELOG.md
The server routes GET /inodes, checks the introspection flag, requests the host-scanner mapping, and returns success or failure responses; the changelog records the endpoint addition.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Server
  participant HostScanner
  Client->>Server: GET /inodes
  Server->>HostScanner: send oneshot response sender
  HostScanner->>HostScanner: serialize inode map
  HostScanner-->>Server: JSON result
  Server-->>Client: HTTP response
Loading

Possibly related PRs

  • stackrox/fact#1221: Both changes modify the host scanner’s inode-map storage and update path.

Suggested reviewers: stringy

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding the /inodes introspection endpoint.
Description check ✅ Passed The PR description matches the template and includes the required sections, checklist, testing notes, and unit-test confirmation.
Linked Issues check ✅ Passed Issue [#1079] is addressed by adding the /inodes introspection endpoint with the suggested channel-based flow and startup-only gating.
Out of Scope Changes check ✅ Passed All changes are centered on introspection plumbing, tests, and changelog updates, with no obvious unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mauro/feat/inodes-introspection

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

@codecov-commenter

codecov-commenter commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.50331% with 77 lines in your changes missing coverage. Please review.
✅ Project coverage is 38.35%. Comparing base (922750c) to head (61ce645).

Files with missing lines Patch % Lines
fact/src/host_scanner.rs 0.00% 27 Missing ⚠️
fact/src/endpoints.rs 0.00% 26 Missing ⚠️
fact/src/config/reloader.rs 94.69% 12 Missing ⚠️
fact/src/lib.rs 0.00% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1273      +/-   ##
==========================================
+ Coverage   32.73%   38.35%   +5.61%     
==========================================
  Files          22       22              
  Lines        3174     3455     +281     
  Branches     3174     3455     +281     
==========================================
+ Hits         1039     1325     +286     
+ Misses       2131     2126       -5     
  Partials        4        4              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

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

@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: 2

🤖 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 `@fact/src/config/tests.rs`:
- Around line 300-325: Update the configuration tests to assert
EndpointConfig::introspection() directly rather than relying only on FactConfig
equality. In fact/src/config/tests.rs:300-325, compare the parsed effective
value in the parsing loop; at 1512-1565, assert the updated value and add an
introspection: false update input; at 2409-2421, assert the environment-derived
value; and at 2644-2657, assert the environment-overrides-YAML value.

In `@fact/src/endpoints.rs`:
- Around line 158-172: Update the host-scanner request flow around
host_scanner_intro to use try_send, returning HTTP 503 when the channel is
saturated or unavailable instead of awaiting indefinitely. Wrap rx.await in a
bounded timeout and return an appropriate 503 response when the scanner does not
respond before it expires, while preserving the existing success and
scanner-error responses.
🪄 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.yml

Review profile: CHILL

Plan: Enterprise

Run ID: 82d61e0c-05b2-4af2-a25b-96743e92d407

📥 Commits

Reviewing files that changed from the base of the PR and between 922750c and 46754dc.

📒 Files selected for processing (5)
  • fact/src/config/mod.rs
  • fact/src/config/tests.rs
  • fact/src/endpoints.rs
  • fact/src/host_scanner.rs
  • fact/src/lib.rs

Comment thread fact/src/config/tests.rs
Comment thread fact/src/endpoints.rs
@Molter73
Molter73 force-pushed the mauro/feat/inodes-introspection branch from 262673f to a142db9 Compare July 23, 2026 15:20

@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 `@fact/src/config/reloader.rs`:
- Around line 189-192: Update the endpoint reload branch around
Reloader::endpoint_should_reload so it applies only reloadable endpoint fields
and preserves the existing old.introspection value, rather than replacing old
with new.endpoint.clone(). Add or extend regression coverage for an
introspection-only change followed by a reloadable endpoint change, ensuring
introspection remains unchanged until restart.
🪄 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.yml

Review profile: CHILL

Plan: Enterprise

Run ID: 0163c873-533a-44c7-a1be-af9dac47f696

📥 Commits

Reviewing files that changed from the base of the PR and between 46754dc and a142db9.

📒 Files selected for processing (2)
  • fact/src/config/mod.rs
  • fact/src/config/reloader.rs

Comment thread fact/src/config/reloader.rs
@Molter73
Molter73 marked this pull request as ready for review July 23, 2026 16:29
@Molter73
Molter73 requested a review from a team as a code owner July 23, 2026 16:29

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

♻️ Duplicate comments (1)
fact/src/config/reloader.rs (1)

177-180: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Clone new.endpoint before using struct-update syntax.

Line 179 moves EndpointConfig out of &FactConfig; this does not compile because EndpointConfig is Clone, not Copy.

Proposed fix
                 *old = EndpointConfig {
                     introspection: old.introspection,
-                    ..new.endpoint
+                    ..new.endpoint.clone()
                 };
#!/usr/bin/env bash
set -euo pipefail

rg -n -C 3 'derive\(.*(Clone|Copy)|struct EndpointConfig|\.{2}new\.endpoint' \
  fact/src/config/mod.rs fact/src/config/reloader.rs
🤖 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 `@fact/src/config/reloader.rs` around lines 177 - 180, Update the
EndpointConfig struct update in the reloader logic to clone new.endpoint before
spreading it, since new is borrowed and EndpointConfig is not Copy. Preserve the
existing introspection override from old while ensuring the assignment does not
move out of the borrowed FactConfig.
🧹 Nitpick comments (1)
fact/src/config/reloader.rs (1)

499-505: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the watch notification state too. Add a per-case expected notification flag and check endpoint.has_changed().unwrap() after send_updates(); otherwise an unconditional send could still leave this test green.

🤖 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 `@fact/src/config/reloader.rs` around lines 499 - 505, Extend the test cases
iterated by the reloader test to include an expected notification flag, then
update the loop around Reloader::from and send_updates to assert
endpoint.has_changed().unwrap() against that per-case expectation. Preserve the
existing endpoint value assertion while ensuring each case verifies both state
and notification behavior.
🤖 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.

Duplicate comments:
In `@fact/src/config/reloader.rs`:
- Around line 177-180: Update the EndpointConfig struct update in the reloader
logic to clone new.endpoint before spreading it, since new is borrowed and
EndpointConfig is not Copy. Preserve the existing introspection override from
old while ensuring the assignment does not move out of the borrowed FactConfig.

---

Nitpick comments:
In `@fact/src/config/reloader.rs`:
- Around line 499-505: Extend the test cases iterated by the reloader test to
include an expected notification flag, then update the loop around
Reloader::from and send_updates to assert endpoint.has_changed().unwrap()
against that per-case expectation. Preserve the existing endpoint value
assertion while ensuring each case verifies both state and notification
behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Enterprise

Run ID: ed55f6e3-23b4-46a8-b9aa-fdc48ab9a94f

📥 Commits

Reviewing files that changed from the base of the PR and between a142db9 and 7e715d5.

📒 Files selected for processing (1)
  • fact/src/config/reloader.rs

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.

Add introspection endpoints

2 participants