@backstage/plugin-techdocs-node 1.14.3 → 1.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,53 @@
|
|
|
1
1
|
# @backstage/plugin-techdocs-node
|
|
2
2
|
|
|
3
|
-
## 1.14.
|
|
3
|
+
## 1.14.4
|
|
4
4
|
|
|
5
5
|
### Patch Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- cb7c6b1: Added `techdocs.generator.mkdocs.dangerouslyAllowAdditionalKeys` configuration option to explicitly bypass MkDocs configuration key restrictions. This enables support for additional MkDocs configuration keys beyond the default safe allow list, such as the `hooks` key which some MkDocs plugins require.
|
|
8
|
+
- e96f6d9: Removed `INHERIT` from the `ALLOWED_MKDOCS_KEYS` set to address a security concern with MkDocs configuration inheritance.
|
|
8
9
|
- Updated dependencies
|
|
9
|
-
- @backstage/
|
|
10
|
+
- @backstage/backend-plugin-api@1.8.0
|
|
11
|
+
- @backstage/integration@2.0.0
|
|
12
|
+
- @backstage/catalog-model@1.7.7
|
|
13
|
+
|
|
14
|
+
## 1.14.4-next.2
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- e96f6d9: Removed `INHERIT` from the `ALLOWED_MKDOCS_KEYS` set to address a security concern with MkDocs configuration inheritance.
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @backstage/backend-plugin-api@1.8.0-next.1
|
|
21
|
+
- @backstage/integration@2.0.0-next.2
|
|
22
|
+
|
|
23
|
+
## 1.14.3-next.1
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- cb7c6b1: Added `techdocs.generator.mkdocs.dangerouslyAllowAdditionalKeys` configuration option to explicitly bypass MkDocs configuration key restrictions. This enables support for additional MkDocs configuration keys beyond the default safe allow list, such as the `hooks` key which some MkDocs plugins require.
|
|
28
|
+
- Updated dependencies
|
|
29
|
+
- @backstage/integration@2.0.0-next.1
|
|
30
|
+
- @backstage/backend-plugin-api@1.7.1-next.0
|
|
31
|
+
- @backstage/catalog-model@1.7.6
|
|
32
|
+
- @backstage/config@1.3.6
|
|
33
|
+
- @backstage/errors@1.2.7
|
|
34
|
+
- @backstage/integration-aws-node@0.1.20
|
|
35
|
+
- @backstage/plugin-search-common@1.2.22
|
|
36
|
+
- @backstage/plugin-techdocs-common@0.1.1
|
|
37
|
+
|
|
38
|
+
## 1.14.3-next.0
|
|
39
|
+
|
|
40
|
+
### Patch Changes
|
|
41
|
+
|
|
42
|
+
- Updated dependencies
|
|
43
|
+
- @backstage/integration@1.21.0-next.0
|
|
44
|
+
- @backstage/backend-plugin-api@1.7.1-next.0
|
|
45
|
+
- @backstage/catalog-model@1.7.6
|
|
46
|
+
- @backstage/config@1.3.6
|
|
47
|
+
- @backstage/errors@1.2.7
|
|
48
|
+
- @backstage/integration-aws-node@0.1.20
|
|
49
|
+
- @backstage/plugin-search-common@1.2.22
|
|
50
|
+
- @backstage/plugin-techdocs-common@0.1.1
|
|
10
51
|
|
|
11
52
|
## 1.14.2
|
|
12
53
|
|
|
@@ -90,10 +90,19 @@ const patchMkdocsYmlWithPlugins = async (mkdocsYmlPath, logger, defaultPlugins =
|
|
|
90
90
|
return changesMade;
|
|
91
91
|
});
|
|
92
92
|
};
|
|
93
|
-
const sanitizeMkdocsYml = async (mkdocsYmlPath, logger) => {
|
|
93
|
+
const sanitizeMkdocsYml = async (mkdocsYmlPath, logger, additionalAllowedKeys) => {
|
|
94
94
|
await patchMkdocsFile(mkdocsYmlPath, logger, (mkdocsYml) => {
|
|
95
|
+
const allowedKeys = new Set(helpers.ALLOWED_MKDOCS_KEYS);
|
|
96
|
+
if (additionalAllowedKeys && additionalAllowedKeys.length > 0) {
|
|
97
|
+
logger.warn(
|
|
98
|
+
`DANGEROUS: Allowing additional MkDocs configuration keys beyond the default safe allowlist: ${additionalAllowedKeys.join(
|
|
99
|
+
", "
|
|
100
|
+
)}. This may introduce security vulnerabilities. Only use in trusted environments.`
|
|
101
|
+
);
|
|
102
|
+
additionalAllowedKeys.forEach((key) => allowedKeys.add(key));
|
|
103
|
+
}
|
|
95
104
|
const removedKeys = Object.keys(mkdocsYml).filter(
|
|
96
|
-
(key) => !
|
|
105
|
+
(key) => !allowedKeys.has(key)
|
|
97
106
|
);
|
|
98
107
|
if (removedKeys.length > 0) {
|
|
99
108
|
logger.warn(
|
|
@@ -103,7 +112,7 @@ const sanitizeMkdocsYml = async (mkdocsYmlPath, logger) => {
|
|
|
103
112
|
);
|
|
104
113
|
}
|
|
105
114
|
const sanitized = {};
|
|
106
|
-
for (const key of
|
|
115
|
+
for (const key of allowedKeys) {
|
|
107
116
|
if (key in mkdocsYml) {
|
|
108
117
|
sanitized[key] = mkdocsYml[key];
|
|
109
118
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mkdocsPatchers.cjs.js","sources":["../../../src/stages/generate/mkdocsPatchers.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport fs from 'fs-extra';\nimport yaml from 'js-yaml';\nimport { ParsedLocationAnnotation } from '../../helpers';\nimport {\n ALLOWED_MKDOCS_KEYS,\n getRepoUrlFromLocationAnnotation,\n MKDOCS_SCHEMA,\n} from './helpers';\nimport { assertError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype MkDocsObject = {\n plugins?: string[];\n docs_dir: string;\n repo_url?: string;\n edit_uri?: string;\n};\n\nconst patchMkdocsFile = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n updateAction: (mkdocsYml: MkDocsObject) => boolean,\n) => {\n // We only want to override the mkdocs.yml if it has actually changed. This is relevant if\n // used with a 'dir' location on the file system as this would permanently update the file.\n let didEdit = false;\n\n let mkdocsYmlFileString;\n try {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not read MkDocs YAML config file ${mkdocsYmlPath} before running the generator: ${error.message}`,\n );\n return;\n }\n\n let mkdocsYml: any;\n try {\n mkdocsYml = yaml.load(mkdocsYmlFileString, { schema: MKDOCS_SCHEMA });\n\n // mkdocsYml should be an object type after successful parsing.\n // But based on its type definition, it can also be a string or undefined, which we don't want.\n if (typeof mkdocsYml === 'string' || typeof mkdocsYml === 'undefined') {\n throw new Error('Bad YAML format.');\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Error in parsing YAML at ${mkdocsYmlPath} before running the generator. ${error.message}`,\n );\n return;\n }\n\n didEdit = updateAction(mkdocsYml);\n\n try {\n if (didEdit) {\n await fs.writeFile(\n mkdocsYmlPath,\n yaml.dump(mkdocsYml, { schema: MKDOCS_SCHEMA }),\n 'utf8',\n );\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not write to ${mkdocsYmlPath} after updating it before running the generator. ${error.message}`,\n );\n return;\n }\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add repo_url or edit_uri if it does not exists\n * If mkdocs.yml has a repo_url, the generated docs site gets an Edit button on the pages by default.\n * If repo_url is missing in mkdocs.yml, we will use techdocs annotation of the entity to possibly get\n * the repository URL.\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param parsedLocationAnnotation - Object with location url and type\n * @param scmIntegrations - the scmIntegration to do url transformations\n */\nexport const patchMkdocsYmlPreBuild = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n parsedLocationAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n if (!('repo_url' in mkdocsYml) || !('edit_uri' in mkdocsYml)) {\n // Add edit_uri and/or repo_url to mkdocs.yml if it is missing.\n // This will enable the Page edit button generated by MkDocs.\n // If the either has been set, keep the original value\n const result = getRepoUrlFromLocationAnnotation(\n parsedLocationAnnotation,\n scmIntegrations,\n mkdocsYml.docs_dir,\n );\n\n if (result.repo_url || result.edit_uri) {\n mkdocsYml.repo_url = mkdocsYml.repo_url || result.repo_url;\n mkdocsYml.edit_uri = mkdocsYml.edit_uri || result.edit_uri;\n\n logger.info(\n `Set ${JSON.stringify(\n result,\n )}. You can disable this feature by manually setting 'repo_url' or 'edit_uri' according to the MkDocs documentation at https://www.mkdocs.org/user-guide/configuration/#repo_url`,\n );\n return true;\n }\n }\n return false;\n });\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add all provided default plugins\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param defaultPlugins - List of default mkdocs plugins\n */\nexport const patchMkdocsYmlWithPlugins = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n defaultPlugins: string[] = ['techdocs-core'],\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n // Modify mkdocs.yaml to contain the required default plugins.\n // If no plugins are defined we can just return the defaults.\n if (!('plugins' in mkdocsYml)) {\n mkdocsYml.plugins = defaultPlugins;\n return true;\n }\n\n // Otherwise, check each default plugin and include it if necessary.\n let changesMade = false;\n\n defaultPlugins.forEach(dp => {\n // if the plugin isn't there as a string, and isn't there as an object (which may itself contain extra config)\n // then we need to add it\n if (\n !(\n mkdocsYml.plugins!.includes(dp) ||\n mkdocsYml.plugins!.some(p => p.hasOwnProperty(dp))\n )\n ) {\n mkdocsYml.plugins = [...new Set([...mkdocsYml.plugins!, dp])];\n changesMade = true;\n }\n });\n\n return changesMade;\n });\n};\n\n/**\n * Sanitize mkdocs.yml by keeping only allowed configuration keys.\n *\n * TechDocs only supports a subset of MkDocs configuration options.\n * This function reconstructs the config with only allowed keys,\n * discarding everything else. This approach ensures that any unknown\n * or potentially dangerous configuration options are not passed to MkDocs.\n *\n * The file is always rewritten to ensure YAML features like merge keys\n * and anchors are resolved into plain configuration.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n */\nexport const sanitizeMkdocsYml = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n // Identify keys that will be removed for logging\n const removedKeys = Object.keys(mkdocsYml).filter(\n key => !ALLOWED_MKDOCS_KEYS.has(key),\n );\n\n if (removedKeys.length > 0) {\n logger.warn(\n `Removed the following unsupported configuration keys from mkdocs.yml: ${removedKeys.join(\n ', ',\n )}. ` +\n `TechDocs only supports a subset of MkDocs configuration options.`,\n );\n }\n\n // Build a new object with only allowed keys\n const sanitized: Record<string, unknown> = {};\n for (const key of ALLOWED_MKDOCS_KEYS) {\n if (key in mkdocsYml) {\n sanitized[key] = (mkdocsYml as Record<string, unknown>)[key];\n }\n }\n\n // Clear the original object and copy sanitized values back\n for (const key of Object.keys(mkdocsYml)) {\n delete (mkdocsYml as Record<string, unknown>)[key];\n }\n Object.assign(mkdocsYml, sanitized);\n\n // Always rewrite to ensure clean YAML output (resolves merge keys, anchors, etc.)\n return true;\n });\n};\n"],"names":["fs","assertError","yaml","MKDOCS_SCHEMA","getRepoUrlFromLocationAnnotation","ALLOWED_MKDOCS_KEYS"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mkdocsPatchers.cjs.js","sources":["../../../src/stages/generate/mkdocsPatchers.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport fs from 'fs-extra';\nimport yaml from 'js-yaml';\nimport { ParsedLocationAnnotation } from '../../helpers';\nimport {\n ALLOWED_MKDOCS_KEYS,\n getRepoUrlFromLocationAnnotation,\n MKDOCS_SCHEMA,\n} from './helpers';\nimport { assertError } from '@backstage/errors';\nimport { ScmIntegrationRegistry } from '@backstage/integration';\nimport { LoggerService } from '@backstage/backend-plugin-api';\n\ntype MkDocsObject = {\n plugins?: string[];\n docs_dir: string;\n repo_url?: string;\n edit_uri?: string;\n};\n\nconst patchMkdocsFile = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n updateAction: (mkdocsYml: MkDocsObject) => boolean,\n) => {\n // We only want to override the mkdocs.yml if it has actually changed. This is relevant if\n // used with a 'dir' location on the file system as this would permanently update the file.\n let didEdit = false;\n\n let mkdocsYmlFileString;\n try {\n mkdocsYmlFileString = await fs.readFile(mkdocsYmlPath, 'utf8');\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not read MkDocs YAML config file ${mkdocsYmlPath} before running the generator: ${error.message}`,\n );\n return;\n }\n\n let mkdocsYml: any;\n try {\n mkdocsYml = yaml.load(mkdocsYmlFileString, { schema: MKDOCS_SCHEMA });\n\n // mkdocsYml should be an object type after successful parsing.\n // But based on its type definition, it can also be a string or undefined, which we don't want.\n if (typeof mkdocsYml === 'string' || typeof mkdocsYml === 'undefined') {\n throw new Error('Bad YAML format.');\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Error in parsing YAML at ${mkdocsYmlPath} before running the generator. ${error.message}`,\n );\n return;\n }\n\n didEdit = updateAction(mkdocsYml);\n\n try {\n if (didEdit) {\n await fs.writeFile(\n mkdocsYmlPath,\n yaml.dump(mkdocsYml, { schema: MKDOCS_SCHEMA }),\n 'utf8',\n );\n }\n } catch (error) {\n assertError(error);\n logger.warn(\n `Could not write to ${mkdocsYmlPath} after updating it before running the generator. ${error.message}`,\n );\n return;\n }\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add repo_url or edit_uri if it does not exists\n * If mkdocs.yml has a repo_url, the generated docs site gets an Edit button on the pages by default.\n * If repo_url is missing in mkdocs.yml, we will use techdocs annotation of the entity to possibly get\n * the repository URL.\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param parsedLocationAnnotation - Object with location url and type\n * @param scmIntegrations - the scmIntegration to do url transformations\n */\nexport const patchMkdocsYmlPreBuild = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n parsedLocationAnnotation: ParsedLocationAnnotation,\n scmIntegrations: ScmIntegrationRegistry,\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n if (!('repo_url' in mkdocsYml) || !('edit_uri' in mkdocsYml)) {\n // Add edit_uri and/or repo_url to mkdocs.yml if it is missing.\n // This will enable the Page edit button generated by MkDocs.\n // If the either has been set, keep the original value\n const result = getRepoUrlFromLocationAnnotation(\n parsedLocationAnnotation,\n scmIntegrations,\n mkdocsYml.docs_dir,\n );\n\n if (result.repo_url || result.edit_uri) {\n mkdocsYml.repo_url = mkdocsYml.repo_url || result.repo_url;\n mkdocsYml.edit_uri = mkdocsYml.edit_uri || result.edit_uri;\n\n logger.info(\n `Set ${JSON.stringify(\n result,\n )}. You can disable this feature by manually setting 'repo_url' or 'edit_uri' according to the MkDocs documentation at https://www.mkdocs.org/user-guide/configuration/#repo_url`,\n );\n return true;\n }\n }\n return false;\n });\n};\n\n/**\n * Update the mkdocs.yml file before TechDocs generator uses it to generate docs site.\n *\n * List of tasks:\n * - Add all provided default plugins\n *\n * This function will not throw an error since this is not critical to the whole TechDocs pipeline.\n * Instead it will log warnings if there are any errors in reading, parsing or writing YAML.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param defaultPlugins - List of default mkdocs plugins\n */\nexport const patchMkdocsYmlWithPlugins = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n defaultPlugins: string[] = ['techdocs-core'],\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n // Modify mkdocs.yaml to contain the required default plugins.\n // If no plugins are defined we can just return the defaults.\n if (!('plugins' in mkdocsYml)) {\n mkdocsYml.plugins = defaultPlugins;\n return true;\n }\n\n // Otherwise, check each default plugin and include it if necessary.\n let changesMade = false;\n\n defaultPlugins.forEach(dp => {\n // if the plugin isn't there as a string, and isn't there as an object (which may itself contain extra config)\n // then we need to add it\n if (\n !(\n mkdocsYml.plugins!.includes(dp) ||\n mkdocsYml.plugins!.some(p => p.hasOwnProperty(dp))\n )\n ) {\n mkdocsYml.plugins = [...new Set([...mkdocsYml.plugins!, dp])];\n changesMade = true;\n }\n });\n\n return changesMade;\n });\n};\n\n/**\n * Sanitize mkdocs.yml by keeping only allowed configuration keys.\n *\n * TechDocs only supports a subset of MkDocs configuration options.\n * This function reconstructs the config with only allowed keys,\n * discarding everything else. This approach ensures that any unknown\n * or potentially dangerous configuration options are not passed to MkDocs.\n *\n * The file is always rewritten to ensure YAML features like merge keys\n * and anchors are resolved into plain configuration.\n *\n * @param mkdocsYmlPath - Absolute path to mkdocs.yml or equivalent of a docs site\n * @param logger - A logger instance\n * @param additionalAllowedKeys - Optional array of additional keys to allow beyond the default allowlist\n */\nexport const sanitizeMkdocsYml = async (\n mkdocsYmlPath: string,\n logger: LoggerService,\n additionalAllowedKeys?: string[],\n) => {\n await patchMkdocsFile(mkdocsYmlPath, logger, mkdocsYml => {\n // Combine default allowed keys with additional keys\n const allowedKeys = new Set(ALLOWED_MKDOCS_KEYS);\n if (additionalAllowedKeys && additionalAllowedKeys.length > 0) {\n logger.warn(\n `DANGEROUS: Allowing additional MkDocs configuration keys beyond the default safe allowlist: ${additionalAllowedKeys.join(\n ', ',\n )}. This may introduce security vulnerabilities. Only use in trusted environments.`,\n );\n additionalAllowedKeys.forEach(key => allowedKeys.add(key));\n }\n\n // Identify keys that will be removed for logging\n const removedKeys = Object.keys(mkdocsYml).filter(\n key => !allowedKeys.has(key),\n );\n\n if (removedKeys.length > 0) {\n logger.warn(\n `Removed the following unsupported configuration keys from mkdocs.yml: ${removedKeys.join(\n ', ',\n )}. ` +\n `TechDocs only supports a subset of MkDocs configuration options.`,\n );\n }\n\n // Build a new object with only allowed keys\n const sanitized: Record<string, unknown> = {};\n for (const key of allowedKeys) {\n if (key in mkdocsYml) {\n sanitized[key] = (mkdocsYml as Record<string, unknown>)[key];\n }\n }\n\n // Clear the original object and copy sanitized values back\n for (const key of Object.keys(mkdocsYml)) {\n delete (mkdocsYml as Record<string, unknown>)[key];\n }\n Object.assign(mkdocsYml, sanitized);\n\n // Always rewrite to ensure clean YAML output (resolves merge keys, anchors, etc.)\n return true;\n });\n};\n"],"names":["fs","assertError","yaml","MKDOCS_SCHEMA","getRepoUrlFromLocationAnnotation","ALLOWED_MKDOCS_KEYS"],"mappings":"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"}
|
|
@@ -61,7 +61,11 @@ class TechdocsGenerator {
|
|
|
61
61
|
siteOptions
|
|
62
62
|
);
|
|
63
63
|
const docsDir = await helpers.validateMkdocsYaml(inputDir, content);
|
|
64
|
-
await mkdocsPatchers.sanitizeMkdocsYml(
|
|
64
|
+
await mkdocsPatchers.sanitizeMkdocsYml(
|
|
65
|
+
mkdocsYmlPath,
|
|
66
|
+
childLogger,
|
|
67
|
+
this.options.dangerouslyAllowAdditionalKeys
|
|
68
|
+
);
|
|
65
69
|
const resolvedDocsDir = path__default.default.join(inputDir, docsDir ?? "docs");
|
|
66
70
|
await helpers.validateDocsDirectory(resolvedDocsDir, inputDir);
|
|
67
71
|
if (parsedLocationAnnotation) {
|
|
@@ -165,6 +169,9 @@ function readGeneratorConfig(config, logger) {
|
|
|
165
169
|
),
|
|
166
170
|
defaultPlugins: config.getOptionalStringArray(
|
|
167
171
|
"techdocs.generator.mkdocs.defaultPlugins"
|
|
172
|
+
),
|
|
173
|
+
dangerouslyAllowAdditionalKeys: config.getOptionalStringArray(
|
|
174
|
+
"techdocs.generator.mkdocs.dangerouslyAllowAdditionalKeys"
|
|
168
175
|
)
|
|
169
176
|
};
|
|
170
177
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"techdocs.cjs.js","sources":["../../../src/stages/generate/techdocs.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport path from 'node:path';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n createOrUpdateMetadata,\n getMkdocsYml,\n patchIndexPreBuild,\n runCommand,\n storeEtagMetadata,\n validateDocsDirectory,\n validateMkdocsYaml,\n} from './helpers';\n\nimport {\n patchMkdocsYmlPreBuild,\n patchMkdocsYmlWithPlugins,\n sanitizeMkdocsYml,\n} from './mkdocsPatchers';\nimport {\n GeneratorBase,\n GeneratorConfig,\n GeneratorOptions,\n GeneratorRunInType,\n GeneratorRunOptions,\n} from './types';\nimport { ForwardedError } from '@backstage/errors';\nimport { DockerContainerRunner } from './DockerContainerRunner';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { TechDocsContainerRunner } from './types';\n\n/**\n * Generates documentation files\n * @public\n */\nexport class TechdocsGenerator implements GeneratorBase {\n /**\n * The default docker image (and version) used to generate content. Public\n * and static so that techdocs-node consumers can use the same version.\n *\n * See {@link https://hub.docker.com/r/spotify/techdocs/tags} for list of available versions.\n */\n public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.8';\n private readonly logger: LoggerService;\n private readonly containerRunner?: TechDocsContainerRunner;\n private readonly options: GeneratorConfig;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n\n /**\n * Returns a instance of TechDocs generator\n * @param config - A Backstage configuration\n * @param options - Options to configure the generator\n */\n static fromConfig(config: Config, options: GeneratorOptions) {\n const { containerRunner, logger } = options;\n const scmIntegrations = ScmIntegrations.fromConfig(config);\n return new TechdocsGenerator({\n logger,\n containerRunner,\n config,\n scmIntegrations,\n });\n }\n\n constructor(options: {\n logger: LoggerService;\n containerRunner?: TechDocsContainerRunner;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n }) {\n this.logger = options.logger;\n this.options = readGeneratorConfig(options.config, options.logger);\n this.containerRunner = options.containerRunner;\n this.scmIntegrations = options.scmIntegrations;\n }\n\n /** {@inheritDoc GeneratorBase.run} */\n public async run(options: GeneratorRunOptions): Promise<void> {\n const {\n inputDir,\n outputDir,\n parsedLocationAnnotation,\n etag,\n logger: childLogger,\n logStream,\n siteOptions,\n runAsDefaultUser,\n } = options;\n\n // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url\n const { path: mkdocsYmlPath, content } = await getMkdocsYml(\n inputDir,\n siteOptions,\n );\n\n // validate the docs_dir first\n const docsDir = await validateMkdocsYaml(inputDir, content);\n\n // Remove unsupported configuration keys\n await sanitizeMkdocsYml(mkdocsYmlPath, childLogger);\n\n // Validate that no symlinks in the docs directory point outside the input directory\n // This prevents path traversal attacks where malicious symlinks could leak host files\n const resolvedDocsDir = path.join(inputDir, docsDir ?? 'docs');\n await validateDocsDirectory(resolvedDocsDir, inputDir);\n\n if (parsedLocationAnnotation) {\n await patchMkdocsYmlPreBuild(\n mkdocsYmlPath,\n childLogger,\n parsedLocationAnnotation,\n this.scmIntegrations,\n );\n }\n\n if (this.options.legacyCopyReadmeMdToIndexMd) {\n await patchIndexPreBuild({ inputDir, logger: childLogger, docsDir });\n }\n\n // patch the list of mkdocs plugins\n const defaultPlugins = this.options.defaultPlugins ?? [];\n\n if (\n !this.options.omitTechdocsCoreMkdocsPlugin &&\n !defaultPlugins.includes('techdocs-core')\n ) {\n defaultPlugins.push('techdocs-core');\n }\n\n await patchMkdocsYmlWithPlugins(mkdocsYmlPath, childLogger, defaultPlugins);\n\n // Directories to bind on container\n const mountDirs = {\n [inputDir]: '/input',\n [outputDir]: '/output',\n };\n\n try {\n switch (this.options.runIn) {\n case 'local':\n await runCommand({\n command: 'mkdocs',\n args: ['build', '-d', outputDir, '-v'],\n options: {\n cwd: inputDir,\n },\n logStream,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using local mkdocs`,\n );\n break;\n case 'docker': {\n const containerRunner =\n this.containerRunner || new DockerContainerRunner();\n await containerRunner.runContainer({\n imageName:\n this.options.dockerImage ?? TechdocsGenerator.defaultDockerImage,\n args: ['build', '-d', '/output'],\n logStream,\n mountDirs,\n workingDir: '/input',\n // Set the home directory inside the container as something that applications can\n // write to, otherwise they will just fail trying to write to /\n envVars: { HOME: '/tmp' },\n pullImage: this.options.pullImage,\n defaultUser: runAsDefaultUser,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using techdocs-container`,\n );\n break;\n }\n default:\n throw new Error(\n `Invalid config value \"${this.options.runIn}\" provided in 'techdocs.generators.techdocs'.`,\n );\n }\n } catch (error) {\n this.logger.debug(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n );\n throw new ForwardedError(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n error,\n );\n }\n\n /**\n * Post Generate steps\n */\n\n // Add build timestamp and files to techdocs_metadata.json\n // Creates techdocs_metadata.json if file does not exist.\n await createOrUpdateMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n childLogger,\n );\n\n // Add etag of the prepared tree to techdocs_metadata.json\n // Assumes that the file already exists.\n if (etag) {\n await storeEtagMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n etag,\n );\n }\n }\n}\n\nexport function readGeneratorConfig(\n config: Config,\n logger: LoggerService,\n): GeneratorConfig {\n const legacyGeneratorType = config.getOptionalString(\n 'techdocs.generators.techdocs',\n ) as GeneratorRunInType;\n\n if (legacyGeneratorType) {\n logger.warn(\n `The 'techdocs.generators.techdocs' configuration key is deprecated and will be removed in the future. Please use 'techdocs.generator' instead. ` +\n `See here https://backstage.io/docs/features/techdocs/configuration`,\n );\n }\n\n return {\n runIn:\n legacyGeneratorType ??\n config.getOptionalString('techdocs.generator.runIn') ??\n 'docker',\n dockerImage: config.getOptionalString('techdocs.generator.dockerImage'),\n pullImage: config.getOptionalBoolean('techdocs.generator.pullImage'),\n omitTechdocsCoreMkdocsPlugin: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.omitTechdocsCorePlugin',\n ),\n legacyCopyReadmeMdToIndexMd: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.legacyCopyReadmeMdToIndexMd',\n ),\n defaultPlugins: config.getOptionalStringArray(\n 'techdocs.generator.mkdocs.defaultPlugins',\n ),\n };\n}\n"],"names":["ScmIntegrations","getMkdocsYml","validateMkdocsYaml","sanitizeMkdocsYml","path","validateDocsDirectory","patchMkdocsYmlPreBuild","patchIndexPreBuild","patchMkdocsYmlWithPlugins","runCommand","DockerContainerRunner","ForwardedError","createOrUpdateMetadata","storeEtagMetadata"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"techdocs.cjs.js","sources":["../../../src/stages/generate/techdocs.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport path from 'node:path';\nimport {\n ScmIntegrationRegistry,\n ScmIntegrations,\n} from '@backstage/integration';\nimport {\n createOrUpdateMetadata,\n getMkdocsYml,\n patchIndexPreBuild,\n runCommand,\n storeEtagMetadata,\n validateDocsDirectory,\n validateMkdocsYaml,\n} from './helpers';\n\nimport {\n patchMkdocsYmlPreBuild,\n patchMkdocsYmlWithPlugins,\n sanitizeMkdocsYml,\n} from './mkdocsPatchers';\nimport {\n GeneratorBase,\n GeneratorConfig,\n GeneratorOptions,\n GeneratorRunInType,\n GeneratorRunOptions,\n} from './types';\nimport { ForwardedError } from '@backstage/errors';\nimport { DockerContainerRunner } from './DockerContainerRunner';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { TechDocsContainerRunner } from './types';\n\n/**\n * Generates documentation files\n * @public\n */\nexport class TechdocsGenerator implements GeneratorBase {\n /**\n * The default docker image (and version) used to generate content. Public\n * and static so that techdocs-node consumers can use the same version.\n *\n * See {@link https://hub.docker.com/r/spotify/techdocs/tags} for list of available versions.\n */\n public static readonly defaultDockerImage = 'spotify/techdocs:v1.2.8';\n private readonly logger: LoggerService;\n private readonly containerRunner?: TechDocsContainerRunner;\n private readonly options: GeneratorConfig;\n private readonly scmIntegrations: ScmIntegrationRegistry;\n\n /**\n * Returns a instance of TechDocs generator\n * @param config - A Backstage configuration\n * @param options - Options to configure the generator\n */\n static fromConfig(config: Config, options: GeneratorOptions) {\n const { containerRunner, logger } = options;\n const scmIntegrations = ScmIntegrations.fromConfig(config);\n return new TechdocsGenerator({\n logger,\n containerRunner,\n config,\n scmIntegrations,\n });\n }\n\n constructor(options: {\n logger: LoggerService;\n containerRunner?: TechDocsContainerRunner;\n config: Config;\n scmIntegrations: ScmIntegrationRegistry;\n }) {\n this.logger = options.logger;\n this.options = readGeneratorConfig(options.config, options.logger);\n this.containerRunner = options.containerRunner;\n this.scmIntegrations = options.scmIntegrations;\n }\n\n /** {@inheritDoc GeneratorBase.run} */\n public async run(options: GeneratorRunOptions): Promise<void> {\n const {\n inputDir,\n outputDir,\n parsedLocationAnnotation,\n etag,\n logger: childLogger,\n logStream,\n siteOptions,\n runAsDefaultUser,\n } = options;\n\n // Do some updates to mkdocs.yml before generating docs e.g. adding repo_url\n const { path: mkdocsYmlPath, content } = await getMkdocsYml(\n inputDir,\n siteOptions,\n );\n\n // validate the docs_dir first\n const docsDir = await validateMkdocsYaml(inputDir, content);\n\n // Remove unsupported configuration keys\n await sanitizeMkdocsYml(\n mkdocsYmlPath,\n childLogger,\n this.options.dangerouslyAllowAdditionalKeys,\n );\n\n // Validate that no symlinks in the docs directory point outside the input directory\n // This prevents path traversal attacks where malicious symlinks could leak host files\n const resolvedDocsDir = path.join(inputDir, docsDir ?? 'docs');\n await validateDocsDirectory(resolvedDocsDir, inputDir);\n\n if (parsedLocationAnnotation) {\n await patchMkdocsYmlPreBuild(\n mkdocsYmlPath,\n childLogger,\n parsedLocationAnnotation,\n this.scmIntegrations,\n );\n }\n\n if (this.options.legacyCopyReadmeMdToIndexMd) {\n await patchIndexPreBuild({ inputDir, logger: childLogger, docsDir });\n }\n\n // patch the list of mkdocs plugins\n const defaultPlugins = this.options.defaultPlugins ?? [];\n\n if (\n !this.options.omitTechdocsCoreMkdocsPlugin &&\n !defaultPlugins.includes('techdocs-core')\n ) {\n defaultPlugins.push('techdocs-core');\n }\n\n await patchMkdocsYmlWithPlugins(mkdocsYmlPath, childLogger, defaultPlugins);\n\n // Directories to bind on container\n const mountDirs = {\n [inputDir]: '/input',\n [outputDir]: '/output',\n };\n\n try {\n switch (this.options.runIn) {\n case 'local':\n await runCommand({\n command: 'mkdocs',\n args: ['build', '-d', outputDir, '-v'],\n options: {\n cwd: inputDir,\n },\n logStream,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using local mkdocs`,\n );\n break;\n case 'docker': {\n const containerRunner =\n this.containerRunner || new DockerContainerRunner();\n await containerRunner.runContainer({\n imageName:\n this.options.dockerImage ?? TechdocsGenerator.defaultDockerImage,\n args: ['build', '-d', '/output'],\n logStream,\n mountDirs,\n workingDir: '/input',\n // Set the home directory inside the container as something that applications can\n // write to, otherwise they will just fail trying to write to /\n envVars: { HOME: '/tmp' },\n pullImage: this.options.pullImage,\n defaultUser: runAsDefaultUser,\n });\n childLogger.info(\n `Successfully generated docs from ${inputDir} into ${outputDir} using techdocs-container`,\n );\n break;\n }\n default:\n throw new Error(\n `Invalid config value \"${this.options.runIn}\" provided in 'techdocs.generators.techdocs'.`,\n );\n }\n } catch (error) {\n this.logger.debug(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n );\n throw new ForwardedError(\n `Failed to generate docs from ${inputDir} into ${outputDir}`,\n error,\n );\n }\n\n /**\n * Post Generate steps\n */\n\n // Add build timestamp and files to techdocs_metadata.json\n // Creates techdocs_metadata.json if file does not exist.\n await createOrUpdateMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n childLogger,\n );\n\n // Add etag of the prepared tree to techdocs_metadata.json\n // Assumes that the file already exists.\n if (etag) {\n await storeEtagMetadata(\n path.join(outputDir, 'techdocs_metadata.json'),\n etag,\n );\n }\n }\n}\n\nexport function readGeneratorConfig(\n config: Config,\n logger: LoggerService,\n): GeneratorConfig {\n const legacyGeneratorType = config.getOptionalString(\n 'techdocs.generators.techdocs',\n ) as GeneratorRunInType;\n\n if (legacyGeneratorType) {\n logger.warn(\n `The 'techdocs.generators.techdocs' configuration key is deprecated and will be removed in the future. Please use 'techdocs.generator' instead. ` +\n `See here https://backstage.io/docs/features/techdocs/configuration`,\n );\n }\n\n return {\n runIn:\n legacyGeneratorType ??\n config.getOptionalString('techdocs.generator.runIn') ??\n 'docker',\n dockerImage: config.getOptionalString('techdocs.generator.dockerImage'),\n pullImage: config.getOptionalBoolean('techdocs.generator.pullImage'),\n omitTechdocsCoreMkdocsPlugin: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.omitTechdocsCorePlugin',\n ),\n legacyCopyReadmeMdToIndexMd: config.getOptionalBoolean(\n 'techdocs.generator.mkdocs.legacyCopyReadmeMdToIndexMd',\n ),\n defaultPlugins: config.getOptionalStringArray(\n 'techdocs.generator.mkdocs.defaultPlugins',\n ),\n dangerouslyAllowAdditionalKeys: config.getOptionalStringArray(\n 'techdocs.generator.mkdocs.dangerouslyAllowAdditionalKeys',\n ),\n };\n}\n"],"names":["ScmIntegrations","getMkdocsYml","validateMkdocsYaml","sanitizeMkdocsYml","path","validateDocsDirectory","patchMkdocsYmlPreBuild","patchIndexPreBuild","patchMkdocsYmlWithPlugins","runCommand","DockerContainerRunner","ForwardedError","createOrUpdateMetadata","storeEtagMetadata"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-techdocs-node",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.4",
|
|
4
4
|
"description": "Common node.js functionalities for TechDocs, to be shared between techdocs-backend plugin and techdocs-cli",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library",
|
|
@@ -53,11 +53,11 @@
|
|
|
53
53
|
"@aws-sdk/types": "^3.347.0",
|
|
54
54
|
"@azure/identity": "^4.0.0",
|
|
55
55
|
"@azure/storage-blob": "^12.5.0",
|
|
56
|
-
"@backstage/backend-plugin-api": "^1.
|
|
57
|
-
"@backstage/catalog-model": "^1.7.
|
|
56
|
+
"@backstage/backend-plugin-api": "^1.8.0",
|
|
57
|
+
"@backstage/catalog-model": "^1.7.7",
|
|
58
58
|
"@backstage/config": "^1.3.6",
|
|
59
59
|
"@backstage/errors": "^1.2.7",
|
|
60
|
-
"@backstage/integration": "^
|
|
60
|
+
"@backstage/integration": "^2.0.0",
|
|
61
61
|
"@backstage/integration-aws-node": "^0.1.20",
|
|
62
62
|
"@backstage/plugin-search-common": "^1.2.22",
|
|
63
63
|
"@backstage/plugin-techdocs-common": "^0.1.1",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
"winston": "^3.2.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@backstage/backend-test-utils": "^1.11.
|
|
82
|
-
"@backstage/cli": "^0.
|
|
81
|
+
"@backstage/backend-test-utils": "^1.11.1",
|
|
82
|
+
"@backstage/cli": "^0.36.0",
|
|
83
83
|
"@types/fs-extra": "^11.0.0",
|
|
84
84
|
"@types/js-yaml": "^4.0.0",
|
|
85
85
|
"@types/mime-types": "^2.1.0",
|