From dc8d1fecb95a4a7b53ead526ee3abbda91f8366f Mon Sep 17 00:00:00 2001 From: Abhishek Arya Date: Fri, 15 Jan 2021 08:29:07 -0800 Subject: [PATCH] Add packaging check. --- README.md | 26 +++++----- checks/packaging.go | 113 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 checks/packaging.go diff --git a/README.md b/README.md index e68638d3..ba9f57de 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Starting [Code-Review] Starting [Contributors] Starting [Frozen-Deps] Starting [Fuzzing] +Starting [Packaging] Starting [Pull-Requests] Starting [SAST] Starting [Security-Policy] @@ -61,33 +62,35 @@ Starting [Signed-Releases] Starting [Signed-Tags] Finished [Fuzzing] Finished [CII-Best-Practices] -Finished [Frozen-Deps] -Finished [Security-Policy] -Finished [Contributors] -Finished [Signed-Releases] Finished [Branch-Protection] +Finished [Packaging] +Finished [Security-Policy] +Finished [Frozen-Deps] Finished [Signed-Tags] -Finished [CI-Tests] +Finished [Signed-Releases] Finished [SAST] -Finished [Code-Review] -Finished [Pull-Requests] +Finished [CI-Tests] Finished [Active] +Finished [Contributors] +Finished [Pull-Requests] +Finished [Code-Review] RESULTS ------- Active: Pass 10 -Branch-Protection: Fail 5 +Branch-Protection: Fail 10 CI-Tests: Pass 10 CII-Best-Practices: Pass 10 Code-Review: Pass 10 Contributors: Pass 10 Frozen-Deps: Pass 10 Fuzzing: Pass 10 +Packaging: Fail 0 Pull-Requests: Pass 10 -SAST: Fail 0 +SAST: Fail 10 Security-Policy: Pass 10 Signed-Releases: Fail 10 -Signed-Tags: Fail 5 +Signed-Tags: Fail 10 ``` ### Authentication @@ -142,7 +145,8 @@ The following checks are all run against the target project: | Fuzzing | Does the project use fuzzing tools, e.g. [OSS-Fuzz](https://github.com/google/oss-fuzz)? | | SAST | Does the project use static code analysis tools, e.g. [CodeQL](https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/enabling-code-scanning-for-a-repository#enabling-code-scanning-using-actions), [SonarCloud](https://sonarcloud.io)? | | Active | Did the project get any commits in the last 90 days? | -| Branch-Protection | Does the project use [Branch Protection](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/about-protected-branches) ? | +| Branch-Protection | Does the project use [Branch Protection](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/about-protected-branches) ? | +| Packaging | Does the project build and publish official packages from CI/CD, e.g. [GitHub Publishing](https://docs.github.com/en/free-pro-team@latest/actions/guides/about-packaging-with-github-actions#workflows-for-publishing-packages) ? To see detailed information on how each check works, see the [check-specific documentation page](checks.md). diff --git a/checks/packaging.go b/checks/packaging.go new file mode 100644 index 00000000..04aaf2d9 --- /dev/null +++ b/checks/packaging.go @@ -0,0 +1,113 @@ +// Copyright 2020 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 checks + +import ( + "path/filepath" + "regexp" + "strings" + + "github.com/google/go-github/v32/github" + "github.com/ossf/scorecard/checker" +) + +func init() { + registerCheck("Packaging", Packaging) +} + +func Packaging(c checker.Checker) checker.CheckResult { + _, dc, _, err := c.Client.Repositories.GetContents(c.Ctx, c.Owner, c.Repo, ".github/workflows", &github.RepositoryContentGetOptions{}) + if err != nil { + return checker.RetryResult(err) + } + + for _, f := range dc { + fp := f.GetPath() + fo, _, _, err := c.Client.Repositories.GetContents(c.Ctx, c.Owner, c.Repo, fp, &github.RepositoryContentGetOptions{}) + if err != nil { + return checker.RetryResult(err) + } + fc, err := fo.GetContent() + if err != nil { + return checker.RetryResult(err) + } + + if !isPackagingWorkflow(fc, fp, c) { + continue + } + + runs, _, err := c.Client.Actions.ListWorkflowRunsByFileName(c.Ctx, c.Owner, c.Repo, filepath.Base(fp), &github.ListWorkflowRunsOptions{ + Status: "success", + }) + if err != nil { + return checker.RetryResult(err) + } + if *runs.TotalCount > 0 { + c.Logf("found a completed run: %s", runs.WorkflowRuns[0].GetHTMLURL()) + return checker.CheckResult{ + Pass: true, + Confidence: 10, + } + } + c.Logf("!! no run completed") + } + + return checker.CheckResult{ + Pass: false, + Confidence: 10, + } +} + +func isPackagingWorkflow(s string, fp string, c checker.Checker) bool { + // nodejs packages + if strings.Contains(s, "uses: actions/setup-node@") { + r1, _ := regexp.Compile("(?s)registry-url.*https://registry.npmjs.org") + r2, _ := regexp.Compile("(?s)npm.*publish") + + if r1.MatchString(s) && r2.MatchString(s) { + c.Logf("found node packaging workflow using npm: %s", fp) + return true + } + } + + if strings.Contains(s, "uses: actions/setup-java@") { + // java packages with maven + r1, _ := regexp.Compile("(?s)mvn.*deploy") + if r1.MatchString(s) { + c.Logf("found java packaging workflow using maven: %s", fp) + return true + } + + // java packages with gradle + r2, _ := regexp.Compile("(?s)gradle.*publish") + if r2.MatchString(s) { + c.Logf("found java packaging workflow using gradle: %s", fp) + return true + } + } + + if strings.Contains(s, "actions/setup-python@") && strings.Contains(s, "pypa/gh-action-pypi-publish@master") { + c.Logf("found python packaging workflow using pypi: %s", fp) + return true + } + + if strings.Contains(s, "uses: docker/build-push-action@") { + c.Logf("found docker publishing workflow: %s", fp) + return true + } + + c.Logf("!! not a packaging workflow: %s", fp) + return false +}