Skip to content

Commit

Permalink
✨ Feature: Dependency-diff ecosystem naming convention mapping (GitHu…
Browse files Browse the repository at this point in the history
…b -> OSV) (ossf#2088)

* save

* save

* save

* save

* save

* save
  • Loading branch information
aidenwang9867 authored and singhsaurabh committed Jul 25, 2022
1 parent 607286f commit b00d0a4
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 5 deletions.
25 changes: 25 additions & 0 deletions dependencydiff/dependencydiff.go
Expand Up @@ -79,13 +79,34 @@ func GetDependencyDiffResults(
if err != nil {
return nil, fmt.Errorf("error in fetchRawDependencyDiffData: %w", err)
}
// Map the ecosystem naming convention from GitHub to OSV.
err = mapDependencyEcosystemNaming(dCtx.dependencydiffs)
if err != nil {
return nil, fmt.Errorf("error in mapDependencyEcosystemNaming: %w", err)
}
err = getScorecardCheckResults(&dCtx)
if err != nil {
return nil, fmt.Errorf("error getting scorecard check results: %w", err)
}
return dCtx.results, nil
}

func mapDependencyEcosystemNaming(deps []dependency) error {
for i := range deps {
if deps[i].Ecosystem == nil {
continue
}
mappedEcosys, err := toEcosystem(*deps[i].Ecosystem)
if err != nil {
wrappedErr := fmt.Errorf("error mapping dependency ecosystem: %w", err)
return wrappedErr
}
deps[i].Ecosystem = asPointer(string(mappedEcosys))

}
return nil
}

func initRepoAndClientByChecks(dCtx *dependencydiffContext, dSrcRepo string) error {
repo, repoClient, ossFuzzClient, ciiClient, vulnsClient, err := checker.GetClients(
dCtx.ctx, dSrcRepo, "", dCtx.logger,
Expand Down Expand Up @@ -171,3 +192,7 @@ func getScorecardCheckResults(dCtx *dependencydiffContext) error {
}
return nil
}

func asPointer(s string) *string {
return &s
}
64 changes: 64 additions & 0 deletions dependencydiff/dependencydiff_test.go
Expand Up @@ -16,6 +16,7 @@ package dependencydiff

import (
"context"
"errors"
"path"
"testing"

Expand Down Expand Up @@ -158,3 +159,66 @@ func Test_getScorecardCheckResults(t *testing.T) {
})
}
}

