@b00dea/cockpit 0.0.0-bootstrap.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/CHANGELOG.md +375 -0
  2. package/LICENSE +21 -0
  3. package/README.md +21 -1
  4. package/bin/cockpit.mjs +33 -0
  5. package/cockpit.schema.json +2574 -0
  6. package/dist/autonomy.d.ts +44 -0
  7. package/dist/autonomy.js +156 -0
  8. package/dist/bounded-read.d.ts +14 -0
  9. package/dist/bounded-read.js +42 -0
  10. package/dist/browser/commands.d.ts +62 -0
  11. package/dist/browser/commands.js +349 -0
  12. package/dist/browser/package-paths.d.ts +1 -0
  13. package/dist/browser/package-paths.js +6 -0
  14. package/dist/browser/proxy.d.ts +22 -0
  15. package/dist/browser/proxy.js +37 -0
  16. package/dist/browser/runtime.d.ts +117 -0
  17. package/dist/browser/runtime.js +183 -0
  18. package/dist/browser/surfaces.d.ts +141 -0
  19. package/dist/browser/surfaces.js +556 -0
  20. package/dist/browser/ui-gate.d.ts +15 -0
  21. package/dist/browser/ui-gate.js +18 -0
  22. package/dist/cli-guard.d.ts +5 -0
  23. package/dist/cli-guard.js +71 -0
  24. package/dist/cli-main.d.ts +139 -0
  25. package/dist/cli-main.js +1405 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.js +16 -0
  28. package/dist/command-table.d.ts +113 -0
  29. package/dist/command-table.js +512 -0
  30. package/dist/config/load.d.ts +171 -0
  31. package/dist/config/load.js +345 -0
  32. package/dist/config/sibling-toml.d.ts +48 -0
  33. package/dist/config/sibling-toml.js +160 -0
  34. package/dist/config/surface-tools-toml.d.ts +9 -0
  35. package/dist/config/surface-tools-toml.js +37 -0
  36. package/dist/config/verified-write.d.ts +43 -0
  37. package/dist/config/verified-write.js +89 -0
  38. package/dist/diagnostics.d.ts +26 -0
  39. package/dist/diagnostics.js +335 -0
  40. package/dist/emit.d.ts +22 -0
  41. package/dist/emit.js +43 -0
  42. package/dist/entrypoint-kinds.d.ts +3 -0
  43. package/dist/entrypoint-kinds.js +11 -0
  44. package/dist/environment/application/destructive.d.ts +6 -0
  45. package/dist/environment/application/destructive.js +425 -0
  46. package/dist/environment/application/doctor.d.ts +89 -0
  47. package/dist/environment/application/doctor.js +235 -0
  48. package/dist/environment/application/guard.d.ts +43 -0
  49. package/dist/environment/application/guard.js +622 -0
  50. package/dist/environment/application/health.d.ts +134 -0
  51. package/dist/environment/application/health.js +379 -0
  52. package/dist/environment/application/lifecycle-context.d.ts +228 -0
  53. package/dist/environment/application/lifecycle-context.js +154 -0
  54. package/dist/environment/application/lifecycle-state.d.ts +25 -0
  55. package/dist/environment/application/lifecycle-state.js +201 -0
  56. package/dist/environment/application/lifecycle.d.ts +17 -0
  57. package/dist/environment/application/lifecycle.js +729 -0
  58. package/dist/environment/application/logs.d.ts +45 -0
  59. package/dist/environment/application/logs.js +127 -0
  60. package/dist/environment/application/setup.d.ts +129 -0
  61. package/dist/environment/application/setup.js +741 -0
  62. package/dist/environment/application/shared.d.ts +11 -0
  63. package/dist/environment/application/shared.js +61 -0
  64. package/dist/environment/claims.d.ts +389 -0
  65. package/dist/environment/claims.js +1709 -0
  66. package/dist/environment/codex-hook-trust.d.ts +11 -0
  67. package/dist/environment/codex-hook-trust.js +185 -0
  68. package/dist/environment/compose-environment.d.ts +1 -0
  69. package/dist/environment/compose-environment.js +6 -0
  70. package/dist/environment/compose-ownership.d.ts +21 -0
  71. package/dist/environment/compose-ownership.js +117 -0
  72. package/dist/environment/compose-topology.d.ts +117 -0
  73. package/dist/environment/compose-topology.js +413 -0
  74. package/dist/environment/contract.d.ts +489 -0
  75. package/dist/environment/contract.js +761 -0
  76. package/dist/environment/declaration.d.ts +14 -0
  77. package/dist/environment/declaration.js +39 -0
  78. package/dist/environment/destructive-composition.d.ts +29 -0
  79. package/dist/environment/destructive-composition.js +333 -0
  80. package/dist/environment/docker-daemon.d.ts +30 -0
  81. package/dist/environment/docker-daemon.js +78 -0
  82. package/dist/environment/docker-endpoint.d.ts +10 -0
  83. package/dist/environment/docker-endpoint.js +19 -0
  84. package/dist/environment/env-schema-observation.d.ts +46 -0
  85. package/dist/environment/env-schema-observation.js +241 -0
  86. package/dist/environment/evidence.d.ts +136 -0
  87. package/dist/environment/evidence.js +437 -0
  88. package/dist/environment/executable.d.ts +26 -0
  89. package/dist/environment/executable.js +167 -0
  90. package/dist/environment/generated-application/authorities.d.ts +5 -0
  91. package/dist/environment/generated-application/authorities.js +61 -0
  92. package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
  93. package/dist/environment/generated-application/bootstrap-skill.js +328 -0
  94. package/dist/environment/generated-application/check.d.ts +13 -0
  95. package/dist/environment/generated-application/check.js +189 -0
  96. package/dist/environment/generated-application/custom-surface.d.ts +26 -0
  97. package/dist/environment/generated-application/custom-surface.js +289 -0
  98. package/dist/environment/generated-application/prepare.d.ts +29 -0
  99. package/dist/environment/generated-application/prepare.js +276 -0
  100. package/dist/environment/generated-application/publication.d.ts +33 -0
  101. package/dist/environment/generated-application/publication.js +547 -0
  102. package/dist/environment/generated-application/shared.d.ts +484 -0
  103. package/dist/environment/generated-application/shared.js +349 -0
  104. package/dist/environment/generated-application/surface-observation.d.ts +4 -0
  105. package/dist/environment/generated-application/surface-observation.js +69 -0
  106. package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
  107. package/dist/environment/generated-application/surface-outputs.js +389 -0
  108. package/dist/environment/generated-application/surfaces.d.ts +3 -0
  109. package/dist/environment/generated-application/surfaces.js +699 -0
  110. package/dist/environment/generated-application/sync.d.ts +6 -0
  111. package/dist/environment/generated-application/sync.js +109 -0
  112. package/dist/environment/git-observation.d.ts +183 -0
  113. package/dist/environment/git-observation.js +544 -0
  114. package/dist/environment/health-composition.d.ts +11 -0
  115. package/dist/environment/health-composition.js +628 -0
  116. package/dist/environment/host-observation.d.ts +56 -0
  117. package/dist/environment/host-observation.js +52 -0
  118. package/dist/environment/identity.d.ts +48 -0
  119. package/dist/environment/identity.js +85 -0
  120. package/dist/environment/init-application.d.ts +308 -0
  121. package/dist/environment/init-application.js +697 -0
  122. package/dist/environment/install-policy-observation.d.ts +71 -0
  123. package/dist/environment/install-policy-observation.js +284 -0
  124. package/dist/environment/install-policy.d.ts +48 -0
  125. package/dist/environment/install-policy.js +96 -0
  126. package/dist/environment/instance.d.ts +33 -0
  127. package/dist/environment/instance.js +122 -0
  128. package/dist/environment/instruction-pointer.d.ts +19 -0
  129. package/dist/environment/instruction-pointer.js +144 -0
  130. package/dist/environment/lifecycle-composition.d.ts +29 -0
  131. package/dist/environment/lifecycle-composition.js +675 -0
  132. package/dist/environment/lifecycle-stage.d.ts +115 -0
  133. package/dist/environment/lifecycle-stage.js +398 -0
  134. package/dist/environment/lifecycle.d.ts +75 -0
  135. package/dist/environment/lifecycle.js +354 -0
  136. package/dist/environment/logs.d.ts +132 -0
  137. package/dist/environment/logs.js +519 -0
  138. package/dist/environment/observations.d.ts +46 -0
  139. package/dist/environment/observations.js +344 -0
  140. package/dist/environment/operator-application.d.ts +50 -0
  141. package/dist/environment/operator-application.js +155 -0
  142. package/dist/environment/ports.d.ts +182 -0
  143. package/dist/environment/ports.js +1205 -0
  144. package/dist/environment/posture-observation.d.ts +68 -0
  145. package/dist/environment/posture-observation.js +253 -0
  146. package/dist/environment/read-composition.d.ts +27 -0
  147. package/dist/environment/read-composition.js +352 -0
  148. package/dist/environment/readiness-composition.d.ts +38 -0
  149. package/dist/environment/readiness-composition.js +130 -0
  150. package/dist/environment/reclaim.d.ts +333 -0
  151. package/dist/environment/reclaim.js +1835 -0
  152. package/dist/environment/repository-identity.d.ts +13 -0
  153. package/dist/environment/repository-identity.js +108 -0
  154. package/dist/environment/runtime-measurement-record.d.ts +38 -0
  155. package/dist/environment/runtime-measurement-record.js +111 -0
  156. package/dist/environment/runtime-measurement.d.ts +27 -0
  157. package/dist/environment/runtime-measurement.js +224 -0
  158. package/dist/environment/runtime-probe-residue.d.ts +43 -0
  159. package/dist/environment/runtime-probe-residue.js +148 -0
  160. package/dist/environment/runtime-probe.d.ts +72 -0
  161. package/dist/environment/runtime-probe.js +725 -0
  162. package/dist/environment/runtime.d.ts +505 -0
  163. package/dist/environment/runtime.js +2335 -0
  164. package/dist/environment/seed.d.ts +16 -0
  165. package/dist/environment/seed.js +43 -0
  166. package/dist/environment/selftest-application.d.ts +86 -0
  167. package/dist/environment/selftest-application.js +713 -0
  168. package/dist/environment/sensitive.d.ts +3 -0
  169. package/dist/environment/sensitive.js +48 -0
  170. package/dist/environment/setup-observation.d.ts +62 -0
  171. package/dist/environment/setup-observation.js +1473 -0
  172. package/dist/environment/setup.d.ts +43 -0
  173. package/dist/environment/setup.js +176 -0
  174. package/dist/environment/sibling-instructions.d.ts +33 -0
  175. package/dist/environment/sibling-instructions.js +224 -0
  176. package/dist/environment/sibling-registration.d.ts +45 -0
  177. package/dist/environment/sibling-registration.js +538 -0
  178. package/dist/environment/state.d.ts +371 -0
  179. package/dist/environment/state.js +2013 -0
  180. package/dist/environment/templates.d.ts +140 -0
  181. package/dist/environment/templates.js +685 -0
  182. package/dist/environment/tool-registration.d.ts +9 -0
  183. package/dist/environment/tool-registration.js +96 -0
  184. package/dist/environment/upgrade-application.d.ts +19 -0
  185. package/dist/environment/upgrade-application.js +175 -0
  186. package/dist/environment-exec/execute.d.ts +102 -0
  187. package/dist/environment-exec/execute.js +1175 -0
  188. package/dist/environment-exec/libexec-program.d.ts +6 -0
  189. package/dist/environment-exec/libexec-program.js +22 -0
  190. package/dist/environment-exec/verified-digest.d.ts +4 -0
  191. package/dist/environment-exec/verified-digest.js +16 -0
  192. package/dist/exact-keys.d.ts +7 -0
  193. package/dist/exact-keys.js +15 -0
  194. package/dist/fix-catalogue.d.ts +32 -0
  195. package/dist/fix-catalogue.js +60 -0
  196. package/dist/freshness.d.ts +29 -0
  197. package/dist/freshness.js +75 -0
  198. package/dist/generated-environment/adopt.d.ts +16 -0
  199. package/dist/generated-environment/adopt.js +275 -0
  200. package/dist/generated-environment/command.d.ts +47 -0
  201. package/dist/generated-environment/command.js +75 -0
  202. package/dist/generated-environment/transaction.d.ts +186 -0
  203. package/dist/generated-environment/transaction.js +1770 -0
  204. package/dist/grading/evaluate.d.ts +71 -0
  205. package/dist/grading/evaluate.js +403 -0
  206. package/dist/grading/grade.d.ts +33 -0
  207. package/dist/grading/grade.js +57 -0
  208. package/dist/guards/evaluator.d.ts +113 -0
  209. package/dist/guards/evaluator.js +1226 -0
  210. package/dist/guards/harness-adapter.d.ts +17 -0
  211. package/dist/guards/harness-adapter.js +57 -0
  212. package/dist/guards/host.d.ts +8 -0
  213. package/dist/guards/host.js +10 -0
  214. package/dist/guards/invocation-parser.d.ts +66 -0
  215. package/dist/guards/invocation-parser.js +595 -0
  216. package/dist/guards/local-identity.d.ts +40 -0
  217. package/dist/guards/local-identity.js +123 -0
  218. package/dist/guards/policy-pin.d.ts +13 -0
  219. package/dist/guards/policy-pin.js +175 -0
  220. package/dist/guards/protected-locations.d.ts +62 -0
  221. package/dist/guards/protected-locations.js +461 -0
  222. package/dist/guards/read-only.d.ts +37 -0
  223. package/dist/guards/read-only.js +315 -0
  224. package/dist/init/command.d.ts +40 -0
  225. package/dist/init/command.js +310 -0
  226. package/dist/init/derive.d.ts +51 -0
  227. package/dist/init/derive.js +715 -0
  228. package/dist/init/draft.d.ts +138 -0
  229. package/dist/init/draft.js +1205 -0
  230. package/dist/init/render.d.ts +35 -0
  231. package/dist/init/render.js +82 -0
  232. package/dist/init/scaffold.d.ts +53 -0
  233. package/dist/init/scaffold.js +121 -0
  234. package/dist/invocation.d.ts +13 -0
  235. package/dist/invocation.js +20 -0
  236. package/dist/package-metadata.d.ts +9 -0
  237. package/dist/package-metadata.js +19 -0
  238. package/dist/readiness.d.ts +53 -0
  239. package/dist/readiness.js +88 -0
  240. package/dist/references/named.d.ts +24 -0
  241. package/dist/references/named.js +27 -0
  242. package/dist/refusal.d.ts +15 -0
  243. package/dist/refusal.js +7 -0
  244. package/dist/registry-derivation.d.ts +31 -0
  245. package/dist/registry-derivation.js +32 -0
  246. package/dist/registry-resolve/command.d.ts +47 -0
  247. package/dist/registry-resolve/command.js +226 -0
  248. package/dist/registry-resolve/registry.d.ts +68 -0
  249. package/dist/registry-resolve/registry.js +292 -0
  250. package/dist/registry-resolve/render-shell.d.ts +18 -0
  251. package/dist/registry-resolve/render-shell.js +36 -0
  252. package/dist/repair.d.ts +29 -0
  253. package/dist/repair.js +8 -0
  254. package/dist/schema-json.d.ts +1 -0
  255. package/dist/schema-json.js +177 -0
  256. package/dist/schema.d.ts +1322 -0
  257. package/dist/schema.js +934 -0
  258. package/dist/setup/command.d.ts +4 -0
  259. package/dist/setup/command.js +4 -0
  260. package/dist/sha256.d.ts +1 -0
  261. package/dist/sha256.js +4 -0
  262. package/dist/surfaces/adoption.d.ts +41 -0
  263. package/dist/surfaces/adoption.js +217 -0
  264. package/dist/surfaces/consumer-instructions.d.ts +20 -0
  265. package/dist/surfaces/consumer-instructions.js +43 -0
  266. package/dist/surfaces/contract.d.ts +42 -0
  267. package/dist/surfaces/contract.js +169 -0
  268. package/dist/surfaces/core-declarations.d.ts +24 -0
  269. package/dist/surfaces/core-declarations.js +79 -0
  270. package/dist/surfaces/development-markers.d.ts +1 -0
  271. package/dist/surfaces/development-markers.js +18 -0
  272. package/dist/surfaces/generator-adapter.d.ts +71 -0
  273. package/dist/surfaces/generator-adapter.js +809 -0
  274. package/dist/surfaces/harness-registry.d.ts +180 -0
  275. package/dist/surfaces/harness-registry.js +117 -0
  276. package/dist/surfaces/mcp.d.ts +95 -0
  277. package/dist/surfaces/mcp.js +186 -0
  278. package/dist/surfaces/merge.d.ts +30 -0
  279. package/dist/surfaces/merge.js +105 -0
  280. package/dist/surfaces/ownership.d.ts +190 -0
  281. package/dist/surfaces/ownership.js +795 -0
  282. package/dist/surfaces/projection.d.ts +136 -0
  283. package/dist/surfaces/projection.js +681 -0
  284. package/dist/surfaces/render.d.ts +118 -0
  285. package/dist/surfaces/render.js +633 -0
  286. package/dist/surfaces/restrictions.d.ts +130 -0
  287. package/dist/surfaces/restrictions.js +447 -0
  288. package/dist/surfaces/selftest.d.ts +162 -0
  289. package/dist/surfaces/selftest.js +393 -0
  290. package/dist/surfaces/skill-contract.d.ts +85 -0
  291. package/dist/surfaces/skill-contract.js +449 -0
  292. package/dist/surfaces/sync.d.ts +57 -0
  293. package/dist/surfaces/sync.js +164 -0
  294. package/dist/team-metadata.d.ts +41 -0
  295. package/dist/team-metadata.js +512 -0
  296. package/dist/testing/gates.d.ts +91 -0
  297. package/dist/testing/gates.js +182 -0
  298. package/dist/testing/hooks.d.ts +59 -0
  299. package/dist/testing/hooks.js +139 -0
  300. package/dist/testing/verdict.d.ts +29 -0
  301. package/dist/testing/verdict.js +62 -0
  302. package/dist/work-orders/application.d.ts +99 -0
  303. package/dist/work-orders/application.js +383 -0
  304. package/dist/work-orders/composition.d.ts +124 -0
  305. package/dist/work-orders/composition.js +1010 -0
  306. package/dist/work-orders/contract.d.ts +61 -0
  307. package/dist/work-orders/contract.js +122 -0
  308. package/dist/work-orders/store.d.ts +158 -0
  309. package/dist/work-orders/store.js +197 -0
  310. package/docs/README.md +65 -0
  311. package/docs/architecture.md +136 -0
  312. package/docs/capability-matrix.md +50 -0
  313. package/docs/cli-reference.md +599 -0
  314. package/docs/command-list.md +51 -0
  315. package/docs/compose-patterns.md +99 -0
  316. package/docs/concepts.md +171 -0
  317. package/docs/configuration-essentials.md +172 -0
  318. package/docs/configuration-reference.md +621 -0
  319. package/docs/environment.md +760 -0
  320. package/docs/extending.md +43 -0
  321. package/docs/faq.md +111 -0
  322. package/docs/getting-started.md +608 -0
  323. package/docs/harness-surfaces.md +433 -0
  324. package/docs/joining-a-team.md +76 -0
  325. package/docs/release-policy.md +49 -0
  326. package/docs/safety-and-autonomy.md +419 -0
  327. package/docs/troubleshooting.md +361 -0
  328. package/docs/tutorial.md +170 -0
  329. package/docs/work-and-browser.md +254 -0
  330. package/libexec/browser-operation.cjs +186 -0
  331. package/libexec/fence-marker.cjs +101 -0
  332. package/libexec/fence-marker.d.cts +24 -0
  333. package/libexec/fenced-group-runner.cjs +77 -0
  334. package/libexec/fenced-supervisor.cjs +137 -0
  335. package/libexec/generated-filesystem.cjs +731 -0
  336. package/libexec/install-filesystem.cjs +225 -0
  337. package/libexec/rulesync-generator.NOTICE.md +1112 -0
  338. package/libexec/rulesync-generator.cjs +743 -0
  339. package/libexec/surface-generator-worker.cjs +266 -0
  340. package/libexec/surface-output-reader.cjs +99 -0
  341. package/libexec/surface-scratch-cleanup.cjs +14 -0
  342. package/libexec/validate-harness-evidence.d.mts +183 -0
  343. package/libexec/validate-harness-evidence.mjs +1312 -0
  344. package/package.json +76 -1
  345. package/surfaces/README.md +33 -0
  346. package/surfaces/agents/evaluator.agent.md +76 -0
  347. package/surfaces/guards/bash-guard.sh +48 -0
  348. package/surfaces/guards/claude.adapter.json +25 -0
  349. package/surfaces/guards/codex.adapter.json +24 -0
  350. package/surfaces/guards/opencode.adapter.json +25 -0
  351. package/surfaces/references/browser.md +63 -0
  352. package/surfaces/references/test-data-and-personas.md +84 -0
  353. package/surfaces/references/testing-tiers.md +11 -0
  354. package/surfaces/skills/cockpit-browser.skill.md +54 -0
  355. package/surfaces/skills/cockpit-explain.skill.md +32 -0
  356. package/surfaces/skills/cockpit-fix.skill.md +37 -0
  357. package/surfaces/skills/cockpit-setup.skill.md +39 -0
  358. package/surfaces/skills/cockpit-work.skill.md +34 -0
  359. package/surfaces/skills/collection.json +5 -0
  360. package/surfaces/skills/procedures/explain.md +61 -0
  361. package/surfaces/skills/procedures/fix.md +81 -0
  362. package/surfaces/skills/procedures/setup.md +379 -0
  363. package/surfaces/skills/procedures/work.md +105 -0
