mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-26 13:39:47 +00:00
3f511a5270
The report engine read every report's metrics from the default organization's store, whatever organization the request came from. A tenant request for a resource ID outside its own inventory fell through to that store with the caller's ID, so one organization could read the default organization's history, and even a tenant's own resources were reported from the wrong store. Reporting was closed to org owners until this was fixed. The engine now resolves the metrics store of each request's OrgID through the multi-tenant monitor and refuses a request that names none, so no report path can fall back to the default store. Report handlers reject resources outside the requesting organization's inventory, scheduled runs resolve their scope against their owning organization's inventory and skip resources it no longer holds, and Pulse Assistant's pulse_summarize reads its executor's organization. With every report read scoped, the reporting routes move to ensureOrgAdminSession and reportingRead is offered to org managers again, so providers can build reports inside client workspaces. The report engine wiring lives in pkg/server/server.go, which the completion guard only let telemetry tests prove. server.go now has its own security-privacy path policy that keeps those proofs and also accepts pkg/server/reporting_engine_test.go; the other telemetry files keep their existing policy unchanged.
31 lines
1.1 KiB
Go
31 lines
1.1 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/monitoring"
|
|
"github.com/rcourtman/pulse-go-rewrite/pkg/metrics"
|
|
"github.com/rcourtman/pulse-go-rewrite/pkg/reporting"
|
|
)
|
|
|
|
// newOrgScopedReportEngine builds the standard report engine. Each report
|
|
// reads the metrics store of the organization it was requested in, resolved
|
|
// per request through the current multi-tenant monitor so it follows monitor
|
|
// reloads (which close and recreate the stores). The engine refuses a request
|
|
// that names no organization rather than falling back to the default one.
|
|
func newOrgScopedReportEngine(multiTenantMonitor func() *monitoring.MultiTenantMonitor) *reporting.ReportEngine {
|
|
return reporting.NewReportEngine(reporting.EngineConfig{
|
|
MetricsStoreForOrg: func(orgID string) (*metrics.Store, error) {
|
|
mtMonitor := multiTenantMonitor()
|
|
if mtMonitor == nil {
|
|
return nil, fmt.Errorf("monitoring is not running")
|
|
}
|
|
monitor, err := mtMonitor.GetMonitor(orgID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return monitor.GetMetricsStore(), nil
|
|
},
|
|
})
|
|
}
|