@synopackageland/cli 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/CHANGELOG.md +846 -0
  2. package/README.md +81 -89
  3. package/dist/add.d.ts +4 -1
  4. package/dist/add.js +45 -17
  5. package/dist/build-spk/delegate-scope.d.ts +6 -0
  6. package/dist/build-spk/delegate-scope.js +34 -0
  7. package/dist/build-spk/dsm-arch.d.ts +7 -1
  8. package/dist/build-spk/dsm-arch.js +24 -28
  9. package/dist/build-spk/dsm-platforms.json +42 -0
  10. package/dist/build-spk/dsm-version.d.ts +11 -0
  11. package/dist/build-spk/dsm-version.js +17 -0
  12. package/dist/build-spk/gateway.js +8 -4
  13. package/dist/build-spk/generator.js +30 -5
  14. package/dist/build-spk/go-toolchain.d.ts +20 -0
  15. package/dist/build-spk/go-toolchain.js +44 -0
  16. package/dist/build-spk/notices.js +4 -1
  17. package/dist/build-spk/resource-worker.js +3 -0
  18. package/dist/build-spk/wizard-messages.d.ts +66 -0
  19. package/dist/build-spk/wizard-messages.js +75 -9
  20. package/dist/cli.js +28 -14
  21. package/dist/contract/schema-validate.js +8 -0
  22. package/dist/contract/validate.js +30 -0
  23. package/dist/deploy/deploy.d.ts +1 -1
  24. package/dist/deploy/deploy.js +8 -0
  25. package/dist/deploy/native-install-values.d.ts +17 -0
  26. package/dist/deploy/native-install-values.js +32 -0
  27. package/dist/deploy/plan.d.ts +6 -2
  28. package/dist/deploy/plan.js +58 -7
  29. package/dist/deploy/spk-version.js +1 -1
  30. package/dist/error-registry.js +54 -20
  31. package/dist/host/dsm-client.d.ts +8 -4
  32. package/dist/host/dsm-client.js +63 -21
  33. package/dist/host/dsm-http.js +24 -2
  34. package/dist/host/types.d.ts +3 -1
  35. package/dist/info.js +45 -10
  36. package/dist/init.d.ts +3 -0
  37. package/dist/init.js +50 -19
  38. package/dist/package-metadata.d.ts +21 -0
  39. package/dist/package-metadata.js +101 -0
  40. package/dist/portal/alias.d.ts +25 -0
  41. package/dist/portal/alias.js +48 -0
  42. package/dist/portal/package.d.ts +33 -0
  43. package/dist/portal/package.js +116 -0
  44. package/dist/runtime/delegate-contract.d.ts +79 -0
  45. package/dist/runtime/delegate-contract.js +27 -0
  46. package/dist/runtime/dsm-version.d.ts +6 -0
  47. package/dist/runtime/dsm-version.js +8 -0
  48. package/dist/runtime/executor-build.js +10 -6
  49. package/dist/runtime/executor-inspect.d.ts +3 -0
  50. package/dist/runtime/executor-inspect.js +11 -5
  51. package/dist/runtime/executor-policy.d.ts +12 -0
  52. package/dist/runtime/executor-policy.js +43 -3
  53. package/dist/runtime/executor-scope-task.d.ts +4 -0
  54. package/dist/runtime/executor-scope-task.js +21 -0
  55. package/dist/runtime/executor-tasks.d.ts +2 -1
  56. package/dist/runtime/executor-tasks.js +4 -4
  57. package/dist/skill.js +1 -0
  58. package/dist/standalone/api-permissions.d.ts +10 -0
  59. package/dist/standalone/api-permissions.js +19 -2
  60. package/dist/standalone/background.d.ts +16 -0
  61. package/dist/standalone/background.js +69 -2
  62. package/dist/standalone/binary.d.ts +1 -1
  63. package/dist/standalone/binary.js +22 -8
  64. package/dist/standalone/build.d.ts +1 -1
  65. package/dist/standalone/build.js +38 -8
  66. package/dist/standalone/daemon.d.ts +1 -0
  67. package/dist/standalone/daemon.js +10 -5
  68. package/dist/standalone/dsm-window.d.ts +3 -1
  69. package/dist/standalone/dsm-window.js +78 -49
  70. package/dist/standalone/inspect-spk.d.ts +8 -0
  71. package/dist/standalone/inspect-spk.js +110 -27
  72. package/dist/standalone/lifecycle.js +86 -8
  73. package/dist/standalone/manifest.d.ts +13 -0
  74. package/dist/standalone/manifest.js +57 -8
  75. package/dist/standalone/native-authorization-window.d.ts +1 -1
  76. package/dist/standalone/native-authorization-window.js +9 -1
  77. package/dist/standalone/native-layout.d.ts +3 -0
  78. package/dist/standalone/native-layout.js +37 -5
  79. package/dist/standalone/native-root-window.d.ts +4 -2
  80. package/dist/standalone/native-root-window.js +33 -18
  81. package/dist/standalone/portal-window.d.ts +21 -0
  82. package/dist/standalone/portal-window.js +155 -0
  83. package/dist/standalone/portal.d.ts +4 -0
  84. package/dist/standalone/portal.js +4 -0
  85. package/dist/standalone/resource.d.ts +5 -3
  86. package/dist/standalone/resource.js +6 -3
  87. package/dist/standalone/root-window.d.ts +4 -1
  88. package/dist/standalone/root-window.js +193 -36
  89. package/dist/standalone/spk.d.ts +1 -1
  90. package/dist/standalone/spk.js +25 -7
  91. package/dist/templates/_daemon/go.mod +1 -1
  92. package/dist/templates/_daemon/main.go +6 -3
  93. package/dist/templates/_daemon/main_test.go +82 -9
  94. package/dist/templates/_daemon/testdata/child.go +3 -0
  95. package/dist/templates/_executor/README.md +130 -16
  96. package/dist/templates/_executor/anchor.go +156 -0
  97. package/dist/templates/_executor/anchor_test.go +161 -0
  98. package/dist/templates/_executor/apppriv_review_test.go +1 -1
  99. package/dist/templates/_executor/cancel_contract_test.go +236 -0
  100. package/dist/templates/_executor/copy.go +64 -0
  101. package/dist/templates/_executor/copy_test.go +88 -0
  102. package/dist/templates/_executor/digest_review_test.go +2 -2
  103. package/dist/templates/_executor/dsm.go +63 -13
  104. package/dist/templates/_executor/dsm_test.go +95 -1
  105. package/dist/templates/_executor/executor.go +260 -49
  106. package/dist/templates/_executor/executor_test.go +36 -6
  107. package/dist/templates/_executor/go.mod +2 -0
  108. package/dist/templates/_executor/identity.go +27 -1
  109. package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
  110. package/dist/templates/_executor/identity_linux.go +82 -0
  111. package/dist/templates/_executor/identity_security_test.go +43 -0
  112. package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  113. package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  114. package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
  115. package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  116. package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
  117. package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
  118. package/dist/templates/_executor/lifecycle_test.go +11 -0
  119. package/dist/templates/_executor/link_linux.go +28 -0
  120. package/dist/templates/_executor/long_running_test.go +530 -0
  121. package/dist/templates/_executor/main.go +83 -25
  122. package/dist/templates/_executor/managed.go +3 -3
  123. package/dist/templates/_executor/managed_test.go +3 -3
  124. package/dist/templates/_executor/move_linux.go +490 -0
  125. package/dist/templates/_executor/move_linux_test.go +460 -0
  126. package/dist/templates/_executor/move_validation.go +46 -0
  127. package/dist/templates/_executor/move_validation_test.go +187 -0
  128. package/dist/templates/_executor/operations.go +926 -0
  129. package/dist/templates/_executor/path_test.go +18 -0
  130. package/dist/templates/_executor/pid.go +37 -0
  131. package/dist/templates/_executor/pid_test.go +113 -0
  132. package/dist/templates/_executor/platform_linux.go +24 -173
  133. package/dist/templates/_executor/platform_linux_test.go +9 -65
  134. package/dist/templates/_executor/platform_other.go +38 -4
  135. package/dist/templates/_executor/process.go +3 -0
  136. package/dist/templates/_executor/purge_log.go +18 -0
  137. package/dist/templates/_executor/records.go +242 -0
  138. package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
  139. package/dist/templates/_executor/scope_client.go +37 -0
  140. package/dist/templates/_executor/scope_contract.go +12 -0
  141. package/dist/templates/_executor/selected_scope.go +146 -0
  142. package/dist/templates/_executor/selected_scope_test.go +186 -0
  143. package/dist/templates/_executor/status_disabled_test.go +33 -0
  144. package/dist/templates/_executor/store.go +4 -3
  145. package/dist/templates/_executor/supervise.go +109 -0
  146. package/dist/templates/_executor/supervise_test.go +130 -0
  147. package/dist/templates/_executor/task_race_review_test.go +1 -1
  148. package/dist/templates/_executor/tasks.go +52 -15
  149. package/dist/templates/_executor/tasks_dsm71_test.go +114 -0
  150. package/dist/templates/_executor/tasks_review_test.go +1 -1
  151. package/dist/templates/_executor/tasks_test.go +62 -5
  152. package/dist/templates/_executor/upgrade_watch_test.go +13 -5
  153. package/dist/templates/_executor/watch.go +8 -0
  154. package/dist/templates/_executor/watch_test.go +23 -2
  155. package/dist/templates/_executor/write_review_linux_test.go +4 -12
  156. package/dist/templates/_gateway/go.mod +2 -0
  157. package/dist/templates/_shared/AGENTS.md +129 -0
  158. package/dist/templates/binary/dsm-package.yaml +24 -0
  159. package/dist/templates/binary/i18n/messages/de.json +4 -0
  160. package/dist/templates/binary/i18n/messages/en.json +4 -0
  161. package/dist/templates/binary/i18n/messages/es.json +4 -0
  162. package/dist/templates/binary/i18n/messages/fr.json +4 -0
  163. package/dist/templates/binary/i18n/messages/it.json +4 -0
  164. package/dist/templates/binary/i18n/messages/ja.json +4 -0
  165. package/dist/templates/binary/i18n/messages/ko.json +4 -0
  166. package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
  167. package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
  168. package/dist/templates/binary/ui/app.js +19 -4
  169. package/dist/templates/native-authorization/AuthorizationGate.vue +5 -3
  170. package/dist/templates/native-authorization/i18n/de.json +1 -0
  171. package/dist/templates/native-authorization/i18n/en.json +1 -0
  172. package/dist/templates/native-authorization/i18n/es.json +2 -1
  173. package/dist/templates/native-authorization/i18n/fr.json +1 -0
  174. package/dist/templates/native-authorization/i18n/it.json +11 -10
  175. package/dist/templates/native-authorization/i18n/ja.json +1 -0
  176. package/dist/templates/native-authorization/i18n/ko.json +10 -9
  177. package/dist/templates/native-authorization/i18n/zh-CN.json +6 -5
  178. package/dist/templates/native-authorization/i18n/zh-TW.json +6 -5
  179. package/dist/templates/native-go/README.md +43 -10
  180. package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
  181. package/dist/templates/native-go/backend/go.mod +1 -1
  182. package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
  183. package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  184. package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
  185. package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  186. package/dist/templates/native-go/backend/internal/api/server.go +18 -5
  187. package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  188. package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  189. package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
  190. package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
  191. package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
  192. package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
  193. package/dist/templates/native-go/backend/internal/background/store.go +16 -14
  194. package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
  195. package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  196. package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  197. package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  198. package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  199. package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  200. package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  201. package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
  202. package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  203. package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  204. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  205. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  206. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  207. package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  208. package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  209. package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  210. package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  211. package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  212. package/dist/templates/native-go/backend/internal/filestation/client.go +39 -3
  213. package/dist/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
  214. package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  215. package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
  216. package/dist/templates/native-go/backend/internal/identity/README.md +5 -1
  217. package/dist/templates/native-go/backend/internal/identity/dsm.go +24 -5
  218. package/dist/templates/native-go/backend/internal/identity/http.go +1 -1
  219. package/dist/templates/native-go/backend/internal/identity/identity_test.go +48 -1
  220. package/dist/templates/native-go/backend/internal/identity/service.go +1 -1
  221. package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
  222. package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  223. package/dist/templates/native-go/dsm-package.yaml +20 -1
  224. package/dist/templates/native-go/i18n/glossary.json +2 -1
  225. package/dist/templates/native-go/i18n/messages/de.json +1 -0
  226. package/dist/templates/native-go/i18n/messages/en.json +1 -0
  227. package/dist/templates/native-go/i18n/messages/es.json +1 -0
  228. package/dist/templates/native-go/i18n/messages/fr.json +1 -0
  229. package/dist/templates/native-go/i18n/messages/it.json +1 -0
  230. package/dist/templates/native-go/i18n/messages/ja.json +1 -0
  231. package/dist/templates/native-go/i18n/messages/ko.json +1 -0
  232. package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
  233. package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
  234. package/dist/templates/native-go/ui/app.css +10 -0
  235. package/dist/templates/native-go/ui/app.js +11 -1
  236. package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
  237. package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  238. package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  239. package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  240. package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  241. package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  242. package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  243. package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  244. package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  245. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  246. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  247. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  248. package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  249. package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  250. package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  251. package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  252. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  253. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  254. package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  255. package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  256. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  257. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  258. package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  259. package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  260. package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  261. package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  262. package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  263. package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  264. package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  265. package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  266. package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  267. package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  268. package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  269. package/dist/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
  270. package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  271. package/dist/templates/native-go-delegate/test.sh +1 -0
  272. package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  273. package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  274. package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  275. package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  276. package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  277. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  278. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  279. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  280. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  281. package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  282. package/dist/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
  283. package/dist/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
  284. package/dist/templates/native-go-vue/README.md +4 -0
  285. package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
  286. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  287. package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
  288. package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
  289. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
  290. package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  291. package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  292. package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  293. package/dist/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
  294. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
  295. package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  296. package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  297. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
  298. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
  299. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
  300. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
  301. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
  302. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
  303. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
  304. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  305. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  306. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  307. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  308. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  309. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  310. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  311. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  312. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  313. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
  314. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
  315. package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  316. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  317. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  318. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  319. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  320. package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  321. package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  322. package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  323. package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  324. package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  325. package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  326. package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  327. package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  328. package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  329. package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  330. package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  331. package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  332. package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  333. package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  334. package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  335. package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  336. package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  337. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  338. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  339. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  340. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  341. package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  342. package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  343. package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  344. package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  345. package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  346. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  347. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  348. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  349. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  350. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  351. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  352. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  353. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  354. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  355. package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  356. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  357. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  358. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  359. package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  360. package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
  361. package/package.json +5 -1
  362. package/schema/package-metadata.schema.json +101 -0
  363. package/schema/synology-app.schema.json +112 -0
  364. package/skills/SKILL.md +106 -4
  365. package/skills/reference/create.md +101 -2
  366. package/skills/reference/deploy.md +2 -2
  367. package/skills/reference/files.md +113 -2
  368. package/skills/reference/identity.md +70 -1
  369. package/skills/reference/portal.md +17 -0
  370. package/skills/reference/ui-vue.md +12 -0
  371. package/templates/_daemon/go.mod +1 -1
  372. package/templates/_daemon/main.go +6 -3
  373. package/templates/_daemon/main_test.go +82 -9
  374. package/templates/_daemon/testdata/child.go +3 -0
  375. package/templates/_executor/README.md +130 -16
  376. package/templates/_executor/anchor.go +156 -0
  377. package/templates/_executor/anchor_test.go +161 -0
  378. package/templates/_executor/apppriv_review_test.go +1 -1
  379. package/templates/_executor/cancel_contract_test.go +236 -0
  380. package/templates/_executor/copy.go +64 -0
  381. package/templates/_executor/copy_test.go +88 -0
  382. package/templates/_executor/digest_review_test.go +2 -2
  383. package/templates/_executor/dsm.go +63 -13
  384. package/templates/_executor/dsm_test.go +95 -1
  385. package/templates/_executor/executor.go +260 -49
  386. package/templates/_executor/executor_test.go +36 -6
  387. package/templates/_executor/go.mod +2 -0
  388. package/templates/_executor/identity.go +27 -1
  389. package/templates/_executor/identity_kernel_linux_test.go +60 -0
  390. package/templates/_executor/identity_linux.go +82 -0
  391. package/templates/_executor/identity_security_test.go +43 -0
  392. package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  393. package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  394. package/templates/_executor/internal/taskscript/boot.sh +9 -9
  395. package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  396. package/templates/_executor/internal/taskscript/control.sh +15 -10
  397. package/templates/_executor/internal/taskscript/tasks.go +5 -3
  398. package/templates/_executor/lifecycle_test.go +11 -0
  399. package/templates/_executor/link_linux.go +28 -0
  400. package/templates/_executor/long_running_test.go +530 -0
  401. package/templates/_executor/main.go +83 -25
  402. package/templates/_executor/managed.go +3 -3
  403. package/templates/_executor/managed_test.go +3 -3
  404. package/templates/_executor/move_linux.go +490 -0
  405. package/templates/_executor/move_linux_test.go +460 -0
  406. package/templates/_executor/move_validation.go +46 -0
  407. package/templates/_executor/move_validation_test.go +187 -0
  408. package/templates/_executor/operations.go +926 -0
  409. package/templates/_executor/path_test.go +18 -0
  410. package/templates/_executor/pid.go +37 -0
  411. package/templates/_executor/pid_test.go +113 -0
  412. package/templates/_executor/platform_linux.go +24 -173
  413. package/templates/_executor/platform_linux_test.go +9 -65
  414. package/templates/_executor/platform_other.go +38 -4
  415. package/templates/_executor/process.go +3 -0
  416. package/templates/_executor/purge_log.go +18 -0
  417. package/templates/_executor/records.go +242 -0
  418. package/templates/_executor/scope_cancel_contract_test.go +91 -0
  419. package/templates/_executor/scope_client.go +37 -0
  420. package/templates/_executor/scope_contract.go +12 -0
  421. package/templates/_executor/selected_scope.go +146 -0
  422. package/templates/_executor/selected_scope_test.go +186 -0
  423. package/templates/_executor/status_disabled_test.go +33 -0
  424. package/templates/_executor/store.go +4 -3
  425. package/templates/_executor/supervise.go +109 -0
  426. package/templates/_executor/supervise_test.go +130 -0
  427. package/templates/_executor/task_race_review_test.go +1 -1
  428. package/templates/_executor/tasks.go +52 -15
  429. package/templates/_executor/tasks_dsm71_test.go +114 -0
  430. package/templates/_executor/tasks_review_test.go +1 -1
  431. package/templates/_executor/tasks_test.go +62 -5
  432. package/templates/_executor/upgrade_watch_test.go +13 -5
  433. package/templates/_executor/watch.go +8 -0
  434. package/templates/_executor/watch_test.go +23 -2
  435. package/templates/_executor/write_review_linux_test.go +4 -12
  436. package/templates/_gateway/go.mod +2 -0
  437. package/templates/_shared/AGENTS.md +129 -0
  438. package/templates/binary/dsm-package.yaml +24 -0
  439. package/templates/binary/i18n/messages/de.json +4 -0
  440. package/templates/binary/i18n/messages/en.json +4 -0
  441. package/templates/binary/i18n/messages/es.json +4 -0
  442. package/templates/binary/i18n/messages/fr.json +4 -0
  443. package/templates/binary/i18n/messages/it.json +4 -0
  444. package/templates/binary/i18n/messages/ja.json +4 -0
  445. package/templates/binary/i18n/messages/ko.json +4 -0
  446. package/templates/binary/i18n/messages/zh-CN.json +4 -0
  447. package/templates/binary/i18n/messages/zh-TW.json +4 -0
  448. package/templates/binary/ui/app.js +19 -4
  449. package/templates/native-authorization/AuthorizationGate.vue +5 -3
  450. package/templates/native-authorization/i18n/de.json +1 -0
  451. package/templates/native-authorization/i18n/en.json +1 -0
  452. package/templates/native-authorization/i18n/es.json +2 -1
  453. package/templates/native-authorization/i18n/fr.json +1 -0
  454. package/templates/native-authorization/i18n/it.json +11 -10
  455. package/templates/native-authorization/i18n/ja.json +1 -0
  456. package/templates/native-authorization/i18n/ko.json +10 -9
  457. package/templates/native-authorization/i18n/zh-CN.json +6 -5
  458. package/templates/native-authorization/i18n/zh-TW.json +6 -5
  459. package/templates/native-go/README.md +43 -10
  460. package/templates/native-go/backend/cmd/app/main.go +27 -7
  461. package/templates/native-go/backend/go.mod +1 -1
  462. package/templates/native-go/backend/internal/api/entry_test.go +47 -0
  463. package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  464. package/templates/native-go/backend/internal/api/registry.go +11 -0
  465. package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  466. package/templates/native-go/backend/internal/api/server.go +18 -5
  467. package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  468. package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  469. package/templates/native-go/backend/internal/app/portal.go +30 -0
  470. package/templates/native-go/backend/internal/app/portal_test.go +55 -0
  471. package/templates/native-go/backend/internal/app/routes.go +8 -2
  472. package/templates/native-go/backend/internal/background/runner.go +1 -1
  473. package/templates/native-go/backend/internal/background/store.go +16 -14
  474. package/templates/native-go/backend/internal/dsm/admin.go +8 -2
  475. package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  476. package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  477. package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  478. package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  479. package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  480. package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  481. package/templates/native-go/backend/internal/dsm/entry.go +177 -0
  482. package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  483. package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  484. package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  485. package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  486. package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  487. package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  488. package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  489. package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  490. package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  491. package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  492. package/templates/native-go/backend/internal/filestation/client.go +39 -3
  493. package/templates/native-go/backend/internal/filestation/download_dsm71_test.go +82 -0
  494. package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  495. package/templates/native-go/backend/internal/filestation/service.go +1 -1
  496. package/templates/native-go/backend/internal/identity/README.md +5 -1
  497. package/templates/native-go/backend/internal/identity/dsm.go +24 -5
  498. package/templates/native-go/backend/internal/identity/http.go +1 -1
  499. package/templates/native-go/backend/internal/identity/identity_test.go +48 -1
  500. package/templates/native-go/backend/internal/identity/service.go +1 -1
  501. package/templates/native-go/backend/internal/portal/portal.go +138 -0
  502. package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  503. package/templates/native-go/dsm-package.yaml +20 -1
  504. package/templates/native-go/i18n/glossary.json +2 -1
  505. package/templates/native-go/i18n/messages/de.json +1 -0
  506. package/templates/native-go/i18n/messages/en.json +1 -0
  507. package/templates/native-go/i18n/messages/es.json +1 -0
  508. package/templates/native-go/i18n/messages/fr.json +1 -0
  509. package/templates/native-go/i18n/messages/it.json +1 -0
  510. package/templates/native-go/i18n/messages/ja.json +1 -0
  511. package/templates/native-go/i18n/messages/ko.json +1 -0
  512. package/templates/native-go/i18n/messages/zh-CN.json +1 -0
  513. package/templates/native-go/i18n/messages/zh-TW.json +1 -0
  514. package/templates/native-go/ui/app.css +10 -0
  515. package/templates/native-go/ui/app.js +11 -1
  516. package/templates/native-go-delegate/DELEGATE.md +126 -5
  517. package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  518. package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  519. package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  520. package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  521. package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  522. package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  523. package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  524. package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  525. package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  526. package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  527. package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  528. package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  529. package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  530. package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  531. package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  532. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  533. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  534. package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  535. package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  536. package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  537. package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  538. package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  539. package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  540. package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  541. package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  542. package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  543. package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  544. package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  545. package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  546. package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  547. package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  548. package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  549. package/templates/native-go-delegate/frontend/test/delegate.test.ts +15 -0
  550. package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  551. package/templates/native-go-delegate/test.sh +1 -0
  552. package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  553. package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  554. package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  555. package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  556. package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  557. package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  558. package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  559. package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  560. package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  561. package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  562. package/templates/native-go-root-ops/backend/internal/app/executor.go +30 -2
  563. package/templates/native-go-root-ops/backend/internal/app/executor_test.go +64 -0
  564. package/templates/native-go-vue/README.md +4 -0
  565. package/templates/native-go-vue/frontend/package-lock.json +4 -4
  566. package/templates/native-go-vue/frontend/package.json +1 -1
  567. package/templates/native-go-vue/frontend/src/App.vue +18 -13
  568. package/templates/native-go-vue/frontend/src/context.ts +31 -0
  569. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +54 -9
  570. package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  571. package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  572. package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  573. package/templates/native-go-vue/frontend/src/delegate/executor-settings.test.ts +23 -0
  574. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +8 -2
  575. package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  576. package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  577. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +47 -0
  578. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +13 -2
  579. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +47 -0
  580. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +47 -0
  581. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +47 -0
  582. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +47 -0
  583. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +47 -0
  584. package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  585. package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  586. package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  587. package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  588. package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  589. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  590. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  591. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  592. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  593. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +47 -0
  594. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +16 -5
  595. package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  596. package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  597. package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  598. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  599. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  600. package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  601. package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  602. package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  603. package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  604. package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  605. package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  606. package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  607. package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  608. package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  609. package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  610. package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  611. package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  612. package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  613. package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  614. package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  615. package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  616. package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  617. package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  618. package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  619. package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  620. package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  621. package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  622. package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  623. package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  624. package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  625. package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  626. package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  627. package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  628. package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  629. package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  630. package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  631. package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  632. package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  633. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  634. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  635. package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  636. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  637. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  638. package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  639. package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  640. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
