diff --git a/.buildkite/hooks/post-command b/.buildkite/hooks/post-command index eaf475755..a843d66ed 100755 --- a/.buildkite/hooks/post-command +++ b/.buildkite/hooks/post-command @@ -10,16 +10,11 @@ if [[ $BUILDKITE_PULL_REQUEST != "false" ]]; then fi if [[ ! $BUILDKITE_BRANCH =~ ^(v.*) ]] && [[ $BUILDKITE_COMMAND_EXIT_STATUS == 0 ]]; then - if [[ $BUILDKITE_LABEL == ":hammer_and_wrench: Unit Test" ]]; then + if [[ $BUILDKITE_LABEL == ":hammer_and_wrench: Unit Test" ]] || [[ $BUILDKITE_LABEL =~ ":selenium:" ]]; then echo "--- :codecov: Upload coverage reports" bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -f "coverage.txt" -F backend bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -F frontend fi - - if [[ $BUILDKITE_LABEL =~ ":selenium:" ]]; then - echo "--- :codecov: Upload coverage reports" - bash <(curl -s --connect-timeout 10 --retry 10 --retry-max-time 0 https://codecov.io/bash) -v -Z -c -f "coverage.txt" -F backend - fi fi if [[ $BUILDKITE_LABEL =~ ":selenium:" ]] || [[ $BUILDKITE_LABEL =~ ":docker: Build Image" ]]; then diff --git a/Dockerfile.coverage b/Dockerfile.coverage index f7af796f5..8b6307bf6 100644 --- a/Dockerfile.coverage +++ b/Dockerfile.coverage @@ -7,7 +7,7 @@ WORKDIR /node/src/app COPY web . # Install the dependencies and build -RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn build +RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage # ======================================= # ===== Build image for the backend ===== diff --git a/cmd/authelia-scripts/cmd_suites.go b/cmd/authelia-scripts/cmd_suites.go index aa2842855..93d01f0e4 100644 --- a/cmd/authelia-scripts/cmd_suites.go +++ b/cmd/authelia-scripts/cmd_suites.go @@ -138,6 +138,21 @@ func runSuiteSetupTeardown(command string, suite string) error { s := suites.GlobalRegistry.Get(selectedSuite) + if command == "teardown" { + if _, err := os.Stat("../../web/.nyc_output"); err == nil { + log.Infof("Generating frontend coverage reports for suite %s...", suite) + + cmd := utils.Command("yarn", "report") + cmd.Dir = "web" + cmd.Env = os.Environ() + + err := cmd.Run() + if err != nil { + log.Fatal(err) + } + } + } + cmd := utils.CommandWithStdout("go", "run", "cmd/authelia-suites/main.go", command, selectedSuite) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr diff --git a/internal/server/const.go b/internal/server/const.go new file mode 100644 index 000000000..d092ebf7d --- /dev/null +++ b/internal/server/const.go @@ -0,0 +1,3 @@ +package server + +const dev = "dev" diff --git a/internal/server/index.go b/internal/server/index.go index fbf09e9cf..ad4f36ac0 100644 --- a/internal/server/index.go +++ b/internal/server/index.go @@ -3,6 +3,7 @@ package server import ( "fmt" "io/ioutil" + "os" "text/template" "github.com/valyala/fasthttp" @@ -36,7 +37,12 @@ func ServeIndex(publicDir, base, rememberMe, resetPassword string) fasthttp.Requ nonce := utils.RandomString(32, alphaNumericRunes) ctx.SetContentType("text/html; charset=utf-8") - ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce)) + + if os.Getenv("ENVIRONMENT") == dev { + ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce)) + } else { + ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce)) + } err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, CSPNonce, RememberMe, ResetPassword string }{Base: base, CSPNonce: nonce, RememberMe: rememberMe, ResetPassword: resetPassword}) if err != nil { diff --git a/internal/server/server.go b/internal/server/server.go index 7225456c0..f2921b1f9 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -99,7 +99,7 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi // Configure DUO api endpoint only if configuration exists. if configuration.DuoAPI != nil { var duoAPI duo.API - if os.Getenv("ENVIRONMENT") == "dev" { + if os.Getenv("ENVIRONMENT") == dev { duoAPI = duo.NewDuoAPI(duoapi.NewDuoApi( configuration.DuoAPI.IntegrationKey, configuration.DuoAPI.SecretKey, diff --git a/internal/suites/LDAP/configuration.yml b/internal/suites/LDAP/configuration.yml index 80645ee4d..5e20f7e30 100644 --- a/internal/suites/LDAP/configuration.yml +++ b/internal/suites/LDAP/configuration.yml @@ -24,6 +24,7 @@ authentication_backend: groups_filter: (&(member={dn})(objectclass=groupOfNames)) group_name_attribute: cn mail_attribute: mail + display_name_attribute: displayName user: cn=admin,dc=example,dc=com password: password diff --git a/internal/suites/example/kube/authelia/configs/configuration.yml b/internal/suites/example/kube/authelia/configs/configuration.yml index ce9e1fa8a..6be69cd9b 100644 --- a/internal/suites/example/kube/authelia/configs/configuration.yml +++ b/internal/suites/example/kube/authelia/configs/configuration.yml @@ -22,6 +22,7 @@ authentication_backend: groups_filter: (&(member={dn})(objectclass=groupOfNames)) group_name_attribute: cn mail_attribute: mail + display_name_attribute: displayName user: cn=admin,dc=example,dc=com access_control: diff --git a/internal/suites/example/kube/authelia/deployment.yml b/internal/suites/example/kube/authelia/deployment.yml index 2945205f0..5530fc3d9 100644 --- a/internal/suites/example/kube/authelia/deployment.yml +++ b/internal/suites/example/kube/authelia/deployment.yml @@ -40,6 +40,8 @@ spec: value: /app/secrets/session - name: AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE value: /app/secrets/sql_password + - name: ENVIRONMENT + value: dev volumes: - name: config-volume configMap: diff --git a/internal/suites/webdriver.go b/internal/suites/webdriver.go index 40896eebf..25fc8b02b 100644 --- a/internal/suites/webdriver.go +++ b/internal/suites/webdriver.go @@ -2,12 +2,15 @@ package suites import ( "context" + "encoding/json" "errors" "fmt" + "io/ioutil" "os" "strconv" "strings" "testing" + "time" "github.com/stretchr/testify/require" "github.com/tebeka/selenium" @@ -82,8 +85,31 @@ func StartWebDriver() (*WebDriverSession, error) { // Stop stop the selenium session. func (wds *WebDriverSession) Stop() error { - err := wds.WebDriver.Quit() + var coverage map[string]interface{} + coverageDir := "../../web/.nyc_output" + time := time.Now() + + resp, err := wds.WebDriver.ExecuteScriptRaw("return JSON.stringify(window.__coverage__)", nil) + if err != nil { + return err + } + + err = json.Unmarshal(resp, &coverage) + if err != nil { + return err + } + + coverageData := fmt.Sprintf("%s", coverage["value"]) + + _ = os.MkdirAll(coverageDir, 0775) + + err = ioutil.WriteFile(fmt.Sprintf("%s/coverage-%d.json", coverageDir, time.Unix()), []byte(coverageData), 0664) //nolint:gosec + if err != nil { + return err + } + + err = wds.WebDriver.Quit() if err != nil { return err } diff --git a/web/craco.config.js b/web/craco.config.js new file mode 100644 index 000000000..67c5744e0 --- /dev/null +++ b/web/craco.config.js @@ -0,0 +1,5 @@ +module.exports = { + babel: { + plugins: [ "babel-plugin-istanbul" ] + } +}; \ No newline at end of file diff --git a/web/package.json b/web/package.json index c13467b93..1eb0e0dad 100644 --- a/web/package.json +++ b/web/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@craco/craco": "^5.8.0", "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-regular-svg-icons": "^5.15.1", "@fortawesome/free-solid-svg-icons": "^5.15.1", @@ -40,9 +41,11 @@ "u2f-api": "^1.1.1" }, "scripts": { - "start": "react-scripts start", + "start": "craco start", "build": "react-scripts build", + "coverage": "craco build", "test": "react-scripts test --coverage --no-cache", + "report": "nyc report -r clover -r json -r lcov -r text", "eject": "react-scripts eject" }, "eslintConfig": { diff --git a/web/yarn.lock b/web/yarn.lock index fe50ce222..6e1cb5ca4 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1159,6 +1159,15 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@craco/craco@^5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@craco/craco/-/craco-5.8.0.tgz#2a0f551290a5eab353b615de4d7093dd83785777" + integrity sha512-4rhusETLD7rJ195GxOK9VmVdv/VD4jawFxc9hcQ9TrZ3/9ny+qwc0uW+08qu9GYwEF9Eb9meSeSvpWjaqdDr1Q== + dependencies: + cross-spawn "^7.0.0" + lodash "^4.17.15" + webpack-merge "^4.2.2" + "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" @@ -11979,6 +11988,13 @@ webpack-manifest-plugin@2.2.0: object.entries "^1.1.0" tapable "^1.0.0" +webpack-merge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + webpack-sources@^1.1.0, webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"