mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-19 10:33:29 +00:00
Allow legacy report-only agent tokens to fetch their own config (#1254)
Back-port v5 fix 04a828264 to v6. canReadConfig now accepts
ScopeAgentReport (legacy host-agent:report) in addition to the config/
manage/settings scopes; resolveConfigAgent already restricts a
report-only token to the host it is bound to, so it can only read its
own config. Without this, a v5 agent upgraded to a v6 server while still
holding a report-only token gets HTTP 403 on config fetch and breaks.
Retargets TestHandleConfigMissingConfigScope to monitoring:read and adds
TestHandleConfigAllowsBoundAgentReportScope as a #1254 regression guard.
This commit is contained in:
parent
545a6f22a0
commit
d9da9b18f2
2 changed files with 45 additions and 2 deletions
|
|
@ -350,6 +350,11 @@ func (h *UnifiedAgentHandlers) canReadConfig(record *config.APITokenRecord) bool
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return record.HasScope(config.ScopeAgentConfigRead) ||
|
return record.HasScope(config.ScopeAgentConfigRead) ||
|
||||||
|
// Older host/docker-agent tokens may only carry agent:report (legacy
|
||||||
|
// host-agent:report). Allow them to keep fetching their own config via
|
||||||
|
// token binding — resolveConfigAgent below restricts a report-only token
|
||||||
|
// to the host it is bound to.
|
||||||
|
record.HasScope(config.ScopeAgentReport) ||
|
||||||
record.HasScope(config.ScopeAgentManage) ||
|
record.HasScope(config.ScopeAgentManage) ||
|
||||||
record.HasScope(config.ScopeSettingsWrite)
|
record.HasScope(config.ScopeSettingsWrite)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -340,8 +340,10 @@ func TestHandleConfigMissingConfigScope(t *testing.T) {
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodGet, "/api/agents/agent/"+hostID+"/config", nil)
|
req := httptest.NewRequest(http.MethodGet, "/api/agents/agent/"+hostID+"/config", nil)
|
||||||
attachAPITokenRecord(req, &config.APITokenRecord{
|
attachAPITokenRecord(req, &config.APITokenRecord{
|
||||||
ID: "token-other",
|
ID: "token-other",
|
||||||
Scopes: []string{config.ScopeAgentReport},
|
// monitoring:read genuinely lacks config-read access (agent:report is
|
||||||
|
// now accepted via token binding, so it would not exercise this path).
|
||||||
|
Scopes: []string{config.ScopeMonitoringRead},
|
||||||
})
|
})
|
||||||
|
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
@ -352,6 +354,42 @@ func TestHandleConfigMissingConfigScope(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestHandleConfigAllowsBoundAgentReportScope verifies that a legacy
|
||||||
|
// report-only token (agent:report / host-agent:report) can still fetch its own
|
||||||
|
// config via token binding — it resolves to the host bound to the token, not
|
||||||
|
// the requested agentID. Regression guard for #1254.
|
||||||
|
func TestHandleConfigAllowsBoundAgentReportScope(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
handler := newUnifiedAgentHandlerForTests(t, models.Host{
|
||||||
|
ID: "host-1",
|
||||||
|
TokenID: "token-expected",
|
||||||
|
})
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/agents/agent/other-host/config", nil)
|
||||||
|
attachAPITokenRecord(req, &config.APITokenRecord{
|
||||||
|
ID: "token-expected",
|
||||||
|
Scopes: []string{config.ScopeAgentReport},
|
||||||
|
})
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
handler.HandleConfig(rec, req)
|
||||||
|
|
||||||
|
if rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected status %d, got %d", http.StatusOK, rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp struct {
|
||||||
|
AgentID string `json:"agentId"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
|
||||||
|
t.Fatalf("failed to decode response: %v", err)
|
||||||
|
}
|
||||||
|
if resp.AgentID != "host-1" {
|
||||||
|
t.Fatalf("expected agent id %q, got %q", "host-1", resp.AgentID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandleConfigUsesTokenBinding(t *testing.T) {
|
func TestHandleConfigUsesTokenBinding(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue