From 71aed951f99eba4e84737895c1251e295f5b71e5 Mon Sep 17 00:00:00 2001 From: Spencer Schrock Date: Thu, 25 Apr 2024 11:23:54 -0700 Subject: [PATCH] :sparkles: allow probes to collect their own data from repo clients (#4052) * introduce independent probe implementations rather than rely on checks collecting raw data, independent probes collect their own raw data using the underlying repo client present in the check request. Signed-off-by: Spencer Schrock * add test Signed-off-by: Spencer Schrock --------- Signed-off-by: Spencer Schrock --- internal/probes/probes.go | 27 ++++++++++++++++++++------- internal/probes/probes_test.go | 12 ++++++++++++ pkg/scorecard.go | 7 ++++++- probes/entries.go | 6 ++++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/internal/probes/probes.go b/internal/probes/probes.go index 9e8858897bd..a5282ba219a 100644 --- a/internal/probes/probes.go +++ b/internal/probes/probes.go @@ -48,13 +48,16 @@ const ( ) type Probe struct { - Name string - Implementation ProbeImpl - RequiredRawData []CheckName + Name string + Implementation ProbeImpl + IndependentImplementation IndependentProbeImpl + RequiredRawData []CheckName } type ProbeImpl func(*checker.RawResults) ([]finding.Finding, string, error) +type IndependentProbeImpl func(*checker.CheckRequest) ([]finding.Finding, string, error) + // registered is the mapping of all registered probes. var registered = map[string]Probe{} @@ -69,15 +72,25 @@ func MustRegister(name string, impl ProbeImpl, requiredRawData []CheckName) { } } +func MustRegisterIndependent(name string, impl IndependentProbeImpl) { + err := register(Probe{ + Name: name, + IndependentImplementation: impl, + }) + if err != nil { + panic(err) + } +} + func register(p Probe) error { if p.Name == "" { return errors.WithMessage(errors.ErrScorecardInternal, "name cannot be empty") } - if p.Implementation == nil { - return errors.WithMessage(errors.ErrScorecardInternal, "implementation cannot be nil") + if p.Implementation == nil && p.IndependentImplementation == nil { + return errors.WithMessage(errors.ErrScorecardInternal, "at least one implementation must be non-nil") } - if len(p.RequiredRawData) == 0 { - return errors.WithMessage(errors.ErrScorecardInternal, "probes need some raw data") + if p.Implementation != nil && len(p.RequiredRawData) == 0 { + return errors.WithMessage(errors.ErrScorecardInternal, "non-independent probes need some raw data") } registered[p.Name] = p return nil diff --git a/internal/probes/probes_test.go b/internal/probes/probes_test.go index 6da3fe0131d..800c721955c 100644 --- a/internal/probes/probes_test.go +++ b/internal/probes/probes_test.go @@ -27,6 +27,10 @@ func emptyImpl(r *checker.RawResults) ([]finding.Finding, string, error) { return nil, "", nil } +func emptyIndependentImpl(c *checker.CheckRequest) ([]finding.Finding, string, error) { + return nil, "", nil +} + var ( p1 = Probe{ Name: "someProbe1", @@ -84,6 +88,14 @@ func Test_register(t *testing.T) { }, wantErr: false, }, + { + name: "independent probe registration", + probe: Probe{ + Name: "bar", + IndependentImplementation: emptyIndependentImpl, + }, + wantErr: false, + }, } for _, tt := range tests { tt := tt diff --git a/pkg/scorecard.go b/pkg/scorecard.go index 99320a2ae0d..03640349fff 100644 --- a/pkg/scorecard.go +++ b/pkg/scorecard.go @@ -207,7 +207,12 @@ func runEnabledProbes(request *checker.CheckRequest, return fmt.Errorf("getting probe %q: %w", probeName, err) } // Run probe - findings, _, err := probe.Implementation(&ret.RawResults) + var findings []finding.Finding + if probe.IndependentImplementation != nil { + findings, _, err = probe.IndependentImplementation(request) + } else { + findings, _, err = probe.Implementation(&ret.RawResults) + } if err != nil { return sce.WithMessage(sce.ErrScorecardInternal, "ending run") } diff --git a/probes/entries.go b/probes/entries.go index 93d7c5d2bf6..ea6bdf43fd4 100644 --- a/probes/entries.go +++ b/probes/entries.go @@ -66,6 +66,9 @@ import ( // ProbeImpl is the implementation of a probe. type ProbeImpl func(*checker.RawResults) ([]finding.Finding, string, error) +// IndependentProbeImpl is the implementation of an independent probe. +type IndependentProbeImpl func(*checker.CheckRequest) ([]finding.Finding, string, error) + var ( // All represents all the probes. All []ProbeImpl @@ -160,6 +163,9 @@ var ( codeReviewOneReviewers.Run, hasBinaryArtifacts.Run, } + + // Probes which don't use pre-computed raw data but rather collect it themselves. + Independent = []IndependentProbeImpl{} ) //nolint:gochecknoinits