@backstage/plugin-techdocs-node 1.12.11-next.2 → 1.12.12-next.0
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 +34 -0
- package/dist/index.cjs.js +70 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +164 -165
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @backstage/plugin-techdocs-node
|
|
2
2
|
|
|
3
|
+
## 1.12.12-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-plugin-api@1.0.1-next.0
|
|
9
|
+
- @backstage/catalog-model@1.7.0
|
|
10
|
+
- @backstage/config@1.2.0
|
|
11
|
+
- @backstage/errors@1.2.4
|
|
12
|
+
- @backstage/integration@1.15.0
|
|
13
|
+
- @backstage/integration-aws-node@0.1.12
|
|
14
|
+
- @backstage/plugin-search-common@1.2.14
|
|
15
|
+
- @backstage/plugin-techdocs-common@0.1.0
|
|
16
|
+
|
|
17
|
+
## 1.12.11
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- f715f5c: Move `TechdocsContainerRunner` from `publish` to `generate`.
|
|
22
|
+
- 4417dd4: Fix typo and unify TechDocs casing in doc strings
|
|
23
|
+
- 57da51f: Add support for mapping custom tags in the techdocs yaml parser that validates the mkdocs.yaml file
|
|
24
|
+
- c2b63ab: Updated dependency `supertest` to `^7.0.0`.
|
|
25
|
+
- 3606843: Internal fixes to match `testcontainers` update
|
|
26
|
+
- 33ebb28: As the `@backstage/backend-common` package is deprecated, we have updated the `techdocs-node` package to stop depending on it.
|
|
27
|
+
- Updated dependencies
|
|
28
|
+
- @backstage/backend-plugin-api@1.0.0
|
|
29
|
+
- @backstage/catalog-model@1.7.0
|
|
30
|
+
- @backstage/integration@1.15.0
|
|
31
|
+
- @backstage/config@1.2.0
|
|
32
|
+
- @backstage/errors@1.2.4
|
|
33
|
+
- @backstage/integration-aws-node@0.1.12
|
|
34
|
+
- @backstage/plugin-search-common@1.2.14
|
|
35
|
+
- @backstage/plugin-techdocs-common@0.1.0
|
|
36
|
+
|
|
3
37
|
## 1.12.11-next.2
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -47,7 +47,29 @@ var os__default = /*#__PURE__*/_interopDefaultCompat(os);
|
|
|
47
47
|
|
|
48
48
|
const getContentTypeForExtension = (ext) => {
|
|
49
49
|
const defaultContentType = "text/plain; charset=utf-8";
|
|
50
|
-
|
|
50
|
+
const excludedTypes = [
|
|
51
|
+
"text/html",
|
|
52
|
+
"text/xml",
|
|
53
|
+
"image/svg+xml",
|
|
54
|
+
"text/xsl",
|
|
55
|
+
"application/vnd.wap.xhtml+xml",
|
|
56
|
+
"multipart/x-mixed-replace",
|
|
57
|
+
"text/rdf",
|
|
58
|
+
"application/mathml+xml",
|
|
59
|
+
"application/octet-stream",
|
|
60
|
+
"application/rdf+xml",
|
|
61
|
+
"application/xhtml+xml",
|
|
62
|
+
"application/xml",
|
|
63
|
+
"text/cache-manifest",
|
|
64
|
+
"text/vtt"
|
|
65
|
+
];
|
|
66
|
+
if (ext.match(
|
|
67
|
+
/htm|xml|svg|appcache|manifest|mathml|owl|rdf|rng|vtt|xht|xsd|xsl/i
|
|
68
|
+
)) {
|
|
69
|
+
return defaultContentType;
|
|
70
|
+
}
|
|
71
|
+
const contentType = mime__default.default.lookup(ext);
|
|
72
|
+
if (contentType && excludedTypes.includes(contentType)) {
|
|
51
73
|
return defaultContentType;
|
|
52
74
|
}
|
|
53
75
|
return mime__default.default.contentType(ext) || defaultContentType;
|
|
@@ -126,6 +148,15 @@ const bulkStorageOperation = async (operation, args, { concurrencyLimit } = { co
|
|
|
126
148
|
const limiter = createLimiter__default.default(concurrencyLimit);
|
|
127
149
|
await Promise.all(args.map((arg) => limiter(operation, arg)));
|
|
128
150
|
};
|
|
151
|
+
const isValidContentPath = (bucketRoot, contentPath) => {
|
|
152
|
+
const relativePath = path__default.default.posix.relative(bucketRoot, contentPath);
|
|
153
|
+
if (relativePath === "") {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
const outsideBase = relativePath.startsWith("..");
|
|
157
|
+
const differentDrive = path__default.default.posix.isAbsolute(relativePath);
|
|
158
|
+
return !outsideBase && !differentDrive;
|
|
159
|
+
};
|
|
129
160
|
|
|
130
161
|
function getGeneratorKey(entity) {
|
|
131
162
|
if (!entity) {
|
|
@@ -1164,6 +1195,12 @@ class AwsS3Publish {
|
|
|
1164
1195
|
const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;
|
|
1165
1196
|
const entityDir = this.legacyPathCasing ? entityTriplet : lowerCaseEntityTriplet(entityTriplet);
|
|
1166
1197
|
const entityRootDir = path__default.default.posix.join(this.bucketRootPath, entityDir);
|
|
1198
|
+
if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {
|
|
1199
|
+
this.logger.error(
|
|
1200
|
+
`Invalid content path found while fetching TechDocs metadata: ${entityRootDir}`
|
|
1201
|
+
);
|
|
1202
|
+
throw new Error(`Metadata Not Found`);
|
|
1203
|
+
}
|
|
1167
1204
|
try {
|
|
1168
1205
|
const resp = await this.storageClient.send(
|
|
1169
1206
|
new clientS3.GetObjectCommand({
|
|
@@ -1201,6 +1238,13 @@ class AwsS3Publish {
|
|
|
1201
1238
|
const decodedUri = decodeURI(req.path.replace(/^\//, ""));
|
|
1202
1239
|
const filePathNoRoot = this.legacyPathCasing ? decodedUri : lowerCaseEntityTripletInStoragePath(decodedUri);
|
|
1203
1240
|
const filePath = path__default.default.posix.join(this.bucketRootPath, filePathNoRoot);
|
|
1241
|
+
if (!isValidContentPath(this.bucketRootPath, filePath)) {
|
|
1242
|
+
this.logger.error(
|
|
1243
|
+
`Attempted to fetch TechDocs content for a file outside of the bucket root: ${filePathNoRoot}`
|
|
1244
|
+
);
|
|
1245
|
+
res.status(404).send("File Not Found");
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1204
1248
|
const fileExtension = path__default.default.extname(filePath);
|
|
1205
1249
|
const responseHeaders = getHeadersForFileExtension(fileExtension);
|
|
1206
1250
|
try {
|
|
@@ -1231,6 +1275,12 @@ class AwsS3Publish {
|
|
|
1231
1275
|
const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
|
|
1232
1276
|
const entityDir = this.legacyPathCasing ? entityTriplet : lowerCaseEntityTriplet(entityTriplet);
|
|
1233
1277
|
const entityRootDir = path__default.default.posix.join(this.bucketRootPath, entityDir);
|
|
1278
|
+
if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {
|
|
1279
|
+
this.logger.error(
|
|
1280
|
+
`Invalid content path found while checking if docs have been generated: ${entityRootDir}`
|
|
1281
|
+
);
|
|
1282
|
+
return Promise.resolve(false);
|
|
1283
|
+
}
|
|
1234
1284
|
await this.storageClient.send(
|
|
1235
1285
|
new clientS3.HeadObjectCommand({
|
|
1236
1286
|
Bucket: this.bucketName,
|
|
@@ -1843,6 +1893,12 @@ class GoogleGCSPublish {
|
|
|
1843
1893
|
const entityTriplet = `${entityName.namespace}/${entityName.kind}/${entityName.name}`;
|
|
1844
1894
|
const entityDir = this.legacyPathCasing ? entityTriplet : lowerCaseEntityTriplet(entityTriplet);
|
|
1845
1895
|
const entityRootDir = path__default.default.posix.join(this.bucketRootPath, entityDir);
|
|
1896
|
+
if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {
|
|
1897
|
+
this.logger.error(
|
|
1898
|
+
`Invalid content path found while fetching TechDocs metadata: ${entityRootDir}`
|
|
1899
|
+
);
|
|
1900
|
+
reject(new Error(`Metadata Not Found`));
|
|
1901
|
+
}
|
|
1846
1902
|
const fileStreamChunks = [];
|
|
1847
1903
|
this.storageClient.bucket(this.bucketName).file(`${entityRootDir}/techdocs_metadata.json`).createReadStream().on("error", (err) => {
|
|
1848
1904
|
this.logger.error(err.message);
|
|
@@ -1863,6 +1919,13 @@ class GoogleGCSPublish {
|
|
|
1863
1919
|
const decodedUri = decodeURI(req.path.replace(/^\//, ""));
|
|
1864
1920
|
const filePathNoRoot = this.legacyPathCasing ? decodedUri : lowerCaseEntityTripletInStoragePath(decodedUri);
|
|
1865
1921
|
const filePath = path__default.default.posix.join(this.bucketRootPath, filePathNoRoot);
|
|
1922
|
+
if (!isValidContentPath(this.bucketRootPath, filePath)) {
|
|
1923
|
+
this.logger.error(
|
|
1924
|
+
`Attempted to fetch TechDocs content for a file outside of the bucket root: ${filePathNoRoot}`
|
|
1925
|
+
);
|
|
1926
|
+
res.status(404).send("File Not Found");
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1866
1929
|
const fileExtension = path__default.default.extname(filePath);
|
|
1867
1930
|
const responseHeaders = getHeadersForFileExtension(fileExtension);
|
|
1868
1931
|
this.storageClient.bucket(this.bucketName).file(filePath).createReadStream().on("pipe", () => {
|
|
@@ -1888,6 +1951,12 @@ class GoogleGCSPublish {
|
|
|
1888
1951
|
const entityTriplet = `${entity.metadata.namespace}/${entity.kind}/${entity.metadata.name}`;
|
|
1889
1952
|
const entityDir = this.legacyPathCasing ? entityTriplet : lowerCaseEntityTriplet(entityTriplet);
|
|
1890
1953
|
const entityRootDir = path__default.default.posix.join(this.bucketRootPath, entityDir);
|
|
1954
|
+
if (!isValidContentPath(this.bucketRootPath, entityRootDir)) {
|
|
1955
|
+
this.logger.error(
|
|
1956
|
+
`Invalid content path found while checking if docs have been generated: ${entityRootDir}`
|
|
1957
|
+
);
|
|
1958
|
+
resolve(false);
|
|
1959
|
+
}
|
|
1891
1960
|
this.storageClient.bucket(this.bucketName).file(`${entityRootDir}/index.html`).exists().then((response) => {
|
|
1892
1961
|
resolve(response[0]);
|
|
1893
1962
|
}).catch(() => {
|