diff --git a/Jenkinsfile b/Jenkinsfile index 37cbdb4064..d89a945e6e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -33,7 +33,7 @@ node('docker') { } stage('Unit Test') { - mvn 'test -Dsonia.scm.test.skip.hg=true -Dmaven.test.failure.ignore=true' + mvn 'test -Pcoverage -Dsonia.scm.test.skip.hg=true -Dmaven.test.failure.ignore=true' } stage('Integration Test') { diff --git a/package.json b/package.json index c50258f18d..758ecdf611 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build:dev": "webpack --mode=development --config=scm-ui/ui-scripts/src/webpack.config.js", "test": "lerna run --scope '@scm-manager/ui-*' test", "typecheck": "lerna run --scope '@scm-manager/ui-*' typecheck", - "serve": "webpack-dev-server --mode=development --config=scm-ui/ui-scripts/src/webpack.config.js", + "serve": "NODE_ENV=development webpack-dev-server --hot --mode=development --config=scm-ui/ui-scripts/src/webpack.config.js", "deploy": "ui-scripts publish", "set-version": "ui-scripts version" }, diff --git a/pom.xml b/pom.xml index 918d43439a..a9e43c9015 100644 --- a/pom.xml +++ b/pom.xml @@ -456,7 +456,7 @@ sonia.scm.maven smp-maven-plugin - 1.0.0-rc1 + 1.0.0-rc2 @@ -685,28 +685,6 @@ 2.6 - - - - org.jacoco - jacoco-maven-plugin - 0.8.1 - - - - prepare-agent - - - - report - prepare-package - - report - - - - - @@ -787,6 +765,39 @@ + + coverage + + + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + + + prepare-agent + + + + report + test + + report + + + + + + + + + + APIviz diff --git a/scm-ui/babel-preset/index.js b/scm-ui/babel-preset/index.js index 54c71e3741..940dd71ff6 100644 --- a/scm-ui/babel-preset/index.js +++ b/scm-ui/babel-preset/index.js @@ -1,12 +1,11 @@ -module.exports = () => ({ - presets: [ - require("@babel/preset-env"), - require("@babel/preset-flow"), - require("@babel/preset-react"), - require("@babel/preset-typescript") - ], - plugins: [ - require("@babel/plugin-proposal-class-properties"), - require("@babel/plugin-proposal-optional-chaining") - ] -}); +module.exports = api => { + return { + presets: [ + require("@babel/preset-env"), + require("@babel/preset-flow"), + require("@babel/preset-react"), + require("@babel/preset-typescript") + ], + plugins: [require("@babel/plugin-proposal-class-properties"), require("@babel/plugin-proposal-optional-chaining")] + }; +}; diff --git a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap index c7ab6a81b6..819d1a4558 100644 --- a/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap +++ b/scm-ui/ui-components/src/__snapshots__/storyshots.test.ts.snap @@ -161,6 +161,154 @@ exports[`Storyshots Buttons|Button Colors 1`] = ` `; +exports[`Storyshots Buttons|Button Disabled 1`] = ` +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+`; + exports[`Storyshots Buttons|Button Loading 1`] = `
+ )) + .add("Disabled", () => ( +
+ {colors.map(color => ( + +
)); const buttonStory = (name: string, storyFn: () => ReactElement) => { diff --git a/scm-ui/ui-scripts/package.json b/scm-ui/ui-scripts/package.json index 7ef5d2819c..4b2564b419 100644 --- a/scm-ui/ui-scripts/package.json +++ b/scm-ui/ui-scripts/package.json @@ -10,6 +10,7 @@ "ui-scripts": "./bin/ui-scripts.js" }, "dependencies": { + "@pmmmwh/react-refresh-webpack-plugin": "^0.1.3", "babel-loader": "^8.0.6", "cache-loader": "^4.1.0", "css-loader": "^3.2.0", @@ -18,13 +19,14 @@ "mustache": "^3.1.0", "node-sass": "^4.12.0", "optimize-css-assets-webpack-plugin": "^5.0.3", + "react-refresh": "^0.7.2", "sass-loader": "^8.0.0", "script-loader": "^0.7.2", "style-loader": "^1.0.0", "thread-loader": "^2.1.3", - "webpack": "^4.41.1", - "webpack-cli": "^3.3.9", - "webpack-dev-server": "^3.8.2" + "webpack": "^4.41.5", + "webpack-cli": "^3.3.10", + "webpack-dev-server": "^3.10.1" }, "eslintConfig": { "extends": "@scm-manager/eslint-config", diff --git a/scm-ui/ui-scripts/src/webpack.config.js b/scm-ui/ui-scripts/src/webpack.config.js index 2dd5b4c470..30d7b159a3 100644 --- a/scm-ui/ui-scripts/src/webpack.config.js +++ b/scm-ui/ui-scripts/src/webpack.config.js @@ -3,11 +3,15 @@ const createIndexMiddleware = require("./middleware/IndexMiddleware"); const createContextPathMiddleware = require("./middleware/ContextPathMiddleware"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin"); + +const isDevelopment = process.env.NODE_ENV !== "production"; const root = path.resolve(process.cwd(), "scm-ui"); module.exports = [ { + mode: isDevelopment ? "development" : "production", context: root, entry: { webapp: [path.resolve(__dirname, "webpack-public-path.js"), "./ui-webapp/src/index.tsx"] @@ -41,7 +45,8 @@ module.exports = [ loader: "babel-loader", options: { cacheDirectory: true, - presets: ["@scm-manager/babel-preset"] + presets: ["@scm-manager/babel-preset"], + plugins: [isDevelopment && require.resolve("react-refresh/babel")].filter(Boolean) } } ] @@ -105,7 +110,8 @@ module.exports = [ } } } - } + }, + plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean) }, { context: root, diff --git a/scm-ui/ui-styles/package.json b/scm-ui/ui-styles/package.json index f5f984be08..d4f160f2d7 100644 --- a/scm-ui/ui-styles/package.json +++ b/scm-ui/ui-styles/package.json @@ -20,8 +20,8 @@ "node-sass": "^4.12.0", "sass-loader": "^8.0.0", "style-loader": "^1.0.0", - "webpack": "^4.41.0", - "webpack-dev-server": "^3.8.2" + "webpack": "^4.41.5", + "webpack-dev-server": "^3.10.1" }, "prettier": "@scm-manager/prettier-config" } diff --git a/scm-ui/ui-styles/src/scm.scss b/scm-ui/ui-styles/src/scm.scss index bcb1fd4aa4..adb3c0b774 100644 --- a/scm-ui/ui-styles/src/scm.scss +++ b/scm-ui/ui-styles/src/scm.scss @@ -303,6 +303,10 @@ $danger-25: scale-color($danger, $lightness: 75%); } } + &.is-warning { + color: #88550D; + } + &.is-primary:hover, &.is-primary.is-hovered { background-color: scale-color($primary, $lightness: -10%); @@ -371,6 +375,7 @@ $danger-25: scale-color($danger, $lightness: 75%); &.is-warning[disabled] { background-color: scale-color($warning, $lightness: 75%); + color: #e1d4c2; } &.is-danger:hover, diff --git a/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenValidator.java b/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenValidator.java index 437174f57e..241b0ac001 100644 --- a/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenValidator.java +++ b/scm-webapp/src/main/java/sonia/scm/security/XsrfAccessTokenValidator.java @@ -30,12 +30,15 @@ */ package sonia.scm.security; +import com.google.common.collect.ImmutableSet; import sonia.scm.plugin.Extension; import javax.inject.Inject; import javax.inject.Provider; import javax.servlet.http.HttpServletRequest; +import java.util.Locale; import java.util.Optional; +import java.util.Set; /** * Validates xsrf protected access tokens. The validator check if the current request contains an xsrf key which is @@ -47,7 +50,11 @@ import java.util.Optional; */ @Extension public class XsrfAccessTokenValidator implements AccessTokenValidator { - + + private static final Set ALLOWED_METHOD = ImmutableSet.of( + "GET", "HEAD", "OPTIONS" + ); + private final Provider requestProvider; @@ -65,8 +72,10 @@ public class XsrfAccessTokenValidator implements AccessTokenValidator { public boolean validate(AccessToken accessToken) { Optional xsrfClaim = accessToken.getCustom(Xsrf.TOKEN_KEY); if (xsrfClaim.isPresent()) { - String xsrfHeaderValue = requestProvider.get().getHeader(Xsrf.HEADER_KEY); - return xsrfClaim.get().equals(xsrfHeaderValue); + HttpServletRequest request = requestProvider.get(); + String xsrfHeaderValue = request.getHeader(Xsrf.HEADER_KEY); + return ALLOWED_METHOD.contains(request.getMethod().toUpperCase(Locale.ENGLISH)) + || xsrfClaim.get().equals(xsrfHeaderValue); } return true; } diff --git a/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java b/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java index 173dcb0638..b0ee63c0e8 100644 --- a/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java +++ b/scm-webapp/src/main/java/sonia/scm/update/MigrationWizardServlet.java @@ -5,6 +5,9 @@ import com.github.mustachejava.Mustache; import com.github.mustachejava.MustacheFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; +import org.apache.shiro.mgt.DefaultSecurityManager; +import org.apache.shiro.subject.Subject; +import org.apache.shiro.util.ThreadContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.event.ScmEventBus; @@ -116,6 +119,8 @@ class MigrationWizardServlet extends HttpServlet { respondWithTemplate(resp, model, "templates/repository-migration-restart.mustache"); + ThreadContext.bind(new Subject.Builder(new DefaultSecurityManager()).authenticated(false).buildSubject()); + ScmEventBus.getInstance().post(new RestartEvent(MigrationWizardServlet.class, "wrote migration data")); } diff --git a/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenValidatorTest.java b/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenValidatorTest.java index a89744cd6e..0692a76bd2 100644 --- a/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenValidatorTest.java +++ b/scm-webapp/src/test/java/sonia/scm/security/XsrfAccessTokenValidatorTest.java @@ -1,19 +1,19 @@ /** * Copyright (c) 2014, Sebastian Sdorra * All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + *

* 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. + * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. * 3. Neither the name of SCM-Manager; nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -24,33 +24,39 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + *

* http://bitbucket.org/sdorra/scm-manager - * */ package sonia.scm.security; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.EnumSource; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.GET; import java.util.Optional; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; /** * Tests {@link XsrfAccessTokenValidator}. - * + * * @author Sebastian Sdorra */ -@RunWith(MockitoJUnitRunner.class) -public class XsrfAccessTokenValidatorTest { +@ExtendWith(MockitoExtension.class) +class XsrfAccessTokenValidatorTest { @Mock private HttpServletRequest request; @@ -59,62 +65,94 @@ public class XsrfAccessTokenValidatorTest { private AccessToken accessToken; private XsrfAccessTokenValidator validator; - + /** * Prepare object under test. */ - @Before - public void prepareObjectUnderTest() { + @BeforeEach + void prepareObjectUnderTest() { validator = new XsrfAccessTokenValidator(() -> request); } - - /** - * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)}. - */ - @Test - public void testValidate() { + + @Nested + class RequestMethodPost { + + @BeforeEach + void setRequestMethod() { + lenient().when(request.getMethod()).thenReturn("POST"); + } + + /** + * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)}. + */ + @Test + void testValidate() { + // prepare + when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.of("abc")); + when(request.getHeader(Xsrf.HEADER_KEY)).thenReturn("abc"); + + // execute and assert + assertTrue(validator.validate(accessToken)); + } + + /** + * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)} with wrong header. + */ + @Test + void testValidateWithWrongHeader() { + // prepare + when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.of("abc")); + when(request.getHeader(Xsrf.HEADER_KEY)).thenReturn("123"); + + // execute and assert + assertFalse(validator.validate(accessToken)); + } + + /** + * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)} without header. + */ + @Test + void testValidateWithoutHeader() { + // prepare + when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.of("abc")); + + // execute and assert + assertFalse(validator.validate(accessToken)); + } + + /** + * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)} without claims key. + */ + @Test + void testValidateWithoutClaimsKey() { + // prepare + when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.empty()); + + // execute and assert + assertTrue(validator.validate(accessToken)); + } + + } + + @ParameterizedTest + @CsvSource({"GET", "HEAD", "OPTIONS"}) + void shouldNotValidateReadRequests(String method) { // prepare + when(request.getMethod()).thenReturn(method); when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.of("abc")); - when(request.getHeader(Xsrf.HEADER_KEY)).thenReturn("abc"); - + // execute and assert assertTrue(validator.validate(accessToken)); } - - /** - * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)} with wrong header. - */ - @Test - public void testValidateWithWrongHeader() { + + @ParameterizedTest + @CsvSource({"POST", "PUT", "DELETE", "PATCH"}) + void shouldFailValidationOfWriteRequests(String method) { // prepare + when(request.getMethod()).thenReturn(method); when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.of("abc")); - when(request.getHeader(Xsrf.HEADER_KEY)).thenReturn("123"); - + // execute and assert assertFalse(validator.validate(accessToken)); } - - /** - * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)} without header. - */ - @Test - public void testValidateWithoutHeader() { - // prepare - when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.of("abc")); - - // execute and assert - assertFalse(validator.validate(accessToken)); - } - - /** - * Tests {@link XsrfAccessTokenValidator#validate(AccessToken)} without claims key. - */ - @Test - public void testValidateWithoutClaimsKey() { - // prepare - when(accessToken.getCustom(Xsrf.TOKEN_KEY)).thenReturn(Optional.empty()); - - // execute and assert - assertTrue(validator.validate(accessToken)); - } } diff --git a/yarn.lock b/yarn.lock index f75ea838fe..ef120d73f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2136,6 +2136,18 @@ dependencies: "@types/node" ">= 8" +"@pmmmwh/react-refresh-webpack-plugin@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.1.3.tgz#bb6815315028087e6af4f96d063376880caf9c82" + integrity sha512-FJ8WzpGrao8Gz8KNAeU9dcTYr1RjbAGnXJMKKXTp4oAw494SqQK4HyGT8HMmIQt0ayukuP+A71w1oV8/5xSAWQ== + dependencies: + ansi-html "^0.0.7" + error-stack-parser "^2.0.4" + html-entities "^1.2.1" + lodash.debounce "^4.0.8" + react-dev-utils "^9.1.0" + sockjs-client "^1.4.0" + "@reach/router@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.2.1.tgz#34ae3541a5ac44fa7796e5506a5d7274a162be4e" @@ -3309,7 +3321,7 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.8.1" -ansi-html@0.0.7: +ansi-html@0.0.7, ansi-html@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= @@ -6265,6 +6277,13 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" + integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== + dependencies: + stackframe "^1.1.1" + es-abstract@^1.13.0, es-abstract@^1.17.0, es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1: version "1.17.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0.tgz#f42a517d0036a5591dbb2c463591dc8bb50309b1" @@ -11937,7 +11956,7 @@ react-clientside-effect@^1.2.0: dependencies: "@babel/runtime" "^7.0.0" -react-dev-utils@^9.0.0: +react-dev-utils@^9.0.0, react-dev-utils@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-9.1.0.tgz#3ad2bb8848a32319d760d0a84c56c14bdaae5e81" integrity sha512-X2KYF/lIGyGwP/F/oXgGDF24nxDA2KC4b7AFto+eqzc/t838gpSGiaU8trTqHXOohuLxxc5qi1eDzsl9ucPDpg== @@ -12130,6 +12149,11 @@ react-redux@^5.0.7: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" +react-refresh@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.7.2.tgz#f30978d21eb8cac6e2f2fde056a7d04f6844dd50" + integrity sha512-u5l7fhAJXecWUJzVxzMRU2Zvw8m4QmDNHlTrT5uo3KBlYBhmChd7syAakBoay1yIiVhx/8Fi7a6v6kQZfsw81Q== + react-router-dom@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" @@ -13292,7 +13316,7 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -sockjs-client@1.4.0: +sockjs-client@1.4.0, sockjs-client@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== @@ -13505,6 +13529,11 @@ stack-utils@^1.0.1: resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== +stackframe@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.1.tgz#ffef0a3318b1b60c3b58564989aca5660729ec71" + integrity sha512-0PlYhdKh6AfFxRyK/v+6/k+/mMfyiEBbTM5L94D0ZytQnJ166wuwoTYLHFWGbs2dpA8Rgq763KGWmN1EQEYHRQ== + state-toggle@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.2.tgz#75e93a61944116b4959d665c8db2d243631d6ddc" @@ -14717,7 +14746,7 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-cli@^3.3.9: +webpack-cli@^3.3.10: version "3.3.10" resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== @@ -14745,7 +14774,7 @@ webpack-dev-middleware@^3.7.0, webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@^3.8.2: +webpack-dev-server@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.10.1.tgz#1ff3e5cccf8e0897aa3f5909c654e623f69b1c0e" integrity sha512-AGG4+XrrXn4rbZUueyNrQgO4KGnol+0wm3MPdqGLmmA+NofZl3blZQKxZ9BND6RDNuvAK9OMYClhjOSnxpWRoA== @@ -14810,7 +14839,7 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.0, webpack@^4.41.1: +webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.5: version "4.41.5" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw==