@forge/manifest 4.9.2 → 4.10.0-next.1

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,5 +1,17 @@
1
1
  # @forge/manifest
2
2
 
3
+ ## 4.10.0-next.1
4
+
5
+ ### Minor Changes
6
+
7
+ - 6e015d7: Update validation logic to handle CSUIK manifests
8
+
9
+ ## 4.9.3-next.0
10
+
11
+ ### Patch Changes
12
+
13
+ - 59c693e: Update manifest definitions
14
+
3
15
  ## 4.9.2
4
16
 
5
17
  ### Patch Changes
@@ -91,6 +91,8 @@
91
91
  "read:account",
92
92
  "read:account:brie",
93
93
  "read:analytics.content:confluence",
94
+ "read:app-system-token",
95
+ "read:app-user-token",
94
96
  "read:application-role:jira",
95
97
  "read:attachment:confluence",
96
98
  "read:attachment:jira",
@@ -27,6 +27,7 @@ export declare const errors: {
27
27
  duplicateKeyFound: (key: string) => string;
28
28
  wrongFunctionReference: (module: string, functionKey: string) => string;
29
29
  wrongResourceReference: (module: string, resourceKey: string) => string;
30
+ wrongResourceType: (folder: string) => string;
30
31
  singleEntryOfTheModule: (moduleType: string) => string;
31
32
  singleEntryOfModuleWithoutConfigureAndStartedParams: (moduleType: string) => string;
32
33
  singleEntryOfModuleWithConfigureParam: (moduleType: string) => string;
@@ -84,11 +85,12 @@ export declare const errors: {
84
85
  };
85
86
  };
86
87
  resources: {
87
- missingDirectory: (folder: string, key: string) => string;
88
+ missingResource: (folder: string, key: string) => string;
88
89
  emptyDirectory: (folder: string, key: string) => string;
89
90
  missingEntrypoint: (folder: string, key: string) => string;
90
91
  deprecatedCspPolicyDefinition: (folder: string) => string;
91
92
  tooManyResourcesError: (limit: number) => string;
93
+ nonDirectory: (folder: string, key: string) => string;
92
94
  };
