@cat-factory/integrations 0.6.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/LICENSE +21 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/datadog/DatadogClient.d.ts +54 -0
- package/dist/modules/datadog/DatadogClient.d.ts.map +1 -0
- package/dist/modules/datadog/DatadogClient.js +132 -0
- package/dist/modules/datadog/DatadogClient.js.map +1 -0
- package/dist/modules/datadog/DatadogReleaseHealthProvider.d.ts +30 -0
- package/dist/modules/datadog/DatadogReleaseHealthProvider.d.ts.map +1 -0
- package/dist/modules/datadog/DatadogReleaseHealthProvider.js +101 -0
- package/dist/modules/datadog/DatadogReleaseHealthProvider.js.map +1 -0
- package/dist/modules/datadog/datadog.logic.d.ts +37 -0
- package/dist/modules/datadog/datadog.logic.d.ts.map +1 -0
- package/dist/modules/datadog/datadog.logic.js +90 -0
- package/dist/modules/datadog/datadog.logic.js.map +1 -0
- package/dist/modules/documents/ConfluenceProvider.d.ts +29 -0
- package/dist/modules/documents/ConfluenceProvider.d.ts.map +1 -0
- package/dist/modules/documents/ConfluenceProvider.js +180 -0
- package/dist/modules/documents/ConfluenceProvider.js.map +1 -0
- package/dist/modules/documents/DocumentConnectionService.d.ts +30 -0
- package/dist/modules/documents/DocumentConnectionService.d.ts.map +1 -0
- package/dist/modules/documents/DocumentConnectionService.js +69 -0
- package/dist/modules/documents/DocumentConnectionService.js.map +1 -0
- package/dist/modules/documents/DocumentImportService.d.ts +34 -0
- package/dist/modules/documents/DocumentImportService.d.ts.map +1 -0
- package/dist/modules/documents/DocumentImportService.js +83 -0
- package/dist/modules/documents/DocumentImportService.js.map +1 -0
- package/dist/modules/documents/DocumentLinkService.d.ts +31 -0
- package/dist/modules/documents/DocumentLinkService.d.ts.map +1 -0
- package/dist/modules/documents/DocumentLinkService.js +75 -0
- package/dist/modules/documents/DocumentLinkService.js.map +1 -0
- package/dist/modules/documents/DocumentPlannerService.d.ts +23 -0
- package/dist/modules/documents/DocumentPlannerService.d.ts.map +1 -0
- package/dist/modules/documents/DocumentPlannerService.js +96 -0
- package/dist/modules/documents/DocumentPlannerService.js.map +1 -0
- package/dist/modules/documents/GitHubDocsProvider.d.ts +42 -0
- package/dist/modules/documents/GitHubDocsProvider.d.ts.map +1 -0
- package/dist/modules/documents/GitHubDocsProvider.js +86 -0
- package/dist/modules/documents/GitHubDocsProvider.js.map +1 -0
- package/dist/modules/documents/NotionProvider.d.ts +32 -0
- package/dist/modules/documents/NotionProvider.d.ts.map +1 -0
- package/dist/modules/documents/NotionProvider.js +221 -0
- package/dist/modules/documents/NotionProvider.js.map +1 -0
- package/dist/modules/documents/confluence.logic.d.ts +37 -0
- package/dist/modules/documents/confluence.logic.d.ts.map +1 -0
- package/dist/modules/documents/confluence.logic.js +133 -0
- package/dist/modules/documents/confluence.logic.js.map +1 -0
- package/dist/modules/documents/documents.logic.d.ts +22 -0
- package/dist/modules/documents/documents.logic.d.ts.map +1 -0
- package/dist/modules/documents/documents.logic.js +138 -0
- package/dist/modules/documents/documents.logic.js.map +1 -0
- package/dist/modules/documents/github-docs.logic.d.ts +52 -0
- package/dist/modules/documents/github-docs.logic.d.ts.map +1 -0
- package/dist/modules/documents/github-docs.logic.js +94 -0
- package/dist/modules/documents/github-docs.logic.js.map +1 -0
- package/dist/modules/documents/notion.logic.d.ts +31 -0
- package/dist/modules/documents/notion.logic.d.ts.map +1 -0
- package/dist/modules/documents/notion.logic.js +142 -0
- package/dist/modules/documents/notion.logic.js.map +1 -0
- package/dist/modules/email/EmailConnectionService.d.ts +34 -0
- package/dist/modules/email/EmailConnectionService.d.ts.map +1 -0
- package/dist/modules/email/EmailConnectionService.js +82 -0
- package/dist/modules/email/EmailConnectionService.js.map +1 -0
- package/dist/modules/email/adapters.d.ts +39 -0
- package/dist/modules/email/adapters.d.ts.map +1 -0
- package/dist/modules/email/adapters.js +79 -0
- package/dist/modules/email/adapters.js.map +1 -0
- package/dist/modules/environments/EnvironmentConnectionService.d.ts +42 -0
- package/dist/modules/environments/EnvironmentConnectionService.d.ts.map +1 -0
- package/dist/modules/environments/EnvironmentConnectionService.js +120 -0
- package/dist/modules/environments/EnvironmentConnectionService.js.map +1 -0
- package/dist/modules/environments/EnvironmentProvisioningService.d.ts +56 -0
- package/dist/modules/environments/EnvironmentProvisioningService.d.ts.map +1 -0
- package/dist/modules/environments/EnvironmentProvisioningService.js +153 -0
- package/dist/modules/environments/EnvironmentProvisioningService.js.map +1 -0
- package/dist/modules/environments/EnvironmentTeardownService.d.ts +24 -0
- package/dist/modules/environments/EnvironmentTeardownService.d.ts.map +1 -0
- package/dist/modules/environments/EnvironmentTeardownService.js +54 -0
- package/dist/modules/environments/EnvironmentTeardownService.js.map +1 -0
- package/dist/modules/environments/HttpEnvironmentProvider.d.ts +30 -0
- package/dist/modules/environments/HttpEnvironmentProvider.d.ts.map +1 -0
- package/dist/modules/environments/HttpEnvironmentProvider.js +316 -0
- package/dist/modules/environments/HttpEnvironmentProvider.js.map +1 -0
- package/dist/modules/environments/environments.logic.d.ts +50 -0
- package/dist/modules/environments/environments.logic.d.ts.map +1 -0
- package/dist/modules/environments/environments.logic.js +257 -0
- package/dist/modules/environments/environments.logic.js.map +1 -0
- package/dist/modules/github/GitHubInstallationService.d.ts +66 -0
- package/dist/modules/github/GitHubInstallationService.d.ts.map +1 -0
- package/dist/modules/github/GitHubInstallationService.js +143 -0
- package/dist/modules/github/GitHubInstallationService.js.map +1 -0
- package/dist/modules/github/GitHubService.d.ts +29 -0
- package/dist/modules/github/GitHubService.d.ts.map +1 -0
- package/dist/modules/github/GitHubService.js +61 -0
- package/dist/modules/github/GitHubService.js.map +1 -0
- package/dist/modules/github/GitHubSyncService.d.ts +97 -0
- package/dist/modules/github/GitHubSyncService.d.ts.map +1 -0
- package/dist/modules/github/GitHubSyncService.js +241 -0
- package/dist/modules/github/GitHubSyncService.js.map +1 -0
- package/dist/modules/github/RepoProvisioningService.d.ts +26 -0
- package/dist/modules/github/RepoProvisioningService.d.ts.map +1 -0
- package/dist/modules/github/RepoProvisioningService.js +36 -0
- package/dist/modules/github/RepoProvisioningService.js.map +1 -0
- package/dist/modules/github/WebhookService.d.ts +28 -0
- package/dist/modules/github/WebhookService.d.ts.map +1 -0
- package/dist/modules/github/WebhookService.js +156 -0
- package/dist/modules/github/WebhookService.js.map +1 -0
- package/dist/modules/github/projection.logic.d.ts +95 -0
- package/dist/modules/github/projection.logic.d.ts.map +1 -0
- package/dist/modules/github/projection.logic.js +94 -0
- package/dist/modules/github/projection.logic.js.map +1 -0
- package/dist/modules/github/provisioning.logic.d.ts +11 -0
- package/dist/modules/github/provisioning.logic.d.ts.map +1 -0
- package/dist/modules/github/provisioning.logic.js +18 -0
- package/dist/modules/github/provisioning.logic.js.map +1 -0
- package/dist/modules/incident/incident.logic.d.ts +16 -0
- package/dist/modules/incident/incident.logic.d.ts.map +1 -0
- package/dist/modules/incident/incident.logic.js +23 -0
- package/dist/modules/incident/incident.logic.js.map +1 -0
- package/dist/modules/incidentio/IncidentIoEnrichmentProvider.d.ts +26 -0
- package/dist/modules/incidentio/IncidentIoEnrichmentProvider.d.ts.map +1 -0
- package/dist/modules/incidentio/IncidentIoEnrichmentProvider.js +84 -0
- package/dist/modules/incidentio/IncidentIoEnrichmentProvider.js.map +1 -0
- package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.d.ts +27 -0
- package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.d.ts.map +1 -0
- package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.js +65 -0
- package/dist/modules/pagerduty/PagerDutyEnrichmentProvider.js.map +1 -0
- package/dist/modules/providers/ApiKeyService.d.ts +73 -0
- package/dist/modules/providers/ApiKeyService.d.ts.map +1 -0
- package/dist/modules/providers/ApiKeyService.js +122 -0
- package/dist/modules/providers/ApiKeyService.js.map +1 -0
- package/dist/modules/providers/LocalModelEndpointService.d.ts +52 -0
- package/dist/modules/providers/LocalModelEndpointService.d.ts.map +1 -0
- package/dist/modules/providers/LocalModelEndpointService.js +131 -0
- package/dist/modules/providers/LocalModelEndpointService.js.map +1 -0
- package/dist/modules/providers/PersonalSubscriptionService.d.ts +94 -0
- package/dist/modules/providers/PersonalSubscriptionService.d.ts.map +1 -0
- package/dist/modules/providers/PersonalSubscriptionService.js +218 -0
- package/dist/modules/providers/PersonalSubscriptionService.js.map +1 -0
- package/dist/modules/providers/ProviderSubscriptionService.d.ts +75 -0
- package/dist/modules/providers/ProviderSubscriptionService.d.ts.map +1 -0
- package/dist/modules/providers/ProviderSubscriptionService.js +130 -0
- package/dist/modules/providers/ProviderSubscriptionService.js.map +1 -0
- package/dist/modules/providers/localModelUrl.d.ts +7 -0
- package/dist/modules/providers/localModelUrl.d.ts.map +1 -0
- package/dist/modules/providers/localModelUrl.js +67 -0
- package/dist/modules/providers/localModelUrl.js.map +1 -0
- package/dist/modules/providers/providers.logic.d.ts +23 -0
- package/dist/modules/providers/providers.logic.d.ts.map +1 -0
- package/dist/modules/providers/providers.logic.js +46 -0
- package/dist/modules/providers/providers.logic.js.map +1 -0
- package/dist/modules/runners/HttpRunnerPoolProvider.d.ts +51 -0
- package/dist/modules/runners/HttpRunnerPoolProvider.d.ts.map +1 -0
- package/dist/modules/runners/HttpRunnerPoolProvider.js +304 -0
- package/dist/modules/runners/HttpRunnerPoolProvider.js.map +1 -0
- package/dist/modules/runners/RunnerPoolConnectionService.d.ts +47 -0
- package/dist/modules/runners/RunnerPoolConnectionService.d.ts.map +1 -0
- package/dist/modules/runners/RunnerPoolConnectionService.js +98 -0
- package/dist/modules/runners/RunnerPoolConnectionService.js.map +1 -0
- package/dist/modules/runners/RunnerPoolTransport.d.ts +11 -0
- package/dist/modules/runners/RunnerPoolTransport.d.ts.map +1 -0
- package/dist/modules/runners/RunnerPoolTransport.js +61 -0
- package/dist/modules/runners/RunnerPoolTransport.js.map +1 -0
- package/dist/modules/runners/runners.logic.d.ts +16 -0
- package/dist/modules/runners/runners.logic.d.ts.map +1 -0
- package/dist/modules/runners/runners.logic.js +52 -0
- package/dist/modules/runners/runners.logic.js.map +1 -0
- package/dist/modules/slack/SlackApiClient.d.ts +67 -0
- package/dist/modules/slack/SlackApiClient.d.ts.map +1 -0
- package/dist/modules/slack/SlackApiClient.js +132 -0
- package/dist/modules/slack/SlackApiClient.js.map +1 -0
- package/dist/modules/slack/SlackConnectionService.d.ts +41 -0
- package/dist/modules/slack/SlackConnectionService.d.ts.map +1 -0
- package/dist/modules/slack/SlackConnectionService.js +136 -0
- package/dist/modules/slack/SlackConnectionService.js.map +1 -0
- package/dist/modules/slack/SlackMemberMappingService.d.ts +17 -0
- package/dist/modules/slack/SlackMemberMappingService.d.ts.map +1 -0
- package/dist/modules/slack/SlackMemberMappingService.js +28 -0
- package/dist/modules/slack/SlackMemberMappingService.js.map +1 -0
- package/dist/modules/slack/SlackNotificationChannel.d.ts +45 -0
- package/dist/modules/slack/SlackNotificationChannel.d.ts.map +1 -0
- package/dist/modules/slack/SlackNotificationChannel.js +84 -0
- package/dist/modules/slack/SlackNotificationChannel.js.map +1 -0
- package/dist/modules/slack/SlackSettingsService.d.ts +16 -0
- package/dist/modules/slack/SlackSettingsService.d.ts.map +1 -0
- package/dist/modules/slack/SlackSettingsService.js +41 -0
- package/dist/modules/slack/SlackSettingsService.js.map +1 -0
- package/dist/modules/slack/slack.logic.d.ts +55 -0
- package/dist/modules/slack/slack.logic.d.ts.map +1 -0
- package/dist/modules/slack/slack.logic.js +149 -0
- package/dist/modules/slack/slack.logic.js.map +1 -0
- package/dist/modules/tasks/GitHubIssuesProvider.d.ts +50 -0
- package/dist/modules/tasks/GitHubIssuesProvider.d.ts.map +1 -0
- package/dist/modules/tasks/GitHubIssuesProvider.js +92 -0
- package/dist/modules/tasks/GitHubIssuesProvider.js.map +1 -0
- package/dist/modules/tasks/JiraProvider.d.ts +29 -0
- package/dist/modules/tasks/JiraProvider.d.ts.map +1 -0
- package/dist/modules/tasks/JiraProvider.js +114 -0
- package/dist/modules/tasks/JiraProvider.js.map +1 -0
- package/dist/modules/tasks/TaskConnectionService.d.ts +30 -0
- package/dist/modules/tasks/TaskConnectionService.d.ts.map +1 -0
- package/dist/modules/tasks/TaskConnectionService.js +69 -0
- package/dist/modules/tasks/TaskConnectionService.js.map +1 -0
- package/dist/modules/tasks/TaskImportService.d.ts +34 -0
- package/dist/modules/tasks/TaskImportService.d.ts.map +1 -0
- package/dist/modules/tasks/TaskImportService.js +96 -0
- package/dist/modules/tasks/TaskImportService.js.map +1 -0
- package/dist/modules/tasks/TaskLinkService.d.ts +30 -0
- package/dist/modules/tasks/TaskLinkService.d.ts.map +1 -0
- package/dist/modules/tasks/TaskLinkService.js +56 -0
- package/dist/modules/tasks/TaskLinkService.js.map +1 -0
- package/dist/modules/tasks/github-issues.logic.d.ts +35 -0
- package/dist/modules/tasks/github-issues.logic.d.ts.map +1 -0
- package/dist/modules/tasks/github-issues.logic.js +67 -0
- package/dist/modules/tasks/github-issues.logic.js.map +1 -0
- package/dist/modules/tasks/jira.logic.d.ts +28 -0
- package/dist/modules/tasks/jira.logic.d.ts.map +1 -0
- package/dist/modules/tasks/jira.logic.js +151 -0
- package/dist/modules/tasks/jira.logic.js.map +1 -0
- package/dist/modules/tasks/tasks.logic.d.ts +12 -0
- package/dist/modules/tasks/tasks.logic.d.ts.map +1 -0
- package/dist/modules/tasks/tasks.logic.js +17 -0
- package/dist/modules/tasks/tasks.logic.js.map +1 -0
- package/dist/modules/tracker/TicketTrackerService.d.ts +45 -0
- package/dist/modules/tracker/TicketTrackerService.d.ts.map +1 -0
- package/dist/modules/tracker/TicketTrackerService.js +52 -0
- package/dist/modules/tracker/TicketTrackerService.js.map +1 -0
- package/dist/modules/tracker/base64.d.ts +2 -0
- package/dist/modules/tracker/base64.d.ts.map +1 -0
- package/dist/modules/tracker/base64.js +18 -0
- package/dist/modules/tracker/base64.js.map +1 -0
- package/dist/modules/tracker/github.create.logic.d.ts +16 -0
- package/dist/modules/tracker/github.create.logic.d.ts.map +1 -0
- package/dist/modules/tracker/github.create.logic.js +25 -0
- package/dist/modules/tracker/github.create.logic.js.map +1 -0
- package/dist/modules/tracker/jira.create.logic.d.ts +31 -0
- package/dist/modules/tracker/jira.create.logic.d.ts.map +1 -0
- package/dist/modules/tracker/jira.create.logic.js +59 -0
- package/dist/modules/tracker/jira.create.logic.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { STRICT_URL_SAFETY_POLICY } from '@cat-factory/kernel';
|
|
2
|
+
import * as environmentsLogic from '../environments/environments.logic.js';
|
|
3
|
+
import * as runnersLogic from './runners.logic.js';
|
|
4
|
+
// The single generic adapter that interprets ANY runner-pool manifest. There are
|
|
5
|
+
// no per-org presets: an org's pool scheduler API is described as HTTP request
|
|
6
|
+
// templates with `{{var}}` interpolation, an auth scheme, and a dot-path mapping
|
|
7
|
+
// from its (arbitrary) status response onto the canonical harness job view. This
|
|
8
|
+
// is the runner-pool sibling of HttpEnvironmentProvider and reuses the same
|
|
9
|
+
// generic primitives (interpolation, dot-path extraction, the SSRF guard).
|
|
10
|
+
//
|
|
11
|
+
// Runtime-neutral (`fetch` + Web APIs only), so both the Cloudflare Worker and the
|
|
12
|
+
// Node service drive an org's self-hosted pool through one shared implementation.
|
|
13
|
+
//
|
|
14
|
+
// Security: every URL is SSRF-guarded before it is fetched; the per-tenant
|
|
15
|
+
// scheduler secrets are resolved in-memory via the injected resolver and only
|
|
16
|
+
// ever placed in request headers — never logged or echoed in errors (error
|
|
17
|
+
// bodies are length-capped and carry no request headers). The per-job GitHub +
|
|
18
|
+
// LLM-proxy tokens travel inside the interpolated dispatch body (the runner needs
|
|
19
|
+
// them) and are likewise never logged.
|
|
20
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
21
|
+
const MAX_RESPONSE_CHARS = 200_000;
|
|
22
|
+
const USER_AGENT = 'cat-factory';
|
|
23
|
+
/** Carries the HTTP status so callers can surface a meaningful (redacted) error. */
|
|
24
|
+
export class RunnerPoolApiError extends Error {
|
|
25
|
+
status;
|
|
26
|
+
constructor(status, message) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.status = status;
|
|
29
|
+
this.name = 'RunnerPoolApiError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class HttpRunnerPoolProvider {
|
|
33
|
+
defaultTimeoutMs;
|
|
34
|
+
urlPolicy;
|
|
35
|
+
/** Per-isolate OAuth token cache, keyed by token URL + client id. */
|
|
36
|
+
oauthCache = new Map();
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.defaultTimeoutMs = options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
39
|
+
this.urlPolicy = options.urlPolicy ?? STRICT_URL_SAFETY_POLICY;
|
|
40
|
+
}
|
|
41
|
+
async dispatch(req) {
|
|
42
|
+
await this.execute(req.manifest, req.manifest.dispatch, this.scope(req.jobId, req.spec), req.resolveSecret);
|
|
43
|
+
}
|
|
44
|
+
async poll(req) {
|
|
45
|
+
const json = await this.execute(req.manifest, req.manifest.poll, this.scope(req.jobId), req.resolveSecret);
|
|
46
|
+
return this.mapJobView(req.manifest, json);
|
|
47
|
+
}
|
|
48
|
+
async release(req) {
|
|
49
|
+
if (!req.manifest.release)
|
|
50
|
+
return;
|
|
51
|
+
await this.execute(req.manifest, req.manifest.release, this.scope(req.jobId), req.resolveSecret);
|
|
52
|
+
}
|
|
53
|
+
// --- internals ----------------------------------------------------------
|
|
54
|
+
/**
|
|
55
|
+
* The bounded interpolation scope a template sees:
|
|
56
|
+
* - `{{input.jobId}}` — the id the pool is keyed on (sticky routing target);
|
|
57
|
+
* - `{{input.job}}` — the full harness job spec as JSON, so a body template can
|
|
58
|
+
* forward it verbatim (`{"payload":{{input.job}}}`);
|
|
59
|
+
* - `{{input.kind}}` — the harness job kind (`run` | `blueprint` | `spec` |
|
|
60
|
+
* `explore` | `bootstrap` | `ci-fix` | `resolve-conflicts` |
|
|
61
|
+
* `merge` | `on-call` | `test` | `fix-tests`). The harness
|
|
62
|
+
* itself reads the kind from the job body (`POST /jobs`), so
|
|
63
|
+
* a manifest does NOT need to route by kind; this is exposed
|
|
64
|
+
* flat only so a manifest can map it to a scheduler-side
|
|
65
|
+
* node selector / queue / resource hint without decoding the
|
|
66
|
+
* embedded `{{input.job}}` JSON;
|
|
67
|
+
* - `{{input.instanceType}}` / `{{input.cloudProvider}}` — the provisioning hints
|
|
68
|
+
* the transport stamped on for a self-provisioning pool
|
|
69
|
+
* (present only when the service pins a size/provider), so a
|
|
70
|
+
* manifest can map them to a node selector / resource request
|
|
71
|
+
* / queue without decoding `{{input.job}}`.
|
|
72
|
+
* Reuses the environments interpolation machinery; the second (`provision`)
|
|
73
|
+
* namespace is unused by runner manifests.
|
|
74
|
+
*/
|
|
75
|
+
scope(jobId, spec) {
|
|
76
|
+
const input = {
|
|
77
|
+
jobId,
|
|
78
|
+
job: spec ? JSON.stringify(spec) : '',
|
|
79
|
+
};
|
|
80
|
+
// Surface the routing/sizing hints the RunnerPoolTransport stamps onto the
|
|
81
|
+
// dispatch spec as first-class `{{input.*}}` variables. They live inside
|
|
82
|
+
// `{{input.job}}` too, but a path/query/header template can't reach into that JSON
|
|
83
|
+
// string — exposing them flat lets a manifest route-by-kind and size declaratively.
|
|
84
|
+
for (const key of ['kind', 'instanceType', 'cloudProvider']) {
|
|
85
|
+
const value = spec?.[key];
|
|
86
|
+
if (typeof value === 'string')
|
|
87
|
+
input[key] = value;
|
|
88
|
+
}
|
|
89
|
+
return { input, provision: {} };
|
|
90
|
+
}
|
|
91
|
+
async execute(manifest, template, scope, resolveSecret) {
|
|
92
|
+
const url = this.buildUrl(manifest.baseUrl, template, scope);
|
|
93
|
+
environmentsLogic.assertSafeEnvironmentUrl(url, 'request URL', this.urlPolicy);
|
|
94
|
+
const headers = {
|
|
95
|
+
accept: 'application/json',
|
|
96
|
+
'user-agent': USER_AGENT,
|
|
97
|
+
...(await this.authHeaders(manifest.auth, resolveSecret)),
|
|
98
|
+
};
|
|
99
|
+
for (const h of template.headers ?? []) {
|
|
100
|
+
headers[h.name] = environmentsLogic.interpolateTemplate(h.value, scope);
|
|
101
|
+
}
|
|
102
|
+
let body;
|
|
103
|
+
if (template.bodyTemplate !== undefined && template.method !== 'GET') {
|
|
104
|
+
body = environmentsLogic.interpolateTemplate(template.bodyTemplate, scope);
|
|
105
|
+
if (!headers['content-type'])
|
|
106
|
+
headers['content-type'] = 'application/json';
|
|
107
|
+
}
|
|
108
|
+
const res = await fetch(url, {
|
|
109
|
+
method: template.method,
|
|
110
|
+
headers,
|
|
111
|
+
body,
|
|
112
|
+
signal: AbortSignal.timeout(template.timeoutMs ?? this.defaultTimeoutMs),
|
|
113
|
+
});
|
|
114
|
+
const text = await res.text().catch(() => '');
|
|
115
|
+
if (!res.ok) {
|
|
116
|
+
throw new RunnerPoolApiError(res.status, `Runner pool ${template.method} → ${res.status}: ${text.slice(0, 300)}`);
|
|
117
|
+
}
|
|
118
|
+
if (text.length > MAX_RESPONSE_CHARS) {
|
|
119
|
+
throw new RunnerPoolApiError(502, 'Runner pool response too large');
|
|
120
|
+
}
|
|
121
|
+
if (!text)
|
|
122
|
+
return {};
|
|
123
|
+
try {
|
|
124
|
+
return JSON.parse(text);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return {};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
buildUrl(baseUrl, template, scope) {
|
|
131
|
+
const base = baseUrl.replace(/\/+$/, '');
|
|
132
|
+
const path = environmentsLogic.interpolateTemplate(template.pathTemplate, scope);
|
|
133
|
+
let url = path ? `${base}${path.startsWith('/') ? '' : '/'}${path}` : base;
|
|
134
|
+
const query = (template.query ?? [])
|
|
135
|
+
.map((q) => `${encodeURIComponent(q.key)}=${encodeURIComponent(environmentsLogic.interpolateTemplate(q.value, scope))}`)
|
|
136
|
+
.join('&');
|
|
137
|
+
if (query)
|
|
138
|
+
url += `${url.includes('?') ? '&' : '?'}${query}`;
|
|
139
|
+
return url;
|
|
140
|
+
}
|
|
141
|
+
async authHeaders(auth, resolveSecret) {
|
|
142
|
+
const secret = (key) => {
|
|
143
|
+
const value = resolveSecret(key);
|
|
144
|
+
if (value === undefined)
|
|
145
|
+
throw new RunnerPoolApiError(500, `Missing secret '${key}'`);
|
|
146
|
+
return value;
|
|
147
|
+
};
|
|
148
|
+
switch (auth.type) {
|
|
149
|
+
case 'none':
|
|
150
|
+
return {};
|
|
151
|
+
case 'api_key':
|
|
152
|
+
return { [auth.headerName]: `${auth.valuePrefix ?? ''}${secret(auth.secretRef.key)}` };
|
|
153
|
+
case 'bearer':
|
|
154
|
+
return { authorization: `Bearer ${secret(auth.secretRef.key)}` };
|
|
155
|
+
case 'basic':
|
|
156
|
+
return {
|
|
157
|
+
authorization: `Basic ${btoa(`${secret(auth.usernameSecretRef.key)}:${secret(auth.passwordSecretRef.key)}`)}`,
|
|
158
|
+
};
|
|
159
|
+
case 'oauth2_client_credentials':
|
|
160
|
+
return { authorization: `Bearer ${await this.oauthToken(auth, secret)}` };
|
|
161
|
+
case 'custom_headers': {
|
|
162
|
+
const headers = {};
|
|
163
|
+
for (const h of auth.headers)
|
|
164
|
+
headers[h.name] = secret(h.secretRef.key);
|
|
165
|
+
return headers;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async oauthToken(auth, secret) {
|
|
170
|
+
const clientId = secret(auth.clientIdSecretRef.key);
|
|
171
|
+
const cacheKey = `${auth.tokenUrl}::${clientId}`;
|
|
172
|
+
const cached = this.oauthCache.get(cacheKey);
|
|
173
|
+
if (cached && cached.expiresAt > Date.now() + 5_000)
|
|
174
|
+
return cached.token;
|
|
175
|
+
environmentsLogic.assertSafeEnvironmentUrl(auth.tokenUrl, 'OAuth token URL', this.urlPolicy);
|
|
176
|
+
const form = new URLSearchParams({
|
|
177
|
+
grant_type: 'client_credentials',
|
|
178
|
+
client_id: clientId,
|
|
179
|
+
client_secret: secret(auth.clientSecretSecretRef.key),
|
|
180
|
+
});
|
|
181
|
+
if (auth.scope)
|
|
182
|
+
form.set('scope', auth.scope);
|
|
183
|
+
if (auth.audience)
|
|
184
|
+
form.set('audience', auth.audience);
|
|
185
|
+
const res = await fetch(auth.tokenUrl, {
|
|
186
|
+
method: 'POST',
|
|
187
|
+
headers: {
|
|
188
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
189
|
+
accept: 'application/json',
|
|
190
|
+
'user-agent': USER_AGENT,
|
|
191
|
+
},
|
|
192
|
+
body: form.toString(),
|
|
193
|
+
signal: AbortSignal.timeout(this.defaultTimeoutMs),
|
|
194
|
+
});
|
|
195
|
+
if (!res.ok) {
|
|
196
|
+
const text = await res.text().catch(() => '');
|
|
197
|
+
throw new RunnerPoolApiError(res.status, `OAuth token request → ${res.status}: ${text.slice(0, 200)}`);
|
|
198
|
+
}
|
|
199
|
+
const json = (await res.json().catch(() => null));
|
|
200
|
+
if (!json?.access_token) {
|
|
201
|
+
throw new RunnerPoolApiError(502, 'OAuth token response missing access_token');
|
|
202
|
+
}
|
|
203
|
+
const ttlMs = (typeof json.expires_in === 'number' ? json.expires_in : 300) * 1000;
|
|
204
|
+
this.oauthCache.set(cacheKey, { token: json.access_token, expiresAt: Date.now() + ttlMs });
|
|
205
|
+
return json.access_token;
|
|
206
|
+
}
|
|
207
|
+
/** Project the scheduler's arbitrary status response onto the canonical view. */
|
|
208
|
+
mapJobView(manifest, json) {
|
|
209
|
+
const r = manifest.response;
|
|
210
|
+
const rawStatus = environmentsLogic.extractString(json, r.statusPath);
|
|
211
|
+
const state = runnersLogic.mapJobState(rawStatus, r.statusMap);
|
|
212
|
+
const error = environmentsLogic.extractString(json, r.errorPath);
|
|
213
|
+
const view = { state };
|
|
214
|
+
const progress = this.mapProgress(manifest, json);
|
|
215
|
+
if (progress)
|
|
216
|
+
view.progress = progress;
|
|
217
|
+
if (state === 'failed') {
|
|
218
|
+
view.error = error ?? 'Runner pool reported the job failed';
|
|
219
|
+
return view;
|
|
220
|
+
}
|
|
221
|
+
if (state === 'done') {
|
|
222
|
+
const result = {};
|
|
223
|
+
// The WHOLE structured work product when the scheduler exposes the harness
|
|
224
|
+
// `result` envelope: forwards EVERY product (blueprint tree, spec, merge
|
|
225
|
+
// assessment, test report, bootstrap branch, …), not just the PR scalars — so a
|
|
226
|
+
// pool-backed tester/merger/blueprinter reaches the engine intact.
|
|
227
|
+
if (r.resultPath) {
|
|
228
|
+
Object.assign(result, coerceRunnerResult(environmentsLogic.extractByPath(json, r.resultPath)));
|
|
229
|
+
}
|
|
230
|
+
// Individual scalar paths still apply (and override) for schedulers that surface
|
|
231
|
+
// the PR url / branch / summary outside any result envelope.
|
|
232
|
+
const prUrl = environmentsLogic.extractString(json, r.prUrlPath);
|
|
233
|
+
const branch = environmentsLogic.extractString(json, r.branchPath);
|
|
234
|
+
const summary = environmentsLogic.extractString(json, r.summaryPath);
|
|
235
|
+
if (prUrl)
|
|
236
|
+
result.prUrl = prUrl;
|
|
237
|
+
if (branch)
|
|
238
|
+
result.branch = branch;
|
|
239
|
+
if (summary)
|
|
240
|
+
result.summary = summary;
|
|
241
|
+
// A structured error on an otherwise-"done" job is still a failure; the
|
|
242
|
+
// executor maps a result-level `error` to a failed step.
|
|
243
|
+
if (error)
|
|
244
|
+
result.error = error;
|
|
245
|
+
view.result = result;
|
|
246
|
+
}
|
|
247
|
+
return view;
|
|
248
|
+
}
|
|
249
|
+
mapProgress(manifest, json) {
|
|
250
|
+
const r = manifest.response;
|
|
251
|
+
const num = (path) => {
|
|
252
|
+
const raw = environmentsLogic.extractString(json, path);
|
|
253
|
+
if (raw === undefined)
|
|
254
|
+
return undefined;
|
|
255
|
+
const n = Number(raw);
|
|
256
|
+
return Number.isFinite(n) ? n : undefined;
|
|
257
|
+
};
|
|
258
|
+
const completed = num(r.progressCompletedPath);
|
|
259
|
+
const inProgress = num(r.progressInProgressPath);
|
|
260
|
+
const total = num(r.progressTotalPath);
|
|
261
|
+
if (completed === undefined && inProgress === undefined && total === undefined)
|
|
262
|
+
return undefined;
|
|
263
|
+
return { completed: completed ?? 0, inProgress: inProgress ?? 0, total: total ?? 0 };
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Coerce a scheduler's `result` envelope into the canonical {@link RunnerJobResult},
|
|
268
|
+
* picking only the known fields by type. The structured products (`service` /
|
|
269
|
+
* `spec` / `assessment` / `report`) are passed through verbatim for the engine to
|
|
270
|
+
* strictly validate; the scalars/booleans are type-guarded. Anything unexpected is
|
|
271
|
+
* dropped, so a malformed envelope can never inject junk into the run result.
|
|
272
|
+
*/
|
|
273
|
+
function coerceRunnerResult(raw) {
|
|
274
|
+
if (typeof raw !== 'object' || raw === null)
|
|
275
|
+
return {};
|
|
276
|
+
const o = raw;
|
|
277
|
+
const out = {};
|
|
278
|
+
const STRINGS = ['prUrl', 'branch', 'summary', 'error', 'defaultBranch'];
|
|
279
|
+
for (const k of STRINGS) {
|
|
280
|
+
if (typeof o[k] === 'string')
|
|
281
|
+
out[k] = o[k];
|
|
282
|
+
}
|
|
283
|
+
if (typeof o.pushed === 'boolean')
|
|
284
|
+
out.pushed = o.pushed;
|
|
285
|
+
if (typeof o.resolved === 'boolean')
|
|
286
|
+
out.resolved = o.resolved;
|
|
287
|
+
// Structured work products (carried as `unknown` on the port — the engine validates).
|
|
288
|
+
for (const k of ['service', 'spec', 'assessment', 'report']) {
|
|
289
|
+
if (o[k] !== undefined)
|
|
290
|
+
out[k] = o[k];
|
|
291
|
+
}
|
|
292
|
+
const usage = o.usage;
|
|
293
|
+
if (typeof usage === 'object' &&
|
|
294
|
+
usage !== null &&
|
|
295
|
+
typeof usage.inputTokens === 'number' &&
|
|
296
|
+
typeof usage.outputTokens === 'number') {
|
|
297
|
+
out.usage = {
|
|
298
|
+
inputTokens: usage.inputTokens,
|
|
299
|
+
outputTokens: usage.outputTokens,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
//# sourceMappingURL=HttpRunnerPoolProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpRunnerPoolProvider.js","sourceRoot":"","sources":["../../../src/modules/runners/HttpRunnerPoolProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Clock } from '@cat-factory/kernel';
|
|
2
|
+
import type { RunnerPoolConnectionRecord, RunnerPoolConnectionRepository } from '@cat-factory/kernel';
|
|
3
|
+
import type { SecretCipher } from '@cat-factory/kernel';
|
|
4
|
+
import type { SecretResolver, UrlSafetyPolicy } from '@cat-factory/kernel';
|
|
5
|
+
import type { RunnerPoolConnection, RunnerPoolManifest } from '@cat-factory/kernel';
|
|
6
|
+
import type { WorkspaceRepository } from '@cat-factory/kernel';
|
|
7
|
+
export interface RunnerPoolConnectionServiceDependencies {
|
|
8
|
+
runnerPoolConnectionRepository: RunnerPoolConnectionRepository;
|
|
9
|
+
workspaceRepository: WorkspaceRepository;
|
|
10
|
+
secretCipher: SecretCipher;
|
|
11
|
+
clock: Clock;
|
|
12
|
+
/** URL/host safety policy applied to a registered manifest. Defaults to strict. */
|
|
13
|
+
urlPolicy?: UrlSafetyPolicy;
|
|
14
|
+
}
|
|
15
|
+
export interface ResolvedRunnerPool {
|
|
16
|
+
manifest: RunnerPoolManifest;
|
|
17
|
+
resolveSecret: SecretResolver;
|
|
18
|
+
}
|
|
19
|
+
export declare class RunnerPoolConnectionService {
|
|
20
|
+
private readonly deps;
|
|
21
|
+
constructor(deps: RunnerPoolConnectionServiceDependencies);
|
|
22
|
+
/** Register (or replace) a workspace's runner pool. */
|
|
23
|
+
register(workspaceId: string, input: {
|
|
24
|
+
manifest: RunnerPoolManifest;
|
|
25
|
+
secrets: Record<string, string>;
|
|
26
|
+
}): Promise<RunnerPoolConnection>;
|
|
27
|
+
/** Rotate/replace the secret bundle without re-sending the manifest. */
|
|
28
|
+
updateSecrets(workspaceId: string, secrets: Record<string, string>): Promise<RunnerPoolConnection>;
|
|
29
|
+
/** The workspace's current connection (safe metadata), or null. */
|
|
30
|
+
getConnection(workspaceId: string): Promise<RunnerPoolConnection | null>;
|
|
31
|
+
/** Resolve the live connection + parsed manifest, or throw if not registered. */
|
|
32
|
+
requireConnection(workspaceId: string): Promise<{
|
|
33
|
+
record: RunnerPoolConnectionRecord;
|
|
34
|
+
manifest: RunnerPoolManifest;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve the workspace's pool (parsed manifest + a secret resolver over its
|
|
38
|
+
* decrypted bundle), or null when it has no live pool registered. Used by the
|
|
39
|
+
* container executor to pick the self-hosted runner backend per job.
|
|
40
|
+
*/
|
|
41
|
+
resolve(workspaceId: string): Promise<ResolvedRunnerPool | null>;
|
|
42
|
+
/** Unregister the pool (tombstones the binding). */
|
|
43
|
+
unregister(workspaceId: string): Promise<void>;
|
|
44
|
+
private decryptSecrets;
|
|
45
|
+
private toConnection;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=RunnerPoolConnectionService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunnerPoolConnectionService.d.ts","sourceRoot":"","sources":["../../../src/modules/runners/RunnerPoolConnectionService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EACV,0BAA0B,EAC1B,8BAA8B,EAC/B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAGnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAS9D,MAAM,WAAW,uCAAuC;IACtD,8BAA8B,EAAE,8BAA8B,CAAA;IAC9D,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,YAAY,EAAE,YAAY,CAAA;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,mFAAmF;IACnF,SAAS,CAAC,EAAE,eAAe,CAAA;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,aAAa,EAAE,cAAc,CAAA;CAC9B;AAED,qBAAa,2BAA2B;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,uCAAuC,EAAI;IAE9E,uDAAuD;IACjD,QAAQ,CACZ,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE;QAAE,QAAQ,EAAE,kBAAkB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GACvE,OAAO,CAAC,oBAAoB,CAAC,CAwB/B;IAED,wEAAwE;IAClE,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAU/B;IAED,mEAAmE;IAC7D,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAK7E;IAED,iFAAiF;IAC3E,iBAAiB,CACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,MAAM,EAAE,0BAA0B,CAAC;QAAC,QAAQ,EAAE,kBAAkB,CAAA;KAAE,CAAC,CAO/E;IAED;;;;OAIG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAMrE;IAED,oDAAoD;IAC9C,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAInD;YAEa,cAAc;IAQ5B,OAAO,CAAC,YAAY;CAYrB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ConflictError, STRICT_URL_SAFETY_POLICY, ValidationError } from '@cat-factory/kernel';
|
|
2
|
+
import { requireWorkspace } from '@cat-factory/kernel';
|
|
3
|
+
import { assertManifestUrlsSafe, referencedSecretKeys } from './runners.logic.js';
|
|
4
|
+
export class RunnerPoolConnectionService {
|
|
5
|
+
deps;
|
|
6
|
+
constructor(deps) {
|
|
7
|
+
this.deps = deps;
|
|
8
|
+
}
|
|
9
|
+
/** Register (or replace) a workspace's runner pool. */
|
|
10
|
+
async register(workspaceId, input) {
|
|
11
|
+
await requireWorkspace(this.deps.workspaceRepository, workspaceId);
|
|
12
|
+
const manifest = input.manifest;
|
|
13
|
+
assertManifestUrlsSafe(manifest, this.deps.urlPolicy ?? STRICT_URL_SAFETY_POLICY);
|
|
14
|
+
const missing = referencedSecretKeys(manifest).filter((key) => !(key in input.secrets));
|
|
15
|
+
if (missing.length) {
|
|
16
|
+
throw new ValidationError(`Missing secret values for: ${missing.join(', ')}`);
|
|
17
|
+
}
|
|
18
|
+
const existing = await this.deps.runnerPoolConnectionRepository.getByWorkspace(workspaceId);
|
|
19
|
+
const secretsCipher = await this.deps.secretCipher.encrypt(JSON.stringify(input.secrets));
|
|
20
|
+
const record = {
|
|
21
|
+
workspaceId,
|
|
22
|
+
providerId: manifest.providerId,
|
|
23
|
+
label: manifest.label,
|
|
24
|
+
baseUrl: manifest.baseUrl,
|
|
25
|
+
manifestJson: JSON.stringify(manifest),
|
|
26
|
+
secretsCipher,
|
|
27
|
+
createdAt: existing?.createdAt ?? this.deps.clock.now(),
|
|
28
|
+
deletedAt: null,
|
|
29
|
+
};
|
|
30
|
+
await this.deps.runnerPoolConnectionRepository.upsert(record);
|
|
31
|
+
return this.toConnection(record, Object.keys(input.secrets));
|
|
32
|
+
}
|
|
33
|
+
/** Rotate/replace the secret bundle without re-sending the manifest. */
|
|
34
|
+
async updateSecrets(workspaceId, secrets) {
|
|
35
|
+
const { record, manifest } = await this.requireConnection(workspaceId);
|
|
36
|
+
const missing = referencedSecretKeys(manifest).filter((key) => !(key in secrets));
|
|
37
|
+
if (missing.length) {
|
|
38
|
+
throw new ValidationError(`Missing secret values for: ${missing.join(', ')}`);
|
|
39
|
+
}
|
|
40
|
+
const secretsCipher = await this.deps.secretCipher.encrypt(JSON.stringify(secrets));
|
|
41
|
+
const updated = { ...record, secretsCipher };
|
|
42
|
+
await this.deps.runnerPoolConnectionRepository.upsert(updated);
|
|
43
|
+
return this.toConnection(updated, Object.keys(secrets));
|
|
44
|
+
}
|
|
45
|
+
/** The workspace's current connection (safe metadata), or null. */
|
|
46
|
+
async getConnection(workspaceId) {
|
|
47
|
+
const record = await this.deps.runnerPoolConnectionRepository.getByWorkspace(workspaceId);
|
|
48
|
+
if (!record)
|
|
49
|
+
return null;
|
|
50
|
+
const keys = Object.keys(await this.decryptSecrets(record));
|
|
51
|
+
return this.toConnection(record, keys);
|
|
52
|
+
}
|
|
53
|
+
/** Resolve the live connection + parsed manifest, or throw if not registered. */
|
|
54
|
+
async requireConnection(workspaceId) {
|
|
55
|
+
const record = await this.deps.runnerPoolConnectionRepository.getByWorkspace(workspaceId);
|
|
56
|
+
if (!record) {
|
|
57
|
+
throw new ConflictError(`Workspace '${workspaceId}' has no runner pool registered`);
|
|
58
|
+
}
|
|
59
|
+
const manifest = JSON.parse(record.manifestJson);
|
|
60
|
+
return { record, manifest };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the workspace's pool (parsed manifest + a secret resolver over its
|
|
64
|
+
* decrypted bundle), or null when it has no live pool registered. Used by the
|
|
65
|
+
* container executor to pick the self-hosted runner backend per job.
|
|
66
|
+
*/
|
|
67
|
+
async resolve(workspaceId) {
|
|
68
|
+
const record = await this.deps.runnerPoolConnectionRepository.getByWorkspace(workspaceId);
|
|
69
|
+
if (!record)
|
|
70
|
+
return null;
|
|
71
|
+
const manifest = JSON.parse(record.manifestJson);
|
|
72
|
+
const bundle = await this.decryptSecrets(record);
|
|
73
|
+
return { manifest, resolveSecret: (key) => bundle[key] };
|
|
74
|
+
}
|
|
75
|
+
/** Unregister the pool (tombstones the binding). */
|
|
76
|
+
async unregister(workspaceId) {
|
|
77
|
+
const record = await this.deps.runnerPoolConnectionRepository.getByWorkspace(workspaceId);
|
|
78
|
+
if (!record)
|
|
79
|
+
return;
|
|
80
|
+
await this.deps.runnerPoolConnectionRepository.softDelete(workspaceId, this.deps.clock.now());
|
|
81
|
+
}
|
|
82
|
+
async decryptSecrets(record) {
|
|
83
|
+
if (!record.secretsCipher)
|
|
84
|
+
return {};
|
|
85
|
+
const parsed = JSON.parse(await this.deps.secretCipher.decrypt(record.secretsCipher));
|
|
86
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
87
|
+
}
|
|
88
|
+
toConnection(record, secretKeys) {
|
|
89
|
+
return {
|
|
90
|
+
providerId: record.providerId,
|
|
91
|
+
label: record.label,
|
|
92
|
+
baseUrl: record.baseUrl,
|
|
93
|
+
connectedAt: record.createdAt,
|
|
94
|
+
secretKeys,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=RunnerPoolConnectionService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunnerPoolConnectionService.js","sourceRoot":"","sources":["../../../src/modules/runners/RunnerPoolConnectionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RunnerDispatchKind, RunnerDispatchOptions, RunnerJobRef, RunnerJobView, RunnerPoolManifest, RunnerPoolProvider, RunnerTransport, SecretResolver } from '@cat-factory/kernel';
|
|
2
|
+
export declare class RunnerPoolTransport implements RunnerTransport {
|
|
3
|
+
private readonly provider;
|
|
4
|
+
private readonly manifest;
|
|
5
|
+
private readonly resolveSecret;
|
|
6
|
+
constructor(provider: RunnerPoolProvider, manifest: RunnerPoolManifest, resolveSecret: SecretResolver);
|
|
7
|
+
dispatch(ref: RunnerJobRef, spec: Record<string, unknown>, kind?: RunnerDispatchKind, options?: RunnerDispatchOptions): Promise<void>;
|
|
8
|
+
poll(ref: RunnerJobRef): Promise<RunnerJobView>;
|
|
9
|
+
release(ref: RunnerJobRef): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=RunnerPoolTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunnerPoolTransport.d.ts","sourceRoot":"","sources":["../../../src/modules/runners/RunnerPoolTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACf,MAAM,qBAAqB,CAAA;AAgB5B,qBAAa,mBAAoB,YAAW,eAAe;IAEvD,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAHhC,YACmB,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,kBAAkB,EAC5B,aAAa,EAAE,cAAc,EAC5C;IAEJ,QAAQ,CACN,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,GAAE,kBAA0B,EAChC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAsBf;IAED,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAM9C;IAED,OAAO,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxC;CACF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Adapts the stateless, manifest-interpreting HttpRunnerPoolProvider to the
|
|
2
|
+
// RunnerTransport the container executor drives, binding one workspace's resolved
|
|
3
|
+
// manifest + secret resolver. One instance per (workspace) dispatch/poll resolution;
|
|
4
|
+
// the underlying provider (and its OAuth cache) is shared.
|
|
5
|
+
//
|
|
6
|
+
// A pool is a PER-JOB backend — it has no per-run container to share across steps —
|
|
7
|
+
// so it keys on the per-step `ref.jobId`; each step is an independent pool job, which
|
|
8
|
+
// is exactly what keeps sibling steps from colliding here too. `ref.runId` is unused
|
|
9
|
+
// (there is no run-scoped resource to address), and `release` cancels the run's
|
|
10
|
+
// in-flight job by its id.
|
|
11
|
+
//
|
|
12
|
+
// Runtime-neutral: both the Cloudflare Worker and the Node service resolve this
|
|
13
|
+
// transport for a workspace whose self-hosted runner pool is registered.
|
|
14
|
+
export class RunnerPoolTransport {
|
|
15
|
+
provider;
|
|
16
|
+
manifest;
|
|
17
|
+
resolveSecret;
|
|
18
|
+
constructor(provider, manifest, resolveSecret) {
|
|
19
|
+
this.provider = provider;
|
|
20
|
+
this.manifest = manifest;
|
|
21
|
+
this.resolveSecret = resolveSecret;
|
|
22
|
+
}
|
|
23
|
+
dispatch(ref, spec, kind = 'run', options) {
|
|
24
|
+
const jobId = ref.jobId;
|
|
25
|
+
// A pool runs the SAME executor-harness image as the Cloudflare backend, so it
|
|
26
|
+
// serves every harness route. Runtime parity is the default and assumed (the "keep
|
|
27
|
+
// the runtimes symmetric" guideline): there is no opt-in allow-list to gate kinds,
|
|
28
|
+
// so a new harness kind dispatches to a pool automatically, exactly as it does to a
|
|
29
|
+
// Cloudflare container, never silently diverging.
|
|
30
|
+
//
|
|
31
|
+
// Forward the harness route kind and the resolved provisioning hints (the
|
|
32
|
+
// instance-type id + the cloud provider) in the dispatch spec so a pool that
|
|
33
|
+
// provisions on its own cloud can route to the right endpoint and size the runner.
|
|
34
|
+
return this.provider.dispatch({
|
|
35
|
+
manifest: this.manifest,
|
|
36
|
+
jobId,
|
|
37
|
+
spec: {
|
|
38
|
+
...spec,
|
|
39
|
+
kind,
|
|
40
|
+
...(options?.instanceTypeId ? { instanceType: options.instanceTypeId } : {}),
|
|
41
|
+
...(options?.provider ? { cloudProvider: options.provider } : {}),
|
|
42
|
+
},
|
|
43
|
+
resolveSecret: this.resolveSecret,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
poll(ref) {
|
|
47
|
+
return this.provider.poll({
|
|
48
|
+
manifest: this.manifest,
|
|
49
|
+
jobId: ref.jobId,
|
|
50
|
+
resolveSecret: this.resolveSecret,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
release(ref) {
|
|
54
|
+
return this.provider.release({
|
|
55
|
+
manifest: this.manifest,
|
|
56
|
+
jobId: ref.jobId,
|
|
57
|
+
resolveSecret: this.resolveSecret,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=RunnerPoolTransport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunnerPoolTransport.js","sourceRoot":"","sources":["../../../src/modules/runners/RunnerPoolTransport.ts"],"names":[],"mappings":"AAWA,4EAA4E;AAC5E,kFAAkF;AAClF,qFAAqF;AACrF,2DAA2D;AAC3D,EAAE;AACF,oFAAoF;AACpF,sFAAsF;AACtF,qFAAqF;AACrF,gFAAgF;AAChF,2BAA2B;AAC3B,EAAE;AACF,gFAAgF;AAChF,yEAAyE;AAEzE,MAAM,OAAO,mBAAmB;IAEX,QAAQ;IACR,QAAQ;IACR,aAAa;IAHhC,YACmB,QAA4B,EAC5B,QAA4B,EAC5B,aAA6B;wBAF7B,QAAQ;wBACR,QAAQ;6BACR,aAAa;IAC7B,CAAC;IAEJ,QAAQ,CACN,GAAiB,EACjB,IAA6B,EAC7B,IAAI,GAAuB,KAAK,EAChC,OAA+B;QAE/B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAA;QACvB,+EAA+E;QAC/E,mFAAmF;QACnF,mFAAmF;QACnF,oFAAoF;QACpF,kDAAkD;QAClD,EAAE;QACF,0EAA0E;QAC1E,6EAA6E;QAC7E,mFAAmF;QACnF,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAC5B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK;YACL,IAAI,EAAE;gBACJ,GAAG,IAAI;gBACP,IAAI;gBACJ,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5E,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClE;YACD,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,CAAC,GAAiB;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACxB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,CAAC,GAAiB;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAA;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RunnerJobState, RunnerPoolManifest, UrlSafetyPolicy } from '@cat-factory/kernel';
|
|
2
|
+
/** Collect every secret key a manifest's auth scheme references. */
|
|
3
|
+
export declare function referencedSecretKeys(manifest: RunnerPoolManifest): string[];
|
|
4
|
+
/** Validate every URL a manifest will fetch (defence against SSRF). */
|
|
5
|
+
export declare function assertManifestUrlsSafe(manifest: RunnerPoolManifest, policy?: UrlSafetyPolicy): void;
|
|
6
|
+
/**
|
|
7
|
+
* Map a scheduler's status string onto the harness job state using the manifest's
|
|
8
|
+
* `statusMap`. Falls back to interpreting the raw value as a state literal
|
|
9
|
+
* (`running`/`done`/`failed`) when it matches one, else `running` — so a poll
|
|
10
|
+
* that can't be classified keeps the driver waiting rather than wrongly failing.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mapJobState(raw: string | undefined, statusMap: {
|
|
13
|
+
from: string;
|
|
14
|
+
to: RunnerJobState;
|
|
15
|
+
}[] | undefined): RunnerJobState;
|
|
16
|
+
//# sourceMappingURL=runners.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runners.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/runners/runners.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAW9F,oEAAoE;AACpE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAe3E;AAED,uEAAuE;AACvE,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,GAAE,eAA0C,GACjD,IAAI,CAKN;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,SAAS,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,cAAc,CAAA;CAAE,EAAE,GAAG,SAAS,GAC5D,cAAc,CAUhB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { STRICT_URL_SAFETY_POLICY } from '@cat-factory/kernel';
|
|
2
|
+
import { assertSafeEnvironmentUrl } from '../environments/environments.logic.js';
|
|
3
|
+
// Pure helpers for the self-hosted runner-pool integration. The generic URL
|
|
4
|
+
// validation, `{{var}}` interpolation and dot-path extraction live in the
|
|
5
|
+
// environments logic module (they are not environment-specific); we reuse them
|
|
6
|
+
// from the manifest interpreter. What is runner-specific lives here: collecting a
|
|
7
|
+
// manifest's referenced secret keys, validating every URL it will fetch, and
|
|
8
|
+
// mapping a scheduler's status string onto the harness job state.
|
|
9
|
+
/** Collect every secret key a manifest's auth scheme references. */
|
|
10
|
+
export function referencedSecretKeys(manifest) {
|
|
11
|
+
const auth = manifest.auth;
|
|
12
|
+
switch (auth.type) {
|
|
13
|
+
case 'none':
|
|
14
|
+
return [];
|
|
15
|
+
case 'api_key':
|
|
16
|
+
case 'bearer':
|
|
17
|
+
return [auth.secretRef.key];
|
|
18
|
+
case 'basic':
|
|
19
|
+
return [auth.usernameSecretRef.key, auth.passwordSecretRef.key];
|
|
20
|
+
case 'oauth2_client_credentials':
|
|
21
|
+
return [auth.clientIdSecretRef.key, auth.clientSecretSecretRef.key];
|
|
22
|
+
case 'custom_headers':
|
|
23
|
+
return auth.headers.map((h) => h.secretRef.key);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Validate every URL a manifest will fetch (defence against SSRF). */
|
|
27
|
+
export function assertManifestUrlsSafe(manifest, policy = STRICT_URL_SAFETY_POLICY) {
|
|
28
|
+
assertSafeEnvironmentUrl(manifest.baseUrl, 'base URL', policy);
|
|
29
|
+
if (manifest.auth.type === 'oauth2_client_credentials') {
|
|
30
|
+
assertSafeEnvironmentUrl(manifest.auth.tokenUrl, 'OAuth token URL', policy);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Map a scheduler's status string onto the harness job state using the manifest's
|
|
35
|
+
* `statusMap`. Falls back to interpreting the raw value as a state literal
|
|
36
|
+
* (`running`/`done`/`failed`) when it matches one, else `running` — so a poll
|
|
37
|
+
* that can't be classified keeps the driver waiting rather than wrongly failing.
|
|
38
|
+
*/
|
|
39
|
+
export function mapJobState(raw, statusMap) {
|
|
40
|
+
if (raw !== undefined) {
|
|
41
|
+
if (statusMap) {
|
|
42
|
+
const hit = statusMap.find((m) => m.from.toLowerCase() === raw.toLowerCase());
|
|
43
|
+
if (hit)
|
|
44
|
+
return hit.to;
|
|
45
|
+
}
|
|
46
|
+
const lower = raw.toLowerCase();
|
|
47
|
+
if (lower === 'running' || lower === 'done' || lower === 'failed')
|
|
48
|
+
return lower;
|
|
49
|
+
}
|
|
50
|
+
return 'running';
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=runners.logic.js.map
|