Skip to content

NE-2451: Implement probe_dns_local diagnostic tool#176

Merged
openshift-merge-bot[bot] merged 3 commits intoopenshift:mainfrom
bentito:feat/NE-2451-probe-dns-local
Mar 19, 2026
Merged

NE-2451: Implement probe_dns_local diagnostic tool#176
openshift-merge-bot[bot] merged 3 commits intoopenshift:mainfrom
bentito:feat/NE-2451-probe-dns-local

Conversation

@bentito
Copy link

@bentito bentito commented Mar 10, 2026

This PR implements an active tool that generates network traffic to verify DNS connectivity and resolution.

This PR implements DNS probing from the server: probe_dns_local (NE-2451)

  • Description: Run a DNS query using local libraries on the MCP server host.
  • It uses the standard Go DNS library (github.com/miekg/dns) and defaults to A record requests if no type is explicitly supplied.
  • It allows for shimming the Exchange function through an interface for offline unit testing without external dependencies.
  • Fixes NE-2451: https://issues.redhat.com/browse/NE-2451

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 10, 2026
@bentito bentito force-pushed the feat/NE-2451-probe-dns-local branch from c6889eb to 7391991 Compare March 10, 2026 18:34
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 10, 2026
@bentito bentito force-pushed the feat/NE-2451-probe-dns-local branch from 7391991 to 804593c Compare March 10, 2026 18:42
@bentito bentito changed the title Implement probe_dns_local diagnostic tool netedge: Implement probe_dns_local diagnostic tool Mar 10, 2026
@bentito bentito changed the title netedge: Implement probe_dns_local diagnostic tool NE-2451: Implement probe_dns_local diagnostic tool Mar 10, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Mar 10, 2026
@openshift-ci-robot
Copy link

openshift-ci-robot commented Mar 10, 2026

@bentito: This pull request references NE-2451 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set.

Details

In response to this:

This PR implements an active tool that generates network traffic to verify DNS connectivity and resolution.

This PR implements DNS probing from the server: probe_dns_local (NE-2451)

  • Description: Run a DNS query using local libraries on the MCP server host.
  • It uses the standard Go DNS library (github.com/miekg/dns) and defaults to A record requests if no type is explicitly supplied.
  • It allows for shimming the Exchange function through an interface for offline unit testing without external dependencies.
  • Fixes NE-2451: https://issues.redhat.com/browse/NE-2451

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@matzew
Copy link
Member

matzew commented Mar 11, 2026

Thanks for the split of actual change and vendor noise 🙃

bentito added a commit to bentito/openshift-mcp-server that referenced this pull request Mar 12, 2026
- Set ClusterAware to false for probe_dns_local

- Improve robust IPv6-aware address port handling

- Use api.NewToolCallResultStructured for structured tool output
@bentito bentito force-pushed the feat/NE-2451-probe-dns-local branch from f7c0746 to 134fc9c Compare March 13, 2026 20:47
bentito added a commit to bentito/openshift-mcp-server that referenced this pull request Mar 13, 2026
- Set ClusterAware to false for probe_dns_local

- Improve robust IPv6-aware address port handling

- Use api.NewToolCallResultStructured for structured tool output
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Review skipped — only excluded labels are configured. (1)
  • do-not-merge/work-in-progress

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7733223a-68f7-414d-ae26-549a9925d9a1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Walkthrough

This PR introduces a new DNS probing tool ("probe_dns_local") to the netedge toolset. It adds the miekg/dns library as a dependency, implements a handler with test-friendly abstractions for DNS queries, registers the tool in the toolset, and includes comprehensive test coverage for success and error paths.

Changes

Cohort / File(s) Summary
Dependency Management
go.mod
Added direct dependency on miekg/dns v1.1.57 and indirect dependencies on golang.org/x/mod and golang.org/x/tools.
DNS Probe Implementation
pkg/toolsets/netedge/probe_dns_local.go
Introduced new DNS probing tool with dnsExchange interface for test mocking, defaultDNSClient wrapper around miekg/dns, and handler that validates inputs, normalizes query names, issues DNS queries, and returns structured DNSResult output containing answers, return codes, and latency metrics.
DNS Probe Tests
pkg/toolsets/netedge/probe_dns_local_test.go
Added comprehensive test suite with mockDNSClient fixture and multiple test cases covering success scenarios, validation errors, invalid DNS types, network failures, type defaults, port augmentation, and structured error returns.
Toolset Integration
pkg/toolsets/netedge/toolset.go
Registered the new probe_dns_local tool in the GetTools method via slices.Concat to include it in available netedge tools.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
pkg/toolsets/netedge/probe_dns_local.go (1)

68-69: Consider configuring explicit timeout on the DNS client.

The dns.Client is initialized without an explicit timeout. While the library has internal defaults, setting an explicit timeout (e.g., 5-10 seconds) would improve predictability and prevent potential hangs when probing unresponsive servers.

