Skip to content

Commit 1a8f2fa

Browse files
Merge pull request #432 from michaelkedar:guided-remediation/resolve
PiperOrigin-RevId: 726775722
2 parents 9da6c8e + bd0c8ee commit 1a8f2fa

File tree

21 files changed

+1520
-28
lines changed

21 files changed

+1520
-28
lines changed

clients/clienttest/mock_resolution_client.go

+2-9
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121

2222
"deps.dev/util/resolve"
2323
"deps.dev/util/resolve/schema"
24-
"github.com/google/osv-scalibr/clients/resolution"
2524
"gopkg.in/yaml.v3"
2625
)
2726

@@ -31,14 +30,8 @@ type ResolutionUniverse struct {
3130
Schema string `yaml:"schema"`
3231
}
3332

34-
type mockDependencyClient struct {
35-
*resolve.LocalClient
36-
}
37-
38-
func (mdc mockDependencyClient) AddRegistries(_ []resolution.Registry) error { return nil }
39-
4033
// NewMockResolutionClient creates a new mock resolution client from the given universe YAML.
41-
func NewMockResolutionClient(t *testing.T, universeYAML string) resolution.DependencyClient {
34+
func NewMockResolutionClient(t *testing.T, universeYAML string) resolve.Client {
4235
t.Helper()
4336
f, err := os.Open(universeYAML)
4437
if err != nil {
@@ -70,5 +63,5 @@ func NewMockResolutionClient(t *testing.T, universeYAML string) resolution.Depen
7063
t.Fatalf("failed parsing schema: %v", err)
7164
}
7265

73-
return mockDependencyClient{sch.NewClient()}
66+
return sch.NewClient()
7467
}

clients/resolution/client.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ import (
1919
"deps.dev/util/resolve"
2020
)
2121

22-
// DependencyClient is the interface of the client required by dependency resolution.
23-
type DependencyClient interface {
22+
// ClientWithRegistries is a resolve.Client that allows package registries to be added.
23+
type ClientWithRegistries interface {
2424
resolve.Client
2525
// AddRegistries adds the specified registries to fetch data.
2626
AddRegistries(registries []Registry) error

clients/resolution/depsdev_client.go

-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,3 @@ func NewDepsDevClient(addr string, userAgent string) (*DepsDevClient, error) {
3434

3535
return &DepsDevClient{APIClient: *resolve.NewAPIClient(c), c: c}, nil
3636
}
37-
38-
// AddRegistries is a placeholder here for DepsDevClient.
39-
func (d *DepsDevClient) AddRegistries(_ []Registry) error { return nil }

clients/resolution/override_client.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,20 @@ import (
2121
"deps.dev/util/resolve"
2222
)
2323

24-
// OverrideClient wraps a DependencyClient, allowing for custom packages & versions to be added
24+
// OverrideClient wraps a resolve.Client, allowing for custom packages & versions to be added
2525
type OverrideClient struct {
26-
DependencyClient
26+
resolve.Client
2727
// Can't quite reuse resolve.LocalClient because it automatically creates dependencies
2828
pkgVers map[resolve.PackageKey][]resolve.Version // versions of a package
2929
verDeps map[resolve.VersionKey][]resolve.RequirementVersion // dependencies of a version
3030
}
3131

3232
// NewOverrideClient makes a new OverrideClient.
33-
func NewOverrideClient(c DependencyClient) *OverrideClient {
33+
func NewOverrideClient(c resolve.Client) *OverrideClient {
3434
return &OverrideClient{
35-
DependencyClient: c,
36-
pkgVers: make(map[resolve.PackageKey][]resolve.Version),
37-
verDeps: make(map[resolve.VersionKey][]resolve.RequirementVersion),
35+
Client: c,
36+
pkgVers: make(map[resolve.PackageKey][]resolve.Version),
37+
verDeps: make(map[resolve.VersionKey][]resolve.RequirementVersion),
3838
}
3939
}
4040

@@ -62,7 +62,7 @@ func (c *OverrideClient) Version(ctx context.Context, vk resolve.VersionKey) (re
6262
}
6363
}
6464

65-
return c.DependencyClient.Version(ctx, vk)
65+
return c.Client.Version(ctx, vk)
6666
}
6767

6868
// Versions returns the versions of a package specified by the PackageKey.
@@ -71,7 +71,7 @@ func (c *OverrideClient) Versions(ctx context.Context, pk resolve.PackageKey) ([
7171
return vers, nil
7272
}
7373

74-
return c.DependencyClient.Versions(ctx, pk)
74+
return c.Client.Versions(ctx, pk)
7575
}
7676

7777
// Requirements returns the requirement versions of the version specified by the VersionKey.
@@ -80,7 +80,7 @@ func (c *OverrideClient) Requirements(ctx context.Context, vk resolve.VersionKey
8080
return deps, nil
8181
}
8282

83-
return c.DependencyClient.Requirements(ctx, vk)
83+
return c.Client.Requirements(ctx, vk)
8484
}
8585

8686
// MatchingVersions returns the versions matching the requirement specified by the VersionKey.
@@ -89,5 +89,5 @@ func (c *OverrideClient) MatchingVersions(ctx context.Context, vk resolve.Versio
8989
return resolve.MatchRequirement(vk, vs), nil
9090
}
9191

92-
return c.DependencyClient.MatchingVersions(ctx, vk)
92+
return c.Client.MatchingVersions(ctx, vk)
9393
}

