@synopackageland/cli 0.4.0 → 0.4.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 (438) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/build-spk/generator.js +3 -0
  4. package/dist/build-spk/notices.d.ts +5 -0
  5. package/dist/build-spk/notices.js +60 -0
  6. package/dist/cli.js +9 -2
  7. package/dist/error-registry.js +20 -0
  8. package/dist/init.d.ts +4 -0
  9. package/dist/init.js +20 -12
  10. package/dist/standalone/build.js +3 -1
  11. package/dist/standalone/daemon.d.ts +23 -0
  12. package/dist/standalone/daemon.js +114 -0
  13. package/dist/standalone/dsm-window.d.ts +1 -1
  14. package/dist/standalone/dsm-window.js +50 -10
  15. package/dist/standalone/helper-inventory.d.ts +16 -0
  16. package/dist/standalone/helper-inventory.js +2 -0
  17. package/dist/standalone/helper.d.ts +2 -12
  18. package/dist/standalone/helper.js +8 -7
  19. package/dist/standalone/host-adapter.d.ts +5 -0
  20. package/dist/standalone/host-adapter.js +148 -0
  21. package/dist/standalone/host-platform.d.ts +13 -0
  22. package/dist/standalone/host-platform.js +42 -0
  23. package/dist/standalone/host-types.d.ts +49 -0
  24. package/dist/standalone/host-types.js +1 -0
  25. package/dist/standalone/inspect-helper.d.ts +6 -0
  26. package/dist/standalone/inspect-helper.js +88 -0
  27. package/dist/standalone/inspect-spk.d.ts +2 -0
  28. package/dist/standalone/inspect-spk.js +49 -0
  29. package/dist/standalone/lifecycle-helper.d.ts +2 -0
  30. package/dist/standalone/lifecycle-helper.js +12 -0
  31. package/dist/standalone/lifecycle.d.ts +3 -0
  32. package/dist/standalone/lifecycle.js +53 -0
  33. package/dist/standalone/manifest.d.ts +2 -0
  34. package/dist/standalone/manifest.js +4 -1
  35. package/dist/standalone/reopen-events.d.ts +2 -0
  36. package/dist/standalone/reopen-events.js +28 -0
  37. package/dist/standalone/root-messages.js +9 -0
  38. package/dist/standalone/root-window.d.ts +4 -3
  39. package/dist/standalone/root-window.js +17 -5
  40. package/dist/standalone/spk.d.ts +4 -3
  41. package/dist/standalone/spk.js +20 -33
  42. package/dist/template-paths.d.ts +2 -0
  43. package/dist/template-paths.js +9 -0
  44. package/dist/templates/_daemon/fixture_linux_test.go +15 -0
  45. package/dist/templates/_daemon/fixture_other_test.go +7 -0
  46. package/dist/templates/_daemon/go.mod +3 -0
  47. package/dist/templates/_daemon/main.go +608 -0
  48. package/dist/templates/_daemon/main_test.go +242 -0
  49. package/dist/templates/_daemon/process_linux.go +55 -0
  50. package/dist/templates/_daemon/process_linux_test.go +161 -0
  51. package/dist/templates/_daemon/process_other.go +14 -0
  52. package/dist/templates/_daemon/testdata/child.go +41 -0
  53. package/dist/templates/_shared/GO-LICENSE +27 -0
  54. package/dist/templates/_shared/GO-PATENTS +22 -0
  55. package/dist/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
  56. package/dist/templates/_shared/notice-overrides/index.json +14 -0
  57. package/dist/templates/_shared/notice-overrides/utils-0.4.2-LICENSE +21 -0
  58. package/dist/templates/_shared/notice-overrides/utils-0.5.0-LICENSE +21 -0
  59. package/dist/templates/_shared/third-party-notices.mjs +51 -0
  60. package/dist/templates/native-go/README.md +57 -1
  61. package/dist/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +59 -0
  62. package/dist/templates/native-go/backend/cmd/dsm-readonly-probe/main_linux.go +46 -0
  63. package/dist/templates/native-go/backend/go.mod +4 -0
  64. package/dist/templates/native-go/backend/go.sum +4 -0
  65. package/dist/templates/native-go/backend/internal/api/binary.go +154 -0
  66. package/dist/templates/native-go/backend/internal/api/binary_test.go +165 -0
  67. package/dist/templates/native-go/backend/internal/api/registry.go +14 -4
  68. package/dist/templates/native-go/backend/internal/api/server.go +4 -0
  69. package/dist/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +121 -0
  70. package/dist/templates/native-go/backend/internal/app/nas_refusal_test.go +46 -0
  71. package/dist/templates/native-go/backend/internal/app/routes.go +11 -0
  72. package/dist/templates/native-go/backend/internal/app/routes_test.go +10 -5
  73. package/dist/templates/native-go/backend/internal/dsmprobe/collector_linux.go +335 -0
  74. package/dist/templates/native-go/backend/internal/dsmprobe/collector_linux_test.go +41 -0
  75. package/dist/templates/native-go/backend/internal/dsmprobe/protocol.go +179 -0
  76. package/dist/templates/native-go/backend/internal/dsmprobe/protocol_test.go +29 -0
  77. package/dist/templates/native-go/backend/internal/helper/cohort.go +393 -0
  78. package/dist/templates/native-go/backend/internal/helper/cohort_publication.go +18 -0
  79. package/dist/templates/native-go/backend/internal/helper/cohort_publication_test.go +105 -0
  80. package/dist/templates/native-go/backend/internal/helper/cohort_test.go +372 -0
  81. package/dist/templates/native-go/backend/internal/helper/control.go +226 -21
  82. package/dist/templates/native-go/backend/internal/helper/control_test.go +10 -2
  83. package/dist/templates/native-go/backend/internal/helper/data_contract.go +242 -0
  84. package/dist/templates/native-go/backend/internal/helper/data_contract_test.go +51 -0
  85. package/dist/templates/native-go/backend/internal/helper/data_decode.go +184 -0
  86. package/dist/templates/native-go/backend/internal/helper/data_decode_pointer_test.go +30 -0
  87. package/dist/templates/native-go/backend/internal/helper/data_protocol.go +416 -0
  88. package/dist/templates/native-go/backend/internal/helper/data_protocol_test.go +449 -0
  89. package/dist/templates/native-go/backend/internal/helper/dsm_acl_linux.go +139 -0
  90. package/dist/templates/native-go/backend/internal/helper/dsm_acl_linux_test.go +121 -0
  91. package/dist/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux.go +95 -0
  92. package/dist/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux_test.go +56 -0
  93. package/dist/templates/native-go/backend/internal/helper/dsm_bridge_linux.go +144 -0
  94. package/dist/templates/native-go/backend/internal/helper/dsm_bridge_linux_test.go +89 -0
  95. package/dist/templates/native-go/backend/internal/helper/dsm_home_linux.go +107 -0
  96. package/dist/templates/native-go/backend/internal/helper/dsm_home_linux_test.go +82 -0
  97. package/dist/templates/native-go/backend/internal/helper/dsm_probe_transport_linux.go +151 -0
  98. package/dist/templates/native-go/backend/internal/helper/dsm_probe_transport_linux_test.go +66 -0
  99. package/dist/templates/native-go/backend/internal/helper/grant_authority.go +516 -0
  100. package/dist/templates/native-go/backend/internal/helper/grant_authority_contract.go +88 -0
  101. package/dist/templates/native-go/backend/internal/helper/grant_authority_test.go +510 -0
  102. package/dist/templates/native-go/backend/internal/helper/grant_cohort.go +389 -0
  103. package/dist/templates/native-go/backend/internal/helper/grant_cohort_test.go +239 -0
  104. package/dist/templates/native-go/backend/internal/helper/grant_delivery.go +49 -0
  105. package/dist/templates/native-go/backend/internal/helper/grant_delivery_methods.go +273 -0
  106. package/dist/templates/native-go/backend/internal/helper/grant_delivery_test.go +322 -0
  107. package/dist/templates/native-go/backend/internal/helper/grant_operation_contract.go +47 -0
  108. package/dist/templates/native-go/backend/internal/helper/grant_readonly_test.go +180 -0
  109. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux.go +415 -0
  110. package/dist/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +468 -0
  111. package/dist/templates/native-go/backend/internal/helper/grant_rpc.go +147 -0
  112. package/dist/templates/native-go/backend/internal/helper/grant_rpc_test.go +51 -0
  113. package/dist/templates/native-go/backend/internal/helper/grant_snapshot.go +75 -0
  114. package/dist/templates/native-go/backend/internal/helper/grant_supervisor_linux.go +134 -0
  115. package/dist/templates/native-go/backend/internal/helper/grant_supervisor_linux_test.go +254 -0
  116. package/dist/templates/native-go/backend/internal/helper/lease.go +112 -0
  117. package/dist/templates/native-go/backend/internal/helper/lease_linux.go +44 -0
  118. package/dist/templates/native-go/backend/internal/helper/lease_other.go +8 -0
  119. package/dist/templates/native-go/backend/internal/helper/lifecycle.go +234 -0
  120. package/dist/templates/native-go/backend/internal/helper/lifecycle_test.go +473 -0
  121. package/dist/templates/native-go/backend/internal/helper/managed_pilot.go +284 -0
  122. package/dist/templates/native-go/backend/internal/helper/managed_pilot_repository_linux.go +74 -0
  123. package/dist/templates/native-go/backend/internal/helper/managed_pilot_repository_linux_test.go +40 -0
  124. package/dist/templates/native-go/backend/internal/helper/managed_pilot_test.go +210 -0
  125. package/dist/templates/native-go/backend/internal/helper/nas_shipped_refusal_linux_test.go +97 -0
  126. package/dist/templates/native-go/backend/internal/helper/native_discovery.go +79 -0
  127. package/dist/templates/native-go/backend/internal/helper/native_identity.go +89 -0
  128. package/dist/templates/native-go/backend/internal/helper/native_provider.go +159 -0
  129. package/dist/templates/native-go/backend/internal/helper/native_provider_test.go +421 -0
  130. package/dist/templates/native-go/backend/internal/helper/observation.go +204 -0
  131. package/dist/templates/native-go/backend/internal/helper/observation_health_test.go +115 -0
  132. package/dist/templates/native-go/backend/internal/helper/observation_reload_budget_test.go +117 -0
  133. package/dist/templates/native-go/backend/internal/helper/observation_test.go +196 -0
  134. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic.go +109 -0
  135. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux.go +76 -0
  136. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +124 -0
  137. package/dist/templates/native-go/backend/internal/helper/observer_diagnostic_test.go +98 -0
  138. package/dist/templates/native-go/backend/internal/helper/operation_bootstrap_linux.go +193 -0
  139. package/dist/templates/native-go/backend/internal/helper/operation_credentials_linux.go +56 -0
  140. package/dist/templates/native-go/backend/internal/helper/operation_linux.go +480 -0
  141. package/dist/templates/native-go/backend/internal/helper/operation_linux_test.go +528 -0
  142. package/dist/templates/native-go/backend/internal/helper/process_linux.go +11 -1
  143. package/dist/templates/native-go/backend/internal/helper/publication_test.go +178 -0
  144. package/dist/templates/native-go/backend/internal/helper/read_stream_cohort_linux_test.go +156 -0
  145. package/dist/templates/native-go/backend/internal/helper/read_transfer.go +40 -0
  146. package/dist/templates/native-go/backend/internal/helper/read_transfer_linux.go +109 -0
  147. package/dist/templates/native-go/backend/internal/helper/read_transfer_linux_test.go +118 -0
  148. package/dist/templates/native-go/backend/internal/helper/read_transfer_test.go +177 -0
  149. package/dist/templates/native-go/backend/internal/helper/readonly.go +105 -0
  150. package/dist/templates/native-go/backend/internal/helper/readonly_admission.go +85 -0
  151. package/dist/templates/native-go/backend/internal/helper/readonly_cohort_linux_test.go +253 -0
  152. package/dist/templates/native-go/backend/internal/helper/readonly_linux_test.go +378 -0
  153. package/dist/templates/native-go/backend/internal/helper/readonly_mount_linux.go +65 -0
  154. package/dist/templates/native-go/backend/internal/helper/readonly_mount_proxy_linux.go +113 -0
  155. package/dist/templates/native-go/backend/internal/helper/readonly_operations_linux.go +168 -0
  156. package/dist/templates/native-go/backend/internal/helper/readonly_resolver_linux.go +241 -0
  157. package/dist/templates/native-go/backend/internal/helper/readonly_test.go +40 -0
  158. package/dist/templates/native-go/backend/internal/helper/relaxed_identity.go +252 -0
  159. package/dist/templates/native-go/backend/internal/helper/relaxed_identity_contract.go +105 -0
  160. package/dist/templates/native-go/backend/internal/helper/relaxed_identity_test.go +406 -0
  161. package/dist/templates/native-go/backend/internal/helper/relaxed_invalidation.go +200 -0
  162. package/dist/templates/native-go/backend/internal/helper/repair.go +132 -0
  163. package/dist/templates/native-go/backend/internal/helper/repair_test.go +271 -0
  164. package/dist/templates/native-go/backend/internal/helper/s1r_actor_acl_linux_test.go +303 -0
  165. package/dist/templates/native-go/backend/internal/helper/s1r_actor_fixture_linux_test.go +184 -0
  166. package/dist/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +231 -0
  167. package/dist/templates/native-go/backend/internal/helper/s1r_fixture_contract_linux_test.go +18 -0
  168. package/dist/templates/native-go/backend/internal/helper/server_linux.go +44 -3
  169. package/dist/templates/native-go/backend/internal/helper/status.go +74 -11
  170. package/dist/templates/native-go/backend/internal/helper/status_test.go +83 -0
  171. package/dist/templates/native-go/backend/internal/helper/supervision.go +28 -5
  172. package/dist/templates/native-go/backend/internal/helper/supervisor_frame.go +76 -0
  173. package/dist/templates/native-go/backend/internal/helper/supervisor_frame_linux_test.go +69 -0
  174. package/dist/templates/native-go/backend/internal/helper/supervisor_frame_test.go +107 -0
  175. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +187 -16
  176. package/dist/templates/native-go/backend/internal/helper/supervisor_linux_test.go +618 -7
  177. package/dist/templates/native-go/backend/internal/helper/supervisor_socket_eof_test.go +74 -0
  178. package/dist/templates/native-go/backend/internal/helper/supervisor_socket_test.go +45 -0
  179. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/create.json +23 -0
  180. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/frames.json +67 -0
  181. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/grant-store.json +52 -0
  182. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/intent.json +20 -0
  183. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/list.json +20 -0
  184. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/publish.json +20 -0
  185. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/read.json +22 -0
  186. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/stat.json +22 -0
  187. package/dist/templates/native-go/backend/internal/helper/testdata/protocol2/write-stream.json +22 -0
  188. package/dist/templates/native-go/backend/internal/helper/unit_connection.go +75 -0
  189. package/dist/templates/native-go/backend/internal/helper/unit_connection_linux_test.go +135 -0
  190. package/dist/templates/native-go/backend/internal/helper/unit_connection_test.go +133 -0
  191. package/dist/templates/native-go/backend/internal/helper/unit_frame_test.go +32 -0
  192. package/dist/templates/native-go/backend/internal/helper/unit_linux.go +364 -0
  193. package/dist/templates/native-go/backend/internal/helper/unit_linux_test.go +46 -0
  194. package/dist/templates/native-go/backend/internal/helper/unit_mechanisms_linux_test.go +217 -0
  195. package/dist/templates/native-go/backend/internal/helper/unit_padding_linux_test.go +178 -0
  196. package/dist/templates/native-go/backend/internal/helper/unit_query_linux.go +111 -0
  197. package/dist/templates/native-go/backend/internal/helper/unit_reload_linux_test.go +372 -0
  198. package/dist/templates/native-go/backend/internal/helper/unit_reload_sequence_linux_test.go +232 -0
  199. package/dist/templates/native-go/backend/internal/helper/write.go +77 -0
  200. package/dist/templates/native-go/backend/internal/helper/write_admission.go +260 -0
  201. package/dist/templates/native-go/backend/internal/helper/write_admission_test.go +135 -0
  202. package/dist/templates/native-go/backend/internal/helper/write_cohort_linux_test.go +218 -0
  203. package/dist/templates/native-go/backend/internal/helper/write_files_linux.go +202 -0
  204. package/dist/templates/native-go/backend/internal/helper/write_files_linux_test.go +199 -0
  205. package/dist/templates/native-go/backend/internal/helper/write_intent_linux.go +116 -0
  206. package/dist/templates/native-go/backend/internal/helper/write_intent_linux_test.go +74 -0
  207. package/dist/templates/native-go/backend/internal/helper/write_operation_linux.go +245 -0
  208. package/dist/templates/native-go/backend/internal/helper/write_test.go +53 -0
  209. package/dist/templates/native-go/ui/app.js +8 -1
  210. package/dist/templates/native-go-better-auth/node/build.mjs +2 -0
  211. package/dist/templates/native-go-vue/README.md +115 -1
  212. package/dist/templates/native-go-vue/frontend/DESIGN.md +1 -1
  213. package/dist/templates/native-go-vue/frontend/package-lock.json +132 -229
  214. package/dist/templates/native-go-vue/frontend/package.json +1 -1
  215. package/dist/templates/native-go-vue/frontend/src/App.vue +33 -6
  216. package/dist/templates/native-go-vue/frontend/src/context.ts +41 -2
  217. package/dist/templates/native-go-vue/frontend/src/main.ts +4 -1
  218. package/dist/templates/native-go-vue/frontend/src/nas/NasGrantSettings.vue +74 -0
  219. package/dist/templates/native-go-vue/frontend/src/nas/NasPathPicker.vue +106 -0
  220. package/dist/templates/native-go-vue/frontend/src/nas/NasUnavailable.vue +20 -0
  221. package/dist/templates/native-go-vue/frontend/src/nas/i18n/de.json +74 -0
  222. package/dist/templates/native-go-vue/frontend/src/nas/i18n/en.json +74 -0
  223. package/dist/templates/native-go-vue/frontend/src/nas/i18n/es.json +74 -0
  224. package/dist/templates/native-go-vue/frontend/src/nas/i18n/fr.json +74 -0
  225. package/dist/templates/native-go-vue/frontend/src/nas/i18n/it.json +74 -0
  226. package/dist/templates/native-go-vue/frontend/src/nas/i18n/ja.json +74 -0
  227. package/dist/templates/native-go-vue/frontend/src/nas/i18n/ko.json +74 -0
  228. package/dist/templates/native-go-vue/frontend/src/nas/i18n/zh-CN.json +74 -0
  229. package/dist/templates/native-go-vue/frontend/src/nas/i18n/zh-TW.json +74 -0
  230. package/dist/templates/native-go-vue/frontend/src/nas/i18n.ts +38 -0
  231. package/dist/templates/native-go-vue/frontend/src/nas/mock-provider.ts +119 -0
  232. package/dist/templates/native-go-vue/frontend/src/nas/provider.ts +59 -0
  233. package/dist/templates/native-go-vue/frontend/src/nas/use-request.ts +27 -0
  234. package/dist/templates/native-go-vue/frontend/src/style.css +17 -0
  235. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +44 -2
  236. package/dist/templates/native-go-vue/frontend/test/nas-provider.test.ts +81 -0
  237. package/dist/templates/native-go-vue/frontend/test/nas-request.test.ts +21 -0
  238. package/dist/templates/native-go-vue/frontend/test/nas-ui.test.ts +261 -0
  239. package/dist/templates/native-go-vue/frontend/tsconfig.json +1 -1
  240. package/dist/templates/native-go-vue/frontend/vite.config.ts +6 -4
  241. package/package.json +3 -2
  242. package/templates/_daemon/fixture_linux_test.go +15 -0
  243. package/templates/_daemon/fixture_other_test.go +7 -0
  244. package/templates/_daemon/go.mod +3 -0
  245. package/templates/_daemon/main.go +608 -0
  246. package/templates/_daemon/main_test.go +242 -0
  247. package/templates/_daemon/process_linux.go +55 -0
  248. package/templates/_daemon/process_linux_test.go +161 -0
  249. package/templates/_daemon/process_other.go +14 -0
  250. package/templates/_daemon/testdata/child.go +41 -0
  251. package/templates/_shared/GO-LICENSE +27 -0
  252. package/templates/_shared/GO-PATENTS +22 -0
  253. package/templates/_shared/LICENSES/TEMPLATE.txt +21 -0
  254. package/templates/_shared/notice-overrides/index.json +14 -0
  255. package/templates/_shared/notice-overrides/utils-0.4.2-LICENSE +21 -0
  256. package/templates/_shared/notice-overrides/utils-0.5.0-LICENSE +21 -0
  257. package/templates/_shared/third-party-notices.mjs +51 -0
  258. package/templates/native-go/README.md +57 -1
  259. package/templates/native-go/backend/THIRD_PARTY_NOTICES.txt +59 -0
  260. package/templates/native-go/backend/cmd/dsm-readonly-probe/main_linux.go +46 -0
  261. package/templates/native-go/backend/go.mod +4 -0
  262. package/templates/native-go/backend/go.sum +4 -0
  263. package/templates/native-go/backend/internal/api/binary.go +154 -0
  264. package/templates/native-go/backend/internal/api/binary_test.go +165 -0
  265. package/templates/native-go/backend/internal/api/registry.go +14 -4
  266. package/templates/native-go/backend/internal/api/server.go +4 -0
  267. package/templates/native-go/backend/internal/app/nas_cgi_artifact_test.go +121 -0
  268. package/templates/native-go/backend/internal/app/nas_refusal_test.go +46 -0
  269. package/templates/native-go/backend/internal/app/routes.go +11 -0
  270. package/templates/native-go/backend/internal/app/routes_test.go +10 -5
  271. package/templates/native-go/backend/internal/dsmprobe/collector_linux.go +335 -0
  272. package/templates/native-go/backend/internal/dsmprobe/collector_linux_test.go +41 -0
  273. package/templates/native-go/backend/internal/dsmprobe/protocol.go +179 -0
  274. package/templates/native-go/backend/internal/dsmprobe/protocol_test.go +29 -0
  275. package/templates/native-go/backend/internal/helper/cohort.go +393 -0
  276. package/templates/native-go/backend/internal/helper/cohort_publication.go +18 -0
  277. package/templates/native-go/backend/internal/helper/cohort_publication_test.go +105 -0
  278. package/templates/native-go/backend/internal/helper/cohort_test.go +372 -0
  279. package/templates/native-go/backend/internal/helper/control.go +226 -21
  280. package/templates/native-go/backend/internal/helper/control_test.go +10 -2
  281. package/templates/native-go/backend/internal/helper/data_contract.go +242 -0
  282. package/templates/native-go/backend/internal/helper/data_contract_test.go +51 -0
  283. package/templates/native-go/backend/internal/helper/data_decode.go +184 -0
  284. package/templates/native-go/backend/internal/helper/data_decode_pointer_test.go +30 -0
  285. package/templates/native-go/backend/internal/helper/data_protocol.go +416 -0
  286. package/templates/native-go/backend/internal/helper/data_protocol_test.go +449 -0
  287. package/templates/native-go/backend/internal/helper/dsm_acl_linux.go +139 -0
  288. package/templates/native-go/backend/internal/helper/dsm_acl_linux_test.go +121 -0
  289. package/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux.go +95 -0
  290. package/templates/native-go/backend/internal/helper/dsm_acl_syscall_linux_test.go +56 -0
  291. package/templates/native-go/backend/internal/helper/dsm_bridge_linux.go +144 -0
  292. package/templates/native-go/backend/internal/helper/dsm_bridge_linux_test.go +89 -0
  293. package/templates/native-go/backend/internal/helper/dsm_home_linux.go +107 -0
  294. package/templates/native-go/backend/internal/helper/dsm_home_linux_test.go +82 -0
  295. package/templates/native-go/backend/internal/helper/dsm_probe_transport_linux.go +151 -0
  296. package/templates/native-go/backend/internal/helper/dsm_probe_transport_linux_test.go +66 -0
  297. package/templates/native-go/backend/internal/helper/grant_authority.go +516 -0
  298. package/templates/native-go/backend/internal/helper/grant_authority_contract.go +88 -0
  299. package/templates/native-go/backend/internal/helper/grant_authority_test.go +510 -0
  300. package/templates/native-go/backend/internal/helper/grant_cohort.go +389 -0
  301. package/templates/native-go/backend/internal/helper/grant_cohort_test.go +239 -0
  302. package/templates/native-go/backend/internal/helper/grant_delivery.go +49 -0
  303. package/templates/native-go/backend/internal/helper/grant_delivery_methods.go +273 -0
  304. package/templates/native-go/backend/internal/helper/grant_delivery_test.go +322 -0
  305. package/templates/native-go/backend/internal/helper/grant_operation_contract.go +47 -0
  306. package/templates/native-go/backend/internal/helper/grant_readonly_test.go +180 -0
  307. package/templates/native-go/backend/internal/helper/grant_repository_linux.go +415 -0
  308. package/templates/native-go/backend/internal/helper/grant_repository_linux_test.go +468 -0
  309. package/templates/native-go/backend/internal/helper/grant_rpc.go +147 -0
  310. package/templates/native-go/backend/internal/helper/grant_rpc_test.go +51 -0
  311. package/templates/native-go/backend/internal/helper/grant_snapshot.go +75 -0
  312. package/templates/native-go/backend/internal/helper/grant_supervisor_linux.go +134 -0
  313. package/templates/native-go/backend/internal/helper/grant_supervisor_linux_test.go +254 -0
  314. package/templates/native-go/backend/internal/helper/lease.go +112 -0
  315. package/templates/native-go/backend/internal/helper/lease_linux.go +44 -0
  316. package/templates/native-go/backend/internal/helper/lease_other.go +8 -0
  317. package/templates/native-go/backend/internal/helper/lifecycle.go +234 -0
  318. package/templates/native-go/backend/internal/helper/lifecycle_test.go +473 -0
  319. package/templates/native-go/backend/internal/helper/managed_pilot.go +284 -0
  320. package/templates/native-go/backend/internal/helper/managed_pilot_repository_linux.go +74 -0
  321. package/templates/native-go/backend/internal/helper/managed_pilot_repository_linux_test.go +40 -0
  322. package/templates/native-go/backend/internal/helper/managed_pilot_test.go +210 -0
  323. package/templates/native-go/backend/internal/helper/nas_shipped_refusal_linux_test.go +97 -0
  324. package/templates/native-go/backend/internal/helper/native_discovery.go +79 -0
  325. package/templates/native-go/backend/internal/helper/native_identity.go +89 -0
  326. package/templates/native-go/backend/internal/helper/native_provider.go +159 -0
  327. package/templates/native-go/backend/internal/helper/native_provider_test.go +421 -0
  328. package/templates/native-go/backend/internal/helper/observation.go +204 -0
  329. package/templates/native-go/backend/internal/helper/observation_health_test.go +115 -0
  330. package/templates/native-go/backend/internal/helper/observation_reload_budget_test.go +117 -0
  331. package/templates/native-go/backend/internal/helper/observation_test.go +196 -0
  332. package/templates/native-go/backend/internal/helper/observer_diagnostic.go +109 -0
  333. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux.go +76 -0
  334. package/templates/native-go/backend/internal/helper/observer_diagnostic_linux_test.go +124 -0
  335. package/templates/native-go/backend/internal/helper/observer_diagnostic_test.go +98 -0
  336. package/templates/native-go/backend/internal/helper/operation_bootstrap_linux.go +193 -0
  337. package/templates/native-go/backend/internal/helper/operation_credentials_linux.go +56 -0
  338. package/templates/native-go/backend/internal/helper/operation_linux.go +480 -0
  339. package/templates/native-go/backend/internal/helper/operation_linux_test.go +528 -0
  340. package/templates/native-go/backend/internal/helper/process_linux.go +11 -1
  341. package/templates/native-go/backend/internal/helper/publication_test.go +178 -0
  342. package/templates/native-go/backend/internal/helper/read_stream_cohort_linux_test.go +156 -0
  343. package/templates/native-go/backend/internal/helper/read_transfer.go +40 -0
  344. package/templates/native-go/backend/internal/helper/read_transfer_linux.go +109 -0
  345. package/templates/native-go/backend/internal/helper/read_transfer_linux_test.go +118 -0
  346. package/templates/native-go/backend/internal/helper/read_transfer_test.go +177 -0
  347. package/templates/native-go/backend/internal/helper/readonly.go +105 -0
  348. package/templates/native-go/backend/internal/helper/readonly_admission.go +85 -0
  349. package/templates/native-go/backend/internal/helper/readonly_cohort_linux_test.go +253 -0
  350. package/templates/native-go/backend/internal/helper/readonly_linux_test.go +378 -0
  351. package/templates/native-go/backend/internal/helper/readonly_mount_linux.go +65 -0
  352. package/templates/native-go/backend/internal/helper/readonly_mount_proxy_linux.go +113 -0
  353. package/templates/native-go/backend/internal/helper/readonly_operations_linux.go +168 -0
  354. package/templates/native-go/backend/internal/helper/readonly_resolver_linux.go +241 -0
  355. package/templates/native-go/backend/internal/helper/readonly_test.go +40 -0
  356. package/templates/native-go/backend/internal/helper/relaxed_identity.go +252 -0
  357. package/templates/native-go/backend/internal/helper/relaxed_identity_contract.go +105 -0
  358. package/templates/native-go/backend/internal/helper/relaxed_identity_test.go +406 -0
  359. package/templates/native-go/backend/internal/helper/relaxed_invalidation.go +200 -0
  360. package/templates/native-go/backend/internal/helper/repair.go +132 -0
  361. package/templates/native-go/backend/internal/helper/repair_test.go +271 -0
  362. package/templates/native-go/backend/internal/helper/s1r_actor_acl_linux_test.go +303 -0
  363. package/templates/native-go/backend/internal/helper/s1r_actor_fixture_linux_test.go +184 -0
  364. package/templates/native-go/backend/internal/helper/s1r_actor_races_linux_test.go +231 -0
  365. package/templates/native-go/backend/internal/helper/s1r_fixture_contract_linux_test.go +18 -0
  366. package/templates/native-go/backend/internal/helper/server_linux.go +44 -3
  367. package/templates/native-go/backend/internal/helper/status.go +74 -11
  368. package/templates/native-go/backend/internal/helper/status_test.go +83 -0
  369. package/templates/native-go/backend/internal/helper/supervision.go +28 -5
  370. package/templates/native-go/backend/internal/helper/supervisor_frame.go +76 -0
  371. package/templates/native-go/backend/internal/helper/supervisor_frame_linux_test.go +69 -0
  372. package/templates/native-go/backend/internal/helper/supervisor_frame_test.go +107 -0
  373. package/templates/native-go/backend/internal/helper/supervisor_linux.go +187 -16
  374. package/templates/native-go/backend/internal/helper/supervisor_linux_test.go +618 -7
  375. package/templates/native-go/backend/internal/helper/supervisor_socket_eof_test.go +74 -0
  376. package/templates/native-go/backend/internal/helper/supervisor_socket_test.go +45 -0
  377. package/templates/native-go/backend/internal/helper/testdata/protocol2/create.json +23 -0
  378. package/templates/native-go/backend/internal/helper/testdata/protocol2/frames.json +67 -0
  379. package/templates/native-go/backend/internal/helper/testdata/protocol2/grant-store.json +52 -0
  380. package/templates/native-go/backend/internal/helper/testdata/protocol2/intent.json +20 -0
  381. package/templates/native-go/backend/internal/helper/testdata/protocol2/list.json +20 -0
  382. package/templates/native-go/backend/internal/helper/testdata/protocol2/publish.json +20 -0
  383. package/templates/native-go/backend/internal/helper/testdata/protocol2/read.json +22 -0
  384. package/templates/native-go/backend/internal/helper/testdata/protocol2/stat.json +22 -0
  385. package/templates/native-go/backend/internal/helper/testdata/protocol2/write-stream.json +22 -0
  386. package/templates/native-go/backend/internal/helper/unit_connection.go +75 -0
  387. package/templates/native-go/backend/internal/helper/unit_connection_linux_test.go +135 -0
  388. package/templates/native-go/backend/internal/helper/unit_connection_test.go +133 -0
  389. package/templates/native-go/backend/internal/helper/unit_frame_test.go +32 -0
  390. package/templates/native-go/backend/internal/helper/unit_linux.go +364 -0
  391. package/templates/native-go/backend/internal/helper/unit_linux_test.go +46 -0
  392. package/templates/native-go/backend/internal/helper/unit_mechanisms_linux_test.go +217 -0
  393. package/templates/native-go/backend/internal/helper/unit_padding_linux_test.go +178 -0
  394. package/templates/native-go/backend/internal/helper/unit_query_linux.go +111 -0
  395. package/templates/native-go/backend/internal/helper/unit_reload_linux_test.go +372 -0
  396. package/templates/native-go/backend/internal/helper/unit_reload_sequence_linux_test.go +232 -0
  397. package/templates/native-go/backend/internal/helper/write.go +77 -0
  398. package/templates/native-go/backend/internal/helper/write_admission.go +260 -0
  399. package/templates/native-go/backend/internal/helper/write_admission_test.go +135 -0
  400. package/templates/native-go/backend/internal/helper/write_cohort_linux_test.go +218 -0
  401. package/templates/native-go/backend/internal/helper/write_files_linux.go +202 -0
  402. package/templates/native-go/backend/internal/helper/write_files_linux_test.go +199 -0
  403. package/templates/native-go/backend/internal/helper/write_intent_linux.go +116 -0
  404. package/templates/native-go/backend/internal/helper/write_intent_linux_test.go +74 -0
  405. package/templates/native-go/backend/internal/helper/write_operation_linux.go +245 -0
  406. package/templates/native-go/backend/internal/helper/write_test.go +53 -0
  407. package/templates/native-go/ui/app.js +8 -1
  408. package/templates/native-go-better-auth/node/build.mjs +2 -0
  409. package/templates/native-go-vue/README.md +115 -1
  410. package/templates/native-go-vue/frontend/DESIGN.md +1 -1
  411. package/templates/native-go-vue/frontend/package-lock.json +132 -229
  412. package/templates/native-go-vue/frontend/package.json +1 -1
  413. package/templates/native-go-vue/frontend/src/App.vue +33 -6
  414. package/templates/native-go-vue/frontend/src/context.ts +41 -2
  415. package/templates/native-go-vue/frontend/src/main.ts +4 -1
  416. package/templates/native-go-vue/frontend/src/nas/NasGrantSettings.vue +74 -0
  417. package/templates/native-go-vue/frontend/src/nas/NasPathPicker.vue +106 -0
  418. package/templates/native-go-vue/frontend/src/nas/NasUnavailable.vue +20 -0
  419. package/templates/native-go-vue/frontend/src/nas/i18n/de.json +74 -0
  420. package/templates/native-go-vue/frontend/src/nas/i18n/en.json +74 -0
  421. package/templates/native-go-vue/frontend/src/nas/i18n/es.json +74 -0
  422. package/templates/native-go-vue/frontend/src/nas/i18n/fr.json +74 -0
  423. package/templates/native-go-vue/frontend/src/nas/i18n/it.json +74 -0
  424. package/templates/native-go-vue/frontend/src/nas/i18n/ja.json +74 -0
  425. package/templates/native-go-vue/frontend/src/nas/i18n/ko.json +74 -0
  426. package/templates/native-go-vue/frontend/src/nas/i18n/zh-CN.json +74 -0
  427. package/templates/native-go-vue/frontend/src/nas/i18n/zh-TW.json +74 -0
  428. package/templates/native-go-vue/frontend/src/nas/i18n.ts +38 -0
  429. package/templates/native-go-vue/frontend/src/nas/mock-provider.ts +119 -0
  430. package/templates/native-go-vue/frontend/src/nas/provider.ts +59 -0
  431. package/templates/native-go-vue/frontend/src/nas/use-request.ts +27 -0
  432. package/templates/native-go-vue/frontend/src/style.css +17 -0
  433. package/templates/native-go-vue/frontend/test/apps.test.ts +44 -2
  434. package/templates/native-go-vue/frontend/test/nas-provider.test.ts +81 -0
  435. package/templates/native-go-vue/frontend/test/nas-request.test.ts +21 -0
  436. package/templates/native-go-vue/frontend/test/nas-ui.test.ts +261 -0
  437. package/templates/native-go-vue/frontend/tsconfig.json +1 -1
  438. package/templates/native-go-vue/frontend/vite.config.ts +6 -4
