diff --git a/main.go b/main.go index de603086..7ae6721c 100644 --- a/main.go +++ b/main.go @@ -15,11 +15,33 @@ package main import ( "encoding/json" + "errors" "fmt" "io/ioutil" + "net/http" "os" + "strconv" ) +var ( + errInputResultFileNotSet = errors.New("INPUT_RESULTS_FILE is not set") + errInputResultFileEmpty = errors.New("INPUT_RESULTS_FILE is empty") + errInputResultFormatNotSet = errors.New("INPUT_RESULTS_FORMAT is not set") + errInputResultFormatEmtpy = errors.New("INPUT_RESULTS_FORMAT is empty") + errInputPublishResultsNotSet = errors.New("INPUT_PUBLISH_RESULTS is not set") + errInputPublishResultsEmpty = errors.New("INPUT_PUBLISH_RESULTS is empty") + errRequiredENVNotSet = errors.New("required environment variables are not set") + errGitHubEventPath = errors.New("error getting GITHUB_EVENT_PATH") + errGitHubEventPathEmpty = errors.New("GITHUB_EVENT_PATH is empty") + errGitHubEventPathNotSet = errors.New("GITHUB_EVENT_PATH is not set") + errEmptyDefaultBranch = errors.New("default branch is empty") +) + +type repositoryInformation struct { + DefaultBranch string `json:"default_branch"` + Private bool `json:"private"` +} + // main is the entrypoint for the action. func main() { // TODO - This is a port of the entrypoint.sh script. @@ -27,6 +49,25 @@ func main() { if err := initalizeENVVariables(); err != nil { panic(err) } + if err := checkIfRequiredENVSet(); err != nil { + panic(err) + } + + repository := os.Getenv("GITHUB_REPOSITORY") + token := os.Getenv("GITHUB_AUTH_TOKEN") + + repo, err := getRepositoryInformation(repository, token) + if err != nil { + panic(err) + } + + if err := updateRepoistoryInformation(repo.Private, repo.DefaultBranch); err != nil { + panic(err) + } + + if err := updateEnvVariables(); err != nil { + panic(err) + } } // initalizeENVVariables is a function to initialize the environment variables required for the action. @@ -40,104 +81,98 @@ func initalizeENVVariables() error { GITHUB_EVENT_NAME contains the event name. GITHUB_ACTIONS is true in GitHub env. */ - if err := os.Setenv("ENABLE_SARIF", "1"); err != nil { - return err - } - if err := os.Setenv("ENABLE_LICENSE", "1"); err != nil { - return err - } - - if err := os.Setenv("ENABLE_DANGEROUS_WORKFLOW", "1"); err != nil { - return err - } + envvars := make(map[string]string) + envvars["ENABLE_SARIF"] = "1" + envvars["ENABLE_LICENSE"] = "1" + envvars["ENABLE_DANGEROUS_WORKFLOW"] = "1" + envvars["SCORECARD_POLICY_FILE"] = "./policy.yml" + envvars["SCORECARD_BIN"] = "/scorecard" + envvars["ENABLED_CHECKS"] = "" - if err := os.Setenv("SCORECARD_POLICY_FILE", "/policy.yml"); err != nil { - return err + for key, val := range envvars { + if err := os.Setenv(key, val); err != nil { + return fmt.Errorf("error setting %s: %w", key, err) + } } if result, exists := os.LookupEnv("INPUT_RESULTS_FILE"); !exists { - return fmt.Errorf("INPUT_RESULTS_FILE is not set") + return errInputResultFileNotSet } else { if result == "" { - return fmt.Errorf("INPUT_RESULTS_FILE is empty") + return errInputResultFileEmpty } if err := os.Setenv("SCORECARD_RESULTS_FILE", result); err != nil { - return err + return fmt.Errorf("error setting SCORECARD_RESULTS_FILE: %w", err) } } if result, exists := os.LookupEnv("INPUT_RESULTS_FORMAT"); !exists { - return fmt.Errorf("INPUT_RESULTS_FORMAT is not set") + return errInputResultFormatNotSet } else { if result == "" { - return fmt.Errorf("INPUT_RESULTS_FORMAT is empty") + return errInputResultFormatEmtpy } if err := os.Setenv("SCORECARD_RESULTS_FORMAT", result); err != nil { - return err + return fmt.Errorf("error setting SCORECARD_RESULTS_FORMAT: %w", err) } } if result, exists := os.LookupEnv("INPUT_PUBLISH_RESULTS"); !exists { - return fmt.Errorf("INPUT_PUBLISH_RESULTS is not set") + return errInputPublishResultsNotSet } else { if result == "" { - return fmt.Errorf("INPUT_PUBLISH_RESULTS is empty") + return errInputPublishResultsEmpty } if err := os.Setenv("SCORECARD_PUBLISH_RESULTS", result); err != nil { - return err + return fmt.Errorf("error setting SCORECARD_PUBLISH_RESULTS: %w", err) } } - if err := os.Setenv("SCORECARD_BIN", "/scorecard"); err != nil { - return err - } - - if err := os.Setenv("ENABLED_CHECKS", ""); err != nil { - return err - } return gitHubEventPath() } // gitHubEventPath is a function to get the path to the GitHub event // and sets the SCORECARD_IS_FORK environment variable. func gitHubEventPath() error { - if result, exists := os.LookupEnv("GITHUB_EVENT_PATH"); !exists { - return fmt.Errorf("GITHUB_EVENT_PATH is not set") - } else { - if result == "" { - return fmt.Errorf("GITHUB_EVENT_PATH is empty") - } - if err := os.Setenv("GITHUB_EVENT_PATH", result); err != nil { - return err - } + var result string + var exists bool - data, err := ioutil.ReadFile(result) - if err != nil { - return err - } + if result, exists = os.LookupEnv("GITHUB_EVENT_PATH"); !exists { + return errGitHubEventPathNotSet + } + + if result == "" { + return errGitHubEventPathEmpty + } - if isFork, err := scorecardIsFork(string(data)); err != nil { - return err - } else { - if isFork { - if err := os.Setenv("SCORECARD_IS_FORK", "true"); err != nil { - return err - } - } else { - if err := os.Setenv("SCORECARD_IS_FORK", "false"); err != nil { - return err - } - } + data, err := ioutil.ReadFile(result) + if err != nil { + return fmt.Errorf("error reading GITHUB_EVENT_PATH: %w", err) + } + var isFork bool + + if isFork, err = scorecardIsFork(string(data)); err != nil { + return fmt.Errorf("error checking if scorecard is a fork: %w", err) + } + + if isFork { + if err := os.Setenv("SCORECARD_IS_FORK", "true"); err != nil { + return fmt.Errorf("error setting SCORECARD_IS_FORK: %w", err) + } + } else { + if err := os.Setenv("SCORECARD_IS_FORK", "false"); err != nil { + return fmt.Errorf("error setting SCORECARD_IS_FORK: %w", err) } } + return nil } // scorecardIsFork is a function to check if the current repo is a fork. func scorecardIsFork(ghEventPath string) (bool, error) { if ghEventPath == "" { - return false, fmt.Errorf("ghEventPath is empty") + return false, errGitHubEventPath } /* https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#github_repository_is_fork @@ -150,8 +185,80 @@ func scorecardIsFork(ghEventPath string) (bool, error) { } var r repo if err := json.Unmarshal([]byte(ghEventPath), &r); err != nil { - return false, err + return false, fmt.Errorf("error unmarshalling ghEventPath: %w", err) } return r.Repository.Fork, nil } + +// checkIfRequiredENVSet is a function to check if the required environment variables are set. +func checkIfRequiredENVSet() error { + envVariables := make(map[string]bool) + envVariables["GITHUB_REPOSITORY"] = true + envVariables["GITHUB_AUTH_TOKEN"] = true + + for key := range envVariables { + if _, exists := os.LookupEnv(key); !exists { + return errRequiredENVNotSet + } + } + return nil +} + +// getRepositoryInformation is a function to get the repository information. +// It is decided to not use the golang GitHub library because of the +// dependency on the github.com/google/go-github/github library +// which will in turn require other dependencies. +func getRepositoryInformation(name, githubauthToken string) (repositoryInformation, error) { + //nolint + req, err := http.NewRequest("GET", fmt.Sprintf("https://api.github.com/repos/%s", name), nil) + if err != nil { + return repositoryInformation{}, fmt.Errorf("error creating request: %w", err) + } + req.Header.Set("Authorization", githubauthToken) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return repositoryInformation{}, fmt.Errorf("error creating request: %w", err) + } + defer resp.Body.Close() + if err != nil { + return repositoryInformation{}, fmt.Errorf("error reading response body: %w", err) + } + var r repositoryInformation + err = json.NewDecoder(resp.Body).Decode(&r) + if err != nil { + return repositoryInformation{}, fmt.Errorf("error decoding response body: %w", err) + } + return r, nil +} + +// updateRepoistoryInformation is a function to update the repository information into ENV variables. +func updateRepoistoryInformation(privateRepo bool, defaultBranch string) error { + if defaultBranch == "" { + return errEmptyDefaultBranch + } + + if err := os.Setenv("SCORECARD_PRIVATE_REPOSITORY", strconv.FormatBool(privateRepo)); err != nil { + return fmt.Errorf("error setting SCORECARD_PRIVATE_REPOSITORY: %w", err) + } + if err := os.Setenv("SCORECARD_DEFAULT_BRANCH", defaultBranch); err != nil { + return fmt.Errorf("error setting SCORECARD_DEFAULT_BRANCH: %w", err) + } + return nil +} + +// updateEnvVariables is a function to update the ENV variables based on results format and private repository. +func updateEnvVariables() error { + resultsFileFormat := os.Getenv("SCORECARD_RESULTS_FORMAT") + if resultsFileFormat != "sarif" { + os.Unsetenv("SCORECARD_POLICY_FILE") + } + isPrivateRepo := os.Getenv("SCORECARD_PRIVATE_REPOSITORY") + if isPrivateRepo != "true" { + if err := os.Setenv("SCORECARD_PUBLISH_RESULTS", "false"); err != nil { + return fmt.Errorf("error setting SCORECARD_PUBLISH_RESULTS: %w", err) + } + } + return nil +} diff --git a/main_test.go b/main_test.go index 79b753b0..e9ee77d2 100644 --- a/main_test.go +++ b/main_test.go @@ -20,6 +20,7 @@ import ( ) func Test_scorecardIsFork(t *testing.T) { + t.Parallel() type args struct { ghEventPath string } @@ -60,7 +61,9 @@ func Test_scorecardIsFork(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() var data []byte var err error if tt.args.ghEventPath != "" { @@ -84,6 +87,7 @@ func Test_scorecardIsFork(t *testing.T) { } func Test_initalizeENVVariables(t *testing.T) { + t.Parallel() tests := []struct { name string wantErr bool @@ -158,7 +162,9 @@ func Test_initalizeENVVariables(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() if tt.inputresultsfileSet { os.Setenv("INPUT_RESULTS_FILE", tt.inputresultsfile) } else { @@ -183,14 +189,18 @@ func Test_initalizeENVVariables(t *testing.T) { t.Errorf("initalizeENVVariables() error = %v, wantErr %v", err, tt.wantErr) } - if os.Getenv("ENABLE_SARIF") == "" && os.Getenv("ENABLE_SARIF") != "1" { - t.Errorf("ENABLE_SARIF is not set") - } - if os.Getenv("ENABLE_LICENSE") == "" && os.Getenv("ENABLE_LICENSE") != "1" { - t.Errorf("ENABLE_LICENSE is not set") - } - if os.Getenv("ENABLE_DANGEROUS_WORKFLOW") == "" && os.Getenv("ENABLE_DANGEROUS_WORKFLOW") != "1" { - t.Errorf("ENABLE_DANGEROUS_WORKFLOW is not set") + envvars := make(map[string]string) + envvars["ENABLE_SARIF"] = "1" + envvars["ENABLE_LICENSE"] = "1" + envvars["ENABLE_DANGEROUS_WORKFLOW"] = "1" + envvars["SCORECARD_POLICY_FILE"] = "./policy.yml" + envvars["SCORECARD_BIN"] = "/scorecard" + envvars["ENABLED_CHECKS"] = "" + + for k, v := range envvars { + if os.Getenv(k) != v { + t.Errorf("%s env var not set correctly", k) + } } }) }