@synopackageland/cli 0.6.0 → 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 (585) hide show
  1. package/CHANGELOG.md +613 -0
  2. package/README.md +81 -78
  3. package/dist/add.js +39 -16
  4. package/dist/authorization-sdk.d.ts +7 -0
  5. package/dist/authorization-sdk.js +7 -0
  6. package/dist/build-spk/delegate-scope.d.ts +6 -0
  7. package/dist/build-spk/delegate-scope.js +34 -0
  8. package/dist/build-spk/dsm-arch.d.ts +7 -1
  9. package/dist/build-spk/dsm-arch.js +24 -28
  10. package/dist/build-spk/dsm-platforms.json +39 -0
  11. package/dist/build-spk/dsm-version.d.ts +11 -0
  12. package/dist/build-spk/dsm-version.js +17 -0
  13. package/dist/build-spk/gateway.d.ts +1 -1
  14. package/dist/build-spk/gateway.js +2 -2
  15. package/dist/build-spk/generator.js +30 -5
  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 +30 -18
  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/plan.js +1 -1
  26. package/dist/deploy/spk-version.js +1 -1
  27. package/dist/error-registry.js +46 -13
  28. package/dist/host/dsm-client.d.ts +8 -4
  29. package/dist/host/dsm-client.js +10 -4
  30. package/dist/host/types.d.ts +2 -1
  31. package/dist/info.js +18 -2
  32. package/dist/init.d.ts +3 -0
  33. package/dist/init.js +49 -18
  34. package/dist/package-metadata.d.ts +21 -0
  35. package/dist/package-metadata.js +101 -0
  36. package/dist/portal/alias.d.ts +25 -0
  37. package/dist/portal/alias.js +48 -0
  38. package/dist/portal/package.d.ts +33 -0
  39. package/dist/portal/package.js +116 -0
  40. package/dist/runtime/delegate-contract.d.ts +79 -0
  41. package/dist/runtime/delegate-contract.js +27 -0
  42. package/dist/runtime/executor-build.d.ts +1 -1
  43. package/dist/runtime/executor-build.js +5 -4
  44. package/dist/runtime/executor-inspect.d.ts +3 -0
  45. package/dist/runtime/executor-inspect.js +11 -5
  46. package/dist/runtime/executor-policy.d.ts +12 -0
  47. package/dist/runtime/executor-policy.js +43 -3
  48. package/dist/runtime/executor-scope-task.d.ts +4 -0
  49. package/dist/runtime/executor-scope-task.js +21 -0
  50. package/dist/runtime/executor-tasks.d.ts +2 -1
  51. package/dist/runtime/executor-tasks.js +4 -4
  52. package/dist/skill.js +1 -0
  53. package/dist/standalone/api-permissions.d.ts +10 -0
  54. package/dist/standalone/api-permissions.js +19 -2
  55. package/dist/standalone/background.d.ts +16 -0
  56. package/dist/standalone/background.js +69 -2
  57. package/dist/standalone/binary.d.ts +1 -1
  58. package/dist/standalone/binary.js +22 -8
  59. package/dist/standalone/build.d.ts +1 -1
  60. package/dist/standalone/build.js +38 -8
  61. package/dist/standalone/daemon.d.ts +1 -1
  62. package/dist/standalone/daemon.js +2 -1
  63. package/dist/standalone/dsm-window.d.ts +3 -1
  64. package/dist/standalone/dsm-window.js +72 -15
  65. package/dist/standalone/inspect-spk.d.ts +9 -1
  66. package/dist/standalone/inspect-spk.js +119 -26
  67. package/dist/standalone/lifecycle.js +86 -8
  68. package/dist/standalone/manifest.d.ts +13 -0
  69. package/dist/standalone/manifest.js +57 -8
  70. package/dist/standalone/native-authorization-window.d.ts +2 -0
  71. package/dist/standalone/native-authorization-window.js +30 -0
  72. package/dist/standalone/native-layout.d.ts +82 -0
  73. package/dist/standalone/native-layout.js +377 -0
  74. package/dist/standalone/native-root-window.d.ts +26 -0
  75. package/dist/standalone/native-root-window.js +282 -0
  76. package/dist/standalone/portal-window.d.ts +21 -0
  77. package/dist/standalone/portal-window.js +155 -0
  78. package/dist/standalone/portal.d.ts +4 -0
  79. package/dist/standalone/portal.js +4 -0
  80. package/dist/standalone/resource.d.ts +5 -3
  81. package/dist/standalone/resource.js +6 -3
  82. package/dist/standalone/root-window.js +62 -15
  83. package/dist/standalone/spk.d.ts +1 -1
  84. package/dist/standalone/spk.js +25 -7
  85. package/dist/templates/_daemon/main_test.go +61 -8
  86. package/dist/templates/_executor/README.md +127 -16
  87. package/dist/templates/_executor/anchor.go +146 -0
  88. package/dist/templates/_executor/anchor_test.go +126 -0
  89. package/dist/templates/_executor/apppriv_review_test.go +1 -1
  90. package/dist/templates/_executor/cancel_contract_test.go +236 -0
  91. package/dist/templates/_executor/copy.go +64 -0
  92. package/dist/templates/_executor/copy_test.go +88 -0
  93. package/dist/templates/_executor/dsm.go +23 -10
  94. package/dist/templates/_executor/dsm_test.go +95 -1
  95. package/dist/templates/_executor/executor.go +260 -49
  96. package/dist/templates/_executor/executor_test.go +36 -6
  97. package/dist/templates/_executor/identity.go +27 -1
  98. package/dist/templates/_executor/identity_kernel_linux_test.go +60 -0
  99. package/dist/templates/_executor/identity_linux.go +82 -0
  100. package/dist/templates/_executor/identity_security_test.go +43 -0
  101. package/dist/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  102. package/dist/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  103. package/dist/templates/_executor/internal/taskscript/boot.sh +9 -9
  104. package/dist/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  105. package/dist/templates/_executor/internal/taskscript/control.sh +15 -10
  106. package/dist/templates/_executor/internal/taskscript/tasks.go +5 -3
  107. package/dist/templates/_executor/lifecycle_test.go +11 -0
  108. package/dist/templates/_executor/link_linux.go +28 -0
  109. package/dist/templates/_executor/long_running_test.go +530 -0
  110. package/dist/templates/_executor/main.go +72 -20
  111. package/dist/templates/_executor/move_linux.go +490 -0
  112. package/dist/templates/_executor/move_linux_test.go +460 -0
  113. package/dist/templates/_executor/move_validation.go +46 -0
  114. package/dist/templates/_executor/move_validation_test.go +187 -0
  115. package/dist/templates/_executor/operations.go +926 -0
  116. package/dist/templates/_executor/platform_linux.go +24 -173
  117. package/dist/templates/_executor/platform_linux_test.go +9 -65
  118. package/dist/templates/_executor/platform_other.go +30 -4
  119. package/dist/templates/_executor/process.go +3 -0
  120. package/dist/templates/_executor/records.go +242 -0
  121. package/dist/templates/_executor/scope_cancel_contract_test.go +91 -0
  122. package/dist/templates/_executor/scope_client.go +37 -0
  123. package/dist/templates/_executor/scope_contract.go +12 -0
  124. package/dist/templates/_executor/selected_scope.go +146 -0
  125. package/dist/templates/_executor/selected_scope_test.go +186 -0
  126. package/dist/templates/_executor/status_disabled_test.go +33 -0
  127. package/dist/templates/_executor/store.go +4 -3
  128. package/dist/templates/_executor/supervise.go +109 -0
  129. package/dist/templates/_executor/supervise_test.go +130 -0
  130. package/dist/templates/_executor/task_race_review_test.go +1 -1
  131. package/dist/templates/_executor/tasks.go +7 -8
  132. package/dist/templates/_executor/tasks_review_test.go +1 -1
  133. package/dist/templates/_executor/tasks_test.go +4 -4
  134. package/dist/templates/_executor/watch.go +8 -0
  135. package/dist/templates/_executor/watch_test.go +23 -2
  136. package/dist/templates/_executor/write_review_linux_test.go +4 -12
  137. package/dist/templates/_shared/AGENTS.md +129 -0
  138. package/dist/templates/binary/dsm-package.yaml +24 -0
  139. package/dist/templates/binary/i18n/messages/de.json +4 -0
  140. package/dist/templates/binary/i18n/messages/en.json +4 -0
  141. package/dist/templates/binary/i18n/messages/es.json +4 -0
  142. package/dist/templates/binary/i18n/messages/fr.json +4 -0
  143. package/dist/templates/binary/i18n/messages/it.json +4 -0
  144. package/dist/templates/binary/i18n/messages/ja.json +4 -0
  145. package/dist/templates/binary/i18n/messages/ko.json +4 -0
  146. package/dist/templates/binary/i18n/messages/zh-CN.json +4 -0
  147. package/dist/templates/binary/i18n/messages/zh-TW.json +4 -0
  148. package/dist/templates/binary/ui/app.js +19 -4
  149. package/dist/templates/native-authorization/AuthorizationGate.vue +91 -0
  150. package/dist/templates/native-authorization/i18n/de.json +37 -0
  151. package/dist/templates/native-authorization/i18n/en.json +37 -0
  152. package/dist/templates/native-authorization/i18n/es.json +37 -0
  153. package/dist/templates/native-authorization/i18n/fr.json +37 -0
  154. package/dist/templates/native-authorization/i18n/index.ts +15 -0
  155. package/dist/templates/native-authorization/i18n/it.json +37 -0
  156. package/dist/templates/native-authorization/i18n/ja.json +37 -0
  157. package/dist/templates/native-authorization/i18n/ko.json +37 -0
  158. package/dist/templates/native-authorization/i18n/zh-CN.json +37 -0
  159. package/dist/templates/native-authorization/i18n/zh-TW.json +37 -0
  160. package/dist/templates/native-go/README.md +43 -10
  161. package/dist/templates/native-go/backend/cmd/app/main.go +27 -7
  162. package/dist/templates/native-go/backend/internal/api/entry_test.go +47 -0
  163. package/dist/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  164. package/dist/templates/native-go/backend/internal/api/registry.go +11 -0
  165. package/dist/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  166. package/dist/templates/native-go/backend/internal/api/server.go +18 -5
  167. package/dist/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  168. package/dist/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  169. package/dist/templates/native-go/backend/internal/app/portal.go +30 -0
  170. package/dist/templates/native-go/backend/internal/app/portal_test.go +55 -0
  171. package/dist/templates/native-go/backend/internal/app/routes.go +8 -2
  172. package/dist/templates/native-go/backend/internal/background/runner.go +1 -1
  173. package/dist/templates/native-go/backend/internal/background/store.go +16 -14
  174. package/dist/templates/native-go/backend/internal/dsm/admin.go +8 -2
  175. package/dist/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  176. package/dist/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  177. package/dist/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  178. package/dist/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  179. package/dist/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  180. package/dist/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  181. package/dist/templates/native-go/backend/internal/dsm/entry.go +177 -0
  182. package/dist/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  183. package/dist/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  184. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  185. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  186. package/dist/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  187. package/dist/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  188. package/dist/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  189. package/dist/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  190. package/dist/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  191. package/dist/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  192. package/dist/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  193. package/dist/templates/native-go/backend/internal/filestation/service.go +1 -1
  194. package/dist/templates/native-go/backend/internal/portal/portal.go +138 -0
  195. package/dist/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  196. package/dist/templates/native-go/dsm-package.yaml +20 -1
  197. package/dist/templates/native-go/i18n/glossary.json +2 -1
  198. package/dist/templates/native-go/i18n/messages/de.json +1 -0
  199. package/dist/templates/native-go/i18n/messages/en.json +1 -0
  200. package/dist/templates/native-go/i18n/messages/es.json +1 -0
  201. package/dist/templates/native-go/i18n/messages/fr.json +1 -0
  202. package/dist/templates/native-go/i18n/messages/it.json +1 -0
  203. package/dist/templates/native-go/i18n/messages/ja.json +1 -0
  204. package/dist/templates/native-go/i18n/messages/ko.json +1 -0
  205. package/dist/templates/native-go/i18n/messages/zh-CN.json +1 -0
  206. package/dist/templates/native-go/i18n/messages/zh-TW.json +1 -0
  207. package/dist/templates/native-go/ui/app.css +10 -0
  208. package/dist/templates/native-go/ui/app.js +11 -1
  209. package/dist/templates/native-go-delegate/DELEGATE.md +126 -5
  210. package/dist/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  211. package/dist/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  212. package/dist/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  213. package/dist/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  214. package/dist/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  215. package/dist/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  216. package/dist/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  217. package/dist/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  218. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  219. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  220. package/dist/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  221. package/dist/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  222. package/dist/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  223. package/dist/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  224. package/dist/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  225. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  226. package/dist/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  227. package/dist/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  228. package/dist/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  229. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  230. package/dist/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  231. package/dist/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  232. package/dist/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  233. package/dist/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  234. package/dist/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  235. package/dist/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  236. package/dist/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  237. package/dist/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  238. package/dist/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  239. package/dist/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  240. package/dist/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  241. package/dist/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  242. package/dist/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  243. package/dist/templates/native-go-delegate/test.sh +1 -0
  244. package/dist/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  245. package/dist/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  246. package/dist/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  247. package/dist/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  248. package/dist/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  249. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  250. package/dist/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  251. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  252. package/dist/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  253. package/dist/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  254. package/dist/templates/native-go-vue/README.md +4 -0
  255. package/dist/templates/native-go-vue/frontend/package-lock.json +4 -4
  256. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  257. package/dist/templates/native-go-vue/frontend/src/App.vue +18 -13
  258. package/dist/templates/native-go-vue/frontend/src/context.ts +31 -0
  259. package/dist/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  260. package/dist/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  261. package/dist/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  262. package/dist/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  263. package/dist/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  264. package/dist/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  265. package/dist/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  266. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  267. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  268. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  269. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  270. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  271. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  272. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  273. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  274. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  275. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  276. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  277. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  278. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  279. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  280. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  281. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  282. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  283. package/dist/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  284. package/dist/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  285. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  286. package/dist/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  287. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  288. package/dist/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  289. package/dist/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  290. package/dist/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  291. package/dist/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  292. package/dist/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  293. package/dist/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  294. package/dist/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  295. package/dist/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  296. package/dist/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  297. package/dist/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  298. package/dist/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  299. package/dist/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  300. package/dist/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  301. package/dist/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  302. package/dist/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  303. package/dist/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  304. package/dist/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  305. package/dist/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  306. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  307. package/dist/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  308. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  309. package/dist/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  310. package/dist/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  311. package/dist/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  312. package/dist/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  313. package/dist/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  314. package/dist/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  315. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  316. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  317. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  318. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  319. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  320. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  321. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  322. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  323. package/dist/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  324. package/dist/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  325. package/dist/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  326. package/dist/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  327. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  328. package/dist/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  329. package/dist/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
  330. package/dist/validate.js +2 -1
  331. package/package.json +12 -2
  332. package/schema/package-metadata.schema.json +101 -0
  333. package/schema/synology-app.schema.json +112 -0
  334. package/skills/SKILL.md +109 -3
  335. package/skills/reference/create.md +101 -2
  336. package/skills/reference/deploy.md +2 -2
  337. package/skills/reference/files.md +113 -2
  338. package/skills/reference/identity.md +70 -1
  339. package/skills/reference/portal.md +17 -0
  340. package/skills/reference/ui-vue.md +12 -0
  341. package/templates/_daemon/main_test.go +61 -8
  342. package/templates/_executor/README.md +127 -16
  343. package/templates/_executor/anchor.go +146 -0
  344. package/templates/_executor/anchor_test.go +126 -0
  345. package/templates/_executor/apppriv_review_test.go +1 -1
  346. package/templates/_executor/cancel_contract_test.go +236 -0
  347. package/templates/_executor/copy.go +64 -0
  348. package/templates/_executor/copy_test.go +88 -0
  349. package/templates/_executor/dsm.go +23 -10
  350. package/templates/_executor/dsm_test.go +95 -1
  351. package/templates/_executor/executor.go +260 -49
  352. package/templates/_executor/executor_test.go +36 -6
  353. package/templates/_executor/identity.go +27 -1
  354. package/templates/_executor/identity_kernel_linux_test.go +60 -0
  355. package/templates/_executor/identity_linux.go +82 -0
  356. package/templates/_executor/identity_security_test.go +43 -0
  357. package/templates/_executor/internal/lifecycle/lifecycle.go +5 -0
  358. package/templates/_executor/internal/lifecycle/lifecycle_test.go +61 -3
  359. package/templates/_executor/internal/taskscript/boot.sh +9 -9
  360. package/templates/_executor/internal/taskscript/cmd/main.go +2 -2
  361. package/templates/_executor/internal/taskscript/control.sh +15 -10
  362. package/templates/_executor/internal/taskscript/tasks.go +5 -3
  363. package/templates/_executor/lifecycle_test.go +11 -0
  364. package/templates/_executor/link_linux.go +28 -0
  365. package/templates/_executor/long_running_test.go +530 -0
  366. package/templates/_executor/main.go +72 -20
  367. package/templates/_executor/move_linux.go +490 -0
  368. package/templates/_executor/move_linux_test.go +460 -0
  369. package/templates/_executor/move_validation.go +46 -0
  370. package/templates/_executor/move_validation_test.go +187 -0
  371. package/templates/_executor/operations.go +926 -0
  372. package/templates/_executor/platform_linux.go +24 -173
  373. package/templates/_executor/platform_linux_test.go +9 -65
  374. package/templates/_executor/platform_other.go +30 -4
  375. package/templates/_executor/process.go +3 -0
  376. package/templates/_executor/records.go +242 -0
  377. package/templates/_executor/scope_cancel_contract_test.go +91 -0
  378. package/templates/_executor/scope_client.go +37 -0
  379. package/templates/_executor/scope_contract.go +12 -0
  380. package/templates/_executor/selected_scope.go +146 -0
  381. package/templates/_executor/selected_scope_test.go +186 -0
  382. package/templates/_executor/status_disabled_test.go +33 -0
  383. package/templates/_executor/store.go +4 -3
  384. package/templates/_executor/supervise.go +109 -0
  385. package/templates/_executor/supervise_test.go +130 -0
  386. package/templates/_executor/task_race_review_test.go +1 -1
  387. package/templates/_executor/tasks.go +7 -8
  388. package/templates/_executor/tasks_review_test.go +1 -1
  389. package/templates/_executor/tasks_test.go +4 -4
  390. package/templates/_executor/watch.go +8 -0
  391. package/templates/_executor/watch_test.go +23 -2
  392. package/templates/_executor/write_review_linux_test.go +4 -12
  393. package/templates/_shared/AGENTS.md +129 -0
  394. package/templates/binary/dsm-package.yaml +24 -0
  395. package/templates/binary/i18n/messages/de.json +4 -0
  396. package/templates/binary/i18n/messages/en.json +4 -0
  397. package/templates/binary/i18n/messages/es.json +4 -0
  398. package/templates/binary/i18n/messages/fr.json +4 -0
  399. package/templates/binary/i18n/messages/it.json +4 -0
  400. package/templates/binary/i18n/messages/ja.json +4 -0
  401. package/templates/binary/i18n/messages/ko.json +4 -0
  402. package/templates/binary/i18n/messages/zh-CN.json +4 -0
  403. package/templates/binary/i18n/messages/zh-TW.json +4 -0
  404. package/templates/binary/ui/app.js +19 -4
  405. package/templates/native-authorization/AuthorizationGate.vue +91 -0
  406. package/templates/native-authorization/i18n/de.json +37 -0
  407. package/templates/native-authorization/i18n/en.json +37 -0
  408. package/templates/native-authorization/i18n/es.json +37 -0
  409. package/templates/native-authorization/i18n/fr.json +37 -0
  410. package/templates/native-authorization/i18n/index.ts +15 -0
  411. package/templates/native-authorization/i18n/it.json +37 -0
  412. package/templates/native-authorization/i18n/ja.json +37 -0
  413. package/templates/native-authorization/i18n/ko.json +37 -0
  414. package/templates/native-authorization/i18n/zh-CN.json +37 -0
  415. package/templates/native-authorization/i18n/zh-TW.json +37 -0
  416. package/templates/native-go/README.md +43 -10
  417. package/templates/native-go/backend/cmd/app/main.go +27 -7
  418. package/templates/native-go/backend/internal/api/entry_test.go +47 -0
  419. package/templates/native-go/backend/internal/api/permissions_test.go +3 -3
  420. package/templates/native-go/backend/internal/api/registry.go +11 -0
  421. package/templates/native-go/backend/internal/api/sdk-permissions.json +14 -1
  422. package/templates/native-go/backend/internal/api/server.go +18 -5
  423. package/templates/native-go/backend/internal/app/delegate_config.go +57 -0
  424. package/templates/native-go/backend/internal/app/delegate_config_test.go +28 -0
  425. package/templates/native-go/backend/internal/app/portal.go +30 -0
  426. package/templates/native-go/backend/internal/app/portal_test.go +55 -0
  427. package/templates/native-go/backend/internal/app/routes.go +8 -2
  428. package/templates/native-go/backend/internal/background/runner.go +1 -1
  429. package/templates/native-go/backend/internal/background/store.go +16 -14
  430. package/templates/native-go/backend/internal/dsm/admin.go +8 -2
  431. package/templates/native-go/backend/internal/dsm/admin_linux.go +43 -13
  432. package/templates/native-go/backend/internal/dsm/admin_linux_test.go +56 -0
  433. package/templates/native-go/backend/internal/dsm/admin_other.go +4 -1
  434. package/templates/native-go/backend/internal/dsm/apppriv.go +30 -0
  435. package/templates/native-go/backend/internal/dsm/bridge_file.go +75 -0
  436. package/templates/native-go/backend/internal/dsm/bridge_file_test.go +57 -0
  437. package/templates/native-go/backend/internal/dsm/entry.go +177 -0
  438. package/templates/native-go/backend/internal/dsm/entry_test.go +315 -0
  439. package/templates/native-go/backend/internal/dsm/native/admin-armv7.elf +0 -0
  440. package/templates/native-go/backend/internal/dsm/native/apppriv-aarch64.elf +0 -0
  441. package/templates/native-go/backend/internal/dsm/native/apppriv-armv7.elf +0 -0
  442. package/templates/native-go/backend/internal/dsm/native/apppriv-x86_64.elf +0 -0
  443. package/templates/native-go/backend/internal/dsm/native/apppriv_check.c +33 -0
  444. package/templates/native-go/backend/internal/dsm/native/build.sh +13 -4
  445. package/templates/native-go/backend/internal/dsm/native/provenance.json +9 -3
  446. package/templates/native-go/backend/internal/filestation/check_permission.go +71 -0
  447. package/templates/native-go/backend/internal/filestation/check_permission_test.go +77 -0
  448. package/templates/native-go/backend/internal/filestation/sdk_policy_test.go +39 -0
  449. package/templates/native-go/backend/internal/filestation/service.go +1 -1
  450. package/templates/native-go/backend/internal/portal/portal.go +138 -0
  451. package/templates/native-go/backend/internal/portal/portal_test.go +89 -0
  452. package/templates/native-go/dsm-package.yaml +20 -1
  453. package/templates/native-go/i18n/glossary.json +2 -1
  454. package/templates/native-go/i18n/messages/de.json +1 -0
  455. package/templates/native-go/i18n/messages/en.json +1 -0
  456. package/templates/native-go/i18n/messages/es.json +1 -0
  457. package/templates/native-go/i18n/messages/fr.json +1 -0
  458. package/templates/native-go/i18n/messages/it.json +1 -0
  459. package/templates/native-go/i18n/messages/ja.json +1 -0
  460. package/templates/native-go/i18n/messages/ko.json +1 -0
  461. package/templates/native-go/i18n/messages/zh-CN.json +1 -0
  462. package/templates/native-go/i18n/messages/zh-TW.json +1 -0
  463. package/templates/native-go/ui/app.css +10 -0
  464. package/templates/native-go/ui/app.js +11 -1
  465. package/templates/native-go-delegate/DELEGATE.md +126 -5
  466. package/templates/native-go-delegate/backend/cmd/background-worker/main.go +7 -0
  467. package/templates/native-go-delegate/backend/internal/app/delegate.go +11 -1
  468. package/templates/native-go-delegate/backend/internal/app/delegate_routes_test.go +14 -0
  469. package/templates/native-go-delegate/backend/internal/background/delegated_moves.go +270 -0
  470. package/templates/native-go-delegate/backend/internal/delegate/admission_recovery_test.go +410 -0
  471. package/templates/native-go-delegate/backend/internal/delegate/cancel_contract_test.go +95 -0
  472. package/templates/native-go-delegate/backend/internal/delegate/client.go +8 -0
  473. package/templates/native-go-delegate/backend/internal/delegate/destination.go +110 -0
  474. package/templates/native-go-delegate/backend/internal/delegate/destination_state.go +117 -0
  475. package/templates/native-go-delegate/backend/internal/delegate/destination_state_test.go +60 -0
  476. package/templates/native-go-delegate/backend/internal/delegate/destination_test.go +116 -0
  477. package/templates/native-go-delegate/backend/internal/delegate/example.go +81 -0
  478. package/templates/native-go-delegate/backend/internal/delegate/example_test.go +91 -0
  479. package/templates/native-go-delegate/backend/internal/delegate/executor_contract_test.go +511 -0
  480. package/templates/native-go-delegate/backend/internal/delegate/files.go +1 -1
  481. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes.go +92 -0
  482. package/templates/native-go-delegate/backend/internal/delegate/long_running_routes_test.go +99 -0
  483. package/templates/native-go-delegate/backend/internal/delegate/move.go +348 -0
  484. package/templates/native-go-delegate/backend/internal/delegate/move_test.go +351 -0
  485. package/templates/native-go-delegate/backend/internal/delegate/operations_list.go +65 -0
  486. package/templates/native-go-delegate/backend/internal/delegate/operations_list_test.go +114 -0
  487. package/templates/native-go-delegate/backend/internal/delegate/retry_test.go +1 -1
  488. package/templates/native-go-delegate/backend/internal/delegate/service.go +58 -17
  489. package/templates/native-go-delegate/backend/internal/delegate/staging.go +121 -0
  490. package/templates/native-go-delegate/backend/internal/delegate/status_disabled_test.go +51 -0
  491. package/templates/native-go-delegate/backend/internal/delegate/testdata/executor_contract.txt +112 -0
  492. package/templates/native-go-delegate/backend/internal/delegate/transient_contract_test.go +137 -0
  493. package/templates/native-go-delegate/backend/internal/filestation/files.go +1 -31
  494. package/templates/native-go-delegate/frontend/src/CapabilityPanels.vue +30 -3
  495. package/templates/native-go-delegate/frontend/src/delegate/BackgroundSavePanel.vue +113 -0
  496. package/templates/native-go-delegate/frontend/src/delegate/copy.ts +5 -6
  497. package/templates/native-go-delegate/frontend/test/background-save.test.ts +121 -0
  498. package/templates/native-go-delegate/frontend/test/scope-settings.test.ts +49 -0
  499. package/templates/native-go-delegate/test.sh +1 -0
  500. package/templates/native-go-jobs/frontend/src/background/i18n/de.json +2 -2
  501. package/templates/native-go-jobs/frontend/src/background/i18n/en.json +2 -2
  502. package/templates/native-go-jobs/frontend/src/background/i18n/es.json +12 -12
  503. package/templates/native-go-jobs/frontend/src/background/i18n/fr.json +4 -4
  504. package/templates/native-go-jobs/frontend/src/background/i18n/it.json +17 -17
  505. package/templates/native-go-jobs/frontend/src/background/i18n/ja.json +7 -7
  506. package/templates/native-go-jobs/frontend/src/background/i18n/ko.json +15 -15
  507. package/templates/native-go-jobs/frontend/src/background/i18n/zh-CN.json +3 -3
  508. package/templates/native-go-jobs/frontend/src/background/i18n/zh-TW.json +2 -2
  509. package/templates/native-go-jobs/frontend/test/background.test.ts +25 -28
  510. package/templates/native-go-vue/README.md +4 -0
  511. package/templates/native-go-vue/frontend/package-lock.json +4 -4
  512. package/templates/native-go-vue/frontend/package.json +1 -1
  513. package/templates/native-go-vue/frontend/src/App.vue +18 -13
  514. package/templates/native-go-vue/frontend/src/context.ts +31 -0
  515. package/templates/native-go-vue/frontend/src/delegate/ExecutorSettings.vue +52 -8
  516. package/templates/native-go-vue/frontend/src/delegate/catalogs.ts +11 -0
  517. package/templates/native-go-vue/frontend/src/delegate/copy.test.ts +12 -0
  518. package/templates/native-go-vue/frontend/src/delegate/copy.ts +4 -4
  519. package/templates/native-go-vue/frontend/src/delegate/executor-setup.ts +4 -2
  520. package/templates/native-go-vue/frontend/src/delegate/facade.test.ts +100 -0
  521. package/templates/native-go-vue/frontend/src/delegate/facade.ts +85 -0
  522. package/templates/native-go-vue/frontend/src/delegate/i18n/de.json +46 -0
  523. package/templates/native-go-vue/frontend/src/delegate/i18n/en.json +12 -2
  524. package/templates/native-go-vue/frontend/src/delegate/i18n/es.json +46 -0
  525. package/templates/native-go-vue/frontend/src/delegate/i18n/fr.json +46 -0
  526. package/templates/native-go-vue/frontend/src/delegate/i18n/it.json +46 -0
  527. package/templates/native-go-vue/frontend/src/delegate/i18n/ja.json +46 -0
  528. package/templates/native-go-vue/frontend/src/delegate/i18n/ko.json +46 -0
  529. package/templates/native-go-vue/frontend/src/delegate/i18n/save/de.json +42 -0
  530. package/templates/native-go-vue/frontend/src/delegate/i18n/save/en.json +42 -0
  531. package/templates/native-go-vue/frontend/src/delegate/i18n/save/es.json +42 -0
  532. package/templates/native-go-vue/frontend/src/delegate/i18n/save/fr.json +42 -0
  533. package/templates/native-go-vue/frontend/src/delegate/i18n/save/it.json +42 -0
  534. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ja.json +42 -0
  535. package/templates/native-go-vue/frontend/src/delegate/i18n/save/ko.json +42 -0
  536. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-CN.json +42 -0
  537. package/templates/native-go-vue/frontend/src/delegate/i18n/save/zh-TW.json +42 -0
  538. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-CN.json +46 -0
  539. package/templates/native-go-vue/frontend/src/delegate/i18n/zh-TW.json +15 -5
  540. package/templates/native-go-vue/frontend/src/delegate/long-running.ts +57 -0
  541. package/templates/native-go-vue/frontend/src/delegate/save-copy.test.ts +12 -0
  542. package/templates/native-go-vue/frontend/src/delegate/save-copy.ts +24 -0
  543. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.test.ts +12 -0
  544. package/templates/native-go-vue/frontend/src/delegate/scoped-picker.ts +21 -0
  545. package/templates/native-go-vue/frontend/src/files/files.test.ts +7 -0
  546. package/templates/native-go-vue/frontend/src/i18n/de.json +20 -0
  547. package/templates/native-go-vue/frontend/src/i18n/en.json +20 -0
  548. package/templates/native-go-vue/frontend/src/i18n/es.json +20 -0
  549. package/templates/native-go-vue/frontend/src/i18n/fr.json +20 -0
  550. package/templates/native-go-vue/frontend/src/i18n/it.json +20 -0
  551. package/templates/native-go-vue/frontend/src/i18n/ja.json +20 -0
  552. package/templates/native-go-vue/frontend/src/i18n/ko.json +20 -0
  553. package/templates/native-go-vue/frontend/src/i18n/zh-CN.json +20 -0
  554. package/templates/native-go-vue/frontend/src/i18n/zh-TW.json +20 -0
  555. package/templates/native-go-vue/frontend/src/i18n.ts +13 -0
  556. package/templates/native-go-vue/frontend/src/identity/LoginPage.vue +16 -14
  557. package/templates/native-go-vue/frontend/src/identity/i18n/de.json +27 -0
  558. package/templates/native-go-vue/frontend/src/identity/i18n/en.json +27 -0
  559. package/templates/native-go-vue/frontend/src/identity/i18n/es.json +27 -0
  560. package/templates/native-go-vue/frontend/src/identity/i18n/fr.json +27 -0
  561. package/templates/native-go-vue/frontend/src/identity/i18n/it.json +27 -0
  562. package/templates/native-go-vue/frontend/src/identity/i18n/ja.json +27 -0
  563. package/templates/native-go-vue/frontend/src/identity/i18n/ko.json +27 -0
  564. package/templates/native-go-vue/frontend/src/identity/i18n/zh-CN.json +27 -0
  565. package/templates/native-go-vue/frontend/src/identity/i18n/zh-TW.json +27 -0
  566. package/templates/native-go-vue/frontend/src/identity/i18n.ts +14 -0
  567. package/templates/native-go-vue/frontend/src/identity/session.test.ts +4 -0
  568. package/templates/native-go-vue/frontend/src/identity/session.ts +9 -8
  569. package/templates/native-go-vue/frontend/src/nas/NasPicker.vue +31 -12
  570. package/templates/native-go-vue/frontend/src/nas/destination.test.ts +48 -0
  571. package/templates/native-go-vue/frontend/src/nas/i18n/files/de.json +1 -1
  572. package/templates/native-go-vue/frontend/src/nas/i18n/files/en.json +1 -1
  573. package/templates/native-go-vue/frontend/src/nas/i18n/files/es.json +10 -10
  574. package/templates/native-go-vue/frontend/src/nas/i18n/files/fr.json +1 -1
  575. package/templates/native-go-vue/frontend/src/nas/i18n/files/it.json +12 -12
  576. package/templates/native-go-vue/frontend/src/nas/i18n/files/ja.json +15 -15
  577. package/templates/native-go-vue/frontend/src/nas/i18n/files/ko.json +12 -12
  578. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-CN.json +1 -1
  579. package/templates/native-go-vue/frontend/src/nas/i18n/files/zh-TW.json +1 -1
  580. package/templates/native-go-vue/frontend/src/portal/PortalSettings.vue +39 -0
  581. package/templates/native-go-vue/frontend/src/shell/i18n/fr.json +1 -1
  582. package/templates/native-go-vue/frontend/src/shell/i18n/ja.json +1 -1
  583. package/templates/native-go-vue/frontend/test/apps.test.ts +14 -0
  584. package/templates/native-go-vue/frontend/test/portal-settings.test.ts +71 -0
  585. package/templates/native-go-vue/frontend/test/shell-i18n.test.ts +50 -0
