From f75bb0c8d3ab43bf1498096cb4af3b69c0cd425c Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Tue, 9 Aug 2022 23:00:02 -0500 Subject: [PATCH 01/11] Adding placeholder for github rego function --- src/cmd/policy.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index dd92a446..26ef7522 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -53,6 +53,13 @@ opslevel run policy -f policy.rego | jq Decl: types.NewFunction(types.Args(types.S), types.S), }, RegoFuncReadFile), + rego.Function2( + ®o.Function{ + Name: "opslevel.repo.github", + Decl: types.NewFunction(types.Args(types.S, types.S), types.A), + Memoize: true, + }, + RegoFuncGetGithubRepo), rego.Input(input), ) rs, err := rego.Eval(context.Background()) @@ -84,6 +91,26 @@ func RegoFuncReadFile(ctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { return nil, nil } +func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error) { + + var org, repo string + + if err := ast.As(a.Value, &org); err != nil { + return nil, err + } else if ast.As(b.Value, &repo); err != nil { + return nil, err + } + fmt.Println(org) + fmt.Println(repo) + + response, err := getClientRest().R(). + Get("https://httpbin.org/get") + + cobra.CheckErr(err) + + return ast.StringTerm(response.String()), nil +} + func init() { runCmd.AddCommand(policyCmd) From d34aee9d8f9332802855f855abb3af07c850cab5 Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Tue, 9 Aug 2022 23:21:10 -0500 Subject: [PATCH 02/11] Update to make call to github api --- src/cmd/policy.go | 10 +++++++--- src/cmd/run.go | 5 ++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 26ef7522..39ed0414 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -100,11 +100,15 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, } else if ast.As(b.Value, &repo); err != nil { return nil, err } - fmt.Println(org) - fmt.Println(repo) + + flags := runCmd.Flags() + githubToken, err := flags.GetString("github-token") + cobra.CheckErr(err) response, err := getClientRest().R(). - Get("https://httpbin.org/get") + SetHeader("Accept", "application/vnd.github+json"). + SetHeader("Authorization", fmt.Sprintf("token %v", githubToken)). + Get(fmt.Sprintf("https://api.github.com/repos/%v/%v", org, repo)) cobra.CheckErr(err) diff --git a/src/cmd/run.go b/src/cmd/run.go index c926b571..a16628a9 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -1,8 +1,6 @@ package cmd -import ( - "github.com/spf13/cobra" -) +import cobra "github.com/spf13/cobra" var runCmd = &cobra.Command{ Use: "run", @@ -12,4 +10,5 @@ var runCmd = &cobra.Command{ func init() { rootCmd.AddCommand(runCmd) + runCmd.PersistentFlags().String("github-token", "", "Github API Token. Overrides environment variable 'GITHUB_API_TOKEN'") } From 64d8370dcbf595740b87c4ba45b412b5c3952690 Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Thu, 11 Aug 2022 16:12:18 -0500 Subject: [PATCH 03/11] Update to return object instead of string --- .../unreleased/Feature-20220809-234610.yaml | 3 +++ src/cmd/document.go | 2 +- src/cmd/policy.go | 17 +++++++++++++++-- src/cmd/run.go | 10 ++++++++-- 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 .changes/unreleased/Feature-20220809-234610.yaml diff --git a/.changes/unreleased/Feature-20220809-234610.yaml b/.changes/unreleased/Feature-20220809-234610.yaml new file mode 100644 index 00000000..09f40f44 --- /dev/null +++ b/.changes/unreleased/Feature-20220809-234610.yaml @@ -0,0 +1,3 @@ +kind: Feature +body: Add Rego function to get Github repo metadata +time: 2022-08-09T23:46:10.611286-05:00 diff --git a/src/cmd/document.go b/src/cmd/document.go index 37715985..88e8f7cc 100644 --- a/src/cmd/document.go +++ b/src/cmd/document.go @@ -7,7 +7,7 @@ import ( "github.com/opslevel/opslevel-go/v2022" "github.com/rs/zerolog/log" - "github.com/spf13/cobra" + cobra "github.com/spf13/cobra" "github.com/spf13/pflag" ) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 39ed0414..89c9199a 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -13,12 +13,19 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" ) type regoInput struct { Files []string `json:"files"` } +type GithubRepo struct { + Name string `json:"name"` + Description string `json:"description"` + Language string `json:"language"` +} + var policyCmd = &cobra.Command{ Use: "policy", Short: "Invoked along with a Rego policy to create and output JSON", @@ -109,10 +116,16 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, SetHeader("Accept", "application/vnd.github+json"). SetHeader("Authorization", fmt.Sprintf("token %v", githubToken)). Get(fmt.Sprintf("https://api.github.com/repos/%v/%v", org, repo)) - cobra.CheckErr(err) - return ast.StringTerm(response.String()), nil + if response.IsError() == true { + log.Error().Msgf("%d: %s", response.StatusCode(), response) + return nil, err + } + + reader := strings.NewReader(response.String()) + v, err := ast.ValueFromReader(reader) + return ast.NewTerm(v), nil } func init() { diff --git a/src/cmd/run.go b/src/cmd/run.go index a16628a9..a205cb8e 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -1,6 +1,9 @@ package cmd -import cobra "github.com/spf13/cobra" +import ( + cobra "github.com/spf13/cobra" + "github.com/spf13/viper" +) var runCmd = &cobra.Command{ Use: "run", @@ -10,5 +13,8 @@ var runCmd = &cobra.Command{ func init() { rootCmd.AddCommand(runCmd) - runCmd.PersistentFlags().String("github-token", "", "Github API Token. Overrides environment variable 'GITHUB_API_TOKEN'") + runCmd.PersistentFlags().String("github-token", "", "Github API Token to get repo data. Overrides environment variable 'GITHUB_API_TOKEN'") + + viper.BindPFlags(runCmd.PersistentFlags()) + viper.BindEnv("github-token", "GITHUB_API_TOKEN") } From fda21f0852712ad2e4aa249e97d47a781589c835 Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Thu, 11 Aug 2022 16:28:23 -0500 Subject: [PATCH 04/11] Get token from env if not passed in with flag --- src/cmd/policy.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 89c9199a..8680a7cf 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -110,6 +110,9 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, flags := runCmd.Flags() githubToken, err := flags.GetString("github-token") + if githubToken == "" { + githubToken = os.Getenv("GITHUB_API_TOKEN") + } cobra.CheckErr(err) response, err := getClientRest().R(). From 9de262c07248ade2b05622fd1fac1038b35175b8 Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Thu, 11 Aug 2022 16:42:23 -0500 Subject: [PATCH 05/11] format change --- src/cmd/policy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 8680a7cf..e8f7d03a 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -117,7 +117,7 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, response, err := getClientRest().R(). SetHeader("Accept", "application/vnd.github+json"). - SetHeader("Authorization", fmt.Sprintf("token %v", githubToken)). + SetHeader("Authorization", fmt.Sprintf("token %s", githubToken)). Get(fmt.Sprintf("https://api.github.com/repos/%v/%v", org, repo)) cobra.CheckErr(err) From 8be4e1230d951fc766260b2fb74bf9cd4016514a Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Fri, 12 Aug 2022 12:33:53 -0500 Subject: [PATCH 06/11] Fixing a few things based on feedback. --- src/cmd/document.go | 2 +- src/cmd/policy.go | 22 +++++++--------------- src/cmd/run.go | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/cmd/document.go b/src/cmd/document.go index 88e8f7cc..37715985 100644 --- a/src/cmd/document.go +++ b/src/cmd/document.go @@ -7,7 +7,7 @@ import ( "github.com/opslevel/opslevel-go/v2022" "github.com/rs/zerolog/log" - cobra "github.com/spf13/cobra" + "github.com/spf13/cobra" "github.com/spf13/pflag" ) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index e8f7d03a..62ad43df 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -9,7 +9,8 @@ import ( "github.com/open-policy-agent/opa/rego" "github.com/open-policy-agent/opa/types" "github.com/rs/zerolog/log" - cobra "github.com/spf13/cobra" + "github.com/spf13/cobra" + "github.com/spf13/viper" "io/ioutil" "os" "path/filepath" @@ -20,12 +21,6 @@ type regoInput struct { Files []string `json:"files"` } -type GithubRepo struct { - Name string `json:"name"` - Description string `json:"description"` - Language string `json:"language"` -} - var policyCmd = &cobra.Command{ Use: "policy", Short: "Invoked along with a Rego policy to create and output JSON", @@ -108,17 +103,14 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, return nil, err } - flags := runCmd.Flags() - githubToken, err := flags.GetString("github-token") - if githubToken == "" { - githubToken = os.Getenv("GITHUB_API_TOKEN") - } - cobra.CheckErr(err) + githubToken := viper.GetString("github-token") + authorizationHeader := fmt.Sprintf("token %s", githubToken) + githubAPIUrl := fmt.Sprintf("https://api.github.com/repos/%v/%v", org, repo) response, err := getClientRest().R(). SetHeader("Accept", "application/vnd.github+json"). - SetHeader("Authorization", fmt.Sprintf("token %s", githubToken)). - Get(fmt.Sprintf("https://api.github.com/repos/%v/%v", org, repo)) + SetHeader("Authorization", authorizationHeader). + Get(githubAPIUrl) cobra.CheckErr(err) if response.IsError() == true { diff --git a/src/cmd/run.go b/src/cmd/run.go index a205cb8e..5a8bb1d6 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -1,7 +1,7 @@ package cmd import ( - cobra "github.com/spf13/cobra" + "github.com/spf13/cobra" "github.com/spf13/viper" ) From 68d5c6e44ca3c6bb8b5868131bc6d4964db3036e Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Fri, 12 Aug 2022 13:22:36 -0500 Subject: [PATCH 07/11] Add error message for empty value for org or repo --- src/cmd/policy.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 62ad43df..9b60856d 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -96,13 +96,17 @@ func RegoFuncReadFile(ctx rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error) { var org, repo string - if err := ast.As(a.Value, &org); err != nil { return nil, err } else if ast.As(b.Value, &repo); err != nil { return nil, err } + if org == "" || repo == "" { + log.Error().Msgf("Please provide a valid org and repo") + return nil, nil + } + githubToken := viper.GetString("github-token") authorizationHeader := fmt.Sprintf("token %s", githubToken) githubAPIUrl := fmt.Sprintf("https://api.github.com/repos/%v/%v", org, repo) @@ -115,7 +119,7 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, if response.IsError() == true { log.Error().Msgf("%d: %s", response.StatusCode(), response) - return nil, err + return nil, nil } reader := strings.NewReader(response.String()) From 6dd72a3d61e2acc6354988f5f08e15aa502b6fcd Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Fri, 12 Aug 2022 14:34:06 -0500 Subject: [PATCH 08/11] Split org/repo error message --- src/cmd/policy.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index 9b60856d..f1664a45 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -102,8 +102,13 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, return nil, err } - if org == "" || repo == "" { - log.Error().Msgf("Please provide a valid org and repo") + if org == "" { + log.Error().Msgf("Please provide a valid org") + return nil, nil + } + + if repo == "" { + log.Error().Msgf("Please provide a valid repo") return nil, nil } From cc923ded9b29955bbafc85e1a89d66c24beacf98 Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Fri, 12 Aug 2022 15:16:30 -0500 Subject: [PATCH 09/11] Update error messages --- src/cmd/policy.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index f1664a45..dbeb5e88 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -103,12 +103,12 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, } if org == "" { - log.Error().Msgf("Please provide a valid org") + log.Error().Msgf("opslevel.repo.github(\"%s\", \"%s\") failed: Please provide a valid org", org, repo) return nil, nil } if repo == "" { - log.Error().Msgf("Please provide a valid repo") + log.Error().Msgf("opslevel.repo.github(\"%s\", \"%s\") failed: Please provide a valid repo", org, repo) return nil, nil } @@ -123,7 +123,7 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, cobra.CheckErr(err) if response.IsError() == true { - log.Error().Msgf("%d: %s", response.StatusCode(), response) + log.Error().Msgf("error requesting Github repo metadata. CODE: %d: REASON: %s", response.StatusCode(), response) return nil, nil } From ed52c34c0ab69ed298b26ba7684b105814c20a95 Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Fri, 12 Aug 2022 15:49:08 -0500 Subject: [PATCH 10/11] Update to make if statements more clear --- src/cmd/policy.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index dbeb5e88..c7aba516 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -98,7 +98,8 @@ func RegoFuncGetGithubRepo(ctx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, var org, repo string if err := ast.As(a.Value, &org); err != nil { return nil, err - } else if ast.As(b.Value, &repo); err != nil { + } + if err := ast.As(b.Value, &repo); err != nil { return nil, err } From dcea704713a026b9b125e869f9d36ba0327106ba Mon Sep 17 00:00:00 2001 From: Edgar Ochoa Date: Mon, 15 Aug 2022 10:34:16 -0500 Subject: [PATCH 11/11] Move github token flag to policy command and update usage verbiage --- src/cmd/policy.go | 4 ++++ src/cmd/run.go | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cmd/policy.go b/src/cmd/policy.go index c7aba516..4ee9a1d3 100644 --- a/src/cmd/policy.go +++ b/src/cmd/policy.go @@ -137,4 +137,8 @@ func init() { runCmd.AddCommand(policyCmd) policyCmd.Flags().StringP("file", "f", "-", "File to read Rego policy from. Defaults to reading from stdin.") + policyCmd.PersistentFlags().String("github-token", "", "The Github API token to use when calling opslevel.repo.github function within a Rego policy. Overrides environment variable 'GITHUB_API_TOKEN'") + + viper.BindPFlags(policyCmd.PersistentFlags()) + viper.BindEnv("github-token", "GITHUB_API_TOKEN") } diff --git a/src/cmd/run.go b/src/cmd/run.go index 5a8bb1d6..c926b571 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -2,7 +2,6 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/spf13/viper" ) var runCmd = &cobra.Command{ @@ -13,8 +12,4 @@ var runCmd = &cobra.Command{ func init() { rootCmd.AddCommand(runCmd) - runCmd.PersistentFlags().String("github-token", "", "Github API Token to get repo data. Overrides environment variable 'GITHUB_API_TOKEN'") - - viper.BindPFlags(runCmd.PersistentFlags()) - viper.BindEnv("github-token", "GITHUB_API_TOKEN") }