Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🌱 Porting shell script to Go #94

Merged
merged 1 commit into from Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
217 changes: 162 additions & 55 deletions main.go
Expand Up @@ -15,18 +15,59 @@ 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.
// This is still a work in progress.
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 := updateRepositoryInformation(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.
Expand All @@ -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
Expand All @@ -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
}

// updateRepositoryInformation is a function to update the repository information into ENV variables.
func updateRepositoryInformation(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
}
26 changes: 18 additions & 8 deletions main_test.go
Expand Up @@ -20,6 +20,7 @@ import (
)

func Test_scorecardIsFork(t *testing.T) {
t.Parallel()
type args struct {
ghEventPath string
}
Expand Down Expand Up @@ -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 != "" {
Expand All @@ -84,6 +87,7 @@ func Test_scorecardIsFork(t *testing.T) {
}

func Test_initalizeENVVariables(t *testing.T) {
t.Parallel()
tests := []struct {
name string
wantErr bool
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
}
})
}
Expand Down