feat(agent): Resources field on ProbeResult + access-log log_sources - #135
Merged
Conversation
…112) The dashboard's capability-driven UI has been inferring resource lists (log sources, services, metric sources) from gear-availability flags. That works for binary "is this gear present?" decisions but breaks down for "what concrete sources does this gear expose?" — the Logs page's hardcoded [haproxy, system] fallback was the worst offender. Phase 2 of issue #112 introduces a structured Resources field the agent populates per-gear, the dashboard consumes by name. Agent changes: - ProbeResult gains `Resources map[string]any`, serialized as the `resources` JSON object on CapabilityEntry. Omitted when empty so older dashboards see the unchanged wire shape. - New gear.ProbeAvailableWithResources(reason, capabilities, resources) constructor for gears that want to publish typed resource lists; gears that don't need this keep using ProbeAvailable. - access-log gear now publishes `log_sources` — a slice of {name, display_name, path} for every readable web-server access log it discovers (haproxy / nginx / apache / caddy). The flat `<src>_log` keys in Capabilities stay for backward compat with pre-Phase-2 dashboards. Tests: - TestProbePopulatesLogSourcesResource on the access-log gear asserts the structured shape, name → display_name mapping, and absence of entries for non-readable paths. - TestCapabilitiesEndpointSurfacesResources on the manager asserts Resources round-trips through the JSON envelope at /api/v1/system/capabilities — decoded via map[string]any so we catch any field-name regression on the wire. Dashboard-side consumer lands in a follow-up PR (sibling to this one). Phase 2 of #112. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a structured Resources payload to agent probe results and the capabilities API, enabling the dashboard to drive UI off concrete resource inventories (starting with access-log publishing log_sources) instead of inferring from flat capability flags.
Changes:
- Extend
gear.ProbeResult/CapabilityEntrywithResources map[string]anyand addProbeAvailableWithResources(...). - Update
access-logprobe to publish structuredresources.log_sourcesentries while keeping legacy<src>_logcapability keys. - Add/extend tests to validate probe population and JSON round-tripping through
/api/v1/system/capabilities.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| gearbox-agent/internal/gears/accesslog/plugin.go | Publishes structured resources.log_sources alongside legacy capability keys. |
| gearbox-agent/internal/gears/accesslog/plugin_test.go | Adds coverage asserting log_sources structure and filtering of unreadable paths. |
| gearbox-agent/internal/framework/gear/manager.go | Extends capabilities API envelope with resources per gear. |
| gearbox-agent/internal/framework/gear/manager_probe_test.go | Adds test ensuring resources round-trips through capabilities JSON response. |
| gearbox-agent/internal/framework/gear/interface.go | Adds Resources to ProbeResult and introduces ProbeAvailableWithResources. |
Four review findings, all addressed: 1. Probe was mutating g.paths despite the ProbeableGear contract that Probe must be side-effect-free. Refactor: extract pathsFromDeps as a shared deps→map helper, add resolveLogPathWith(src, overrides) so Probe operates on a local override map. Initialize is now the single place g.paths gets written. 2. Resources was always populated with a "log_sources" key even when no readable log files were found, so the JSON envelope's `omitempty` tag never fired and the wire format gained a permanent (empty-slice) field. Only attach Resources when log_sources actually has entries. 3. Manager.ProbeResults returned a shallow copy — callers could mutate nested Capabilities/Resources maps and race against manager state under load. Added cloneProbeResult that duplicates Capabilities as a fresh map and JSON-round-trips Resources (so nested slices and sub-maps come back as fresh allocations). JSON round-trip is the same cost the capabilities endpoint encoder pays anyway, and falls back to a shallow Resources copy if marshaling fails. 4. Test comment claimed "decode through json.RawMessage" but the test actually decoded straight into map[string]any. Switch the test to a two-stage decode: first peel the outer envelope into json.RawMessage per gear (catches field-name regressions in the wire format), then decode the resources object into a typed shape and assert on payload contents. Avoids Go's `any` decoding quirks in the wire-format guard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 tasks
sarg3nt
added a commit
that referenced
this pull request
May 17, 2026
The agent-side companion PR adds a structured Resources field to
ProbeResult and has the access-log gear publish a `log_sources` list
(one entry per discovered web-server access log, name + display_name
+ path). This commit teaches the dashboard to read it.
- agent.CapabilityEntry mirrors the new `resources` JSON field as
map[string]any so per-gear shapes don't need a shared Go struct.
- BoxCapabilities.Resource(gearName, key) — small helper to look up
a single resource without manually chaining Entry/.Resources/map
indexing.
- defaultLogSourcesForBox prefers the agent's published log_sources
when present, falling back to the existing capability heuristic
for pre-Phase-2 agents and the legacy [haproxy, system] pair when
capabilities aren't reachable. The path field the agent publishes
is dropped at this layer — the dashboard doesn't expose log paths
to the browser.
The resolution chain is now (in priority):
1. Operator's saved per-box log-source settings (DB)
2. Agent's structured log_sources resource (Phase 2)
3. Capability heuristic (pre-Phase-2 fallback)
4. Legacy [haproxy, system] (agent unreachable / forward-compat)
Tests cover the new path: JSON-decoded shape (production), Go-typed
shape (in-process tests), missing access-log gear, missing resource
key, and five malformed-payload variants (string instead of array,
array of strings, missing fields, empty array). All exercise
logSourcesFromResources directly so the helper's contract is locked
in independently of the surrounding handler.
Phase 2 of #112. Stacked on fix/issue-112-log-sources-capabilities
(PR #116); pairs with feature/issue-112-probe-resources (PR #135)
on the agent.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 2 of issue #112 introduces a structured
Resourcesfield on agent probe results so the dashboard's capability-driven UI can read concrete resource lists (log sources, services, metric sources) directly from the agent rather than inferring them from gear-availability flags.ProbeResultgainsResources map[string]any, serialized as theresourcesJSON object onCapabilityEntry. Omitted when empty so older dashboards see the unchanged wire shape.gear.ProbeAvailableWithResources(reason, capabilities, resources)constructor.log_sources— a slice of{name, display_name, path}for every readable web-server access log it discovers (haproxy / nginx / apache / caddy). The flat<src>_logkeys in Capabilities stay for backward compat.Dashboard-side consumer lives in the sibling PR on
sarg3nt/gearbox.Test plan
go build ./...,go vet ./...,go test -count=1 ./...all cleanTestProbePopulatesLogSourcesResourcecovers the structured shape, name→display_name mapping, and absence of unreadable pathsTestCapabilitiesEndpointSurfacesResourcesround-tripsResourcesthrough the JSON envelope (decoded viamap[string]anyto catch any field-name regression on the wire)/api/v1/system/capabilities, confirm theaccess-loggear'sresources.log_sourcesshows up with the host's actual access-log paths.🤖 Generated with Claude Code