@shipfox/api-runners 5.0.0 → 7.0.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 (400) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/CHANGELOG.md +80 -0
  3. package/dist/config.d.ts +5 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +54 -7
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/demand.d.ts +6 -6
  8. package/dist/core/demand.d.ts.map +1 -1
  9. package/dist/core/demand.js +10 -10
  10. package/dist/core/demand.js.map +1 -1
  11. package/dist/core/entities/ephemeral-registration-token.d.ts +1 -1
  12. package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -1
  13. package/dist/core/entities/ephemeral-registration-token.js.map +1 -1
  14. package/dist/core/entities/provisioner-capability-snapshot.d.ts +13 -0
  15. package/dist/core/entities/provisioner-capability-snapshot.d.ts.map +1 -0
  16. package/dist/core/entities/provisioner-capability-snapshot.js +3 -0
  17. package/dist/core/entities/provisioner-capability-snapshot.js.map +1 -0
  18. package/dist/core/entities/provisioner-token.d.ts +10 -2
  19. package/dist/core/entities/provisioner-token.d.ts.map +1 -1
  20. package/dist/core/entities/provisioner-token.js.map +1 -1
  21. package/dist/core/entities/{provisioned-runner.d.ts → runner-instance.d.ts} +7 -6
  22. package/dist/core/entities/runner-instance.d.ts.map +1 -0
  23. package/dist/core/entities/runner-instance.js +3 -0
  24. package/dist/core/entities/runner-instance.js.map +1 -0
  25. package/dist/core/entities/runner-session.d.ts +4 -2
  26. package/dist/core/entities/runner-session.d.ts.map +1 -1
  27. package/dist/core/entities/runner-session.js.map +1 -1
  28. package/dist/core/ephemeral-registration-tokens.d.ts +5 -5
  29. package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -1
  30. package/dist/core/ephemeral-registration-tokens.js +12 -12
  31. package/dist/core/ephemeral-registration-tokens.js.map +1 -1
  32. package/dist/core/errors.d.ts +16 -4
  33. package/dist/core/errors.d.ts.map +1 -1
  34. package/dist/core/errors.js +22 -4
  35. package/dist/core/errors.js.map +1 -1
  36. package/dist/core/index.d.ts +9 -5
  37. package/dist/core/index.d.ts.map +1 -1
  38. package/dist/core/index.js +6 -3
  39. package/dist/core/index.js.map +1 -1
  40. package/dist/core/job-executions.d.ts +2 -0
  41. package/dist/core/job-executions.d.ts.map +1 -1
  42. package/dist/core/job-executions.js +1 -2
  43. package/dist/core/job-executions.js.map +1 -1
  44. package/dist/core/maintenance.d.ts +1 -1
  45. package/dist/core/maintenance.d.ts.map +1 -1
  46. package/dist/core/maintenance.js +5 -5
  47. package/dist/core/maintenance.js.map +1 -1
  48. package/dist/core/provisioner-capability-snapshots.d.ts +5 -0
  49. package/dist/core/provisioner-capability-snapshots.d.ts.map +1 -0
  50. package/dist/core/provisioner-capability-snapshots.js +10 -0
  51. package/dist/core/provisioner-capability-snapshots.js.map +1 -0
  52. package/dist/core/provisioner-tokens.d.ts +10 -0
  53. package/dist/core/provisioner-tokens.d.ts.map +1 -1
  54. package/dist/core/provisioner-tokens.js +23 -1
  55. package/dist/core/provisioner-tokens.js.map +1 -1
  56. package/dist/core/rate-limit.d.ts.map +1 -1
  57. package/dist/core/rate-limit.js +2 -7
  58. package/dist/core/rate-limit.js.map +1 -1
  59. package/dist/core/runner-activation.d.ts +13 -0
  60. package/dist/core/runner-activation.d.ts.map +1 -0
  61. package/dist/core/runner-activation.js +36 -0
  62. package/dist/core/runner-activation.js.map +1 -0
  63. package/dist/core/runner-assignments.d.ts +6 -0
  64. package/dist/core/runner-assignments.d.ts.map +1 -0
  65. package/dist/core/runner-assignments.js +6 -0
  66. package/dist/core/runner-assignments.js.map +1 -0
  67. package/dist/core/runner-control-sessions.d.ts +46 -0
  68. package/dist/core/runner-control-sessions.d.ts.map +1 -0
  69. package/dist/core/runner-control-sessions.js +121 -0
  70. package/dist/core/runner-control-sessions.js.map +1 -0
  71. package/dist/core/runner-instances.d.ts +72 -0
  72. package/dist/core/runner-instances.d.ts.map +1 -0
  73. package/dist/core/runner-instances.js +165 -0
  74. package/dist/core/runner-instances.js.map +1 -0
  75. package/dist/core/runner-sessions.d.ts +8 -2
  76. package/dist/core/runner-sessions.d.ts.map +1 -1
  77. package/dist/core/runner-sessions.js +8 -5
  78. package/dist/core/runner-sessions.js.map +1 -1
  79. package/dist/db/db.d.ts +2698 -1054
  80. package/dist/db/db.d.ts.map +1 -1
  81. package/dist/db/db.js +9 -2
  82. package/dist/db/db.js.map +1 -1
  83. package/dist/db/ephemeral-registration-tokens.d.ts +2 -2
  84. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
  85. package/dist/db/ephemeral-registration-tokens.js +21 -21
  86. package/dist/db/ephemeral-registration-tokens.js.map +1 -1
  87. package/dist/db/index.d.ts +7 -4
  88. package/dist/db/index.d.ts.map +1 -1
  89. package/dist/db/index.js +5 -2
  90. package/dist/db/index.js.map +1 -1
  91. package/dist/db/job-executions.d.ts +6 -6
  92. package/dist/db/job-executions.d.ts.map +1 -1
  93. package/dist/db/job-executions.js +20 -19
  94. package/dist/db/job-executions.js.map +1 -1
  95. package/dist/db/provisioner-capability-snapshots.d.ts +21 -0
  96. package/dist/db/provisioner-capability-snapshots.d.ts.map +1 -0
  97. package/dist/db/provisioner-capability-snapshots.js +57 -0
  98. package/dist/db/provisioner-capability-snapshots.js.map +1 -0
  99. package/dist/db/provisioner-tokens.d.ts +7 -2
  100. package/dist/db/provisioner-tokens.d.ts.map +1 -1
  101. package/dist/db/provisioner-tokens.js +59 -10
  102. package/dist/db/provisioner-tokens.js.map +1 -1
  103. package/dist/db/reservations.d.ts +18 -0
  104. package/dist/db/reservations.d.ts.map +1 -1
  105. package/dist/db/reservations.js +88 -1
  106. package/dist/db/reservations.js.map +1 -1
  107. package/dist/db/runner-assignments.d.ts +7 -0
  108. package/dist/db/runner-assignments.d.ts.map +1 -0
  109. package/dist/db/runner-assignments.js +55 -0
  110. package/dist/db/runner-assignments.js.map +1 -0
  111. package/dist/db/runner-instances.d.ts +84 -0
  112. package/dist/db/runner-instances.d.ts.map +1 -0
  113. package/dist/db/runner-instances.js +497 -0
  114. package/dist/db/runner-instances.js.map +1 -0
  115. package/dist/db/runner-sessions.d.ts +5 -0
  116. package/dist/db/runner-sessions.d.ts.map +1 -1
  117. package/dist/db/runner-sessions.js +48 -2
  118. package/dist/db/runner-sessions.js.map +1 -1
  119. package/dist/db/schema/ephemeral-registration-tokens.d.ts +2 -2
  120. package/dist/db/schema/ephemeral-registration-tokens.js +3 -3
  121. package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -1
  122. package/dist/db/schema/provisioner-capability-snapshots.d.ts +207 -0
  123. package/dist/db/schema/provisioner-capability-snapshots.d.ts.map +1 -0
  124. package/dist/db/schema/provisioner-capability-snapshots.js +38 -0
  125. package/dist/db/schema/provisioner-capability-snapshots.js.map +1 -0
  126. package/dist/db/schema/provisioner-tokens.d.ts +19 -1
  127. package/dist/db/schema/provisioner-tokens.d.ts.map +1 -1
  128. package/dist/db/schema/provisioner-tokens.js +29 -3
  129. package/dist/db/schema/provisioner-tokens.js.map +1 -1
  130. package/dist/db/schema/runner-activation-tokens.d.ts +161 -0
  131. package/dist/db/schema/runner-activation-tokens.d.ts.map +1 -0
  132. package/dist/db/schema/runner-activation-tokens.js +27 -0
  133. package/dist/db/schema/runner-activation-tokens.js.map +1 -0
  134. package/dist/db/schema/runner-control-sessions.d.ts +338 -0
  135. package/dist/db/schema/runner-control-sessions.d.ts.map +1 -0
  136. package/dist/db/schema/runner-control-sessions.js +52 -0
  137. package/dist/db/schema/runner-control-sessions.js.map +1 -0
  138. package/dist/db/schema/{provisioned-runners.d.ts → runner-instances.d.ts} +105 -34
  139. package/dist/db/schema/runner-instances.d.ts.map +1 -0
  140. package/dist/db/schema/{provisioned-runners.js → runner-instances.js} +23 -14
  141. package/dist/db/schema/runner-instances.js.map +1 -0
  142. package/dist/db/schema/runner-sessions.d.ts +39 -5
  143. package/dist/db/schema/runner-sessions.d.ts.map +1 -1
  144. package/dist/db/schema/runner-sessions.js +13 -6
  145. package/dist/db/schema/runner-sessions.js.map +1 -1
  146. package/dist/db/schema/running-job-executions.d.ts +2 -2
  147. package/dist/db/schema/running-job-executions.js +4 -4
  148. package/dist/db/schema/running-job-executions.js.map +1 -1
  149. package/dist/index.d.ts +6 -2
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +45 -39
  152. package/dist/index.js.map +1 -1
  153. package/dist/installation-provisioning.d.ts +14 -0
  154. package/dist/installation-provisioning.d.ts.map +1 -0
  155. package/dist/installation-provisioning.js +7 -0
  156. package/dist/installation-provisioning.js.map +1 -0
  157. package/dist/metrics/index.d.ts +1 -1
  158. package/dist/metrics/index.d.ts.map +1 -1
  159. package/dist/metrics/index.js +1 -1
  160. package/dist/metrics/index.js.map +1 -1
  161. package/dist/metrics/instance.d.ts +11 -7
  162. package/dist/metrics/instance.d.ts.map +1 -1
  163. package/dist/metrics/instance.js +13 -7
  164. package/dist/metrics/instance.js.map +1 -1
  165. package/dist/presentation/auth/index.d.ts +1 -0
  166. package/dist/presentation/auth/index.d.ts.map +1 -1
  167. package/dist/presentation/auth/index.js +1 -0
  168. package/dist/presentation/auth/index.js.map +1 -1
  169. package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -1
  170. package/dist/presentation/auth/provisioner-token-auth.js +5 -1
  171. package/dist/presentation/auth/provisioner-token-auth.js.map +1 -1
  172. package/dist/presentation/auth/runner-control-session-auth.d.ts +4 -0
  173. package/dist/presentation/auth/runner-control-session-auth.d.ts.map +1 -0
  174. package/dist/presentation/auth/runner-control-session-auth.js +29 -0
  175. package/dist/presentation/auth/runner-control-session-auth.js.map +1 -0
  176. package/dist/presentation/auth/runner-registration-token-auth.d.ts +5 -1
  177. package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -1
  178. package/dist/presentation/auth/runner-registration-token-auth.js +21 -1
  179. package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -1
  180. package/dist/presentation/dto/index.d.ts +1 -2
  181. package/dist/presentation/dto/index.d.ts.map +1 -1
  182. package/dist/presentation/dto/index.js +1 -2
  183. package/dist/presentation/dto/index.js.map +1 -1
  184. package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
  185. package/dist/presentation/dto/poll-demand.js +7 -1
  186. package/dist/presentation/dto/poll-demand.js.map +1 -1
  187. package/dist/presentation/dto/provisioner-token.d.ts +1 -0
  188. package/dist/presentation/dto/provisioner-token.d.ts.map +1 -1
  189. package/dist/presentation/dto/provisioner-token.js +5 -1
  190. package/dist/presentation/dto/provisioner-token.js.map +1 -1
  191. package/dist/presentation/dto/{provisioned-runners.d.ts → runner-instances.d.ts} +9 -9
  192. package/dist/presentation/dto/runner-instances.d.ts.map +1 -0
  193. package/dist/presentation/dto/{provisioned-runners.js → runner-instances.js} +6 -6
  194. package/dist/presentation/dto/runner-instances.js.map +1 -0
  195. package/dist/presentation/index.d.ts +2 -2
  196. package/dist/presentation/index.d.ts.map +1 -1
  197. package/dist/presentation/index.js +2 -2
  198. package/dist/presentation/index.js.map +1 -1
  199. package/dist/presentation/inter-module.d.ts +5 -0
  200. package/dist/presentation/inter-module.d.ts.map +1 -0
  201. package/dist/presentation/inter-module.js +43 -0
  202. package/dist/presentation/inter-module.js.map +1 -0
  203. package/dist/presentation/routes/assign-runner-instances.d.ts +2 -0
  204. package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -0
  205. package/dist/presentation/routes/assign-runner-instances.js +40 -0
  206. package/dist/presentation/routes/assign-runner-instances.js.map +1 -0
  207. package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -1
  208. package/dist/presentation/routes/get-provisioner-me.js +5 -1
  209. package/dist/presentation/routes/get-provisioner-me.js.map +1 -1
  210. package/dist/presentation/routes/heartbeat.d.ts +2 -1
  211. package/dist/presentation/routes/heartbeat.d.ts.map +1 -1
  212. package/dist/presentation/routes/heartbeat.js +60 -50
  213. package/dist/presentation/routes/heartbeat.js.map +1 -1
  214. package/dist/presentation/routes/index.d.ts +3 -1
  215. package/dist/presentation/routes/index.d.ts.map +1 -1
  216. package/dist/presentation/routes/index.js +80 -51
  217. package/dist/presentation/routes/index.js.map +1 -1
  218. package/dist/presentation/routes/poll-demand.d.ts +2 -0
  219. package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
  220. package/dist/presentation/routes/poll-demand.js +86 -45
  221. package/dist/presentation/routes/poll-demand.js.map +1 -1
  222. package/dist/presentation/routes/reconcile-runner-instances.d.ts +2 -0
  223. package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -0
  224. package/dist/presentation/routes/reconcile-runner-instances.js +27 -0
  225. package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -0
  226. package/dist/presentation/routes/register.d.ts +2 -1
  227. package/dist/presentation/routes/register.d.ts.map +1 -1
  228. package/dist/presentation/routes/register.js +55 -52
  229. package/dist/presentation/routes/register.js.map +1 -1
  230. package/dist/presentation/routes/report-runner-instances.d.ts +2 -0
  231. package/dist/presentation/routes/report-runner-instances.d.ts.map +1 -0
  232. package/dist/presentation/routes/report-runner-instances.js +37 -0
  233. package/dist/presentation/routes/report-runner-instances.js.map +1 -0
  234. package/dist/presentation/routes/request-job.d.ts +2 -1
  235. package/dist/presentation/routes/request-job.d.ts.map +1 -1
  236. package/dist/presentation/routes/request-job.js +39 -36
  237. package/dist/presentation/routes/request-job.js.map +1 -1
  238. package/dist/presentation/routes/runner-enrollment.d.ts +8 -0
  239. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -0
  240. package/dist/presentation/routes/runner-enrollment.js +212 -0
  241. package/dist/presentation/routes/runner-enrollment.js.map +1 -0
  242. package/dist/temporal/activities/index.d.ts +2 -2
  243. package/dist/temporal/activities/index.d.ts.map +1 -1
  244. package/dist/temporal/activities/index.js +2 -2
  245. package/dist/temporal/activities/index.js.map +1 -1
  246. package/dist/temporal/activities/maintenance-activities.d.ts +1 -1
  247. package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -1
  248. package/dist/temporal/activities/maintenance-activities.js +3 -3
  249. package/dist/temporal/activities/maintenance-activities.js.map +1 -1
  250. package/dist/temporal/workflows/index.bundle.js +3 -3
  251. package/dist/temporal/workflows/stuck-job-detector.js +2 -2
  252. package/dist/temporal/workflows/stuck-job-detector.js.map +1 -1
  253. package/dist/tsconfig.test.tsbuildinfo +1 -1
  254. package/drizzle/0000_initial.sql +91 -24
  255. package/drizzle/meta/0000_snapshot.json +392 -63
  256. package/package.json +21 -16
  257. package/src/config.test.ts +0 -26
  258. package/src/config.ts +48 -7
  259. package/src/core/demand.test.ts +29 -29
  260. package/src/core/demand.ts +22 -22
  261. package/src/core/entities/ephemeral-registration-token.ts +1 -1
  262. package/src/core/entities/provisioner-capability-snapshot.ts +12 -0
  263. package/src/core/entities/provisioner-token.ts +8 -2
  264. package/src/core/entities/{provisioned-runner.ts → runner-instance.ts} +6 -5
  265. package/src/core/entities/runner-session.ts +4 -2
  266. package/src/core/ephemeral-registration-tokens.test.ts +11 -11
  267. package/src/core/ephemeral-registration-tokens.ts +18 -20
  268. package/src/core/errors.ts +23 -4
  269. package/src/core/index.ts +37 -22
  270. package/src/core/job-executions.ts +3 -2
  271. package/src/core/maintenance.test.ts +13 -17
  272. package/src/core/maintenance.ts +5 -5
  273. package/src/core/provisioner-capability-snapshots.test.ts +35 -0
  274. package/src/core/provisioner-capability-snapshots.ts +12 -0
  275. package/src/core/provisioner-tokens.test.ts +20 -0
  276. package/src/core/provisioner-tokens.ts +33 -0
  277. package/src/core/rate-limit.test.ts +11 -27
  278. package/src/core/rate-limit.ts +3 -11
  279. package/src/core/runner-activation.ts +72 -0
  280. package/src/core/runner-assignments.ts +9 -0
  281. package/src/core/runner-control-sessions.ts +190 -0
  282. package/src/core/{provisioned-runners.test.ts → runner-instances.test.ts} +24 -24
  283. package/src/core/runner-instances.ts +301 -0
  284. package/src/core/runner-sessions.test.ts +112 -22
  285. package/src/core/runner-sessions.ts +25 -14
  286. package/src/db/db.ts +9 -2
  287. package/src/db/ephemeral-registration-tokens.test.ts +9 -9
  288. package/src/db/ephemeral-registration-tokens.ts +26 -26
  289. package/src/db/index.ts +30 -21
  290. package/src/db/job-executions.test.ts +13 -11
  291. package/src/db/job-executions.ts +33 -27
  292. package/src/db/provisioner-capability-snapshots.test.ts +175 -0
  293. package/src/db/provisioner-capability-snapshots.ts +130 -0
  294. package/src/db/provisioner-tokens.test.ts +139 -2
  295. package/src/db/provisioner-tokens.ts +123 -15
  296. package/src/db/reservations.test.ts +49 -0
  297. package/src/db/reservations.ts +146 -1
  298. package/src/db/runner-assignments.test.ts +163 -0
  299. package/src/db/runner-assignments.ts +115 -0
  300. package/src/db/{provisioned-runners.test.ts → runner-instances.test.ts} +442 -353
  301. package/src/db/runner-instances.ts +922 -0
  302. package/src/db/runner-sessions.test.ts +19 -6
  303. package/src/db/runner-sessions.ts +78 -2
  304. package/src/db/schema/ephemeral-registration-tokens.ts +4 -4
  305. package/src/db/schema/provisioner-capability-snapshots.ts +46 -0
  306. package/src/db/schema/provisioner-tokens.ts +33 -2
  307. package/src/db/schema/runner-activation-tokens.ts +22 -0
  308. package/src/db/schema/runner-control-sessions.ts +46 -0
  309. package/src/db/schema/{provisioned-runners.ts → runner-instances.ts} +28 -27
  310. package/src/db/schema/runner-sessions.ts +11 -7
  311. package/src/db/schema/running-job-executions.ts +5 -5
  312. package/src/index.test.ts +26 -0
  313. package/src/index.ts +38 -27
  314. package/src/installation-provisioning.ts +14 -0
  315. package/src/metrics/index.ts +5 -5
  316. package/src/metrics/instance.ts +25 -14
  317. package/src/presentation/auth/index.ts +4 -0
  318. package/src/presentation/auth/provisioner-token-auth.ts +8 -4
  319. package/src/presentation/auth/runner-control-session-auth.ts +31 -0
  320. package/src/presentation/auth/runner-registration-token-auth.ts +39 -3
  321. package/src/presentation/dto/index.ts +4 -8
  322. package/src/presentation/dto/poll-demand.ts +3 -1
  323. package/src/presentation/dto/provisioner-token.ts +5 -0
  324. package/src/presentation/dto/{provisioned-runners.ts → runner-instances.ts} +13 -15
  325. package/src/presentation/index.ts +2 -1
  326. package/src/presentation/inter-module.test.ts +15 -0
  327. package/src/presentation/inter-module.ts +53 -0
  328. package/src/presentation/routes/assign-runner-instances.ts +49 -0
  329. package/src/presentation/routes/get-provisioner-me.ts +3 -4
  330. package/src/presentation/routes/heartbeat.test.ts +4 -3
  331. package/src/presentation/routes/heartbeat.ts +67 -64
  332. package/src/presentation/routes/index.ts +91 -44
  333. package/src/presentation/routes/list-active-runners.test.ts +23 -23
  334. package/src/presentation/routes/manual-registration-tokens.test.ts +4 -3
  335. package/src/presentation/routes/poll-demand-release.test.ts +4 -4
  336. package/src/presentation/routes/poll-demand.test.ts +161 -22
  337. package/src/presentation/routes/poll-demand.ts +105 -45
  338. package/src/presentation/routes/provisioner-me.test.ts +37 -3
  339. package/src/presentation/routes/{reconcile-provisioned-runners.test.ts → reconcile-runner-instances.test.ts} +66 -61
  340. package/src/presentation/routes/reconcile-runner-instances.ts +30 -0
  341. package/src/presentation/routes/register.test.ts +9 -5
  342. package/src/presentation/routes/register.ts +61 -57
  343. package/src/presentation/routes/{report-provisioned-runners.test.ts → report-runner-instances.test.ts} +28 -28
  344. package/src/presentation/routes/{report-provisioned-runners.ts → report-runner-instances.ts} +14 -14
  345. package/src/presentation/routes/request-job.test.ts +5 -3
  346. package/src/presentation/routes/request-job.ts +41 -37
  347. package/src/presentation/routes/runner-enrollment.test.ts +319 -0
  348. package/src/presentation/routes/runner-enrollment.ts +196 -0
  349. package/src/temporal/activities/index.ts +2 -2
  350. package/src/temporal/activities/maintenance-activities.test.ts +7 -7
  351. package/src/temporal/activities/maintenance-activities.ts +3 -3
  352. package/src/temporal/workflows/stuck-job-detector.test.ts +3 -3
  353. package/src/temporal/workflows/stuck-job-detector.ts +2 -2
  354. package/test/env.ts +1 -3
  355. package/test/factories/ephemeral-registration-token.ts +2 -2
  356. package/test/factories/provisioner-token.ts +3 -1
  357. package/test/factories/runner-instance.ts +57 -0
  358. package/test/factories/runner-session.ts +3 -1
  359. package/test/fixtures/auth-inter-module.ts +30 -0
  360. package/test/globalSetup.ts +4 -1
  361. package/test/index.ts +2 -1
  362. package/tsconfig.build.tsbuildinfo +1 -1
  363. package/dist/core/entities/provisioned-runner.d.ts.map +0 -1
  364. package/dist/core/entities/provisioned-runner.js +0 -3
  365. package/dist/core/entities/provisioned-runner.js.map +0 -1
  366. package/dist/core/provisioned-runners.d.ts +0 -67
  367. package/dist/core/provisioned-runners.d.ts.map +0 -1
  368. package/dist/core/provisioned-runners.js +0 -162
  369. package/dist/core/provisioned-runners.js.map +0 -1
  370. package/dist/db/provisioned-runners.d.ts +0 -79
  371. package/dist/db/provisioned-runners.d.ts.map +0 -1
  372. package/dist/db/provisioned-runners.js +0 -466
  373. package/dist/db/provisioned-runners.js.map +0 -1
  374. package/dist/db/schema/provisioned-runners.d.ts.map +0 -1
  375. package/dist/db/schema/provisioned-runners.js.map +0 -1
  376. package/dist/presentation/dto/mint-registration-tokens.d.ts +0 -5
  377. package/dist/presentation/dto/mint-registration-tokens.d.ts.map +0 -1
  378. package/dist/presentation/dto/mint-registration-tokens.js +0 -19
  379. package/dist/presentation/dto/mint-registration-tokens.js.map +0 -1
  380. package/dist/presentation/dto/provisioned-runners.d.ts.map +0 -1
  381. package/dist/presentation/dto/provisioned-runners.js.map +0 -1
  382. package/dist/presentation/routes/mint-registration-tokens.d.ts +0 -2
  383. package/dist/presentation/routes/mint-registration-tokens.d.ts.map +0 -1
  384. package/dist/presentation/routes/mint-registration-tokens.js +0 -74
  385. package/dist/presentation/routes/mint-registration-tokens.js.map +0 -1
  386. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +0 -2
  387. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +0 -1
  388. package/dist/presentation/routes/reconcile-provisioned-runners.js +0 -27
  389. package/dist/presentation/routes/reconcile-provisioned-runners.js.map +0 -1
  390. package/dist/presentation/routes/report-provisioned-runners.d.ts +0 -2
  391. package/dist/presentation/routes/report-provisioned-runners.d.ts.map +0 -1
  392. package/dist/presentation/routes/report-provisioned-runners.js +0 -37
  393. package/dist/presentation/routes/report-provisioned-runners.js.map +0 -1
  394. package/src/core/provisioned-runners.ts +0 -301
  395. package/src/db/provisioned-runners.ts +0 -886
  396. package/src/presentation/dto/mint-registration-tokens.ts +0 -35
  397. package/src/presentation/routes/mint-registration-tokens.test.ts +0 -453
  398. package/src/presentation/routes/mint-registration-tokens.ts +0 -82
  399. package/src/presentation/routes/reconcile-provisioned-runners.ts +0 -30
  400. package/test/factories/provisioned-runner.ts +0 -78
