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 <sschrock@google.com>

* add test

Signed-off-by: Spencer Schrock <sschrock@google.com>

---------

Signed-off-by: Spencer Schrock <sschrock@google.com>
This commit is contained in:
Spencer Schrock 2024-04-25 11:23:54 -07:00 committed by GitHub
parent 0ea86598f6
commit 71aed951f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 44 additions and 8 deletions

View File

@ -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

View File

@ -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

View File

@ -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")
}

View File

@ -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