From 14641899f71cf31f1e39ee01a69f13576b1e71ac Mon Sep 17 00:00:00 2001 From: Pei Wang Date: Wed, 1 Dec 2021 22:19:48 +0000 Subject: [PATCH 1/3] ci: Add tsec_test for all ng_module targets. Instead of modifying ~250 BUILD.bazel files, instrument the ng_module macro to conveniently create tsec_test for all modules. The ts_library macro is not instrumented since most of them are about testing, schematics and examples, which are not relevant to XSS. For those that are indeed security sensitive, tsec_test is manually added into individual BUILD.bazel files. --- BUILD.bazel | 1 + package.json | 2 ++ src/BUILD.bazel | 12 ++++++++++-- src/cdk-experimental/BUILD.bazel | 7 +++++++ src/cdk/BUILD.bazel | 7 +++++++ src/cdk/a11y/focus-monitor/focus-monitor.ts | 2 +- src/cdk/coercion/BUILD.bazel | 7 +++++++ src/material-experimental/BUILD.bazel | 7 +++++++ src/material-experimental/mdc-chips/chip-row.ts | 2 +- src/tsconfig-tsec.json | 9 +++++++++ src/tsec-exemption.json | 17 +++++++++++++++++ tools/defaults.bzl | 8 ++++++++ yarn.lock | 10 +++++++++- 13 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 src/tsconfig-tsec.json create mode 100644 src/tsec-exemption.json diff --git a/BUILD.bazel b/BUILD.bazel index 399afc9eff28..4f8c651dec73 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,6 +3,7 @@ load("//src/cdk:config.bzl", "CDK_ENTRYPOINTS") load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_ENTRYPOINTS") load("//src/material:config.bzl", "MATERIAL_ENTRYPOINTS", "MATERIAL_TESTING_ENTRYPOINTS") load("//src/material-experimental:config.bzl", "MATERIAL_EXPERIMENTAL_ENTRYPOINTS", "MATERIAL_EXPERIMENTAL_TESTING_ENTRYPOINTS") +load("@npm//@bazel/typescript:index.bzl", "ts_config") package(default_visibility = ["//visibility:public"]) diff --git a/package.json b/package.json index d3da06b18dc4..41d2655cbb72 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "test": "node ./scripts/run-component-tests.js", "test-local": "yarn -s test --local", "test-firefox": "yarn -s test --firefox", + "test-tsec": "yarn bazelisk test //... --build_tag_filters=tsec --test_tag_filters=tsec", "lint": "yarn -s tslint && yarn -s stylelint && yarn -s ownerslint && yarn -s ng-dev format changed --check", "e2e": "bazel test //src/... --build_tag_filters=e2e --test_tag_filters=e2e --build_tests_only", "deploy-dev-app": "node ./scripts/deploy-dev-app.js", @@ -211,6 +212,7 @@ "stylelint": "^14.0.1", "terser": "^5.9.0", "ts-node": "^10.2.1", + "tsec": "0.2.1", "tsickle": "0.39.1", "tslint": "^6.1.3", "tsutils": "^3.21.0", diff --git a/src/BUILD.bazel b/src/BUILD.bazel index d84776afa83c..f67e836d6023 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -32,8 +32,7 @@ dgeni_api_docs( # Add all Angular packages to the sources because some Material exports use # Angular exports and these should not cause any warnings when Dgeni uses the # type checker to parse our TypeScript sources. - "@npm//@angular/core", - "@npm//@angular/common", + "@npm//@angular/core", "@npm//@angular/common", "@npm//@angular/forms", "@npm//@angular/animations", "@npm//@angular/platform-browser", @@ -49,3 +48,12 @@ ts_library( name = "dev_mode_types", srcs = ["dev-mode-types.d.ts"], ) + +ts_config( + name = "tsec_config", + src = "tsconfig-tsec.json", + deps = [ + ":bazel-tsconfig-build.json", + ":tsec-exemption.json", + ], +) diff --git a/src/cdk-experimental/BUILD.bazel b/src/cdk-experimental/BUILD.bazel index f9804d89bcb9..cfa3426bd3c3 100644 --- a/src/cdk-experimental/BUILD.bazel +++ b/src/cdk-experimental/BUILD.bazel @@ -1,5 +1,6 @@ load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_TARGETS") load("//tools:defaults.bzl", "ng_package", "ts_library") +load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -12,6 +13,12 @@ ts_library( deps = ["@npm//@angular/core"], ) +tsec_test( + name = "cdk-experimental_tsec_test", + target = "cdk-experimental", + tsconfig = "//src:tsec_config", +) + ng_package( name = "npm_package", srcs = ["package.json"], diff --git a/src/cdk/BUILD.bazel b/src/cdk/BUILD.bazel index 5d254c5a4a94..31bdf2ea9466 100644 --- a/src/cdk/BUILD.bazel +++ b/src/cdk/BUILD.bazel @@ -1,5 +1,6 @@ load("//src/cdk:config.bzl", "CDK_ENTRYPOINTS", "CDK_ENTRYPOINTS_WITH_STYLES", "CDK_SCSS_LIBS", "CDK_TARGETS") load("//tools:defaults.bzl", "ng_package", "sass_library", "ts_library") +load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -12,6 +13,12 @@ ts_library( deps = ["@npm//@angular/core"], ) +tsec_test( + name = "cdk_tsec_test", + target = "cdk", + tsconfig = "//src:tsec_config", +) + # List of style files that need to be copied to the root of the CDK package. We do this # to make it easier for developers to import these styles without needing to know about # deep imports in the release output. Note that this is done for backwards compatibility diff --git a/src/cdk/a11y/focus-monitor/focus-monitor.ts b/src/cdk/a11y/focus-monitor/focus-monitor.ts index 4b827bf0e731..fe7b50acaf54 100644 --- a/src/cdk/a11y/focus-monitor/focus-monitor.ts +++ b/src/cdk/a11y/focus-monitor/focus-monitor.ts @@ -134,7 +134,7 @@ export class FocusMonitor implements OnDestroy { // Make a note of when the window regains focus, so we can // restore the origin info for the focused element. this._windowFocused = true; - this._windowFocusTimeoutId = setTimeout(() => (this._windowFocused = false)); + this._windowFocusTimeoutId = window.setTimeout(() => (this._windowFocused = false)); }; /** Used to reference correct document/window */ diff --git a/src/cdk/coercion/BUILD.bazel b/src/cdk/coercion/BUILD.bazel index c6887bee13c6..9fef0747e06b 100644 --- a/src/cdk/coercion/BUILD.bazel +++ b/src/cdk/coercion/BUILD.bazel @@ -1,4 +1,5 @@ load("//tools:defaults.bzl", "karma_web_test_suite", "markdown_to_html", "ts_library") +load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -13,6 +14,12 @@ ts_library( ], ) +tsec_test( + name = "coercion_tsec_test", + target = "coercion", + tsconfig = "//src:tsec_config", +) + ts_library( name = "unit_test_sources", testonly = True, diff --git a/src/material-experimental/BUILD.bazel b/src/material-experimental/BUILD.bazel index fabb2dc7df0a..4acf824fa7be 100644 --- a/src/material-experimental/BUILD.bazel +++ b/src/material-experimental/BUILD.bazel @@ -5,6 +5,7 @@ load( "MATERIAL_EXPERIMENTAL_TESTING_TARGETS", ) load("//tools:defaults.bzl", "ng_package", "sass_library", "ts_library") +load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -17,6 +18,12 @@ ts_library( deps = ["@npm//@angular/core"], ) +tsec_test( + name = "material-experimental_tsec_test", + target = "material-experimental", + tsconfig = "//src:tsec_config", +) + sass_library( name = "theming_scss_lib", srcs = MATERIAL_EXPERIMENTAL_SCSS_LIBS + [ diff --git a/src/material-experimental/mdc-chips/chip-row.ts b/src/material-experimental/mdc-chips/chip-row.ts index 768553eb2739..9460b42dc189 100644 --- a/src/material-experimental/mdc-chips/chip-row.ts +++ b/src/material-experimental/mdc-chips/chip-row.ts @@ -168,7 +168,7 @@ export class MatChipRow } // Wait to see if focus moves to the other gridcell - this._focusoutTimeout = setTimeout(() => { + this._focusoutTimeout = window.setTimeout(() => { this._hasFocusInternal = false; this._onBlur.next({chip: this}); this._handleInteraction(event); diff --git a/src/tsconfig-tsec.json b/src/tsconfig-tsec.json new file mode 100644 index 000000000000..fdc0baa8fbb2 --- /dev/null +++ b/src/tsconfig-tsec.json @@ -0,0 +1,9 @@ +{ + "extends": "./bazel-tsconfig-build.json", + "compilerOptions": { + "plugins": [ + {"name": "tsec", "exemptionConfig": "./tsec-exemption.json"} + ] + } +} + diff --git a/src/tsec-exemption.json b/src/tsec-exemption.json new file mode 100644 index 000000000000..b8d1bf827d62 --- /dev/null +++ b/src/tsec-exemption.json @@ -0,0 +1,17 @@ +{ + "ban-trustedtypes-createpolicy": [ + "material/icon/trusted-types.ts" + ], + "ban-element-innerhtml-assignments": [ + "material/icon/icon-registry.ts" + ], + "ban-element-setattribute": [ + "cdk/a11y/aria-describer/aria-reference.ts", + "material-experimental/mdc-checkbox/checkbox.ts", + "material-experimental/mdc-list/interactive-list-base.ts", + "material-experimental/mdc-progress-spinner/progress-spinner.ts", + "material-experimental/mdc-slide-toggle/slide-toggle.ts", + "material/icon/icon-registry.ts", + "material/icon/icon.ts" + ] +} diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 18f6bd8c519e..88f7e7e0a516 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -12,6 +12,7 @@ load("@npm//@bazel/jasmine:index.bzl", _jasmine_node_test = "jasmine_node_test") load("@npm//@bazel/concatjs:index.bzl", _karma_web_test = "karma_web_test", _karma_web_test_suite = "karma_web_test_suite") load("@npm//@bazel/protractor:index.bzl", _protractor_web_test_suite = "protractor_web_test_suite") load("@npm//@bazel/typescript:index.bzl", _ts_library = "ts_library") +load("@npm//tsec:index.bzl", _tsec_test = "tsec_test") load("//:packages.bzl", "NO_STAMP_NPM_PACKAGE_SUBSTITUTIONS", "NPM_PACKAGE_SUBSTITUTIONS") load("//:pkg-externals.bzl", "PKG_EXTERNALS") load("//tools/markdown-to-html:index.bzl", _markdown_to_html = "markdown_to_html") @@ -147,6 +148,13 @@ def ng_module( **kwargs ) + if not testonly: + _tsec_test( + name = kwargs["name"] + "_tsec_test", + target = kwargs["name"], + tsconfig = "//src:tsec_config", + ) + def ng_package(name, data = [], deps = [], externals = PKG_EXTERNALS, readme_md = None, visibility = None, **kwargs): # If no readme file has been specified explicitly, use the default readme for # release packages from "src/README.md". diff --git a/yarn.lock b/yarn.lock index 8182a2bf84b6..9f295153ffe2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11256,7 +11256,7 @@ minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -15642,6 +15642,14 @@ ts-node@^10.2.1: make-error "^1.1.1" yn "3.1.1" +tsec@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tsec/-/tsec-0.2.1.tgz#017423174b2be54f26da5cb7591dc7035996086b" + integrity sha512-RP9vhbRbRI9VH4CfOlQvo5W9HdfiPKq0gdiUOWI5oKmLaZKNFN8CsPwBfT5ySmhnKNwmmAS/BtY3WoTfABwwig== + dependencies: + glob "^7.1.1" + minimatch "^3.0.3" + tsickle@0.39.1: version "0.39.1" resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.39.1.tgz#7ccf672cde5b430f5dd0b281ee49e170ef390ff9" From dc504cf347e9ccb5fec818d17b5fdcef28c6cf1f Mon Sep 17 00:00:00 2001 From: Pei Wang Date: Wed, 8 Dec 2021 00:39:30 +0000 Subject: [PATCH 2/3] fixup! ci: Add tsec_test for all ng_module targets. --- BUILD.bazel | 1 - src/BUILD.bazel | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 4f8c651dec73..399afc9eff28 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -3,7 +3,6 @@ load("//src/cdk:config.bzl", "CDK_ENTRYPOINTS") load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_ENTRYPOINTS") load("//src/material:config.bzl", "MATERIAL_ENTRYPOINTS", "MATERIAL_TESTING_ENTRYPOINTS") load("//src/material-experimental:config.bzl", "MATERIAL_EXPERIMENTAL_ENTRYPOINTS", "MATERIAL_EXPERIMENTAL_TESTING_ENTRYPOINTS") -load("@npm//@bazel/typescript:index.bzl", "ts_config") package(default_visibility = ["//visibility:public"]) diff --git a/src/BUILD.bazel b/src/BUILD.bazel index f67e836d6023..a58deea08198 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -32,7 +32,8 @@ dgeni_api_docs( # Add all Angular packages to the sources because some Material exports use # Angular exports and these should not cause any warnings when Dgeni uses the # type checker to parse our TypeScript sources. - "@npm//@angular/core", "@npm//@angular/common", + "@npm//@angular/core", + "@npm//@angular/common", "@npm//@angular/forms", "@npm//@angular/animations", "@npm//@angular/platform-browser", From 3b68126c624f19b5784cfc5a8d4094ac6ad8da82 Mon Sep 17 00:00:00 2001 From: Pei Wang Date: Thu, 9 Dec 2021 19:01:06 +0000 Subject: [PATCH 3/3] fixup! ci: Add tsec_test for all ng_module targets. --- goldens/BUILD.bazel | 1 + goldens/tsec-exemption.json | 17 +++++++++++++++++ src/BUILD.bazel | 2 +- src/cdk-experimental/BUILD.bazel | 7 ------- src/cdk/BUILD.bazel | 7 ------- src/cdk/coercion/BUILD.bazel | 7 ------- src/material-experimental/BUILD.bazel | 7 ------- src/tsconfig-tsec.json | 2 +- src/tsec-exemption.json | 17 ----------------- tools/defaults.bzl | 22 ++++++++++++++++------ 10 files changed, 36 insertions(+), 53 deletions(-) create mode 100644 goldens/tsec-exemption.json delete mode 100644 src/tsec-exemption.json diff --git a/goldens/BUILD.bazel b/goldens/BUILD.bazel index e8a75f0d5692..16bac4c0e639 100644 --- a/goldens/BUILD.bazel +++ b/goldens/BUILD.bazel @@ -1,3 +1,4 @@ exports_files([ "size-test.yaml", + "tsec-exemption.json", ]) diff --git a/goldens/tsec-exemption.json b/goldens/tsec-exemption.json new file mode 100644 index 000000000000..17bc2283c356 --- /dev/null +++ b/goldens/tsec-exemption.json @@ -0,0 +1,17 @@ +{ + "ban-trustedtypes-createpolicy": [ + "../src/material/icon/trusted-types.ts" + ], + "ban-element-innerhtml-assignments": [ + "../src/material/icon/icon-registry.ts" + ], + "ban-element-setattribute": [ + "../src/cdk/a11y/aria-describer/aria-reference.ts", + "../src/material-experimental/mdc-checkbox/checkbox.ts", + "../src/material-experimental/mdc-list/interactive-list-base.ts", + "../src/material-experimental/mdc-progress-spinner/progress-spinner.ts", + "../src/material-experimental/mdc-slide-toggle/slide-toggle.ts", + "../src/material/icon/icon-registry.ts", + "../src/material/icon/icon.ts" + ] +} diff --git a/src/BUILD.bazel b/src/BUILD.bazel index a58deea08198..5bd9ad3bf60e 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -55,6 +55,6 @@ ts_config( src = "tsconfig-tsec.json", deps = [ ":bazel-tsconfig-build.json", - ":tsec-exemption.json", + "//goldens:tsec-exemption.json", ], ) diff --git a/src/cdk-experimental/BUILD.bazel b/src/cdk-experimental/BUILD.bazel index cfa3426bd3c3..f9804d89bcb9 100644 --- a/src/cdk-experimental/BUILD.bazel +++ b/src/cdk-experimental/BUILD.bazel @@ -1,6 +1,5 @@ load("//src/cdk-experimental:config.bzl", "CDK_EXPERIMENTAL_TARGETS") load("//tools:defaults.bzl", "ng_package", "ts_library") -load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -13,12 +12,6 @@ ts_library( deps = ["@npm//@angular/core"], ) -tsec_test( - name = "cdk-experimental_tsec_test", - target = "cdk-experimental", - tsconfig = "//src:tsec_config", -) - ng_package( name = "npm_package", srcs = ["package.json"], diff --git a/src/cdk/BUILD.bazel b/src/cdk/BUILD.bazel index 31bdf2ea9466..5d254c5a4a94 100644 --- a/src/cdk/BUILD.bazel +++ b/src/cdk/BUILD.bazel @@ -1,6 +1,5 @@ load("//src/cdk:config.bzl", "CDK_ENTRYPOINTS", "CDK_ENTRYPOINTS_WITH_STYLES", "CDK_SCSS_LIBS", "CDK_TARGETS") load("//tools:defaults.bzl", "ng_package", "sass_library", "ts_library") -load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -13,12 +12,6 @@ ts_library( deps = ["@npm//@angular/core"], ) -tsec_test( - name = "cdk_tsec_test", - target = "cdk", - tsconfig = "//src:tsec_config", -) - # List of style files that need to be copied to the root of the CDK package. We do this # to make it easier for developers to import these styles without needing to know about # deep imports in the release output. Note that this is done for backwards compatibility diff --git a/src/cdk/coercion/BUILD.bazel b/src/cdk/coercion/BUILD.bazel index 9fef0747e06b..c6887bee13c6 100644 --- a/src/cdk/coercion/BUILD.bazel +++ b/src/cdk/coercion/BUILD.bazel @@ -1,5 +1,4 @@ load("//tools:defaults.bzl", "karma_web_test_suite", "markdown_to_html", "ts_library") -load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -14,12 +13,6 @@ ts_library( ], ) -tsec_test( - name = "coercion_tsec_test", - target = "coercion", - tsconfig = "//src:tsec_config", -) - ts_library( name = "unit_test_sources", testonly = True, diff --git a/src/material-experimental/BUILD.bazel b/src/material-experimental/BUILD.bazel index 4acf824fa7be..fabb2dc7df0a 100644 --- a/src/material-experimental/BUILD.bazel +++ b/src/material-experimental/BUILD.bazel @@ -5,7 +5,6 @@ load( "MATERIAL_EXPERIMENTAL_TESTING_TARGETS", ) load("//tools:defaults.bzl", "ng_package", "sass_library", "ts_library") -load("@npm//tsec:index.bzl", "tsec_test") package(default_visibility = ["//visibility:public"]) @@ -18,12 +17,6 @@ ts_library( deps = ["@npm//@angular/core"], ) -tsec_test( - name = "material-experimental_tsec_test", - target = "material-experimental", - tsconfig = "//src:tsec_config", -) - sass_library( name = "theming_scss_lib", srcs = MATERIAL_EXPERIMENTAL_SCSS_LIBS + [ diff --git a/src/tsconfig-tsec.json b/src/tsconfig-tsec.json index fdc0baa8fbb2..e397df4d2315 100644 --- a/src/tsconfig-tsec.json +++ b/src/tsconfig-tsec.json @@ -2,7 +2,7 @@ "extends": "./bazel-tsconfig-build.json", "compilerOptions": { "plugins": [ - {"name": "tsec", "exemptionConfig": "./tsec-exemption.json"} + {"name": "tsec", "exemptionConfig": "../goldens/tsec-exemption.json"} ] } } diff --git a/src/tsec-exemption.json b/src/tsec-exemption.json deleted file mode 100644 index b8d1bf827d62..000000000000 --- a/src/tsec-exemption.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ban-trustedtypes-createpolicy": [ - "material/icon/trusted-types.ts" - ], - "ban-element-innerhtml-assignments": [ - "material/icon/icon-registry.ts" - ], - "ban-element-setattribute": [ - "cdk/a11y/aria-describer/aria-reference.ts", - "material-experimental/mdc-checkbox/checkbox.ts", - "material-experimental/mdc-list/interactive-list-base.ts", - "material-experimental/mdc-progress-spinner/progress-spinner.ts", - "material-experimental/mdc-slide-toggle/slide-toggle.ts", - "material/icon/icon-registry.ts", - "material/icon/icon.ts" - ] -} diff --git a/tools/defaults.bzl b/tools/defaults.bzl index 88f7e7e0a516..68d308af1efa 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -32,6 +32,17 @@ integration_test = _integration_test esbuild = _esbuild esbuild_config = _esbuild_config +def _make_tsec_test(target): + package_name = native.package_name() + if not package_name.startswith("src/components-examples") and \ + not package_name.endswith("/testing") and \ + not package_name.endswith("/schematics"): + _tsec_test( + name = target + "_tsec_test", + target = target, + tsconfig = "//src:tsec_config", + ) + def _compute_module_name(testonly): current_pkg = native.package_name() @@ -110,6 +121,9 @@ def ts_library( **kwargs ) + if module_name and not testonly: + _make_tsec_test(kwargs["name"]) + def ng_module( deps = [], srcs = [], @@ -148,12 +162,8 @@ def ng_module( **kwargs ) - if not testonly: - _tsec_test( - name = kwargs["name"] + "_tsec_test", - target = kwargs["name"], - tsconfig = "//src:tsec_config", - ) + if module_name and not testonly: + _make_tsec_test(kwargs["name"]) def ng_package(name, data = [], deps = [], externals = PKG_EXTERNALS, readme_md = None, visibility = None, **kwargs): # If no readme file has been specified explicitly, use the default readme for