@@ -13,7 +13,7 @@ describe('mintEphemeralRegistrationToken', () => {
13
13
  const result = await mintEphemeralRegistrationToken({
14
14
  workspaceId,
15
15
  provisionerId,
16
- provisionedRunnerId: 'gh-runner-7',
16
+ providerRunnerId: 'gh-runner-7',
17
17
  ttlSeconds: 600,
18
18
  });
19
19
 
@@ -22,7 +22,7 @@ describe('mintEphemeralRegistrationToken', () => {
22
22
  );
23
23
  expect(result.token.workspaceId).toBe(workspaceId);
24
24
  expect(result.token.provisionerId).toBe(provisionerId);
25
- expect(result.token.provisionedRunnerId).toBe('gh-runner-7');
25
+ expect(result.token.providerRunnerId).toBe('gh-runner-7');
26
26
  expect(result.token.reservationId).toBeNull();
27
27
  expect(result.token.prefix).toBe(result.rawToken.slice(0, 12));
28
28
  const [row] = await db()
@@ -40,7 +40,7 @@ describe('mintEphemeralRegistrationToken', () => {
40
40
  const result = await mintEphemeralRegistrationToken({
41
41
  workspaceId: crypto.randomUUID(),
42
42
  provisionerId: crypto.randomUUID(),
43
- provisionedRunnerId: 'gh-runner-7',
43
+ providerRunnerId: 'gh-runner-7',
44
44
  ttlSeconds,
45
45
  });
46
46
 
@@ -56,7 +56,7 @@ describe('mintEphemeralRegistrationToken', () => {
56
56
  const result = await mintEphemeralRegistrationToken({
57
57
  workspaceId: crypto.randomUUID(),
58
58
  provisionerId: crypto.randomUUID(),
59
- provisionedRunnerId: 'gh-runner-7',
59
+ providerRunnerId: 'gh-runner-7',
60
60
  reservationId,
61
61
  ttlSeconds: 600,
62
62
  });
@@ -67,11 +67,11 @@ describe('mintEphemeralRegistrationToken', () => {
67
67
  it('rejects a second active token for the same provisioned runner', async () => {
68
68
  const workspaceId = crypto.randomUUID();
69
69
  const provisionerId = crypto.randomUUID();
70
- const provisionedRunnerId = 'gh-runner-7';
70
+ const providerRunnerId = 'gh-runner-7';
71
71
  await mintEphemeralRegistrationToken({
72
72
  workspaceId,
73
73
  provisionerId,
74
- provisionedRunnerId,
74
+ providerRunnerId,
75
75
  ttlSeconds: 600,
76
76
  });
77
77
 
@@ -79,7 +79,7 @@ describe('mintEphemeralRegistrationToken', () => {
79
79
  mintEphemeralRegistrationToken({
80
80
  workspaceId,
81
81
  provisionerId,
82
- provisionedRunnerId,
82
+ providerRunnerId,
83
83
  ttlSeconds: 600,
84
84
  }),
85
85
  ).rejects.toBeInstanceOf(ActiveEphemeralRegistrationTokenExistsError);
@@ -88,21 +88,21 @@ describe('mintEphemeralRegistrationToken', () => {
88
88
  it('allows minting a replacement after the previous token expires', async () => {
89
89
  const workspaceId = crypto.randomUUID();
90
90
  const provisionerId = crypto.randomUUID();
91
- const provisionedRunnerId = 'gh-runner-7';
91
+ const providerRunnerId = 'gh-runner-7';
92
92
  await mintEphemeralRegistrationToken({
93
93
  workspaceId,
94
94
  provisionerId,
95
- provisionedRunnerId,
95
+ providerRunnerId,
96
96
  ttlSeconds: -1,
97
97
  });
98
98
 
99
99
  const replacement = await mintEphemeralRegistrationToken({
100
100
  workspaceId,
101
101
  provisionerId,
102
- provisionedRunnerId,
102
+ providerRunnerId,
103
103
  ttlSeconds: 600,
104
104
  });
105
105
 
106
- expect(replacement.token.provisionedRunnerId).toBe(provisionedRunnerId);
106
+ expect(replacement.token.providerRunnerId).toBe(providerRunnerId);
107
107
  });
108
108
  });
@@ -9,7 +9,7 @@ import {RegistrationTokenBatchTooLargeError} from './errors.js';
9
9
  export interface MintEphemeralRegistrationTokenParams {
10
10
  workspaceId: string;
11
11
  provisionerId: string;
12
- provisionedRunnerId: string;
12
+ providerRunnerId: string;
13
13
  reservationId?: string | null | undefined;
14
14
  ttlSeconds: number;
15
15
  }
@@ -19,21 +19,21 @@ export interface MintEphemeralRegistrationTokenResult {
19
19
  rawToken: string;
20
20
  }
21
21
 
22
- export interface MintEphemeralRegistrationTokensBatchProvisionedRunner {
23
- provisionedRunnerId: string;
22
+ export interface MintEphemeralRegistrationTokensBatchRunnerInstance {
23
+ providerRunnerId: string;
24
24
  }
25
25
 
26
26
  export interface MintEphemeralRegistrationTokensBatchParams {
27
27
  workspaceId: string;
28
28
  provisionerId: string;
29
29
  reservationId: string;
30
- provisionedRunners: MintEphemeralRegistrationTokensBatchProvisionedRunner[];
30
+ providerRunners: MintEphemeralRegistrationTokensBatchRunnerInstance[];
31
31
  ttlSeconds: number;
32
32
  maxBatchSize: number;
33
33
  }
34
34
 
35
35
  export interface MintEphemeralRegistrationTokensBatchResult {
36
- provisionedRunnerId: string;
36
+ providerRunnerId: string;
37
37
  token: EphemeralRegistrationToken;
38
38
  rawToken: string;
39
39
  }
@@ -42,12 +42,12 @@ export async function mintEphemeralRegistrationToken(
42
42
  params: MintEphemeralRegistrationTokenParams,
43
43
  ): Promise<MintEphemeralRegistrationTokenResult> {
44
44
  const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);
45
- const row = buildEphemeralTokenRow(params.provisionedRunnerId, expiresAt);
45
+ const row = buildEphemeralTokenRow(params.providerRunnerId, expiresAt);
46
46
  const token = await createEphemeralRegistrationToken({
47
47
  workspaceId: params.workspaceId,
48
48
  provisionerId: params.provisionerId,
49
49
  reservationId: params.reservationId ?? null,
50
- provisionedRunnerId: params.provisionedRunnerId,
50
+ providerRunnerId: params.providerRunnerId,
51
51
  hashedToken: row.hashedToken,
52
52
  prefix: row.prefix,
53
53
  expiresAt: row.expiresAt,
@@ -59,16 +59,16 @@ export async function mintEphemeralRegistrationToken(
59
59
  export async function mintEphemeralRegistrationTokensBatch(
60
60
  params: MintEphemeralRegistrationTokensBatchParams,
61
61
  ): Promise<MintEphemeralRegistrationTokensBatchResult[]> {
62
- if (params.provisionedRunners.length > params.maxBatchSize) {
62
+ if (params.providerRunners.length > params.maxBatchSize) {
63
63
  throw new RegistrationTokenBatchTooLargeError(
64
- params.provisionedRunners.length,
64
+ params.providerRunners.length,
65
65
  params.maxBatchSize,
66
66
  );
67
67
  }
68
68
 
69
69
  const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);
70
- const rows = params.provisionedRunners.map((provisionedRunner) =>
71
- buildEphemeralTokenRow(provisionedRunner.provisionedRunnerId, expiresAt),
70
+ const rows = params.providerRunners.map((providerRunner) =>
71
+ buildEphemeralTokenRow(providerRunner.providerRunnerId, expiresAt),
72
72
  );
73
73
  const tokens = await createEphemeralRegistrationTokensBatch({
74
74
  workspaceId: params.workspaceId,
@@ -77,33 +77,31 @@ export async function mintEphemeralRegistrationTokensBatch(
77
77
  expiresAt,
78
78
  rows,
79
79
  });
80
- const tokensByProvisionedRunnerId = new Map(
81
- tokens.map((token) => [token.provisionedRunnerId, token]),
82
- );
80
+ const tokensByRunnerInstanceId = new Map(tokens.map((token) => [token.providerRunnerId, token]));
83
81
 
84
82
  return rows.map((row) => {
85
- const token = tokensByProvisionedRunnerId.get(row.provisionedRunnerId);
83
+ const token = tokensByRunnerInstanceId.get(row.providerRunnerId);
86
84
  if (!token) {
87
85
  throw new Error(
88
- `Inserted token not returned for provisioned runner: ${row.provisionedRunnerId}`,
86
+ `Inserted token not returned for provisioned runner: ${row.providerRunnerId}`,
89
87
  );
90
88
  }
91
- return {provisionedRunnerId: row.provisionedRunnerId, rawToken: row.rawToken, token};
89
+ return {providerRunnerId: row.providerRunnerId, rawToken: row.rawToken, token};
92
90
  });
93
91
  }
94
92
 
95
93
  interface EphemeralTokenRow {
96
- provisionedRunnerId: string;
94
+ providerRunnerId: string;
97
95
  rawToken: string;
98
96
  hashedToken: string;
99
97
  prefix: string;
100
98
  expiresAt: Date;
101
99
  }
102
100
 
103
- function buildEphemeralTokenRow(provisionedRunnerId: string, expiresAt: Date): EphemeralTokenRow {
101
+ function buildEphemeralTokenRow(providerRunnerId: string, expiresAt: Date): EphemeralTokenRow {
104
102
  const rawToken = generateOpaqueToken('ephemeralRegistrationToken');
105
103
  return {
106
- provisionedRunnerId,
104
+ providerRunnerId,
107
105
  rawToken,
108
106
  hashedToken: hashOpaqueToken(rawToken),
109
107
  prefix: extractDisplayPrefix(rawToken),
@@ -63,10 +63,10 @@ export class ActiveEphemeralRegistrationTokenExistsError extends Error {
63
63
  constructor(
64
64
  public readonly workspaceId: string,
65
65
  public readonly provisionerId: string,
66
- public readonly provisionedRunnerId: string,
66
+ public readonly providerRunnerId: string,
67
67
  ) {
68
68
  super(
69
- `Active ephemeral registration token already exists for provisioned runner ${provisionedRunnerId} in workspace ${workspaceId}`,
69
+ `Active ephemeral registration token already exists for provisioned runner ${providerRunnerId} in workspace ${workspaceId}`,
70
70
  );
71
71
  this.name = 'ActiveEphemeralRegistrationTokenExistsError';
72
72
  }
@@ -86,6 +86,25 @@ export class ReservationExpiredError extends Error {
86
86
  }
87
87
  }
88
88
 
89
+ export class RunnerInstanceNotAssignableError extends Error {
90
+ constructor(public readonly runnerInstanceId: string) {
91
+ super(`Runner instance cannot be assigned: ${runnerInstanceId}`);
92
+ this.name = 'RunnerInstanceNotAssignableError';
93
+ }
94
+ }
95
+ export class RunnerInstanceAlreadyAssignedError extends Error {
96
+ constructor(public readonly runnerInstanceId: string) {
97
+ super(`Runner instance is already assigned: ${runnerInstanceId}`);
98
+ this.name = 'RunnerInstanceAlreadyAssignedError';
99
+ }
100
+ }
101
+ export class ReservationAlreadyAssignedError extends Error {
102
+ constructor(public readonly reservationId: string) {
103
+ super(`Reservation is already assigned: ${reservationId}`);
104
+ this.name = 'ReservationAlreadyAssignedError';
105
+ }
106
+ }
107
+
89
108
  export class RegistrationTokenBatchTooLargeError extends Error {
90
109
  constructor(
91
110
  public readonly requested: number,
@@ -112,9 +131,9 @@ export class RegistrationTokenBatchExceedsReservationError extends Error {
112
131
  }
113
132
 
114
133
  export class ActiveEphemeralRegistrationTokensExistError extends Error {
115
- constructor(public readonly provisionedRunnerIds: string[]) {
134
+ constructor(public readonly providerRunnerIds: string[]) {
116
135
  super(
117
- `Active ephemeral registration tokens already exist for provisioned runners: ${provisionedRunnerIds.join(', ')}`,
136
+ `Active ephemeral registration tokens already exist for provisioned runners: ${providerRunnerIds.join(', ')}`,
118
137
  );
119
138
  this.name = 'ActiveEphemeralRegistrationTokensExistError';
120
139
  }
package/src/core/index.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  export type {EphemeralRegistrationToken} from './entities/ephemeral-registration-token.js';
2
2
  export type {ManualRegistrationToken} from './entities/manual-registration-token.js';
3
+ export type {ProvisionerCapabilitySnapshot} from './entities/provisioner-capability-snapshot.js';
3
4
  export type {
4
- ProvisionedRunner,
5
- ProvisionedRunnerState,
6
- } from './entities/provisioned-runner.js';
7
- export type {ActiveProvisionerToken, ProvisionerToken} from './entities/provisioner-token.js';
5
+ ActiveProvisionerToken,
6
+ ProvisionerScope,
7
+ ProvisionerToken,
8
+ } from './entities/provisioner-token.js';
9
+ export type {
10
+ RunnerInstance,
11
+ RunnerInstanceState,
12
+ } from './entities/runner-instance.js';
8
13
  export type {RunnerSession} from './entities/runner-session.js';
9
- export {
10
- type MintEphemeralRegistrationTokenParams,
11
- type MintEphemeralRegistrationTokenResult,
12
- mintEphemeralRegistrationToken,
13
- } from './ephemeral-registration-tokens.js';
14
14
  export {
15
15
  EmptyRunnerLabelsError,
16
16
  ManualRegistrationTokenNotFoundError,
@@ -26,25 +26,40 @@ export {
26
26
  listUsableManualRegistrationTokens,
27
27
  revokeWorkspaceManualRegistrationToken,
28
28
  } from './manual-registration-tokens.js';
29
+ export {hasActiveWorkspaceProvisionerCapability} from './provisioner-capability-snapshots.js';
29
30
  export {
30
- type ActiveRunner,
31
- listActiveRunners,
32
- type ReconcileDesiredIntent,
33
- type ReconciledBoundJobExecution,
34
- type ReconciledProvisionedRunner,
35
- type ReconcileProvisionedRunnersParams,
36
- type ReconcileProvisionedRunnersResult,
37
- type ReportProvisionedRunnersParams,
38
- type ReportProvisionedRunnersResult,
39
- reconcileProvisionedRunners,
40
- reportProvisionedRunners,
41
- } from './provisioned-runners.js';
42
- export {
31
+ createInstallationProvisionerToken,
43
32
  createWorkspaceProvisionerToken,
44
33
  listActiveProvisioners,
45
34
  listUsableProvisionerTokens,
35
+ revokeInstallationProvisionerToken,
46
36
  revokeWorkspaceProvisionerToken,
47
37
  } from './provisioner-tokens.js';
38
+ export {getRunnerAssignment, issueRunnerActivationToken} from './runner-activation.js';
39
+ export {assignRunnerInstances} from './runner-assignments.js';
40
+ export {
41
+ attachRunnerControlProviderId,
42
+ createRunnerInstancesWithBootstrapTokens,
43
+ enrollRunnerControlSession,
44
+ exchangeRunnerBootstrapToken,
45
+ RunnerBootstrapTokenInvalidError,
46
+ RunnerControlSessionInvalidError,
47
+ touchRunnerControlSession,
48
+ } from './runner-control-sessions.js';
49
+ export {
50
+ type ActiveRunner,
51
+ attachRunnerInstanceProviderId,
52
+ listActiveRunners,
53
+ type ReconcileDesiredIntent,
54
+ type ReconciledBoundJobExecution,
55
+ type ReconciledRunnerInstance,
56
+ type ReconcileRunnerInstancesParams,
57
+ type ReconcileRunnerInstancesResult,
58
+ type ReportRunnerInstancesParams,
59
+ type ReportRunnerInstancesResult,
60
+ reconcileRunnerInstances,
61
+ reportRunnerInstances,
62
+ } from './runner-instances.js';
48
63
  export {
49
64
  type RegisterRunnerSessionResult,
50
65
  type RunnerRegistrationCredential,
@@ -1,4 +1,4 @@
1
- import {issueJobLeaseToken} from '@shipfox/api-auth';
1
+ import type {AuthInterModuleClient} from '@shipfox/api-auth-dto/inter-module';
2
2
  import {claimPendingJobExecution} from '#db/job-executions.js';
3
3
  import {jobExecutionClaimedCount} from '#metrics/instance.js';
4
4
  import {config} from '../config.js';
@@ -12,6 +12,7 @@ export interface ClaimJobExecutionResult {
12
12
  }
13
13
 
14
14
  export async function claimJobExecution(params: {
15
+ auth: AuthInterModuleClient;
15
16
  workspaceId: string;
16
17
  runnerSessionId: string;
17
18
  sessionLabels: string[];
@@ -27,7 +28,7 @@ export async function claimJobExecution(params: {
27
28
  }
28
29
  jobExecutionClaimedCount.add(1, {outcome: 'claimed'});
29
30
 
30
- const leaseToken = await issueJobLeaseToken({
31
+ const {token: leaseToken} = await params.auth.mintJobLeaseToken({
31
32
  workflowRunId: claimed.workflowRunId,
32
33
  workflowRunAttemptId: claimed.workflowRunAttemptId,
33
34
  jobId: claimed.jobId,
@@ -2,20 +2,16 @@ import {vi} from '@shipfox/vitest/vi';
2
2
  import {eq} from 'drizzle-orm';
3
3
  import {db} from '#db/db.js';
4
4
  import {ephemeralRegistrationTokens} from '#db/schema/ephemeral-registration-tokens.js';
5
- import {provisionedRunners} from '#db/schema/provisioned-runners.js';
6
5
  import {reservations} from '#db/schema/reservations.js';
6
+ import {providerRunners} from '#db/schema/runner-instances.js';
7
7
  import {runnerSessions} from '#db/schema/runner-sessions.js';
8
- import {provisionedRunnerReapedCount, reservationReleasedCount} from '#metrics/instance.js';
9
- import {
10
- provisionedRunnerFactory,
11
- provisionerTokenFactory,
12
- reservationFactory,
13
- } from '#test/index.js';
8
+ import {providerRunnerReapedCount, reservationReleasedCount} from '#metrics/instance.js';
9
+ import {providerRunnerFactory, provisionerTokenFactory, reservationFactory} from '#test/index.js';
14
10
  import {
15
11
  deleteExpiredEphemeralRegistrationTokens,
16
12
  deleteExpiredRunnerReservations,
17
13
  deleteExpiredRunnerSessions,
18
- reapStaleProvisionedRunners,
14
+ reapStaleRunnerInstances,
19
15
  } from './maintenance.js';
20
16
 
21
17
  describe('deleteExpiredRunnerReservations', () => {
@@ -55,7 +51,7 @@ describe('deleteExpiredRunnerReservations', () => {
55
51
  });
56
52
  });
57
53
 
58
- describe('reapStaleProvisionedRunners', () => {
54
+ describe('reapStaleRunnerInstances', () => {
59
55
  it('returns reaped counts and records maintenance metrics', async () => {
60
56
  const workspaceId = crypto.randomUUID();
61
57
  const provisioner = await provisionerTokenFactory.create({workspaceId});
@@ -71,21 +67,21 @@ describe('reapStaleProvisionedRunners', () => {
71
67
  .from(reservations)
72
68
  .where(eq(reservations.workspaceId, workspaceId));
73
69
  if (!reservation) throw new Error('Expected reservation');
74
- const provisionedRunner = await provisionedRunnerFactory.create({
70
+ const providerRunner = await providerRunnerFactory.create({
75
71
  workspaceId,
76
72
  provisionerId: provisioner.id,
77
- provisionedRunnerId: 'provisioned-runner-1',
73
+ providerRunnerId: 'provisioned-runner-1',
78
74
  reservationId: reservation.id,
79
75
  reportedAt: new Date(Date.now() - 120_000),
80
76
  });
81
77
  await db()
82
- .update(provisionedRunners)
78
+ .update(providerRunners)
83
79
  .set({updatedAt: new Date(Date.now() - 120_000)})
84
- .where(eq(provisionedRunners.id, provisionedRunner.id));
85
- const reapedSpy = vi.spyOn(provisionedRunnerReapedCount, 'add');
80
+ .where(eq(providerRunners.id, providerRunner.id));
81
+ const reapedSpy = vi.spyOn(providerRunnerReapedCount, 'add');
86
82
  const releasedSpy = vi.spyOn(reservationReleasedCount, 'add');
87
83
 
88
- const result = await reapStaleProvisionedRunners({thresholdSeconds: 60, limit: 100});
84
+ const result = await reapStaleRunnerInstances({thresholdSeconds: 60, limit: 100});
89
85
 
90
86
  expect(result).toEqual({reaped: 1, reservationsReleased: 1});
91
87
  expect(reapedSpy).toHaveBeenCalledWith(1);
@@ -173,7 +169,7 @@ describe('deleteExpiredRunnerSessions', () => {
173
169
  registrationTokenId: crypto.randomUUID(),
174
170
  registrationTokenKind: params.kind,
175
171
  provisionerId,
176
- provisionedRunnerId: params.kind === 'ephemeral' ? `provisioned-${params.id}` : null,
172
+ providerRunnerId: params.kind === 'ephemeral' ? `provisioned-${params.id}` : null,
177
173
  labels: ['linux'],
178
174
  maxClaims: params.kind === 'ephemeral' ? 1 : null,
179
175
  claimsUsed: 0,
@@ -240,7 +236,7 @@ describe('deleteExpiredEphemeralRegistrationTokens', () => {
240
236
  id: params.id,
241
237
  workspaceId,
242
238
  provisionerId: crypto.randomUUID(),
243
- provisionedRunnerId: `provisioned-${params.id}`,
239
+ providerRunnerId: `provisioned-${params.id}`,
244
240
  hashedToken: crypto.randomUUID(),
245
241
  prefix: 'sfxr_test',
246
242
  expiresAt: params.expiresAt,
@@ -1,10 +1,10 @@
1
1
  import {config} from '#config.js';
2
2
  import {deleteExpiredEphemeralRegistrationTokens as deleteExpiredEphemeralRegistrationTokensDb} from '#db/ephemeral-registration-tokens.js';
3
3
  import {expireStuckJobExecutions} from '#db/job-executions.js';
4
- import {reapStaleProvisionedRunners as reapStaleProvisionedRunnersDb} from '#db/provisioned-runners.js';
5
4
  import {deleteExpiredReservations} from '#db/reservations.js';
5
+ import {reapStaleRunnerInstances as reapStaleRunnerInstancesDb} from '#db/runner-instances.js';
6
6
  import {deleteExpiredRunnerSessions as deleteExpiredRunnerSessionsDb} from '#db/runner-sessions.js';
7
- import {provisionedRunnerReapedCount, reservationReleasedCount} from '#metrics/instance.js';
7
+ import {providerRunnerReapedCount, reservationReleasedCount} from '#metrics/instance.js';
8
8
  import {STUCK_JOB_THRESHOLD_SECONDS} from './maintenance-policy.js';
9
9
 
10
10
  export interface DetectAndExpireStuckJobsParams {
@@ -30,17 +30,17 @@ export async function deleteExpiredRunnerReservations(params?: {
30
30
  return {deleted};
31
31
  }
32
32
 
33
- export async function reapStaleProvisionedRunners(params?: {
33
+ export async function reapStaleRunnerInstances(params?: {
34
34
  thresholdSeconds?: number;
35
35
  limit?: number;
36
36
  }): Promise<{reaped: number; reservationsReleased: number}> {
37
- const result = await reapStaleProvisionedRunnersDb({
37
+ const result = await reapStaleRunnerInstancesDb({
38
38
  thresholdSeconds:
39
39
  params?.thresholdSeconds ?? config.RUNNER_STALE_PROVISIONED_RUNNER_THRESHOLD_SECONDS,
40
40
  limit: params?.limit ?? config.RUNNER_STALE_PROVISIONED_RUNNER_REAPER_LIMIT,
41
41
  });
42
42
 
43
- if (result.reaped > 0) provisionedRunnerReapedCount.add(result.reaped);
43
+ if (result.reaped > 0) providerRunnerReapedCount.add(result.reaped);
44
44
  if (result.reservationsReleased > 0) {
45
45
  reservationReleasedCount.add(result.reservationsReleased);
46
46
  }
@@ -0,0 +1,35 @@
1
+ import {eq} from 'drizzle-orm';
2
+ import {config} from '#config.js';
3
+ import {db} from '#db/db.js';
4
+ import {publishWorkspaceProvisionerCapabilitySnapshot} from '#db/provisioner-capability-snapshots.js';
5
+ import {provisionerCapabilitySnapshots} from '#db/schema/provisioner-capability-snapshots.js';
6
+ import {provisionerTokenFactory} from '#test/index.js';
7
+ import {hasActiveWorkspaceProvisionerCapability} from './provisioner-capability-snapshots.js';
8
+
9
+ describe('workspace provisioner capability core', () => {
10
+ it('applies the configured active window to capability matching', async () => {
11
+ const workspaceId = crypto.randomUUID();
12
+ const provisioner = await provisionerTokenFactory.create({workspaceId});
13
+
14
+ await publishWorkspaceProvisionerCapabilitySnapshot({
15
+ workspaceId,
16
+ provisionerId: provisioner.id,
17
+ templates: [
18
+ {templateKey: 'linux', labels: ['linux'], availableSlots: 1, starting: 0, running: 0},
19
+ ],
20
+ });
21
+ await db()
22
+ .update(provisionerCapabilitySnapshots)
23
+ .set({
24
+ advertisedAt: new Date(Date.now() - (config.PROVISIONER_ACTIVE_WINDOW_SECONDS + 1) * 1000),
25
+ })
26
+ .where(eq(provisionerCapabilitySnapshots.provisionerId, provisioner.id));
27
+
28
+ const hasLinux = await hasActiveWorkspaceProvisionerCapability({
29
+ workspaceId,
30
+ requiredLabels: ['linux'],
31
+ });
32
+
33
+ expect(hasLinux).toBe(false);
34
+ });
35
+ });
@@ -0,0 +1,12 @@
1
+ import {config} from '#config.js';
2
+ import {hasActiveWorkspaceProvisionerCapability as hasActiveWorkspaceProvisionerCapabilityDb} from '#db/provisioner-capability-snapshots.js';
3
+
4
+ export function hasActiveWorkspaceProvisionerCapability(params: {
5
+ workspaceId: string;
6
+ requiredLabels: string[];
7
+ }): Promise<boolean> {
8
+ return hasActiveWorkspaceProvisionerCapabilityDb({
9
+ ...params,
10
+ windowSeconds: config.PROVISIONER_ACTIVE_WINDOW_SECONDS,
11
+ });
12
+ }
@@ -4,8 +4,10 @@ import {db} from '#db/db.js';
4
4
  import {provisionerTokens} from '#db/schema/provisioner-tokens.js';
5
5
  import {provisionerTokenFactory} from '#test/index.js';
6
6
  import {
7
+ createInstallationProvisionerToken,
7
8
  createWorkspaceProvisionerToken,
8
9
  listUsableProvisionerTokens,
10
+ revokeInstallationProvisionerToken,
9
11
  revokeWorkspaceProvisionerToken,
10
12
  } from './provisioner-tokens.js';
11
13
 
@@ -34,6 +36,24 @@ describe('provisioner token core', () => {
34
36
  expect(rows[0]?.hashedToken).not.toBe(result.rawToken);
35
37
  });
36
38
 
39
+ it('creates and revokes an installation provisioner token without a workspace', async () => {
40
+ const createdByUserId = crypto.randomUUID();
41
+
42
+ const created = await createInstallationProvisionerToken({createdByUserId, name: 'cloud'});
43
+
44
+ expect(created.token).toMatchObject({
45
+ scope: 'installation',
46
+ workspaceId: null,
47
+ createdByUserId,
48
+ });
49
+ const revoked = await revokeInstallationProvisionerToken({
50
+ tokenId: created.token.id,
51
+ revokedByUserId: crypto.randomUUID(),
52
+ });
53
+ expect(revoked).toMatchObject({id: created.token.id, scope: 'installation'});
54
+ expect(revoked.revokedAt).toBeInstanceOf(Date);
55
+ });
56
+
37
57
  it('lists usable tokens and excludes revoked tokens after revoke', async () => {
38
58
  const workspaceId = crypto.randomUUID();
39
59
  const token = await provisionerTokenFactory.create({workspaceId});
@@ -3,6 +3,7 @@ import {
3
3
  createProvisionerToken,
4
4
  listActiveProvisionerTokens,
5
5
  listUsableProvisionerTokensByWorkspaceId,
6
+ revokeInstallationProvisionerToken as revokeInstallationProvisionerTokenDb,
6
7
  revokeProvisionerToken,
7
8
  } from '#db/provisioner-tokens.js';
8
9
  import {config} from '../config.js';
@@ -28,6 +29,7 @@ export async function createWorkspaceProvisionerToken(
28
29
  const expiresAt = params.ttlSeconds ? new Date(Date.now() + params.ttlSeconds * 1000) : undefined;
29
30
 
30
31
  const token = await createProvisionerToken({
32
+ scope: 'workspace',
31
33
  workspaceId: params.workspaceId,
32
34
  hashedToken: hashOpaqueToken(rawToken),
33
35
  prefix: extractDisplayPrefix(rawToken),
@@ -39,6 +41,28 @@ export async function createWorkspaceProvisionerToken(
39
41
  return {token, rawToken};
40
42
  }
41
43
 
44
+ export interface CreateInstallationProvisionerTokenParams {
45
+ createdByUserId: string;
46
+ name?: string | undefined;
47
+ ttlSeconds?: number | undefined;
48
+ }
49
+
50
+ export async function createInstallationProvisionerToken(
51
+ params: CreateInstallationProvisionerTokenParams,
52
+ ): Promise<CreateWorkspaceProvisionerTokenResult> {
53
+ const rawToken = generateOpaqueToken('provisionerToken');
54
+ const expiresAt = params.ttlSeconds ? new Date(Date.now() + params.ttlSeconds * 1000) : undefined;
55
+ const token = await createProvisionerToken({
56
+ scope: 'installation',
57
+ hashedToken: hashOpaqueToken(rawToken),
58
+ prefix: extractDisplayPrefix(rawToken),
59
+ name: params.name,
60
+ createdByUserId: params.createdByUserId,
61
+ expiresAt,
62
+ });
63
+ return {token, rawToken};
64
+ }
65
+
42
66
  export function listUsableProvisionerTokens(workspaceId: string): Promise<ProvisionerToken[]> {
43
67
  return listUsableProvisionerTokensByWorkspaceId(workspaceId);
44
68
  }
@@ -59,3 +83,12 @@ export async function revokeWorkspaceProvisionerToken(params: {
59
83
  if (!token) throw new ProvisionerTokenNotFoundError(params.tokenId);
60
84
  return token;
61
85
  }
86
+
87
+ export async function revokeInstallationProvisionerToken(params: {
88
+ tokenId: string;
89
+ revokedByUserId: string;
90
+ }): Promise<ProvisionerToken> {
91
+ const token = await revokeInstallationProvisionerTokenDb(params);
92
+ if (!token) throw new ProvisionerTokenNotFoundError(params.tokenId);
93
+ return token;
94
+ }
@@ -111,47 +111,31 @@ describe('checkRunnersRateLimit', () => {
111
111
  });
112
112
  });
113
113
 
114
- it('uses the configured shared identifier secret when present', async () => {
114
+ it('uses the root-derived identifier key', async () => {
115
115
  vi.resetModules();
116
- vi.doMock('#config.js', () => ({
117
- config: {
118
- RATE_LIMIT_IDENTIFIER_SECRET: 'configured-secret',
119
- RUNNERS_RATE_LIMIT_TIMEOUT_MS: 250,
120
- },
121
- }));
122
- vi.doMock('@shipfox/api-auth/config', () => ({
123
- config: {
124
- AUTH_JWT_SECRET: 'jwt-secret',
125
- },
126
- }));
116
+ vi.stubEnv('AUTH_ROOT_KEY', 'MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=');
127
117
 
128
118
  try {
129
- const configuredSecretModule = await import('./rate-limit.js');
130
- const configuredSecretHash = configuredSecretModule.hashRunnersRateLimitIdentifier({
119
+ const firstModule = await import('./rate-limit.js');
120
+ const firstHash = firstModule.hashRunnersRateLimitIdentifier({
131
121
  action: 'provisioner-mint',
132
122
  scope: 'provisioner',
133
123
  identifier: 'provisioner-token-id',
134
124
  });
135
- vi.doMock('#config.js', () => ({
136
- config: {
137
- RATE_LIMIT_IDENTIFIER_SECRET: undefined,
138
- RUNNERS_RATE_LIMIT_TIMEOUT_MS: 250,
139
- },
140
- }));
125
+ vi.stubEnv('AUTH_ROOT_KEY', 'ZmVkY2JhOTg3NjU0MzIxMGZlZGNiYTk4NzY1NDMyMTA=');
141
126
  vi.resetModules();
142
- const derivedSecretModule = await import('./rate-limit.js');
143
- const derivedSecretHash = derivedSecretModule.hashRunnersRateLimitIdentifier({
127
+ const secondModule = await import('./rate-limit.js');
128
+ const secondHash = secondModule.hashRunnersRateLimitIdentifier({
144
129
  action: 'provisioner-mint',
145
130
  scope: 'provisioner',
146
131
  identifier: 'provisioner-token-id',
147
132
  });
148
133
 
149
- expect(configuredSecretHash).toMatch(HMAC_HEX_PATTERN);
150
- expect(derivedSecretHash).toMatch(HMAC_HEX_PATTERN);
151
- expect(configuredSecretHash).not.toBe(derivedSecretHash);
134
+ expect(firstHash).toMatch(HMAC_HEX_PATTERN);
135
+ expect(secondHash).toMatch(HMAC_HEX_PATTERN);
136
+ expect(firstHash).not.toBe(secondHash);
152
137
  } finally {
153
- vi.doUnmock('#config.js');
154
- vi.doUnmock('@shipfox/api-auth/config');
138
+ vi.unstubAllEnvs();
155
139
  vi.resetModules();
156
140
  }
157
141
  });