func Test_mapDependencyEcosystemNaming(t *testing.T) {
t.Parallel()
//nolint
tests := []struct {
name string
deps []dependency
errWanted error
}{
{
name: "error invalid github ecosystem",
deps: []dependency{
{
Name: "dependency_1",
Ecosystem: asPointer("not_supported"),
},
{
Name: "dependency_2",
Ecosystem: asPointer("gomod"),
},
},
errWanted: errInvalid,
},
{
name: "error cannot find mapping",
deps: []dependency{
{
Name: "dependency_3",
Ecosystem: asPointer("actions"),
},
},
errWanted: errInvalid,
},
{
name: "correct mapping",
deps: []dependency{
{
Name: "dependency_4",
Ecosystem: asPointer("gomod"),
},
{
Name: "dependency_5",
Ecosystem: asPointer("pip"),
},
{
Name: "dependency_6",
Ecosystem: asPointer("cargo"),
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := mapDependencyEcosystemNaming(tt.deps)
if tt.errWanted != nil && errors.Is(tt.errWanted, err) {
t.Errorf("not a wanted error, want:%v, got:%v", tt.errWanted, err)
return
}
})
}
}
3 changes: 2 additions & 1 deletion dependencydiff/errors.go
Expand Up @@ -18,5 +18,6 @@ import "errors"

// static Errors for mapping
var (
errInvalid = errors.New("invalid")
errMappingNotFound = errors.New("ecosystem mapping not found")
errInvalid = errors.New("invalid")
)
89 changes: 89 additions & 0 deletions dependencydiff/mapping.go
@@ -0,0 +1,89 @@
// Copyright 2022 Security Scorecard 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 dependencydiff

import (
"fmt"
)

// Ecosystem is a package ecosystem supported by OSV, GitHub, etc.
type ecosystem string

// OSV ecosystem naming data source: https://ossf.github.io/osv-schema/#affectedpackage-field
// nolint
const (
// The Go ecosystem.
ecosystemGo ecosystem = "Go"

// The NPM ecosystem.
ecosystemNpm ecosystem = "npm"

// The Android ecosystem
ecosystemAndroid ecosystem = "Android" // nolint:unused

// The crates.io ecosystem for RUST.
ecosystemCrates ecosystem = "crates.io"

// For reports from the OSS-Fuzz project that have no more appropriate ecosystem.
ecosystemOssFuzz ecosystem = "OSS-Fuzz" // nolint:unused

// The Python PyPI ecosystem. PyPI is the main package source of pip.
ecosystemPyPI ecosystem = "PyPI"

// The RubyGems ecosystem.
ecosystemRubyGems ecosystem = "RubyGems"

// The PHP package manager ecosystem. Packagist is the main Composer repository.
ecosystemPackagist ecosystem = "Packagist"

// The Maven Java package ecosystem.
ecosystemMaven ecosystem = "Maven"

// The NuGet package ecosystem.
ecosystemNuGet ecosystem = "Nuget"

// The Linux kernel.
ecosystemLinux ecosystem = "Linux" // nolint:unused

// The Debian package ecosystem.
ecosystemDebian ecosystem = "Debian" // nolint:unused

// Hex is the package manager of Erlang.
// TODO: GitHub doesn't support hex as the ecosystem for Erlang yet. Add this to the map in the future.
ecosystemHex ecosystem = "Hex" // nolint:unused
)

var (
//gitHubToOSV defines the ecosystem naming mapping relationship between GitHub and others.
gitHubToOSV = map[string]ecosystem{
// GitHub ecosystem naming data source: https://docs.github.com/en/code-security/supply-chain-security/
// understanding-your-software-supply-chain/about-the-dependency-graph#supported-package-ecosystems
"gomod": ecosystemGo, /* go.mod and go.sum */
"cargo": ecosystemCrates,
"pip": ecosystemPyPI, /* pip and poetry */
"npm": ecosystemNpm, /* npm and yarn */
"maven": ecosystemMaven,
"composer": ecosystemPackagist,
"rubygems": ecosystemRubyGems,
"nuget": ecosystemNuGet,
}
)

func toEcosystem(e string) (ecosystem, error) {
if ecosystemOSV, found := gitHubToOSV[e]; found {
return ecosystemOSV, nil
}
return "", fmt.Errorf("%w for github entry %s", errMappingNotFound, e)
}
5 changes: 5 additions & 0 deletions dependencydiff/raw_dependencies.go
Expand Up @@ -68,5 +68,10 @@ func fetchRawDependencyDiffData(dCtx *dependencydiffContext) error {
if err != nil {
return fmt.Errorf("error parsing the dependency-diff reponse: %w", err)
}
for _, d := range dCtx.dependencydiffs {
if !d.ChangeType.IsValid() {
return fmt.Errorf("%w: change type", errInvalid)
}
}
return nil
}
8 changes: 4 additions & 4 deletions pkg/dependencydiff_result.go
Expand Up @@ -35,8 +35,8 @@ const (
)

// IsValid determines if a ChangeType is valid.
func (ct *ChangeType) IsValid() bool {
switch *ct {
func (ct ChangeType) IsValid() bool {
switch ct {
case Added, Updated, Removed:
return true
default:
Expand All @@ -45,7 +45,7 @@ func (ct *ChangeType) IsValid() bool {
}

// ScorecardResultWithError is used for the dependency-diff module to record the scorecard result
// and a potential error field if the Scorecard run fails.
// and a error field to record potential errors when the Scorecard run fails.
type ScorecardResultWithError struct {
// ScorecardResult is the scorecard result for the dependency repo.
ScorecardResult *ScorecardResult
Expand Down Expand Up @@ -74,7 +74,7 @@ type DependencyCheckResult struct {
// Version is the package version of the dependency.
Version *string

// ScorecardResultWithError is the scorecard checking results of the dependency.
// ScorecardResultWithError is the scorecard checking result of the dependency.
ScorecardResultWithError ScorecardResultWithError

// Name is the name of the dependency.
Expand Down

0 comments on commit b00d0a4

Please sign in to comment.