@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
@@ -0,0 +1,200 @@
1
+ package helper
2
+
3
+ import (
4
+ "context"
5
+ "math"
6
+ )
7
+
8
+ // A deleted account cannot supply its former UID. Select its recorded identity
9
+ // by the validated native name, never drop invalidation because lookup failed.
10
+ func (r *relaxedProvider) invalidateName(ctx context.Context, name string, observed ...RelaxedIdentity) Code {
11
+ a := r.authority
12
+ a.mu.Lock()
13
+ selected := map[RelaxedIdentity]bool{}
14
+ related := func(id RelaxedIdentity) bool {
15
+ if id.Username == name {
16
+ return true
17
+ }
18
+ for _, current := range observed {
19
+ if validRelaxedIdentity(current) && relaxedRelated(id, current) {
20
+ return true
21
+ }
22
+ }
23
+ return false
24
+ }
25
+ for id := range r.principals {
26
+ if related(id) {
27
+ selected[id] = true
28
+ }
29
+ }
30
+ code := a.transaction(func(s *GrantStore) (bool, Code) {
31
+ for _, g := range s.Grants {
32
+ for _, p := range []Principal{g.Owner, g.Issuer} {
33
+ if p.IdentityBasis == "uid-username" && related(relaxedPrincipalIdentity(p)) {
34
+ selected[relaxedPrincipalIdentity(p)] = true
35
+ }
36
+ }
37
+ }
38
+ return false, ""
39
+ })
40
+ if code != "" {
41
+ a.mu.Unlock()
42
+ return ErrCleanupRequired
43
+ }
44
+ if len(selected) == 0 {
45
+ a.mu.Unlock()
46
+ return ""
47
+ }
48
+ ids := make([]RelaxedIdentity, 0, len(selected))
49
+ for id := range selected {
50
+ ids = append(ids, id)
51
+ }
52
+ return r.invalidateLocked(ctx, ids)
53
+ }
54
+
55
+ // Observed identity changes use the existing S3 transaction/order, never an
56
+ // auxiliary store. Old generations are denied before R and never reused.
57
+ func (r *relaxedProvider) invalidate(ctx context.Context, ids []RelaxedIdentity) Code {
58
+ if r == nil || r.authority == nil {
59
+ return ErrUnavailable
60
+ }
61
+ r.authority.mu.Lock()
62
+ return r.invalidateLocked(ctx, ids)
63
+ }
64
+
65
+ // Takes ownership of the held admission lock; all exit paths release it.
66
+ func (r *relaxedProvider) invalidateLocked(ctx context.Context, ids []RelaxedIdentity, prospective ...RelaxedIdentity) Code {
67
+ ctx, cancel := context.WithTimeout(ctx, MetadataTimeout)
68
+ defer cancel()
69
+ a := r.authority
70
+ selected := map[RelaxedIdentity]bool{}
71
+ blocked := map[RelaxedIdentity]bool{}
72
+ for _, id := range append(append([]RelaxedIdentity{}, ids...), prospective...) {
73
+ if !validRelaxedIdentity(id) || r.blocked[id] {
74
+ a.fenced = true
75
+ a.mu.Unlock()
76
+ return ErrCleanupRequired
77
+ }
78
+ blocked[id] = true
79
+ }
80
+ for id := range blocked {
81
+ r.blocked[id] = true
82
+ }
83
+ for _, id := range ids {
84
+ selected[id] = true
85
+ delete(r.principals, id)
86
+ }
87
+ for id, pending := range a.intents {
88
+ if selected[relaxedActorIdentity(pending.actor)] {
89
+ delete(a.intents, id)
90
+ }
91
+ }
92
+ keys := []GrantDrainKey{}
93
+ code := safeGrantCode(a.repository.Transact(func(policy GrantPolicy, s *GrantStore) (bool, Code) {
94
+ if policy != a.policy || !policy.Enabled || a.fenced {
95
+ return false, ErrFenced
96
+ }
97
+ // Plan all revisions first, so overflow or malformed authority cannot partly R.
98
+ indices := []int{}
99
+ for n, g := range s.Grants {
100
+ affected := false
101
+ for _, p := range []Principal{g.Owner, g.Issuer} {
102
+ if p.IdentityBasis == "uid-username" && selected[relaxedPrincipalIdentity(p)] {
103
+ affected = true
104
+ }
105
+ }
106
+ if !affected {
107
+ continue
108
+ }
109
+ revision := g.Revision
110
+ if g.State != GrantRevoked {
111
+ if revision == math.MaxUint64 || s.Revision == math.MaxUint64 {
112
+ return false, ErrLimit
113
+ }
114
+ revision++
115
+ indices = append(indices, n)
116
+ }
117
+ keys = append(keys, GrantDrainKey{policy.Epoch, g.ID, revision})
118
+ }
119
+ for _, n := range indices {
120
+ g := &s.Grants[n]
121
+ g.State = GrantRevoked
122
+ g.Reason = ErrRevoked
123
+ g.RevokedAt = max(g.CreatedAt, a.now().UnixMilli())
124
+ g.Revision++
125
+ }
126
+ if len(indices) > 0 {
127
+ s.Revision++
128
+ }
129
+ return len(indices) > 0, ""
130
+ }))
131
+ if code != "" {
132
+ a.fenced = true
133
+ clear(a.intents)
134
+ }
135
+ a.mu.Unlock()
136
+ complete := code == ""
137
+ // The caller's operations on foreign shared grants must stop without rewriting
138
+ // those grants. This seam must prove actual owned-child/relay completion.
139
+ identityCohort, ok := a.cohort.(relaxedIdentityCohort)
140
+ if !ok {
141
+ complete = false
142
+ } else {
143
+ for id := range selected {
144
+ if c := nativeObservationCode(ctx, identityCohort.drainRelaxedIdentity(ctx, id)); c != "" {
145
+ complete = false
146
+ }
147
+ }
148
+ }
149
+ for _, key := range keys {
150
+ q, c := a.drain(ctx, key)
151
+ if c != "" {
152
+ complete = false
153
+ continue
154
+ }
155
+ if code == "" {
156
+ a.mu.Lock()
157
+ saved := safeGrantCode(a.repository.SaveQuiescence(q))
158
+ a.mu.Unlock()
159
+ if saved != "" {
160
+ complete = false
161
+ }
162
+ }
163
+ }
164
+ a.mu.Lock()
165
+ defer a.mu.Unlock()
166
+ if !complete {
167
+ a.fenced = true
168
+ clear(a.intents)
169
+ if a.gate != nil {
170
+ a.gate.fenceLocked("relaxed-identity-cleanup-required")
171
+ }
172
+ return ErrCleanupRequired
173
+ }
174
+ for id := range blocked {
175
+ delete(r.blocked, id)
176
+ }
177
+ // The revoked grants remain revoked; a subsequent Resolve gets a new opaque
178
+ // generation and consent must create a new grant. Completed Q is not consent.
179
+ return ""
180
+ }
181
+
182
+ // This is the existing S2 owner/reaper, not a new identity process manager.
183
+ func (c *operationCohort) drainRelaxedIdentity(ctx context.Context, id RelaxedIdentity) Code {
184
+ ctx, cancel := context.WithTimeout(ctx, RevokeDrainTimeout)
185
+ defer cancel()
186
+ if err := c.drainSelected(ctx, TerminateGrace, func(op *cohortOperation) bool {
187
+ return op.actor.relaxed != nil && relaxedActorIdentity(op.actor) == id
188
+ }); err != nil {
189
+ return ErrCleanupRequired
190
+ }
191
+ if nativeContextCode(ctx) != "" {
192
+ return ErrCleanupRequired
193
+ }
194
+ for _, op := range c.operations {
195
+ if op.actor.relaxed != nil && relaxedActorIdentity(op.actor) == id {
196
+ return ErrCleanupRequired
197
+ }
198
+ }
199
+ return ""
200
+ }
@@ -0,0 +1,132 @@
1
+ package helper
2
+
3
+ import (
4
+ "errors"
5
+ "io/fs"
6
+ "net"
7
+ "os"
8
+ "path/filepath"
9
+ "syscall"
10
+ "time"
11
+ )
12
+
13
+ type RepairCompletion struct {
14
+ Inventory Inventory `json:"inventory"`
15
+ Boot string `json:"boot"`
16
+ Lease Lease `json:"lease"`
17
+ }
18
+
19
+ // repair is entered with control.lock held. It never calls Processes.Stop or
20
+ // Start: the lifetime lock proves quiescence without observing/signalling PIDs.
21
+ func (c Controller) repair(r Record) error {
22
+ if r.Inventory.Package != c.Expected.Package || r.Lifecycle == nil || r.Lifecycle.Lease == nil {
23
+ return errTrust
24
+ }
25
+ if r.Lifecycle.Completion != "" {
26
+ if _, err := completionRecord(c.Client, r); err != nil {
27
+ return err
28
+ }
29
+ }
30
+ lock, err := acquireLifetime(c.Client, r.Lifecycle)
31
+ if err != nil {
32
+ return err
33
+ }
34
+ defer lock.Close()
35
+ // Persist denial before any unlink; neither crash nor later active unit can
36
+ // clear this epoch's latch. Preserve Enabled and the old inventory.
37
+ if err = policyUpdate(c.Client, func(current *Record) error {
38
+ if !sameRepairEpoch(*current, r) {
39
+ return errTrust
40
+ }
41
+ current.Residual = true
42
+ current.Lifecycle.Phase = "fenced"
43
+ current.Lifecycle.Reason = "admin-repair"
44
+ current.Lifecycle.Completion = ""
45
+ return nil
46
+ }); err != nil {
47
+ return err
48
+ }
49
+ entries, err := repairEntries(c.Client, r)
50
+ if err != nil {
51
+ return err
52
+ }
53
+ for name, st := range entries {
54
+ path := filepath.Join(c.RunDir, name)
55
+ now, err := os.Lstat(path)
56
+ if err != nil || !os.SameFile(st, now) || now.Mode() != st.Mode() {
57
+ return errTrust
58
+ }
59
+ if err = os.Remove(path); err != nil {
60
+ return err
61
+ }
62
+ }
63
+ if err = syncDirectory(c.RunDir); err != nil {
64
+ return err
65
+ }
66
+ return policyUpdate(c.Client, func(current *Record) error {
67
+ if !sameRepairEpoch(*current, r) || current.Lifecycle.Phase != "fenced" || !runtimeAbsent(c.Client) {
68
+ return errTrust
69
+ }
70
+ if err := validateLifetime(c.Client, current.Lifecycle, lock); err != nil {
71
+ return err
72
+ }
73
+ current.Lifecycle.Phase = "stopped"
74
+ return storeCompletion(c.Client, current, Completion{Epoch: current.Lifecycle.Epoch, Repair: &RepairCompletion{Inventory: current.Inventory, Boot: current.Lifecycle.Binding.Boot, Lease: *current.Lifecycle.Lease}})
75
+ })
76
+ }
77
+
78
+ // Both repair policy transactions compare the same immutable epoch witness.
79
+ func sameRepairEpoch(current, original Record) bool {
80
+ if current.Inventory != original.Inventory || current.Lifecycle == nil || original.Lifecycle == nil {
81
+ return false
82
+ }
83
+ got, want := current.Lifecycle, original.Lifecycle
84
+ return got.Epoch == want.Epoch && got.Lease != nil && want.Lease != nil && *got.Lease == *want.Lease
85
+ }
86
+
87
+ // Preflight every entry before deleting any, then recheck inode at unlink.
88
+ // Missing entries permit retry after an interrupted repair, never proof alone.
89
+ func repairEntries(c Client, r Record) (map[string]os.FileInfo, error) {
90
+ if err := protected(c.RunDir, c.Owner, true); err != nil {
91
+ return nil, err
92
+ }
93
+ entries := map[string]os.FileInfo{}
94
+ for _, name := range []string{"helper.sock", "supervisor.sock", "process.json"} {
95
+ path := filepath.Join(c.RunDir, name)
96
+ st, err := os.Lstat(path)
97
+ if errors.Is(err, fs.ErrNotExist) {
98
+ continue
99
+ }
100
+ if err != nil {
101
+ return nil, err
102
+ }
103
+ s, ok := st.Sys().(*syscall.Stat_t)
104
+ if !ok || s.Uid != c.Owner {
105
+ return nil, errTrust
106
+ }
107
+ if name == "process.json" {
108
+ p, err := readProcess(c.RunDir, c.Owner)
109
+ if err != nil || st.Mode().Perm() != 0600 || s.Nlink != 1 || p.Inventory != r.Inventory || p.Boot != r.Lifecycle.Binding.Boot {
110
+ return nil, errTrust
111
+ }
112
+ } else {
113
+ mode := fs.FileMode(0660)
114
+ if name == "supervisor.sock" {
115
+ mode = 0600
116
+ }
117
+ if st.Mode()&os.ModeSocket == 0 || st.Mode().Perm() != mode {
118
+ return nil, errTrust
119
+ }
120
+ conn, err := net.DialTimeout("unix", path, 100*time.Millisecond)
121
+ if err == nil {
122
+ conn.Close()
123
+ return nil, errTrust
124
+ }
125
+ if !errors.Is(err, syscall.ECONNREFUSED) {
126
+ return nil, errTrust
127
+ }
128
+ }
129
+ entries[name] = st
130
+ }
131
+ return entries, nil
132
+ }
@@ -0,0 +1,271 @@
1
+ package helper
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "errors"
7
+ "os"
8
+ "path/filepath"
9
+ "syscall"
10
+ "testing"
11
+ )
12
+
13
+ // Write the wire format independently of production constructors. This also
14
+ // checks strict approval parsing and the pre-R2 parser's refusal of lease.
15
+ func repairFixture(t *testing.T) (Controller, *fakeProcesses, string) {
16
+ t.Helper()
17
+ c, f := controlFixture(t)
18
+ f.stopErr = errTrust
19
+ r, err := readRecord(c.StateDir, c.Owner)
20
+ if err != nil {
21
+ t.Fatal(err)
22
+ }
23
+ path := filepath.Join(c.StateDir, "lifetime-"+r.Lifecycle.Epoch+".lock")
24
+ if err := os.WriteFile(path, []byte(r.Lifecycle.Epoch), 0600); err != nil {
25
+ t.Fatal(err)
26
+ }
27
+ st, _ := os.Lstat(path)
28
+ stat := st.Sys().(*syscall.Stat_t)
29
+ b, _ := json.Marshal(r)
30
+ var wire map[string]any
31
+ json.Unmarshal(b, &wire)
32
+ wire["lifecycle"].(map[string]any)["lease"] = map[string]any{"device": uint64(stat.Dev), "inode": stat.Ino}
33
+ b, _ = json.Marshal(wire)
34
+ if err := os.WriteFile(filepath.Join(c.StateDir, "approval.json"), b, 0644); err != nil {
35
+ t.Fatal(err)
36
+ }
37
+ staleSocket(t, filepath.Join(c.RunDir, "helper.sock"))
38
+ staleSocket(t, filepath.Join(c.RunDir, "supervisor.sock"))
39
+ os.Chmod(filepath.Join(c.RunDir, "helper.sock"), 0660)
40
+ os.Chmod(filepath.Join(c.RunDir, "supervisor.sock"), 0600)
41
+ return c, f, path
42
+ }
43
+
44
+ func TestRepairCommitsQuiescenceWithoutSignalOrStart(t *testing.T) {
45
+ for _, disabled := range []bool{false, true} {
46
+ c, f, _ := repairFixture(t)
47
+ if disabled {
48
+ // Wire read will succeed only when the new lease field is implemented.
49
+ r, e := readRecord(c.StateDir, c.Owner)
50
+ if e != nil {
51
+ t.Fatal(e)
52
+ }
53
+ r.Enabled = false
54
+ record(t, c.Client, r)
55
+ }
56
+ if err := c.Control(context.Background(), "repair"); err != nil {
57
+ t.Fatal("repair refused valid lifetime evidence", err)
58
+ }
59
+ r, e := readRecord(c.StateDir, c.Owner)
60
+ if e != nil || r.Residual || r.Enabled == disabled || r.Lifecycle.Phase != "stopped" || r.Lifecycle.Completion == "" {
61
+ t.Fatalf("bad commit: %+v %v", r, e)
62
+ }
63
+ if _, e := completionRecord(c.Client, r); e != nil {
64
+ t.Fatal(e)
65
+ }
66
+ if !runtimeAbsent(c.Client) || f.stopped != 0 || f.started != 0 {
67
+ t.Fatal("repair signalled or started", f)
68
+ }
69
+ if err := c.Control(context.Background(), "repair"); err != nil {
70
+ t.Fatal("retry not idempotent", err)
71
+ }
72
+ if disabled {
73
+ if c.Control(context.Background(), "recover") == nil {
74
+ t.Fatal("disabled repair revived integration")
75
+ }
76
+ } else if err := c.Control(context.Background(), "recover"); err != nil {
77
+ t.Fatal(err)
78
+ }
79
+ }
80
+ }
81
+
82
+ func TestRepairRefusesMissingLegacyBusyAndForeignEvidence(t *testing.T) {
83
+ for _, kind := range []string{"legacy", "pre-r2-m1g", "missing", "symlink", "replacement", "hardlink", "mode", "content", "busy", "foreign-process", "live", "foreign-socket"} {
84
+ t.Run(kind, func(t *testing.T) {
85
+ c, f, path := repairFixture(t)
86
+ switch kind {
87
+ case "legacy":
88
+ record(t, c.Client, Record{Inventory: c.Expected, Enabled: true, Residual: true})
89
+ case "pre-r2-m1g":
90
+ record(t, c.Client, Record{Inventory: c.Expected, Enabled: true, Residual: true, Lifecycle: testLifecycle("fenced")})
91
+ case "missing":
92
+ os.Remove(path)
93
+ case "symlink":
94
+ os.Remove(path)
95
+ os.Symlink("/etc/passwd", path)
96
+ case "replacement":
97
+ os.Rename(path, path+".old")
98
+ os.WriteFile(path, []byte(testLifecycle("running").Epoch), 0600)
99
+ case "hardlink":
100
+ os.Link(path, path+".alias")
101
+ case "mode":
102
+ os.Chmod(path, 0644)
103
+ case "content":
104
+ os.WriteFile(path, []byte("wrong epoch"), 0600)
105
+ case "busy":
106
+ h, e := os.OpenFile(path, os.O_RDWR, 0)
107
+ if e != nil {
108
+ t.Fatal(e)
109
+ }
110
+ defer h.Close()
111
+ if e = syscall.Flock(int(h.Fd()), syscall.LOCK_EX); e != nil {
112
+ t.Fatal(e)
113
+ }
114
+ case "foreign-process":
115
+ p := f.current
116
+ p.Inventory.Version = "9.0.0-9999"
117
+ writeProcess(c.RunDir, p)
118
+ case "live":
119
+ os.Remove(filepath.Join(c.RunDir, "helper.sock"))
120
+ live(t, c.Client, c.Expected, nil)
121
+ case "foreign-socket":
122
+ os.Remove(filepath.Join(c.RunDir, "supervisor.sock"))
123
+ os.WriteFile(filepath.Join(c.RunDir, "supervisor.sock"), []byte("foreign"), 0600)
124
+ }
125
+ if c.Control(context.Background(), "repair") == nil {
126
+ t.Fatal("unsafe repair accepted", kind)
127
+ }
128
+ if _, e := os.Lstat(filepath.Join(c.RunDir, "process.json")); e != nil {
129
+ t.Fatal("failure evidence removed", e)
130
+ }
131
+ if _, e := os.Lstat(filepath.Join(c.RunDir, "helper.sock")); e != nil {
132
+ t.Fatal("partial deletion before preflight", e)
133
+ }
134
+ if f.stopped != 0 || f.started != 0 {
135
+ t.Fatal("repair touched process", f)
136
+ }
137
+ })
138
+ }
139
+ }
140
+
141
+ func TestRepairRetriesInterruptedUnlinkAndOrphanProof(t *testing.T) {
142
+ for _, gap := range []string{"fence", "one-socket", "all-sockets", "all-runtime", "orphan-proof"} {
143
+ t.Run(gap, func(t *testing.T) {
144
+ c, f, _ := repairFixture(t)
145
+ r, e := readRecord(c.StateDir, c.Owner)
146
+ if e != nil {
147
+ t.Fatal(e)
148
+ }
149
+ r.Residual = true
150
+ r.Lifecycle.Phase = "fenced"
151
+ r.Lifecycle.Reason = "admin-repair"
152
+ record(t, c.Client, r)
153
+ if gap != "fence" {
154
+ os.Remove(filepath.Join(c.RunDir, "helper.sock"))
155
+ }
156
+ if gap == "all-sockets" || gap == "all-runtime" || gap == "orphan-proof" {
157
+ os.Remove(filepath.Join(c.RunDir, "supervisor.sock"))
158
+ }
159
+ if gap == "all-runtime" || gap == "orphan-proof" {
160
+ os.Remove(filepath.Join(c.RunDir, "process.json"))
161
+ }
162
+ if gap == "orphan-proof" {
163
+ // A correctly bound private artifact without the approval digest is
164
+ // still an uncommitted repair, not permission to recover.
165
+ proof := Completion{Epoch: r.Lifecycle.Epoch, Repair: &RepairCompletion{Inventory: r.Inventory, Boot: r.Lifecycle.Binding.Boot, Lease: *r.Lifecycle.Lease}}
166
+ if e := writeProtected(c.StateDir, "completion-"+r.Lifecycle.Epoch+".json", proof); e != nil {
167
+ t.Fatal(e)
168
+ }
169
+ }
170
+ if c.Control(context.Background(), "recover") == nil || f.started != 0 {
171
+ t.Fatal("crash gap recovered without repair")
172
+ }
173
+ if e := c.Control(context.Background(), "repair"); e != nil {
174
+ t.Fatal("retry failed", e)
175
+ }
176
+ r, e = readRecord(c.StateDir, c.Owner)
177
+ if e != nil || r.Residual {
178
+ t.Fatal("retry incomplete", e)
179
+ }
180
+ })
181
+ }
182
+ }
183
+
184
+ func TestRepairProofWriteFailureKeepsLatchAfterUnlink(t *testing.T) {
185
+ c, f, _ := repairFixture(t)
186
+ r, e := readRecord(c.StateDir, c.Owner)
187
+ if e != nil {
188
+ t.Fatal(e)
189
+ }
190
+ proof := filepath.Join(c.StateDir, "completion-"+r.Lifecycle.Epoch+".json")
191
+ os.Mkdir(proof, 0700) // deterministic failure after runtime unlink, before proof commit
192
+ if c.Control(context.Background(), "repair") == nil {
193
+ t.Fatal("proof failure committed")
194
+ }
195
+ r, e = readRecord(c.StateDir, c.Owner)
196
+ if e != nil || !r.Residual || r.Lifecycle.Phase != "fenced" || !runtimeAbsent(c.Client) {
197
+ t.Fatal("lost crash intent", e)
198
+ }
199
+ if c.Control(context.Background(), "recover") == nil || f.started != 0 {
200
+ t.Fatal("uncommitted repair revived")
201
+ }
202
+ os.Remove(proof)
203
+ if e := c.Control(context.Background(), "repair"); e != nil {
204
+ t.Fatal(e)
205
+ }
206
+ os.Remove(proof)
207
+ if c.Control(context.Background(), "recover") == nil {
208
+ t.Fatal("missing committed proof accepted")
209
+ }
210
+ }
211
+
212
+ func TestRepairAcrossPayloadRetainsOldApprovalAndRequiresEnable(t *testing.T) {
213
+ c, f, _ := repairFixture(t)
214
+ c.Expected.Version = "2.0.0-0002"
215
+ if e := c.Control(context.Background(), "repair"); e != nil {
216
+ t.Fatal(e)
217
+ }
218
+ r, e := readRecord(c.StateDir, c.Owner)
219
+ if e != nil || r.Inventory.Version != "1.0.0-0001" {
220
+ t.Fatal("repair expanded approval", e)
221
+ }
222
+ if c.Control(context.Background(), "recover") == nil || f.started != 0 {
223
+ t.Fatal("old inventory recovered")
224
+ }
225
+ if e := c.Control(context.Background(), "enable"); e != nil {
226
+ t.Fatal(e)
227
+ }
228
+ }
229
+
230
+ func TestRepairCanceledBeforeMutation(t *testing.T) {
231
+ c, f, _ := repairFixture(t)
232
+ ctx, cancel := context.WithCancel(context.Background())
233
+ cancel()
234
+ if e := c.Control(ctx, "repair"); !errors.Is(e, context.Canceled) {
235
+ t.Fatal(e)
236
+ }
237
+ if f.stopped != 0 || f.started != 0 {
238
+ t.Fatal(f)
239
+ }
240
+ }
241
+
242
+ func TestRepairAfterAutonomousCompletionKeepsLifetimeAuthority(t *testing.T) {
243
+ c, f, _ := repairFixture(t)
244
+ r, err := readRecord(c.StateDir, c.Owner)
245
+ if err != nil {
246
+ t.Fatal(err)
247
+ }
248
+ if err := fenceRecord(c.Client, r.Lifecycle.Epoch, "admin-stop"); err != nil {
249
+ t.Fatal(err)
250
+ }
251
+ if err := cleanRuntime(c.Client, true); err != nil {
252
+ t.Fatal(err)
253
+ }
254
+ if err := completeRecord(c.Client, r.Lifecycle.Epoch, f.current); err != nil {
255
+ t.Fatal(err)
256
+ }
257
+ if err := c.Control(context.Background(), "repair"); err != nil {
258
+ t.Fatal(err)
259
+ }
260
+ got, err := readRecord(c.StateDir, c.Owner)
261
+ if err != nil {
262
+ t.Fatal(err)
263
+ }
264
+ proof, err := completionRecord(c.Client, got)
265
+ if err != nil {
266
+ t.Fatal(err)
267
+ }
268
+ if got.Residual || !got.Enabled || got.Lifecycle.Epoch != r.Lifecycle.Epoch || proof.Repair == nil || f.stopped != 0 || f.started != 0 {
269
+ t.Fatal("Repair lost lifetime authority or touched a PID")
270
+ }
271
+ }