@synopackageland/cli 0.6.1 → 0.7.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.
Files changed (578) hide show
  1. package/CHANGELOG.md +613 -0
  2. package/README.md +81 -89
  3. package/dist/add.js +39 -16
  4. package/dist/build-spk/delegate-scope.d.ts +6 -0
  5. package/dist/build-spk/delegate-scope.js +34 -0
  6. package/dist/build-spk/dsm-arch.d.ts +7 -1
  7. package/dist/build-spk/dsm-arch.js +24 -28
  8. package/dist/build-spk/dsm-platforms.json +39 -0
  9. package/dist/build-spk/dsm-version.d.ts +11 -0
  10. package/dist/build-spk/dsm-version.js +17 -0
  11. package/dist/build-spk/gateway.d.ts +1 -1
  12. package/dist/build-spk/gateway.js +2 -2
  13. package/dist/build-spk/generator.js +30 -5
  14. package/dist/build-spk/notices.js +4 -1
  15. package/dist/build-spk/resource-worker.js +3 -0
  16. package/dist/build-spk/wizard-messages.d.ts +66 -0
  17. package/dist/build-spk/wizard-messages.js +75 -9
  18. package/dist/cli.js +15 -7
  19. package/dist/contract/schema-validate.js +8 -0
  20. package/dist/contract/validate.js +30 -0
  21. package/dist/deploy/deploy.d.ts +1 -1
  22. package/dist/deploy/deploy.js +8 -0
  23. package/dist/deploy/plan.js +1 -1
  24. package/dist/deploy/spk-version.js +1 -1
  25. package/dist/error-registry.js +43 -15
  26. package/dist/host/dsm-client.d.ts +8 -4
  27. package/dist/host/dsm-client.js +10 -4
  28. package/dist/host/types.d.ts +2 -1
  29. package/dist/info.js +18 -2
  30. package/dist/init.d.ts +3 -0
  31. package/dist/init.js +49 -18
  32. package/dist/package-metadata.d.ts +21 -0
  33. package/dist/package-metadata.js +101 -0
  34. package/dist/portal/alias.d.ts +25 -0
  35. package/dist/portal/alias.js +48 -0
  36. package/dist/portal/package.d.ts +33 -0
  37. package/dist/portal/package.js +116 -0
  38. package/dist/runtime/delegate-contract.d.ts +79 -0
  39. package/dist/runtime/delegate-contract.js +27 -0
  40. package/dist/runtime/executor-build.d.ts +1 -1
  41. package/dist/runtime/executor-build.js +5 -4
  42. package/dist/runtime/executor-inspect.d.ts +3 -0
  43. package/dist/runtime/executor-inspect.js +11 -5
  44. package/dist/runtime/executor-policy.d.ts +12 -0
  45. package/dist/runtime/executor-policy.js +43 -3
  46. package/dist/runtime/executor-scope-task.d.ts +4 -0
  47. package/dist/runtime/executor-scope-task.js +21 -0
  48. package/dist/runtime/executor-tasks.d.ts +2 -1
  49. package/dist/runtime/executor-tasks.js +4 -4
  50. package/dist/skill.js +1 -0
  51. package/dist/standalone/api-permissions.d.ts +10 -0
  52. package/dist/standalone/api-permissions.js +19 -2
  53. package/dist/standalone/background.d.ts +16 -0
  54. package/dist/standalone/background.js +69 -2
  55. package/dist/standalone/binary.d.ts +1 -1
  56. package/dist/standalone/binary.js +22 -8
  57. package/dist/standalone/build.d.ts +1 -1
  58. package/dist/standalone/build.js +38 -8
  59. package/dist/standalone/daemon.d.ts +1 -1
  60. package/dist/standalone/daemon.js +2 -1
  61. package/dist/standalone/dsm-window.d.ts +3 -1
  62. package/dist/standalone/dsm-window.js +72 -15
  63. package/dist/standalone/inspect-spk.d.ts +8 -0
  64. package/dist/standalone/inspect-spk.js +105 -26
  65. package/dist/standalone/lifecycle.js +86 -8
  66. package/dist/standalone/manifest.d.ts +13 -0
  67. package/dist/standalone/manifest.js +57 -8
  68. package/dist/standalone/native-authorization-window.d.ts +1 -1
  69. package/dist/standalone/native-authorization-window.js +2 -0
  70. package/dist/standalone/native-layout.d.ts +3 -0
  71. package/dist/standalone/native-layout.js +37 -5
  72. package/dist/standalone/portal-window.d.ts +21 -0
  73. package/dist/standalone/portal-window.js +155 -0
  74. package/dist/standalone/portal.d.ts +4 -0
  75. package/dist/standalone/portal.js +4 -0
  76. package/dist/standalone/resource.d.ts +5 -3
  77. package/dist/standalone/resource.js +6 -3
  78. package/dist/standalone/root-window.js +62 -15
  79. package/dist/standalone/spk.d.ts +1 -1
  80. package/dist/standalone/spk.js +25 -7
  81. package/dist/templates/_daemon/main_test.go +61 -8
  82. package/dist/templates/_executor/README.md +127 -16
  83. package/dist/templates/_executor/anchor.go +146 -0
  84. package/dist/templates/_executor/anchor_test.go +126 -0
  85. package/dist/templates/_executor/apppriv_review_test.go +1 -1
  86. package/dist/templates/_executor/cancel_contract_test.go +236 -0
  87. package/dist/templates/_executor/copy.go +64 -0
  88. package/dist/templates/_executor/copy_test.go +88 -0
  89. package/dist/templates/_executor/dsm.go +23 -10
  90. package/dist/templates/_executor/dsm_test.go +95 -1
  91. package/dist/templates/_executor/executor.go +260 -49
  92. package/dist/templates/_executor/executor_test.go +36 -6
  93. package/dist/templates/_executor/identity.go +27 -1
  94. package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
  95. package/dist/templates/_executor/identity_linux.go +82 -0
  96. package/dist/templates/_executor/identity_security_test.go +43 -0
  97. package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  98. package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  99. package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
  100. package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  101. package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
  102. package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
  103. package/dist/templates/_executor/lifecycle_test.go +11 -0
  104. package/dist/templates/_executor/link_linux.go +28 -0
  105. package/dist/templates/_executor/long_running_test.go +530 -0
  106. package/dist/templates/_executor/main.go +72 -20
  107. package/dist/templates/_executor/move_linux.go +490 -0
  108. package/dist/templates/_executor/move_linux_test.go +460 -0
  109. package/dist/templates/_executor/move_validation.go +46 -0
  110. package/dist/templates/_executor/move_validation_test.go +187 -0
  111. package/dist/templates/_executor/operations.go +926 -0
  112. package/dist/templates/_executor/platform_linux.go +24 -173
  113. package/dist/templates/_executor/platform_linux_test.go +9 -65
  114. package/dist/templates/_executor/platform_other.go +30 -4
  115. package/dist/templates/_executor/process.go +3 -0
  116. package/dist/templates/_executor/records.go +242 -0
  117. package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
  118. package/dist/templates/_executor/scope_client.go +37 -0
  119. package/dist/templates/_executor/scope_contract.go +12 -0
  120. package/dist/templates/_executor/selected_scope.go +146 -0
  121. package/dist/templates/_executor/selected_scope_test.go +186 -0
  122. package/dist/templates/_executor/status_disabled_test.go +33 -0
  123. package/dist/templates/_executor/store.go +4 -3
  124. package/dist/templates/_executor/supervise.go +109 -0
  125. package/dist/templates/_executor/supervise_test.go +130 -0
  126. package/dist/templates/_executor/task_race_review_test.go +1 -1
  127. package/dist/templates/_executor/tasks.go +7 -8
  128. package/dist/templates/_executor/tasks_review_test.go +1 -1
  129. package/dist/templates/_executor/tasks_test.go +4 -4
  130. package/dist/templates/_executor/watch.go +8 -0
  131. package/dist/templates/_executor/watch_test.go +23 -2
  132. package/dist/templates/_executor/write_review_linux_test.go +4 -12
  133. package/dist/templates/_shared/AGENTS.md +129 -0
  134. package/dist/templates/binary/dsm-package.yaml +24 -0
  135. package/dist/templates/binary/i18n/messages/de.json +4 -0
  136. package/dist/templates/binary/i18n/messages/en.json +4 -0
  137. package/dist/templates/binary/i18n/messages/es.json +4 -0
  138. package/dist/templates/binary/i18n/messages/fr.json +4 -0
  139. package/dist/templates/binary/i18n/messages/it.json +4 -0
  140. package/dist/templates/binary/i18n/messages/ja.json +4 -0
  141. package/dist/templates/binary/i18n/messages/ko.json +4 -0
  142. package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
  143. package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
  144. package/dist/templates/binary/ui/app.js +19 -4
  145. package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
  146. package/dist/templates/native-authorization/i18n/de.json +1 -0
  147. package/dist/templates/native-authorization/i18n/en.json +1 -0
  148. package/dist/templates/native-authorization/i18n/es.json +2 -1
  149. package/dist/templates/native-authorization/i18n/fr.json +1 -0
  150. package/dist/templates/native-authorization/i18n/it.json +11 -10
  151. package/dist/templates/native-authorization/i18n/ja.json +1 -0
  152. package/dist/templates/native-authorization/i18n/ko.json +10 -9
  153. package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
  154. package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
  155. package/dist/templates/native-go/README.md +43 -10
  156. package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
  157. package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
  158. package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  159. package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
  160. package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  161. package/dist/templates/native-go/backend/internal/api/server.go +18 -5
  162. package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  163. package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  164. package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
  165. package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
  166. package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
  167. package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
  168. package/dist/templates/native-go/backend/internal/background/store.go +16 -14
  169. package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
  170. package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  171. package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  172. package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  173. package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  174. package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  175. package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  176. package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
  177. package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  178. package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  179. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  180. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  181. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  182. package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  183. package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  184. package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  185. package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  186. package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  187. package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  188. package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
  189. package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
  190. package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  191. package/dist/templates/native-go/dsm-package.yaml +20 -1
  192. package/dist/templates/native-go/i18n/glossary.json +2 -1
  193. package/dist/templates/native-go/i18n/messages/de.json +1 -0
  194. package/dist/templates/native-go/i18n/messages/en.json +1 -0
  195. package/dist/templates/native-go/i18n/messages/es.json +1 -0
  196. package/dist/templates/native-go/i18n/messages/fr.json +1 -0
  197. package/dist/templates/native-go/i18n/messages/it.json +1 -0
  198. package/dist/templates/native-go/i18n/messages/ja.json +1 -0
  199. package/dist/templates/native-go/i18n/messages/ko.json +1 -0
  200. package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
  201. package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
  202. package/dist/templates/native-go/ui/app.css +10 -0
  203. package/dist/templates/native-go/ui/app.js +11 -1
  204. package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
  205. package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  206. package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  207. package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  208. package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  209. package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  210. package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  211. package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  212. package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  213. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  214. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  215. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  216. package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  217. package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  218. package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  219. package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  220. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  221. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  222. package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  223. package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  224. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  225. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  226. package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  227. package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  228. package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  229. package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  230. package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  231. package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  232. package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  233. package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  234. package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  235. package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  236. package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  237. package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  238. package/dist/templates/native-go-delegate/test.sh +1 -0
  239. package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  240. package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  241. package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  242. package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  243. package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  244. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  245. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  246. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  247. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  248. package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  249. package/dist/templates/native-go-vue/README.md +4 -0
  250. package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
  251. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  252. package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
  253. package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
  254. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  255. package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  256. package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  257. package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  258. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  259. package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  260. package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  261. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  262. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  263. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  264. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  265. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  266. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  267. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  268. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  269. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  270. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  271. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  272. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  273. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  274. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  275. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  276. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  277. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  278. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  279. package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  280. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  281. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  282. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  283. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  284. package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  285. package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  286. package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  287. package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  288. package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  289. package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  290. package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  291. package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  292. package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  293. package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  294. package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  295. package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  296. package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  297. package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  298. package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  299. package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  300. package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  301. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  302. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  303. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  304. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  305. package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  306. package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  307. package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  308. package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  309. package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  310. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  311. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  312. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  313. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  314. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  315. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  316. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  317. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  318. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  319. package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  320. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  321. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  322. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  323. package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  324. package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
  325. package/package.json +5 -1
  326. package/schema/package-metadata.schema.json +101 -0
  327. package/schema/synology-app.schema.json +112 -0
  328. package/skills/SKILL.md +106 -4
  329. package/skills/reference/create.md +101 -2
  330. package/skills/reference/deploy.md +2 -2
  331. package/skills/reference/files.md +113 -2
  332. package/skills/reference/identity.md +70 -1
  333. package/skills/reference/portal.md +17 -0
  334. package/skills/reference/ui-vue.md +12 -0
  335. package/templates/_daemon/main_test.go +61 -8
  336. package/templates/_executor/README.md +127 -16
  337. package/templates/_executor/anchor.go +146 -0
  338. package/templates/_executor/anchor_test.go +126 -0
  339. package/templates/_executor/apppriv_review_test.go +1 -1
  340. package/templates/_executor/cancel_contract_test.go +236 -0
  341. package/templates/_executor/copy.go +64 -0
  342. package/templates/_executor/copy_test.go +88 -0
  343. package/templates/_executor/dsm.go +23 -10
  344. package/templates/_executor/dsm_test.go +95 -1
  345. package/templates/_executor/executor.go +260 -49
  346. package/templates/_executor/executor_test.go +36 -6
  347. package/templates/_executor/identity.go +27 -1
  348. package/templates/_executor/identity_kernel_linux_test.go +60 -0
  349. package/templates/_executor/identity_linux.go +82 -0
  350. package/templates/_executor/identity_security_test.go +43 -0
  351. package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  352. package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  353. package/templates/_executor/internal/taskscript/boot.sh +9 -9
  354. package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  355. package/templates/_executor/internal/taskscript/control.sh +15 -10
  356. package/templates/_executor/internal/taskscript/tasks.go +5 -3
  357. package/templates/_executor/lifecycle_test.go +11 -0
  358. package/templates/_executor/link_linux.go +28 -0
  359. package/templates/_executor/long_running_test.go +530 -0
  360. package/templates/_executor/main.go +72 -20
  361. package/templates/_executor/move_linux.go +490 -0
  362. package/templates/_executor/move_linux_test.go +460 -0
  363. package/templates/_executor/move_validation.go +46 -0
  364. package/templates/_executor/move_validation_test.go +187 -0
  365. package/templates/_executor/operations.go +926 -0
  366. package/templates/_executor/platform_linux.go +24 -173
  367. package/templates/_executor/platform_linux_test.go +9 -65
  368. package/templates/_executor/platform_other.go +30 -4
  369. package/templates/_executor/process.go +3 -0
  370. package/templates/_executor/records.go +242 -0
  371. package/templates/_executor/scope_cancel_contract_test.go +91 -0
  372. package/templates/_executor/scope_client.go +37 -0
  373. package/templates/_executor/scope_contract.go +12 -0
  374. package/templates/_executor/selected_scope.go +146 -0
  375. package/templates/_executor/selected_scope_test.go +186 -0
  376. package/templates/_executor/status_disabled_test.go +33 -0
  377. package/templates/_executor/store.go +4 -3
  378. package/templates/_executor/supervise.go +109 -0
  379. package/templates/_executor/supervise_test.go +130 -0
  380. package/templates/_executor/task_race_review_test.go +1 -1
  381. package/templates/_executor/tasks.go +7 -8
  382. package/templates/_executor/tasks_review_test.go +1 -1
  383. package/templates/_executor/tasks_test.go +4 -4
  384. package/templates/_executor/watch.go +8 -0
  385. package/templates/_executor/watch_test.go +23 -2
  386. package/templates/_executor/write_review_linux_test.go +4 -12
  387. package/templates/_shared/AGENTS.md +129 -0
  388. package/templates/binary/dsm-package.yaml +24 -0
  389. package/templates/binary/i18n/messages/de.json +4 -0
  390. package/templates/binary/i18n/messages/en.json +4 -0
  391. package/templates/binary/i18n/messages/es.json +4 -0
  392. package/templates/binary/i18n/messages/fr.json +4 -0
  393. package/templates/binary/i18n/messages/it.json +4 -0
  394. package/templates/binary/i18n/messages/ja.json +4 -0
  395. package/templates/binary/i18n/messages/ko.json +4 -0
  396. package/templates/binary/i18n/messages/zh-CN.json +4 -0
  397. package/templates/binary/i18n/messages/zh-TW.json +4 -0
  398. package/templates/binary/ui/app.js +19 -4
  399. package/templates/native-authorization/AuthorizationGate.vue +5 -3
  400. package/templates/native-authorization/i18n/de.json +1 -0
  401. package/templates/native-authorization/i18n/en.json +1 -0
  402. package/templates/native-authorization/i18n/es.json +2 -1
  403. package/templates/native-authorization/i18n/fr.json +1 -0
  404. package/templates/native-authorization/i18n/it.json +11 -10
  405. package/templates/native-authorization/i18n/ja.json +1 -0
  406. package/templates/native-authorization/i18n/ko.json +10 -9
  407. package/templates/native-authorization/i18n/zh-CN.json +6 -5
  408. package/templates/native-authorization/i18n/zh-TW.json +6 -5
  409. package/templates/native-go/README.md +43 -10
  410. package/templates/native-go/backend/cmd/app/main.go +27 -7
  411. package/templates/native-go/backend/internal/api/entry_test.go +47 -0
  412. package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  413. package/templates/native-go/backend/internal/api/registry.go +11 -0
  414. package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  415. package/templates/native-go/backend/internal/api/server.go +18 -5
  416. package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  417. package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  418. package/templates/native-go/backend/internal/app/portal.go +30 -0
  419. package/templates/native-go/backend/internal/app/portal_test.go +55 -0
  420. package/templates/native-go/backend/internal/app/routes.go +8 -2
  421. package/templates/native-go/backend/internal/background/runner.go +1 -1
  422. package/templates/native-go/backend/internal/background/store.go +16 -14
  423. package/templates/native-go/backend/internal/dsm/admin.go +8 -2
  424. package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  425. package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  426. package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  427. package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  428. package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  429. package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  430. package/templates/native-go/backend/internal/dsm/entry.go +177 -0
  431. package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  432. package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  433. package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  434. package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  435. package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  436. package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  437. package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  438. package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  439. package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  440. package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  441. package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  442. package/templates/native-go/backend/internal/filestation/service.go +1 -1
  443. package/templates/native-go/backend/internal/portal/portal.go +138 -0
  444. package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  445. package/templates/native-go/dsm-package.yaml +20 -1
  446. package/templates/native-go/i18n/glossary.json +2 -1
  447. package/templates/native-go/i18n/messages/de.json +1 -0
  448. package/templates/native-go/i18n/messages/en.json +1 -0
  449. package/templates/native-go/i18n/messages/es.json +1 -0
  450. package/templates/native-go/i18n/messages/fr.json +1 -0
  451. package/templates/native-go/i18n/messages/it.json +1 -0
  452. package/templates/native-go/i18n/messages/ja.json +1 -0
  453. package/templates/native-go/i18n/messages/ko.json +1 -0
  454. package/templates/native-go/i18n/messages/zh-CN.json +1 -0
  455. package/templates/native-go/i18n/messages/zh-TW.json +1 -0
  456. package/templates/native-go/ui/app.css +10 -0
  457. package/templates/native-go/ui/app.js +11 -1
  458. package/templates/native-go-delegate/DELEGATE.md +126 -5
  459. package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  460. package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  461. package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  462. package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  463. package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  464. package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  465. package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  466. package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  467. package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  468. package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  469. package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  470. package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  471. package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  472. package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  473. package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  474. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  475. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  476. package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  477. package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  478. package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  479. package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  480. package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  481. package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  482. package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  483. package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  484. package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  485. package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  486. package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  487. package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  488. package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  489. package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  490. package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  491. package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  492. package/templates/native-go-delegate/test.sh +1 -0
  493. package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  494. package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  495. package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  496. package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  497. package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  498. package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  499. package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  500. package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  501. package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  502. package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  503. package/templates/native-go-vue/README.md +4 -0
  504. package/templates/native-go-vue/frontend/package-lock.json +4 -4
  505. package/templates/native-go-vue/frontend/package.json +1 -1
  506. package/templates/native-go-vue/frontend/src/App.vue +18 -13
  507. package/templates/native-go-vue/frontend/src/context.ts +31 -0
  508. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  509. package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  510. package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  511. package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  512. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  513. package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  514. package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  515. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  516. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  517. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  518. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  519. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  520. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  521. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  522. package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  523. package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  524. package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  525. package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  526. package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  527. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  528. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  529. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  530. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  531. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  532. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  533. package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  534. package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  535. package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  536. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  537. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  538. package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  539. package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  540. package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  541. package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  542. package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  543. package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  544. package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  545. package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  546. package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  547. package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  548. package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  549. package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  550. package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  551. package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  552. package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  553. package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  554. package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  555. package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  556. package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  557. package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  558. package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  559. package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  560. package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  561. package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  562. package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  563. package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  564. package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  565. package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  566. package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  567. package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  568. package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  569. package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  570. package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  571. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  572. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  573. package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  574. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  575. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  576. package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  577. package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  578. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
