@forge/manifest

12.1.0-next.2-experimental-d99730712.1.0-next.3-experimental-44a932f
out/validators/permissions-validator.js
out/validators/permissions-validator.js
+25
Index: package/out/validators/permissions-validator.js
===================================================================
--- package/out/validators/permissions-validator.js
+++ package/out/validators/permissions-validator.js
@@ -69,8 +69,20 @@
             /^sha512-[a-zA-Z0-9=+/]{88}$/
         ];
         return BASE_64_HASH_PATTERNS.some((pattern) => pattern.test(cspString));
     }
+    hasPathComponent(url) {
+        try {
+            const protocolRegex = /^(.*?:\/\/)/;
+            const urlWithProtocol = protocolRegex.test(url) ? url : `https://${url}`;
+            const parsedUrl = new url_1.URL(urlWithProtocol);
+            const pathname = parsedUrl.pathname;
+            return pathname.length > 0 && pathname !== '/';
+        }
+        catch {
+            return false;
+        }
+    }
     addValidationErrors(result, element, values, manifest) {
         values.forEach((value) => {
             result.push({
                 message: text_1.errors.permissions.invalidPermission(element, value),
@@ -114,8 +126,21 @@
                     });
                 });
             }
         }
+        if (extPermType === 'external.fetch.backend') {
+            const urlsWithPaths = perms?.filter((key) => this.hasPathComponent(key));
+            if (urlsWithPaths?.length) {
+                urlsWithPaths.forEach((url) => {
+                    result.push({
+                        message: text_1.errors.permissions.backendEgressPathIgnored(url),
+                        reference: text_1.References.Permissions,
+                        level: 'warning',
+                        ...(0, utils_1.findPosition)(url, manifest.yamlContentByLine)
+                    });
+                });
+            }
+        }
     }
     async validate(manifest) {
         if (!manifest || !manifest.typedContent || !manifest.typedContent.permissions) {
             return {