@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,30 @@
1
+ package app
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+
7
+ "dsmapp/internal/api"
8
+ "dsmapp/internal/portal"
9
+ )
10
+
11
+ // portalRoutes serves portal.status when dsm-package.yaml declares `portal`.
12
+ // An administrator sets the alias with DSM's own AppPortal API from the UI;
13
+ // the package only reads DSM's saved setting.
14
+ func (cfg Config) portalRoutes() []api.Route {
15
+ if !cfg.Portal {
16
+ return nil
17
+ }
18
+ return []api.Route{api.Handle("portal.status", cfg.portalStatus)}
19
+ }
20
+
21
+ func (cfg Config) portalStatus(_ context.Context, _ api.Caller, params json.RawMessage) (any, error) {
22
+ if err := decodeParams(params, &struct{}{}); err != nil {
23
+ return nil, err
24
+ }
25
+ path := cfg.PortalConfig
26
+ if path == "" {
27
+ path = portal.ConfigPath(cfg.PackageID)
28
+ }
29
+ return portal.Read(path, "SYNO.SDS."+cfg.PackageID+".Instance"), nil
30
+ }
@@ -0,0 +1,55 @@
1
+ package app
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "testing"
7
+ )
8
+
9
+ func portalConfig(t *testing.T, saved string) Config {
10
+ cfg := testConfig(t)
11
+ cfg.Portal = true
12
+ cfg.PortalConfig = filepath.Join(t.TempDir(), "AppPortal.json")
13
+ if saved != "" {
14
+ if err := os.WriteFile(cfg.PortalConfig, []byte(saved), 0o644); err != nil {
15
+ t.Fatal(err)
16
+ }
17
+ }
18
+ return cfg
19
+ }
20
+
21
+ func TestPortalStatusTellsEverySignedInUserTheAlias(t *testing.T) {
22
+ cfg := portalConfig(t, `{"alias":"hello-go","id":"SYNO.SDS.HelloGo.Instance","version":3}`)
23
+ code, out := call(t, cfg, bob, "portal.status", `{}`)
24
+ if code != "" {
25
+ t.Fatalf("%q %v", code, out)
26
+ }
27
+ data := out["data"].(map[string]any)
28
+ if data["state"] != "active" || data["alias"] != "hello-go" {
29
+ t.Fatalf("%v", data)
30
+ }
31
+ if code, _ := call(t, cfg, nobody, "portal.status", `{}`); code != "session_required" {
32
+ t.Fatalf("anonymous: %q", code)
33
+ }
34
+ if code, _ := call(t, cfg, bob, "portal.status", `{"alias":"x"}`); code != "bad_request" {
35
+ t.Fatalf("params: %q", code)
36
+ }
37
+ }
38
+
39
+ func TestPortalStatusFailsClosedOnAnotherAppsSetting(t *testing.T) {
40
+ cfg := portalConfig(t, `{"alias":"hello-go","id":"SYNO.SDS.Other.Instance"}`)
41
+ _, out := call(t, cfg, bob, "portal.status", `{}`)
42
+ if data := out["data"].(map[string]any); data["state"] != "unavailable" || data["alias"] != nil {
43
+ t.Fatalf("%v", data)
44
+ }
45
+ _, out = call(t, portalConfig(t, ""), bob, "portal.status", `{}`)
46
+ if data := out["data"].(map[string]any); data["state"] != "inactive" {
47
+ t.Fatalf("%v", data)
48
+ }
49
+ }
50
+
51
+ func TestPortalStatusExistsOnlyForAPortalBuild(t *testing.T) {
52
+ if code, _ := call(t, testConfig(t), alice, "portal.status", `{}`); code != "unknown_method" {
53
+ t.Fatalf("%q", code)
54
+ }
55
+ }
@@ -24,8 +24,9 @@ import (
24
24
 
25
25
  // Config is fixed at build time and startup, never taken from a request.
26
26
  type Config struct {
27
- DelegateScope string
28
- ExecutorDigest, PolicyDigest string
27
+ DelegateScope string
28
+ DelegateOperationsJSON, DelegateDestinationsJSON, DelegateLifetime string
29
+ ExecutorDigest, PolicyDigest string
29
30
 
30
31
  // SessionFiles is the interactive File Station adapter; nil keeps legacy refusal.
31
32
  SessionFiles *filestation.Service
@@ -36,6 +37,10 @@ type Config struct {
36
37
  DataDir string
37
38
  // VolumeRoot is where /volumeN lives; empty means "/". Tests set it.
38
39
  VolumeRoot string
40
+ // Portal serves portal.status; PortalConfig overrides DSM's saved
41
+ // AppPortal.json path in tests.
42
+ Portal bool
43
+ PortalConfig string
39
44
  }
40
45
 
41
46
  func Routes(cfg Config) []api.Route {
@@ -47,6 +52,7 @@ func Routes(cfg Config) []api.Route {
47
52
  }...)
48
53
  routes = append(routes, cfg.SessionFiles.Routes()...)
49
54
  routes = append(routes, cfg.backgroundRoutes()...)
55
+ routes = append(routes, cfg.portalRoutes()...)
50
56
  return append(routes, cfg.rootRoutes()...)
51
57
  }
52
58
 
@@ -14,7 +14,7 @@ import (
14
14
  // Work is one fixed worker algorithm. It receives only the job's input bytes.
15
15
  type Work func(ctx context.Context, in io.Reader) (Result, error)
16
16
 
17
- // SHA256V1 is the only worker in this version: it hashes the imported copy.
17
+ // SHA256V1 hashes the imported private copy; delegate assembly adds a separate fixed worker.
18
18
  func SHA256V1(ctx context.Context, in io.Reader) (Result, error) {
19
19
  h := sha256.New()
20
20
  buf := make([]byte, 32*1024)
@@ -61,18 +61,20 @@ const (
61
61
  func (s State) terminal() bool { return s != StateQueued && s != StateRunning }
62
62
 
63
63
  var (
64
- ErrBusy = errors.New("background journal is busy; retry later")
65
- ErrOwnerQueueFull = errors.New("owner pending quota reached")
66
- ErrOwnerQuota = errors.New("owner storage quota reached")
67
- ErrInvalid = errors.New("invalid background request")
68
- ErrTooLarge = errors.New("input is larger than the per-file limit")
69
- ErrQueueFull = errors.New("background queue is full")
70
- ErrQuota = errors.New("background spool quota reached")
71
- ErrKeyConflict = errors.New("idempotency key already used for another input")
72
- ErrNotFound = errors.New("job not found")
73
- ErrNotCancelable = errors.New("job already finished")
74
- ErrNotRunning = errors.New("job is not running")
75
- ErrUnsafeSpool = errors.New("background spool is not private to the package account")
64
+ ErrBusy = errors.New("background journal is busy; retry later")
65
+ ErrOwnerQueueFull = errors.New("owner pending quota reached")
66
+ ErrOwnerQuota = errors.New("owner storage quota reached")
67
+ ErrInvalid = errors.New("invalid background request")
68
+ ErrTooLarge = errors.New("input is larger than the per-file limit")
69
+ ErrQueueFull = errors.New("background queue is full")
70
+ ErrQuota = errors.New("background spool quota reached")
71
+ ErrKeyConflict = errors.New("idempotency key already used for another input")
72
+ ErrNotFound = errors.New("job not found")
73
+ ErrNotCancelable = errors.New("job already finished")
74
+ ErrNotRunning = errors.New("job is not running")
75
+ ErrUnsafeSpool = errors.New("background spool is not private to the package account")
76
+ ErrJournalUnreadable = errors.New("background journal unreadable")
77
+ ErrJournalSchema = errors.New("background journal has an unsupported schema")
76
78
  )
77
79
 
78
80
  // Submitter binds visibility to a fresh DSM username and UID. It never grants
@@ -336,10 +338,10 @@ func (s *Store) readJournal(root *os.Root) (journal, error) {
336
338
  }
337
339
  b, err := io.ReadAll(io.LimitReader(f, maxJournal+1))
338
340
  if err != nil || len(b) > maxJournal {
339
- return j, errors.New("background journal unreadable")
341
+ return j, ErrJournalUnreadable
340
342
  }
341
343
  if err := json.Unmarshal(b, &j); err != nil || j.Schema != schemaVersion {
342
- return journal{}, errors.New("background journal has an unsupported schema")
344
+ return journal{}, ErrJournalSchema
343
345
  }
344
346
  return j, nil
345
347
  }
@@ -56,8 +56,14 @@ func runCGI(ctx context.Context, path string, env []string) ([]byte, error) {
56
56
  }
57
57
 
58
58
  func parseNativeRole(out []byte, err error) (bool, error) {
59
+ return parseNativeBit(out, err, errNativeRole)
60
+ }
61
+
62
+ // parseNativeBit accepts only a bridge's exact "1\n" or "0\n"; anything else,
63
+ // including a failed run, is the caller's unavailable error.
64
+ func parseNativeBit(out []byte, err, unavailable error) (bool, error) {
59
65
  if err != nil {
60
- return false, errNativeRole
66
+ return false, unavailable
61
67
  }
62
68
  switch string(out) {
63
69
  case "1\n":
@@ -65,6 +71,6 @@ func parseNativeRole(out []byte, err error) (bool, error) {
65
71
  case "0\n":
66
72
  return false, nil
67
73
  default:
68
- return false, errNativeRole
74
+ return false, unavailable
69
75
  }
70
76
  }
@@ -23,31 +23,61 @@ var adminAMD64 []byte
23
23
  //go:embed native/admin-aarch64.elf
24
24
  var adminARM64 []byte
25
25
 
26
+ //go:embed native/apppriv-x86_64.elf
27
+ var appPrivAMD64 []byte
28
+
29
+ //go:embed native/apppriv-aarch64.elf
30
+ var appPrivARM64 []byte
31
+
32
+ //go:embed native/admin-armv7.elf
33
+ var adminARMv7 []byte
34
+
35
+ //go:embed native/apppriv-armv7.elf
36
+ var appPrivARMv7 []byte
37
+
38
+ // Bridges per runtime.GOARCH; an architecture without one is refused.
39
+ var (
40
+ adminBridges = map[string][]byte{"amd64": adminAMD64, "arm64": adminARM64, "arm": adminARMv7}
41
+ appPrivBridges = map[string][]byte{"amd64": appPrivAMD64, "arm64": appPrivARM64, "arm": appPrivARMv7}
42
+ )
43
+
26
44
  func nativeAdministrator(ctx context.Context, principal string) (bool, error) {
27
- var payload []byte
28
- switch runtime.GOARCH {
29
- case "amd64":
30
- payload = adminAMD64
31
- case "arm64":
32
- payload = adminARM64
33
- default:
34
- return false, errNativeRole
45
+ out, err := runBridge(ctx, adminBridges, principal)
46
+ return parseNativeRole(out, err)
47
+ }
48
+
49
+ func nativeAppPrivilege(ctx context.Context, principal, app, addr string) (bool, error) {
50
+ out, err := runBridge(ctx, appPrivBridges, principal, app, addr)
51
+ return parseNativeBit(out, err, errNativeAppPriv)
52
+ }
53
+
54
+ // runBridge executes the sealed bridge for this architecture with fixed
55
+ // arguments and a minimal environment, returning at most 16 bytes of output.
56
+ func runBridge(ctx context.Context, bridges map[string][]byte, args ...string) ([]byte, error) {
57
+ payload, ok := bridges[runtime.GOARCH]
58
+ if !ok {
59
+ return nil, errors.New("unsupported architecture")
35
60
  }
36
61
  file, err := sealedBridge(payload)
37
62
  if err != nil {
38
- return false, errNativeRole
63
+ return nil, err
39
64
  }
40
65
  defer file.Close()
41
- cmd := exec.CommandContext(ctx, "/proc/self/fd/3", principal)
66
+ cmd := exec.CommandContext(ctx, "/proc/self/fd/3", args...)
42
67
  cmd.ExtraFiles = []*os.File{file}
43
68
  // In particular, never inherit LD_PRELOAD/LD_LIBRARY_PATH or credentials.
44
69
  cmd.Env = []string{"LANG=C", "LC_ALL=C"}
45
- out, err := commandOutput(cmd, 16)
46
- return parseNativeRole(out, err)
70
+ return commandOutput(cmd, 16)
47
71
  }
48
72
 
73
+ // memfdCreate is the sealing primitive; tests replace it to model old kernels.
74
+ var memfdCreate = unix.MemfdCreate
75
+
49
76
  func sealedBridge(payload []byte) (*os.File, error) {
50
- fd, err := unix.MemfdCreate("synopkgland-admin", unix.MFD_CLOEXEC|unix.MFD_ALLOW_SEALING)
77
+ fd, err := memfdCreate("synopkgland-admin", unix.MFD_CLOEXEC|unix.MFD_ALLOW_SEALING)
78
+ if errors.Is(err, unix.ENOSYS) {
79
+ return unlinkedBridge(bridgeFallbackDir, payload)
80
+ }
51
81
  if err != nil {
52
82
  return nil, err
53
83
  }
@@ -3,14 +3,23 @@
3
3
  package dsm
4
4
 
5
5
  import (
6
+ "bytes"
6
7
  "context"
8
+ "debug/elf"
9
+ "errors"
7
10
  "golang.org/x/sys/unix"
11
+ "io"
8
12
  "os"
9
13
  "strings"
10
14
  "testing"
11
15
  )
12
16
 
13
17
  func TestNativeBridgeIsSealedBeforeExecution(t *testing.T) {
18
+ if fd, err := unix.MemfdCreate("probe", unix.MFD_CLOEXEC); errors.Is(err, unix.ENOSYS) {
19
+ t.Skip("kernel has no memfd_create; covered by the fallback tests")
20
+ } else if err == nil {
21
+ unix.Close(fd)
22
+ }
14
23
  file, err := sealedBridge([]byte("immutable"))
15
24
  if err != nil {
16
25
  t.Fatal(err)
@@ -28,6 +37,53 @@ func TestNativeBridgeIsSealedBeforeExecution(t *testing.T) {
28
37
  }
29
38
  }
30
39
 
40
+ func TestEveryShippedArchHasBothBridges(t *testing.T) {
41
+ for arch, machine := range map[string]elf.Machine{"amd64": elf.EM_X86_64, "arm64": elf.EM_AARCH64, "arm": elf.EM_ARM} {
42
+ for name, bridges := range map[string]map[string][]byte{"admin": adminBridges, "apppriv": appPrivBridges} {
43
+ file, err := elf.NewFile(bytes.NewReader(bridges[arch]))
44
+ if err != nil || file.Machine != machine {
45
+ t.Fatalf("%s bridge for %s: %v %v", name, arch, file, err)
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ func withMemfd(t *testing.T, create func(string, int) (int, error), fallback string) {
52
+ t.Helper()
53
+ saved, savedDir := memfdCreate, bridgeFallbackDir
54
+ t.Cleanup(func() { memfdCreate, bridgeFallbackDir = saved, savedDir })
55
+ memfdCreate = create
56
+ SetBridgeFallbackDir(fallback)
57
+ }
58
+
59
+ func TestBridgeFallsBackToPackageTempOnlyWithoutMemfd(t *testing.T) {
60
+ dir := t.TempDir()
61
+ withMemfd(t, func(string, int) (int, error) { return -1, unix.ENOSYS }, dir)
62
+ file, err := sealedBridge([]byte("bridge"))
63
+ if err != nil {
64
+ t.Fatal(err)
65
+ }
66
+ defer file.Close()
67
+ got, err := io.ReadAll(file)
68
+ if err != nil || string(got) != "bridge" {
69
+ t.Fatalf("payload %q %v", got, err)
70
+ }
71
+ if entries, _ := os.ReadDir(dir); len(entries) != 0 {
72
+ t.Fatalf("fallback left %v", entries)
73
+ }
74
+ }
75
+
76
+ func TestBridgeRefusesOtherMemfdFailuresAndUnsetFallback(t *testing.T) {
77
+ withMemfd(t, func(string, int) (int, error) { return -1, unix.EPERM }, t.TempDir())
78
+ if _, err := sealedBridge([]byte("bridge")); !errors.Is(err, unix.EPERM) {
79
+ t.Fatalf("EPERM must not fall back: %v", err)
80
+ }
81
+ withMemfd(t, func(string, int) (int, error) { return -1, unix.ENOSYS }, "")
82
+ if _, err := sealedBridge([]byte("bridge")); err == nil {
83
+ t.Fatal("ENOSYS without a package temp directory must refuse")
84
+ }
85
+ }
86
+
31
87
  // Read-only device fixture. The runner provides existing principals and executes
32
88
  // this test binary from a memfd. No files, users, groups or NAS settings change.
33
89
  func TestNativeAdministratorDeviceFixture(t *testing.T) {
@@ -9,4 +9,7 @@ import (
9
9
 
10
10
  // Host tests inject a role provider; DSM native roles require Linux.
11
11
  func nativeAdministrator(context.Context, string) (bool, error) { return false, errNativeRole }
12
- func configureCommand(*exec.Cmd) {}
12
+ func nativeAppPrivilege(context.Context, string, string, string) (bool, error) {
13
+ return false, errNativeAppPriv
14
+ }
15
+ func configureCommand(*exec.Cmd) {}
@@ -0,0 +1,30 @@
1
+ package dsm
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "net/netip"
7
+ "regexp"
8
+ "time"
9
+ )
10
+
11
+ var errNativeAppPriv = errors.New("DSM Application Privileges verification unavailable")
12
+
13
+ // appID is a DSM application ID such as SYNO.SDS.<package>.Instance.
14
+ var appID = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*(\.[A-Za-z][A-Za-z0-9]*){1,7}$`)
15
+
16
+ // AppPrivilege asks DSM's native SDK whether principal may use app from addr.
17
+ // DSM applies its own user, group and everyone rules, deny precedence and IP
18
+ // ranges, and always allows administrators. Unknown results refuse.
19
+ func AppPrivilege(ctx context.Context, principal, app, addr string) (bool, error) {
20
+ if !validPrincipal(principal) || len(app) > 128 || !appID.MatchString(app) {
21
+ return false, errNativeAppPriv
22
+ }
23
+ ip, err := netip.ParseAddr(addr)
24
+ if err != nil || ip.Zone() != "" || ip.String() != addr {
25
+ return false, errNativeAppPriv
26
+ }
27
+ ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
28
+ defer cancel()
29
+ return nativeAppPrivilege(ctx, principal, app, addr)
30
+ }
@@ -0,0 +1,75 @@
1
+ package dsm
2
+
3
+ import (
4
+ "errors"
5
+ "os"
6
+ "path/filepath"
7
+ "syscall"
8
+ )
9
+
10
+ // bridgeFallbackDir is where a kernel without memfd_create (DSM 7 platforms on
11
+ // Linux 3.10) stages the bridge. Empty refuses, as before the fallback existed.
12
+ var bridgeFallbackDir string
13
+
14
+ // SetBridgeFallbackDir names the package's own temp directory,
15
+ // /var/packages/<package>/tmp. main calls it once, before serving.
16
+ func SetBridgeFallbackDir(dir string) { bridgeFallbackDir = dir }
17
+
18
+ var errBridgeDir = errors.New("bridge fallback directory must be a private absolute directory")
19
+
20
+ // unlinkedBridge stages payload in a fresh 0700 directory under dir and returns
21
+ // a read-only descriptor whose name is already gone. /tmp is noexec on DSM, so
22
+ // dir is the package's own exec-capable temp. Unlike a sealed memfd, a process
23
+ // running as the same package account could rewrite the file before it is
24
+ // unlinked; that account already controls the CGI, so the trust is unchanged.
25
+ func unlinkedBridge(dir string, payload []byte) (*os.File, error) {
26
+ if err := privateDir(dir); err != nil {
27
+ return nil, err
28
+ }
29
+ stage, err := os.MkdirTemp(dir, "bridge-")
30
+ if err != nil {
31
+ return nil, err
32
+ }
33
+ defer os.RemoveAll(stage)
34
+ path := filepath.Join(stage, "bridge")
35
+ writer, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
36
+ if err != nil {
37
+ return nil, err
38
+ }
39
+ _, err = writer.Write(payload)
40
+ if closeErr := writer.Close(); err == nil {
41
+ err = closeErr
42
+ }
43
+ if err == nil {
44
+ err = os.Chmod(path, 0o500)
45
+ }
46
+ if err != nil {
47
+ return nil, err
48
+ }
49
+ file, err := os.Open(path)
50
+ if err != nil {
51
+ return nil, err
52
+ }
53
+ if err = os.Remove(path); err != nil {
54
+ file.Close()
55
+ return nil, err
56
+ }
57
+ return file, nil
58
+ }
59
+
60
+ // privateDir accepts an absolute directory owned by this account and writable
61
+ // by no one else. It follows links: DSM's /var/packages/<pkg>/tmp is one.
62
+ func privateDir(dir string) error {
63
+ if !filepath.IsAbs(dir) {
64
+ return errBridgeDir
65
+ }
66
+ info, err := os.Stat(dir)
67
+ if err != nil {
68
+ return err
69
+ }
70
+ st, ok := info.Sys().(*syscall.Stat_t)
71
+ if !info.IsDir() || info.Mode().Perm()&0o022 != 0 || !ok || int(st.Uid) != os.Geteuid() {
72
+ return errBridgeDir
73
+ }
74
+ return nil
75
+ }
@@ -0,0 +1,57 @@
1
+ package dsm
2
+
3
+ import (
4
+ "io"
5
+ "os"
6
+ "path/filepath"
7
+ "testing"
8
+ )
9
+
10
+ func TestUnlinkedBridgeLeavesOnlyAReadOnlyDescriptor(t *testing.T) {
11
+ dir := t.TempDir()
12
+ file, err := unlinkedBridge(dir, []byte("bridge"))
13
+ if err != nil {
14
+ t.Fatal(err)
15
+ }
16
+ defer file.Close()
17
+ got, err := io.ReadAll(file)
18
+ if err != nil || string(got) != "bridge" {
19
+ t.Fatalf("payload %q %v", got, err)
20
+ }
21
+ if _, err = file.Seek(0, io.SeekStart); err != nil {
22
+ t.Fatal(err)
23
+ }
24
+ if _, err = file.Write([]byte("attack")); err == nil {
25
+ t.Fatal("bridge descriptor is writable")
26
+ }
27
+ info, err := file.Stat()
28
+ if err != nil || info.Mode().Perm() != 0o500 {
29
+ t.Fatalf("mode %v %v", info.Mode(), err)
30
+ }
31
+ if entries, err := os.ReadDir(dir); err != nil || len(entries) != 0 {
32
+ t.Fatalf("bridge left a name behind: %v %v", entries, err)
33
+ }
34
+ }
35
+
36
+ func TestUnlinkedBridgeRefusesWithoutAPrivateDirectory(t *testing.T) {
37
+ shared := t.TempDir()
38
+ if err := os.Chmod(shared, 0o777); err != nil {
39
+ t.Fatal(err)
40
+ }
41
+ link := filepath.Join(t.TempDir(), "link")
42
+ if err := os.Symlink(t.TempDir(), link); err != nil {
43
+ t.Fatal(err)
44
+ }
45
+ for name, dir := range map[string]string{"unset": "", "relative": "tmp", "missing": filepath.Join(shared, "none"), "shared": shared} {
46
+ if file, err := unlinkedBridge(dir, []byte("bridge")); err == nil {
47
+ file.Close()
48
+ t.Fatalf("%s directory accepted", name)
49
+ }
50
+ }
51
+ // DSM's /var/packages/<pkg>/tmp is a root-owned link to @apptemp/<pkg>.
52
+ file, err := unlinkedBridge(link, []byte("bridge"))
53
+ if err != nil {
54
+ t.Fatalf("linked private directory refused: %v", err)
55
+ }
56
+ file.Close()
57
+ }