@backstage/backend-defaults 0.17.8 → 0.17.9-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 +22 -12
- package/dist/entrypoints/auth/JwksClient.cjs.js +61 -32
- package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js +0 -1
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js +0 -1
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/database/DatabaseManager.cjs.js +12 -0
- package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js +216 -59
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js +1 -0
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js +58 -25
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +1 -1
- package/dist/urlReader.d.ts +3 -0
- package/package.json +17 -17
|
@@ -5,16 +5,21 @@ var fetch = require('node-fetch');
|
|
|
5
5
|
var ReadUrlResponseFactory = require('./ReadUrlResponseFactory.cjs.js');
|
|
6
6
|
var errors = require('@backstage/errors');
|
|
7
7
|
var node_stream = require('node:stream');
|
|
8
|
+
var FetchUrlReader = require('./FetchUrlReader.cjs.js');
|
|
8
9
|
|
|
9
10
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
10
11
|
|
|
11
12
|
var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
|
|
12
13
|
|
|
14
|
+
const REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308];
|
|
15
|
+
const MAX_REDIRECTS = 5;
|
|
13
16
|
class HarnessUrlReader {
|
|
14
17
|
static factory = ({ config, treeResponseFactory }) => {
|
|
18
|
+
const allowedRedirectPredicate = FetchUrlReader.predicateFromConfig(config);
|
|
15
19
|
return integration.ScmIntegrations.fromConfig(config).harness.list().map((integration) => {
|
|
16
20
|
const reader = new HarnessUrlReader(integration, {
|
|
17
|
-
treeResponseFactory
|
|
21
|
+
treeResponseFactory,
|
|
22
|
+
allowedRedirectPredicate
|
|
18
23
|
});
|
|
19
24
|
const predicate = (url) => {
|
|
20
25
|
return url.host === integration.config.host;
|
|
@@ -24,26 +29,19 @@ class HarnessUrlReader {
|
|
|
24
29
|
};
|
|
25
30
|
integration;
|
|
26
31
|
deps;
|
|
32
|
+
allowedRedirectPredicate;
|
|
27
33
|
constructor(integration, deps) {
|
|
28
34
|
this.integration = integration;
|
|
29
35
|
this.deps = deps;
|
|
36
|
+
this.allowedRedirectPredicate = deps.allowedRedirectPredicate ?? (() => false);
|
|
30
37
|
}
|
|
31
38
|
async read(url) {
|
|
32
39
|
const response = await this.readUrl(url);
|
|
33
40
|
return response.buffer();
|
|
34
41
|
}
|
|
35
42
|
async readUrl(url, options) {
|
|
36
|
-
let response;
|
|
37
43
|
const blobUrl = integration.getHarnessFileContentsUrl(this.integration.config, url);
|
|
38
|
-
|
|
39
|
-
response = await fetch__default.default(blobUrl, {
|
|
40
|
-
method: "GET",
|
|
41
|
-
...integration.getHarnessRequestOptions(this.integration.config),
|
|
42
|
-
signal: options?.signal
|
|
43
|
-
});
|
|
44
|
-
} catch (e) {
|
|
45
|
-
throw new Error(`Unable to read ${blobUrl}, ${e}`);
|
|
46
|
-
}
|
|
44
|
+
const response = await this.fetchUrl(blobUrl, options?.signal);
|
|
47
45
|
if (response.ok) {
|
|
48
46
|
const jsonResponse = { data: response.body };
|
|
49
47
|
if (jsonResponse) {
|
|
@@ -74,16 +72,7 @@ class HarnessUrlReader {
|
|
|
74
72
|
throw new errors.NotModifiedError();
|
|
75
73
|
}
|
|
76
74
|
const archiveUri = integration.getHarnessArchiveUrl(this.integration.config, url);
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
response = await fetch__default.default(archiveUri, {
|
|
80
|
-
method: "GET",
|
|
81
|
-
...integration.getHarnessRequestOptions(this.integration.config),
|
|
82
|
-
signal: options?.signal
|
|
83
|
-
});
|
|
84
|
-
} catch (e) {
|
|
85
|
-
throw new Error(`Unable to read ${archiveUri}, ${e}`);
|
|
86
|
-
}
|
|
75
|
+
const response = await this.fetchUrl(archiveUri, options?.signal);
|
|
87
76
|
const parsedUri = integration.parseHarnessUrl(this.integration.config, url);
|
|
88
77
|
return this.deps.treeResponseFactory.fromZipArchive({
|
|
89
78
|
stream: node_stream.Readable.from(response.body),
|
|
@@ -126,12 +115,56 @@ class HarnessUrlReader {
|
|
|
126
115
|
this.integration.config.token || this.integration.config.apiKey
|
|
127
116
|
)}}`;
|
|
128
117
|
}
|
|
118
|
+
async fetchUrl(url, signal) {
|
|
119
|
+
const configuredOrigin = new URL(`https://${this.integration.config.host}`).origin;
|
|
120
|
+
let currentUrl = url;
|
|
121
|
+
let includeCredentials = true;
|
|
122
|
+
for (let redirectCount = 0; ; redirectCount += 1) {
|
|
123
|
+
const currentUrlObject = new URL(currentUrl);
|
|
124
|
+
const requestOptions = includeCredentials && currentUrlObject.origin === configuredOrigin ? integration.getHarnessRequestOptions(this.integration.config) : {};
|
|
125
|
+
let response;
|
|
126
|
+
try {
|
|
127
|
+
response = await fetch__default.default(currentUrl, {
|
|
128
|
+
method: "GET",
|
|
129
|
+
...requestOptions,
|
|
130
|
+
redirect: "manual",
|
|
131
|
+
signal
|
|
132
|
+
});
|
|
133
|
+
} catch (e) {
|
|
134
|
+
throw new Error(`Unable to read ${currentUrl}, ${e}`);
|
|
135
|
+
}
|
|
136
|
+
const location = response.headers.get("location");
|
|
137
|
+
if (!REDIRECT_STATUS_CODES.includes(response.status) || !location) {
|
|
138
|
+
return response;
|
|
139
|
+
}
|
|
140
|
+
response.body.resume();
|
|
141
|
+
let redirectUrl;
|
|
142
|
+
try {
|
|
143
|
+
redirectUrl = new URL(location, currentUrl);
|
|
144
|
+
} catch (e) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Unable to read ${currentUrl}, invalid redirect URL ${location}, ${e}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (redirectUrl.origin !== configuredOrigin && !this.allowedRedirectPredicate(redirectUrl)) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`Refusing to follow cross-origin Harness redirect to ${redirectUrl.origin}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (redirectUrl.origin !== configuredOrigin) {
|
|
155
|
+
includeCredentials = false;
|
|
156
|
+
}
|
|
157
|
+
if (redirectCount === MAX_REDIRECTS) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Too many redirects (max ${MAX_REDIRECTS}) when reading ${url}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
currentUrl = redirectUrl.toString();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
129
165
|
async getLastCommitHash(url) {
|
|
130
166
|
const commitUri = integration.getHarnessLatestCommitUrl(this.integration.config, url);
|
|
131
|
-
const response = await
|
|
132
|
-
commitUri,
|
|
133
|
-
integration.getHarnessRequestOptions(this.integration.config)
|
|
134
|
-
);
|
|
167
|
+
const response = await this.fetchUrl(commitUri);
|
|
135
168
|
if (!response.ok) {
|
|
136
169
|
const message = `Failed to retrieve latest commit information from ${commitUri}, ${response.status} ${response.statusText}`;
|
|
137
170
|
if (response.status === 404) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HarnessUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/HarnessUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2025 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 {\n UrlReaderService,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceSearchOptions,\n} from '@backstage/backend-plugin-api';\nimport {\n getHarnessRequestOptions,\n getHarnessFileContentsUrl,\n HarnessIntegration,\n ScmIntegrations,\n getHarnessLatestCommitUrl,\n getHarnessArchiveUrl,\n parseHarnessUrl,\n} from '@backstage/integration';\nimport { ReadTreeResponseFactory, ReaderFactory } from './types';\nimport fetch, { Response } from 'node-fetch';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n toError,\n AuthenticationError,\n NotFoundError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { Readable } from 'node:stream';\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Harness code v1 api.\n *\n *\n * @public\n */\nexport class HarnessUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n return ScmIntegrations.fromConfig(config)\n .harness.list()\n .map(integration => {\n const reader = new HarnessUrlReader(integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return url.host === integration.config.host;\n };\n return { reader, predicate };\n });\n };\n\n private readonly integration: HarnessIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n integration: HarnessIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.integration = integration;\n this.deps = deps;\n }\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n let response: Response;\n const blobUrl = getHarnessFileContentsUrl(this.integration.config, url);\n\n try {\n response = await fetch(blobUrl, {\n method: 'GET',\n ...getHarnessRequestOptions(this.integration.config),\n signal: options?.signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${blobUrl}, ${e}`);\n }\n\n if (response.ok) {\n // Harness Code returns the raw content object\n const jsonResponse = { data: response.body };\n if (jsonResponse) {\n return ReadUrlResponseFactory.fromReadable(\n Readable.from(jsonResponse.data),\n {\n etag: response.headers.get('ETag') ?? undefined,\n },\n );\n }\n\n throw new Error(`Unknown json: ${jsonResponse}`);\n }\n\n const message = `${url} x ${blobUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n\n if (response.status === 304) {\n throw new NotModifiedError();\n }\n\n if (response.status === 403) {\n throw new AuthenticationError();\n }\n\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const lastCommitHash = await this.getLastCommitHash(url);\n\n if (options?.etag && options.etag === lastCommitHash) {\n throw new NotModifiedError();\n }\n\n const archiveUri = getHarnessArchiveUrl(this.integration.config, url);\n\n let response: Response;\n try {\n response = await fetch(archiveUri, {\n method: 'GET',\n ...getHarnessRequestOptions(this.integration.config),\n signal: options?.signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${archiveUri}, ${e}`);\n }\n\n const parsedUri = parseHarnessUrl(this.integration.config, url);\n\n return this.deps.treeResponseFactory.fromZipArchive({\n stream: Readable.from(response.body),\n subpath: parsedUri.path,\n etag: lastCommitHash,\n filter: options?.filter,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseHarnessUrl(this.integration.config, url);\n\n if (path.match(/[*?]/)) {\n throw new Error('Unsupported search pattern URL');\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (e) {\n const error = toError(e);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\n toString() {\n const { host } = this.integration.config;\n return `harness{host=${host},authed=${Boolean(\n this.integration.config.token || this.integration.config.apiKey,\n )}}`;\n }\n private async getLastCommitHash(url: string): Promise<string> {\n const commitUri = getHarnessLatestCommitUrl(this.integration.config, url);\n\n const response = await fetch(\n commitUri,\n getHarnessRequestOptions(this.integration.config),\n );\n if (!response.ok) {\n const message = `Failed to retrieve latest commit information from ${commitUri}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return (await response.json()).latest_commit.sha;\n }\n}\n"],"names":["ScmIntegrations","getHarnessFileContentsUrl","fetch","getHarnessRequestOptions","ReadUrlResponseFactory","Readable","NotFoundError","NotModifiedError","AuthenticationError","getHarnessArchiveUrl","parseHarnessUrl","toError","getHarnessLatestCommitUrl"],"mappings":";;;;;;;;;;;;AAmDO,MAAM,gBAAA,CAA6C;AAAA,EACxD,OAAO,OAAA,GAAyB,CAAC,EAAE,MAAA,EAAQ,qBAAoB,KAAM;AACnE,IAAA,OAAOA,2BAAA,CAAgB,WAAW,MAAM,CAAA,CACrC,QAAQ,IAAA,EAAK,CACb,IAAI,CAAA,WAAA,KAAe;AAClB,MAAA,MAAM,MAAA,GAAS,IAAI,gBAAA,CAAiB,WAAA,EAAa;AAAA,QAC/C;AAAA,OACD,CAAA;AACD,MAAA,MAAM,SAAA,GAAY,CAAC,GAAA,KAAa;AAC9B,QAAA,OAAO,GAAA,CAAI,IAAA,KAAS,WAAA,CAAY,MAAA,CAAO,IAAA;AAAA,MACzC,CAAA;AACA,MAAA,OAAO,EAAE,QAAQ,SAAA,EAAU;AAAA,IAC7B,CAAC,CAAA;AAAA,EACL,CAAA;AAAA,EAEiB,WAAA;AAAA,EACA,IAAA;AAAA,EAIjB,WAAA,CACE,aACA,IAAA,EAGA;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AACnB,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AAAA,EACA,MAAM,KAAK,GAAA,EAA8B;AACvC,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACvC,IAAA,OAAO,SAAS,MAAA,EAAO;AAAA,EACzB;AAAA,EAEA,MAAM,OAAA,CACJ,GAAA,EACA,OAAA,EAC0C;AAC1C,IAAA,IAAI,QAAA;AACJ,IAAA,MAAM,OAAA,GAAUC,qCAAA,CAA0B,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAEtE,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAMC,uBAAM,OAAA,EAAS;AAAA,QAC9B,MAAA,EAAQ,KAAA;AAAA,QACR,GAAGC,oCAAA,CAAyB,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA;AAAA,QACnD,QAAQ,OAAA,EAAS;AAAA,OAClB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,OAAO,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IACnD;AAEA,IAAA,IAAI,SAAS,EAAA,EAAI;AAEf,MAAA,MAAM,YAAA,GAAe,EAAE,IAAA,EAAM,QAAA,CAAS,IAAA,EAAK;AAC3C,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,OAAOC,6CAAA,CAAuB,YAAA;AAAA,UAC5BC,oBAAA,CAAS,IAAA,CAAK,YAAA,CAAa,IAAI,CAAA;AAAA,UAC/B;AAAA,YACE,IAAA,EAAM,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,IAAK;AAAA;AACxC,SACF;AAAA,MACF;AAEA,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,YAAY,CAAA,CAAE,CAAA;AAAA,IACjD;AAEA,IAAA,MAAM,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,GAAA,EAAM,OAAO,KAAK,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,UAAU,CAAA,CAAA;AAC9E,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAIC,qBAAc,OAAO,CAAA;AAAA,IACjC;AAEA,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAIC,uBAAA,EAAiB;AAAA,IAC7B;AAEA,IAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,MAAA,MAAM,IAAIC,0BAAA,EAAoB;AAAA,IAChC;AAEA,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AAAA,EAEA,MAAM,QAAA,CACJ,GAAA,EACA,OAAA,EAC2C;AAC3C,IAAA,MAAM,cAAA,GAAiB,MAAM,IAAA,CAAK,iBAAA,CAAkB,GAAG,CAAA;AAEvD,IAAA,IAAI,OAAA,EAAS,IAAA,IAAQ,OAAA,CAAQ,IAAA,KAAS,cAAA,EAAgB;AACpD,MAAA,MAAM,IAAID,uBAAA,EAAiB;AAAA,IAC7B;AAEA,IAAA,MAAM,UAAA,GAAaE,gCAAA,CAAqB,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAEpE,IAAA,IAAI,QAAA;AACJ,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,MAAMP,uBAAM,UAAA,EAAY;AAAA,QACjC,MAAA,EAAQ,KAAA;AAAA,QACR,GAAGC,oCAAA,CAAyB,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA;AAAA,QACnD,QAAQ,OAAA,EAAS;AAAA,OAClB,CAAA;AAAA,IACH,SAAS,CAAA,EAAG;AACV,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,UAAU,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IACtD;AAEA,IAAA,MAAM,SAAA,GAAYO,2BAAA,CAAgB,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAE9D,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,mBAAA,CAAoB,cAAA,CAAe;AAAA,MAClD,MAAA,EAAQL,oBAAA,CAAS,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA;AAAA,MACnC,SAAS,SAAA,CAAU,IAAA;AAAA,MACnB,IAAA,EAAM,cAAA;AAAA,MACN,QAAQ,OAAA,EAAS;AAAA,KAClB,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,MAAA,CACJ,GAAA,EACA,OAAA,EACyC;AACzC,IAAA,MAAM,EAAE,IAAA,EAAK,GAAIK,4BAAgB,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAE7D,IAAA,IAAI,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,MAAM,gCAAgC,CAAA;AAAA,IAClD;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,OAAA,CAAQ,KAAK,OAAO,CAAA;AAE5C,MAAA,OAAO;AAAA,QACL,KAAA,EAAO;AAAA,UACL;AAAA,YACE,GAAA;AAAA,YACA,SAAS,IAAA,CAAK,MAAA;AAAA,YACd,gBAAgB,IAAA,CAAK;AAAA;AACvB,SACF;AAAA,QACA,IAAA,EAAM,KAAK,IAAA,IAAQ;AAAA,OACrB;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,MAAM,KAAA,GAAQC,eAAQ,CAAC,CAAA;AACvB,MAAA,IAAI,KAAA,CAAM,SAAS,eAAA,EAAiB;AAClC,QAAA,OAAO;AAAA,UACL,OAAO,EAAC;AAAA,UACR,IAAA,EAAM;AAAA,SACR;AAAA,MACF;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,QAAA,GAAW;AACT,IAAA,MAAM,EAAE,IAAA,EAAK,GAAI,IAAA,CAAK,WAAA,CAAY,MAAA;AAClC,IAAA,OAAO,CAAA,aAAA,EAAgB,IAAI,CAAA,QAAA,EAAW,OAAA;AAAA,MACpC,KAAK,WAAA,CAAY,MAAA,CAAO,KAAA,IAAS,IAAA,CAAK,YAAY,MAAA,CAAO;AAAA,KAC1D,CAAA,CAAA,CAAA;AAAA,EACH;AAAA,EACA,MAAc,kBAAkB,GAAA,EAA8B;AAC5D,IAAA,MAAM,SAAA,GAAYC,qCAAA,CAA0B,IAAA,CAAK,WAAA,CAAY,QAAQ,GAAG,CAAA;AAExE,IAAA,MAAM,WAAW,MAAMV,sBAAA;AAAA,MACrB,SAAA;AAAA,MACAC,oCAAA,CAAyB,IAAA,CAAK,WAAA,CAAY,MAAM;AAAA,KAClD;AACA,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,OAAA,GAAU,qDAAqD,SAAS,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA,CAAA;AACzH,MAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,QAAA,MAAM,IAAIG,qBAAc,OAAO,CAAA;AAAA,MACjC;AACA,MAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,IACzB;AAEA,IAAA,OAAA,CAAQ,MAAM,QAAA,CAAS,IAAA,EAAK,EAAG,aAAA,CAAc,GAAA;AAAA,EAC/C;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"HarnessUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/HarnessUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2025 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 {\n UrlReaderService,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchResponse,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceSearchOptions,\n} from '@backstage/backend-plugin-api';\nimport {\n getHarnessRequestOptions,\n getHarnessFileContentsUrl,\n HarnessIntegration,\n ScmIntegrations,\n getHarnessLatestCommitUrl,\n getHarnessArchiveUrl,\n parseHarnessUrl,\n} from '@backstage/integration';\nimport { ReadTreeResponseFactory, ReaderFactory } from './types';\nimport fetch, { Response } from 'node-fetch';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport {\n toError,\n AuthenticationError,\n NotFoundError,\n NotModifiedError,\n} from '@backstage/errors';\nimport { Readable } from 'node:stream';\nimport { predicateFromConfig } from './FetchUrlReader';\n\nconst REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308];\nconst MAX_REDIRECTS = 5;\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for the Harness code v1 api.\n *\n *\n * @public\n */\nexport class HarnessUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const allowedRedirectPredicate = predicateFromConfig(config);\n return ScmIntegrations.fromConfig(config)\n .harness.list()\n .map(integration => {\n const reader = new HarnessUrlReader(integration, {\n treeResponseFactory,\n allowedRedirectPredicate,\n });\n const predicate = (url: URL) => {\n return url.host === integration.config.host;\n };\n return { reader, predicate };\n });\n };\n\n private readonly integration: HarnessIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n allowedRedirectPredicate?: (url: URL) => boolean;\n };\n private readonly allowedRedirectPredicate: (url: URL) => boolean;\n\n constructor(\n integration: HarnessIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n allowedRedirectPredicate?: (url: URL) => boolean;\n },\n ) {\n this.integration = integration;\n this.deps = deps;\n this.allowedRedirectPredicate =\n deps.allowedRedirectPredicate ?? (() => false);\n }\n async read(url: string): Promise<Buffer> {\n const response = await this.readUrl(url);\n return response.buffer();\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n const blobUrl = getHarnessFileContentsUrl(this.integration.config, url);\n const response = await this.fetchUrl(blobUrl, options?.signal);\n\n if (response.ok) {\n // Harness Code returns the raw content object\n const jsonResponse = { data: response.body };\n if (jsonResponse) {\n return ReadUrlResponseFactory.fromReadable(\n Readable.from(jsonResponse.data),\n {\n etag: response.headers.get('ETag') ?? undefined,\n },\n );\n }\n\n throw new Error(`Unknown json: ${jsonResponse}`);\n }\n\n const message = `${url} x ${blobUrl}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n\n if (response.status === 304) {\n throw new NotModifiedError();\n }\n\n if (response.status === 403) {\n throw new AuthenticationError();\n }\n\n throw new Error(message);\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n const lastCommitHash = await this.getLastCommitHash(url);\n\n if (options?.etag && options.etag === lastCommitHash) {\n throw new NotModifiedError();\n }\n\n const archiveUri = getHarnessArchiveUrl(this.integration.config, url);\n\n const response = await this.fetchUrl(archiveUri, options?.signal);\n\n const parsedUri = parseHarnessUrl(this.integration.config, url);\n\n return this.deps.treeResponseFactory.fromZipArchive({\n stream: Readable.from(response.body),\n subpath: parsedUri.path,\n etag: lastCommitHash,\n filter: options?.filter,\n });\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseHarnessUrl(this.integration.config, url);\n\n if (path.match(/[*?]/)) {\n throw new Error('Unsupported search pattern URL');\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (e) {\n const error = toError(e);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\n toString() {\n const { host } = this.integration.config;\n return `harness{host=${host},authed=${Boolean(\n this.integration.config.token || this.integration.config.apiKey,\n )}}`;\n }\n\n private async fetchUrl(url: string, signal?: AbortSignal): Promise<Response> {\n const configuredOrigin = new URL(`https://${this.integration.config.host}`)\n .origin;\n let currentUrl = url;\n let includeCredentials = true;\n\n for (let redirectCount = 0; ; redirectCount += 1) {\n const currentUrlObject = new URL(currentUrl);\n const requestOptions =\n includeCredentials && currentUrlObject.origin === configuredOrigin\n ? getHarnessRequestOptions(this.integration.config)\n : {};\n let response: Response;\n try {\n response = await fetch(currentUrl, {\n method: 'GET',\n ...requestOptions,\n redirect: 'manual',\n signal: signal as any,\n });\n } catch (e) {\n throw new Error(`Unable to read ${currentUrl}, ${e}`);\n }\n\n const location = response.headers.get('location');\n if (!REDIRECT_STATUS_CODES.includes(response.status) || !location) {\n return response;\n }\n\n response.body.resume();\n\n let redirectUrl: URL;\n try {\n redirectUrl = new URL(location, currentUrl);\n } catch (e) {\n throw new Error(\n `Unable to read ${currentUrl}, invalid redirect URL ${location}, ${e}`,\n );\n }\n\n if (\n redirectUrl.origin !== configuredOrigin &&\n !this.allowedRedirectPredicate(redirectUrl)\n ) {\n throw new Error(\n `Refusing to follow cross-origin Harness redirect to ${redirectUrl.origin}`,\n );\n }\n\n if (redirectUrl.origin !== configuredOrigin) {\n includeCredentials = false;\n }\n\n if (redirectCount === MAX_REDIRECTS) {\n throw new Error(\n `Too many redirects (max ${MAX_REDIRECTS}) when reading ${url}`,\n );\n }\n\n currentUrl = redirectUrl.toString();\n }\n }\n\n private async getLastCommitHash(url: string): Promise<string> {\n const commitUri = getHarnessLatestCommitUrl(this.integration.config, url);\n\n const response = await this.fetchUrl(commitUri);\n if (!response.ok) {\n const message = `Failed to retrieve latest commit information from ${commitUri}, ${response.status} ${response.statusText}`;\n if (response.status === 404) {\n throw new NotFoundError(message);\n }\n throw new Error(message);\n }\n\n return (await response.json()).latest_commit.sha;\n }\n}\n"],"names":["predicateFromConfig","ScmIntegrations","getHarnessFileContentsUrl","ReadUrlResponseFactory","Readable","NotFoundError","NotModifiedError","AuthenticationError","getHarnessArchiveUrl","parseHarnessUrl","toError","getHarnessRequestOptions","fetch","getHarnessLatestCommitUrl"],"mappings":"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"}
|
package/dist/package.json.cjs.js
CHANGED
package/dist/urlReader.d.ts
CHANGED
|
@@ -287,14 +287,17 @@ declare class HarnessUrlReader implements UrlReaderService {
|
|
|
287
287
|
static factory: ReaderFactory;
|
|
288
288
|
private readonly integration;
|
|
289
289
|
private readonly deps;
|
|
290
|
+
private readonly allowedRedirectPredicate;
|
|
290
291
|
constructor(integration: HarnessIntegration, deps: {
|
|
291
292
|
treeResponseFactory: ReadTreeResponseFactory;
|
|
293
|
+
allowedRedirectPredicate?: (url: URL) => boolean;
|
|
292
294
|
});
|
|
293
295
|
read(url: string): Promise<Buffer>;
|
|
294
296
|
readUrl(url: string, options?: UrlReaderServiceReadUrlOptions): Promise<UrlReaderServiceReadUrlResponse>;
|
|
295
297
|
readTree(url: string, options?: UrlReaderServiceReadTreeOptions): Promise<UrlReaderServiceReadTreeResponse>;
|
|
296
298
|
search(url: string, options?: UrlReaderServiceSearchOptions): Promise<UrlReaderServiceSearchResponse>;
|
|
297
299
|
toString(): string;
|
|
300
|
+
private fetchUrl;
|
|
298
301
|
private getLastCommitHash;
|
|
299
302
|
}
|
|
300
303
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-defaults",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.9-next.0",
|
|
4
4
|
"description": "Backend defaults used by Backstage backend apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -226,20 +226,20 @@
|
|
|
226
226
|
"@aws-sdk/types": "^3.347.0",
|
|
227
227
|
"@azure/identity": "^4.0.0",
|
|
228
228
|
"@azure/storage-blob": "^12.5.0",
|
|
229
|
-
"@backstage/backend-app-api": "
|
|
230
|
-
"@backstage/backend-dev-utils": "
|
|
231
|
-
"@backstage/backend-plugin-api": "
|
|
232
|
-
"@backstage/cli-node": "
|
|
233
|
-
"@backstage/config": "
|
|
234
|
-
"@backstage/config-loader": "
|
|
235
|
-
"@backstage/errors": "
|
|
236
|
-
"@backstage/integration": "
|
|
237
|
-
"@backstage/integration-aws-node": "
|
|
238
|
-
"@backstage/plugin-auth-node": "
|
|
239
|
-
"@backstage/plugin-events-node": "
|
|
240
|
-
"@backstage/plugin-permission-common": "
|
|
241
|
-
"@backstage/plugin-permission-node": "
|
|
242
|
-
"@backstage/types": "
|
|
229
|
+
"@backstage/backend-app-api": "1.7.4-next.0",
|
|
230
|
+
"@backstage/backend-dev-utils": "0.1.7",
|
|
231
|
+
"@backstage/backend-plugin-api": "1.10.1-next.0",
|
|
232
|
+
"@backstage/cli-node": "0.3.4",
|
|
233
|
+
"@backstage/config": "1.3.8",
|
|
234
|
+
"@backstage/config-loader": "1.11.2",
|
|
235
|
+
"@backstage/errors": "1.3.1",
|
|
236
|
+
"@backstage/integration": "2.1.2-next.0",
|
|
237
|
+
"@backstage/integration-aws-node": "0.2.1",
|
|
238
|
+
"@backstage/plugin-auth-node": "0.7.5-next.0",
|
|
239
|
+
"@backstage/plugin-events-node": "0.4.26-next.0",
|
|
240
|
+
"@backstage/plugin-permission-common": "0.9.10",
|
|
241
|
+
"@backstage/plugin-permission-node": "0.11.4-next.0",
|
|
242
|
+
"@backstage/types": "1.2.2",
|
|
243
243
|
"@google-cloud/storage": "^7.0.0",
|
|
244
244
|
"@keyv/memcache": "^2.0.1",
|
|
245
245
|
"@keyv/redis": "^4.0.1",
|
|
@@ -294,8 +294,8 @@
|
|
|
294
294
|
},
|
|
295
295
|
"devDependencies": {
|
|
296
296
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
297
|
-
"@backstage/backend-test-utils": "
|
|
298
|
-
"@backstage/cli": "
|
|
297
|
+
"@backstage/backend-test-utils": "1.11.7-next.0",
|
|
298
|
+
"@backstage/cli": "0.36.6-next.0",
|
|
299
299
|
"@google-cloud/cloud-sql-connector": "^1.4.0",
|
|
300
300
|
"@types/archiver": "^7.0.0",
|
|
301
301
|
"@types/base64-stream": "^1.0.2",
|