@microsoft/teamsfx-core 3.1.2-alpha.7d8ba7acc9.0 → 3.1.2

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.
Files changed (127) hide show
  1. package/build/client/teamsDevPortalClient.d.ts +1 -1
  2. package/build/client/teamsDevPortalClient.d.ts.map +1 -1
  3. package/build/client/teamsDevPortalClient.js +2 -4
  4. package/build/client/teamsDevPortalClient.js.map +1 -1
  5. package/build/common/globalVars.d.ts.map +1 -1
  6. package/build/common/globalVars.js.map +1 -1
  7. package/build/common/permissionInterface.d.ts +3 -12
  8. package/build/common/permissionInterface.d.ts.map +1 -1
  9. package/build/common/permissionInterface.js +1 -7
  10. package/build/common/permissionInterface.js.map +1 -1
  11. package/build/common/templates-config.json +3 -3
  12. package/build/component/configManager/lifecycle.d.ts +2 -2
  13. package/build/component/configManager/lifecycle.d.ts.map +1 -1
  14. package/build/component/configManager/lifecycle.js +16 -24
  15. package/build/component/configManager/lifecycle.js.map +1 -1
  16. package/build/component/driver/botAadApp/create.js +1 -1
  17. package/build/component/driver/botAadApp/create.js.map +1 -1
  18. package/build/component/driver/deploy/azure/impl/AzureZipDeployImpl.js +1 -1
  19. package/build/component/driver/deploy/azure/impl/AzureZipDeployImpl.js.map +1 -1
  20. package/build/component/driver/deploy/azure/impl/azureDeployImpl.js +2 -2
  21. package/build/component/driver/deploy/azure/impl/azureDeployImpl.js.map +1 -1
  22. package/build/component/driver/interface/buildAndDeployArgs.d.ts +1 -1
  23. package/build/component/driver/interface/buildAndDeployArgs.d.ts.map +1 -1
  24. package/build/component/driver/interface/commonArgs.d.ts +1 -2
  25. package/build/component/driver/interface/commonArgs.d.ts.map +1 -1
  26. package/build/component/driver/script/baseBuildDriver.d.ts +2 -1
  27. package/build/component/driver/script/baseBuildDriver.d.ts.map +1 -1
  28. package/build/component/driver/script/baseBuildDriver.js +2 -0
  29. package/build/component/driver/script/baseBuildDriver.js.map +1 -1
  30. package/build/component/driver/teamsApp/createAppPackage.d.ts +7 -0
  31. package/build/component/driver/teamsApp/createAppPackage.d.ts.map +1 -1
  32. package/build/component/driver/teamsApp/createAppPackage.js +280 -86
  33. package/build/component/driver/teamsApp/createAppPackage.js.map +1 -1
  34. package/build/component/driver/teamsApp/teamsappMgr.d.ts +0 -2
  35. package/build/component/driver/teamsApp/teamsappMgr.d.ts.map +1 -1
  36. package/build/component/driver/teamsApp/teamsappMgr.js +0 -32
  37. package/build/component/driver/teamsApp/teamsappMgr.js.map +1 -1
  38. package/build/component/driver/teamsApp/validateAppPackage.d.ts +0 -13
  39. package/build/component/driver/teamsApp/validateAppPackage.d.ts.map +1 -1
  40. package/build/component/driver/teamsApp/validateAppPackage.js +3 -53
  41. package/build/component/driver/teamsApp/validateAppPackage.js.map +1 -1
  42. package/build/component/driver/util/utils.d.ts.map +1 -1
  43. package/build/component/driver/util/utils.js +0 -1
  44. package/build/component/driver/util/utils.js.map +1 -1
  45. package/build/component/feature/sso.js +2 -2
  46. package/build/component/feature/sso.js.map +1 -1
  47. package/build/component/generator/configFiles/configGenerator.js +1 -1
  48. package/build/component/generator/configFiles/configGenerator.js.map +1 -1
  49. package/build/component/generator/openApiSpec/common.js +1 -1
  50. package/build/component/generator/openApiSpec/common.js.map +1 -1
  51. package/build/component/generator/openApiSpec/helper.js +3 -3
  52. package/build/component/generator/openApiSpec/helper.js.map +1 -1
  53. package/build/component/generator/spfx/spfxGenerator.js +5 -5
  54. package/build/component/generator/spfx/spfxGenerator.js.map +1 -1
  55. package/build/component/m365/packageService.d.ts +5 -4
  56. package/build/component/m365/packageService.d.ts.map +1 -1
  57. package/build/component/m365/packageService.js +98 -22
  58. package/build/component/m365/packageService.js.map +1 -1
  59. package/build/component/m365/serviceConstant.d.ts.map +1 -1
  60. package/build/component/m365/serviceConstant.js +10 -0
  61. package/build/component/m365/serviceConstant.js.map +1 -1
  62. package/build/component/utils/envFunctionUtils.js +77 -22
  63. package/build/component/utils/envFunctionUtils.js.map +1 -1
  64. package/build/core/FxCore.d.ts +3 -4
  65. package/build/core/FxCore.d.ts.map +1 -1
  66. package/build/core/FxCore.declarativeAgent.js +1 -1
  67. package/build/core/FxCore.declarativeAgent.js.map +1 -1
  68. package/build/core/FxCore.js +21 -51
  69. package/build/core/FxCore.js.map +1 -1
  70. package/build/core/collaborator.d.ts +0 -1
  71. package/build/core/collaborator.d.ts.map +1 -1
  72. package/build/core/collaborator.js +0 -37
  73. package/build/core/collaborator.js.map +1 -1
  74. package/build/core/createFrontDoorAdapters.d.ts.map +1 -1
  75. package/build/core/createFrontDoorAdapters.js +4 -38
  76. package/build/core/createFrontDoorAdapters.js.map +1 -1
  77. package/build/core/createProjectFrontDoor.d.ts.map +1 -1
  78. package/build/core/createProjectFrontDoor.js +41 -6
  79. package/build/core/createProjectFrontDoor.js.map +1 -1
  80. package/build/core/modifyProjectFrontDoor.d.ts.map +1 -1
  81. package/build/core/modifyProjectFrontDoor.js +1 -0
  82. package/build/core/modifyProjectFrontDoor.js.map +1 -1
  83. package/build/error/teamsApp.d.ts +4 -1
  84. package/build/error/teamsApp.d.ts.map +1 -1
  85. package/build/error/teamsApp.js +20 -4
  86. package/build/error/teamsApp.js.map +1 -1
  87. package/build/index.d.ts +5 -6
  88. package/build/index.d.ts.map +1 -1
  89. package/build/index.js +12 -13
  90. package/build/index.js.map +1 -1
  91. package/build/question/other.d.ts.map +1 -1
  92. package/build/question/other.js +0 -3
  93. package/build/question/other.js.map +1 -1
  94. package/build/v4/buildTarget/parseSelector.d.ts.map +1 -1
  95. package/build/v4/buildTarget/parseSelector.js +6 -2
  96. package/build/v4/buildTarget/parseSelector.js.map +1 -1
  97. package/build/v4/buildTarget/resolveBuildTarget.d.ts +4 -1
  98. package/build/v4/buildTarget/resolveBuildTarget.d.ts.map +1 -1
  99. package/build/v4/buildTarget/resolveBuildTarget.js +23 -6
  100. package/build/v4/buildTarget/resolveBuildTarget.js.map +1 -1
  101. package/build/v4/surface/createSelectorWalk.d.ts.map +1 -1
  102. package/build/v4/surface/createSelectorWalk.js +3 -0
  103. package/build/v4/surface/createSelectorWalk.js.map +1 -1
  104. package/build/v4/surface/modifySelectorWalk.d.ts.map +1 -1
  105. package/build/v4/surface/modifySelectorWalk.js +3 -0
  106. package/build/v4/surface/modifySelectorWalk.js.map +1 -1
  107. package/package.json +6 -6
  108. package/resource/package.nls.json +7 -1
  109. package/resource/yaml-schema/v1.13/yaml.schema.json +1 -1
  110. package/resource/yaml-schema/yaml.schema.json +1 -1
  111. package/templates/configs/remote/python/env/.env.dev +1 -2
  112. package/templates/configs/remote/python/m365agents.yml.tpl +0 -1
  113. package/templates/configs/remote/typescript/env/.env.dev +1 -2
  114. package/templates/configs/remote/typescript/m365agents.yml.tpl +0 -1
  115. package/templates/fallback/common.zip +0 -0
  116. package/templates/fallback/csharp.zip +0 -0
  117. package/templates/fallback/js.zip +0 -0
  118. package/templates/fallback/python.zip +0 -0
  119. package/templates/fallback/ts.zip +0 -0
  120. package/templates/v4/floor.json +1 -1
  121. package/templates/v4/templates-metadata.zip +0 -0
  122. package/templates/v4/templates.zip +0 -0
  123. package/build/core/FxCoreClient.d.ts +0 -74
  124. package/build/core/FxCoreClient.d.ts.map +0 -1
  125. package/build/core/FxCoreClient.js +0 -141
  126. package/build/core/FxCoreClient.js.map +0 -1
  127. package/templates/metadata.zip +0 -0
