mirror of
https://github.com/ossf/scorecard.git
synced 2024-09-17 11:57:12 +03:00
Adding line numbers for rest of Token-Permessions (and by extension, (#1381)
Packaging)
This commit is contained in:
parent
ca97581538
commit
f991fee32d
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"github.com/rhysd/actionlint"
|
"github.com/rhysd/actionlint"
|
||||||
|
|
||||||
|
"github.com/ossf/scorecard/v3/checker"
|
||||||
sce "github.com/ossf/scorecard/v3/errors"
|
sce "github.com/ossf/scorecard/v3/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,6 +60,59 @@ func IsStepExecKind(step *actionlint.Step, kind actionlint.ExecKind) bool {
|
|||||||
return step.Exec.Kind() == kind
|
return step.Exec.Kind() == kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLineNumber returns the line number for this position.
|
||||||
|
func GetLineNumber(pos *actionlint.Pos) int {
|
||||||
|
if pos == nil {
|
||||||
|
return checker.OffsetDefault
|
||||||
|
}
|
||||||
|
return pos.Line
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUses returns the 'uses' statement in this step or nil if this step does not have one.
|
||||||
|
func GetUses(step *actionlint.Step) *actionlint.String {
|
||||||
|
if step == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !IsStepExecKind(step, actionlint.ExecKindAction) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
execAction, ok := step.Exec.(*actionlint.ExecAction)
|
||||||
|
if !ok || execAction == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return execAction.Uses
|
||||||
|
}
|
||||||
|
|
||||||
|
// getWith returns the 'with' statement in this step or nil if this step does not have one.
|
||||||
|
func getWith(step *actionlint.Step) map[string]*actionlint.Input {
|
||||||
|
if step == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !IsStepExecKind(step, actionlint.ExecKindAction) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
execAction, ok := step.Exec.(*actionlint.ExecAction)
|
||||||
|
if !ok || execAction == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return execAction.Inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRun returns the 'run' statement in this step or nil if this step does not have one.
|
||||||
|
func getRun(step *actionlint.Step) *actionlint.String {
|
||||||
|
if step == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !IsStepExecKind(step, actionlint.ExecKindRun) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
execAction, ok := step.Exec.(*actionlint.ExecRun)
|
||||||
|
if !ok || execAction == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return execAction.Run
|
||||||
|
}
|
||||||
|
|
||||||
func getExecRunShell(execRun *actionlint.ExecRun) string {
|
func getExecRunShell(execRun *actionlint.ExecRun) string {
|
||||||
if execRun != nil && execRun.Shell != nil {
|
if execRun != nil && execRun.Shell != nil {
|
||||||
return execRun.Shell.Value
|
return execRun.Shell.Value
|
||||||
@ -250,3 +304,80 @@ func IsGitHubOwnedAction(actionName string) bool {
|
|||||||
c := strings.HasPrefix(actionName, "github/")
|
c := strings.HasPrefix(actionName, "github/")
|
||||||
return a || c
|
return a || c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JobMatcher is rule for matching a job.
|
||||||
|
type JobMatcher struct {
|
||||||
|
// The text to be logged when a job match is found.
|
||||||
|
LogText string
|
||||||
|
// Each step in this field has a matching step in the job.
|
||||||
|
Steps []*JobMatcherStep
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobMatcherStep is a single step that needs to be matched.
|
||||||
|
type JobMatcherStep struct {
|
||||||
|
// If set, the step's 'Uses' must match this field. Checks that the action name is the same.
|
||||||
|
Uses string
|
||||||
|
// If set, the step's 'With' have the keys and values that are in this field.
|
||||||
|
With map[string]string
|
||||||
|
// If set, the step's 'Run' must match this field. Does a regex match using this field.
|
||||||
|
Run string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches returns true if the job matches the job matcher.
|
||||||
|
func (m *JobMatcher) Matches(job *actionlint.Job) bool {
|
||||||
|
for _, stepToMatch := range m.Steps {
|
||||||
|
hasMatch := false
|
||||||
|
for _, step := range job.Steps {
|
||||||
|
if stepsMatch(stepToMatch, step) {
|
||||||
|
hasMatch = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasMatch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// stepsMatch returns true if the fields on 'stepToMatch' match what's in 'step'.
|
||||||
|
func stepsMatch(stepToMatch *JobMatcherStep, step *actionlint.Step) bool {
|
||||||
|
// Make sure 'uses' matches if present.
|
||||||
|
if stepToMatch.Uses != "" {
|
||||||
|
uses := GetUses(step)
|
||||||
|
if uses == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(uses.Value, stepToMatch.Uses+"@") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure 'with' matches if present.
|
||||||
|
if len(stepToMatch.With) > 0 {
|
||||||
|
with := getWith(step)
|
||||||
|
if with == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for keyToMatch, valToMatch := range stepToMatch.With {
|
||||||
|
input, ok := with[keyToMatch]
|
||||||
|
if !ok || input == nil || input.Value == nil || input.Value.Value != valToMatch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure 'run' matches if present.
|
||||||
|
if stepToMatch.Run != "" {
|
||||||
|
run := getRun(step)
|
||||||
|
if run == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
r := regexp.MustCompile(stepToMatch.Run)
|
||||||
|
if !r.MatchString(run.Value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
@ -17,10 +17,12 @@ package checks
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rhysd/actionlint"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,7 +53,12 @@ func Packaging(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
return checker.CreateRuntimeErrorResult(CheckPackaging, e)
|
return checker.CreateRuntimeErrorResult(CheckPackaging, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPackagingWorkflow(string(fc), fp, c.Dlogger) {
|
workflow, errs := actionlint.Parse(fc)
|
||||||
|
if len(errs) > 0 && workflow == nil {
|
||||||
|
e := fileparser.FormatActionlintError(errs)
|
||||||
|
return checker.CreateRuntimeErrorResult(CheckPackaging, e)
|
||||||
|
}
|
||||||
|
if !isPackagingWorkflow(workflow, fp, c.Dlogger) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,147 +94,135 @@ func Packaging(c *checker.CheckRequest) checker.CheckResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A packaging workflow.
|
// A packaging workflow.
|
||||||
func isPackagingWorkflow(s, fp string, dl checker.DetailLogger) bool {
|
func isPackagingWorkflow(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) bool {
|
||||||
// Nodejs packages.
|
jobMatchers := []fileparser.JobMatcher{
|
||||||
if strings.Contains(s, "actions/setup-node@") {
|
{
|
||||||
r1 := regexp.MustCompile(`(?s)registry-url.*https://registry\.npmjs\.org`)
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
r2 := regexp.MustCompile(`(?s)npm.*publish`)
|
{
|
||||||
|
Uses: "actions/setup-node",
|
||||||
|
With: map[string]string{"registry-url": "https://registry.npmjs.org"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Run: "npm.*publish",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate node publishing workflow using npm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Java packages with maven.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Uses: "actions/setup-java",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Run: "mvn.*deploy",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate java publishing workflow using maven",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Java packages with gradle.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Uses: "actions/setup-java",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Run: "gradle.*publish",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate java publishing workflow using gradle",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Ruby packages.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Run: "gem.*push",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate ruby publishing workflow using gem",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// NuGet packages.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Run: "nuget.*push",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate nuget publishing workflow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Docker packages.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Run: "docker.*push",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate docker publishing workflow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Docker packages.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Uses: "docker/build-push-action",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate docker publishing workflow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Python packages.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Uses: "actions/setup-python",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Uses: "pypa/gh-action-pypi-publish",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate python publishing workflow using pypi",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Go packages.
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Uses: "actions/setup-go",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Uses: "goreleaser/goreleaser-action",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate golang publishing workflow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Rust packages. https://doc.rust-lang.org/cargo/reference/publishing.html
|
||||||
|
Steps: []*fileparser.JobMatcherStep{
|
||||||
|
{
|
||||||
|
Run: "cargo.*publish",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
LogText: "candidate rust publishing workflow using cargo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, job := range workflow.Jobs {
|
||||||
|
for _, matcher := range jobMatchers {
|
||||||
|
if !matcher.Matches(job) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if r1.MatchString(s) && r2.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
dl.Info3(&checker.LogMessage{
|
||||||
Path: fp,
|
Path: fp,
|
||||||
Type: checker.FileTypeSource,
|
Type: checker.FileTypeSource,
|
||||||
// Source file must have line number > 0.
|
Offset: fileparser.GetLineNumber(job.Pos),
|
||||||
Offset: 1,
|
Text: matcher.LogText,
|
||||||
Text: "candidate node publishing workflow using npm",
|
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Java packages.
|
|
||||||
if strings.Contains(s, "actions/setup-java@") {
|
|
||||||
// Java packages with maven.
|
|
||||||
r1 := regexp.MustCompile(`(?s)mvn.*deploy`)
|
|
||||||
if r1.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate java publishing workflow using maven",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Java packages with gradle.
|
|
||||||
r2 := regexp.MustCompile(`(?s)gradle.*publish`)
|
|
||||||
if r2.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate java publishing workflow using gradle",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ruby packages.
|
|
||||||
r := regexp.MustCompile(`(?s)gem.*push`)
|
|
||||||
if r.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate ruby publishing workflow using gem",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// NuGet packages.
|
|
||||||
r = regexp.MustCompile(`(?s)nuget.*push`)
|
|
||||||
if r.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate nuget publishing workflow",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Docker packages.
|
|
||||||
if strings.Contains(s, "docker/build-push-action@") {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate docker publishing workflow",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
r = regexp.MustCompile(`(?s)docker.*push`)
|
|
||||||
if r.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate docker publishing workflow",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Python packages.
|
|
||||||
if strings.Contains(s, "actions/setup-python@") && strings.Contains(s, "pypa/gh-action-pypi-publish@master") {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate python publishing workflow using pypi",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go packages.
|
|
||||||
if strings.Contains(s, "actions/setup-go") &&
|
|
||||||
strings.Contains(s, "goreleaser/goreleaser-action@") {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate golang publishing workflow",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rust packages.
|
|
||||||
// https://doc.rust-lang.org/cargo/reference/publishing.html.
|
|
||||||
r = regexp.MustCompile(`(?s)cargo.*publish`)
|
|
||||||
if r.MatchString(s) {
|
|
||||||
dl.Info3(&checker.LogMessage{
|
|
||||||
Path: fp,
|
|
||||||
Type: checker.FileTypeSource,
|
|
||||||
// Source file must have line number > 0.
|
|
||||||
Offset: 1,
|
|
||||||
Text: "candidate rust publishing workflow using cargo",
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
dl.Debug3(&checker.LogMessage{
|
dl.Debug3(&checker.LogMessage{
|
||||||
Path: fp,
|
Path: fp,
|
||||||
Type: checker.FileTypeSource,
|
Type: checker.FileTypeSource,
|
||||||
// Source file must have line number > 0.
|
Offset: checker.OffsetDefault,
|
||||||
Offset: 1,
|
|
||||||
Text: "not a publishing workflow",
|
Text: "not a publishing workflow",
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
|
110
checks/packaging_test.go
Normal file
110
checks/packaging_test.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// 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 checks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rhysd/actionlint"
|
||||||
|
|
||||||
|
scut "github.com/ossf/scorecard/v3/utests"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsPackagingWorkflow(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
filename string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "npmjs.org publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-npm.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "npm github publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-npm-github.yaml",
|
||||||
|
expected: false, // Should this be false?
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "maven publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-maven.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gradle publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-gradle.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gem publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-gem.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nuget publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-nuget.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "docker action publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-docker-action.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "docker push publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-docker-push.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pypi publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-pypi.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "go publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-go.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "cargo publish",
|
||||||
|
filename: "./testdata/github-workflow-packaging-cargo.yaml",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt // Re-initializing variable so it is not changed while executing the closure below
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
content, err := os.ReadFile(tt.filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot read file: %w", err))
|
||||||
|
}
|
||||||
|
workflow, errs := actionlint.Parse(content)
|
||||||
|
if len(errs) > 0 && workflow == nil {
|
||||||
|
panic(fmt.Errorf("cannot parse file: %w", err))
|
||||||
|
}
|
||||||
|
dl := scut.TestDetailLogger{}
|
||||||
|
result := isPackagingWorkflow(workflow, tt.filename, &dl)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("isPackagingWorkflow() = %v, expected %v", result, tt.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -64,10 +64,7 @@ func validatePermission(permissionKey string, permissionValue *actionlint.Permis
|
|||||||
return sce.WithMessage(sce.ErrScorecardInternal, errInvalidGitHubWorkflow.Error())
|
return sce.WithMessage(sce.ErrScorecardInternal, errInvalidGitHubWorkflow.Error())
|
||||||
}
|
}
|
||||||
val := permissionValue.Value.Value
|
val := permissionValue.Value.Value
|
||||||
lineNumber := checker.OffsetDefault
|
lineNumber := fileparser.GetLineNumber(permissionValue.Value.Pos)
|
||||||
if permissionValue.Value.Pos != nil {
|
|
||||||
lineNumber = permissionValue.Value.Pos.Line
|
|
||||||
}
|
|
||||||
if strings.EqualFold(val, "write") {
|
if strings.EqualFold(val, "write") {
|
||||||
if isPermissionOfInterest(permissionKey, ignoredPermissions) {
|
if isPermissionOfInterest(permissionKey, ignoredPermissions) {
|
||||||
dl.Warn3(&checker.LogMessage{
|
dl.Warn3(&checker.LogMessage{
|
||||||
@ -138,11 +135,7 @@ func validatePermissions(permissions *actionlint.Permissions, permLevel, path st
|
|||||||
}
|
}
|
||||||
if allIsSet {
|
if allIsSet {
|
||||||
val := permissions.All.Value
|
val := permissions.All.Value
|
||||||
lineNumber := checker.OffsetDefault
|
lineNumber := fileparser.GetLineNumber(permissions.All.Pos)
|
||||||
if permissions.All.Pos != nil {
|
|
||||||
lineNumber = permissions.All.Pos.Line
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.EqualFold(val, "read-all") && val != "" {
|
if !strings.EqualFold(val, "read-all") && val != "" {
|
||||||
dl.Warn3(&checker.LogMessage{
|
dl.Warn3(&checker.LogMessage{
|
||||||
Path: path,
|
Path: path,
|
||||||
@ -195,14 +188,10 @@ func validateRunLevelPermissions(workflow *actionlint.Workflow, path string,
|
|||||||
// For most workflows, no write permissions are needed,
|
// For most workflows, no write permissions are needed,
|
||||||
// so only top-level read-only permissions need to be declared.
|
// so only top-level read-only permissions need to be declared.
|
||||||
if job.Permissions == nil {
|
if job.Permissions == nil {
|
||||||
lineNumber := checker.OffsetDefault
|
|
||||||
if job.Pos != nil {
|
|
||||||
lineNumber = job.Pos.Line
|
|
||||||
}
|
|
||||||
dl.Debug3(&checker.LogMessage{
|
dl.Debug3(&checker.LogMessage{
|
||||||
Path: path,
|
Path: path,
|
||||||
Type: checker.FileTypeSource,
|
Type: checker.FileTypeSource,
|
||||||
Offset: lineNumber,
|
Offset: fileparser.GetLineNumber(job.Pos),
|
||||||
Text: fmt.Sprintf("no %s permission defined", runLevelPermission),
|
Text: fmt.Sprintf("no %s permission defined", runLevelPermission),
|
||||||
})
|
})
|
||||||
recordAllPermissionsWrite(pdata.runLevelWritePermissions)
|
recordAllPermissionsWrite(pdata.runLevelWritePermissions)
|
||||||
@ -385,7 +374,7 @@ func validateGitHubActionTokenPermissions(path string, content []byte,
|
|||||||
|
|
||||||
// 2. Run-level permission definitions,
|
// 2. Run-level permission definitions,
|
||||||
// see https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idpermissions.
|
// see https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idpermissions.
|
||||||
ignoredPermissions := createIgnoredPermissions(string(content), path, dl)
|
ignoredPermissions := createIgnoredPermissions(workflow, path, dl)
|
||||||
if err := validateRunLevelPermissions(workflow, path, dl, pdata, ignoredPermissions); err != nil {
|
if err := validateRunLevelPermissions(workflow, path, dl, pdata, ignoredPermissions); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -397,15 +386,15 @@ func validateGitHubActionTokenPermissions(path string, content []byte,
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createIgnoredPermissions(s, fp string, dl checker.DetailLogger) map[string]bool {
|
func createIgnoredPermissions(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) map[string]bool {
|
||||||
ignoredPermissions := make(map[string]bool)
|
ignoredPermissions := make(map[string]bool)
|
||||||
if requiresPackagesPermissions(s, fp, dl) {
|
if requiresPackagesPermissions(workflow, fp, dl) {
|
||||||
ignoredPermissions["packages"] = true
|
ignoredPermissions["packages"] = true
|
||||||
}
|
}
|
||||||
if requiresContentsPermissions(s, fp, dl) {
|
if requiresContentsPermissions(workflow, fp, dl) {
|
||||||
ignoredPermissions["contents"] = true
|
ignoredPermissions["contents"] = true
|
||||||
}
|
}
|
||||||
if isSARIFUploadWorkflow(s, fp, dl) {
|
if isSARIFUploadWorkflow(workflow, fp, dl) {
|
||||||
ignoredPermissions["security-events"] = true
|
ignoredPermissions["security-events"] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,12 +402,12 @@ func createIgnoredPermissions(s, fp string, dl checker.DetailLogger) map[string]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scanning tool run externally and SARIF file uploaded.
|
// Scanning tool run externally and SARIF file uploaded.
|
||||||
func isSARIFUploadWorkflow(s, fp string, dl checker.DetailLogger) bool {
|
func isSARIFUploadWorkflow(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) bool {
|
||||||
//nolint
|
//nolint
|
||||||
// CodeQl analysis workflow automatically sends sarif file to GitHub.
|
// CodeQl analysis workflow automatically sends sarif file to GitHub.
|
||||||
// https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github#about-sarif-file-uploads-for-code-scanning.
|
// https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github#about-sarif-file-uploads-for-code-scanning.
|
||||||
// `The CodeQL action uploads the SARIF file automatically when it completes analysis`.
|
// `The CodeQL action uploads the SARIF file automatically when it completes analysis`.
|
||||||
if isCodeQlAnalysisWorkflow(s, fp, dl) {
|
if isCodeQlAnalysisWorkflow(workflow, fp, dl) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,7 +415,7 @@ func isSARIFUploadWorkflow(s, fp string, dl checker.DetailLogger) bool {
|
|||||||
// Third-party scanning tools use the SARIF-upload action from code-ql.
|
// Third-party scanning tools use the SARIF-upload action from code-ql.
|
||||||
// https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github#uploading-a-code-scanning-analysis-with-github-actions
|
// https://docs.github.com/en/code-security/secure-coding/integrating-with-code-scanning/uploading-a-sarif-file-to-github#uploading-a-code-scanning-analysis-with-github-actions
|
||||||
// We only support CodeQl today.
|
// We only support CodeQl today.
|
||||||
if isSARIFUploadAction(s, fp, dl) {
|
if isSARIFUploadAction(workflow, fp, dl) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,22 +427,29 @@ func isSARIFUploadWorkflow(s, fp string, dl checker.DetailLogger) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CodeQl run externally and SARIF file uploaded.
|
// CodeQl run externally and SARIF file uploaded.
|
||||||
func isSARIFUploadAction(s, fp string, dl checker.DetailLogger) bool {
|
func isSARIFUploadAction(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) bool {
|
||||||
if strings.Contains(s, "github/codeql-action/upload-sarif@") {
|
for _, job := range workflow.Jobs {
|
||||||
dl.Debug3(&checker.LogMessage{
|
for _, step := range job.Steps {
|
||||||
Path: fp,
|
uses := fileparser.GetUses(step)
|
||||||
Type: checker.FileTypeSource,
|
if uses == nil {
|
||||||
// TODO: set line.
|
continue
|
||||||
Offset: 1,
|
}
|
||||||
Text: "codeql SARIF upload workflow detected",
|
if strings.HasPrefix(uses.Value, "github/codeql-action/upload-sarif@") {
|
||||||
// TODO: set Snippet.
|
dl.Debug3(&checker.LogMessage{
|
||||||
})
|
Path: fp,
|
||||||
return true
|
Type: checker.FileTypeSource,
|
||||||
|
Offset: fileparser.GetLineNumber(uses.Pos),
|
||||||
|
Text: "codeql SARIF upload workflow detected",
|
||||||
|
// TODO: set Snippet.
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dl.Debug3(&checker.LogMessage{
|
dl.Debug3(&checker.LogMessage{
|
||||||
Path: fp,
|
Path: fp,
|
||||||
Type: checker.FileTypeSource,
|
Type: checker.FileTypeSource,
|
||||||
Offset: 1,
|
Offset: checker.OffsetDefault,
|
||||||
Text: "not a codeql upload SARIF workflow",
|
Text: "not a codeql upload SARIF workflow",
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
@ -463,22 +459,29 @@ func isSARIFUploadAction(s, fp string, dl checker.DetailLogger) bool {
|
|||||||
// CodeQl run within GitHub worklow automatically bubbled up to
|
// CodeQl run within GitHub worklow automatically bubbled up to
|
||||||
// security events, see
|
// security events, see
|
||||||
// https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning.
|
// https://docs.github.com/en/code-security/secure-coding/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning.
|
||||||
func isCodeQlAnalysisWorkflow(s, fp string, dl checker.DetailLogger) bool {
|
func isCodeQlAnalysisWorkflow(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) bool {
|
||||||
if strings.Contains(s, "github/codeql-action/analyze@") {
|
for _, job := range workflow.Jobs {
|
||||||
dl.Debug3(&checker.LogMessage{
|
for _, step := range job.Steps {
|
||||||
Path: fp,
|
uses := fileparser.GetUses(step)
|
||||||
Type: checker.FileTypeSource,
|
if uses == nil {
|
||||||
// TODO: set line.
|
continue
|
||||||
Offset: 1,
|
}
|
||||||
Text: "codeql workflow detected",
|
if strings.HasPrefix(uses.Value, "github/codeql-action/analyze@") {
|
||||||
// TODO: set Snippet.
|
dl.Debug3(&checker.LogMessage{
|
||||||
})
|
Path: fp,
|
||||||
return true
|
Type: checker.FileTypeSource,
|
||||||
|
Offset: fileparser.GetLineNumber(uses.Pos),
|
||||||
|
Text: "codeql workflow detected",
|
||||||
|
// TODO: set Snippet.
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dl.Debug3(&checker.LogMessage{
|
dl.Debug3(&checker.LogMessage{
|
||||||
Path: fp,
|
Path: fp,
|
||||||
Type: checker.FileTypeSource,
|
Type: checker.FileTypeSource,
|
||||||
Offset: 1,
|
Offset: checker.OffsetDefault,
|
||||||
Text: "not a codeql workflow",
|
Text: "not a codeql workflow",
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
@ -486,19 +489,19 @@ func isCodeQlAnalysisWorkflow(s, fp string, dl checker.DetailLogger) bool {
|
|||||||
|
|
||||||
// A packaging workflow using GitHub's supported packages:
|
// A packaging workflow using GitHub's supported packages:
|
||||||
// https://docs.github.com/en/packages.
|
// https://docs.github.com/en/packages.
|
||||||
func requiresPackagesPermissions(s, fp string, dl checker.DetailLogger) bool {
|
func requiresPackagesPermissions(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) bool {
|
||||||
// TODO: add support for GitHub registries.
|
// TODO: add support for GitHub registries.
|
||||||
// Example: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry.
|
// Example: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry.
|
||||||
// This feature requires parsing actions properly.
|
// This feature requires parsing actions properly.
|
||||||
// For now, we just re-use the Packaging check to verify that the
|
// For now, we just re-use the Packaging check to verify that the
|
||||||
// workflow is a packaging workflow.
|
// workflow is a packaging workflow.
|
||||||
return isPackagingWorkflow(s, fp, dl)
|
return isPackagingWorkflow(workflow, fp, dl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this needs to be improved.
|
// Note: this needs to be improved.
|
||||||
// Currently we don't differentiate between publishing on GitHub vs
|
// Currently we don't differentiate between publishing on GitHub vs
|
||||||
// pubishing on registries. In terms of risk, both are similar, as
|
// pubishing on registries. In terms of risk, both are similar, as
|
||||||
// an attacker would gain the ability to push a package.
|
// an attacker would gain the ability to push a package.
|
||||||
func requiresContentsPermissions(s, fp string, dl checker.DetailLogger) bool {
|
func requiresContentsPermissions(workflow *actionlint.Workflow, fp string, dl checker.DetailLogger) bool {
|
||||||
return requiresPackagesPermissions(s, fp, dl)
|
return requiresPackagesPermissions(workflow, fp, dl)
|
||||||
}
|
}
|
||||||
|
@ -274,6 +274,17 @@ func TestGithubTokenPermissions(t *testing.T) {
|
|||||||
NumberOfDebug: 4,
|
NumberOfDebug: 4,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "security-events write, codeql comment",
|
||||||
|
filename: "./testdata/github-workflow-permissions-run-write-codeql-comment.yaml",
|
||||||
|
expected: scut.TestReturn{
|
||||||
|
Error: nil,
|
||||||
|
Score: checker.MaxResultScore - 1,
|
||||||
|
NumberOfWarn: 1,
|
||||||
|
NumberOfInfo: 1,
|
||||||
|
NumberOfDebug: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
tt := tt // Re-initializing variable so it is not changed while executing the closure below
|
tt := tt // Re-initializing variable so it is not changed while executing the closure below
|
||||||
|
20
checks/testdata/github-workflow-packaging-cargo.yaml
vendored
Normal file
20
checks/testdata/github-workflow-packaging-cargo.yaml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: cargo publish
|
23
checks/testdata/github-workflow-packaging-docker-action.yaml
vendored
Normal file
23
checks/testdata/github-workflow-packaging-docker-action.yaml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
tags: user/app:latest
|
20
checks/testdata/github-workflow-packaging-docker-push.yaml
vendored
Normal file
20
checks/testdata/github-workflow-packaging-docker-push.yaml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: docker push myapp/myimage:latest
|
20
checks/testdata/github-workflow-packaging-gem.yaml
vendored
Normal file
20
checks/testdata/github-workflow-packaging-gem.yaml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: gem push *.gem
|
31
checks/testdata/github-workflow-packaging-go.yaml
vendored
Normal file
31
checks/testdata/github-workflow-packaging-go.yaml
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.17
|
||||||
|
- uses: goreleaser/goreleaser-action@v2
|
||||||
|
with:
|
||||||
|
distribution: goreleaser
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
21
checks/testdata/github-workflow-packaging-gradle.yaml
vendored
Normal file
21
checks/testdata/github-workflow-packaging-gradle.yaml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
- run: gradle publish
|
21
checks/testdata/github-workflow-packaging-maven.yaml
vendored
Normal file
21
checks/testdata/github-workflow-packaging-maven.yaml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
- run: mvn deploy
|
25
checks/testdata/github-workflow-packaging-npm-github.yaml
vendored
Normal file
25
checks/testdata/github-workflow-packaging-npm-github.yaml
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
registry-url: 'https://npm.pkg.github.com'
|
||||||
|
- run: npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
34
checks/testdata/github-workflow-packaging-npm.yaml
vendored
Normal file
34
checks/testdata/github-workflow-packaging-npm.yaml
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14.x'
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
- run: npm install
|
||||||
|
- run: npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
registry-url: 'https://npm.pkg.github.com'
|
||||||
|
- run: npm publish
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
20
checks/testdata/github-workflow-packaging-nuget.yaml
vendored
Normal file
20
checks/testdata/github-workflow-packaging-nuget.yaml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- run: nuget push **\*.nupkg -Source 'https://nuget.pkg.github.com/MyOrg/index.json' -ApiKey ${{secrets.NUGET_TOKEN}}
|
26
checks/testdata/github-workflow-packaging-pypi.yaml
vendored
Normal file
26
checks/testdata/github-workflow-packaging-pypi.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-python@v1
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
with:
|
||||||
|
user: __token__
|
||||||
|
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
@ -22,5 +22,4 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- name: some name
|
- name: some name
|
||||||
run: echo "write-and-read workflow"
|
|
||||||
uses: docker/build-push-action@1.2.3
|
uses: docker/build-push-action@1.2.3
|
27
checks/testdata/github-workflow-permissions-run-write-codeql-comment.yaml
vendored
Normal file
27
checks/testdata/github-workflow-permissions-run-write-codeql-comment.yaml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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.
|
||||||
|
name: write-and-read workflow
|
||||||
|
on: [push]
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Explore-GitHub-Actions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
security-events: write
|
||||||
|
steps:
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/some-action/analyze@v1
|
||||||
|
run: echo "write-and-read workflow"
|
||||||
|
# Some comment about github/codeql-action/analyze@v1
|
Loading…
Reference in New Issue
Block a user