@@ -2,6 +2,7 @@ package helper
2
2
 
3
3
  import (
4
4
  "context"
5
+ "encoding/json"
5
6
  "errors"
6
7
  "net"
7
8
  "os"
@@ -25,18 +26,43 @@ func linuxFixture(t *testing.T) LinuxProcesses {
25
26
  if os.Geteuid() != 0 {
26
27
  t.Fatal("VM fixture requires root")
27
28
  }
29
+ traces, _ := filepath.Glob("/tmp/m1h-trace-*")
30
+ for _, path := range traces {
31
+ if err := os.Remove(path); err != nil {
32
+ t.Fatal(err)
33
+ }
34
+ }
35
+ if t.Name() == "TestLinuxHelperSelfExitIsReapedWithoutSignallingReusedPID" {
36
+ source = "/helper-self-exit"
37
+ }
38
+ if t.Name() == "TestLinuxControllerWaitsForRealCompletionPublisher" {
39
+ source = "/helper-held-completion"
40
+ }
28
41
  digest, err := executableDigest(source)
29
42
  if err != nil {
30
43
  t.Fatal(err)
31
44
  }
32
45
  i := Inventory{Package: "root", Version: "1.0.0-0001", Protocol: 1, PayloadDigest: digest, RegistryDigest: strings.Repeat("b", 64)}
33
46
  c := NewClient(i)
47
+
34
48
  for _, dir := range []string{c.StateDir, c.RunDir} {
35
49
  if err := os.Mkdir(dir, 0700); err != nil {
36
50
  t.Fatal(err)
37
51
  }
38
52
  t.Cleanup(func() { os.RemoveAll(dir) })
39
53
  }
54
+ t.Cleanup(func() {
55
+ r, e := readRecord(c.StateDir, 0)
56
+ b, _ := json.Marshal(r)
57
+ t.Logf("VM final lifecycle=%s readError=%v failed=%t", b, e, t.Failed())
58
+ if t.Failed() {
59
+ traces, _ := filepath.Glob("/tmp/m1h-trace-*")
60
+ for _, path := range traces {
61
+ b, _ := os.ReadFile(path)
62
+ t.Logf("VM trace %s: %s", path, b)
63
+ }
64
+ }
65
+ })
40
66
  exe := filepath.Join(c.StateDir, "payload-"+digest)
41
67
  b, err := os.ReadFile(source)
42
68
  if err != nil {
@@ -45,11 +71,26 @@ func linuxFixture(t *testing.T) LinuxProcesses {
45
71
  if err := os.WriteFile(exe, b, 0700); err != nil {
46
72
  t.Fatal(err)
47
73
  }
74
+ vmUnit(t, "start")
48
75
  return LinuxProcesses{Client: c, Binary: exe}
49
76
  }
50
77
  func startVMHelper(t *testing.T, p LinuxProcesses) Process {
51
78
  t.Helper()
52
- ctl := Controller{Client: p.Client, Processes: p}
79
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
80
+ t.Cleanup(func() {
81
+ r, e := readRecord(p.StateDir, 0)
82
+ b, _ := json.Marshal(r)
83
+ t.Logf("VM pre-cleanup lifecycle=%s readError=%v failed=%t", b, e, t.Failed())
84
+ err := ctl.Control(context.Background(), "disable")
85
+ t.Logf("VM cleanup disable=%v", err)
86
+ if t.Failed() {
87
+ traces, _ := filepath.Glob("/tmp/m1h-trace-*")
88
+ for _, path := range traces {
89
+ b, _ := os.ReadFile(path)
90
+ t.Logf("VM trace %s: %s", path, b)
91
+ }
92
+ }
93
+ })
53
94
  if err := ctl.Control(context.Background(), "enable"); err != nil {
54
95
  t.Fatal(err)
55
96
  }
@@ -57,7 +98,6 @@ func startVMHelper(t *testing.T, p LinuxProcesses) Process {
57
98
  if err != nil {
58
99
  t.Fatal(err)
59
100
  }
60
- t.Cleanup(func() { ctl.Control(context.Background(), "disable") })
61
101
  return record
62
102
  }
63
103
  func supervisedPID(t *testing.T, pid int) int {
@@ -105,7 +145,7 @@ func TestLinuxActivationAlwaysUsesSupervisorAndNormalStop(t *testing.T) {
105
145
  if p.Status(context.Background()).State != "ready" {
106
146
  t.Fatal("missing live handshake")
107
147
  }
108
- if err := (Controller{Client: p.Client, Processes: p}).Control(context.Background(), "disable"); err != nil {
148
+ if err := (Controller{Client: p.Client, Processes: p, Observe: observeLinux}).Control(context.Background(), "disable"); err != nil {
109
149
  t.Fatal(err)
110
150
  }
111
151
  waitPIDExit(t, child)
@@ -142,7 +182,7 @@ func TestLinuxHelperSelfExitIsReapedWithoutSignallingReusedPID(t *testing.T) {
142
182
  }
143
183
  func TestLinuxSupervisorDeathKillsHelperAndPreservesFailedCleanup(t *testing.T) {
144
184
  p := linuxFixture(t)
145
- record(t, p.Client, Record{Inventory: p.Expected, Enabled: true})
185
+ record(t, p.Client, Record{Inventory: p.Expected, Enabled: true, Lifecycle: vmLifecycle(t, p)})
146
186
  // Keep the supervisor as our own unreaped child; only its parent signals it.
147
187
  cmd := exec.Command(p.Binary, "supervise")
148
188
  if err := cmd.Start(); err != nil {
@@ -166,7 +206,7 @@ func TestLinuxSupervisorDeathKillsHelperAndPreservesFailedCleanup(t *testing.T)
166
206
  }
167
207
  waitPIDExit(t, child)
168
208
  waitPIDExit(t, proc.PID)
169
- ctl := Controller{Client: p.Client, Processes: p}
209
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
170
210
  if ctl.Control(context.Background(), "teardown") == nil {
171
211
  t.Fatal("lost supervisor falsely cleaned")
172
212
  }
@@ -197,7 +237,7 @@ func TestLinuxUnsupervisedRecordAndDirectServeRefuse(t *testing.T) {
197
237
  }
198
238
  // Remove stopped sockets before testing the retired action, so a bind
199
239
  // conflict cannot masquerade as refusal of unsupervised startup.
200
- if err := (Controller{Client: p.Client, Processes: p}).Control(context.Background(), "teardown"); err != nil {
240
+ if err := (Controller{Client: p.Client, Processes: p, Observe: observeLinux}).Control(context.Background(), "teardown"); err != nil {
201
241
  t.Fatal(err)
202
242
  }
203
243
  ctx, cancel := context.WithTimeout(context.Background(), time.Second)
@@ -290,7 +330,7 @@ func TestLinuxSupervisorIdentityConflictsAndSocketSubstitutionRefuse(t *testing.
290
330
  }
291
331
  func TestLinuxReparentedChildRefusesBeforeSocket(t *testing.T) {
292
332
  p := linuxFixture(t)
293
- record(t, p.Client, Record{Inventory: p.Expected, Enabled: true})
333
+ record(t, p.Client, Record{Inventory: p.Expected, Enabled: true, Lifecycle: vmLifecycle(t, p)})
294
334
  cmd := exec.Command(p.Binary, "serve-child")
295
335
  cmd.Env = []string{"PATH=/usr/sbin:/usr/bin:/sbin:/bin", "SYNOPKGLAND_PARENT=1"}
296
336
  if cmd.Run() == nil {
@@ -300,3 +340,574 @@ func TestLinuxReparentedChildRefusesBeforeSocket(t *testing.T) {
300
340
  t.Fatal("unsafe child opened socket")
301
341
  }
302
342
  }
343
+
344
+ func vmUnit(t *testing.T, action string) {
345
+ t.Helper()
346
+ if out, err := exec.Command("/bin/systemctl", action, "pkgctl-root.service").CombinedOutput(); err != nil {
347
+ t.Fatalf("systemctl %s: %v %s", action, err, out)
348
+ }
349
+ }
350
+
351
+ // Run the generated M1f hook as an unprivileged user against the real M1g
352
+ // helper. The VM models management ordering, not DSM Package Center itself.
353
+ func TestLinuxPrestopRequiresAdminTeardownAndPrestartNeverRecovers(t *testing.T) {
354
+ p := linuxFixture(t)
355
+ for _, dir := range []string{p.StateDir, p.RunDir} {
356
+ if err := os.Chmod(dir, 0755); err != nil {
357
+ t.Fatal(err)
358
+ }
359
+ }
360
+ proc := startVMHelper(t, p)
361
+ child := supervisedPID(t, proc.PID)
362
+ log := "/tmp/m1f-prestop-message"
363
+ if err := os.WriteFile(log, nil, 0600); err != nil {
364
+ t.Fatal(err)
365
+ }
366
+ if err := os.Chown(log, 65534, 65534); err != nil {
367
+ t.Fatal(err)
368
+ }
369
+ t.Cleanup(func() { os.Remove(log) })
370
+ hook := func(action string, allow bool) {
371
+ t.Helper()
372
+ before, err := os.ReadFile(filepath.Join(p.StateDir, "approval.json"))
373
+ if err != nil {
374
+ t.Fatal(err)
375
+ }
376
+ if err := os.Truncate(log, 0); err != nil {
377
+ t.Fatal(err)
378
+ }
379
+ cmd := exec.Command("/var/packages/root/scripts/start-stop-status", action)
380
+ cmd.Env = append(os.Environ(), "SYNOPKG_TEMP_LOGFILE="+log)
381
+ cmd.SysProcAttr = &syscall.SysProcAttr{Credential: &syscall.Credential{Uid: 65534, Gid: 65534}}
382
+ out, err := cmd.CombinedOutput()
383
+ if (err == nil) != allow {
384
+ t.Fatalf("%s allow=%v: %v %s", action, allow, err, out)
385
+ }
386
+ if !allow {
387
+ message, err := os.ReadFile(log)
388
+ if err != nil || string(message) != string(out) || !strings.Contains(string(out), "helper_teardown") {
389
+ t.Fatalf("missing DSM refusal message: %v %s %s", err, out, message)
390
+ }
391
+ }
392
+ after, err := os.ReadFile(filepath.Join(p.StateDir, "approval.json"))
393
+ if err != nil || string(before) != string(after) {
394
+ t.Fatal("nonprivileged hook changed lifecycle latch", err)
395
+ }
396
+ }
397
+ hook("prestop", false)
398
+ if _, err := observeLinux(context.Background(), p.Expected); err != nil {
399
+ t.Fatal("prestop refusal changed active unit", err)
400
+ }
401
+ current, err := readProcess(p.RunDir, 0)
402
+ if err != nil || current != proc || p.Status(context.Background()).State != "ready" {
403
+ t.Fatal("prestop refusal stopped helper", err)
404
+ }
405
+ hook("prestart", true)
406
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
407
+ if err := ctl.Control(context.Background(), "teardown"); err != nil {
408
+ t.Fatal(err)
409
+ }
410
+ waitPIDExit(t, child)
411
+ waitPIDExit(t, proc.PID)
412
+ hook("prestop", true)
413
+ vmUnit(t, "stop")
414
+ hook("stop", true)
415
+ vmUnit(t, "start")
416
+ hook("prestart", true)
417
+ hook("start", true)
418
+ if p.Status(context.Background()).State != "stopped" || !runtimeAbsent(p.Client) {
419
+ t.Fatal("package Start recovered integration")
420
+ }
421
+ stopped, err := readRecord(p.StateDir, 0)
422
+ if err != nil {
423
+ t.Fatal(err)
424
+ }
425
+ incomplete := stopped
426
+ incomplete.Residual = true
427
+ record(t, p.Client, incomplete)
428
+ hook("prestop", false)
429
+ hook("prestart", true)
430
+ record(t, p.Client, stopped)
431
+ if err := ctl.Control(context.Background(), "recover"); err != nil {
432
+ t.Fatal(err)
433
+ }
434
+ recovered, err := readRecord(p.StateDir, 0)
435
+ if err != nil || recovered.Lifecycle.Epoch == stopped.Lifecycle.Epoch || p.Status(context.Background()).State != "ready" {
436
+ t.Fatal("explicit Recover failed", err)
437
+ }
438
+ if err := ctl.Control(context.Background(), "disable"); err != nil {
439
+ t.Fatal(err)
440
+ }
441
+ hook("prestop", true)
442
+ hook("prestart", true)
443
+ if p.Status(context.Background()).State != "not-enabled" || !runtimeAbsent(p.Client) {
444
+ t.Fatal("prestart cleared disabled gate")
445
+ }
446
+ }
447
+
448
+ func vmLifecycle(t *testing.T, p LinuxProcesses) *Lifecycle {
449
+ t.Helper()
450
+ b, err := observeLinux(context.Background(), p.Expected)
451
+ if err != nil {
452
+ t.Fatal(err)
453
+ }
454
+ l, err := newLifecycle(b)
455
+ if err != nil {
456
+ t.Fatal(err)
457
+ }
458
+ if err := createLifetime(p.Client, l); err != nil {
459
+ t.Fatal(err)
460
+ }
461
+ return l
462
+ }
463
+
464
+ func TestLinuxUnitStopFencesBeforeLockAndPublishesCompletion(t *testing.T) {
465
+ p := linuxFixture(t)
466
+ proc := startVMHelper(t, p)
467
+ child := supervisedPID(t, proc.PID)
468
+ lock, err := os.OpenFile(filepath.Join(p.StateDir, "policy.lock"), os.O_RDWR, 0600)
469
+ if err != nil {
470
+ t.Fatal(err)
471
+ }
472
+ defer lock.Close()
473
+ if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); err != nil {
474
+ t.Fatal(err)
475
+ }
476
+ vmUnit(t, "stop")
477
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second)
478
+ err = waitHealthy(ctx, func(context.Context) bool {
479
+ s := p.Status(context.Background())
480
+ return s.State == "failed" && s.Cleanup == "required"
481
+ })
482
+ cancel()
483
+ syscall.Flock(int(lock.Fd()), syscall.LOCK_UN)
484
+ if err != nil {
485
+ t.Fatal("memory fence waited for policy lock", err)
486
+ }
487
+ ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second)
488
+ defer cancel()
489
+ if waitHealthy(ctx, func(context.Context) bool {
490
+ r, e := readRecord(p.StateDir, 0)
491
+ return e == nil && !r.Residual && r.Lifecycle.Phase == "stopped" && r.Lifecycle.Completion != ""
492
+ }) != nil {
493
+ t.Fatal("completion missing")
494
+ }
495
+ r, _ := readRecord(p.StateDir, 0)
496
+ proof, e := completionRecord(p.Client, r)
497
+ if e != nil {
498
+ t.Fatal(e)
499
+ }
500
+ if proof.Process != proc {
501
+ t.Fatal("wrong completion identity", r)
502
+ }
503
+ waitPIDExit(t, child)
504
+ waitPIDExit(t, proc.PID)
505
+ if err := p.CheckStopped(context.Background()); err != nil {
506
+ t.Fatal(err)
507
+ }
508
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
509
+ if ctl.Control(context.Background(), "recover") == nil {
510
+ t.Fatal("inactive unit recovered")
511
+ }
512
+ vmUnit(t, "start")
513
+ if p.Status(context.Background()).State != "stopped" {
514
+ t.Fatal("unit Start resurrected integration")
515
+ }
516
+ if err := ctl.Control(context.Background(), "recover"); err != nil {
517
+ t.Fatal(err)
518
+ }
519
+ next, _ := readRecord(p.StateDir, 0)
520
+ if next.Lifecycle.Epoch == r.Lifecycle.Epoch || p.Status(context.Background()).State != "ready" {
521
+ t.Fatal("explicit recovery failed")
522
+ }
523
+ }
524
+ func TestLinuxRapidUnitStopStartNeverClearsFence(t *testing.T) {
525
+ p := linuxFixture(t)
526
+ proc := startVMHelper(t, p)
527
+ vmUnit(t, "stop")
528
+ vmUnit(t, "start")
529
+ ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
530
+ defer cancel()
531
+ if waitHealthy(ctx, func(context.Context) bool {
532
+ r, e := readRecord(p.StateDir, 0)
533
+ return e == nil && r.Lifecycle.Phase == "stopped" && !r.Residual
534
+ }) != nil {
535
+ t.Fatal("rapid transition missed")
536
+ }
537
+ waitPIDExit(t, proc.PID)
538
+ if p.Status(context.Background()).State != "stopped" {
539
+ t.Fatal("rapid Start resurrected")
540
+ }
541
+ }
542
+ func TestLinuxBusUnavailableRefusesActivation(t *testing.T) {
543
+ p := linuxFixture(t)
544
+ socket := busPath
545
+ if err := os.Rename(socket, socket+".fixture"); err != nil {
546
+ t.Fatal(err)
547
+ }
548
+ defer os.Rename(socket+".fixture", socket)
549
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
550
+ if ctl.Control(context.Background(), "enable") == nil {
551
+ t.Fatal("activation without bus")
552
+ }
553
+ if !runtimeAbsent(p.Client) {
554
+ t.Fatal("unknown authority spawned runtime")
555
+ }
556
+ }
557
+
558
+ func TestLinuxRealOldPayloadReplayRefusesNewApproval(t *testing.T) {
559
+ p := linuxFixture(t)
560
+ _ = startVMHelper(t, p)
561
+ if err := (Controller{Client: p.Client, Processes: p, Observe: observeLinux}).Control(context.Background(), "teardown"); err != nil {
562
+ t.Fatal(err)
563
+ }
564
+ before, err := os.ReadFile(filepath.Join(p.StateDir, "approval.json"))
565
+ if err != nil {
566
+ t.Fatal(err)
567
+ }
568
+ digest, err := executableDigest("/helper-legacy")
569
+ if err != nil {
570
+ t.Fatal(err)
571
+ }
572
+ path := filepath.Join(p.StateDir, "payload-"+digest)
573
+ b, err := os.ReadFile("/helper-legacy")
574
+ if err != nil {
575
+ t.Fatal(err)
576
+ }
577
+ if err := os.WriteFile(path, b, 0700); err != nil {
578
+ t.Fatal(err)
579
+ }
580
+ for _, action := range []string{"enable", "recover", "supervise"} {
581
+ if out, err := exec.Command(path, action).CombinedOutput(); err == nil {
582
+ t.Fatalf("old payload replayed %s %s", action, out)
583
+ }
584
+ }
585
+ after, _ := os.ReadFile(filepath.Join(p.StateDir, "approval.json"))
586
+ if string(before) != string(after) || !runtimeAbsent(p.Client) {
587
+ t.Fatal("old payload changed latch")
588
+ }
589
+ }
590
+ func TestLinuxBusRestartFencesAndCompletesRuntime(t *testing.T) {
591
+ p := linuxFixture(t)
592
+ proc := startVMHelper(t, p)
593
+ if out, err := exec.Command("/bin/systemctl", "restart", "dbus.service").CombinedOutput(); err != nil {
594
+ t.Fatal(err, string(out))
595
+ }
596
+ ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
597
+ defer cancel()
598
+ if waitHealthy(ctx, func(context.Context) bool {
599
+ r, e := readRecord(p.StateDir, 0)
600
+ return e == nil && r.Lifecycle.Phase == "stopped" && !r.Residual && r.Lifecycle.Completion != ""
601
+ }) != nil {
602
+ t.Fatal("bus loss did not complete")
603
+ }
604
+ waitPIDExit(t, proc.PID)
605
+ if p.Status(context.Background()).State != "stopped" {
606
+ t.Fatal("bus reconnection revived helper")
607
+ }
608
+ }
609
+
610
+ func TestLinuxLostSupervisorRepairThenExplicitRecover(t *testing.T) {
611
+ p := linuxFixture(t)
612
+ record(t, p.Client, Record{Inventory: p.Expected, Enabled: true, Lifecycle: vmLifecycle(t, p)})
613
+ cmd := exec.Command(p.Binary, "supervise")
614
+ if err := cmd.Start(); err != nil {
615
+ t.Fatal(err)
616
+ }
617
+ owned := &ownedLinuxChild{process: cmd.Process}
618
+ t.Cleanup(func() { stopChild(context.Background(), owned, time.Millisecond) })
619
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
620
+ err := waitHealthy(ctx, func(ctx context.Context) bool { return p.Status(ctx).State == "ready" })
621
+ cancel()
622
+ if err != nil {
623
+ t.Fatal(err)
624
+ }
625
+ proc, err := readProcess(p.RunDir, 0)
626
+ if err != nil {
627
+ t.Fatal(err)
628
+ }
629
+ child := supervisedPID(t, proc.PID)
630
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
631
+ if ctl.Control(context.Background(), "repair") == nil {
632
+ t.Fatal("repaired live supervisor")
633
+ }
634
+ if p.Status(context.Background()).State != "ready" {
635
+ t.Fatal("busy repair fenced active helper")
636
+ }
637
+ if err := owned.signal(syscall.SIGKILL); err != nil {
638
+ t.Fatal(err)
639
+ }
640
+ waitPIDExit(t, proc.PID)
641
+ waitPIDExit(t, child)
642
+ if ctl.Control(context.Background(), "recover") == nil {
643
+ t.Fatal("loss recovered without repair")
644
+ }
645
+ if err := ctl.Control(context.Background(), "repair"); err != nil {
646
+ t.Fatal(err)
647
+ }
648
+ repaired, err := readRecord(p.StateDir, 0)
649
+ if err != nil || repaired.Residual || repaired.Lifecycle.Completion == "" || p.Status(context.Background()).State != "stopped" {
650
+ t.Fatal("repair not committed", err)
651
+ }
652
+ proof, err := completionRecord(p.Client, repaired)
653
+ if err != nil || proof.Repair == nil || !runtimeAbsent(p.Client) {
654
+ t.Fatal("no repair proof", err)
655
+ }
656
+ if err := ctl.Control(context.Background(), "repair"); err != nil {
657
+ t.Fatal(err)
658
+ }
659
+ if err := ctl.Control(context.Background(), "recover"); err != nil {
660
+ t.Fatal(err)
661
+ }
662
+ next, _ := readRecord(p.StateDir, 0)
663
+ if next.Lifecycle.Epoch == repaired.Lifecycle.Epoch || p.Status(context.Background()).State != "ready" {
664
+ t.Fatal("explicit recovery did not start new epoch")
665
+ }
666
+ t.Cleanup(func() { ctl.Control(context.Background(), "disable") })
667
+ // A package/nonroot process cannot use the executable repair entry.
668
+ for _, dir := range []string{p.StateDir, p.RunDir} {
669
+ if err := os.Chmod(dir, 0755); err != nil {
670
+ t.Fatal(err)
671
+ }
672
+ }
673
+ if err := os.Chmod(p.Binary, 0755); err != nil {
674
+ t.Fatal(err)
675
+ }
676
+ denied := exec.Command(p.Binary, "repair")
677
+ denied.SysProcAttr = &syscall.SysProcAttr{Credential: &syscall.Credential{Uid: 65534, Gid: 65534}}
678
+ output, err := denied.CombinedOutput()
679
+ if err == nil || !strings.Contains(string(output), "helper lifecycle refused") {
680
+ t.Fatal("package user did not reach euid refusal", err, string(output))
681
+ }
682
+
683
+ }
684
+
685
+ func TestLinuxInheritedLifetimePinsLockUntilLastHolderExit(t *testing.T) {
686
+ p := linuxFixture(t)
687
+ l := vmLifecycle(t, p)
688
+ lease, err := acquireLifetime(p.Client, l)
689
+ if err != nil {
690
+ t.Fatal(err)
691
+ }
692
+ cmd := exec.Command("/bin/sleep", "60")
693
+ cmd.ExtraFiles = []*os.File{lease}
694
+ if err := cmd.Start(); err != nil {
695
+ t.Fatal(err)
696
+ }
697
+ child := &ownedLinuxChild{process: cmd.Process}
698
+ t.Cleanup(func() { stopChild(context.Background(), child, time.Millisecond) })
699
+ // Model supervisor loss while the inherited child is still alive. No
700
+ // LOCK_UN: closing that would release the shared flock prematurely.
701
+ lease.Close()
702
+ if got, err := acquireLifetime(p.Client, l); err == nil {
703
+ got.Close()
704
+ t.Fatal("parent close released live child's witness")
705
+ }
706
+ if err := stopChild(context.Background(), child, time.Millisecond); err != nil {
707
+ t.Fatal(err)
708
+ }
709
+ got, err := acquireLifetime(p.Client, l)
710
+ if err != nil {
711
+ t.Fatal(err)
712
+ }
713
+ got.Close()
714
+ }
715
+
716
+ func TestLinuxPreR2PayloadReplayAndLateSupervisorRefuseRepairLatch(t *testing.T) {
717
+ p := linuxFixture(t)
718
+ record(t, p.Client, Record{Inventory: p.Expected, Enabled: true, Residual: true, Lifecycle: vmLifecycle(t, p)})
719
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
720
+ // No process was started: the same lease also proves the startup crash gap.
721
+ if err := ctl.Control(context.Background(), "repair"); err != nil {
722
+ t.Fatal(err)
723
+ }
724
+ before, _ := os.ReadFile(filepath.Join(p.StateDir, "approval.json"))
725
+ if out, err := exec.Command(p.Binary, "supervise").CombinedOutput(); err == nil {
726
+ t.Fatal("late supervisor crossed repair latch", string(out))
727
+ }
728
+ for _, source := range []string{"/helper-pre-r2", "/helper-m1d"} {
729
+ digest, err := executableDigest(source)
730
+ if err != nil {
731
+ t.Fatal(err)
732
+ }
733
+ bytes, err := os.ReadFile(source)
734
+ if err != nil {
735
+ t.Fatal(err)
736
+ }
737
+ path := filepath.Join(p.StateDir, "payload-"+digest)
738
+ if err := os.WriteFile(path, bytes, 0700); err != nil {
739
+ t.Fatal(err)
740
+ }
741
+ for _, action := range []string{"enable", "recover", "supervise", "disable", "teardown"} {
742
+ if out, err := exec.Command(path, action).CombinedOutput(); err == nil {
743
+ t.Fatal("old payload crossed repair schema", source, action, string(out))
744
+ }
745
+ }
746
+ }
747
+ after, _ := os.ReadFile(filepath.Join(p.StateDir, "approval.json"))
748
+ if string(before) != string(after) || !runtimeAbsent(p.Client) {
749
+ t.Fatal("replay altered completion")
750
+ }
751
+ }
752
+
753
+ func TestLinuxActualM1dLostSupervisorResidueCannotGainRepairWitness(t *testing.T) {
754
+ p := linuxFixture(t)
755
+ digest, err := executableDigest("/helper-m1d")
756
+ if err != nil {
757
+ t.Fatal(err)
758
+ }
759
+ old := p
760
+ old.Expected.PayloadDigest = digest
761
+ old.Binary = filepath.Join(p.StateDir, "payload-"+digest)
762
+ bytes, err := os.ReadFile("/helper-m1d")
763
+ if err != nil {
764
+ t.Fatal(err)
765
+ }
766
+ if err := os.WriteFile(old.Binary, bytes, 0700); err != nil {
767
+ t.Fatal(err)
768
+ }
769
+ record(t, p.Client, Record{Inventory: old.Expected, Enabled: true})
770
+ cmd := exec.Command(old.Binary, "supervise")
771
+ if err := cmd.Start(); err != nil {
772
+ t.Fatal(err)
773
+ }
774
+ owned := &ownedLinuxChild{process: cmd.Process}
775
+ t.Cleanup(func() { stopChild(context.Background(), owned, time.Millisecond) })
776
+ ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
777
+ err = waitHealthy(ctx, func(ctx context.Context) bool { return old.Status(ctx).State == "ready" })
778
+ cancel()
779
+ if err != nil {
780
+ t.Fatal(err)
781
+ }
782
+ proc, err := readProcess(p.RunDir, 0)
783
+ if err != nil {
784
+ t.Fatal(err)
785
+ }
786
+ child := supervisedPID(t, proc.PID)
787
+ if err := owned.signal(syscall.SIGKILL); err != nil {
788
+ t.Fatal(err)
789
+ }
790
+ waitPIDExit(t, proc.PID)
791
+ waitPIDExit(t, child)
792
+ // Mimic an upgraded controller; it must not create a new lock as purported
793
+ // historical proof, even though both observed PIDs have exited in this VM.
794
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux}
795
+ if ctl.Control(context.Background(), "repair") == nil {
796
+ t.Fatal("upgraded helper repaired unwitnessed legacy residue")
797
+ }
798
+ for _, name := range []string{"helper.sock", "supervisor.sock", "process.json"} {
799
+ if _, err := os.Lstat(filepath.Join(p.RunDir, name)); err != nil {
800
+ t.Fatal("legacy evidence removed", name, err)
801
+ }
802
+ }
803
+ leases, _ := filepath.Glob(filepath.Join(p.StateDir, "lifetime-*.lock"))
804
+ if len(leases) != 0 {
805
+ t.Fatal("retroactively manufactured witness", leases)
806
+ }
807
+ }
808
+
809
+ func TestLinuxAdminTeardownSnapshotRace(t *testing.T) {
810
+ p := linuxFixture(t)
811
+ proc := startVMHelper(t, p)
812
+ child := supervisedPID(t, proc.PID)
813
+ ctl := Controller{Client: p.Client, Processes: p, Observe: observeLinux, Boot: linuxBoot}
814
+ // Capture the fenced snapshot inside the policy transaction, before the
815
+ // owner can complete it. Then deliberately let the real owner win the race.
816
+ var before Record
817
+ if err := policyUpdate(p.Client, func(r *Record) error {
818
+ r.Lifecycle.Phase = "fenced"
819
+ r.Lifecycle.Reason = "admin-stop"
820
+ r.Residual = true
821
+ before = *r
822
+ return nil
823
+ }); err != nil {
824
+ t.Fatal(err)
825
+ }
826
+ ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
827
+ defer cancel()
828
+ if waitHealthy(ctx, func(context.Context) bool {
829
+ r, e := readRecord(p.StateDir, 0)
830
+ if e != nil {
831
+ return false
832
+ }
833
+ proof, e := completionRecord(p.Client, r)
834
+ return e == nil && proof.Process == proc && runtimeAbsent(p.Client)
835
+ }) != nil {
836
+ t.Fatal("owner did not commit autonomous admin-stop")
837
+ }
838
+ waitPIDExit(t, child)
839
+ waitPIDExit(t, proc.PID)
840
+ if err := ctl.teardownRecord(before, proc); err != nil {
841
+ t.Fatal("exact committed completion rejected after approval snapshot", err)
842
+ }
843
+ }
844
+
845
+ type pausedCompletionProcesses struct {
846
+ LinuxProcesses
847
+ visible string
848
+ }
849
+
850
+ func (p pausedCompletionProcesses) Stop(proc Process) error {
851
+ ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
852
+ defer cancel()
853
+ if err := waitHealthy(ctx, func(context.Context) bool {
854
+ _, err := os.Stat(p.visible)
855
+ return err == nil
856
+ }); err != nil {
857
+ return err
858
+ }
859
+ // Exercise the real socket/identity path after autonomous runtime unlink.
860
+ return p.LinuxProcesses.Stop(proc)
861
+ }
862
+
863
+ func TestLinuxControllerWaitsForRealCompletionPublisher(t *testing.T) {
864
+ p := linuxFixture(t)
865
+ proc := startVMHelper(t, p)
866
+ child := supervisedPID(t, proc.PID)
867
+ hold := filepath.Join(p.StateDir, "fixture-hold-completion")
868
+ if err := os.WriteFile(hold, []byte("pause publisher after approval rename"), 0600); err != nil {
869
+ t.Fatal(err)
870
+ }
871
+ defer func() {
872
+ os.Remove(hold) // disposable VM fixture only; never a NAS operation
873
+ waitPIDExit(t, child)
874
+ waitPIDExit(t, proc.PID)
875
+ }()
876
+ result := make(chan error, 1)
877
+ go func() {
878
+ processes := pausedCompletionProcesses{LinuxProcesses: p, visible: filepath.Join(p.StateDir, "fixture-completion-visible")}
879
+ result <- (Controller{Client: p.Client, Processes: processes, Observe: observeLinux, Boot: linuxBoot}).Control(context.Background(), "teardown")
880
+ }()
881
+ ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
882
+ defer cancel()
883
+ if waitHealthy(ctx, func(context.Context) bool {
884
+ _, visible := os.Stat(filepath.Join(p.StateDir, "fixture-completion-visible"))
885
+ r, e := readRecord(p.StateDir, 0)
886
+ if visible != nil || e != nil {
887
+ return false
888
+ }
889
+ proof, e := completionRecord(p.Client, r)
890
+ return e == nil && proof.Process == proc && runtimeAbsent(p.Client)
891
+ }) != nil {
892
+ t.Fatal("real supervisor did not publish while holding policy.lock")
893
+ }
894
+ select {
895
+ case err := <-result:
896
+ t.Fatal("controller returned before publisher unlocked", err)
897
+ case <-time.After(100 * time.Millisecond):
898
+ }
899
+ if err := os.Remove(hold); err != nil {
900
+ t.Fatal(err)
901
+ }
902
+ select {
903
+ case err := <-result:
904
+ if err != nil {
905
+ t.Fatal("real committed completion refused after publisher unlock", err)
906
+ }
907
+ case <-ctx.Done():
908
+ t.Fatal("controller did not finish after publisher unlock")
909
+ }
910
+ if err := p.CheckStopped(context.Background()); err != nil {
911
+ t.Fatal(err)
912
+ }
913
+ }