@forge/manifest 12.0.0 → 12.1.0-experimental-8b78d46
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 +91 -0
- package/out/index.d.ts +1 -1
- package/out/index.d.ts.map +1 -1
- package/out/processor/full-validation-processor.d.ts.map +1 -1
- package/out/processor/full-validation-processor.js +2 -0
- package/out/schema/display-conditions-schema.json +168 -13
- package/out/schema/manifest-schema.json +179 -28
- package/out/schema/manifest.d.ts +160 -22
- package/out/scopes/shipyard-scopes.json +1 -0
- package/out/text/errors.d.ts +2 -2
- package/out/text/errors.d.ts.map +1 -1
- package/out/text/errors.js +5 -3
- package/out/types/display-condition-types.d.ts +31 -1
- package/out/types/display-condition-types.d.ts.map +1 -1
- package/out/validators/permissions-validator.d.ts +1 -0
- package/out/validators/permissions-validator.d.ts.map +1 -1
- package/out/validators/permissions-validator.js +37 -22
- package/out/validators/remotes-is-configurable-validator.d.ts.map +1 -1
- package/out/validators/remotes-is-configurable-validator.js +7 -36
- package/out/validators/twg-preview-scopes-validator.d.ts +7 -0
- package/out/validators/twg-preview-scopes-validator.d.ts.map +1 -0
- package/out/validators/twg-preview-scopes-validator.js +32 -0
- package/package.json +1 -1
|
@@ -28,9 +28,9 @@ class PermissionsValidator {
|
|
|
28
28
|
remotesHasValidEntryForKey(remoteMap, key) {
|
|
29
29
|
return (remoteMap !== undefined &&
|
|
30
30
|
remoteMap.has(key) &&
|
|
31
|
-
(remoteMap.get(key) === null || this.isValidURL(remoteMap.get(key))));
|
|
31
|
+
(remoteMap.get(key) === null || this.isValidURL(remoteMap.get(key), false)));
|
|
32
32
|
}
|
|
33
|
-
isValidURL(inputURL) {
|
|
33
|
+
isValidURL(inputURL, allowGlobalUrl) {
|
|
34
34
|
const protocolRegex = /^(.*?:\/\/)/;
|
|
35
35
|
const validURI = /^(\*\.)?[.a-zA-Z0-9_\-\/:~#%?=&]+$/;
|
|
36
36
|
const allowedProtocols = ['https:', 'wss:'];
|
|
@@ -38,8 +38,8 @@ class PermissionsValidator {
|
|
|
38
38
|
if (inputURL.length > MAX_URL_LENGTH) {
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
|
-
if (inputURL ===
|
|
42
|
-
return
|
|
41
|
+
if (inputURL === egress_types_1.GLOBAL_URL) {
|
|
42
|
+
return allowGlobalUrl;
|
|
43
43
|
}
|
|
44
44
|
const customURLSchemeRegex = /^[a-zA-Z]+:(\\\\)?/;
|
|
45
45
|
if (customURLSchemeRegex.test(inputURL) &&
|
|
@@ -70,6 +70,18 @@ class PermissionsValidator {
|
|
|
70
70
|
];
|
|
71
71
|
return BASE_64_HASH_PATTERNS.some((pattern) => pattern.test(cspString));
|
|
72
72
|
}
|
|
73
|
+
hasPathComponent(url) {
|
|
74
|
+
try {
|
|
75
|
+
const protocolRegex = /^(.*?:\/\/)/;
|
|
76
|
+
const urlWithProtocol = protocolRegex.test(url) ? url : `https://${url}`;
|
|
77
|
+
const parsedUrl = new url_1.URL(urlWithProtocol);
|
|
78
|
+
const pathname = parsedUrl.pathname;
|
|
79
|
+
return pathname.length > 0 && pathname !== '/';
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
73
85
|
addValidationErrors(result, element, values, manifest) {
|
|
74
86
|
values.forEach((value) => {
|
|
75
87
|
result.push({
|
|
@@ -81,7 +93,7 @@ class PermissionsValidator {
|
|
|
81
93
|
});
|
|
82
94
|
}
|
|
83
95
|
validateExternalPermissionURLs(result, extPermType, perms, manifest) {
|
|
84
|
-
const invalidPerms = perms?.filter((key) => !this.isValidURL(key));
|
|
96
|
+
const invalidPerms = perms?.filter((key) => !this.isValidURL(key, true));
|
|
85
97
|
if (invalidPerms?.length) {
|
|
86
98
|
this.addValidationErrors(result, extPermType, invalidPerms, manifest);
|
|
87
99
|
}
|
|
@@ -115,6 +127,19 @@ class PermissionsValidator {
|
|
|
115
127
|
});
|
|
116
128
|
}
|
|
117
129
|
}
|
|
130
|
+
if (extPermType === 'external.fetch.backend') {
|
|
131
|
+
const urlsWithPaths = perms?.filter((key) => this.hasPathComponent(key));
|
|
132
|
+
if (urlsWithPaths?.length) {
|
|
133
|
+
urlsWithPaths.forEach((url) => {
|
|
134
|
+
result.push({
|
|
135
|
+
message: text_1.errors.permissions.backendEgressPathIgnored(url),
|
|
136
|
+
reference: text_1.References.Permissions,
|
|
137
|
+
level: 'warning',
|
|
138
|
+
...(0, utils_1.findPosition)(url, manifest.yamlContentByLine)
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
118
143
|
}
|
|
119
144
|
async validate(manifest) {
|
|
120
145
|
if (!manifest || !manifest.typedContent || !manifest.typedContent.permissions) {
|
|
@@ -186,7 +211,7 @@ class PermissionsValidator {
|
|
|
186
211
|
}
|
|
187
212
|
];
|
|
188
213
|
mapping.forEach((item) => this.validateExternalPermissionURLs(errors, item.element, item.perms, manifest));
|
|
189
|
-
const { fetch: originalFetch, ...restOfExternalPermissions } = manifest.typedContent.permissions.external || {};
|
|
214
|
+
const { fetch: originalFetch, configurable: _configurable, ...restOfExternalPermissions } = manifest.typedContent.permissions.external || {};
|
|
190
215
|
Object.entries(originalFetch || {}).forEach(([key, values]) => {
|
|
191
216
|
if (values.some((value) => typeof value === 'string')) {
|
|
192
217
|
errors.push({
|
|
@@ -215,24 +240,14 @@ class PermissionsValidator {
|
|
|
215
240
|
});
|
|
216
241
|
const remoteMap = manifest.typedContent.remotes?.reduce((prev, item) => {
|
|
217
242
|
if ((0, features_1.configurableRemotesEnabled)()) {
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return prev.set(item.key, baseUrl);
|
|
222
|
-
}
|
|
223
|
-
else {
|
|
224
|
-
return prev.set(item.key, null);
|
|
225
|
-
}
|
|
243
|
+
if (item.baseUrl) {
|
|
244
|
+
const baseUrl = typeof item.baseUrl === 'string' ? item.baseUrl : item.baseUrl.default;
|
|
245
|
+
return prev.set(item.key, baseUrl);
|
|
226
246
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const baseUrl = typeof item.baseUrl === 'string' ? item.baseUrl : item.baseUrl.default;
|
|
230
|
-
return prev.set(item.key, baseUrl);
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
return prev;
|
|
234
|
-
}
|
|
247
|
+
if (!item.baseUrl && item.configurable) {
|
|
248
|
+
return prev.set(item.key, null);
|
|
235
249
|
}
|
|
250
|
+
return prev;
|
|
236
251
|
}
|
|
237
252
|
else {
|
|
238
253
|
if (item.baseUrl !== undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remotes-is-configurable-validator.d.ts","sourceRoot":"","sources":["../../src/validators/remotes-is-configurable-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAmB,MAAM,UAAU,CAAC;AAKrF,qBAAa,kCACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;YAI3E,WAAW;IAiCnB,WAAW,CACf,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"remotes-is-configurable-validator.d.ts","sourceRoot":"","sources":["../../src/validators/remotes-is-configurable-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAmB,MAAM,UAAU,CAAC;AAKrF,qBAAa,kCACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;YAI3E,WAAW;IAiCnB,WAAW,CACf,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;IA+B9C,QAAQ,CACZ,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;CAOrD"}
|
|
@@ -38,43 +38,14 @@ class RemotesIsUserConfigurableValidator {
|
|
|
38
38
|
}
|
|
39
39
|
const remotes = manifest.typedContent.remotes;
|
|
40
40
|
const validationErrors = [];
|
|
41
|
-
const configurableRemotesAllowed = manifest.typedContent.permissions?.configurable?.enabled ?? false;
|
|
42
41
|
remotes?.forEach((remote) => {
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
if (remote.configurable === undefined && remote.baseUrl === undefined) {
|
|
53
|
-
validationErrors.push({
|
|
54
|
-
message: text_1.errors.modules.remote.baseUrlNotPresent(remote.key),
|
|
55
|
-
reference: text_1.References.App,
|
|
56
|
-
level: 'error',
|
|
57
|
-
...(0, utils_1.findPosition)(remote.key, manifest.yamlContentByLine)
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
if (remote.configurable === undefined && remote.baseUrl === undefined) {
|
|
63
|
-
validationErrors.push({
|
|
64
|
-
message: text_1.errors.modules.remote.neitherBaseUrlNorUserConfigurationPresent(remote.key),
|
|
65
|
-
reference: text_1.References.App,
|
|
66
|
-
level: 'error',
|
|
67
|
-
...(0, utils_1.findPosition)(remote.key, manifest.yamlContentByLine)
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
else if (remote.configurable !== undefined && remote.baseUrl !== undefined) {
|
|
71
|
-
validationErrors.push({
|
|
72
|
-
message: text_1.errors.modules.remote.bothBaseUrlAndUserConfigurationPresent(remote.key),
|
|
73
|
-
reference: text_1.References.App,
|
|
74
|
-
level: 'error',
|
|
75
|
-
...(0, utils_1.findPosition)(remote.key, manifest.yamlContentByLine)
|
|
76
|
-
});
|
|
77
|
-
}
|
|
42
|
+
if (remote.configurable === undefined && remote.baseUrl === undefined) {
|
|
43
|
+
validationErrors.push({
|
|
44
|
+
message: text_1.errors.modules.remote.neitherBaseUrlNorUserConfigurationPresent(remote.key),
|
|
45
|
+
reference: text_1.References.App,
|
|
46
|
+
level: 'error',
|
|
47
|
+
...(0, utils_1.findPosition)(remote.key, manifest.yamlContentByLine)
|
|
48
|
+
});
|
|
78
49
|
}
|
|
79
50
|
});
|
|
80
51
|
return {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidatorInterface } from './validator-interface';
|
|
2
|
+
import { ManifestObject, ManifestValidationResult } from '../types';
|
|
3
|
+
import { ManifestSchema } from '../schema/manifest';
|
|
4
|
+
export declare class TwgPreviewScopesValidator implements ValidatorInterface<ManifestObject<ManifestSchema> | undefined, ManifestSchema> {
|
|
5
|
+
validate(manifest: ManifestObject<ManifestSchema> | undefined): Promise<ManifestValidationResult<ManifestSchema>>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=twg-preview-scopes-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twg-preview-scopes-validator.d.ts","sourceRoot":"","sources":["../../src/validators/twg-preview-scopes-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAepD,qBAAa,yBACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;IAEnF,QAAQ,CACZ,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;CAyBrD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwgPreviewScopesValidator = void 0;
|
|
4
|
+
const text_1 = require("../text");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const scopes_1 = require("../utils/scopes");
|
|
7
|
+
const TWG_PREVIEW_SCOPES = ['read:graph:jira', 'read:graph:confluence'];
|
|
8
|
+
class TwgPreviewScopesValidator {
|
|
9
|
+
async validate(manifest) {
|
|
10
|
+
if (!manifest?.typedContent?.permissions?.scopes) {
|
|
11
|
+
return { success: true, manifestObject: manifest };
|
|
12
|
+
}
|
|
13
|
+
const manifestScopes = (0, scopes_1.getAllScopeKeys)(manifest.typedContent.permissions.scopes);
|
|
14
|
+
const foundTwgScopes = manifestScopes.filter((scope) => TWG_PREVIEW_SCOPES.includes(scope));
|
|
15
|
+
if (foundTwgScopes.length > 0) {
|
|
16
|
+
return {
|
|
17
|
+
success: true,
|
|
18
|
+
manifestObject: manifest,
|
|
19
|
+
errors: [
|
|
20
|
+
{
|
|
21
|
+
message: text_1.errors.twgPreviewScopes(foundTwgScopes),
|
|
22
|
+
reference: text_1.References.Deprecated,
|
|
23
|
+
level: 'warning',
|
|
24
|
+
...(0, utils_1.findPosition)('scopes', manifest?.yamlContentByLine)
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return { success: true, manifestObject: manifest };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.TwgPreviewScopesValidator = TwgPreviewScopesValidator;
|