Skip to content

Comer/remote ruleset config #30

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

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
26f302b
Added remote ruleset logic
Aug 3, 2021
5947155
Added unit tests for remote rule sets
Aug 3, 2021
920fa68
Refactored method name for stylecheck - func isValidUrl should be isV…
Aug 3, 2021
85fe4cf
Refactored method name for stylecheck - func isValidUrl should be isV…
Aug 3, 2021
77d2108
Fixed linting warnings and removed usage of http.get
Aug 3, 2021
91a3885
Removed whitespace and linting warnings
Aug 3, 2021
5d4f398
Refactored code to use newrequestwithcontext
Aug 3, 2021
f6fb076
MAdding more error handling in response text
Aug 4, 2021
0e14eed
Adding additional edge cases for isValidURL
Aug 4, 2021
b64f5f5
Updated README to include documentation on adding remote rulesets
Aug 4, 2021
865618f
Removed TODO comment
Aug 4, 2021
58ece7e
Merge branch 'main' into comer/remote-ruleset-config
Aug 5, 2021
cef7e1b
Adding downloadedRules.yaml to woke ignore
mkcomer Aug 5, 2021
46af11d
Removed DownloadFile functionality and updated remote config to marsh…
Aug 10, 2021
2103fd5
Removed downloadedfile from wokeignore as downloadfile functionality …
Aug 10, 2021
d2c4185
Updated get remote config logic and updated unit tests
Aug 11, 2021
43cb02e
Merge branch 'main' into comer/remote-ruleset-config
mkcomer Aug 12, 2021
11ba44c
docs: autogenerated update for docs/snippets/woke.md: `7eb51d`
github-actions[bot] Sep 29, 2021
9231c98
Merge branch 'get-woke:main' into main
mkcomer Oct 7, 2021
4b1a979
Merge branch 'main' into comer/remote-ruleset-config
Oct 7, 2021
4c82011
Updated request with context to resolve lint error. added tests
Oct 7, 2021
99366dc
Added readme, remove woke binary and coverage report
Oct 8, 2021
09ec3e0
removed space
Oct 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package config

import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"

Expand All @@ -27,7 +30,13 @@ func NewConfig(filename string) (*Config, error) {
var c Config
if len(filename) > 0 {
var err error
c, err = loadConfig(filename)

if isValidURL(filename) {
c, err = loadRemoteConfig(filename)
} else {
c, err = loadConfig(filename)
}

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -117,13 +126,42 @@ func (c *Config) RemoveRule(i int) {

func loadConfig(filename string) (c Config, err error) {
yamlFile, err := ioutil.ReadFile(filename)
log.Debug().Str("filename", filename).Msg("Adding custom ruleset from")
if err != nil {
return c, err
}

return c, yaml.Unmarshal(yamlFile, &c)
}

// gets the remote config from the url provided and returns config
func loadRemoteConfig(url string) (c Config, err error) {
log.Debug().Str("url", url).Msg("Downloading file from")
client := &http.Client{}
ctx := context.Background()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return c, err
}
resp, err := client.Do(req)
if err != nil {
return c, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return c, err
}
defer resp.Body.Close()

// only parse response body if it is in the response is in the 2xx range
statusOK := resp.StatusCode >= 200 && resp.StatusCode <= 299
if !statusOK {
return c, fmt.Errorf("unable to download remote config from url. Response code: %v. Response body: %c", resp.StatusCode, body)
}

log.Debug().Int("HTTP Response Status:", resp.StatusCode).Msg("Valid URL Response")
return c, yaml.Unmarshal(body, &c)
}

func relative(filename string) string {
// viper provides an absolute path to the config file, but we want the relative
// path to the config file from the current directory to make it easy for woke to ignore it
Expand Down
27 changes: 25 additions & 2 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ func TestNewConfig(t *testing.T) {
enabledRules[i] = fmt.Sprintf("%q", c.Rules[i].Name)
}

loadedRemoteConfigMsg := `{"level":"debug","filename":"testdata/good.yaml","message":"Adding custom ruleset from"}`
loadedRemoteConfig := `{"level":"debug","filename":"testdata/good.yaml","message":"Adding custom ruleset from"}`
loadedConfigMsg := `{"level":"debug","config":"testdata/good.yaml","message":"loaded config file"}`
configRulesMsg := fmt.Sprintf(`{"level":"debug","rules":[%s],"message":"config rules"}`, strings.Join(configRules, ","))
defaultRulesMsg := fmt.Sprintf(`{"level":"debug","rules":[%s],"message":"default rules"}`, strings.Join(defaultRules, ","))
allRulesMsg := fmt.Sprintf(`{"level":"debug","rules":[%s],"message":"all enabled rules"}`, strings.Join(enabledRules, ","))
assert.Equal(t,
loadedConfigMsg+"\n"+configRulesMsg+"\n"+defaultRulesMsg+"\n"+allRulesMsg+"\n",
loadedRemoteConfigMsg+"\n"+loadedRemoteConfig+"\n"+loadedConfigMsg+"\n"+configRulesMsg+"\n"+defaultRulesMsg+"\n"+allRulesMsg+"\n",
out.String())
})

Expand Down Expand Up @@ -206,8 +208,29 @@ func TestNewConfig(t *testing.T) {
assert.EqualValues(t, expected.Rules, c.Rules)
assert.Equal(t, "No findings found.", c.GetSuccessExitMessage())
})
}