@@ -90,15 +90,9 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
90
90
  }
91
91
  for (const file of relativeFiles) {
92
92
  const filePath = path.resolve(appDirectory, file);
93
- if (!(await fs_extra_1.default.pathExists(filePath))) {
94
- const error = new common_1.FileNotFoundError(exports.actionName, filePath, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage");
95
- return (0, teamsfx_api_1.err)(error);
96
- }
97
- const realFilePath = await fs_extra_1.default.realpath(filePath);
98
- const realAppDirectory = await fs_extra_1.default.realpath(appDirectory);
99
- const fileRelativePath = path.relative(realAppDirectory, realFilePath);
100
- if (fileRelativePath.startsWith("..")) {
101
- return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(filePath));
93
+ const validationResult = await this.validateReferencedFile(filePath, appDirectory, file);
94
+ if (validationResult.isErr()) {
95
+ return (0, teamsfx_api_1.err)(validationResult.error);
102
96
  }
103
97
  }
104
98
  // pre-check existence
@@ -129,19 +123,22 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
129
123
  if (additionalLanguages && additionalLanguages.length > 0) {
130
124
  for (const language of additionalLanguages) {
131
125
  const file = language.file;
132
- const fileName = path.join(appDirectory, file);
133
- if (!(await fs_extra_1.default.pathExists(fileName))) {
134
- return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, fileName, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
126
+ const fileName = path.resolve(appDirectory, file);
127
+ const validationResult = await this.validateReferencedFile(fileName, appDirectory, file);
128
+ if (validationResult.isErr()) {
129
+ return (0, teamsfx_api_1.err)(validationResult.error);
135
130
  }
136
131
  }
137
132
  }
138
133
  if (defaultLanguageFile) {
139
- const fileName = path.join(appDirectory, defaultLanguageFile);
140
- if (!(await fs_extra_1.default.pathExists(fileName))) {
141
- return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, fileName, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
134
+ const fileName = path.resolve(appDirectory, defaultLanguageFile);
135
+ const validationResult = await this.validateReferencedFile(fileName, appDirectory, defaultLanguageFile);
136
+ if (validationResult.isErr()) {
137
+ return (0, teamsfx_api_1.err)(validationResult.error);
142
138
  }
143
139
  }
144
140
  const zip = new adm_zip_1.default();
141
+ const resolvedJsonFiles = new Map();
145
142
  zip.addFile(constants_1.Constants.MANIFEST_FILE, Buffer.from(JSON.stringify(manifest, null, 4)));
146
143
  // icon images, relative path
147
144
  for (const icon of relativeFiles) {
@@ -156,9 +153,6 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
156
153
  const realFileName = await fs_extra_1.default.realpath(fileName);
157
154
  const realAppDirectory = await fs_extra_1.default.realpath(appDirectory);
158
155
  const relativePath = path.relative(realAppDirectory, realFileName);
159
- if (relativePath.startsWith("..")) {
160
- return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(fileName));
161
- }
162
156
  const resolvedLocFileRes = await ManifestUtils_1.manifestUtils.resolveLocFile(fileName, context);
163
157
  if (resolvedLocFileRes.isErr()) {
164
158
  return (0, teamsfx_api_1.err)(resolvedLocFileRes.error);
@@ -173,9 +167,6 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
173
167
  const realFileName = await fs_extra_1.default.realpath(fileName);
174
168
  const realAppDirectory = await fs_extra_1.default.realpath(appDirectory);
175
169
  const relativePath = path.relative(realAppDirectory, realFileName);
176
- if (relativePath.startsWith("..")) {
177
- return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(fileName));
178
- }
179
170
  const resolvedLocFileRes = await ManifestUtils_1.manifestUtils.resolveLocFile(fileName, context);
180
171
  if (resolvedLocFileRes.isErr()) {
181
172
  return (0, teamsfx_api_1.err)(resolvedLocFileRes.error);
@@ -187,7 +178,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
187
178
  // API ME, API specification and Adaptive card templates
188
179
  if (composeExtensionType == "apiBased" && apiSpecificationFile) {
189
180
  const apiSpecificationFilePath = path.resolve(appDirectory, apiSpecificationFile);
190
- const checkExistenceRes = await this.validateReferencedFile(apiSpecificationFilePath, appDirectory);
181
+ const checkExistenceRes = await this.validateReferencedFile(apiSpecificationFilePath, appDirectory, apiSpecificationFile);
191
182
  if (checkExistenceRes.isErr()) {
192
183
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
193
184
  }
@@ -199,7 +190,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
199
190
  for (const command of commands) {
200
191
  if (command.apiResponseRenderingTemplateFile) {
201
192
  const adaptiveCardFile = path.resolve(appDirectory, command.apiResponseRenderingTemplateFile);
202
- const checkExistenceRes = await this.validateReferencedFile(adaptiveCardFile, appDirectory);
193
+ const checkExistenceRes = await this.validateReferencedFile(adaptiveCardFile, appDirectory, command.apiResponseRenderingTemplateFile);
203
194
  if (checkExistenceRes.isErr()) {
204
195
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
205
196
  }
@@ -212,13 +203,13 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
212
203
  // Copilot GPT
213
204
  if (declarativeAgents?.length && declarativeAgents[0].file) {
214
205
  const declarativeAgentManifestFile = path.resolve(hasTTKGeneratedFolder ? generatedFolder : appDirectory, declarativeAgents[0].file);
215
- const checkExistenceRes = await this.validateReferencedFile(declarativeAgentManifestFile, appDirectory);
206
+ const checkExistenceRes = await this.validateReferencedFile(declarativeAgentManifestFile, appDirectory, declarativeAgents[0].file);
216
207
  if (checkExistenceRes.isErr()) {
217
208
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
218
209
  }
219
210
  const addFileWithVariableRes = await this.addFileWithVariable(zip, declarativeAgents[0].file, declarativeAgentManifestFile, envFunctionUtils_1.ManifestType.DeclarativeCopilotManifest, context, shouldwriteAllManifest
220
211
  ? path.join(jsonFileDir, path.relative(appDirectory, declarativeAgentManifestFile))
221
- : undefined);
212
+ : undefined, resolvedJsonFiles);
222
213
  if (addFileWithVariableRes.isErr()) {
223
214
  return (0, teamsfx_api_1.err)(addFileWithVariableRes.error);
224
215
  }
@@ -238,7 +229,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
238
229
  const pluginFileAbsolutePath = path.resolve(path.dirname(declarativeAgentManifestFile), pluginFile);
239
230
  const pluginFileRelativePath = path.relative(hasTTKGeneratedFolder ? generatedFolder : appDirectory, pluginFileAbsolutePath);
240
231
  const useForwardSlash = declarativeAgents[0].file.concat(pluginFile).includes("/");
241
- const addPluginRes = await this.addPlugin(zip, (0, utils_2.normalizePath)(pluginFileRelativePath, useForwardSlash), hasTTKGeneratedFolder ? generatedFolder : appDirectory, context, !shouldwriteAllManifest ? undefined : jsonFileDir, hasTTKGeneratedFolder ? appDirectory : undefined);
232
+ const addPluginRes = await this.addPlugin(zip, (0, utils_2.normalizePath)(pluginFileRelativePath, useForwardSlash), hasTTKGeneratedFolder ? generatedFolder : appDirectory, context, !shouldwriteAllManifest ? undefined : jsonFileDir, hasTTKGeneratedFolder ? appDirectory : undefined, resolvedJsonFiles, pluginFile);
242
233
  if (addPluginRes.isErr()) {
243
234
  return (0, teamsfx_api_1.err)(addPluginRes.error);
244
235
  }
@@ -264,7 +255,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
264
255
  for (const file of fileArr) {
265
256
  const knowledgeFileAbsolutePath = path.resolve(appDirectory, file);
266
257
  // check existence
267
- const checkExistenceRes = await this.validateReferencedFile(knowledgeFileAbsolutePath, appDirectory);
258
+ const checkExistenceRes = await this.validateReferencedFile(knowledgeFileAbsolutePath, appDirectory, file);
268
259
  if (checkExistenceRes.isErr()) {
269
260
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
270
261
  }
@@ -284,16 +275,15 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
284
275
  // Resolve skill folder relative to appDirectory (not .generated/)
285
276
  // since skill folders don't support env var substitution
286
277
  const skillFolderAbsolutePath = path.resolve(appDirectory, skill.folder);
287
- const checkExistenceRes = await this.validateReferencedFile(skillFolderAbsolutePath, appDirectory);
278
+ const checkExistenceRes = await this.validateReferencedFile(skillFolderAbsolutePath, appDirectory, skill.folder);
288
279
  if (checkExistenceRes.isErr()) {
289
280
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
290
281
  }
291
282
  const skillMdPath = path.join(skillFolderAbsolutePath, "SKILL.md");
292
283
  if (!(await fs_extra_1.default.pathExists(skillMdPath))) {
293
- return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, skillMdPath, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
284
+ return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, path.basename(skillMdPath), "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
294
285
  }
295
- const skillRelativePath = path.relative(appDirectory, skillFolderAbsolutePath);
296
- zip.addLocalFolder(skillFolderAbsolutePath, skillRelativePath);
286
+ await this.addLocalFolderRecursive(zip, skillFolderAbsolutePath, appDirectory);
297
287
  }
298
288
  }
299
289
  }
@@ -318,14 +308,53 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
318
308
  return (0, teamsfx_api_1.err)(addConnectorsRes.error);
319
309
  }
320
310
  }
321
- zip.writeZip(zipFileName);
322
- // Validate zip package size against 10 MB hard limit
311
+ if (resolvedJsonFiles.has(teamsManifestJsonFileName)) {
312
+ return (0, teamsfx_api_1.err)(new common_1.InvalidActionInputError(exports.actionName, ["outputFolder"], "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
313
+ }
314
+ resolvedJsonFiles.set(teamsManifestJsonFileName, JSON.stringify(manifest, null, 4));
315
+ const outputFileNames = [zipFileName, ...resolvedJsonFiles.keys()];
316
+ const canonicalOutputPaths = [];
317
+ let hasInvalidOutputPath = false;
318
+ for (const outputFileName of outputFileNames) {
319
+ let canonicalOutputPath;
320
+ try {
321
+ if (await this.isDirectory(outputFileName)) {
322
+ hasInvalidOutputPath = true;
323
+ break;
324
+ }
325
+ canonicalOutputPath = await this.getCanonicalDestinationPath(outputFileName);
326
+ }
327
+ catch (error) {
328
+ return (0, teamsfx_api_1.err)(new teamsApp_1.AppPackageFileSystemError(error, outputFileName));
329
+ }
330
+ if (canonicalOutputPaths.some((outputPath) => this.isPathContained(outputPath, canonicalOutputPath) ||
331
+ this.isPathContained(canonicalOutputPath, outputPath))) {
332
+ hasInvalidOutputPath = true;
333
+ break;
334
+ }
335
+ canonicalOutputPaths.push(canonicalOutputPath);
336
+ }
337
+ if (hasInvalidOutputPath) {
338
+ return (0, teamsfx_api_1.err)(new common_1.InvalidActionInputError(exports.actionName, ["outputZipPath", args.outputJsonPath ? "outputJsonPath" : "outputFolder"], "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
339
+ }
340
+ const stagedZipFileName = this.getStagedOutputPath(zipFileName);
323
341
  const maxPackageSize = 10 * 1024 * 1024;
324
- const zipStats = await fs_extra_1.default.stat(zipFileName);
325
- if (zipStats.size > maxPackageSize) {
326
- return (0, teamsfx_api_1.err)(new teamsApp_1.AppPackageSizeExceededError(zipStats.size, maxPackageSize));
342
+ try {
343
+ zip.writeZip(stagedZipFileName);
344
+ const zipStats = await fs_extra_1.default.stat(stagedZipFileName);
345
+ if (zipStats.size > maxPackageSize) {
346
+ return (0, teamsfx_api_1.err)(new teamsApp_1.AppPackageSizeExceededError(zipStats.size, maxPackageSize));
347
+ }
348
+ await this.publishOutputs(stagedZipFileName, zipFileName, resolvedJsonFiles);
349
+ }
350
+ catch (error) {
351
+ return (0, teamsfx_api_1.err)(error instanceof teamsApp_1.AppPackageFileSystemError
352
+ ? error
353
+ : new teamsApp_1.AppPackageFileSystemError(error, zipFileName));
354
+ }
355
+ finally {
356
+ await fs_extra_1.default.remove(stagedZipFileName).catch(() => { });
327
357
  }
328
- await this.writeJsonFile(teamsManifestJsonFileName, JSON.stringify(manifest, null, 4));
329
358
  const builtSuccess = [
330
359
  { content: "(√)Done: ", color: teamsfx_api_1.Colors.BRIGHT_GREEN },
331
360
  { content: "App Package ", color: teamsfx_api_1.Colors.BRIGHT_WHITE },
@@ -357,33 +386,47 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
357
386
  return (0, teamsfx_api_1.ok)(undefined);
358
387
  }
359
388
  }
360
- async validateReferencedFile(file, directory) {
389
+ async validateReferencedFile(file, directory, originalReference) {
390
+ const displayDirectory = path.resolve(directory);
391
+ const resolvedFile = path.resolve(file);
392
+ const fileReference = originalReference ?? path.relative(displayDirectory, resolvedFile);
393
+ if (!this.isPathContained(directory, file)) {
394
+ return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(fileReference, resolvedFile, displayDirectory));
395
+ }
361
396
  if (!(await fs_extra_1.default.pathExists(file))) {
362
- return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, file, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
397
+ return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, path.basename(file), "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
398
+ }
399
+ let realFile;
400
+ let realDirectory;
401
+ try {
402
+ realFile = await fs_extra_1.default.realpath(file);
403
+ realDirectory = await fs_extra_1.default.realpath(directory);
404
+ }
405
+ catch (error) {
406
+ return (0, teamsfx_api_1.err)(new teamsApp_1.AppPackageFileSystemError(error, file));
363
407
  }
364
- const realFile = await fs_extra_1.default.realpath(file);
365
- const realDirectory = await fs_extra_1.default.realpath(directory);
366
- const relativePath = path.relative(realDirectory, realFile);
367
- if (relativePath.startsWith("..")) {
368
- return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(file));
408
+ if (!this.isPathContained(realDirectory, realFile)) {
409
+ return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(fileReference, realFile, displayDirectory));
369
410
  }
370
411
  return (0, teamsfx_api_1.ok)(undefined);
371
412
  }
413
+ isPathContained(directory, file) {
414
+ const relativePath = path.relative(directory, file);
415
+ return (relativePath === "" ||
416
+ (relativePath !== ".." &&
417
+ !relativePath.startsWith(`..${path.sep}`) &&
418
+ !path.isAbsolute(relativePath)));
419
+ }
372
420
  async addAgentSkillFolders(zip, agentSkills, appDirectory) {
373
421
  for (const skill of agentSkills) {
374
422
  const skillFolderAbs = path.resolve(appDirectory, skill.folder);
375
- if (!(await fs_extra_1.default.pathExists(skillFolderAbs))) {
376
- return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, skillFolderAbs, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
423
+ const validationResult = await this.validateReferencedFile(skillFolderAbs, appDirectory, skill.folder);
424
+ if (validationResult.isErr()) {
425
+ return (0, teamsfx_api_1.err)(validationResult.error);
377
426
  }
378
427
  const skillMdPath = path.join(skillFolderAbs, "SKILL.md");
379
428
  if (!(await fs_extra_1.default.pathExists(skillMdPath))) {
380
- return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, skillMdPath, "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
381
- }
382
- const realSkillFolder = await fs_extra_1.default.realpath(skillFolderAbs);
383
- const realAppDirectory = await fs_extra_1.default.realpath(appDirectory);
384
- const relativeToApp = path.relative(realAppDirectory, realSkillFolder);
385
- if (relativeToApp.startsWith("..") || path.isAbsolute(relativeToApp)) {
386
- return (0, teamsfx_api_1.err)(new teamsApp_1.InvalidFileOutsideOfTheDirectotryError(skillFolderAbs));
429
+ return (0, teamsfx_api_1.err)(new common_1.FileNotFoundError(exports.actionName, path.basename(skillMdPath), "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
387
430
  }
388
431
  await this.addLocalFolderRecursive(zip, skillFolderAbs, appDirectory);
389
432
  }
@@ -396,7 +439,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
396
439
  continue;
397
440
  }
398
441
  const mcpFileAbsolutePath = path.resolve(appDirectory, mcpToolDescriptionFile);
399
- const checkExistenceRes = await this.validateReferencedFile(mcpFileAbsolutePath, appDirectory);
442
+ const checkExistenceRes = await this.validateReferencedFile(mcpFileAbsolutePath, appDirectory, mcpToolDescriptionFile);
400
443
  if (checkExistenceRes.isErr()) {
401
444
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
402
445
  }
@@ -418,8 +461,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
418
461
  }
419
462
  else if (entry.isFile()) {
420
463
  const realEntryAbs = await fs_extra_1.default.realpath(entryAbs);
421
- const relToApp = path.relative(realAppDirectory, realEntryAbs);
422
- if (relToApp.startsWith("..")) {
464
+ if (!this.isPathContained(realAppDirectory, realEntryAbs)) {
423
465
  continue;
424
466
  }
425
467
  const relDir = path.dirname(path.relative(appDirectory, entryAbs));
@@ -436,9 +478,9 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
436
478
  * @param outputDirectory optional. Folder where we should put the resolved manifest in.
437
479
  * @returns result of adding plugin file and plugin related files
438
480
  */
439
- async addPlugin(zip, pluginRelativePath, appDirectory, context, outputDirectory, defaultAppDirectry) {
481
+ async addPlugin(zip, pluginRelativePath, appDirectory, context, outputDirectory, defaultAppDirectry, resolvedJsonFiles, originalReference) {
440
482
  const pluginFile = path.resolve(appDirectory, pluginRelativePath);
441
- const checkExistenceRes = await this.validateReferencedFile(pluginFile, appDirectory);
483
+ const checkExistenceRes = await this.validateReferencedFile(pluginFile, appDirectory, originalReference ?? pluginRelativePath);
442
484
  if (checkExistenceRes.isErr()) {
443
485
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
444
486
  }
@@ -453,12 +495,16 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
453
495
  if (pluginFileContent.functions) {
454
496
  for (const func of pluginFileContent.functions) {
455
497
  if (func.capabilities?.response_semantics?.static_template?.file) {
456
- const staticTemplateFile = await this.getAdaptiveCardTemplateFile(context, pluginFile, func, appDirectory, defaultAppDirectry);
498
+ const staticTemplateFileResult = await this.getAdaptiveCardTemplateFile(context, pluginFile, func, appDirectory, defaultAppDirectry);
499
+ if (staticTemplateFileResult.isErr()) {
500
+ return (0, teamsfx_api_1.err)(staticTemplateFileResult.error);
501
+ }
502
+ const staticTemplateFile = staticTemplateFileResult.value;
457
503
  if (!staticTemplateFile) {
458
504
  continue;
459
505
  }
460
506
  if (Object.keys(func.capabilities.response_semantics.static_template).length > 1) {
461
- context.logProvider.warning((0, localizeUtils_1.getLocalizedString)("plugins.appstudio.createPackage.aiPlugin.overrideWarning", pluginFile, func.name));
507
+ context.logProvider.warning((0, localizeUtils_1.getLocalizedString)("plugins.appstudio.createPackage.aiPlugin.overrideWarning", path.basename(pluginFile), func.name));
462
508
  }
463
509
  const staticTemplateFileContent = await fs_extra_1.default.readJSON(staticTemplateFile);
464
510
  func.capabilities.response_semantics.static_template = staticTemplateFileContent;
@@ -477,22 +523,30 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
477
523
  if (containExternalAdaptiveCard) {
478
524
  await (0, utils_1.updateVersionForTeamsAppYamlFile)(context.projectPath);
479
525
  }
480
- if (namespaceContainsUnderscore || containExternalAdaptiveCard) {
481
- tempFolder = path.join(appDirectory, ".tmp");
482
- await fs_extra_1.default.ensureDir(tempFolder);
483
- tmpPluginFile = path.join(tempFolder, `tmp-ai-plugin-${uuid.v4().slice(0, 6)}.json`);
484
- const processedFunctionRes = await (0, envFunctionUtils_1.expandVariableWithFunction)(JSON.stringify(pluginFileContent), context, undefined, true, envFunctionUtils_1.ManifestType.PluginManifest, pluginFile);
485
- if (processedFunctionRes.isErr()) {
486
- return (0, teamsfx_api_1.err)(processedFunctionRes.error);
526
+ let addFileWithVariableRes;
527
+ try {
528
+ if (namespaceContainsUnderscore || containExternalAdaptiveCard) {
529
+ const processedFunctionRes = await (0, envFunctionUtils_1.expandVariableWithFunction)(JSON.stringify(pluginFileContent), context, undefined, true, envFunctionUtils_1.ManifestType.PluginManifest, pluginFile);
530
+ if (processedFunctionRes.isErr()) {
531
+ return (0, teamsfx_api_1.err)(processedFunctionRes.error);
532
+ }
533
+ pluginFileContent = JSON.parse(processedFunctionRes.value);
534
+ tempFolder = await fs_extra_1.default.mkdtemp(path.join(appDirectory, ".tmp-"));
535
+ const tempFolderValidation = await this.validateReferencedFile(tempFolder, appDirectory);
536
+ if (tempFolderValidation.isErr()) {
537
+ return (0, teamsfx_api_1.err)(tempFolderValidation.error);
538
+ }
539
+ tmpPluginFile = path.join(tempFolder, `tmp-ai-plugin-${uuid.v4().slice(0, 6)}.json`);
540
+ await fs_extra_1.default.writeJSON(tmpPluginFile, pluginFileContent, { spaces: 4 });
487
541
  }
488
- pluginFileContent = JSON.parse(processedFunctionRes.value);
489
- await fs_extra_1.default.writeJSON(tmpPluginFile, pluginFileContent, { spaces: 4 });
542
+ addFileWithVariableRes = await this.addFileWithVariable(zip, pluginRelativePath, tmpPluginFile, envFunctionUtils_1.ManifestType.PluginManifest, context, !outputDirectory
543
+ ? undefined
544
+ : path.join(outputDirectory, path.relative(appDirectory, pluginFile)), resolvedJsonFiles);
490
545
  }
491
- const addFileWithVariableRes = await this.addFileWithVariable(zip, pluginRelativePath, tmpPluginFile, envFunctionUtils_1.ManifestType.PluginManifest, context, !outputDirectory
492
- ? undefined
493
- : path.join(outputDirectory, path.relative(appDirectory, pluginFile)));
494
- if (containExternalAdaptiveCard && tmpPluginFile !== pluginFile && tempFolder) {
495
- await fs_extra_1.default.remove(tempFolder);
546
+ finally {
547
+ if (tempFolder) {
548
+ await fs_extra_1.default.remove(tempFolder);
549
+ }
496
550
  }
497
551
  if (addFileWithVariableRes.isErr()) {
498
552
  return (0, teamsfx_api_1.err)(addFileWithVariableRes.error);
@@ -522,7 +576,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
522
576
  if (runtime.type === "OpenApi" && runtime.spec?.url) {
523
577
  const specFile = path.resolve(path.dirname(pluginFilePath), runtime.spec.url);
524
578
  // add openapi spec
525
- const checkExistenceRes = await this.validateReferencedFile(specFile, appDirectory);
579
+ const checkExistenceRes = await this.validateReferencedFile(specFile, appDirectory, runtime.spec.url);
526
580
  if (checkExistenceRes.isErr()) {
527
581
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
528
582
  }
@@ -537,7 +591,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
537
591
  runtime.spec?.mcp_tool_description?.file) {
538
592
  const mcpFile = path.resolve(path.dirname(pluginFilePath), runtime.spec.mcp_tool_description.file);
539
593
  // add mcp tool description file
540
- const checkExistenceRes = await this.validateReferencedFile(mcpFile, appDirectory);
594
+ const checkExistenceRes = await this.validateReferencedFile(mcpFile, appDirectory, runtime.spec.mcp_tool_description.file);
541
595
  if (checkExistenceRes.isErr()) {
542
596
  return (0, teamsfx_api_1.err)(checkExistenceRes.error);
543
597
  }
@@ -548,8 +602,7 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
548
602
  }
549
603
  return (0, teamsfx_api_1.ok)(undefined);
550
604
  }
551
- async addFileWithVariable(zip, entryName, filePath, manifestType, context, outputPath // If outputPath exists, we will write down the file after replacing placeholders.
552
- ) {
605
+ async addFileWithVariable(zip, entryName, filePath, manifestType, context, outputPath, resolvedJsonFiles) {
553
606
  const expandedEnvVarResult = await CreateAppPackageDriver_1.expandEnvVars(filePath, context, manifestType);
554
607
  if (expandedEnvVarResult.isErr()) {
555
608
  return (0, teamsfx_api_1.err)(expandedEnvVarResult.error);
@@ -558,7 +611,11 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
558
611
  const attr = await fs_extra_1.default.stat(filePath);
559
612
  zip.addFile(entryName, Buffer.from(content), "", attr.mode);
560
613
  if (outputPath && path.extname(outputPath).toLowerCase() === ".json") {
561
- await this.writeJsonFile(`${outputPath.substring(0, outputPath.length - 5)}.${process.env.TEAMSFX_ENV}.json`, content);
614
+ const resolvedOutputPath = `${outputPath.substring(0, outputPath.length - 5)}.${process.env.TEAMSFX_ENV}.json`;
615
+ if (resolvedJsonFiles?.has(resolvedOutputPath)) {
616
+ return (0, teamsfx_api_1.err)(new common_1.InvalidActionInputError(exports.actionName, ["outputFolder"], "https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"));
617
+ }
618
+ resolvedJsonFiles?.set(resolvedOutputPath, content);
562
619
  }
563
620
  return (0, teamsfx_api_1.ok)(undefined);
564
621
  }
@@ -570,26 +627,163 @@ let CreateAppPackageDriver = CreateAppPackageDriver_1 = class CreateAppPackageDr
570
627
  await fs_extra_1.default.chmod(jsonFileName, 0o777);
571
628
  }
572
629
  await fs_extra_1.default.ensureDir(path.dirname(jsonFileName));
573
- await fs_extra_1.default.writeFile(jsonFileName, content);
630
+ await fs_extra_1.default.outputFile(jsonFileName, content);
574
631
  await fs_extra_1.default.chmod(jsonFileName, 0o444);
575
632
  }
633
+ getStagedOutputPath(outputPath) {
634
+ return path.join(path.dirname(outputPath), `.${path.basename(outputPath)}.${uuid.v4()}.tmp`);
635
+ }
636
+ async isDirectory(filePath) {
637
+ try {
638
+ return (await fs_extra_1.default.stat(filePath)).isDirectory();
639
+ }
640
+ catch (error) {
641
+ if (this.isFileNotFoundError(error)) {
642
+ return false;
643
+ }
644
+ throw error;
645
+ }
646
+ }
647
+ async getCanonicalDestinationPath(outputPath) {
648
+ try {
649
+ return await fs_extra_1.default.realpath(outputPath);
650
+ }
651
+ catch (error) {
652
+ if (!this.isFileNotFoundError(error)) {
653
+ throw error;
654
+ }
655
+ }
656
+ const missingDirectories = [];
657
+ let ancestor = path.dirname(outputPath);
658
+ while (true) {
659
+ try {
660
+ const realAncestor = await fs_extra_1.default.realpath(ancestor);
661
+ return path.join(realAncestor, ...missingDirectories, path.basename(outputPath));
662
+ }
663
+ catch (error) {
664
+ if (!this.isFileNotFoundError(error)) {
665
+ throw error;
666
+ }
667
+ const parent = path.dirname(ancestor);
668
+ if (parent === ancestor) {
669
+ throw error;
670
+ }
671
+ missingDirectories.unshift(path.basename(ancestor));
672
+ ancestor = parent;
673
+ }
674
+ }
675
+ }
676
+ async publishOutputs(stagedZipFile, outputZipFile, jsonFiles) {
677
+ const stagedJsonFiles = new Map();
678
+ const backupFiles = new Map();
679
+ const publishedFiles = [];
680
+ let publicationError;
681
+ try {
682
+ for (const [jsonFile, content] of jsonFiles) {
683
+ const stagedJsonFile = this.getStagedOutputPath(jsonFile);
684
+ stagedJsonFiles.set(jsonFile, stagedJsonFile);
685
+ await this.writeJsonFile(stagedJsonFile, content);
686
+ }
687
+ for (const [jsonFile, stagedJsonFile] of stagedJsonFiles) {
688
+ await this.backUpOutputFile(jsonFile, backupFiles);
689
+ await fs_extra_1.default.rename(stagedJsonFile, jsonFile);
690
+ publishedFiles.push(jsonFile);
691
+ }
692
+ await this.backUpOutputFile(outputZipFile, backupFiles);
693
+ await fs_extra_1.default.rename(stagedZipFile, outputZipFile);
694
+ publishedFiles.push(outputZipFile);
695
+ }
696
+ catch (error) {
697
+ let rollbackError;
698
+ for (const publishedFile of publishedFiles.reverse()) {
699
+ try {
700
+ await fs_extra_1.default.chmod(publishedFile, 0o777);
701
+ }
702
+ catch (cleanupError) {
703
+ if (!this.isFileNotFoundError(cleanupError)) {
704
+ rollbackError ??= cleanupError;
705
+ }
706
+ }
707
+ try {
708
+ await fs_extra_1.default.remove(publishedFile);
709
+ }
710
+ catch (cleanupError) {
711
+ rollbackError ??= cleanupError;
712
+ }
713
+ }
714
+ for (const [outputFile, backupFile] of Array.from(backupFiles.entries()).reverse()) {
715
+ try {
716
+ await fs_extra_1.default.rename(backupFile, outputFile);
717
+ }
718
+ catch (restoreError) {
719
+ rollbackError ??= restoreError;
720
+ }
721
+ }
722
+ if (rollbackError) {
723
+ publicationError = rollbackError;
724
+ }
725
+ else {
726
+ publicationError = error;
727
+ }
728
+ }
729
+ let stagedCleanupError;
730
+ for (const stagedJsonFile of stagedJsonFiles.values()) {
731
+ try {
732
+ await fs_extra_1.default.remove(stagedJsonFile);
733
+ }
734
+ catch (error) {
735
+ stagedCleanupError ??= error;
736
+ }
737
+ }
738
+ if (publicationError) {
739
+ throw new teamsApp_1.AppPackageFileSystemError(publicationError, outputZipFile);
740
+ }
741
+ if (stagedCleanupError) {
742
+ throw new teamsApp_1.AppPackageFileSystemError(stagedCleanupError, outputZipFile);
743
+ }
744
+ for (const backupFile of backupFiles.values()) {
745
+ await fs_extra_1.default.chmod(backupFile, 0o600).catch(() => { });
746
+ await fs_extra_1.default.remove(backupFile).catch(() => { });
747
+ }
748
+ }
749
+ async backUpOutputFile(outputFile, backupFiles) {
750
+ const backupFile = this.getStagedOutputPath(outputFile);
751
+ try {
752
+ await fs_extra_1.default.rename(outputFile, backupFile);
753
+ backupFiles.set(outputFile, backupFile);
754
+ }
755
+ catch (error) {
756
+ if (!this.isFileNotFoundError(error)) {
757
+ throw error;
758
+ }
759
+ }
760
+ }
761
+ isFileNotFoundError(error) {
762
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
763
+ }
576
764
  async getAdaptiveCardTemplateFile(context, pluginFile, func, appDirectory, defaultAppDirectry) {
577
765
  let staticTemplateFile = path.resolve(defaultAppDirectry ?? path.dirname(pluginFile), func.capabilities.response_semantics.static_template.file);
578
- let checkExistenceRes = await this.validateReferencedFile(staticTemplateFile, defaultAppDirectry ?? appDirectory);
766
+ let checkExistenceRes = await this.validateReferencedFile(staticTemplateFile, defaultAppDirectry ?? appDirectory, func.capabilities.response_semantics.static_template.file);
579
767
  if (checkExistenceRes.isOk()) {
580
- return staticTemplateFile;
768
+ return (0, teamsfx_api_1.ok)(staticTemplateFile);
769
+ }
770
+ if (checkExistenceRes.error instanceof teamsApp_1.InvalidFileOutsideOfTheDirectotryError) {
771
+ return (0, teamsfx_api_1.err)(checkExistenceRes.error);
581
772
  }
582
773
  if (defaultAppDirectry) {
583
774
  // Try generated folder
584
775
  staticTemplateFile = path.resolve(appDirectory, func.capabilities.response_semantics.static_template.file);
585
- checkExistenceRes = await this.validateReferencedFile(staticTemplateFile, appDirectory);
776
+ checkExistenceRes = await this.validateReferencedFile(staticTemplateFile, appDirectory, func.capabilities.response_semantics.static_template.file);
586
777
  }
587
778
  if (checkExistenceRes.isErr()) {
779
+ if (checkExistenceRes.error instanceof teamsApp_1.InvalidFileOutsideOfTheDirectotryError) {
780
+ return (0, teamsfx_api_1.err)(checkExistenceRes.error);
781
+ }
588
782
  delete func.capabilities.response_semantics.static_template;
589
- context.logProvider.warning((0, localizeUtils_1.getLocalizedString)("plugins.appstudio.createPackage.aiPlugin.invalidFilePropertyWarning", pluginFile, func.name));
590
- return undefined;
783
+ context.logProvider.warning((0, localizeUtils_1.getLocalizedString)("plugins.appstudio.createPackage.aiPlugin.invalidFilePropertyWarning", path.basename(pluginFile), func.name));
784
+ return (0, teamsfx_api_1.ok)(undefined);
591
785
  }
592
- return staticTemplateFile;
786
+ return (0, teamsfx_api_1.ok)(staticTemplateFile);
593
787
  }
594
788
  };
595
789
  exports.CreateAppPackageDriver = CreateAppPackageDriver;