diff --git a/checker/context.go b/checker/context.go new file mode 100644 index 0000000..9dd8918 --- /dev/null +++ b/checker/context.go @@ -0,0 +1,52 @@ +// Copyright 2020-2026 The happyDomain Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package checker + +import "context" + +type enabledRulesCtxKey struct{} + +// WithEnabledRules returns a context carrying the host's per-rule enable map. +// The SDK server attaches it before calling ObservationProvider.Collect so +// providers can skip optional work (network calls, paid API hits, …) for +// rules the host has disabled. A nil map means "run everything". +func WithEnabledRules(ctx context.Context, enabled map[string]bool) context.Context { + if enabled == nil { + return ctx + } + return context.WithValue(ctx, enabledRulesCtxKey{}, enabled) +} + +// EnabledRulesFromContext returns the enabled-rule map attached by +// WithEnabledRules, or nil if none. RuleEnabled is the usual access pattern. +func EnabledRulesFromContext(ctx context.Context) map[string]bool { + m, _ := ctx.Value(enabledRulesCtxKey{}).(map[string]bool) + return m +} + +// RuleEnabled reports whether ruleName is enabled given the host's map. +// Absent rules default to enabled (nil map or rule not in map), matching +// the SDK server's evaluate-side semantics. +func RuleEnabled(ctx context.Context, ruleName string) bool { + m := EnabledRulesFromContext(ctx) + if m == nil { + return true + } + enabled, ok := m[ruleName] + if !ok { + return true + } + return enabled +} diff --git a/checker/server/server.go b/checker/server/server.go index 763a600..5505307 100644 --- a/checker/server/server.go +++ b/checker/server/server.go @@ -325,7 +325,8 @@ func (s *Server) handleCollect(w http.ResponseWriter, r *http.Request) { return } - data, err := s.provider.Collect(r.Context(), req.Options) + ctx := checker.WithEnabledRules(r.Context(), req.EnabledRules) + data, err := s.provider.Collect(ctx, req.Options) if err != nil { writeJSON(w, http.StatusInternalServerError, checker.ExternalCollectResponse{ Error: err.Error(), diff --git a/checker/types.go b/checker/types.go index 7256766..ea25247 100644 --- a/checker/types.go +++ b/checker/types.go @@ -421,10 +421,17 @@ type OptionsValidator interface { } // ExternalCollectRequest is sent to POST /collect on a remote checker endpoint. +// +// EnabledRules lets the host inform the provider which rules will be evaluated +// downstream, so the provider can skip optional work (network calls, paid API +// hits, …) for data that would not surface in any state. nil means "run +// everything"; an explicit map with a rule name set to false means that rule +// is off. Providers access the value via EnabledRulesFromContext(ctx). type ExternalCollectRequest struct { - Key ObservationKey `json:"key"` - Target CheckTarget `json:"target"` - Options CheckerOptions `json:"options"` + Key ObservationKey `json:"key"` + Target CheckTarget `json:"target"` + Options CheckerOptions `json:"options"` + EnabledRules map[string]bool `json:"enabledRules,omitempty"` } // ExternalCollectResponse is returned by POST /collect on a remote checker endpoint.