@shipfox/api-runners 5.0.0 → 6.0.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.
- package/.turbo/turbo-build.log +6 -6
- package/CHANGELOG.md +61 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +53 -6
- package/dist/config.js.map +1 -1
- package/dist/core/capacity-assignments.d.ts +7 -0
- package/dist/core/capacity-assignments.d.ts.map +1 -0
- package/dist/core/capacity-assignments.js +6 -0
- package/dist/core/capacity-assignments.js.map +1 -0
- package/dist/core/demand.d.ts +6 -6
- package/dist/core/demand.d.ts.map +1 -1
- package/dist/core/demand.js +10 -10
- package/dist/core/demand.js.map +1 -1
- package/dist/core/entities/capacity-assignment.d.ts +9 -0
- package/dist/core/entities/capacity-assignment.d.ts.map +1 -0
- package/dist/core/entities/capacity-assignment.js +3 -0
- package/dist/core/entities/capacity-assignment.js.map +1 -0
- package/dist/core/entities/ephemeral-registration-token.d.ts +1 -1
- package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -1
- package/dist/core/entities/ephemeral-registration-token.js.map +1 -1
- package/dist/core/entities/provisioner-capability-snapshot.d.ts +13 -0
- package/dist/core/entities/provisioner-capability-snapshot.d.ts.map +1 -0
- package/dist/core/entities/provisioner-capability-snapshot.js +3 -0
- package/dist/core/entities/provisioner-capability-snapshot.js.map +1 -0
- package/dist/core/entities/provisioner-token.d.ts +10 -2
- package/dist/core/entities/provisioner-token.d.ts.map +1 -1
- package/dist/core/entities/provisioner-token.js.map +1 -1
- package/dist/core/entities/{provisioned-runner.d.ts → runner-instance.d.ts} +6 -6
- package/dist/core/entities/runner-instance.d.ts.map +1 -0
- package/dist/core/entities/runner-instance.js +3 -0
- package/dist/core/entities/runner-instance.js.map +1 -0
- package/dist/core/entities/runner-session.d.ts +4 -2
- package/dist/core/entities/runner-session.d.ts.map +1 -1
- package/dist/core/entities/runner-session.js.map +1 -1
- package/dist/core/ephemeral-registration-tokens.d.ts +5 -5
- package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -1
- package/dist/core/ephemeral-registration-tokens.js +12 -12
- package/dist/core/ephemeral-registration-tokens.js.map +1 -1
- package/dist/core/errors.d.ts +16 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +22 -4
- package/dist/core/errors.js.map +1 -1
- package/dist/core/index.d.ts +10 -4
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/job-executions.d.ts +2 -0
- package/dist/core/job-executions.d.ts.map +1 -1
- package/dist/core/job-executions.js +1 -2
- package/dist/core/job-executions.js.map +1 -1
- package/dist/core/maintenance.d.ts +1 -1
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +5 -5
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/provisioner-capability-snapshots.d.ts +5 -0
- package/dist/core/provisioner-capability-snapshots.d.ts.map +1 -0
- package/dist/core/provisioner-capability-snapshots.js +10 -0
- package/dist/core/provisioner-capability-snapshots.js.map +1 -0
- package/dist/core/provisioner-tokens.d.ts +10 -0
- package/dist/core/provisioner-tokens.d.ts.map +1 -1
- package/dist/core/provisioner-tokens.js +23 -1
- package/dist/core/provisioner-tokens.js.map +1 -1
- package/dist/core/rate-limit.d.ts.map +1 -1
- package/dist/core/rate-limit.js +2 -7
- package/dist/core/rate-limit.js.map +1 -1
- package/dist/core/runner-activation.d.ts +13 -0
- package/dist/core/runner-activation.d.ts.map +1 -0
- package/dist/core/runner-activation.js +36 -0
- package/dist/core/runner-activation.js.map +1 -0
- package/dist/core/runner-control-sessions.d.ts +46 -0
- package/dist/core/runner-control-sessions.d.ts.map +1 -0
- package/dist/core/runner-control-sessions.js +121 -0
- package/dist/core/runner-control-sessions.js.map +1 -0
- package/dist/core/runner-instances.d.ts +79 -0
- package/dist/core/runner-instances.d.ts.map +1 -0
- package/dist/core/runner-instances.js +168 -0
- package/dist/core/runner-instances.js.map +1 -0
- package/dist/core/runner-sessions.d.ts +8 -2
- package/dist/core/runner-sessions.d.ts.map +1 -1
- package/dist/core/runner-sessions.js +8 -5
- package/dist/core/runner-sessions.js.map +1 -1
- package/dist/db/capacity-assignments.d.ts +7 -0
- package/dist/db/capacity-assignments.d.ts.map +1 -0
- package/dist/db/capacity-assignments.js +72 -0
- package/dist/db/capacity-assignments.js.map +1 -0
- package/dist/db/db.d.ts +2837 -1009
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +11 -2
- package/dist/db/db.js.map +1 -1
- package/dist/db/ephemeral-registration-tokens.d.ts +2 -2
- package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
- package/dist/db/ephemeral-registration-tokens.js +21 -21
- package/dist/db/ephemeral-registration-tokens.js.map +1 -1
- package/dist/db/index.d.ts +7 -4
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +5 -2
- package/dist/db/index.js.map +1 -1
- package/dist/db/job-executions.d.ts +6 -6
- package/dist/db/job-executions.d.ts.map +1 -1
- package/dist/db/job-executions.js +20 -19
- package/dist/db/job-executions.js.map +1 -1
- package/dist/db/provisioner-capability-snapshots.d.ts +21 -0
- package/dist/db/provisioner-capability-snapshots.d.ts.map +1 -0
- package/dist/db/provisioner-capability-snapshots.js +57 -0
- package/dist/db/provisioner-capability-snapshots.js.map +1 -0
- package/dist/db/provisioner-tokens.d.ts +7 -2
- package/dist/db/provisioner-tokens.d.ts.map +1 -1
- package/dist/db/provisioner-tokens.js +59 -10
- package/dist/db/provisioner-tokens.js.map +1 -1
- package/dist/db/reservations.d.ts +18 -0
- package/dist/db/reservations.d.ts.map +1 -1
- package/dist/db/reservations.js +88 -1
- package/dist/db/reservations.js.map +1 -1
- package/dist/db/runner-instances.d.ts +91 -0
- package/dist/db/runner-instances.d.ts.map +1 -0
- package/dist/db/runner-instances.js +511 -0
- package/dist/db/runner-instances.js.map +1 -0
- package/dist/db/runner-sessions.d.ts +5 -0
- package/dist/db/runner-sessions.d.ts.map +1 -1
- package/dist/db/runner-sessions.js +48 -2
- package/dist/db/runner-sessions.js.map +1 -1
- package/dist/db/schema/capacity-assignments.d.ts +113 -0
- package/dist/db/schema/capacity-assignments.d.ts.map +1 -0
- package/dist/db/schema/capacity-assignments.js +29 -0
- package/dist/db/schema/capacity-assignments.js.map +1 -0
- package/dist/db/schema/ephemeral-registration-tokens.d.ts +2 -2
- package/dist/db/schema/ephemeral-registration-tokens.js +3 -3
- package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -1
- package/dist/db/schema/provisioner-capability-snapshots.d.ts +207 -0
- package/dist/db/schema/provisioner-capability-snapshots.d.ts.map +1 -0
- package/dist/db/schema/provisioner-capability-snapshots.js +38 -0
- package/dist/db/schema/provisioner-capability-snapshots.js.map +1 -0
- package/dist/db/schema/provisioner-tokens.d.ts +19 -1
- package/dist/db/schema/provisioner-tokens.d.ts.map +1 -1
- package/dist/db/schema/provisioner-tokens.js +29 -3
- package/dist/db/schema/provisioner-tokens.js.map +1 -1
- package/dist/db/schema/runner-activation-tokens.d.ts +161 -0
- package/dist/db/schema/runner-activation-tokens.d.ts.map +1 -0
- package/dist/db/schema/runner-activation-tokens.js +27 -0
- package/dist/db/schema/runner-activation-tokens.js.map +1 -0
- package/dist/db/schema/runner-control-sessions.d.ts +338 -0
- package/dist/db/schema/runner-control-sessions.d.ts.map +1 -0
- package/dist/db/schema/runner-control-sessions.js +52 -0
- package/dist/db/schema/runner-control-sessions.js.map +1 -0
- package/dist/db/schema/{provisioned-runners.d.ts → runner-instances.d.ts} +88 -34
- package/dist/db/schema/runner-instances.d.ts.map +1 -0
- package/dist/db/schema/{provisioned-runners.js → runner-instances.js} +19 -14
- package/dist/db/schema/runner-instances.js.map +1 -0
- package/dist/db/schema/runner-sessions.d.ts +39 -5
- package/dist/db/schema/runner-sessions.d.ts.map +1 -1
- package/dist/db/schema/runner-sessions.js +13 -6
- package/dist/db/schema/runner-sessions.js.map +1 -1
- package/dist/db/schema/running-job-executions.d.ts +2 -2
- package/dist/db/schema/running-job-executions.js +4 -4
- package/dist/db/schema/running-job-executions.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -38
- package/dist/index.js.map +1 -1
- package/dist/installation-provisioning.d.ts +14 -0
- package/dist/installation-provisioning.d.ts.map +1 -0
- package/dist/installation-provisioning.js +7 -0
- package/dist/installation-provisioning.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +1 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/instance.d.ts +11 -7
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +13 -7
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/auth/index.d.ts +1 -0
- package/dist/presentation/auth/index.d.ts.map +1 -1
- package/dist/presentation/auth/index.js +1 -0
- package/dist/presentation/auth/index.js.map +1 -1
- package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -1
- package/dist/presentation/auth/provisioner-token-auth.js +5 -1
- package/dist/presentation/auth/provisioner-token-auth.js.map +1 -1
- package/dist/presentation/auth/runner-control-session-auth.d.ts +4 -0
- package/dist/presentation/auth/runner-control-session-auth.d.ts.map +1 -0
- package/dist/presentation/auth/runner-control-session-auth.js +29 -0
- package/dist/presentation/auth/runner-control-session-auth.js.map +1 -0
- package/dist/presentation/auth/runner-registration-token-auth.d.ts +5 -1
- package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -1
- package/dist/presentation/auth/runner-registration-token-auth.js +21 -1
- package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -1
- package/dist/presentation/dto/index.d.ts +2 -2
- package/dist/presentation/dto/index.d.ts.map +1 -1
- package/dist/presentation/dto/index.js +2 -2
- package/dist/presentation/dto/index.js.map +1 -1
- package/dist/presentation/dto/mint-registration-tokens.d.ts +5 -3
- package/dist/presentation/dto/mint-registration-tokens.d.ts.map +1 -1
- package/dist/presentation/dto/mint-registration-tokens.js +4 -4
- package/dist/presentation/dto/mint-registration-tokens.js.map +1 -1
- package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
- package/dist/presentation/dto/poll-demand.js +7 -1
- package/dist/presentation/dto/poll-demand.js.map +1 -1
- package/dist/presentation/dto/provisioner-token.d.ts +1 -0
- package/dist/presentation/dto/provisioner-token.d.ts.map +1 -1
- package/dist/presentation/dto/provisioner-token.js +5 -1
- package/dist/presentation/dto/provisioner-token.js.map +1 -1
- package/dist/presentation/dto/{provisioned-runners.d.ts → runner-instances.d.ts} +9 -9
- package/dist/presentation/dto/runner-instances.d.ts.map +1 -0
- package/dist/presentation/dto/{provisioned-runners.js → runner-instances.js} +6 -6
- package/dist/presentation/dto/runner-instances.js.map +1 -0
- package/dist/presentation/index.d.ts +2 -2
- package/dist/presentation/index.d.ts.map +1 -1
- package/dist/presentation/index.js +2 -2
- package/dist/presentation/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts +5 -0
- package/dist/presentation/inter-module.d.ts.map +1 -0
- package/dist/presentation/inter-module.js +43 -0
- package/dist/presentation/inter-module.js.map +1 -0
- package/dist/presentation/routes/assign-capacity.d.ts +2 -0
- package/dist/presentation/routes/assign-capacity.d.ts.map +1 -0
- package/dist/presentation/routes/assign-capacity.js +44 -0
- package/dist/presentation/routes/assign-capacity.js.map +1 -0
- package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -1
- package/dist/presentation/routes/get-provisioner-me.js +5 -1
- package/dist/presentation/routes/get-provisioner-me.js.map +1 -1
- package/dist/presentation/routes/heartbeat.d.ts +2 -1
- package/dist/presentation/routes/heartbeat.d.ts.map +1 -1
- package/dist/presentation/routes/heartbeat.js +60 -50
- package/dist/presentation/routes/heartbeat.js.map +1 -1
- package/dist/presentation/routes/index.d.ts +3 -1
- package/dist/presentation/routes/index.d.ts.map +1 -1
- package/dist/presentation/routes/index.js +83 -50
- package/dist/presentation/routes/index.js.map +1 -1
- package/dist/presentation/routes/mint-registration-tokens.d.ts.map +1 -1
- package/dist/presentation/routes/mint-registration-tokens.js +5 -5
- package/dist/presentation/routes/mint-registration-tokens.js.map +1 -1
- package/dist/presentation/routes/planned-capacity.d.ts +3 -0
- package/dist/presentation/routes/planned-capacity.d.ts.map +1 -0
- package/dist/presentation/routes/planned-capacity.js +54 -0
- package/dist/presentation/routes/planned-capacity.js.map +1 -0
- package/dist/presentation/routes/poll-demand.d.ts +2 -0
- package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
- package/dist/presentation/routes/poll-demand.js +86 -45
- package/dist/presentation/routes/poll-demand.js.map +1 -1
- package/dist/presentation/routes/reconcile-runner-instances.d.ts +2 -0
- package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -0
- package/dist/presentation/routes/reconcile-runner-instances.js +27 -0
- package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -0
- package/dist/presentation/routes/register.d.ts +2 -1
- package/dist/presentation/routes/register.d.ts.map +1 -1
- package/dist/presentation/routes/register.js +55 -52
- package/dist/presentation/routes/register.js.map +1 -1
- package/dist/presentation/routes/report-runner-instances.d.ts +2 -0
- package/dist/presentation/routes/report-runner-instances.d.ts.map +1 -0
- package/dist/presentation/routes/report-runner-instances.js +37 -0
- package/dist/presentation/routes/report-runner-instances.js.map +1 -0
- package/dist/presentation/routes/request-job.d.ts +2 -1
- package/dist/presentation/routes/request-job.d.ts.map +1 -1
- package/dist/presentation/routes/request-job.js +39 -36
- package/dist/presentation/routes/request-job.js.map +1 -1
- package/dist/presentation/routes/runner-enrollment.d.ts +7 -0
- package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -0
- package/dist/presentation/routes/runner-enrollment.js +185 -0
- package/dist/presentation/routes/runner-enrollment.js.map +1 -0
- package/dist/temporal/activities/index.d.ts +2 -2
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/index.js +2 -2
- package/dist/temporal/activities/index.js.map +1 -1
- package/dist/temporal/activities/maintenance-activities.d.ts +1 -1
- package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -1
- package/dist/temporal/activities/maintenance-activities.js +3 -3
- package/dist/temporal/activities/maintenance-activities.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +3 -3
- package/dist/temporal/workflows/stuck-job-detector.js +2 -2
- package/dist/temporal/workflows/stuck-job-detector.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0000_initial.sql +102 -24
- package/drizzle/meta/0000_snapshot.json +483 -63
- package/package.json +21 -16
- package/src/config.test.ts +0 -26
- package/src/config.ts +47 -6
- package/src/core/capacity-assignments.ts +10 -0
- package/src/core/demand.test.ts +29 -29
- package/src/core/demand.ts +22 -22
- package/src/core/entities/capacity-assignment.ts +8 -0
- package/src/core/entities/ephemeral-registration-token.ts +1 -1
- package/src/core/entities/provisioner-capability-snapshot.ts +12 -0
- package/src/core/entities/provisioner-token.ts +8 -2
- package/src/core/entities/{provisioned-runner.ts → runner-instance.ts} +5 -5
- package/src/core/entities/runner-session.ts +4 -2
- package/src/core/ephemeral-registration-tokens.test.ts +11 -11
- package/src/core/ephemeral-registration-tokens.ts +18 -20
- package/src/core/errors.ts +23 -4
- package/src/core/index.ts +39 -17
- package/src/core/job-executions.ts +3 -2
- package/src/core/maintenance.test.ts +13 -17
- package/src/core/maintenance.ts +5 -5
- package/src/core/provisioner-capability-snapshots.test.ts +35 -0
- package/src/core/provisioner-capability-snapshots.ts +12 -0
- package/src/core/provisioner-tokens.test.ts +20 -0
- package/src/core/provisioner-tokens.ts +33 -0
- package/src/core/rate-limit.test.ts +11 -27
- package/src/core/rate-limit.ts +3 -11
- package/src/core/runner-activation.ts +72 -0
- package/src/core/runner-control-sessions.ts +190 -0
- package/src/core/{provisioned-runners.test.ts → runner-instances.test.ts} +24 -24
- package/src/core/runner-instances.ts +310 -0
- package/src/core/runner-sessions.test.ts +112 -22
- package/src/core/runner-sessions.ts +25 -14
- package/src/db/capacity-assignments.test.ts +159 -0
- package/src/db/capacity-assignments.ts +116 -0
- package/src/db/db.ts +11 -2
- package/src/db/ephemeral-registration-tokens.test.ts +9 -9
- package/src/db/ephemeral-registration-tokens.ts +26 -26
- package/src/db/index.ts +31 -21
- package/src/db/job-executions.test.ts +13 -11
- package/src/db/job-executions.ts +33 -27
- package/src/db/provisioner-capability-snapshots.test.ts +175 -0
- package/src/db/provisioner-capability-snapshots.ts +130 -0
- package/src/db/provisioner-tokens.test.ts +139 -2
- package/src/db/provisioner-tokens.ts +123 -15
- package/src/db/reservations.test.ts +49 -0
- package/src/db/reservations.ts +146 -1
- package/src/db/{provisioned-runners.test.ts → runner-instances.test.ts} +429 -353
- package/src/db/runner-instances.ts +942 -0
- package/src/db/runner-sessions.test.ts +19 -6
- package/src/db/runner-sessions.ts +78 -2
- package/src/db/schema/capacity-assignments.ts +34 -0
- package/src/db/schema/ephemeral-registration-tokens.ts +4 -4
- package/src/db/schema/provisioner-capability-snapshots.ts +46 -0
- package/src/db/schema/provisioner-tokens.ts +33 -2
- package/src/db/schema/runner-activation-tokens.ts +22 -0
- package/src/db/schema/runner-control-sessions.ts +46 -0
- package/src/db/schema/{provisioned-runners.ts → runner-instances.ts} +26 -27
- package/src/db/schema/runner-sessions.ts +11 -7
- package/src/db/schema/running-job-executions.ts +5 -5
- package/src/index.test.ts +26 -0
- package/src/index.ts +39 -19
- package/src/installation-provisioning.ts +14 -0
- package/src/metrics/index.ts +5 -5
- package/src/metrics/instance.ts +25 -14
- package/src/presentation/auth/index.ts +4 -0
- package/src/presentation/auth/provisioner-token-auth.ts +8 -4
- package/src/presentation/auth/runner-control-session-auth.ts +31 -0
- package/src/presentation/auth/runner-registration-token-auth.ts +39 -3
- package/src/presentation/dto/index.ts +5 -5
- package/src/presentation/dto/mint-registration-tokens.ts +8 -15
- package/src/presentation/dto/poll-demand.ts +3 -1
- package/src/presentation/dto/provisioner-token.ts +5 -0
- package/src/presentation/dto/{provisioned-runners.ts → runner-instances.ts} +13 -15
- package/src/presentation/index.ts +2 -1
- package/src/presentation/inter-module.test.ts +15 -0
- package/src/presentation/inter-module.ts +53 -0
- package/src/presentation/routes/assign-capacity.ts +48 -0
- package/src/presentation/routes/get-provisioner-me.ts +3 -4
- package/src/presentation/routes/heartbeat.test.ts +4 -3
- package/src/presentation/routes/heartbeat.ts +67 -64
- package/src/presentation/routes/index.ts +93 -43
- package/src/presentation/routes/list-active-runners.test.ts +23 -23
- package/src/presentation/routes/manual-registration-tokens.test.ts +4 -3
- package/src/presentation/routes/mint-registration-tokens.test.ts +12 -12
- package/src/presentation/routes/mint-registration-tokens.ts +5 -7
- package/src/presentation/routes/planned-capacity.ts +49 -0
- package/src/presentation/routes/poll-demand-release.test.ts +4 -4
- package/src/presentation/routes/poll-demand.test.ts +161 -22
- package/src/presentation/routes/poll-demand.ts +105 -45
- package/src/presentation/routes/provisioner-me.test.ts +37 -3
- package/src/presentation/routes/{reconcile-provisioned-runners.test.ts → reconcile-runner-instances.test.ts} +66 -61
- package/src/presentation/routes/reconcile-runner-instances.ts +30 -0
- package/src/presentation/routes/register.test.ts +9 -5
- package/src/presentation/routes/register.ts +61 -57
- package/src/presentation/routes/{report-provisioned-runners.test.ts → report-runner-instances.test.ts} +28 -28
- package/src/presentation/routes/{report-provisioned-runners.ts → report-runner-instances.ts} +14 -14
- package/src/presentation/routes/request-job.test.ts +5 -3
- package/src/presentation/routes/request-job.ts +41 -37
- package/src/presentation/routes/runner-enrollment.test.ts +259 -0
- package/src/presentation/routes/runner-enrollment.ts +174 -0
- package/src/temporal/activities/index.ts +2 -2
- package/src/temporal/activities/maintenance-activities.test.ts +7 -7
- package/src/temporal/activities/maintenance-activities.ts +3 -3
- package/src/temporal/workflows/stuck-job-detector.test.ts +3 -3
- package/src/temporal/workflows/stuck-job-detector.ts +2 -2
- package/test/env.ts +1 -3
- package/test/factories/ephemeral-registration-token.ts +2 -2
- package/test/factories/provisioner-token.ts +3 -1
- package/test/factories/runner-instance.ts +57 -0
- package/test/factories/runner-session.ts +3 -1
- package/test/fixtures/auth-inter-module.ts +30 -0
- package/test/globalSetup.ts +5 -1
- package/test/index.ts +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/dist/core/entities/provisioned-runner.d.ts.map +0 -1
- package/dist/core/entities/provisioned-runner.js +0 -3
- package/dist/core/entities/provisioned-runner.js.map +0 -1
- package/dist/core/provisioned-runners.d.ts +0 -67
- package/dist/core/provisioned-runners.d.ts.map +0 -1
- package/dist/core/provisioned-runners.js +0 -162
- package/dist/core/provisioned-runners.js.map +0 -1
- package/dist/db/provisioned-runners.d.ts +0 -79
- package/dist/db/provisioned-runners.d.ts.map +0 -1
- package/dist/db/provisioned-runners.js +0 -466
- package/dist/db/provisioned-runners.js.map +0 -1
- package/dist/db/schema/provisioned-runners.d.ts.map +0 -1
- package/dist/db/schema/provisioned-runners.js.map +0 -1
- package/dist/presentation/dto/provisioned-runners.d.ts.map +0 -1
- package/dist/presentation/dto/provisioned-runners.js.map +0 -1
- package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +0 -2
- package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +0 -1
- package/dist/presentation/routes/reconcile-provisioned-runners.js +0 -27
- package/dist/presentation/routes/reconcile-provisioned-runners.js.map +0 -1
- package/dist/presentation/routes/report-provisioned-runners.d.ts +0 -2
- package/dist/presentation/routes/report-provisioned-runners.d.ts.map +0 -1
- package/dist/presentation/routes/report-provisioned-runners.js +0 -37
- package/dist/presentation/routes/report-provisioned-runners.js.map +0 -1
- package/src/core/provisioned-runners.ts +0 -301
- package/src/db/provisioned-runners.ts +0 -886
- package/src/presentation/routes/reconcile-provisioned-runners.ts +0 -30
- 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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
70
|
+
const providerRunnerId = 'gh-runner-7';
|
|
71
71
|
await mintEphemeralRegistrationToken({
|
|
72
72
|
workspaceId,
|
|
73
73
|
provisionerId,
|
|
74
|
-
|
|
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
|
-
|
|
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
|
|
91
|
+
const providerRunnerId = 'gh-runner-7';
|
|
92
92
|
await mintEphemeralRegistrationToken({
|
|
93
93
|
workspaceId,
|
|
94
94
|
provisionerId,
|
|
95
|
-
|
|
95
|
+
providerRunnerId,
|
|
96
96
|
ttlSeconds: -1,
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
const replacement = await mintEphemeralRegistrationToken({
|
|
100
100
|
workspaceId,
|
|
101
101
|
provisionerId,
|
|
102
|
-
|
|
102
|
+
providerRunnerId,
|
|
103
103
|
ttlSeconds: 600,
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
-
expect(replacement.token.
|
|
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
|
-
|
|
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
|
|
23
|
-
|
|
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
|
-
|
|
30
|
+
providerRunners: MintEphemeralRegistrationTokensBatchRunnerInstance[];
|
|
31
31
|
ttlSeconds: number;
|
|
32
32
|
maxBatchSize: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export interface MintEphemeralRegistrationTokensBatchResult {
|
|
36
|
-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
62
|
+
if (params.providerRunners.length > params.maxBatchSize) {
|
|
63
63
|
throw new RegistrationTokenBatchTooLargeError(
|
|
64
|
-
params.
|
|
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.
|
|
71
|
-
buildEphemeralTokenRow(
|
|
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
|
|
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 =
|
|
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.
|
|
86
|
+
`Inserted token not returned for provisioned runner: ${row.providerRunnerId}`,
|
|
89
87
|
);
|
|
90
88
|
}
|
|
91
|
-
return {
|
|
89
|
+
return {providerRunnerId: row.providerRunnerId, rawToken: row.rawToken, token};
|
|
92
90
|
});
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
interface EphemeralTokenRow {
|
|
96
|
-
|
|
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(
|
|
101
|
+
function buildEphemeralTokenRow(providerRunnerId: string, expiresAt: Date): EphemeralTokenRow {
|
|
104
102
|
const rawToken = generateOpaqueToken('ephemeralRegistrationToken');
|
|
105
103
|
return {
|
|
106
|
-
|
|
104
|
+
providerRunnerId,
|
|
107
105
|
rawToken,
|
|
108
106
|
hashedToken: hashOpaqueToken(rawToken),
|
|
109
107
|
prefix: extractDisplayPrefix(rawToken),
|
package/src/core/errors.ts
CHANGED
|
@@ -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
|
|
66
|
+
public readonly providerRunnerId: string,
|
|
67
67
|
) {
|
|
68
68
|
super(
|
|
69
|
-
`Active ephemeral registration token already exists for provisioned runner ${
|
|
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 CapacityNotAssignableError extends Error {
|
|
90
|
+
constructor(public readonly capacityId: string) {
|
|
91
|
+
super(`Capacity cannot be assigned: ${capacityId}`);
|
|
92
|
+
this.name = 'CapacityNotAssignableError';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export class CapacityAlreadyAssignedError extends Error {
|
|
96
|
+
constructor(public readonly capacityId: string) {
|
|
97
|
+
super(`Capacity is already assigned: ${capacityId}`);
|
|
98
|
+
this.name = 'CapacityAlreadyAssignedError';
|
|
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
|
|
134
|
+
constructor(public readonly providerRunnerIds: string[]) {
|
|
116
135
|
super(
|
|
117
|
-
`Active ephemeral registration tokens already exist for provisioned runners: ${
|
|
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,10 +1,17 @@
|
|
|
1
|
+
export {assignCapacityBatch} from './capacity-assignments.js';
|
|
2
|
+
export type {CapacityAssignment} from './entities/capacity-assignment.js';
|
|
1
3
|
export type {EphemeralRegistrationToken} from './entities/ephemeral-registration-token.js';
|
|
2
4
|
export type {ManualRegistrationToken} from './entities/manual-registration-token.js';
|
|
5
|
+
export type {ProvisionerCapabilitySnapshot} from './entities/provisioner-capability-snapshot.js';
|
|
3
6
|
export type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
ActiveProvisionerToken,
|
|
8
|
+
ProvisionerScope,
|
|
9
|
+
ProvisionerToken,
|
|
10
|
+
} from './entities/provisioner-token.js';
|
|
11
|
+
export type {
|
|
12
|
+
RunnerInstance,
|
|
13
|
+
RunnerInstanceState,
|
|
14
|
+
} from './entities/runner-instance.js';
|
|
8
15
|
export type {RunnerSession} from './entities/runner-session.js';
|
|
9
16
|
export {
|
|
10
17
|
type MintEphemeralRegistrationTokenParams,
|
|
@@ -26,25 +33,40 @@ export {
|
|
|
26
33
|
listUsableManualRegistrationTokens,
|
|
27
34
|
revokeWorkspaceManualRegistrationToken,
|
|
28
35
|
} from './manual-registration-tokens.js';
|
|
36
|
+
export {hasActiveWorkspaceProvisionerCapability} from './provisioner-capability-snapshots.js';
|
|
29
37
|
export {
|
|
30
|
-
|
|
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 {
|
|
38
|
+
createInstallationProvisionerToken,
|
|
43
39
|
createWorkspaceProvisionerToken,
|
|
44
40
|
listActiveProvisioners,
|
|
45
41
|
listUsableProvisionerTokens,
|
|
42
|
+
revokeInstallationProvisionerToken,
|
|
46
43
|
revokeWorkspaceProvisionerToken,
|
|
47
44
|
} from './provisioner-tokens.js';
|
|
45
|
+
export {getRunnerAssignment, issueRunnerActivationToken} from './runner-activation.js';
|
|
46
|
+
export {
|
|
47
|
+
attachRunnerControlProviderId,
|
|
48
|
+
createRunnerInstancesWithBootstrapTokens,
|
|
49
|
+
enrollRunnerControlSession,
|
|
50
|
+
exchangeRunnerBootstrapToken,
|
|
51
|
+
RunnerBootstrapTokenInvalidError,
|
|
52
|
+
RunnerControlSessionInvalidError,
|
|
53
|
+
touchRunnerControlSession,
|
|
54
|
+
} from './runner-control-sessions.js';
|
|
55
|
+
export {
|
|
56
|
+
type ActiveRunner,
|
|
57
|
+
attachProviderRunnerId,
|
|
58
|
+
createPlannedProvisionedCapacity,
|
|
59
|
+
listActiveRunners,
|
|
60
|
+
type ReconcileDesiredIntent,
|
|
61
|
+
type ReconciledBoundJobExecution,
|
|
62
|
+
type ReconciledRunnerInstance,
|
|
63
|
+
type ReconcileRunnerInstancesParams,
|
|
64
|
+
type ReconcileRunnerInstancesResult,
|
|
65
|
+
type ReportRunnerInstancesParams,
|
|
66
|
+
type ReportRunnerInstancesResult,
|
|
67
|
+
reconcileRunnerInstances,
|
|
68
|
+
reportRunnerInstances,
|
|
69
|
+
} from './runner-instances.js';
|
|
48
70
|
export {
|
|
49
71
|
type RegisterRunnerSessionResult,
|
|
50
72
|
type RunnerRegistrationCredential,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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('
|
|
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
|
|
70
|
+
const providerRunner = await providerRunnerFactory.create({
|
|
75
71
|
workspaceId,
|
|
76
72
|
provisionerId: provisioner.id,
|
|
77
|
-
|
|
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(
|
|
78
|
+
.update(providerRunners)
|
|
83
79
|
.set({updatedAt: new Date(Date.now() - 120_000)})
|
|
84
|
-
.where(eq(
|
|
85
|
-
const reapedSpy = vi.spyOn(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
239
|
+
providerRunnerId: `provisioned-${params.id}`,
|
|
244
240
|
hashedToken: crypto.randomUUID(),
|
|
245
241
|
prefix: 'sfxr_test',
|
|
246
242
|
expiresAt: params.expiresAt,
|
package/src/core/maintenance.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
114
|
+
it('uses the root-derived identifier key', async () => {
|
|
115
115
|
vi.resetModules();
|
|
116
|
-
vi.
|
|
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
|
|
130
|
-
const
|
|
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.
|
|
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
|
|
143
|
-
const
|
|
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(
|
|
150
|
-
expect(
|
|
151
|
-
expect(
|
|
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.
|
|
154
|
-
vi.doUnmock('@shipfox/api-auth/config');
|
|
138
|
+
vi.unstubAllEnvs();
|
|
155
139
|
vi.resetModules();
|
|
156
140
|
}
|
|
157
141
|
});
|