@@ -0,0 +1,77 @@
1
+ 'use strict'
2
+
3
+ // Runs one fenced action as the leader of its own process group, under libexec/fenced-supervisor.cjs.
4
+ //
5
+ // argv: <config>, base64url JSON { command, args, argv0, cwd, spawnNotAfter, fence, approved }, where
6
+ // `approved` is the active marker the executor published ({ supervisorPid, markerDev, markerIno,
7
+ // parentDev, parentIno }).
8
+ // fd 3 to the supervisor: 'EXPIRED\n' when the spawn deadline had passed (the action never starts),
9
+ // otherwise exactly one 'DONE <exit code>\n' when the action closes.
10
+ // stdin from the supervisor: 'STOP\n' stops the group. Any other input, or stdin closing without it,
11
+ // means the supervisor is gone: the runner then records a 'terminating' marker naming its group, so
12
+ // a later repair can prove the group ended, before it stops the group itself.
13
+ const { spawn } = require('node:child_process')
14
+ const fs = require('node:fs')
15
+ const path = require('node:path')
16
+ const { replaceApprovedActiveMarker, syncDirectory } = require('./fence-marker.cjs')
17
+
18
+ const STOP_KILL_DELAY_MS = 50
19
+
20
+ const config = JSON.parse(Buffer.from(process.argv[2], 'base64url').toString('utf8'))
21
+ const { fence, approved } = config
22
+
23
+ // The group ends only through SIGKILL below, after the action had its SIGTERM; a stray terminal
24
+ // signal must not take the runner down and orphan the action outside its fence.
25
+ process.on('SIGTERM', () => {})
26
+ process.on('SIGINT', () => {})
27
+
28
+ const expired = config.spawnNotAfter !== undefined && Date.now() > Date.parse(config.spawnNotAfter)
29
+ const child = expired ? undefined : spawn(config.command, config.args, {
30
+ argv0: config.argv0, cwd: config.cwd, env: process.env, stdio: ['ignore', 'inherit', 'inherit'],
31
+ })
32
+ let reported = false
33
+ const report = code => {
34
+ if (reported) return
35
+ reported = true
36
+ fs.writeSync(3, `DONE ${Number.isInteger(code) ? code : 1}\n`)
37
+ }
38
+ if (expired) fs.writeSync(3, 'EXPIRED\n')
39
+ else {
40
+ child.once('error', () => report(1))
41
+ child.once('close', code => report(code))
42
+ }
43
+
44
+ function publishTerminating() {
45
+ if (!replaceApprovedActiveMarker(fence, approved, 'runner', { status: 'terminating', groupPid: process.pid })) return false
46
+ try {
47
+ try { fs.unlinkSync(fence.socketPath) } catch (error) { if (error.code !== 'ENOENT') return false }
48
+ syncDirectory(path.dirname(fence.socketPath))
49
+ return true
50
+ } catch {
51
+ // The 'terminating' marker is already durable; repair still waits for the socket to go.
52
+ return false
53
+ }
54
+ }
55
+
56
+ let stopping = false
57
+ let controlled = false
58
+ function stop(supervisorLost) {
59
+ if (stopping) return
60
+ if (supervisorLost) publishTerminating()
61
+ stopping = true
62
+ process.kill(-process.pid, 'SIGTERM')
63
+ setTimeout(() => process.kill(-process.pid, 'SIGKILL'), STOP_KILL_DELAY_MS)
64
+ }
65
+
66
+ let input = ''
67
+ process.stdin.setEncoding('utf8')
68
+ process.stdin.on('data', chunk => {
69
+ input += chunk
70
+ if (stopping || !input.includes('\n')) return
71
+ if (input !== 'STOP\n') return stop(true)
72
+ controlled = true
73
+ stop(false)
74
+ })
75
+ process.stdin.on('end', () => { if (!controlled) stop(true) })
76
+ // Keeps the runner alive after the action closes, until the supervisor sends STOP.
77
+ setInterval(() => {}, 1000)
@@ -0,0 +1,137 @@
1
+ 'use strict'
2
+
3
+ // Supervises one fenced action for the executor (packages/cockpit/src/environment-exec/execute.ts) so
4
+ // that an attempt whose executor died can still be ended and proven gone by `repairFencedExecution`.
5
+ //
6
+ // argv: <config>, base64url JSON { command, args, argv0, cwd, spawnNotAfter, fence }.
7
+ // fd 3 to the executor: 'READY\n' once the repair socket listens; 'EXPIRED\n' before exiting when the
8
+ // action was never released because its spawn deadline passed or the executor cancelled it.
9
+ // stdin from the executor: one release line, 'GO' or 'CANCEL', then the attempt id and the device and
10
+ // inode of the active marker and its parent directory that the executor published. Anything else exits.
11
+ // repair socket: a client that writes the attempt id is answered { attemptId, supervisorPid } and the
12
+ // action is stopped.
13
+ // exit code: the action's exit code, or 125 when the fence could not be kept (protocol violation, the
14
+ // runner lost, or no durable 'terminated' marker). The supervisor exits only after the action's process
15
+ // group is gone and the marker reads 'terminated', so that marker proves nothing of the attempt runs.
16
+ const { spawn } = require('node:child_process')
17
+ const { createServer } = require('node:net')
18
+ const fs = require('node:fs')
19
+ const path = require('node:path')
20
+ const { replaceApprovedActiveMarker } = require('./fence-marker.cjs')
21
+
22
+ const FENCE_LOST = 125
23
+ const GROUP_EXIT_WAIT_MS = 2000
24
+ const RUNNER = path.join(__dirname, 'fenced-group-runner.cjs')
25
+
26
+ const config = JSON.parse(Buffer.from(process.argv[2], 'base64url').toString('utf8'))
27
+ const { fence } = config
28
+
29
+ let action
30
+ let approved
31
+ let started = false
32
+ let finished = false
33
+ let terminating = false
34
+ let expired = false
35
+ let actionCode = 1
36
+
37
+ const groupGone = pid => {
38
+ try { process.kill(-pid, 0); return false } catch (error) { return error.code === 'ESRCH' }
39
+ }
40
+ const removeSocket = () => {
41
+ try { fs.unlinkSync(fence.socketPath) } catch { /* already absent; repair checks absence itself */ }
42
+ }
43
+ const abandon = () => {
44
+ removeSocket()
45
+ process.exit(FENCE_LOST)
46
+ }
47
+ const publishTerminated = () => approved !== undefined && replaceApprovedActiveMarker(
48
+ fence, { ...approved, supervisorPid: process.pid }, 'supervisor',
49
+ { status: 'terminated', finishedAt: new Date().toISOString() },
50
+ )
51
+
52
+ const server = createServer(socket => {
53
+ let request = ''
54
+ socket.setEncoding('utf8')
55
+ socket.on('data', chunk => {
56
+ request += chunk
57
+ if (request.length > 256) return socket.destroy()
58
+ if (!request.includes('\n')) return
59
+ if (request.trim() !== fence.attemptId) return socket.destroy()
60
+ socket.end(`${JSON.stringify({ attemptId: fence.attemptId, supervisorPid: process.pid })}\n`)
61
+ terminate()
62
+ })
63
+ })
64
+
65
+ function finish(deadline) {
66
+ if (finished) return
67
+ if (action && !groupGone(action.pid)) {
68
+ if (Date.now() >= deadline) return abandon()
69
+ return setTimeout(() => finish(deadline), 10)
70
+ }
71
+ finished = true
72
+ server.close()
73
+ removeSocket()
74
+ if (!publishTerminated()) process.exit(FENCE_LOST)
75
+ if (expired) fs.writeSync(3, 'EXPIRED\n')
76
+ process.exit(actionCode)
77
+ }
78
+
79
+ function terminate(code) {
80
+ if (!action || terminating) return
81
+ terminating = true
82
+ actionCode = Number.isInteger(code) ? code : 1
83
+ // A stop line that cannot be written means the action is unreachable; abandon exits with the fence-lost status.
84
+ try { action.stdin.end('STOP\n') } catch { abandon() }
85
+ }
86
+
87
+ function startAction() {
88
+ const runnerConfig = Buffer.from(JSON.stringify({
89
+ command: config.command, args: config.args, argv0: config.argv0, cwd: config.cwd,
90
+ spawnNotAfter: config.spawnNotAfter, fence, approved: { ...approved, supervisorPid: process.pid },
91
+ })).toString('base64url')
92
+ action = spawn(process.execPath, ['--', RUNNER, runnerConfig], {
93
+ cwd: config.cwd, env: process.env, stdio: ['pipe', 'inherit', 'inherit', 'pipe'], detached: true,
94
+ })
95
+ let control = ''
96
+ action.stdio[3].setEncoding('utf8')
97
+ action.stdio[3].on('data', chunk => {
98
+ control += chunk
99
+ if (control.length > 64) return abandon()
100
+ if (!control.includes('\n')) return
101
+ if (control === 'EXPIRED\n') {
102
+ expired = true
103
+ return terminate(1)
104
+ }
105
+ const done = /^DONE (-?[0-9]+)\n$/.exec(control)
106
+ if (!done) return abandon()
107
+ terminate(Number(done[1]))
108
+ })
109
+ action.once('error', abandon)
110
+ action.once('close', () => {
111
+ if (!terminating) return abandon()
112
+ finish(Date.now() + GROUP_EXIT_WAIT_MS)
113
+ })
114
+ }
115
+
116
+ try { fs.unlinkSync(fence.socketPath) } catch (error) { if (error.code !== 'ENOENT') process.exit(FENCE_LOST) }
117
+ server.listen(fence.socketPath, () => fs.writeSync(3, 'READY\n'))
118
+
119
+ let release = ''
120
+ process.stdin.setEncoding('utf8')
121
+ process.stdin.on('data', chunk => {
122
+ release += chunk
123
+ if (started || !release.includes('\n')) return
124
+ const fields = release.trim().split(' ')
125
+ if (fields.length !== 6 || (fields[0] !== 'GO' && fields[0] !== 'CANCEL') || fields[1] !== fence.attemptId
126
+ || fields.slice(2).some(value => !/^[0-9]+$/.test(value))) return abandon()
127
+ approved = { markerDev: fields[2], markerIno: fields[3], parentDev: fields[4], parentIno: fields[5] }
128
+ started = true
129
+ if (fields[0] === 'CANCEL' || config.spawnNotAfter !== undefined && Date.now() > Date.parse(config.spawnNotAfter)) {
130
+ expired = true
131
+ return finish(Date.now() + GROUP_EXIT_WAIT_MS)
132
+ }
133
+ startAction()
134
+ })
135
+ process.stdin.on('end', () => { if (!started) abandon() })
136
+ process.on('SIGTERM', () => terminate(1))
137
+ process.on('SIGINT', () => terminate(1))