t.Run("load-config-with-bad-url", func(t *testing.T) {
_, err := NewConfig("https://raw.githubusercontent.com/get-woke/woke/main/example")
assert.Error(t, err)
})

t.Run("load-config-with-url", func(t *testing.T) {
c, err := NewConfig("https://raw.githubusercontent.com/get-woke/woke/main/example.yaml")
assert.NoError(t, err)
assert.NotNil(t, c)
})

t.Run("load-remote-config-valid-url", func(t *testing.T) {
c, err := loadRemoteConfig("https://raw.githubusercontent.com/get-woke/woke/main/example.yaml")
assert.NoError(t, err)
assert.NotNil(t, c)
})

t.Run("load-remote-config-invalid-url", func(t *testing.T) {
_, err := loadRemoteConfig("https://raw.githubusercontent.com/get-woke/woke/main/example")
assert.Error(t, err)
})
}
func Test_relative(t *testing.T) {
cwd, err := os.Getwd()
assert.NoError(t, err)
Expand Down
22 changes: 22 additions & 0 deletions pkg/config/remote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package config

import (
"net/url"

"github.com/rs/zerolog/log"
)

// isValidUrl tests a string to determine if it is a valid URL or not
func isValidURL(toTest string) bool {
_, err := url.ParseRequestURI(toTest)
if err != nil {
return false
}

u, err := url.Parse(toTest)
if err != nil || u.Scheme == "" || u.Host == "" {
return false
}
log.Debug().Str("remoteConfig", toTest).Msg("Valid URL for remote config.")
return true
}
34 changes: 34 additions & 0 deletions pkg/config/remote_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package config

import (
"testing"

"github.com/stretchr/testify/assert"
)

func Test_isValidURL(t *testing.T) {
t.Run("valid-url-test1", func(t *testing.T) {
boolResponse := isValidURL("https://raw.githubusercontent.com/get-woke/woke/main/example.yaml")
assert.True(t, boolResponse)
})

t.Run("invalid-url-test1", func(t *testing.T) {
boolResponse := isValidURL("Users/Document/test.yaml")
assert.False(t, boolResponse)
})

t.Run("invalid-url-test2", func(t *testing.T) {
boolResponse := isValidURL("/Users/Document/test.yaml")
assert.False(t, boolResponse)
})

t.Run("invalid-url-test3", func(t *testing.T) {
boolResponse := isValidURL("C:User\testpath\test.yaml")
assert.False(t, boolResponse)
})

t.Run("invalid-url-test4", func(t *testing.T) {
boolResponse := isValidURL("C:\\directory.com\test.yaml")
assert.False(t, boolResponse)
})
}