extractor/filesystem/language/java/pomxmlnet/pomxmlnet.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ import (
3838

3939
// Extractor extracts Maven packages with transitive dependency resolution.
4040
type Extractor struct {
41-
depClient resolution.DependencyClient
41+
depClient resolve.Client
4242
mavenClient *datasource.MavenRegistryAPIClient
4343
}
4444

4545
// Config is the configuration for the pomxmlnet Extractor.
4646
type Config struct {
47-
resolution.DependencyClient
47+
DependencyClient resolve.Client
4848
*datasource.MavenRegistryAPIClient
4949
}
5050

@@ -133,8 +133,10 @@ func (e Extractor) Extract(ctx context.Context, input *filesystem.ScanInput) ([]
133133
for i, reg := range registries {
134134
clientRegs[i] = reg
135135
}
136-
if err := e.depClient.AddRegistries(clientRegs); err != nil {
137-
return nil, err
136+
if cl, ok := e.depClient.(resolution.ClientWithRegistries); ok {
137+
if err := cl.AddRegistries(clientRegs); err != nil {
138+
return nil, err
139+
}
138140
}
139141
}
140142

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ require (
2323
github.com/opencontainers/go-digest v1.0.0
2424
github.com/opencontainers/image-spec v1.1.0
2525
github.com/opencontainers/runtime-spec v1.1.0
26+
github.com/ossf/osv-schema/bindings/go v0.0.0-20250210065807-ab8a4f6e6389
2627
github.com/package-url/packageurl-go v0.1.2
2728
github.com/spdx/tools-golang v0.5.3
2829
github.com/tidwall/jsonc v0.3.2

go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bl
157157
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
158158
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
159159
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
160+
github.com/ossf/osv-schema v1.6.7/go.mod h1:5JF2BtmJlCOVvx9ojzEXpSvqyJDfHDtRk8E5KIRO6uA=
161+
github.com/ossf/osv-schema/bindings/go v0.0.0-20250210065807-ab8a4f6e6389 h1:1ITHMJ7xNLEC9Qq9kvXPe8/rf7rrCxV5/fjyhawBbgI=
162+
github.com/ossf/osv-schema/bindings/go v0.0.0-20250210065807-ab8a4f6e6389/go.mod h1:lILztSxHU7VsdlYqCnwgxSDBhbXMf7iEQWtldJCDXPo=
160163
github.com/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4=
161164
github.com/package-url/packageurl-go v0.1.2/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c=
162165
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package manifest provides methods for parsing and writing manifest files.
16+
package manifest
17+
18+
import (
19+
"deps.dev/util/resolve"
20+
"github.com/google/osv-scalibr/internal/guidedremediation/manifest/maven"
21+
"github.com/google/osv-scalibr/internal/guidedremediation/manifest/npm"
22+
)
23+
24+
// Manifest is the interface for the representation of a manifest file needed for dependency resolution.
25+
type Manifest interface {
26+
FilePath() string // Path to the manifest file
27+
Root() resolve.Version // Version representing this package
28+
System() resolve.System // The System of this manifest
29+
Requirements() []resolve.RequirementVersion // All direct requirements, including dev
30+
Groups() map[RequirementKey][]string // Dependency groups that the imports belong to
31+
LocalManifests() []Manifest // Manifests of local packages
32+
EcosystemSpecific() any // Any ecosystem-specific information needed
33+
34+
Clone() Manifest // Clone the manifest
35+
}
36+
37+
// RequirementKey is a comparable type that uniquely identifies a package dependency in a manifest.
38+
// It does not include the version specification.
39+
type RequirementKey any
40+
41+
// MakeRequirementKey constructs an ecosystem-specific RequirementKey from the given RequirementVersion.
42+
func MakeRequirementKey(requirement resolve.RequirementVersion) RequirementKey {
43+
switch requirement.System {
44+
case resolve.NPM:
45+
return npm.MakeRequirementKey(requirement)
46+
case resolve.Maven:
47+
return maven.MakeRequirementKey(requirement)
48+
case resolve.UnknownSystem:
49+
fallthrough
50+
default:
51+
return requirement.PackageKey
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package maven provides the manifest parsing and writing for the Maven pom.xml format.
16+
package maven
17+
18+
import (
19+
"deps.dev/util/maven"
20+
"deps.dev/util/resolve"
21+
"deps.dev/util/resolve/dep"
22+
)
23+
24+
// RequirementKey is a comparable type that uniquely identifies a package dependency in a manifest.
25+
type RequirementKey struct {
26+
resolve.PackageKey
27+
ArtifactType string
28+
Classifier string
29+
}
30+
31+
var _ map[RequirementKey]any
32+
33+
// MakeRequirementKey constructs a maven RequirementKey from the given RequirementVersion.
34+
func MakeRequirementKey(requirement resolve.RequirementVersion) RequirementKey {
35+
// Maven dependencies must have unique groupId:artifactId:type:classifier.
36+
artifactType, _ := requirement.Type.GetAttr(dep.MavenArtifactType)
37+
classifier, _ := requirement.Type.GetAttr(dep.MavenClassifier)
38+
39+
return RequirementKey{
40+
PackageKey: requirement.PackageKey,
41+
ArtifactType: artifactType,
42+
Classifier: classifier,
43+
}
44+
}
45+
46+
// ManifestSpecific is ecosystem-specific information needed for the pom.xml manifest.
47+
type ManifestSpecific struct {
48+
Parent maven.Parent
49+
Properties []PropertyWithOrigin // Properties from the base project
50+
OriginalRequirements []DependencyWithOrigin // Dependencies from the base project
51+
RequirementsForUpdates []resolve.RequirementVersion // Requirements that we only need for updates
52+
Repositories []maven.Repository
53+
}
54+
55+
// PropertyWithOrigin is a maven property with the origin where it comes from.
56+
type PropertyWithOrigin struct {
57+
maven.Property
58+
Origin string // Origin indicates where the property comes from
59+
}
60+
61+
// DependencyWithOrigin is a maven dependency with the origin where it comes from.
62+
type DependencyWithOrigin struct {
63+
maven.Dependency
64+
Origin string // Origin indicates where the dependency comes from
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package npm provides the manifest parsing and writing for the npm package.json format.
16+
package npm
17+
18+
import (
19+
"deps.dev/util/resolve"
20+
"deps.dev/util/resolve/dep"
21+
)
22+
23+
// RequirementKey is a comparable type that uniquely identifies a package dependency in a manifest.
24+
type RequirementKey struct {
25+
resolve.PackageKey
26+
KnownAs string
27+
}
28+
29+
var _ map[RequirementKey]any
30+
31+
// MakeRequirementKey constructs an npm RequirementKey from the given RequirementVersion.
32+
func MakeRequirementKey(requirement resolve.RequirementVersion) RequirementKey {
33+
// Npm requirements are the uniquely identified by the key in the dependencies fields (which ends up being the path in node_modules)
34+
// Declaring a dependency in multiple places (dependencies, devDependencies, optionalDependencies) only installs it once at one version.
35+
// Aliases & non-registry dependencies are keyed on their 'KnownAs' attribute.
36+
knownAs, _ := requirement.Type.GetAttr(dep.KnownAs)
37+
return RequirementKey{
38+
PackageKey: requirement.PackageKey,
39+
KnownAs: knownAs,
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package matcher provides the interface for the vulnerability matcher used by guided remediation.
16+
package matcher
17+
18+
import (
19+
"context"
20+
21+
"github.com/google/osv-scalibr/extractor"
22+
"github.com/ossf/osv-schema/bindings/go/osvschema"
23+
)
24+
25+
// TODO(#454): Temporarily internal while migration is in progress.
26+
// Will need to be moved to publicly accessible location once external interface is created.
27+
28+
// VulnerabilityMatcher interface provides functionality get a list of affecting vulnerabilities for each package in an inventory.
29+
type VulnerabilityMatcher interface {
30+
MatchVulnerabilities(ctx context.Context, invs []*extractor.Inventory) ([][]*osvschema.Vulnerability, error)
31+
}

0 commit comments

Comments
 (0)