@@ -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,17 @@ 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.
154
178
 
155
179
  At start, scheduler readback must exactly match the canonical lifecycle scripts
156
- regenerated from the package identity and approved executor/policy pins. Package
180
+ regenerated from the package identity and approved policy pin. Package
157
181
  setup metadata supplies hints only. The verified names, pins and script hashes
158
182
  are stored in root:root 0600 `runtime/tasks.json`. Purge regenerates the scripts
159
183
  and revalidates each current definition before EventScheduler v1
@@ -188,9 +212,10 @@ and `purge` clears state immediately. A root-approved new monitor ignores the
188
212
  stop file already present at startup; that exception ends after an absence.
189
213
 
190
214
  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
215
+ It verifies the retained policy pin before offline purge from the root-only
216
+ runtime. Normal boot verifies the copies against the policy pin and the INFO
217
+ executor anchor, installs them and calls root control start to replace a
218
+ previous monitor. Scripts stay within 1 KiB with no percent characters, including the
194
219
  longest package name. Partial/tampered retained state requires administrator
195
220
  review. All nine uninstall wizard locales name the two tasks and disclose the
196
221
  retained DSM storage/infrastructure. `inspect`/`status` cleanup guidance is
@@ -202,3 +227,89 @@ a directory descriptor and verified with fstat, so boot umask 0077 cannot reduce
202
227
  validated and never repaired/adopted. The package directory must already have