@@ -41,10 +41,16 @@ func fixture(t *testing.T, mode string) (string, string, string) {
41
41
  if err != nil {
42
42
  t.Fatal(err)
43
43
  }
44
- if err := os.WriteFile(filepath.Join(dest, "daemon/payload/app"), raw, 0755); err != nil {
44
+ app := filepath.Join(dest, "daemon/payload/app")
45
+ if err := os.WriteFile(app, raw, 0755); err != nil {
45
46
  t.Fatal(err)
46
47
  }
47
- cfg := config{Package: "DaemonFixture", Exec: "app", Args: []string{"${SYNOPKG_PKGVAR}/a space", "$(touch BAD)'", "${SYNOPKG_PKGDEST}"}, Env: map[string]string{"APP_MODE": mode}, Timeouts: deadlines{Start: 2, Stop: 2, Status: 1}}
48
+ // macOS verifies a newly written executable on its first exec, which takes
49
+ // seconds on a loaded host; pay it here, not inside a one-second budget.
50
+ if raw, err := exec.Command(app, "cleanup").CombinedOutput(); err != nil {
51
+ t.Fatalf("payload warm-up: %v %s", err, raw)
52
+ }
53
+ cfg := config{Package: "DaemonFixture", Exec: "app", Args: []string{"${SYNOPKG_PKGVAR}/a space", "$(touch BAD)'", "${SYNOPKG_PKGDEST}"}, Env: map[string]string{"APP_MODE": mode}, Timeouts: deadlines{Start: 2, Stop: 2, Status: 1, Uninstall: 2}}
48
54
  if os.Geteuid() == 0 {
49
55
  cfg.Package = "nobody"
50
56
  } else {
@@ -91,22 +97,69 @@ func runControl(control, action, dest, data string) (int, string) {
91
97
  return -1, err.Error()
92
98
  }
93
99
 
100
+ // Readiness only proves the child stayed alive for a second, not that it reached
101
+ // main: on a loaded host a stop can kill it before it writes its line. Spawn
102
+ // identity therefore comes from the inventory, and log content is awaited.
103
+ func recordedChild(t *testing.T, data string) int {
104
+ t.Helper()
105
+ raw, err := os.ReadFile(filepath.Join(data, "daemon/daemon.pid"))
106
+ if err != nil {
107
+ t.Fatal(err)
108
+ }
109
+ var r record
110
+ if err := json.Unmarshal(raw, &r); err != nil || r.Child < 1 {
111
+ t.Fatalf("daemon inventory: %v %s", err, raw)
112
+ }
113
+ return r.Child
114
+ }
115
+
116
+ func awaitChildLines(t *testing.T, data string, want int) {
117
+ t.Helper()
118
+ path := filepath.Join(data, "daemon/daemon.log")
119
+ for deadline := time.Now().Add(10 * time.Second); ; time.Sleep(20 * time.Millisecond) {
120
+ raw, _ := os.ReadFile(path)
121
+ if got := strings.Count(string(raw), `"uid":`); got >= want || time.Now().After(deadline) {
122
+ if got != want {
123
+ t.Fatalf("child lines=%d want=%d: %s", got, want, raw)
124
+ }
125
+ return
126
+ }
127
+ }
128
+ }
129
+
94
130
  func TestDaemonLifecycle(t *testing.T) {
95
131
  control, dest, data := fixture(t, "normal")
96
- for _, step := range []struct {
97
- action string
98
- want int
99
- }{{"status", 3}, {"stop", 0}, {"start", 0}, {"status", 0}, {"start", 0}, {"restart", 0}, {"stop", 0}, {"stop", 0}, {"status", 3}, {"unknown", 1}} {
100
- if rc, out := runControl(control, step.action, dest, data); rc != step.want {
101
- t.Fatalf("%s rc=%d want=%d: %s", step.action, rc, step.want, out)
132
+ step := func(action string, want int) {
133
+ t.Helper()
134
+ if rc, out := runControl(control, action, dest, data); rc != want {
135
+ t.Fatalf("%s rc=%d want=%d: %s", action, rc, want, out)
102
136
  }
103
137
  }
138
+ step("status", 3)
139
+ step("stop", 0)
140
+ step("start", 0)
141
+ awaitChildLines(t, data, 1)
142
+ first := recordedChild(t, data)
143
+ step("status", 0)
144
+ step("start", 0)
145
+ if child := recordedChild(t, data); child != first {
146
+ t.Fatalf("duplicate start spawned another child: %d replaced %d", child, first)
147
+ }
148
+ step("restart", 0)
149
+ if child := recordedChild(t, data); child == first {
150
+ t.Fatalf("restart kept child %d", child)
151
+ }
152
+ awaitChildLines(t, data, 2)
153
+ step("stop", 0)
154
+ step("stop", 0)
155
+ step("status", 3)
156
+ step("unknown", 1)
104
157
  raw, err := os.ReadFile(filepath.Join(data, "daemon/daemon.log"))
105
158
  if err != nil {
106
159
  t.Fatal(err)
107
160
  }
108
161
  if strings.Count(string(raw), `"uid":`) != 2 {
109
- t.Fatalf("duplicate start spawned another child: %s", raw)
162
+ t.Fatalf("unexpected child spawn: %s", raw)
110
163
  }
111
164
  if strings.Contains(string(raw), "must-not-leak") {
112
165
  t.Fatalf("ambient environment leaked: %s", raw)
@@ -197,6 +250,26 @@ func TestUninstallCleanup(t *testing.T) {
197
250
  }
198
251
  }
199
252
 
253
+ // A revoke on uninstall can outlast the stop deadline on a loaded NAS; it has
254
+ // its own budget instead of Stop-1.
255
+ func TestUninstallCommandHasItsOwnBudget(t *testing.T) {
256
+ control, dest, data := fixture(t, "normal")
257
+ path := filepath.Join(dest, "daemon/config.json")
258
+ raw, _ := os.ReadFile(path)
259
+ var cfg config
260
+ json.Unmarshal(raw, &cfg)
261
+ cfg.UninstallArgs = []string{"cleanup-slow"}
262
+ cfg.Timeouts.Uninstall = 5
263
+ raw, _ = json.Marshal(cfg)
264
+ os.WriteFile(path, raw, 0644)
265
+ if rc, out := runControl(control, "start", dest, data); rc != 0 {
266
+ t.Fatalf("start: %d %s", rc, out)
267
+ }
268
+ if rc, out := runControl(control, "uninstall", dest, data); rc != 0 {
269
+ t.Fatalf("slow uninstall within its budget failed: %d %s", rc, out)
270
+ }
271
+ }
272
+
200
273
  func TestPackageAccountIdentity(t *testing.T) {
201
274
  control, dest, data := fixture(t, "normal")
202
275
  path := filepath.Join(dest, "daemon/config.json")
@@ -14,6 +14,9 @@ func main() {
14
14
  switch os.Args[1] {
15
15
  case "cleanup":
16
16
  os.Exit(0)
17
+ case "cleanup-slow":
18
+ time.Sleep(2500 * time.Millisecond)
19
+ os.Exit(0)
17
20
  case "cleanup-fail":
18
21
  os.Exit(2)
19
22
  case "cleanup-hang":
@@ -7,9 +7,16 @@ including newline at most 65536 bytes). Socket access additionally requires exac
7
7
  Linux SO_PEERCRED UID equality, even for another member of the package group.
8
8
  Non-Linux builds support portable tests and refuse privileged service operations.
9
9
 
10
+ Fixed writer children verify `no_new_privs` with `PR_GET_NO_NEW_PRIVS` on their
11
+ locked Linux thread. DSM kernel 4.4 supports this flag but omits its proc status
12
+ field; a failed syscall or a value other than one still refuses the write.
13
+ Saved IDs and zero capabilities remain mandatory. The parent passes the pinned
14
+ package-owned private source as a read-only FD; destination creation and publish
15
+ remain under the subject UID, and source cleanup runs under the package UID.
16
+
10
17
  ## Protected inventory and policy
11
18
 
12
- Setup must copy the digest-pinned executor, policy and root scripts into:
19
+ Setup must copy the INFO-anchored executor, policy-pinned policy and root scripts into:
13
20
 
14
21
  ```
15
22
  /usr/local/etc/synopkgland/<package>/ root:root 0700
@@ -74,7 +81,7 @@ operations and policy-excluded operations are rejected. Replies follow §2.4.
74
81
 
75
82
  | Operation | Parameters | Result |
76
83
  | --- | --- | --- |
77
- | status | none | executor_digest, policy_digest, version, ready |
84
+ | status | none | executor_digest, policy_digest, version, ready, disabled |
78
85
  | delegate.create | job_id, ops[], scope, path, ttl_seconds | delegation_id, subject {username, uid}, expires_at (RFC3339) |
79
86
  | delegate.list | none | delegations[] with public metadata, including revoked/expired records |
80
87
  | delegate.revoke | delegation_id; job_id required without cookie | revoked |
@@ -86,7 +93,7 @@ operations and policy-excluded operations are rejected. Replies follow §2.4.
86
93
  Create/list require a cookie and SynoToken. Revoke accepts the subject/admin session pair or a matching
87
94
  package job ID. Root operations require the session pair independently verified as an
88
95
  active administrators member. Delegated operations recheck the account, UID,
89
- expired=`normal`, non-admin membership, App and File Station privileges, scope,
96
+ expired=`normal`, App and File Station privileges, scope,
90
97
  job, operation, expiry and revocation. UIDs below 1024 are excluded as system
91
98
  accounts. TTL must be 1–2592000 seconds. No cookie/SynoToken/SID/password is persisted.
92
99
 
@@ -94,22 +101,26 @@ Paths use File Station spellings `/home[/...]` or `/<share>[/...]`. A delegation
94
101
  binds the requested directory's canonical path. Symlinks resolving outside that
95
102
  directory are denied. `files.write` opens package-owned, singly linked regular
96
103
  staging files with no symlink components; its fresh child checks setgroups,
97
- setresgid and setresuid in order, then all real/effective IDs and groups. The child
104
+ setresgid and setresuid in order, then real/effective/saved/filesystem IDs and groups, empty capability sets and
105
+ `no_new_privs`. Admin users retain their own nonzero UID and current groups. The child
98
106
  opens the destination after dropping identity, verifies its pinned directory and
99
107
  scope, and copies into an exclusive hidden `.synopkgland-<job_id>-<random>.part`
100
108
  file. After fsync it publishes the complete file with a hard link, then removes
101
109
  the temporary name. Existing files and symlinks are never overwritten. The
102
110
  executor cleans the exact temporary name as the subject user after a canceled or
103
111
  killed child, using a retained directory descriptor; startup performs no scan.
104
- Successful writes delete staging. DSM ACL inheritance can
112
+ Successful writes request exact source cleanup in a separate package-UID child;
113
+ cleanup failure retains the source and never downgrades a committed receipt. DSM ACL inheritance can
105
114
  produce a mode different from the requested 0600 (observed 0711 on vt-nas).
106
115
 
107
116
  File Station CheckPermission uses v3 with a fixed non-overwriting probe filename
108
117
  and size zero; it creates no file. Missing/failed API data is denied. DSM output
109
118
  and root script output are capped at 1 MiB; commands have 20-second deadlines,
110
119
  connection read/write deadlines are 15/5 seconds and request execution is bounded
111
- by 30 seconds. At most 16 connections are admitted. Execution/revocation are
112
- serialized. Linux command timeouts kill the entire command process group.
120
+ by 30 seconds. At most 16 connections are admitted. Legacy runner APIs use short
121
+ admission leases; revoke/disable persist the fence then drain accepted legacy
122
+ calls outside the commit lock before acknowledging. Bulk copy holds no commit
123
+ lock. Linux command timeouts kill the entire command process group.
113
124
 
114
125
  File Station APIs resolve path strings inside DSM after executor scope validation;
115
126
  there is no atomic DSM API for binding that subsequent lookup to our directory
@@ -122,13 +133,20 @@ items, not assertions of complete race freedom.
122
133
 
123
134
  ```
124
135
  executor serve --package com.example.downloader
136
+ executor supervise --package com.example.downloader
125
137
  executor control start --package com.example.downloader
126
138
  executor control stop --package com.example.downloader
127
139
  executor control purge --package com.example.downloader
128
140
  ```
129
141
 
130
142
  Root control start launches asynchronously; the caller reads socket status to
131
- establish readiness. A held flock pidfile refuses duplicate serve. Root's pinned
143
+ establish readiness. It starts `executor supervise`, a root supervisor that runs
144
+ `serve` as its child and restarts it after an abnormal end (signal or non-zero
145
+ exit) with a 1 s backoff doubling to 60 s, reset after a minute of healthy run.
146
+ A restarted `serve --revived` honors a `stop` already in the mailbox. Exit 0
147
+ (root replacement, shutdown, purge), exit 3 (another monitor holds the pidfile)
148
+ or a removed runtime end supervision. A held flock pidfile refuses duplicate
149
+ serve. Root's pinned
132
150
  boot/control start can validate and terminate a previous monitor before launching
133
151
  its replacement; package-account start only writes the mailbox and cannot replace
134
152
  runtime. Stop pauses the listener while the monitor continues. Purge removes this
@@ -136,7 +154,8 @@ package's protected state and deletes only its verified recorded scheduler tasks
136
154
 
137
155
  Run `go test -race ./...` and `bash scripts/ci/gate.sh native-go`. The gate adds
138
156
  Linux amd64/arm64 vet, static binary builds and test compilation. Linux-specific
139
- syscall tests also run on vt-nas from a cross-compiled test executable. The
157
+ syscall tests require a disposable Linux root fixture. This revision was tested
158
+ on a Linux VM; DSM ACL, logout and reboot behavior remain unverified. The
140
159
  `testdata/live_probe.py` harness expects isolated disposable accounts and a
141
160
  manually copied runtime, reads passwords only from stdin, and logs no credentials.
142
161
  The live harness uses DSM's registered `SYNO.Desktop` AppPriv ID as a stand-in for
@@ -148,12 +167,20 @@ an installed App; installed-package AppPriv integration belongs to setup testing
148
167
  Package-account hooks atomically write `stop` before upgrades/stops, `start` on
149
168
  install/upgrade completion and package start, and `purge` before uninstall.
150
169
  `stop` cancels/drains requests and removes the listener without ending the root
151
- monitor. `start` resumes only if both package executor and policy hashes equal
152
- the approved runtime pins; otherwise the service stays paused for administrator
153
- approval. Only root's pinned boot/control path can replace a monitor or runtime.
170
+ monitor. `start` resumes if both package executor and policy hashes equal the approved
171
+ runtime pins. If only the executor changed, the policy hash is unchanged and the
172
+ executor hash equals the single `synopkgland_executor_sha256` key in the
173
+ root-owned `/var/packages/<package>/INFO`, the root monitor copies it into
174
+ `runtime/`, verifies the copy and runs root `control start`, which replaces the
175
+ monitor without reapproval. Any other change stays paused for administrator
176
+ approval. Only root's pinned boot/control path or this anchored install can
177
+ replace a monitor or runtime. To exercise this path on a NAS without a real
178
+ executor change, the repository's `scripts/test/executor-bump.py` makes a
179
+ build+1 SPK whose executor differs by one byte and rewrites the INFO anchor,
180
+ `executor/setup.json` and the window script's embedded pins together.
154
181
 
155
182
  At start, scheduler readback must exactly match the canonical lifecycle scripts
156
- regenerated from the package identity and approved executor/policy pins. Package
183
+ regenerated from the package identity and approved policy pin. Package
157
184
  setup metadata supplies hints only. The verified names, pins and script hashes
158
185
  are stored in root:root 0600 `runtime/tasks.json`. Purge regenerates the scripts
159
186
  and revalidates each current definition before EventScheduler v1
@@ -188,9 +215,10 @@ and `purge` clears state immediately. A root-approved new monitor ignores the
188
215
  stop file already present at startup; that exception ends after an absence.
189
216
 
190
217
  The boot task checks pending purge/package disappearance before accessing source.
191
- It verifies retained pins and protected copies again before offline purge. Normal
192
- boot installs verified copies and calls root control start to replace a previous
193
- monitor. Scripts stay within 1 KiB with no percent characters, including the
218
+ It verifies the retained policy pin before offline purge from the root-only
219
+ runtime. Normal boot verifies the copies against the policy pin and the INFO
220
+ executor anchor, installs them and calls root control start to replace a
221
+ previous monitor. Scripts stay within 1 KiB with no percent characters, including the
194
222
  longest package name. Partial/tampered retained state requires administrator
195
223
  review. All nine uninstall wizard locales name the two tasks and disclose the
196
224
  retained DSM storage/infrastructure. `inspect`/`status` cleanup guidance is
@@ -202,3 +230,89 @@ a directory descriptor and verified with fstat, so boot umask 0077 cannot reduce
202
230
  validated and never repaired/adopted. The package directory must already have
203
231
  root/package-group ownership. The socket is set to root/package-group 0660 and
204
232
  verified using Linux O_PATH + fstat on its filesystem inode.
233
+
234
+ ## Explicit long-running v1 extension
235
+
236
+ The pinned policy opts in with top-level `destinations: ["save"]` and
237
+ `lifetime: "until-revoked"`, together with `files.moveFromStaging` in the
238
+ operation allowlist. Destination keys match `^[a-z][a-z0-9_-]{0,63}$`; unknown
239
+ keys/lifetimes fail closed. Legacy policies/TTL grants never become permanent.
240
+ The existing v1 envelope, peer UID check, protected runtime and session verifier
241
+ remain unchanged. `root.run` is independent and is never a writer fallback.
242
+
243
+ | Operation | Parameters | Result |
244
+ | --- | --- | --- |
245
+ | delegate.create (permanent) | scope, ops:[files.moveFromStaging], path, destination, lifetime:until-revoked | delegation_id, subject, path, destination, lifetime; zero expiry |
246
+ | files.moveFromStaging | delegation_id, job_id, staging, name, size | job_id, state |
247
+ | files.operationStatus | original delegation_id, job_id | job_id, state, optional code/receipt |
248
+ | files.cancelOperation | original delegation_id, job_id | current operation state |
249
+ | delegate.disable / delegate.enable | none; live administrator session | disabled |
250
+ | delegate.audit | none; live owner/admin session | latest bounded events |
251
+
252
+ Permanent create needs the current user's cookie and SynoToken and a successful
253
+ File Station write check. The executor derives username/UID and exact directory
254
+ identity itself. Permanent revoke is owner-bound even for administrators; admins
255
+ can disable the entire package. Auth-less operation submission/status/cancel is
256
+ for the trusted package producer holding the grant reference and original job ID.
257
+ If credentials are supplied, both must verify and the owner must match; failed
258
+ caller auth never falls back to offline authority. A compromised package backend
259
+ can use all valid grants it holds, as documented in the approved trust model.
260
+
261
+ Grants survive service restart in the protected store. The disabled flag also
262
+ survives; mailbox start/boot never clears it. Disable persists first and revokes
263
+ all legacy/permanent grants. Enable checks the live admin session and completes
264
+ revocation before clearing the flag; it never restores old grants. Repeated enable
265
+ while already enabled is a no-op.
266
+
267
+ Operations are separate `operation-<sha256(job_id)>.record` files, root:root 0600.
268
+ They bind immutable grant/job/staging/name/size and move through queued, copying,
269
+ committed, canceled, interrupted or uncertain. Queued resumes without credentials;
270
+ copying becomes interrupted on restart, or uncertain after durable publish intent.
271
+ Neither state is replayed. Changed input for the same job is `operation-conflict`.
272
+ Committed status alone includes `receipt:{path,size}`. Cleanup failures retain
273
+ committed and add `CLEANUP_PENDING`. No same-name/hash guessing establishes receipt.
274
+
275
+ Limits: 16 GiB per file, actual size+1 read, 16 queued, one active copy per package,
276
+ 24-hour attempt, 10 MiB operation metadata. Full journals reject new admissions;
277
+ terminal records are retained to prevent replay. Bulk input bypasses job spools
278
+ and the old 64 MiB wrapper limit. Long copies revalidate account/AppPriv/ACL/path
279
+ with five-second polling and bounded checks; publish revalidates again. A failed
280
+ identity/ACL/path check invalidates the grant and requires a new selection.
281
+
282
+ The fixed child drops identity before opening the destination and creating any
283
+ inode. Every component uses FD-relative O_NOFOLLOW; ancestors use O_PATH so only
284
+ search rights are required. Source is package-owned, regular and singly linked;
285
+ destination is the exact granted device/inode, never a caller-supplied path.
286
+ Part metadata is durable before copying. Publish links the open part inode with
287
+ no replacement, refusing files/symlinks/FIFOs at the final name. Revoke, disable
288
+ and publish share the commit lock. Lost/malformed publish replies drain the child
289
+ before releasing that lock and produce uncertain; a confirmed no-side-effect
290
+ refusal such as `destination-exists` remains interrupted. The lock covers bounded
291
+ publish handshake/fsync, never the bulk copy. During the copy the child watches
292
+ its control pipe: if `serve` dies the pipe closes, so the child stops within one
293
+ 1 MiB chunk and unlinks its part (no `PR_SET_PDEATHSIG`, which the identity drop
294
+ clears; works on kernel 3.10). Kernel-blocked filesystem I/O can
295
+ still delay draining; it cannot be declared safely complete by a timeout.
296
+ Legacy `files.write` uses this same child and publish handshake; the executor
297
+ has no other writer, so no child can publish after `serve` is gone.
298
+
299
+ Destination/part cleanup runs as the owner; source cleanup runs as package UID.
300
+ Restart cleans only journaled exact part identity as the current eligible owner;
301
+ changed/missing/inaccessible directories are retained for review, never scanned
302
+ or deleted as root. Subject-controlled directory moves after the final check
303
+ can still complete in the pinned directory object. DSM ACL changes and publication
304
+ are not atomic, and silent UID/inode reuse is not universally detected. A subject
305
+ who owns the destination can mutate its own output; this is not a content sandbox.
306
+
307
+ Structured audit lives in protected `audit.jsonl`/`audit.previous`, at most 50 MiB
308
+ combined, separate from authority. Events include package, username/UID, operation,
309
+ job, location and result; no session credentials. Owner queries are filtered,
310
+ admins can view this package's events. Replies contain at most 256 events/1 MiB.
311
+ Admission events are labeled `admitting` because a subsequent durable write can
312
+ fail. The operation journal, not an admission audit event, establishes completion.
313
+
314
+ The existing status operation reads `Store.Disabled`; protected-store errors set
315
+ `ready:false` rather than assuming enabled. Backend `delegate.status` exposes the
316
+ verified boolean and `disabled` capability state. Backend `delegate.operations.list`
317
+ is strictly empty-params, freshly owner/UID-filtered move-mirror metadata; it is
318
+ not an executor operation. Live completion remains `files.operationStatus`.
@@ -0,0 +1,156 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "os"
7
+ "os/exec"
8
+ "path/filepath"
9
+ "regexp"
10
+ "strings"
11
+ "syscall"
12
+ )
13
+
14
+ // Package Center writes the SPK INFO as root. The package account cannot change
15
+ // it, so its executor digest authorizes executor-only upgrades under the
16
+ // administrator-approved policy without a new PasswordConfirm.
17
+ const executorAnchorKey = "synopkgland_executor_sha256"
18
+
19
+ var anchorRE = regexp.MustCompile(`^"([a-f0-9]{64})"$`)
20
+
21
+ type pinState int
22
+
23
+ const (
24
+ pinsDiffer pinState = iota
25
+ pinsMatch
26
+ pinsAnchored
27
+ )
28
+
29
+ func executorAnchor(info string, trusted func(os.FileInfo) bool) (string, error) {
30
+ b, stat, err := readLifecycleFile(info, 65536)
31
+ if err != nil {
32
+ return "", err
33
+ }
34
+ if !trusted(stat) {
35
+ return "", errors.New("untrusted package INFO")
36
+ }
37
+ anchor := ""
38
+ for _, line := range strings.Split(string(b), "\n") {
39
+ value, ok := strings.CutPrefix(line, executorAnchorKey+"=")
40
+ if !ok {
41
+ continue
42
+ }
43
+ m := anchorRE.FindStringSubmatch(value)
44
+ if m == nil || anchor != "" {
45
+ return "", errors.New("executor anchor")
46
+ }
47
+ anchor = m[1]
48
+ }
49
+ if anchor == "" {
50
+ return "", errors.New("executor anchor")
51
+ }
52
+ return anchor, nil
53
+ }
54
+
55
+ func rootOwnedReadOnly(info os.FileInfo) bool {
56
+ return ownedByRoot(info) && info.Mode().Perm()&0022 == 0
57
+ }
58
+
59
+ func packagePins(ctx context.Context, dir, info string, trusted func(os.FileInfo) bool, executorDigest, policyDigest string) pinState {
60
+ if samePackagePins(ctx, dir, executorDigest, policyDigest) {
61
+ return pinsMatch
62
+ }
63
+ dir, err := filepath.EvalSymlinks(dir)
64
+ if err != nil {
65
+ return pinsDiffer
66
+ }
67
+ if pd, err := digestFile(ctx, dir+"/policy.json", maxPolicyBytes); err != nil || pd != policyDigest {
68
+ return pinsDiffer
69
+ }
70
+ anchor, err := executorAnchor(info, trusted)
71
+ if err != nil {
72
+ return pinsDiffer
73
+ }
74
+ if ed, err := digestFile(ctx, dir+"/executor", maxExecutorBytes); err != nil || ed != anchor {
75
+ return pinsDiffer
76
+ }
77
+ return pinsAnchored
78
+ }
79
+
80
+ // The policy is unchanged, so root scripts (pinned by policy digests) stay too.
81
+ // Verify the protected copy, never the package-reachable source.
82
+ func installAnchored(ctx context.Context, source, info string, trusted func(os.FileInfo) bool, runtime string) error {
83
+ anchor, err := executorAnchor(info, trusted)
84
+ if err != nil {
85
+ return err
86
+ }
87
+ // DSM links the package target to the volume; openRegular refuses links.
88
+ source, err = filepath.EvalSymlinks(source)
89
+ if err != nil {
90
+ return err
91
+ }
92
+ src, err := openRegular(filepath.Join(source, "executor"))
93
+ if err != nil {
94
+ return err
95
+ }
96
+ defer src.Close()
97
+ stat, err := src.Stat()
98
+ if err != nil || stat.Size() > maxExecutorBytes {
99
+ return errors.New("executor size")
100
+ }
101
+ staged, err := os.CreateTemp(runtime, ".executor-")
102
+ if err != nil {
103
+ return err
104
+ }
105
+ defer os.Remove(staged.Name())
106
+ err = copyExact(staged, src, stat.Size())
107
+ if err == nil {
108
+ err = staged.Chmod(0700)
109
+ }
110
+ if err == nil {
111
+ err = staged.Sync()
112
+ }
113
+ if closeErr := staged.Close(); err == nil {
114
+ err = closeErr
115
+ }
116
+ if err != nil {
117
+ return err
118
+ }
119
+ if digest, err := digestFile(ctx, staged.Name(), maxExecutorBytes); err != nil || digest != anchor {
120
+ return errors.New("executor anchor mismatch")
121
+ }
122
+ return os.Rename(staged.Name(), filepath.Join(runtime, "executor"))
123
+ }
124
+
125
+ // Root control start replaces this monitor with the newly installed runtime.
126
+ func startInstalled(runtime, pkg string) error {
127
+ cmd := exec.Command(filepath.Join(runtime, "executor"), "control", "start", "--package", pkg)
128
+ cmd.Env = []string{"PATH=/usr/bin:/bin", "LANG=C"}
129
+ cmd.Dir = "/"
130
+ cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
131
+ if err := cmd.Start(); err != nil {
132
+ return err
133
+ }
134
+ return cmd.Process.Release()
135
+ }
136
+
137
+ // An anchored upgrade is handed to root start, which replaces this monitor:
138
+ // only differing pins are an approval request, and only they say so.
139
+ func approvedPins(state pinState, install, start func() error, log func(string)) bool {
140
+ if state == pinsDiffer {
141
+ log("executor paused: package pins require administrator approval")
142
+ }
143
+ if state != pinsAnchored {
144
+ return state == pinsMatch
145
+ }
146
+ if err := install(); err != nil {
147
+ log("executor upgrade refused: INFO-anchored executor could not be installed")
148
+ return false
149
+ }
150
+ if err := start(); err != nil {
151
+ log("executor upgrade installed; root start failed")
152
+ return false
153
+ }
154
+ log("executor upgrade: INFO-anchored executor installed under the approved policy")
155
+ return false
156
+ }