93
95
  deprecationInfo: {
94
96
  app: {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/text/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/text/errors.ts"],"names":[],"mappings":"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"}
@@ -41,6 +41,7 @@ exports.errors = {
41
41
  duplicateKeyFound: (key) => `found duplicate module key '${key}'`,
42
42
  wrongFunctionReference: (module, functionKey) => `${module} references undefined function module with key '${functionKey}'`,
43
43
  wrongResourceReference: (module, resourceKey) => `missing resource key '${resourceKey}' is being referenced by ${module} module`,
44
+ wrongResourceType: (folder) => `Client Side UI Kit resource (${folder}) cannot be a directory`,
44
45
  singleEntryOfTheModule: (moduleType) => `Only a single entry of the ${moduleType} module can be defined in the manifest`,
45
46
  singleEntryOfModuleWithoutConfigureAndStartedParams: (moduleType) => `The ${moduleType} module can only have a single entry that doesn’t include either useAsConfig or useAsGetStarted properties.`,
46
47
  singleEntryOfModuleWithConfigureParam: (moduleType) => `The ${moduleType} module can only have a single entry that includes the useAsConfig property.`,
@@ -98,11 +99,12 @@ exports.errors = {
98
99
  }
99
100
  },
100
101
  resources: {
101
- missingDirectory: (folder, key) => `missing directory '${folder}' is being referenced by '${key}' in resources`,
102
+ missingResource: (folder, key) => `missing resource '${folder}' is being referenced by '${key}' in resources`,
102
103
  emptyDirectory: (folder, key) => `empty directory '${folder}' is being referenced by '${key}' in resources`,
103
- missingEntrypoint: (folder, key) => `missing index.html file in directory (${folder}) is being referenced by a custom UI resource in ${key} module`,
104
+ missingEntrypoint: (folder, key) => `missing index.html file in directory (${folder}) is being referenced by a Custom UI resource in ${key} module`,
104
105
  deprecatedCspPolicyDefinition: (folder) => `The index.html file in the (${folder}) directory is using a deprecated method of defining CSP. To use the supported method, go to: https://go.atlassian.com/forge-content-security-and-egress-controls`,
105
- tooManyResourcesError: (limit) => `document exceeds ${limit} resources`
106
+ tooManyResourcesError: (limit) => `document exceeds ${limit} resources`,
107
+ nonDirectory: (folder, key) => `Custom UI resource must be a directory. (${folder}) in ${key} module is not a directory`
106
108
  },
107
109
  deprecationInfo: {
108
110
  app: {
@@ -1 +1 @@
1
- {"version":3,"file":"resources-validator.d.ts","sourceRoot":"","sources":["../../src/validators/resources-validator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAmB,MAAM,UAAU,CAAC;AAGrF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAK3D,qBAAa,kBACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;IACnF,QAAQ,CACZ,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;CAgIrD"}
1
+ {"version":3,"file":"resources-validator.d.ts","sourceRoot":"","sources":["../../src/validators/resources-validator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAmB,MAAM,UAAU,CAAC;AAGrF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAK3D,qBAAa,kBACX,YAAW,kBAAkB,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,EAAE,cAAc,CAAC;IACnF,QAAQ,CACZ,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,SAAS,GACnD,OAAO,CAAC,wBAAwB,CAAC,cAAc,CAAC,CAAC;CAsKrD"}
@@ -37,33 +37,48 @@ class ResourcesValidator {
37
37
  (0, utils_2.findInvalidResourceReferences)(module, resources).forEach((resourceKey) => {
38
38
  validationErrors.push(Object.assign({ message: text_1.errors.modules.wrongResourceReference(moduleKey, resourceKey), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(moduleKey, yamlContentByLine)));
39
39
  });
40
+ const resourcePath = resourceMap.get(module.resource);
41
+ if (resourcePath === undefined)
42
+ return;
43
+ const resourcePathDir = (0, path_1.resolve)(resourcePath);
44
+ if (module.render === 'native') {
45
+ if (fs_1.default.lstatSync(resourcePathDir).isDirectory()) {
46
+ validationErrors.push(Object.assign({ message: text_1.errors.modules.wrongResourceType(resourcePath), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(moduleKey, yamlContentByLine)));
47
+ }
48
+ }
49
+ else {
50
+ if (fs_1.default.lstatSync(resourcePathDir).isDirectory() &&
51
+ !fs_1.default.existsSync((0, path_1.resolve)(manifestDir, resourcePath, 'index.html'))) {
52
+ validationErrors.push(Object.assign({ message: text_1.errors.resources.missingEntrypoint(resourcePath, moduleKey), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(resourcePath, yamlContentByLine)));
53
+ }
54
+ else if (!fs_1.default.lstatSync(resourcePathDir).isDirectory()) {
55
+ validationErrors.push(Object.assign({ message: text_1.errors.resources.nonDirectory(resourcePath, moduleKey), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(resourcePath, yamlContentByLine)));
56
+ }
57
+ }
40
58
  });
41
59
  });
42
60
  (0, utils_1.getValidModules)(modules).forEach((moduleKey) => {
43
61
  const uniquePaths = new Set(modules[moduleKey].map(({ resource }) => resourceMap.get(resource)));
44
62
  uniquePaths.forEach((path) => {
45
63
  var _a, _b, _c;
46
- if (path) {
47
- if (!fs_1.default.existsSync((0, path_1.resolve)(manifestDir, path, 'index.html'))) {
48
- validationErrors.push(Object.assign({ message: text_1.errors.resources.missingEntrypoint(path, moduleKey), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(path, yamlContentByLine)));
49
- }
50
- else {
51
- const content = fs_1.default.readFileSync((0, path_1.resolve)(manifestDir, path, 'index.html'));
52
- const $ = cheerio_1.default.load(content);
53
- const cspContent = $('meta[http-equiv="Content-Security-Policy"]').attr('content');
54
- if (cspContent) {
55
- const cspStyleSrc = cspContent.split(';').find((s) => s.startsWith('style-src'));
56
- if (cspStyleSrc === null || cspStyleSrc === void 0 ? void 0 : cspStyleSrc.includes("'unsafe-inline'")) {
57
- const existingStylesPermissions = (_c = (_b = (_a = manifest.typedContent) === null || _a === void 0 ? void 0 : _a.permissions) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c.styles;
58
- let shouldShowError = false;
59
- if (!(existingStylesPermissions === null || existingStylesPermissions === void 0 ? void 0 : existingStylesPermissions.length) || !(existingStylesPermissions === null || existingStylesPermissions === void 0 ? void 0 : existingStylesPermissions.includes('unsafe-inline'))) {
60
- shouldShowError = true;
61
- }
62
- if (shouldShowError) {
63
- validationErrors.push(Object.assign({ message: text_1.errors.resources.deprecatedCspPolicyDefinition(path), reference: text_1.References.Resources, level: 'error', metadata: {
64
- missingContentStylePermission: 'unsafe-inline'
65
- } }, (0, utils_1.findPosition)(path, yamlContentByLine)));
66
- }
64
+ if (!path)
65
+ return;
66
+ if (fs_1.default.existsSync((0, path_1.resolve)(manifestDir, path, 'index.html'))) {
67
+ const content = fs_1.default.readFileSync((0, path_1.resolve)(manifestDir, path, 'index.html'));
68
+ const $ = cheerio_1.default.load(content);
69
+ const cspContent = $('meta[http-equiv="Content-Security-Policy"]').attr('content');
70
+ if (cspContent) {
71
+ const cspStyleSrc = cspContent.split(';').find((s) => s.startsWith('style-src'));
72
+ if (cspStyleSrc === null || cspStyleSrc === void 0 ? void 0 : cspStyleSrc.includes("'unsafe-inline'")) {
73
+ const existingStylesPermissions = (_c = (_b = (_a = manifest.typedContent) === null || _a === void 0 ? void 0 : _a.permissions) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c.styles;
74
+ let shouldShowError = false;
75
+ if (!(existingStylesPermissions === null || existingStylesPermissions === void 0 ? void 0 : existingStylesPermissions.length) || !(existingStylesPermissions === null || existingStylesPermissions === void 0 ? void 0 : existingStylesPermissions.includes('unsafe-inline'))) {
76
+ shouldShowError = true;
77
+ }
78
+ if (shouldShowError) {
79
+ validationErrors.push(Object.assign({ message: text_1.errors.resources.deprecatedCspPolicyDefinition(path), reference: text_1.References.Resources, level: 'error', metadata: {
80
+ missingContentStylePermission: 'unsafe-inline'
81
+ } }, (0, utils_1.findPosition)(path, yamlContentByLine)));
67
82
  }
68
83
  }
69
84
  }
@@ -75,10 +90,11 @@ class ResourcesValidator {
75
90
  .map((resource) => {
76
91
  const { key, path } = resource;
77
92
  const manifestDir = (0, path_1.dirname)(filePath);
78
- if (!fs_1.default.existsSync((0, path_1.resolve)(manifestDir, path))) {
79
- return Object.assign({ message: text_1.errors.resources.missingDirectory(path, key), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(path, yamlContentByLine));
93
+ const resourceDirPath = (0, path_1.resolve)(manifestDir, path);
94
+ if (!fs_1.default.existsSync(resourceDirPath)) {
95
+ return Object.assign({ message: text_1.errors.resources.missingResource(path, key), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(path, yamlContentByLine));
80
96
  }
81
- else if (fs_1.default.readdirSync((0, path_1.resolve)(manifestDir, path)).length === 0) {
97
+ else if (fs_1.default.lstatSync(resourceDirPath).isDirectory() && fs_1.default.readdirSync(resourceDirPath).length === 0) {
82
98
  return Object.assign({ message: text_1.errors.resources.emptyDirectory(path, key), reference: text_1.References.Resources, level: 'error' }, (0, utils_1.findPosition)(path, yamlContentByLine));
83
99
  }
84
100
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/manifest",
3
- "version": "4.9.2",
3
+ "version": "4.10.0-next.1",
4
4
  "description": "Definitions and validations of the Forge manifest",
5
5
  "main": "out/index.js",
6
6
  "scripts": {