203
228
  root/package-group ownership. The socket is set to root/package-group 0660 and
204
229
  verified using Linux O_PATH + fstat on its filesystem inode.
230
+
231
+ ## Explicit long-running v1 extension
232
+
233
+ The pinned policy opts in with top-level `destinations: ["save"]` and
234
+ `lifetime: "until-revoked"`, together with `files.moveFromStaging` in the
235
+ operation allowlist. Destination keys match `^[a-z][a-z0-9_-]{0,63}$`; unknown
236
+ keys/lifetimes fail closed. Legacy policies/TTL grants never become permanent.
237
+ The existing v1 envelope, peer UID check, protected runtime and session verifier
238
+ remain unchanged. `root.run` is independent and is never a writer fallback.
239
+
240
+ | Operation | Parameters | Result |
241
+ | --- | --- | --- |
242
+ | delegate.create (permanent) | scope, ops:[files.moveFromStaging], path, destination, lifetime:until-revoked | delegation_id, subject, path, destination, lifetime; zero expiry |
243
+ | files.moveFromStaging | delegation_id, job_id, staging, name, size | job_id, state |
244
+ | files.operationStatus | original delegation_id, job_id | job_id, state, optional code/receipt |
245
+ | files.cancelOperation | original delegation_id, job_id | current operation state |
246
+ | delegate.disable / delegate.enable | none; live administrator session | disabled |
247
+ | delegate.audit | none; live owner/admin session | latest bounded events |
248
+
249
+ Permanent create needs the current user's cookie and SynoToken and a successful
250
+ File Station write check. The executor derives username/UID and exact directory
251
+ identity itself. Permanent revoke is owner-bound even for administrators; admins
252
+ can disable the entire package. Auth-less operation submission/status/cancel is
253
+ for the trusted package producer holding the grant reference and original job ID.
254
+ If credentials are supplied, both must verify and the owner must match; failed
255
+ caller auth never falls back to offline authority. A compromised package backend
256
+ can use all valid grants it holds, as documented in the approved trust model.
257
+
258
+ Grants survive service restart in the protected store. The disabled flag also
259
+ survives; mailbox start/boot never clears it. Disable persists first and revokes
260
+ all legacy/permanent grants. Enable checks the live admin session and completes
261
+ revocation before clearing the flag; it never restores old grants. Repeated enable
262
+ while already enabled is a no-op.
263
+
264
+ Operations are separate `operation-<sha256(job_id)>.record` files, root:root 0600.
265
+ They bind immutable grant/job/staging/name/size and move through queued, copying,
266
+ committed, canceled, interrupted or uncertain. Queued resumes without credentials;
267
+ copying becomes interrupted on restart, or uncertain after durable publish intent.
268
+ Neither state is replayed. Changed input for the same job is `operation-conflict`.
269
+ Committed status alone includes `receipt:{path,size}`. Cleanup failures retain
270
+ committed and add `CLEANUP_PENDING`. No same-name/hash guessing establishes receipt.
271
+
272
+ Limits: 16 GiB per file, actual size+1 read, 16 queued, one active copy per package,
273
+ 24-hour attempt, 10 MiB operation metadata. Full journals reject new admissions;
274
+ terminal records are retained to prevent replay. Bulk input bypasses job spools
275
+ and the old 64 MiB wrapper limit. Long copies revalidate account/AppPriv/ACL/path
276
+ with five-second polling and bounded checks; publish revalidates again. A failed
277
+ identity/ACL/path check invalidates the grant and requires a new selection.
278
+
279
+ The fixed child drops identity before opening the destination and creating any
280
+ inode. Every component uses FD-relative O_NOFOLLOW; ancestors use O_PATH so only
281
+ search rights are required. Source is package-owned, regular and singly linked;
282
+ destination is the exact granted device/inode, never a caller-supplied path.
283
+ Part metadata is durable before copying. Publish links the open part inode with
284
+ no replacement, refusing files/symlinks/FIFOs at the final name. Revoke, disable
285
+ and publish share the commit lock. Lost/malformed publish replies drain the child
286
+ before releasing that lock and produce uncertain; a confirmed no-side-effect
287
+ refusal such as `destination-exists` remains interrupted. The lock covers bounded
288
+ publish handshake/fsync, never the bulk copy. During the copy the child watches
289
+ its control pipe: if `serve` dies the pipe closes, so the child stops within one
290
+ 1 MiB chunk and unlinks its part (no `PR_SET_PDEATHSIG`, which the identity drop
291
+ clears; works on kernel 3.10). Kernel-blocked filesystem I/O can
292
+ still delay draining; it cannot be declared safely complete by a timeout.
293
+ Legacy `files.write` uses this same child and publish handshake; the executor
294
+ has no other writer, so no child can publish after `serve` is gone.
295
+
296
+ Destination/part cleanup runs as the owner; source cleanup runs as package UID.
297
+ Restart cleans only journaled exact part identity as the current eligible owner;
298
+ changed/missing/inaccessible directories are retained for review, never scanned
299
+ or deleted as root. Subject-controlled directory moves after the final check
300
+ can still complete in the pinned directory object. DSM ACL changes and publication
301
+ are not atomic, and silent UID/inode reuse is not universally detected. A subject
302
+ who owns the destination can mutate its own output; this is not a content sandbox.
303
+
304
+ Structured audit lives in protected `audit.jsonl`/`audit.previous`, at most 50 MiB
305
+ combined, separate from authority. Events include package, username/UID, operation,
306
+ job, location and result; no session credentials. Owner queries are filtered,
307
+ admins can view this package's events. Replies contain at most 256 events/1 MiB.
308
+ Admission events are labeled `admitting` because a subsequent durable write can
309
+ fail. The operation journal, not an admission audit event, establishes completion.
310
+
311
+ The existing status operation reads `Store.Disabled`; protected-store errors set
312
+ `ready:false` rather than assuming enabled. Backend `delegate.status` exposes the
313
+ verified boolean and `disabled` capability state. Backend `delegate.operations.list`
314
+ is strictly empty-params, freshly owner/UID-filtered move-mirror metadata; it is
315
+ not an executor operation. Live completion remains `files.operationStatus`.
@@ -0,0 +1,146 @@
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
+ src, err := openRegular(filepath.Join(source, "executor"))
88
+ if err != nil {
89
+ return err
90
+ }
91
+ defer src.Close()
92
+ stat, err := src.Stat()
93
+ if err != nil || stat.Size() > maxExecutorBytes {
94
+ return errors.New("executor size")
95
+ }
96
+ staged, err := os.CreateTemp(runtime, ".executor-")
97
+ if err != nil {
98
+ return err
99
+ }
100
+ defer os.Remove(staged.Name())
101
+ err = copyExact(staged, src, stat.Size())
102
+ if err == nil {
103
+ err = staged.Chmod(0700)
104
+ }
105
+ if err == nil {
106
+ err = staged.Sync()
107
+ }
108
+ if closeErr := staged.Close(); err == nil {
109
+ err = closeErr
110
+ }
111
+ if err != nil {
112
+ return err
113
+ }
114
+ if digest, err := digestFile(ctx, staged.Name(), maxExecutorBytes); err != nil || digest != anchor {
115
+ return errors.New("executor anchor mismatch")
116
+ }
117
+ return os.Rename(staged.Name(), filepath.Join(runtime, "executor"))
118
+ }
119
+
120
+ // Root control start replaces this monitor with the newly installed runtime.
121
+ func startInstalled(runtime, pkg string) error {
122
+ cmd := exec.Command(filepath.Join(runtime, "executor"), "control", "start", "--package", pkg)
123
+ cmd.Env = []string{"PATH=/usr/bin:/bin", "LANG=C"}
124
+ cmd.Dir = "/"
125
+ cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
126
+ if err := cmd.Start(); err != nil {
127
+ return err
128
+ }
129
+ return cmd.Process.Release()
130
+ }
131
+
132
+ func approvedPins(state pinState, install, start func() error, log func(string)) bool {
133
+ if state != pinsAnchored {
134
+ return state == pinsMatch
135
+ }
136
+ if err := install(); err != nil {
137
+ log("executor upgrade refused: INFO-anchored executor could not be installed")
138
+ return false
139
+ }
140
+ if err := start(); err != nil {
141
+ log("executor upgrade installed; root start failed")
142
+ return false
143
+ }
144
+ log("executor upgrade: INFO-anchored executor installed under the approved policy")
145
+ return false
146
+ }
@@ -0,0 +1,126 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "os"
7
+ "path/filepath"
8
+ "strings"
9
+ "testing"
10
+ )
11
+
12
+ func trustAll(os.FileInfo) bool { return true }
13
+
14
+ // anchoredPackage writes a target executor/policy pair and the package INFO.
15
+ func anchoredPackage(t *testing.T, executor, policy string, anchors ...string) (target, info string) {
16
+ t.Helper()
17
+ pkg := realTestPath(t, t.TempDir())
18
+ target = filepath.Join(pkg, "target", "executor")
19
+ os.MkdirAll(target, 0755)
20
+ os.WriteFile(filepath.Join(target, "executor"), []byte(executor), 0755)
21
+ os.WriteFile(filepath.Join(target, "policy.json"), []byte(policy), 0644)
22
+ text := "package=\"TestApp\"\n"
23
+ for _, a := range anchors {
24
+ text += "synopkgland_executor_sha256=\"" + a + "\"\n"
25
+ }
26
+ info = filepath.Join(pkg, "INFO")
27
+ os.WriteFile(info, []byte(text), 0644)
28
+ return target, info
29
+ }
30
+
31
+ func TestExecutorAnchorRequiresOneLowercaseDigestInTrustedINFO(t *testing.T) {
32
+ digest := hashBytes([]byte("new executor"))
33
+ _, info := anchoredPackage(t, "new executor", "policy", digest)
34
+ if got, err := executorAnchor(info, trustAll); err != nil || got != digest {
35
+ t.Fatal("anchor", got, err)
36
+ }
37
+ if _, err := executorAnchor(info, func(os.FileInfo) bool { return false }); err == nil {
38
+ t.Fatal("package-writable INFO accepted")
39
+ }
40
+ for name, anchors := range map[string][]string{"missing": nil, "duplicate": {digest, digest}, "uppercase": {strings.ToUpper(digest)}, "short": {digest[:63]}} {
41
+ _, info := anchoredPackage(t, "new executor", "policy", anchors...)
42
+ if _, err := executorAnchor(info, trustAll); err == nil {
43
+ t.Fatal(name, "anchor accepted")
44
+ }
45
+ }
46
+ }
47
+
48
+ func TestPackagePinsAcceptAnExecutorUpgradeOnlyUnderTheApprovedPolicyAndINFOAnchor(t *testing.T) {
49
+ ctx := context.Background()
50
+ ed, pd := hashBytes([]byte("approved executor")), hashBytes([]byte("approved policy"))
51
+ upgraded := hashBytes([]byte("new executor"))
52
+ for _, tc := range []struct {
53
+ name, executor, policy string
54
+ anchors []string
55
+ want pinState
56
+ }{
57
+ {"same bytes", "approved executor", "approved policy", nil, pinsMatch},
58
+ {"anchored executor", "new executor", "approved policy", []string{upgraded}, pinsAnchored},
59
+ {"unanchored executor", "new executor", "approved policy", nil, pinsDiffer},
60
+ {"different anchor", "new executor", "approved policy", []string{ed}, pinsDiffer},
61
+ {"changed policy", "new executor", "wider policy", []string{upgraded}, pinsDiffer},
62
+ {"changed policy only", "approved executor", "wider policy", []string{ed}, pinsDiffer},
63
+ } {
64
+ t.Run(tc.name, func(t *testing.T) {
65
+ target, info := anchoredPackage(t, tc.executor, tc.policy, tc.anchors...)
66
+ if got := packagePins(ctx, target, info, trustAll, ed, pd); got != tc.want {
67
+ t.Fatal("pin state", got)
68
+ }
69
+ })
70
+ }
71
+ }
72
+
73
+ func TestInstallAnchoredReplacesOnlyTheProtectedExecutorWithVerifiedBytes(t *testing.T) {
74
+ ctx := context.Background()
75
+ for _, anchored := range []bool{true, false} {
76
+ t.Run(map[bool]string{true: "anchored", false: "swapped after check"}[anchored], func(t *testing.T) {
77
+ anchor := hashBytes([]byte("new executor"))
78
+ target, info := anchoredPackage(t, "new executor", "approved policy", anchor)
79
+ if !anchored {
80
+ os.WriteFile(filepath.Join(target, "executor"), []byte("package swapped"), 0755)
81
+ }
82
+ runtime := realTestPath(t, t.TempDir())
83
+ os.WriteFile(filepath.Join(runtime, "executor"), []byte("approved executor"), 0700)
84
+ os.WriteFile(filepath.Join(runtime, "policy.json"), []byte("approved policy"), 0600)
85
+ err := installAnchored(ctx, target, info, trustAll, runtime)
86
+ b, _ := os.ReadFile(filepath.Join(runtime, "executor"))
87
+ if anchored && (err != nil || string(b) != "new executor") {
88
+ t.Fatal("anchored executor not installed", err, string(b))
89
+ }
90
+ if !anchored && (err == nil || string(b) != "approved executor") {
91
+ t.Fatal("unanchored executor installed", err, string(b))
92
+ }
93
+ if info, err := os.Stat(filepath.Join(runtime, "executor")); err != nil || info.Mode().Perm() != 0700 {
94
+ t.Fatal("protected executor mode", err)
95
+ }
96
+ entries, _ := os.ReadDir(runtime)
97
+ if len(entries) != 2 {
98
+ t.Fatal("staging copy left in runtime", entries)
99
+ }
100
+ })
101
+ }
102
+ }
103
+
104
+ func TestApprovedPinsHandOverAnAnchoredUpgradeToRootStart(t *testing.T) {
105
+ for _, tc := range []struct {
106
+ name string
107
+ state pinState
108
+ installErr error
109
+ open bool
110
+ installs int
111
+ starts int
112
+ }{
113
+ {"match", pinsMatch, nil, true, 0, 0},
114
+ {"differ", pinsDiffer, nil, false, 0, 0},
115
+ {"anchored", pinsAnchored, nil, false, 1, 1},
116
+ {"install failed", pinsAnchored, errors.New("digest"), false, 1, 0},
117
+ } {
118
+ t.Run(tc.name, func(t *testing.T) {
119
+ installs, starts := 0, 0
120
+ open := approvedPins(tc.state, func() error { installs++; return tc.installErr }, func() error { starts++; return nil }, func(string) {})
121
+ if open != tc.open || installs != tc.installs || starts != tc.starts {
122
+ t.Fatal("handover", open, installs, starts)
123
+ }
124
+ })
125
+ }
126
+ }
@@ -20,7 +20,7 @@ func TestReviewAppPrivRejectsAmbiguousOrError(t *testing.T) {
20
20
  for name, reply := range cases {
21
21
  t.Run(name, func(t *testing.T) {
22
22
  d := &liveDSM{Command: &cmdStub{reply: reply}}
23
- if d.Allow(context.Background(), Subject{Username: "alice"}, "app") == nil {
23
+ if d.Allow(context.Background(), Subject{Username: "alice"}, "app", "") == nil {
24
24
  t.Fatal("unsafe AppPriv response allowed")
25
25
  }
26
26
  })