@@ -0,0 +1,77 @@
1
+ package filestation
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "net/http"
7
+ "net/http/httptest"
8
+ "testing"
9
+ )
10
+
11
+ func TestCheckPermissionRequiresVerifiedSessionAndExplicitWriteResult(t *testing.T) {
12
+ for _, body := range []string{`{"blSkip":false}`, `{}`, `{"blSkip":true}`, `{"blSkip":null}`, `{"blSkip":false,"errors":[{"code":407}]}`} {
13
+ t.Run(body, func(t *testing.T) {
14
+ checks := 0
15
+ client := fakeClient(t, func(w http.ResponseWriter, r *http.Request) {
16
+ r.ParseForm()
17
+ switch r.Form.Get("api") {
18
+ case "SYNO.Core.NormalUser":
19
+ fmt.Fprint(w, `{"success":true,"data":{"username":"alice"}}`)
20
+ case "SYNO.FileStation.CheckPermission":
21
+ checks++
22
+ if r.Form.Get("version") != "3" || r.Form.Get("method") != "write" || r.Form.Get("path") != "/home" || r.Form.Get("filename") != ".synopkgland-permission-probe" || r.Form.Get("overwrite") != "false" || r.Form.Get("size") != "0" || r.Header.Get("Cookie") != "id=test-session" || r.Header.Get("X-SYNO-TOKEN") != "test-token" {
23
+ t.Error("incorrect permission check transport")
24
+ }
25
+ fmt.Fprintf(w, `{"success":true,"data":%s}`, body)
26
+ default:
27
+ t.Error("unexpected API")
28
+ }
29
+ })
30
+ service := NewService(client)
31
+ err := service.CheckPermission(context.Background(), callerFor(t, "alice"), sessionRequest(), "/home")
32
+ if (err == nil) != (body == `{"blSkip":false}`) || checks != 1 {
33
+ t.Fatalf("checks=%d err=%v", checks, err)
34
+ }
35
+ checks = 0
36
+ if err := service.CheckPermission(context.Background(), callerFor(t, "bob"), sessionRequest(), "/home"); err == nil || checks != 0 {
37
+ t.Fatal("mismatched subject checked write permission")
38
+ }
39
+ if err := service.CheckPermission(context.Background(), callerFor(t, "alice"), sessionRequest(), "/home/../etc"); err == nil || checks != 0 {
40
+ t.Fatal("invalid path checked")
41
+ }
42
+ })
43
+ }
44
+ }
45
+
46
+ func TestCheckPermissionValidatesCredentialPairBeforeDSM(t *testing.T) {
47
+ calls := 0
48
+ client := fakeClient(t, func(w http.ResponseWriter, r *http.Request) {
49
+ calls++
50
+ r.ParseForm()
51
+ if r.Form.Get("api") == "SYNO.Core.NormalUser" {
52
+ fmt.Fprint(w, `{"success":true,"data":{"username":"alice"}}`)
53
+ } else {
54
+ fmt.Fprint(w, `{"success":true,"data":{"blSkip":false}}`)
55
+ }
56
+ })
57
+ service := NewService(client)
58
+ for index, r := range []*http.Request{nil, httptest.NewRequest("POST", "/", nil), sessionRequest(), sessionRequest()} {
59
+ if r != nil && r.Header.Get("X-SYNO-TOKEN") != "" {
60
+ if index == 2 {
61
+ r.Header.Del("X-SYNO-TOKEN")
62
+ } else {
63
+ r.Header.Set("SynoToken", "different")
64
+ }
65
+ }
66
+ before := calls
67
+ if err := service.CheckPermission(context.Background(), callerFor(t, "alice"), r, "/home"); err == nil || calls != before {
68
+ t.Fatal("invalid session reached DSM", err, calls)
69
+ }
70
+ }
71
+ r := sessionRequest()
72
+ r.Header.Del("X-SYNO-TOKEN")
73
+ r.Header.Set("SynoToken", "test-token")
74
+ if err := service.CheckPermission(context.Background(), callerFor(t, "alice"), r, "/home"); err != nil {
75
+ t.Fatal("canonical alias refused", err)
76
+ }
77
+ }
@@ -0,0 +1,39 @@
1
+ package filestation
2
+
3
+ import (
4
+ "encoding/json"
5
+ "os"
6
+ "sort"
7
+ "testing"
8
+ )
9
+
10
+ // Every files entry in the SDK policy must name a route this package serves.
11
+ func TestSDKPolicyListsExactlyTheFileRoutes(t *testing.T) {
12
+ raw, err := os.ReadFile("../api/sdk-permissions.json")
13
+ if err != nil {
14
+ t.Fatal(err)
15
+ }
16
+ var policy struct {
17
+ Files map[string]string `json:"files"`
18
+ }
19
+ if err := json.Unmarshal(raw, &policy); err != nil {
20
+ t.Fatal(err)
21
+ }
22
+ var declared, routed []string
23
+ for method := range policy.Files {
24
+ declared = append(declared, method)
25
+ }
26
+ for _, route := range (&Service{}).Routes() {
27
+ routed = append(routed, route.Method())
28
+ }
29
+ sort.Strings(declared)
30
+ sort.Strings(routed)
31
+ if len(declared) != len(routed) {
32
+ t.Fatalf("policy %v, routes %v", declared, routed)
33
+ }
34
+ for i := range declared {
35
+ if declared[i] != routed[i] {
36
+ t.Fatalf("policy %v, routes %v", declared, routed)
37
+ }
38
+ }
39
+ }
@@ -204,7 +204,7 @@ func (s *Service) discover(ctx context.Context, r *http.Request, folder string,
204
204
  // Browse lists share roots (empty folder) or one folder through the caller's
205
205
  // own DSM session, so File Station's current permissions decide what is
206
206
  // visible. It is read-only metadata and stores no grant; background jobs use it
207
- // to let an administrator pick the file that ReadFile will then import.
207
+ // to let an authenticated caller pick the file that ReadFile will then import.
208
208
  func (s *Service) Browse(ctx context.Context, c api.Caller, r *http.Request, folder string, offset int) (Page, error) {
209
209
  if !c.Authenticated() {
210
210
  return Page{}, fail("session_required")
@@ -0,0 +1,138 @@
1
+ // Package portal reads the DSM Application Portal alias an administrator set
2
+ // for this package. DSM owns the setting: the package never writes it, and
3
+ // anything this reader does not fully understand reads as Unavailable.
4
+ package portal
5
+
6
+ import (
7
+ "bytes"
8
+ "encoding/json"
9
+ "errors"
10
+ "io"
11
+ "io/fs"
12
+ "os"
13
+ "regexp"
14
+ "syscall"
15
+ "unicode/utf8"
16
+
17
+ "dsmapp/internal/jsonlimits"
18
+ )
19
+
20
+ // MaxConfigBytes bounds DSM's saved setting; its real size is a few hundred bytes.
21
+ const MaxConfigBytes = 64 << 10
22
+
23
+ const (
24
+ // Active means users can open the app at /<alias>/ after DSM sign-in.
25
+ Active = "active"
26
+ // Inactive means no administrator has set an alias yet.
27
+ Inactive = "inactive"
28
+ // Unavailable means the setting could not be read safely.
29
+ Unavailable = "unavailable"
30
+ )
31
+
32
+ // Status is what portal.status returns; Alias is set only when Active.
33
+ type Status struct {
34
+ State string `json:"state"`
35
+ Alias string `json:"alias,omitempty"`
36
+ }
37
+
38
+ // A single URL path segment; DSM's own validation is looser than this.
39
+ var aliasPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$`)
40
+
41
+ // ConfigPath is where DSM saves the package's portal setting
42
+ // (/var/packages/<package>/etc is the package's @appconf directory).
43
+ func ConfigPath(packageID string) string {
44
+ return "/var/packages/" + packageID + "/etc/AppPortal.json"
45
+ }
46
+
47
+ // Read returns the saved alias when the setting belongs to appID.
48
+ func Read(path, appID string) Status {
49
+ raw, err := readBounded(path)
50
+ if errors.Is(err, fs.ErrNotExist) {
51
+ return Status{State: Inactive}
52
+ }
53
+ if err != nil {
54
+ return Status{State: Unavailable}
55
+ }
56
+ id, alias, ok := parse(raw)
57
+ if !ok || id != appID {
58
+ return Status{State: Unavailable}
59
+ }
60
+ if alias == "" {
61
+ return Status{State: Inactive}
62
+ }
63
+ if !aliasPattern.MatchString(alias) {
64
+ return Status{State: Unavailable}
65
+ }
66
+ return Status{State: Active, Alias: alias}
67
+ }
68
+
69
+ func readBounded(path string) ([]byte, error) {
70
+ f, err := os.OpenFile(path, os.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_NONBLOCK, 0)
71
+ if err != nil {
72
+ return nil, err
73
+ }
74
+ defer f.Close()
75
+ info, err := f.Stat()
76
+ if err != nil {
77
+ return nil, err
78
+ }
79
+ if !info.Mode().IsRegular() {
80
+ return nil, errors.New("not a regular file")
81
+ }
82
+ raw, err := io.ReadAll(io.LimitReader(f, MaxConfigBytes+1))
83
+ if err != nil {
84
+ return nil, err
85
+ }
86
+ if len(raw) > MaxConfigBytes {
87
+ return nil, errors.New("too large")
88
+ }
89
+ return raw, nil
90
+ }
91
+
92
+ // parse accepts exactly one JSON object with unique top-level keys, a string
93
+ // id and a string or null alias; other DSM fields are skipped unread.
94
+ func parse(raw []byte) (id, alias string, ok bool) {
95
+ if !utf8.Valid(raw) || !jsonlimits.WithinLimits(raw) {
96
+ return "", "", false
97
+ }
98
+ d := json.NewDecoder(bytes.NewReader(raw))
99
+ if token, err := d.Token(); err != nil || token != json.Delim('{') {
100
+ return "", "", false
101
+ }
102
+ seen := map[string]bool{}
103
+ hasID := false
104
+ for d.More() {
105
+ token, err := d.Token()
106
+ key, isKey := token.(string)
107
+ if err != nil || !isKey || seen[key] {
108
+ return "", "", false
109
+ }
110
+ seen[key] = true
111
+ var value json.RawMessage
112
+ if err := d.Decode(&value); err != nil {
113
+ return "", "", false
114
+ }
115
+ switch key {
116
+ case "id":
117
+ if json.Unmarshal(value, &id) != nil || id == "" {
118
+ return "", "", false
119
+ }
120
+ hasID = true
121
+ case "alias":
122
+ var text *string
123
+ if json.Unmarshal(value, &text) != nil {
124
+ return "", "", false
125
+ }
126
+ if text != nil {
127
+ alias = *text
128
+ }
129
+ }
130
+ }
131
+ if token, err := d.Token(); err != nil || token != json.Delim('}') {
132
+ return "", "", false
133
+ }
134
+ if _, err := d.Token(); err != io.EOF {
135
+ return "", "", false
136
+ }
137
+ return id, alias, hasID
138
+ }
@@ -0,0 +1,89 @@
1
+ package portal
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ const appID = "SYNO.SDS.HelloGo.Instance"
11
+
12
+ // saved mirrors DSM 7.4's AppPortal.json after an administrator sets an alias.
13
+ func saved(alias string) string {
14
+ return "{\n\t\"acl\" : \"\",\n\t\"alias\" : " + alias + ",\n\t\"alternatePort\" : null,\n\t\"application\" : \"Hello Go\",\n\t\"fqdn\" : null,\n\t\"https\" : \n\t{\n\t\t\"hsts\" : false\n\t},\n\t\"id\" : \"" + appID + "\",\n\t\"version\" : 3\n}\n"
15
+ }
16
+
17
+ func write(t *testing.T, content string) string {
18
+ t.Helper()
19
+ path := filepath.Join(t.TempDir(), "AppPortal.json")
20
+ if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
21
+ t.Fatal(err)
22
+ }
23
+ return path
24
+ }
25
+
26
+ func TestActiveAlias(t *testing.T) {
27
+ got := Read(write(t, saved(`"hello-go"`)), appID)
28
+ if got != (Status{State: Active, Alias: "hello-go"}) {
29
+ t.Fatalf("got %+v", got)
30
+ }
31
+ }
32
+
33
+ func TestNoSavedSettingIsInactive(t *testing.T) {
34
+ if got := Read(filepath.Join(t.TempDir(), "AppPortal.json"), appID); got != (Status{State: Inactive}) {
35
+ t.Fatalf("missing file: %+v", got)
36
+ }
37
+ for _, alias := range []string{`null`, `""`} {
38
+ if got := Read(write(t, saved(alias)), appID); got != (Status{State: Inactive}) {
39
+ t.Fatalf("alias %s: %+v", alias, got)
40
+ }
41
+ }
42
+ }
43
+
44
+ func TestAnythingElseFailsClosed(t *testing.T) {
45
+ other := strings.Replace(saved(`"hello-go"`), appID, "SYNO.SDS.Other.Instance", 1)
46
+ cases := map[string]string{
47
+ "another app": other,
48
+ "no id": `{"alias":"hello-go"}`,
49
+ "duplicate alias": `{"alias":"hello-go","alias":"evil","id":"` + appID + `"}`,
50
+ "duplicate id": `{"id":"SYNO.SDS.Other.Instance","alias":"hello-go","id":"` + appID + `"}`,
51
+ "alias number": saved(`1`),
52
+ "alias path": saved(`"a/b"`),
53
+ "alias dots": saved(`".."`),
54
+ "alias query": saved(`"a?b"`),
55
+ "alias too long": saved(`"` + strings.Repeat("a", 65) + `"`),
56
+ "array": `[]`,
57
+ "trailing value": saved(`"hello-go"`) + `{}`,
58
+ "not json": `alias=hello-go`,
59
+ "not utf8": "{\"alias\":\"\xff\",\"id\":\"" + appID + "\"}",
60
+ "too large": saved(`"hello-go"`) + strings.Repeat(" ", MaxConfigBytes),
61
+ "too deep": strings.Replace(saved(`"hello-go"`), `"acl" : ""`, `"acl" : `+strings.Repeat("[", 64)+strings.Repeat("]", 64), 1),
62
+ }
63
+ for name, content := range cases {
64
+ if got := Read(write(t, content), appID); got != (Status{State: Unavailable}) {
65
+ t.Errorf("%s: %+v", name, got)
66
+ }
67
+ }
68
+ }
69
+
70
+ func TestOnlyARegularFileIsRead(t *testing.T) {
71
+ dir := t.TempDir()
72
+ target := write(t, saved(`"hello-go"`))
73
+ link := filepath.Join(dir, "AppPortal.json")
74
+ if err := os.Symlink(target, link); err != nil {
75
+ t.Fatal(err)
76
+ }
77
+ if got := Read(link, appID); got != (Status{State: Unavailable}) {
78
+ t.Fatalf("symlink: %+v", got)
79
+ }
80
+ if got := Read(dir, appID); got != (Status{State: Unavailable}) {
81
+ t.Fatalf("directory: %+v", got)
82
+ }
83
+ }
84
+
85
+ func TestConfigPathIsThePackagesOwnSetting(t *testing.T) {
86
+ if got := ConfigPath("HelloGo"); got != "/var/packages/HelloGo/etc/AppPortal.json" {
87
+ t.Fatal(got)
88
+ }
89
+ }
@@ -11,9 +11,28 @@ build: 1
11
11
  displayname: __DISPLAY_NAME__
12
12
  description: A native DSM package with a Go backend and a DSM window UI.
13
13
  maintainer: Your Name
14
+ # Optional INFO/website metadata. Omit fields you do not need.
15
+ # metadata:
16
+ # contact_email: you@example.com
17
+ # support_email: support@example.com
18
+ # homepage: https://example.com
19
+ # source_url: https://github.com/you/your-app
20
+ # issues_url: https://github.com/you/your-app/issues
21
+ # license: MIT
22
+ # long_description:
23
+ # en: |-
24
+ # Explain what the app does and how to use it.
25
+ # zh-TW: Translated description.
26
+ # changelog: # text, or per-language like long_description
27
+ # en: |-
28
+ # - Most important change first. Omit to use Release notes.
29
+ # zh-TW: |-
30
+ # - Translated changes.
31
+ # screenshots: [https://example.com/screenshot.png]
14
32
  os_min_ver: "7.1-42661"
15
33
 
16
- # One SPK per architecture. Supported: x86_64, aarch64.
34
+ # One SPK per architecture. Supported: x86_64, aarch64, armv7 (add it here to
35
+ # build it; armv7 jobs/delegate/root-ops/daemon are built but not NAS-verified).
17
36
  arches: [x86_64, aarch64]
18
37
 
19
38
  backend:
@@ -580,7 +580,8 @@
580
580
  "it": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione."
581
581
  },
582
582
  "keys": [
583
- "error.admin_required"
583
+ "error.admin_required",
584
+ "error.app_privilege_denied"
584
585
  ]
585
586
  },
586
587
  {
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "Aktualisieren",
4
4
  "app.title": "Es funktioniert",
5
5
  "error.admin_required": "Dieses Benutzerkonto verfügt nicht über die erforderlichen Berechtigungen, um diese Aktion durchzuführen.",
6
+ "error.app_privilege_denied": "Dieses Benutzerkonto verfügt nicht über die erforderlichen Berechtigungen, um diese Aktion durchzuführen.",
6
7
  "error.auth_unavailable": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
7
8
  "error.bad_request": "Überprüfen Sie den eingegebenen Wert und versuchen Sie es erneut.",
8
9
  "error.bad_response": "Dieser Vorgang kann nicht ausgeführt werden. Bitte versuchen Sie es später erneut.",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "Refresh",
4
4
  "app.title": "It works",
5
5
  "error.admin_required": "Sorry, this user account has not been assigned proper privileges to perform this action.",
6
+ "error.app_privilege_denied": "Sorry, this user account has not been assigned proper privileges to perform this action.",
6
7
  "error.auth_unavailable": "Unable to perform this operation. Please try again later.",
7
8
  "error.bad_request": "Check the entered value and try again.",
8
9
  "error.bad_response": "Unable to perform this operation. Please try again later.",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "Actualizar",
4
4
  "app.title": "Funciona",
5
5
  "error.admin_required": "A esta cuenta de usuario no se le han asignado los privilegios adecuados para realizar esta acción.",
6
+ "error.app_privilege_denied": "A esta cuenta de usuario no se le han asignado los privilegios adecuados para realizar esta acción.",
6
7
  "error.auth_unavailable": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
7
8
  "error.bad_request": "Compruebe el valor introducido y vuelva a intentarlo.",
8
9
  "error.bad_response": "No se puede realizar esta operación. Vuelva a intentarlo más tarde.",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "Actualiser",
4
4
  "app.title": "Ça fonctionne",
5
5
  "error.admin_required": "Désolé, ce compte utilisateur ne dispose pas des droits nécessaires pour accomplir cette action.",
6
+ "error.app_privilege_denied": "Désolé, ce compte utilisateur ne dispose pas des droits nécessaires pour accomplir cette action.",
6
7
  "error.auth_unavailable": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
7
8
  "error.bad_request": "Vérifiez la valeur saisie et réessayez.",
8
9
  "error.bad_response": "Impossible d'effectuer cette opération. Veuillez réessayer ultérieurement.",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "Aggiorna",
4
4
  "app.title": "Funziona",
5
5
  "error.admin_required": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione.",
6
+ "error.app_privilege_denied": "Siamo spiacenti, a questo account utente non sono stati assegnati privilegi appropriati per eseguire questa azione.",
6
7
  "error.auth_unavailable": "Impossibile eseguire questa operazione. Riprovare più tardi.",
7
8
  "error.bad_request": "Controllare il valore inserito e riprovare.",
8
9
  "error.bad_response": "Impossibile eseguire questa operazione. Riprovare più tardi.",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "最新の情報に更新",
4
4
  "app.title": "動作しています",
5
5
  "error.admin_required": "申し訳ありませんが、このユーザー アカウントにはこの操作を行うための権限が与えられていません。",
6
+ "error.app_privilege_denied": "申し訳ありませんが、このユーザー アカウントにはこの操作を行うための権限が与えられていません。",
6
7
  "error.auth_unavailable": "この操作は実行できません。後でもう一度お試しください。",
7
8
  "error.bad_request": "入力した値を確認して、もう一度お試しください。",
8
9
  "error.bad_response": "この操作は実行できません。後でもう一度お試しください。",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "새로 고침",
4
4
  "app.title": "정상적으로 작동합니다",
5
5
  "error.admin_required": "죄송합니다. 이 사용자 계정에는 이 작업을 수행하기에 적절한 권한이 할당되지 않았습니다.",
6
+ "error.app_privilege_denied": "죄송합니다. 이 사용자 계정에는 이 작업을 수행하기에 적절한 권한이 할당되지 않았습니다.",
6
7
  "error.auth_unavailable": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
7
8
  "error.bad_request": "입력한 값을 확인한 후 다시 시도하십시오.",
8
9
  "error.bad_response": "이 작업을 수행할 수 없습니다. 나중에 다시 시도하십시오.",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "刷新",
4
4
  "app.title": "运行成功",
5
5
  "error.admin_required": "抱歉,此用户帐户权限不足,无法执行此操作。",
6
+ "error.app_privilege_denied": "抱歉,此用户帐户权限不足,无法执行此操作。",
6
7
  "error.auth_unavailable": "无法执行此操作。请稍后再试。",
7
8
  "error.bad_request": "请检查输入的值后重试。",
8
9
  "error.bad_response": "无法执行此操作。请稍后再试。",
@@ -3,6 +3,7 @@
3
3
  "app.refresh": "重新整理",
4
4
  "app.title": "成功運作了",
5
5
  "error.admin_required": "抱歉,此使用者帳號權限不足,無法執行此動作。",
6
+ "error.app_privilege_denied": "抱歉,此使用者帳號權限不足,無法執行此動作。",
6
7
  "error.auth_unavailable": "無法執行此操作。請稍後再試。",
7
8
  "error.bad_request": "請檢查輸入的值後再試一次。",
8
9
  "error.bad_response": "無法執行此操作。請稍後再試。",
@@ -33,3 +33,13 @@
33
33
  .dsmapp-facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px; margin: 0; }
34
34
  .dsmapp-facts dt { color: #5d6b7a; }
35
35
  .dsmapp-facts dd { margin: 0; }
36
+ /* SDK portal panel (ctx.portal.mountPanel). */
37
+ .dsmapp-portal-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; max-width: 560px; }
38
+ .dsmapp-portal input { height: 28px; padding: 0 8px; border: 1px solid #c8d0da; border-radius: 3px; font: inherit; }
39
+ .dsmapp-portal button {
40
+ height: 30px; padding: 0 12px; border: 1px solid #c8d0da; border-radius: 3px;
41
+ background: #fff; color: inherit; font: inherit; cursor: pointer; margin-top: 8px;
42
+ }
43
+ .dsmapp-portal-form button { margin-top: 0; }
44
+ .dsmapp-portal-form button[type="submit"] { border-color: #0086e5; background: #0086e5; color: #fff; }
45
+ .dsmapp-portal-error { color: #c0392b; }
@@ -15,6 +15,9 @@
15
15
  // host-theme/language-change unsupported
16
16
  // ctx.host.openFileManager(path) / revealFile(path) -> File Station virtual path
17
17
  // request only; preview/details/settings return unsupported, never a grant
18
+ // ctx.portal -> only with `portal:` in dsm-package.yaml;
19
+ // mountPanel(element) shows the DSM Application
20
+ // Portal link, or the alias form to administrators
18
21
  // Replace everything below with your own UI (plain JS, or a bundle you build
19
22
  // with Vite/Vue into this folder -- see README.md).
20
23
  (function () {
@@ -40,6 +43,7 @@
40
43
  var message = el("p", { class: "dsmapp-message", role: "status" });
41
44
  var form = el("form", { class: "dsmapp-form", hidden: "" }, [input, save]);
42
45
  var adminOnly = el("p", { class: "dsmapp-note", hidden: "", text: t("greeting.adminOnly") });
46
+ var portal = ctx.portal ? el("section", { class: "dsmapp-portal" }) : null;
43
47
 
44
48
  root.classList.add("dsmapp");
45
49
  root.replaceChildren(
@@ -51,6 +55,7 @@
51
55
  el("h2", { text: t("status.heading") }),
52
56
  status
53
57
  );
58
+ var portalPanel = portal && (root.appendChild(portal), ctx.portal.mountPanel(portal));
54
59
 
55
60
  // Errors arrive as { code }; the backend's English message is only a fallback.
56
61
  function showError(error) {
@@ -93,7 +98,12 @@
93
98
 
94
99
  ctx.reopen(refresh);
95
100
  refresh();
96
- return { unmount: function () { root.replaceChildren(); } };
101
+ return {
102
+ unmount: function () {
103
+ if (portalPanel) portalPanel.dispose();
104
+ root.replaceChildren();
105
+ }
106
+ };
97
107
  }
98
108
 
99
109
  window.DsmPackageApps = window.DsmPackageApps || {};