mirror of
https://github.com/ossf/scorecard.git
synced 2024-11-04 03:52:31 +03:00
✨ [Check split]: Binary-Artifacts (#1244)
* split binary artifact check * fix * missing file * comments * linter * fix * comments * linter
This commit is contained in:
parent
4bd24b8291
commit
cc4949465b
@ -15,14 +15,9 @@
|
|||||||
package checks
|
package checks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/h2non/filetype"
|
|
||||||
"github.com/h2non/filetype/types"
|
|
||||||
|
|
||||||
"github.com/ossf/scorecard/v3/checker"
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/evaluation"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/raw"
|
||||||
sce "github.com/ossf/scorecard/v3/errors"
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,86 +29,13 @@ func init() {
|
|||||||
registerCheck(CheckBinaryArtifacts, BinaryArtifacts)
|
registerCheck(CheckBinaryArtifacts, BinaryArtifacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BinaryArtifacts will check the repository if it contains binary artifacts.
|
// BinaryArtifacts will check the repository contains binary artifacts.
|
||||||
func BinaryArtifacts(c *checker.CheckRequest) checker.CheckResult {
|
func BinaryArtifacts(c *checker.CheckRequest) checker.CheckResult {
|
||||||
var binFound bool
|
rawData, err := raw.BinaryArtifacts(c)
|
||||||
err := CheckFilesContent("*", false, c, checkBinaryFileContent, &binFound)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
||||||
return checker.CreateRuntimeErrorResult(CheckBinaryArtifacts, e)
|
return checker.CreateRuntimeErrorResult(CheckBinaryArtifacts, e)
|
||||||
}
|
}
|
||||||
if binFound {
|
|
||||||
return checker.CreateMinScoreResult(CheckBinaryArtifacts, "binaries present in source code")
|
|
||||||
}
|
|
||||||
|
|
||||||
return checker.CreateMaxScoreResult(CheckBinaryArtifacts, "no binaries found in the repo")
|
return evaluation.BinaryArtifacts(CheckBinaryArtifacts, c.Dlogger, &rawData)
|
||||||
}
|
|
||||||
|
|
||||||
func checkBinaryFileContent(path string, content []byte,
|
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
|
||||||
pfound := FileGetCbDataAsBoolPointer(data)
|
|
||||||
binaryFileTypes := map[string]bool{
|
|
||||||
"crx": true,
|
|
||||||
"deb": true,
|
|
||||||
"dex": true,
|
|
||||||
"dey": true,
|
|
||||||
"elf": true,
|
|
||||||
"bin": true,
|
|
||||||
"o": true,
|
|
||||||
"so": true,
|
|
||||||
"iso": true,
|
|
||||||
"class": true,
|
|
||||||
"jar": true,
|
|
||||||
"bundle": true,
|
|
||||||
"dylib": true,
|
|
||||||
"lib": true,
|
|
||||||
"msi": true,
|
|
||||||
"acm": true,
|
|
||||||
"ax": true,
|
|
||||||
"cpl": true,
|
|
||||||
"dll": true,
|
|
||||||
"drv": true,
|
|
||||||
"efi": true,
|
|
||||||
"exe": true,
|
|
||||||
"mui": true,
|
|
||||||
"ocx": true,
|
|
||||||
"scr": true,
|
|
||||||
"sys": true,
|
|
||||||
"tsp": true,
|
|
||||||
"pyc": true,
|
|
||||||
"pyo": true,
|
|
||||||
"par": true,
|
|
||||||
"rpm": true,
|
|
||||||
"swf": true,
|
|
||||||
"torrent": true,
|
|
||||||
"cab": true,
|
|
||||||
"whl": true,
|
|
||||||
}
|
|
||||||
var t types.Type
|
|
||||||
var err error
|
|
||||||
if len(content) == 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if t, err = filetype.Get(content); err != nil {
|
|
||||||
return false, sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("filetype.Get:%v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := binaryFileTypes[t.Extension]; ok {
|
|
||||||
dl.Warn3(&checker.LogMessage{
|
|
||||||
Path: path, Type: checker.FileTypeBinary,
|
|
||||||
Text: "binary detected",
|
|
||||||
})
|
|
||||||
*pfound = true
|
|
||||||
return true, nil
|
|
||||||
} else if _, ok := binaryFileTypes[strings.ReplaceAll(filepath.Ext(path), ".", "")]; ok {
|
|
||||||
// Falling back to file based extension.
|
|
||||||
dl.Warn3(&checker.LogMessage{
|
|
||||||
Path: path, Type: checker.FileTypeBinary,
|
|
||||||
Text: "binary detected",
|
|
||||||
})
|
|
||||||
*pfound = true
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
|
@ -46,14 +46,14 @@ func DangerousWorkflow(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
data := patternCbData{
|
data := patternCbData{
|
||||||
workflowPattern: make(map[string]bool),
|
workflowPattern: make(map[string]bool),
|
||||||
}
|
}
|
||||||
err := CheckFilesContent(".github/workflows/*", false,
|
err := fileparser.CheckFilesContent(".github/workflows/*", false,
|
||||||
c, validateGitHubActionWorkflowPatterns, &data)
|
c, validateGitHubActionWorkflowPatterns, &data)
|
||||||
return createResultForDangerousWorkflowPatterns(data, err)
|
return createResultForDangerousWorkflowPatterns(data, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check file content.
|
// Check file content.
|
||||||
func validateGitHubActionWorkflowPatterns(path string, content []byte, dl checker.DetailLogger,
|
func validateGitHubActionWorkflowPatterns(path string, content []byte, dl checker.DetailLogger,
|
||||||
data FileCbData) (bool, error) {
|
data fileparser.FileCbData) (bool, error) {
|
||||||
if !fileparser.IsWorkflowFile(path) {
|
if !fileparser.IsWorkflowFile(path) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ func validateGitHubActionWorkflowPatterns(path string, content []byte, dl checke
|
|||||||
panic("invalid type")
|
panic("invalid type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !CheckFileContainsCommands(content, "#") {
|
if !fileparser.CheckFileContainsCommands(content, "#") {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ossf/scorecard/v3/checker"
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/fileparser"
|
||||||
sce "github.com/ossf/scorecard/v3/errors"
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ func init() {
|
|||||||
// UsesDependencyUpdateTool will check the repository uses a dependency update tool.
|
// UsesDependencyUpdateTool will check the repository uses a dependency update tool.
|
||||||
func UsesDependencyUpdateTool(c *checker.CheckRequest) checker.CheckResult {
|
func UsesDependencyUpdateTool(c *checker.CheckRequest) checker.CheckResult {
|
||||||
var r bool
|
var r bool
|
||||||
err := CheckIfFileExists(CheckDependencyUpdateTool, c, fileExists, &r)
|
err := fileparser.CheckIfFileExists(CheckDependencyUpdateTool, c, fileExists, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
e := sce.WithMessage(sce.ErrScorecardInternal, err.Error())
|
||||||
return checker.CreateRuntimeErrorResult(CheckDependencyUpdateTool, e)
|
return checker.CreateRuntimeErrorResult(CheckDependencyUpdateTool, e)
|
||||||
@ -54,8 +55,8 @@ func UsesDependencyUpdateTool(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fileExists will validate the if frozen dependencies file name exists.
|
// fileExists will validate the if frozen dependencies file name exists.
|
||||||
func fileExists(name string, dl checker.DetailLogger, data FileCbData) (bool, error) {
|
func fileExists(name string, dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
pdata := FileGetCbDataAsBoolPointer(data)
|
pdata := fileparser.FileGetCbDataAsBoolPointer(data)
|
||||||
|
|
||||||
switch strings.ToLower(name) {
|
switch strings.ToLower(name) {
|
||||||
case ".github/dependabot.yml":
|
case ".github/dependabot.yml":
|
||||||
|
44
checks/evaluation/binary_artifacts.go
Normal file
44
checks/evaluation/binary_artifacts.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2021 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 evaluation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/raw"
|
||||||
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BinaryArtifacts applies the score policy for the Binary-Artiacts check.
|
||||||
|
func BinaryArtifacts(name string, dl checker.DetailLogger,
|
||||||
|
r *raw.BinaryArtifactData) checker.CheckResult {
|
||||||
|
if r == nil {
|
||||||
|
e := sce.WithMessage(sce.ErrScorecardInternal, "empty raw data")
|
||||||
|
return checker.CreateRuntimeErrorResult(name, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the policy evaluation.
|
||||||
|
if r.Files == nil || len(r.Files) == 0 {
|
||||||
|
return checker.CreateMaxScoreResult(name, "no binaries found in the repo")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range r.Files {
|
||||||
|
dl.Warn3(&checker.LogMessage{
|
||||||
|
Path: f.Path, Type: checker.FileTypeBinary,
|
||||||
|
Text: "binary detected",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return checker.CreateMinScoreResult(name, "binaries present in source code")
|
||||||
|
}
|
@ -18,4 +18,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errInvalidGitHubWorkflow = errors.New("invalid GitHub workflow")
|
var (
|
||||||
|
errInvalidGitHubWorkflow = errors.New("invalid GitHub workflow")
|
||||||
|
errInternalFilenameMatch = errors.New("filename match error")
|
||||||
|
)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package checks
|
package fileparser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -21,6 +21,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ossf/scorecard/v3/checker"
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/clients"
|
||||||
sce "github.com/ossf/scorecard/v3/errors"
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,6 +116,58 @@ func CheckFilesContent(shellPathFnPattern string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileContentCbV6 is the callback.
|
||||||
|
// The bool returned indicates whether the CheckFilesContent2
|
||||||
|
// should continue iterating over files or not.
|
||||||
|
type FileContentCbV6 func(path string, content []byte, data FileCbData) (bool, error)
|
||||||
|
|
||||||
|
// CheckFilesContentV6 is the same as CheckFilesContent
|
||||||
|
// but for use with separated check/policy code.
|
||||||
|
func CheckFilesContentV6(shellPathFnPattern string,
|
||||||
|
caseSensitive bool,
|
||||||
|
repoClient clients.RepoClient,
|
||||||
|
onFileContent FileContentCbV6,
|
||||||
|
data FileCbData,
|
||||||
|
) error {
|
||||||
|
predicate := func(filepath string) (bool, error) {
|
||||||
|
// Filter out test files.
|
||||||
|
if isTestdataFile(filepath) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
// Filter out files based on path/names using the pattern.
|
||||||
|
b, err := isMatchingPath(shellPathFnPattern, filepath, caseSensitive)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
matchedFiles, err := repoClient.ListFiles(predicate)
|
||||||
|
if err != nil {
|
||||||
|
// nolint: wrapcheck
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range matchedFiles {
|
||||||
|
content, err := repoClient.GetFileContent(file)
|
||||||
|
if err != nil {
|
||||||
|
//nolint
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
continueIter, err := onFileContent(file, content, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !continueIter {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// FileCb represents a callback fn.
|
// FileCb represents a callback fn.
|
||||||
type FileCb func(path string,
|
type FileCb func(path string,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error)
|
dl checker.DetailLogger, data FileCbData) (bool, error)
|
@ -21,6 +21,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/ossf/scorecard/v3/checker"
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/fileparser"
|
||||||
"github.com/ossf/scorecard/v3/clients"
|
"github.com/ossf/scorecard/v3/clients"
|
||||||
"github.com/ossf/scorecard/v3/clients/githubrepo"
|
"github.com/ossf/scorecard/v3/clients/githubrepo"
|
||||||
sce "github.com/ossf/scorecard/v3/errors"
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
@ -44,13 +45,13 @@ func init() {
|
|||||||
|
|
||||||
func checkCFLite(c *checker.CheckRequest) (bool, error) {
|
func checkCFLite(c *checker.CheckRequest) (bool, error) {
|
||||||
result := false
|
result := false
|
||||||
e := CheckFilesContent(".clusterfuzzlite/Dockerfile", true, c,
|
e := fileparser.CheckFilesContent(".clusterfuzzlite/Dockerfile", true, c,
|
||||||
func(path string, content []byte, dl checker.DetailLogger, data FileCbData) (bool, error) {
|
func(path string, content []byte, dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
result = CheckFileContainsCommands(content, "#")
|
result = fileparser.CheckFileContainsCommands(content, "#")
|
||||||
return false, nil
|
return false, nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
return result, e
|
return result, fmt.Errorf("%w", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkOSSFuzz(c *checker.CheckRequest) (bool, error) {
|
func checkOSSFuzz(c *checker.CheckRequest) (bool, error) {
|
||||||
|
@ -48,7 +48,7 @@ func TokenPermissions(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
topLevelWritePermissions: make(map[string]bool),
|
topLevelWritePermissions: make(map[string]bool),
|
||||||
runLevelWritePermissions: make(map[string]bool),
|
runLevelWritePermissions: make(map[string]bool),
|
||||||
}
|
}
|
||||||
err := CheckFilesContent(".github/workflows/*", false,
|
err := fileparser.CheckFilesContent(".github/workflows/*", false,
|
||||||
c, validateGitHubActionTokenPermissions, &data)
|
c, validateGitHubActionTokenPermissions, &data)
|
||||||
return createResultForLeastPrivilegeTokens(data, err)
|
return createResultForLeastPrivilegeTokens(data, err)
|
||||||
}
|
}
|
||||||
@ -326,7 +326,7 @@ func testValidateGitHubActionTokenPermissions(pathfn string,
|
|||||||
|
|
||||||
// Check file content.
|
// Check file content.
|
||||||
func validateGitHubActionTokenPermissions(path string, content []byte,
|
func validateGitHubActionTokenPermissions(path string, content []byte,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
if !fileparser.IsWorkflowFile(path) {
|
if !fileparser.IsWorkflowFile(path) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -337,7 +337,7 @@ func validateGitHubActionTokenPermissions(path string, content []byte,
|
|||||||
panic("invalid type")
|
panic("invalid type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !CheckFileContainsCommands(content, "#") {
|
if !fileparser.CheckFileContainsCommands(content, "#") {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ func addPinnedResult(r *pinnedResult, to bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataAsWorkflowResultPointer(data FileCbData) *worklowPinningResult {
|
func dataAsWorkflowResultPointer(data fileparser.FileCbData) *worklowPinningResult {
|
||||||
pdata, ok := data.(*worklowPinningResult)
|
pdata, ok := data.(*worklowPinningResult)
|
||||||
if !ok {
|
if !ok {
|
||||||
// panic if it is not correct type
|
// panic if it is not correct type
|
||||||
@ -169,7 +169,7 @@ func createReturnValuesForGitHubActionsWorkflowPinned(r worklowPinningResult, in
|
|||||||
return score, nil
|
return score, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func dataAsResultPointer(data FileCbData) *pinnedResult {
|
func dataAsResultPointer(data fileparser.FileCbData) *pinnedResult {
|
||||||
pdata, ok := data.(*pinnedResult)
|
pdata, ok := data.(*pinnedResult)
|
||||||
if !ok {
|
if !ok {
|
||||||
// This never happens.
|
// This never happens.
|
||||||
@ -197,7 +197,8 @@ func createReturnValues(r pinnedResult, infoMsg string, dl checker.DetailLogger,
|
|||||||
|
|
||||||
func isShellScriptFreeOfInsecureDownloads(c *checker.CheckRequest) (int, error) {
|
func isShellScriptFreeOfInsecureDownloads(c *checker.CheckRequest) (int, error) {
|
||||||
var r pinnedResult
|
var r pinnedResult
|
||||||
err := CheckFilesContent("*", false, c, validateShellScriptIsFreeOfInsecureDownloads, &r)
|
err := fileparser.CheckFilesContent("*", false,
|
||||||
|
c, validateShellScriptIsFreeOfInsecureDownloads, &r)
|
||||||
return createReturnForIsShellScriptFreeOfInsecureDownloads(r, c.Dlogger, err)
|
return createReturnForIsShellScriptFreeOfInsecureDownloads(r, c.Dlogger, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +217,7 @@ func testValidateShellScriptIsFreeOfInsecureDownloads(pathfn string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateShellScriptIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
func validateShellScriptIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
pdata := dataAsResultPointer(data)
|
pdata := dataAsResultPointer(data)
|
||||||
|
|
||||||
// Validate the file type.
|
// Validate the file type.
|
||||||
@ -236,7 +237,8 @@ func validateShellScriptIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
|||||||
|
|
||||||
func isDockerfileFreeOfInsecureDownloads(c *checker.CheckRequest) (int, error) {
|
func isDockerfileFreeOfInsecureDownloads(c *checker.CheckRequest) (int, error) {
|
||||||
var r pinnedResult
|
var r pinnedResult
|
||||||
err := CheckFilesContent("*Dockerfile*", false, c, validateDockerfileIsFreeOfInsecureDownloads, &r)
|
err := fileparser.CheckFilesContent("*Dockerfile*",
|
||||||
|
false, c, validateDockerfileIsFreeOfInsecureDownloads, &r)
|
||||||
return createReturnForIsDockerfileFreeOfInsecureDownloads(r, c.Dlogger, err)
|
return createReturnForIsDockerfileFreeOfInsecureDownloads(r, c.Dlogger, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +258,7 @@ func testValidateDockerfileIsFreeOfInsecureDownloads(pathfn string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateDockerfileIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
func validateDockerfileIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
pdata := dataAsResultPointer(data)
|
pdata := dataAsResultPointer(data)
|
||||||
|
|
||||||
// Return early if this is a script, e.g. script_dockerfile_something.sh
|
// Return early if this is a script, e.g. script_dockerfile_something.sh
|
||||||
@ -265,7 +267,7 @@ func validateDockerfileIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !CheckFileContainsCommands(content, "#") {
|
if !fileparser.CheckFileContainsCommands(content, "#") {
|
||||||
addPinnedResult(pdata, true)
|
addPinnedResult(pdata, true)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -312,7 +314,8 @@ func validateDockerfileIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
|||||||
|
|
||||||
func isDockerfilePinned(c *checker.CheckRequest) (int, error) {
|
func isDockerfilePinned(c *checker.CheckRequest) (int, error) {
|
||||||
var r pinnedResult
|
var r pinnedResult
|
||||||
err := CheckFilesContent("*Dockerfile*", false, c, validateDockerfileIsPinned, &r)
|
err := fileparser.CheckFilesContent("*Dockerfile*", false,
|
||||||
|
c, validateDockerfileIsPinned, &r)
|
||||||
return createReturnForIsDockerfilePinned(r, c.Dlogger, err)
|
return createReturnForIsDockerfilePinned(r, c.Dlogger, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +333,7 @@ func testValidateDockerfileIsPinned(pathfn string, content []byte, dl checker.De
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateDockerfileIsPinned(pathfn string, content []byte,
|
func validateDockerfileIsPinned(pathfn string, content []byte,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
// Users may use various names, e.g.,
|
// Users may use various names, e.g.,
|
||||||
// Dockerfile.aarch64, Dockerfile.template, Dockerfile_template, dockerfile, Dockerfile-name.template
|
// Dockerfile.aarch64, Dockerfile.template, Dockerfile_template, dockerfile, Dockerfile-name.template
|
||||||
// Templates may trigger false positives, e.g. FROM { NAME }.
|
// Templates may trigger false positives, e.g. FROM { NAME }.
|
||||||
@ -342,7 +345,7 @@ func validateDockerfileIsPinned(pathfn string, content []byte,
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !CheckFileContainsCommands(content, "#") {
|
if !fileparser.CheckFileContainsCommands(content, "#") {
|
||||||
addPinnedResult(pdata, true)
|
addPinnedResult(pdata, true)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -429,7 +432,8 @@ func validateDockerfileIsPinned(pathfn string, content []byte,
|
|||||||
|
|
||||||
func isGitHubWorkflowScriptFreeOfInsecureDownloads(c *checker.CheckRequest) (int, error) {
|
func isGitHubWorkflowScriptFreeOfInsecureDownloads(c *checker.CheckRequest) (int, error) {
|
||||||
var r pinnedResult
|
var r pinnedResult
|
||||||
err := CheckFilesContent(".github/workflows/*", false, c, validateGitHubWorkflowIsFreeOfInsecureDownloads, &r)
|
err := fileparser.CheckFilesContent(".github/workflows/*", false,
|
||||||
|
c, validateGitHubWorkflowIsFreeOfInsecureDownloads, &r)
|
||||||
return createReturnForIsGitHubWorkflowScriptFreeOfInsecureDownloads(r, c.Dlogger, err)
|
return createReturnForIsGitHubWorkflowScriptFreeOfInsecureDownloads(r, c.Dlogger, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,14 +455,14 @@ func testValidateGitHubWorkflowScriptFreeOfInsecureDownloads(pathfn string,
|
|||||||
// validateGitHubWorkflowIsFreeOfInsecureDownloads checks if the workflow file downloads dependencies that are unpinned.
|
// validateGitHubWorkflowIsFreeOfInsecureDownloads checks if the workflow file downloads dependencies that are unpinned.
|
||||||
// Returns true if the check should continue executing after this file.
|
// Returns true if the check should continue executing after this file.
|
||||||
func validateGitHubWorkflowIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
func validateGitHubWorkflowIsFreeOfInsecureDownloads(pathfn string, content []byte,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
if !fileparser.IsWorkflowFile(pathfn) {
|
if !fileparser.IsWorkflowFile(pathfn) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pdata := dataAsResultPointer(data)
|
pdata := dataAsResultPointer(data)
|
||||||
|
|
||||||
if !CheckFileContainsCommands(content, "#") {
|
if !fileparser.CheckFileContainsCommands(content, "#") {
|
||||||
addPinnedResult(pdata, true)
|
addPinnedResult(pdata, true)
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -513,7 +517,8 @@ func validateGitHubWorkflowIsFreeOfInsecureDownloads(pathfn string, content []by
|
|||||||
// Check pinning of github actions in workflows.
|
// Check pinning of github actions in workflows.
|
||||||
func isGitHubActionsWorkflowPinned(c *checker.CheckRequest) (int, error) {
|
func isGitHubActionsWorkflowPinned(c *checker.CheckRequest) (int, error) {
|
||||||
var r worklowPinningResult
|
var r worklowPinningResult
|
||||||
err := CheckFilesContent(".github/workflows/*", true, c, validateGitHubActionWorkflow, &r)
|
err := fileparser.CheckFilesContent(".github/workflows/*",
|
||||||
|
true, c, validateGitHubActionWorkflow, &r)
|
||||||
return createReturnForIsGitHubActionsWorkflowPinned(r, c.Dlogger, err)
|
return createReturnForIsGitHubActionsWorkflowPinned(r, c.Dlogger, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,14 +539,14 @@ func testIsGitHubActionsWorkflowPinned(pathfn string, content []byte, dl checker
|
|||||||
// validateGitHubActionWorkflow checks if the workflow file contains unpinned actions. Returns true if the check
|
// validateGitHubActionWorkflow checks if the workflow file contains unpinned actions. Returns true if the check
|
||||||
// should continue executing after this file.
|
// should continue executing after this file.
|
||||||
func validateGitHubActionWorkflow(pathfn string, content []byte,
|
func validateGitHubActionWorkflow(pathfn string, content []byte,
|
||||||
dl checker.DetailLogger, data FileCbData) (bool, error) {
|
dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
if !fileparser.IsWorkflowFile(pathfn) {
|
if !fileparser.IsWorkflowFile(pathfn) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
pdata := dataAsWorkflowResultPointer(data)
|
pdata := dataAsWorkflowResultPointer(data)
|
||||||
|
|
||||||
if !CheckFileContainsCommands(content, "#") {
|
if !fileparser.CheckFileContainsCommands(content, "#") {
|
||||||
addWorkflowPinnedResult(pdata, true, true)
|
addWorkflowPinnedResult(pdata, true, true)
|
||||||
addWorkflowPinnedResult(pdata, true, true)
|
addWorkflowPinnedResult(pdata, true, true)
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -598,9 +603,9 @@ func addWorkflowPinnedResult(w *worklowPinningResult, to, isGitHub bool) {
|
|||||||
// Check presence of lock files thru validatePackageManagerFile().
|
// Check presence of lock files thru validatePackageManagerFile().
|
||||||
func isPackageManagerLockFilePresent(c *checker.CheckRequest) (int, error) {
|
func isPackageManagerLockFilePresent(c *checker.CheckRequest) (int, error) {
|
||||||
var r pinnedResult
|
var r pinnedResult
|
||||||
err := CheckIfFileExists(CheckPinnedDependencies, c, validatePackageManagerFile, &r)
|
err := fileparser.CheckIfFileExists(CheckPinnedDependencies, c, validatePackageManagerFile, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return checker.InconclusiveResultScore, err
|
return checker.InconclusiveResultScore, fmt.Errorf("%w", err)
|
||||||
}
|
}
|
||||||
if r != pinned {
|
if r != pinned {
|
||||||
c.Dlogger.Warn("no lock files detected for a package manager")
|
c.Dlogger.Warn("no lock files detected for a package manager")
|
||||||
@ -613,7 +618,7 @@ func isPackageManagerLockFilePresent(c *checker.CheckRequest) (int, error) {
|
|||||||
// validatePackageManagerFile will validate the if frozen dependecies file name exists.
|
// validatePackageManagerFile will validate the if frozen dependecies file name exists.
|
||||||
// TODO(laurent): need to differentiate between libraries and programs.
|
// TODO(laurent): need to differentiate between libraries and programs.
|
||||||
// TODO(laurent): handle multi-language repos.
|
// TODO(laurent): handle multi-language repos.
|
||||||
func validatePackageManagerFile(name string, dl checker.DetailLogger, data FileCbData) (bool, error) {
|
func validatePackageManagerFile(name string, dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
switch strings.ToLower(name) {
|
switch strings.ToLower(name) {
|
||||||
// TODO(laurent): "go.mod" is for libraries
|
// TODO(laurent): "go.mod" is for libraries
|
||||||
default:
|
default:
|
||||||
|
117
checks/raw/binary_artifact.go
Normal file
117
checks/raw/binary_artifact.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// Copyright 2021 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 raw
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/h2non/filetype"
|
||||||
|
"github.com/h2non/filetype/types"
|
||||||
|
|
||||||
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/fileparser"
|
||||||
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// File represents a file.
|
||||||
|
type File struct {
|
||||||
|
Path string
|
||||||
|
// TODO: add hash if needed.
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryArtifactData contains the raw results.
|
||||||
|
type BinaryArtifactData struct {
|
||||||
|
// Files contains a list of files.
|
||||||
|
Files []File
|
||||||
|
}
|
||||||
|
|
||||||
|
// BinaryArtifacts retrieves the raw data for the Binary-Artifacts check.
|
||||||
|
func BinaryArtifacts(c *checker.CheckRequest) (BinaryArtifactData, error) {
|
||||||
|
var files []File
|
||||||
|
err := fileparser.CheckFilesContentV6("*", false, c.RepoClient, checkBinaryFileContent, &files)
|
||||||
|
if err != nil {
|
||||||
|
return BinaryArtifactData{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// No error, return the files.
|
||||||
|
return BinaryArtifactData{Files: files}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkBinaryFileContent(path string, content []byte,
|
||||||
|
data fileparser.FileCbData) (bool, error) {
|
||||||
|
pfiles, ok := data.(*[]File)
|
||||||
|
if !ok {
|
||||||
|
// This never happens.
|
||||||
|
panic("invalid type")
|
||||||
|
}
|
||||||
|
|
||||||
|
binaryFileTypes := map[string]bool{
|
||||||
|
"crx": true,
|
||||||
|
"deb": true,
|
||||||
|
"dex": true,
|
||||||
|
"dey": true,
|
||||||
|
"elf": true,
|
||||||
|
"bin": true,
|
||||||
|
"o": true,
|
||||||
|
"so": true,
|
||||||
|
"iso": true,
|
||||||
|
"class": true,
|
||||||
|
"jar": true,
|
||||||
|
"bundle": true,
|
||||||
|
"dylib": true,
|
||||||
|
"lib": true,
|
||||||
|
"msi": true,
|
||||||
|
"acm": true,
|
||||||
|
"ax": true,
|
||||||
|
"cpl": true,
|
||||||
|
"dll": true,
|
||||||
|
"drv": true,
|
||||||
|
"efi": true,
|
||||||
|
"exe": true,
|
||||||
|
"mui": true,
|
||||||
|
"ocx": true,
|
||||||
|
"scr": true,
|
||||||
|
"sys": true,
|
||||||
|
"tsp": true,
|
||||||
|
"pyc": true,
|
||||||
|
"pyo": true,
|
||||||
|
"par": true,
|
||||||
|
"rpm": true,
|
||||||
|
"swf": true,
|
||||||
|
"torrent": true,
|
||||||
|
"cab": true,
|
||||||
|
"whl": true,
|
||||||
|
}
|
||||||
|
var t types.Type
|
||||||
|
var err error
|
||||||
|
if len(content) == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if t, err = filetype.Get(content); err != nil {
|
||||||
|
return false, sce.WithMessage(sce.ErrScorecardInternal, fmt.Sprintf("filetype.Get:%v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
exists1 := binaryFileTypes[t.Extension]
|
||||||
|
exists2 := binaryFileTypes[strings.ReplaceAll(filepath.Ext(path), ".", "")]
|
||||||
|
if exists1 || exists2 {
|
||||||
|
*pfiles = append(*pfiles, File{
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
@ -21,6 +21,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/ossf/scorecard/v3/checker"
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
|
"github.com/ossf/scorecard/v3/checks/fileparser"
|
||||||
"github.com/ossf/scorecard/v3/clients/githubrepo"
|
"github.com/ossf/scorecard/v3/clients/githubrepo"
|
||||||
sce "github.com/ossf/scorecard/v3/errors"
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
)
|
)
|
||||||
@ -39,8 +40,8 @@ func SecurityPolicy(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
var r bool
|
var r bool
|
||||||
// Check repository for repository-specific policy.
|
// Check repository for repository-specific policy.
|
||||||
// https://docs.github.com/en/github/building-a-strong-community/creating-a-default-community-health-file.
|
// https://docs.github.com/en/github/building-a-strong-community/creating-a-default-community-health-file.
|
||||||
onFile := func(name string, dl checker.DetailLogger, data FileCbData) (bool, error) {
|
onFile := func(name string, dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
pdata := FileGetCbDataAsBoolPointer(data)
|
pdata := fileparser.FileGetCbDataAsBoolPointer(data)
|
||||||
if strings.EqualFold(name, "security.md") ||
|
if strings.EqualFold(name, "security.md") ||
|
||||||
strings.EqualFold(name, ".github/security.md") ||
|
strings.EqualFold(name, ".github/security.md") ||
|
||||||
strings.EqualFold(name, "docs/security.md") {
|
strings.EqualFold(name, "docs/security.md") {
|
||||||
@ -66,7 +67,7 @@ func SecurityPolicy(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
err := CheckIfFileExists(CheckSecurityPolicy, c, onFile, &r)
|
err := fileparser.CheckIfFileExists(CheckSecurityPolicy, c, onFile, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return checker.CreateRuntimeErrorResult(CheckSecurityPolicy, err)
|
return checker.CreateRuntimeErrorResult(CheckSecurityPolicy, err)
|
||||||
}
|
}
|
||||||
@ -90,8 +91,8 @@ func SecurityPolicy(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
switch {
|
switch {
|
||||||
case err == nil:
|
case err == nil:
|
||||||
defer dotGitHub.RepoClient.Close()
|
defer dotGitHub.RepoClient.Close()
|
||||||
onFile = func(name string, dl checker.DetailLogger, data FileCbData) (bool, error) {
|
onFile = func(name string, dl checker.DetailLogger, data fileparser.FileCbData) (bool, error) {
|
||||||
pdata := FileGetCbDataAsBoolPointer(data)
|
pdata := fileparser.FileGetCbDataAsBoolPointer(data)
|
||||||
if strings.EqualFold(name, "security.md") ||
|
if strings.EqualFold(name, "security.md") ||
|
||||||
strings.EqualFold(name, ".github/security.md") ||
|
strings.EqualFold(name, ".github/security.md") ||
|
||||||
strings.EqualFold(name, "docs/security.md") {
|
strings.EqualFold(name, "docs/security.md") {
|
||||||
@ -107,7 +108,7 @@ func SecurityPolicy(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
err = CheckIfFileExists(CheckSecurityPolicy, dotGitHub, onFile, &r)
|
err = fileparser.CheckIfFileExists(CheckSecurityPolicy, dotGitHub, onFile, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return checker.CreateRuntimeErrorResult(CheckSecurityPolicy, err)
|
return checker.CreateRuntimeErrorResult(CheckSecurityPolicy, err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user