♻️ Suggested improvement
-var activeDNSClient dnsExchange = &defaultDNSClient{client: new(dns.Client)}
+var activeDNSClient dnsExchange = &defaultDNSClient{client: &dns.Client{
+	Timeout: 10 * time.Second,
+}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/toolsets/netedge/probe_dns_local.go` around lines 68 - 69, The DNS client
is created without an explicit timeout which can hang probes; update the
initialization of activeDNSClient (and the defaultDNSClient.client field of type
dns.Client) to set a sensible Timeout (e.g., 5–10 seconds) on the dns.Client
instance and ensure the time package is imported; specifically replace
new(dns.Client) with an explicitly constructed &dns.Client{Timeout: 5 *
time.Second} (or configured constant) so defaultDNSClient.client uses that timed
client.
pkg/toolsets/netedge/probe_dns_local_test.go (1)

166-170: Consider resetting the mock client for better test isolation.

The mock client is only set when tt.mockClient != nil, which means tests without a mock (like "missing name parameter") inherit the client from a previous test. While this works because those tests fail before Exchange is called, the pattern is fragile if test order changes or logic is modified.

♻️ Suggested improvement
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
+			// Reset to original client for isolation
+			activeDNSClient = origClient
 			if tt.mockClient != nil {
 				activeDNSClient = tt.mockClient
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/toolsets/netedge/probe_dns_local_test.go` around lines 166 - 170, Tests
set activeDNSClient only when tt.mockClient != nil, causing state leakage
between subtests; reset or restore the global before/after each run to guarantee
isolation. Inside the t.Run closure for the table-driven tests, capture the
original activeDNSClient, then if tt.mockClient != nil assign it, and use defer
to restore the original (or alternatively set activeDNSClient = nil at the start
of each subtest) so tests like the "missing name parameter" cannot inherit a
previous mock.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@pkg/toolsets/netedge/probe_dns_local_test.go`:
- Around line 166-170: Tests set activeDNSClient only when tt.mockClient != nil,
causing state leakage between subtests; reset or restore the global before/after
each run to guarantee isolation. Inside the t.Run closure for the table-driven
tests, capture the original activeDNSClient, then if tt.mockClient != nil assign
it, and use defer to restore the original (or alternatively set activeDNSClient
= nil at the start of each subtest) so tests like the "missing name parameter"
cannot inherit a previous mock.

In `@pkg/toolsets/netedge/probe_dns_local.go`:
- Around line 68-69: The DNS client is created without an explicit timeout which
can hang probes; update the initialization of activeDNSClient (and the
defaultDNSClient.client field of type dns.Client) to set a sensible Timeout
(e.g., 5–10 seconds) on the dns.Client instance and ensure the time package is
imported; specifically replace new(dns.Client) with an explicitly constructed
&dns.Client{Timeout: 5 * time.Second} (or configured constant) so
defaultDNSClient.client uses that timed client.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6003540a-7996-424f-af8e-0787404e193c

📥 Commits

Reviewing files that changed from the base of the PR and between cfa14b8 and 134fc9c.

⛔ Files ignored due to path filters (296)
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/bahlo/generic-list-go/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/bahlo/generic-list-go/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/bahlo/generic-list-go/list.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/.gitignore is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/.travis.yml is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/Dockerfile is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/Makefile is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/bytes.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/bytes_safe.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/bytes_unsafe.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/escape.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/fuzz.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/oss-fuzz-build.sh is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/buger/jsonparser/parser.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/.gitignore is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/.golangci.yml is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/COPYING is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/id.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/reflect.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/reflect_comments.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/schema.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/invopop/jsonschema/utils.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/client.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/elicitation.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/http.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/inprocess.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/interface.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/oauth.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/roots.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/sampling.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/sse.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/stdio.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/constants.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/error.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/interface.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/oauth.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/oauth_utils.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/sse.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/stdio.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/client/transport/utils.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/consts.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/errors.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/prompts.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/resources.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/tasks.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/tools.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/typed_tools.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/mcp/utils.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/completion.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/constants.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/ctx.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/elicitation.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/errors.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/hooks.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/http_transport_options.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/inprocess_session.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/request_handler.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/roots.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/sampling.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/server.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/session.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/sse.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/stdio.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/streamable_http.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/server/task_hooks.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/mark3labs/mcp-go/util/logger.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/.codecov.yml is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/.gitignore is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/AUTHORS is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/CODEOWNERS is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/CONTRIBUTORS is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/COPYRIGHT is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/Makefile.fuzz is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/Makefile.release is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/acceptfunc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/client.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/clientconfig.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dane.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/defaults.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dns.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec_keygen.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec_keyscan.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec_privkey.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/duplicate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/edns.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/format.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/fuzz.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/generate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/hash.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/labels.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/listen_no_reuseport.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/listen_reuseport.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/msg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/msg_helpers.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/msg_truncate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/nsecx.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/privaterr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/reverse.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/sanitize.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/scan.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/scan_rr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/serve_mux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/server.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/sig0.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/smimea.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/svcb.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/tlsa.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/tools.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/tsig.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/udp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/udp_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/update.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/version.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/xfr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/zduplicate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/zmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/ztypes.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/.gitignore is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/.golangci.yml is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/CHANGELOG.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/Makefile is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/json.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/orderedmap.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/wk8/go-ordered-map/v2/yaml.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/mod/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/mod/PATENTS is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/mod/semver/semver.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/asm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/constants.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/instructions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/setter.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/vm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/vm_instructions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/iana/const.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_linux_32bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_solaris_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/complete_dontwait.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/complete_nodontwait.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/empty.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/error_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/error_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_32bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/mmsghdr_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/norace.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/race.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_msg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_nommsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_nomsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/socket.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_const_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_386.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mips.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mips64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mipsle.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_ppc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_ppc64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_s390x.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_netbsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_posix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_zos_s390x.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_aix_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_darwin_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_dragonfly_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_loong64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mips.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mips64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mipsle.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_solaris_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/batch.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_pktinfo.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_zos.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/dgramopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/endpoint.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/genericopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/header.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/helper.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/iana.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/icmp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/icmp_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/icmp_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/packet.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/payload.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/payload_cmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/payload_nocmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sockopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sockopt_posix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sockopt_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_aix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreq.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreq_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreqn.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreqn_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_bpf.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_bpf_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_darwin.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_dragonfly.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_freebsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_solaris.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_ssmreq.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_ssmreq_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_zos.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_aix_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_darwin.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_dragonfly.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_amd64.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (4)
  • go.mod
  • pkg/toolsets/netedge/probe_dns_local.go
  • pkg/toolsets/netedge/probe_dns_local_test.go
  • pkg/toolsets/netedge/toolset.go

@matzew
Copy link
Member

matzew commented Mar 17, 2026

@bentito can you do a proper rebase of this, against latest downstream/main (e.g. git fetch downstream && git rebase -i downstream/main)

also, afterwards, you must run go mod vendor. When I do that on the branch, it still deletes a lot of dependencies.

@bentito
Copy link
Author

bentito commented Mar 17, 2026

@bentito can you do a proper rebase of this, against latest downstream/main (e.g. git fetch downstream && git rebase -i downstream/main)

also, afterwards, you must run go mod vendor. When I do that on the branch, it still deletes a lot of dependencies.

Sorry about that.

I think I had a go version problem on my end. Most recent push and commit after rebase and tidy should be clean. Lemme know if still problems. Thanks.

bentito added a commit to bentito/openshift-mcp-server that referenced this pull request Mar 17, 2026
- Set ClusterAware to false for probe_dns_local

- Improve robust IPv6-aware address port handling

- Use api.NewToolCallResultStructured for structured tool output
@bentito bentito force-pushed the feat/NE-2451-probe-dns-local branch from fd0b5c3 to 666482e Compare March 17, 2026 18:33
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
local-dev-docs/MCP Server Enhancement for NIDS Troubleshooting.md (1)

200-203: Minor: Empty bullet point on line 202.

There's a stray empty bullet point that should be removed.

 * Istio down, Gateway not programmed.  
-* 

 Metrics include accuracy, completeness, and adherence to RBAC boundaries.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/MCP` Server Enhancement for NIDS Troubleshooting.md around
lines 200 - 203, Remove the stray empty bullet in the markdown list that appears
after the "IngressController degraded condition propagation." and "Istio down,
Gateway not programmed." entries; edit the list in the document so there is no
blank list item (delete the lone "*" or "-" line), ensuring the bullets are
contiguous and formatting remains valid.
local-dev-docs/NE-2279-Offline-Access-Notes.md (3)

74-84: Enhance session management and user experience.

The tool design would benefit from richer session lifecycle management:

Session metadata gaps:

  • Returns only the path string - consider returning a session object with:
    • Unique session ID
    • Original source (for reference)
    • Timestamp of creation
    • Available features (has Prometheus data? has specific resources?)
    • Status (hydrating, ready, failed)

Session lifecycle:

  • No mention of session expiration or TTL
  • What happens if the same source is hydrated multiple times? (deduplication?)
  • Missing companion tools: list_offline_sessions, close_offline_session, cleanup_expired_sessions
  • No mechanism to resume a previously hydrated session

Agent guidance:

  • Step 3 instructs agent to use the path as cluster argument, but how does the agent know when to invoke this tool vs using live clusters?
  • Consider adding a session status check tool to verify readiness before querying
💡 Recommended session management enhancements
### 5. Offline Session Management Tools

- **analyze_offline_session**:
    - Arguments: `source` (string), optional `ttl` (duration, default 1h)
    - Returns: JSON object with:
        - `session_id`: unique identifier
        - `cluster_path`: prepared path for cluster argument
        - `source`: original source reference
        - `features`: { "kubernetes": true, "prometheus": true/false }
        - `expires_at`: timestamp
        - `status`: "ready" | "hydrating" | "failed"
    - Side effects: Registers session for cleanup scheduling

- **list_offline_sessions**:
    - Returns: Array of active sessions with metadata

- **close_offline_session**:
    - Arguments: `session_id` or `cluster_path`
    - Behavior: Terminates containers, removes temp files, unregisters session

- **get_offline_session_status**:
    - Arguments: `session_id` or `cluster_path`
    - Returns: Current status, resource usage, error details if failed
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md` around lines 74 - 84, The
analyze_offline_session tool currently returns only a path (via
OfflineManager.HydrateContext(source)); update it to return a session object
containing session_id, cluster_path (the hydrated path), source, created_at
timestamp, features (e.g., has_prometheus), and status (hydrating|ready|failed),
and add optional ttl support; also implement companion endpoints/tools
list_offline_sessions, close_offline_session, and get_offline_session_status to
register/deregister sessions and report readiness/expiry, ensure duplicate
hydrations deduplicate by source (or return existing session_id), and schedule
cleanup for expired sessions so agents can check status before using
cluster_path.

105-121: Expand verification plan to cover error paths and security.

The current plan is a good start but should include:

Additional unit tests:

  • Error handling: corrupted archives, network failures, invalid URLs, missing required files
  • Security: path traversal attempts, malicious archive patterns, oversized downloads
  • Concurrency: multiple simultaneous HydrateContext calls for different sources
  • Cleanup: verify temp directory removal, container termination, orphan detection

Additional integration tests:

  • Full must-gather workflow (not just Prometheus): verify omc commands work end-to-end
  • Port conflict handling: start two sessions simultaneously, verify second gets different port
  • Session lifecycle: create, query, close, verify cleanup
  • Resource limits: verify container memory/CPU limits are enforced
  • Network isolation: verify containers can't access external network

Security-focused tests:

  • Attempt to download from HTTP (should fail)
  • Attempt to extract archive with ../ path traversal
  • Validate certificate validation for HTTPS downloads
  • Test with ZIP bomb patterns (should hit size limits)
🧪 Extended verification plan
### Automated Tests

**3. Error Path Tests**:
- Network failures during download (timeout, connection refused)
- Corrupted archive files (truncated, invalid format)
- Missing required components (no prometheus.tar)
- Port conflicts (9091 already in use)
- Disk space exhaustion scenarios
- Container runtime unavailable

**4. Security Tests**:
- Path traversal in archive extraction
- HTTP URL rejection (enforce HTTPS)
- Certificate validation on HTTPS
- Archive size bomb protection
- Download size limit enforcement

**5. Concurrency Tests**:
- Multiple simultaneous sessions from different sources
- Same source hydrated multiple times concurrently
- Stress test: 10+ concurrent sessions

### Manual Verification

**3. Negative Testing**:
- Invalid must-gather structure
- Prow URL that 404s
- Must-gather from incompatible OpenShift version
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md` around lines 105 - 121,
Update the Verification Plan section to explicitly add tests for error paths,
security, concurrency and cleanup: under Automated Tests add unit tests for
HydrateContext error handling (corrupted archives, invalid URLs, network
failures), security checks (path traversal, malicious archive patterns,
oversized downloads, HTTP vs HTTPS/certificate validation), concurrency tests
for multiple simultaneous HydrateContext calls, and cleanup verification for
temp directory and container termination; extend integration tests to cover full
must-gather workflows (omc wrapper end-to-end), port conflict handling (ensure
analyze_offline_session assigns different ports when 9091 is in use), session
lifecycle (create/query/close and verify cleanup), resource limits and network
isolation, and negative tests for missing prometheus.tar and download failures;
ensure query_prometheus, analyze_offline_session, and omc-related scenarios are
explicitly referenced in each relevant test bullet to guide implementation.

1-121: Consider adding observability and user documentation sections.

To complete the design, consider adding:

Observability:

  • Logging strategy for offline operations (session lifecycle events, extraction progress, container management)
  • Metrics to track: active sessions, disk usage, container resource consumption, hydration duration
  • Tracing context propagation for offline vs live operations
  • Error categorization for troubleshooting (network, extraction, validation, runtime)

User-facing documentation:

  • How-to guide for agents/engineers on using offline mode
  • Example workflows (debugging Prow failure, analyzing customer must-gather)
  • Troubleshooting guide for common issues (port conflicts, missing dependencies)
  • Limitations documentation (what doesn't work in offline mode)

Rollout considerations:

  • Feature flag for gradual rollout?
  • Backward compatibility with existing tools?
  • Migration plan if changes affect existing must-gather workflows?
📚 Suggested additional sections
## 7. Observability & Debugging

**Structured Logging**:
- Session lifecycle: `offline.session.created`, `offline.session.hydrating`, `offline.session.ready`, `offline.session.closed`
- Resource events: `offline.extract.start`, `offline.container.start`, `offline.query.executed`
- Error events: Include session_id, source, error category, resolution hints

**Metrics** (Prometheus format):
- `nids_offline_sessions_active{status}`: Gauge of active sessions by status
- `nids_offline_hydration_duration_seconds`: Histogram of hydration times
- `nids_offline_disk_usage_bytes`: Gauge of temp directory size
- `nids_offline_container_cpu_usage`: Container resource consumption

**Tracing**:
- Tag all offline operations with `offline=true` span attribute
- Propagate session_id in trace context

## 8. User Documentation Updates

- Update tool catalog to document offline mode for each tool
- Add examples using `file://` cluster paths
- Document required dependencies (omc, docker/podman)
- Add troubleshooting section to runbook
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md` around lines 1 - 121, Add
observability and user documentation sections: instrument
OfflineManager.HydrateContext and CleanupContext,
OfflinePrometheusManager.EnsureRunning, and the omc/prometheus offline wrappers
(pkg/context/offline_manager.go, pkg/clients/kubernetes/offline.go,
pkg/clients/prometheus/offline.go) with structured logs (session lifecycle
events like offline.session.hydrating/ready/closed and extraction/container
events) and emit Prometheus metrics (nids_offline_sessions_active,
nids_offline_hydration_duration_seconds, nids_offline_disk_usage_bytes) plus
trace/span tagging (offline=true and session_id) for all async flows; also add a
user-facing docs page and examples for analyze_offline_session usage, dependency
requirements (omc, docker/podman), troubleshooting (port conflicts, missing
files), limitations, and rollout notes (feature flag, backward compatibility) so
tools using GetDerivedKubernetes/GetDerivedPrometheus can be debugged and
adopted safely.
🤖 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/verify_inspect_route.sh`:
- Around line 50-57: The script calls a non-registered tool "inspect_route" via
the CLI (see the CLI invocation using CLI_BIN and SERVER_CMD with --tool
inspect_route and redirects to mcp_output.json); update the codebase so
"inspect_route" is actually registered in the netedge toolset (or change
SERVER_CMD to use the toolset that contains inspect_route) by adding the tool to
the netedge toolset registration list (where tools QueryPrometheus, CoreDNS,
Endpoints, ProbeDNSLocal are registered) and/or moving the tool to the correct
toolset, and change the error handling in the script so the CLI failure branch
exits non-zero (e.g., call exit 1) instead of continuing after printing "MCP CLI
failed!" so failures are not silently masked.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md`:
- Around line 59-73: GetDerivedKubernetes and GetDerivedPrometheus routing is
underspecified and lacks validation, error handling and lifecycle coordination;
update GetDerivedKubernetes(ctx, clusterID) to explicitly detect prefixes
(file:// with absolute-path validation, offline:// for session IDs), reject
relative paths or any path containing "..", validate path exists/access, return
explicit errors for malformed paths or missing omc binary rather than falling
back to live, and return OfflineKubernetesClient(resolvedPath) on success;
update GetDerivedPrometheus(ctx, clusterID) to use the same validation rules,
check container runtime availability, call
OfflinePrometheusManager.EnsureRunning(resolvedPath) and propagate a clear error
if EnsureRunning fails (don’t silently fall back), and record a session
reference so closing derived clients coordinates cleanup (ensure
cleanup/shutdown logic ties OfflineKubernetesClient closure and any Prometheus
container session reference together to avoid leaked containers or
double-shutdowns).
- Around line 18-28: HydrateContext currently lacks security and resource
controls; update HydrateContext(source string) to enforce HTTPS with certificate
validation for URL downloads, impose a configurable maximum download size and
pre-flight disk-space check (e.g., require 2x archive size), validate
checksums/signatures if available, verify archive type and integrity before
extraction, use a unique session ID (per call) to create isolated temp dirs,
implement secure extraction that rejects path-traversal and enforces extraction
size limits to defend against zip bombs, and validate must-gather/Prometheus
structure after extraction; also change CleanupContext to CleanupContext(path
string, force bool) error and implement deterministic cleanup with retries for
locked files, termination of any session-bound containers, handling of partial
extractions/orphaned temp dirs, and robust logging for failures so manual
remediation is possible.
- Around line 41-58: Update pkg/clients/prometheus/offline.go to make container
management robust: validate prometheus.tar in extractTarball, detect available
runtime in ensureRuntimeAvailable (docker/podman) and fail fast if missing,
replace hardcoded 9091 with an ephemeral session-scoped port chosen by
getAvailablePort (e.g., retry within a 9091–9191 range) and return that port in
PrometheusClient config, enforce resource limits and a fixed image tag (e.g.,
quay.io/prometheus/prometheus:v2.45.0) when starting the container in
startContainer, tag containers with the session ID and make startContainer
idempotent by checking for an existing container for the session, register
cleanup hooks and implement stopContainer to remove containers on session end or
crash (and handle orphan detection on startup), and improve error handling
around tar extraction and readiness polling (/-/ready) so failures surface
clearly.

---

Nitpick comments:
In `@local-dev-docs/MCP` Server Enhancement for NIDS Troubleshooting.md:
- Around line 200-203: Remove the stray empty bullet in the markdown list that
appears after the "IngressController degraded condition propagation." and "Istio
down, Gateway not programmed." entries; edit the list in the document so there
is no blank list item (delete the lone "*" or "-" line), ensuring the bullets
are contiguous and formatting remains valid.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md`:
- Around line 74-84: The analyze_offline_session tool currently returns only a
path (via OfflineManager.HydrateContext(source)); update it to return a session
object containing session_id, cluster_path (the hydrated path), source,
created_at timestamp, features (e.g., has_prometheus), and status
(hydrating|ready|failed), and add optional ttl support; also implement companion
endpoints/tools list_offline_sessions, close_offline_session, and
get_offline_session_status to register/deregister sessions and report
readiness/expiry, ensure duplicate hydrations deduplicate by source (or return
existing session_id), and schedule cleanup for expired sessions so agents can
check status before using cluster_path.
- Around line 105-121: Update the Verification Plan section to explicitly add
tests for error paths, security, concurrency and cleanup: under Automated Tests
add unit tests for HydrateContext error handling (corrupted archives, invalid
URLs, network failures), security checks (path traversal, malicious archive
patterns, oversized downloads, HTTP vs HTTPS/certificate validation),
concurrency tests for multiple simultaneous HydrateContext calls, and cleanup
verification for temp directory and container termination; extend integration
tests to cover full must-gather workflows (omc wrapper end-to-end), port
conflict handling (ensure analyze_offline_session assigns different ports when
9091 is in use), session lifecycle (create/query/close and verify cleanup),
resource limits and network isolation, and negative tests for missing
prometheus.tar and download failures; ensure query_prometheus,
analyze_offline_session, and omc-related scenarios are explicitly referenced in
each relevant test bullet to guide implementation.
- Around line 1-121: Add observability and user documentation sections:
instrument OfflineManager.HydrateContext and CleanupContext,
OfflinePrometheusManager.EnsureRunning, and the omc/prometheus offline wrappers
(pkg/context/offline_manager.go, pkg/clients/kubernetes/offline.go,
pkg/clients/prometheus/offline.go) with structured logs (session lifecycle
events like offline.session.hydrating/ready/closed and extraction/container
events) and emit Prometheus metrics (nids_offline_sessions_active,
nids_offline_hydration_duration_seconds, nids_offline_disk_usage_bytes) plus
trace/span tagging (offline=true and session_id) for all async flows; also add a
user-facing docs page and examples for analyze_offline_session usage, dependency
requirements (omc, docker/podman), troubleshooting (port conflicts, missing
files), limitations, and rollout notes (feature flag, backward compatibility) so
tools using GetDerivedKubernetes/GetDerivedPrometheus can be debugged and
adopted safely.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 845af032-8c97-4fd6-b725-08ac8bce4b3b

📥 Commits

Reviewing files that changed from the base of the PR and between fd0b5c3 and 666482e.

⛔ Files ignored due to path filters (291)
  • local-dev-docs/PromeCleus-screenshot.png is excluded by !**/*.png
  • vendor/github.com/miekg/dns/.codecov.yml is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/.gitignore is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/AUTHORS is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/CODEOWNERS is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/CONTRIBUTORS is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/COPYRIGHT is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/Makefile.fuzz is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/Makefile.release is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/README.md is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/acceptfunc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/client.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/clientconfig.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dane.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/defaults.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dns.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec_keygen.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec_keyscan.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/dnssec_privkey.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/duplicate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/edns.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/format.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/fuzz.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/generate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/hash.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/labels.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/listen_no_reuseport.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/listen_reuseport.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/msg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/msg_helpers.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/msg_truncate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/nsecx.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/privaterr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/reverse.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/sanitize.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/scan.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/scan_rr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/serve_mux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/server.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/sig0.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/smimea.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/svcb.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/tlsa.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/tools.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/tsig.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/udp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/udp_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/update.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/version.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/xfr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/zduplicate.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/zmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/miekg/dns/ztypes.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/mod/LICENSE is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/mod/PATENTS is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/mod/semver/semver.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/asm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/constants.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/instructions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/setter.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/vm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/bpf/vm_instructions.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/iana/const.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_linux_32bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_solaris_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/complete_dontwait.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/complete_nodontwait.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/empty.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/error_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/error_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_32bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/iovec_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/mmsghdr_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/msghdr_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/norace.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/race.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_msg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_nommsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/rawconn_nomsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/socket.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_const_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_386.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mips.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mips64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_mipsle.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_ppc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_ppc64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_linux_s390x.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_netbsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_posix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/sys_zos_s390x.s is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_aix_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_darwin_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_dragonfly_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_freebsd_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_loong64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mips.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mips64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_mipsle.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_linux_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_solaris_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/internal/socket/zsys_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/batch.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_pktinfo.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/control_zos.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/dgramopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/endpoint.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/genericopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/header.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/helper.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/iana.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/icmp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/icmp_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/icmp_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/packet.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/payload.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/payload_cmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/payload_nocmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sockopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sockopt_posix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sockopt_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_aix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreq.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreq_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreqn.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_asmreqn_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_bpf.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_bpf_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_darwin.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_dragonfly.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_freebsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_solaris.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_ssmreq.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_ssmreq_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/sys_zos.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_aix_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_darwin.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_dragonfly.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_freebsd_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_loong64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_mips.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_mips64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_mips64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_mipsle.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_ppc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_ppc64le.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_linux_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_netbsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_openbsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_solaris.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv4/zsys_zos_s390x.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/batch.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/control.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/control_rfc2292_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/control_rfc3542_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/control_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/control_unix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/control_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/dgramopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/endpoint.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/genericopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/header.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/helper.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/iana.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp_solaris.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/icmp_zos.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/payload.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/payload_cmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/payload_nocmsg.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sockopt.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sockopt_posix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sockopt_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_aix.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_asmreq.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_asmreq_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_bpf.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_bpf_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_bsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_darwin.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_freebsd.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_linux.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_solaris.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_ssmreq.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_ssmreq_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_stub.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_windows.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/sys_zos.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_aix_ppc64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_darwin.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_dragonfly.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_freebsd_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_freebsd_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_freebsd_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_freebsd_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_freebsd_riscv64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_linux_386.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_linux_amd64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_linux_arm.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_linux_arm64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_linux_loong64.go is excluded by !vendor/**, !**/vendor/**
  • vendor/golang.org/x/net/ipv6/zsys_linux_mips.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (9)
  • bin/mcp-cli-verify
  • bin/openshift-mcp-server
  • dev/verify_inspect_route.sh
  • go.mod
  • local-dev-docs/MCP Server Enhancement for NIDS Troubleshooting.md
  • local-dev-docs/NE-2279-Offline-Access-Notes.md
  • pkg/toolsets/netedge/probe_dns_local.go
  • pkg/toolsets/netedge/probe_dns_local_test.go
  • pkg/toolsets/netedge/toolset.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/toolsets/netedge/toolset.go
  • go.mod
  • pkg/toolsets/netedge/probe_dns_local_test.go

Comment on lines +18 to +28
#### [NEW] `pkg/context/offline_manager.go`
- **Responsibility**: Manage the lifecycle of offline sessions.
- **Functions**:
- `HydrateContext(source string) (string, error)`:
- **Identification**: Determine if `source` is a local directory, a tarball, or a URL.
- **Retrieval**: If URL, download artifacts (prioritizing `must-gather.tar.gz` and `prometheus.tar`).
- **Extraction**: Extract archives to a clean, isolated temporary directory.
- **Validation**: Check for required components (OMC-compatible data, Prometheus metrics).
- Returns the absolute path to the prepared directory.
- `CleanupContext(path string)`: specific cleanup logic.

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add security controls for URL downloads and archive extraction.

The HydrateContext design lacks critical security and resource management controls:

Security risks:

  • URL downloads should enforce HTTPS and validate certificates to prevent MITM attacks
  • No checksum or signature validation for downloaded artifacts
  • Archive extraction needs protection against zip bombs, path traversal attacks, and arbitrary file writes outside the target directory
  • No content validation before extraction (e.g., verifying it's actually a must-gather archive)

Resource management risks:

  • No pre-flight disk space check before extraction
  • No size limits on downloads or extracted content
  • Concurrent HydrateContext calls could race on temp directory creation or exhaust resources
  • CleanupContext logic is too vague - needs specific handling for partial extractions, locked files, and orphaned containers
🛡️ Recommended security controls to add to the design

Update the design to include:

- `HydrateContext(source string) (string, error)`:
    - **Security Validation**:
        - Enforce HTTPS for URL sources with certificate validation
        - Verify checksums/signatures if provided (e.g., `.sha256` files)
        - Validate archive integrity before extraction
        - Use secure extraction with path traversal protection (reject `../` paths)
    - **Resource Management**:
        - Check available disk space (require at least 2x archive size)
        - Enforce maximum download size limit (e.g., 10GB)
        - Use unique session IDs to prevent concurrent extraction conflicts
        - Implement extraction size limits to prevent zip bombs
    - **Validation**: 
        - Verify must-gather structure (required directories/files)
        - Validate OMC-compatible metadata
        - Check Prometheus data format
    - Returns the absolute path to the prepared directory.
- `CleanupContext(path string, force bool) error`:
    - Terminate any running Prometheus containers for this session
    - Remove temp directory with retry logic for locked files
    - Log cleanup failures for manual intervention
    - Support force flag to override locks
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md` around lines 18 - 28,
HydrateContext currently lacks security and resource controls; update
HydrateContext(source string) to enforce HTTPS with certificate validation for
URL downloads, impose a configurable maximum download size and pre-flight
disk-space check (e.g., require 2x archive size), validate checksums/signatures
if available, verify archive type and integrity before extraction, use a unique
session ID (per call) to create isolated temp dirs, implement secure extraction
that rejects path-traversal and enforces extraction size limits to defend
against zip bombs, and validate must-gather/Prometheus structure after
extraction; also change CleanupContext to CleanupContext(path string, force
bool) error and implement deterministic cleanup with retries for locked files,
termination of any session-bound containers, handling of partial
extractions/orphaned temp dirs, and robust logging for failures so manual
remediation is possible.

Comment on lines +41 to +58
### 3. Offline Prometheus Client ("Promecieus" Integration)

This is the core new feature: spinning up a real Prometheus instance to serve metrics from the offline archive.

#### [NEW] `pkg/clients/prometheus/offline.go`
- **Responsibility**: Provide a `PrometheusClient` that queries a local container.
- **Components**:
- **Container Manager**:
- Check for `prometheus.tar` in the offline context path.
- Extract the tarball if not already extracted (Prometheus needs the data directory).
- Start a local container (e.g., `quay.io/prometheus/prometheus:latest`) using Docker or Podman.
- Mount the extracted data directory to `/prometheus`.
- Map a free local port (e.g., `9091`) to `9090`.
- Wait for readiness (poll `/-/ready`).
- **Client Factory**:
- Return a standard Prometheus API client configured with `Address: http://localhost:9091`.
- This allows existing `query_prometheus` tool logic to work *unchanged*.

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify port management and add container resource controls.

The Prometheus container design has several operational gaps:

Port management inconsistency (Line 51):

  • States "map a free local port" but then hardcodes 9091 in the example and later references (http://localhost:9091)
  • No strategy for handling port conflicts when 9091 is already in use
  • Multiple concurrent offline sessions would collide

Missing resource controls:

  • No CPU/memory limits specified for containers (could exhaust host resources)
  • No container cleanup strategy when sessions end
  • No handling for orphaned containers if process crashes
  • No mechanism to prevent running multiple containers for the same session

Operational concerns:

  • Using :latest tag is not reproducible; should specify a version
  • No detection of container runtime (docker vs podman) availability
  • Missing error handling when prometheus.tar is absent or corrupted
  • No mention of container network isolation or security policies
📝 Recommended updates for container management
- **Container Manager**:
    - Validate `prometheus.tar` exists and is readable
    - Detect available container runtime (docker/podman) with version check
    - Assign session-unique port using ephemeral port allocation (e.g., 9091-9191 range)
    - Set resource limits: `--memory=512m --cpus=1.0`
    - Use specific image version: `quay.io/prometheus/prometheus:v2.45.0`
    - Tag container with session ID for lifecycle tracking
    - Implement idempotent start: check if container for session already running
    - Register cleanup hook to terminate container on session end
    - Handle port conflicts: retry with next available port or fail gracefully
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md` around lines 41 - 58, Update
pkg/clients/prometheus/offline.go to make container management robust: validate
prometheus.tar in extractTarball, detect available runtime in
ensureRuntimeAvailable (docker/podman) and fail fast if missing, replace
hardcoded 9091 with an ephemeral session-scoped port chosen by getAvailablePort
(e.g., retry within a 9091–9191 range) and return that port in PrometheusClient
config, enforce resource limits and a fixed image tag (e.g.,
quay.io/prometheus/prometheus:v2.45.0) when starting the container in
startContainer, tag containers with the session ID and make startContainer
idempotent by checking for an existing container for the session, register
cleanup hooks and implement stopContainer to remove containers on session end or
crash (and handle orphan detection on startup), and improve error handling
around tar extraction and readiness polling (/-/ready) so failures surface
clearly.

Comment on lines +59 to +73
### 4. Tool Integration Updates

Update the factory/resolver logic to switch between Live and Offline clients based on the input.

#### [MODIFY] `pkg/toolsets/netedge/utils.go` (or wherever `GetDerived*` lives)
- `GetDerivedKubernetes(ctx, clusterID)`:
- If `clusterID` starts with `file://` or matches a known offline pattern:
- Return `OfflineKubernetesClient(path)`.
- Else: Return Live Client.
- `GetDerivedPrometheus(ctx, clusterID)`:
- If `clusterID` starts with `file://`:
- Trigger `OfflinePrometheusManager.EnsureRunning(path)` (idempotent start of container).
- Return client pointing to that container.
- Else: Return Live Client (Thanos/Prometheus).

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify offline pattern detection and error handling strategy.

The routing logic needs more precise specification:

Pattern matching ambiguity (Line 65):

  • "matches a known offline pattern" is too vague - what patterns qualify beyond file://?
  • Consider explicit examples: file:///path, offline://session-id, local absolute paths?
  • Should relative paths be supported or rejected?

Error handling gaps:

  • No strategy when offline infrastructure is unavailable (omc missing, no container runtime)
  • Missing validation for malformed file:// paths (e.g., file:///../../../etc/passwd)
  • No graceful degradation if OfflinePrometheusManager.EnsureRunning fails
  • Should failed offline requests fall back to live, or fail explicitly?

Lifecycle management:

  • When derived clients are closed, how does cleanup occur?
  • Does closing a Kubernetes client trigger Prometheus container shutdown?
  • What happens if the same offline path is requested multiple times concurrently?
📋 Recommended clarifications
- `GetDerivedKubernetes(ctx, clusterID)`:
    - **Pattern Detection**: 
        - Match `file://` prefix with absolute path validation
        - Match `offline://` prefix for session IDs
        - Reject relative paths and paths with `..` traversal
        - Validate path exists and is accessible before routing
    - **Error Handling**:
        - Return explicit error if omc binary not found in PATH
        - Return error for malformed paths (don't fall back to live)
        - Log routing decision for observability
    - **Success**: Return `OfflineKubernetesClient(resolvedPath)`

- `GetDerivedPrometheus(ctx, clusterID)`:
    - **Validation**: Same pattern matching as Kubernetes
    - **Startup**: 
        - Call `OfflinePrometheusManager.EnsureRunning(path)` (idempotent)
        - Return error with actionable message if container start fails
        - Include container runtime check before attempting start
    - **Lifecycle**: Store session reference for cleanup coordination
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@local-dev-docs/NE-2279-Offline-Access-Notes.md` around lines 59 - 73,
GetDerivedKubernetes and GetDerivedPrometheus routing is underspecified and
lacks validation, error handling and lifecycle coordination; update
GetDerivedKubernetes(ctx, clusterID) to explicitly detect prefixes (file:// with
absolute-path validation, offline:// for session IDs), reject relative paths or
any path containing "..", validate path exists/access, return explicit errors
for malformed paths or missing omc binary rather than falling back to live, and
return OfflineKubernetesClient(resolvedPath) on success; update
GetDerivedPrometheus(ctx, clusterID) to use the same validation rules, check
container runtime availability, call
OfflinePrometheusManager.EnsureRunning(resolvedPath) and propagate a clear error
if EnsureRunning fails (don’t silently fall back), and record a session
reference so closing derived clients coordinates cleanup (ensure
cleanup/shutdown logic ties OfflineKubernetesClient closure and any Prometheus
container session reference together to avoid leaked containers or
double-shutdowns).

bentito added a commit to bentito/openshift-mcp-server that referenced this pull request Mar 17, 2026
@bentito bentito force-pushed the feat/NE-2451-probe-dns-local branch from a724f62 to 935fd61 Compare March 17, 2026 18:48
@matzew
Copy link
Member

matzew commented Mar 18, 2026

/override "Konflux kflux-prd-rh02 / openshift-mcp-server-on-pull-request"

@openshift-ci
Copy link

openshift-ci bot commented Mar 18, 2026

@matzew: Overrode contexts on behalf of matzew: Konflux kflux-prd-rh02 / openshift-mcp-server-on-pull-request

Details

In response to this:

/override "Konflux kflux-prd-rh02 / openshift-mcp-server-on-pull-request"

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

bentito added a commit to bentito/openshift-mcp-server that referenced this pull request Mar 18, 2026
Addresses PR openshift#176 reviewer feedback from matzew:

- Eliminate package-level mutable var activeDNSClient in favor of a
  closure-based approach. initProbeDNSLocal() delegates to
  initProbeDNSLocalWith(client dnsExchange) which builds the handler via
  makeProbeDNSLocalHandler(client). Tests inject a mock client directly
  through initProbeDNSLocalWith without any global variable swapping.

- Refactor probe_dns_local_test.go to use the existing NetEdgeTestSuite
  (testify/suite), consistent with coredns_test.go and endpoints_test.go.
  All test cases are now methods on NetEdgeTestSuite using s.Run()
  subtests and s.Assert()/s.Require() assertions.
@openshift-ci openshift-ci bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 18, 2026
@matzew
Copy link
Member

matzew commented Mar 18, 2026

I guess needs a rebase 🙈

sorry, @bentito

bentito added 3 commits March 18, 2026 12:24
Addresses PR openshift#176 reviewer feedback from matzew:

- Eliminate package-level mutable var activeDNSClient in favor of a
  closure-based approach. initProbeDNSLocal() delegates to
  initProbeDNSLocalWith(client dnsExchange) which builds the handler via
  makeProbeDNSLocalHandler(client). Tests inject a mock client directly
  through initProbeDNSLocalWith without any global variable swapping.

- Refactor probe_dns_local_test.go to use the existing NetEdgeTestSuite
  (testify/suite), consistent with coredns_test.go and endpoints_test.go.
  All test cases are now methods on NetEdgeTestSuite using s.Run()
  subtests and s.Assert()/s.Require() assertions.
@bentito bentito force-pushed the feat/NE-2451-probe-dns-local branch from 99eb0cc to 8269a8b Compare March 18, 2026 17:19
@openshift-ci openshift-ci bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 18, 2026
@matzew
Copy link
Member

matzew commented Mar 19, 2026

/override "Konflux kflux-prd-rh02 / openshift-mcp-server-on-pull-request"

@openshift-ci
Copy link

openshift-ci bot commented Mar 19, 2026

@matzew: Overrode contexts on behalf of matzew: Konflux kflux-prd-rh02 / openshift-mcp-server-on-pull-request

Details

In response to this:

/override "Konflux kflux-prd-rh02 / openshift-mcp-server-on-pull-request"

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Copy link
Member

@matzew matzew left a comment

Choose a reason for hiding this comment

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

/lgtm
/approve

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Mar 19, 2026
@openshift-ci
Copy link

openshift-ci bot commented Mar 19, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bentito, matzew

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Mar 19, 2026
@openshift-ci
Copy link

openshift-ci bot commented Mar 19, 2026

@bentito: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot bot merged commit 1103650 into openshift:main Mar 19, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants