adispatchd 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -2
- package/dist/api/errors.d.ts +27 -0
- package/dist/api/errors.js +80 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +11 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/logs.d.ts +30 -0
- package/dist/api/logs.js +88 -0
- package/dist/api/logs.js.map +1 -0
- package/dist/api/serialize.d.ts +65 -0
- package/dist/api/serialize.js +135 -0
- package/dist/api/serialize.js.map +1 -0
- package/dist/api/server.d.ts +89 -0
- package/dist/api/server.js +751 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/sse.d.ts +90 -0
- package/dist/api/sse.js +225 -0
- package/dist/api/sse.js.map +1 -0
- package/dist/app.d.ts +173 -0
- package/dist/app.js +488 -0
- package/dist/app.js.map +1 -0
- package/dist/cli/config-validate.d.ts +6 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/config-validate.js.map +1 -0
- package/dist/cli/control.d.ts +31 -0
- package/dist/cli/control.js +186 -0
- package/dist/cli/control.js.map +1 -0
- package/dist/cli/http-client.d.ts +57 -0
- package/dist/cli/http-client.js +174 -0
- package/dist/cli/http-client.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +20 -0
- package/dist/cli/init-templates.js +275 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +107 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +25 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +102 -0
- package/dist/cli/program.js +133 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/service.d.ts +27 -0
- package/dist/cli/service.js +252 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/start.d.ts +22 -0
- package/dist/cli/start.js +133 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/workflow-dry-run.d.ts +13 -0
- package/dist/cli/workflow-dry-run.js +144 -0
- package/dist/cli/workflow-dry-run.js.map +1 -0
- package/dist/config/field-catalog.d.ts +33 -0
- package/dist/config/field-catalog.js +172 -0
- package/dist/config/field-catalog.js.map +1 -0
- package/dist/config/filter-schema.d.ts +15 -0
- package/dist/config/filter-schema.js +110 -0
- package/dist/config/filter-schema.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.js +16 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/issues.d.ts +27 -0
- package/dist/config/issues.js +37 -0
- package/dist/config/issues.js.map +1 -0
- package/dist/config/loader.d.ts +32 -0
- package/dist/config/loader.js +250 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +153 -0
- package/dist/config/manager.js +276 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/model.d.ts +334 -0
- package/dist/config/model.js +2 -0
- package/dist/config/model.js.map +1 -0
- package/dist/config/normalize.d.ts +20 -0
- package/dist/config/normalize.js +200 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/config/parameters.d.ts +37 -0
- package/dist/config/parameters.js +71 -0
- package/dist/config/parameters.js.map +1 -0
- package/dist/config/public.d.ts +6 -0
- package/dist/config/public.js +18 -0
- package/dist/config/public.js.map +1 -0
- package/dist/config/schemas.d.ts +538 -0
- package/dist/config/schemas.js +321 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/snapshot.d.ts +38 -0
- package/dist/config/snapshot.js +57 -0
- package/dist/config/snapshot.js.map +1 -0
- package/dist/config/validate.d.ts +33 -0
- package/dist/config/validate.js +346 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/clock.d.ts +59 -0
- package/dist/core/clock.js +133 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/duration.d.ts +19 -0
- package/dist/core/duration.js +93 -0
- package/dist/core/duration.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.js +72 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/ids.d.ts +57 -0
- package/dist/core/ids.js +88 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +100 -0
- package/dist/core/logger.js +207 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/paths.d.ts +84 -0
- package/dist/core/paths.js +138 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/template.d.ts +136 -0
- package/dist/core/template.js +261 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/types.d.ts +544 -0
- package/dist/core/types.js +172 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/worker-protocol.d.ts +102 -0
- package/dist/core/worker-protocol.js +75 -0
- package/dist/core/worker-protocol.js.map +1 -0
- package/dist/executors/classify.d.ts +25 -0
- package/dist/executors/classify.js +54 -0
- package/dist/executors/classify.js.map +1 -0
- package/dist/executors/dispatcher.d.ts +35 -0
- package/dist/executors/dispatcher.js +68 -0
- package/dist/executors/dispatcher.js.map +1 -0
- package/dist/executors/env.d.ts +43 -0
- package/dist/executors/env.js +66 -0
- package/dist/executors/env.js.map +1 -0
- package/dist/executors/event-parser.d.ts +41 -0
- package/dist/executors/event-parser.js +106 -0
- package/dist/executors/event-parser.js.map +1 -0
- package/dist/executors/index.d.ts +12 -0
- package/dist/executors/index.js +13 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/log-capture.d.ts +57 -0
- package/dist/executors/log-capture.js +155 -0
- package/dist/executors/log-capture.js.map +1 -0
- package/dist/executors/process-identity.d.ts +124 -0
- package/dist/executors/process-identity.js +283 -0
- package/dist/executors/process-identity.js.map +1 -0
- package/dist/executors/shell-executor.d.ts +35 -0
- package/dist/executors/shell-executor.js +478 -0
- package/dist/executors/shell-executor.js.map +1 -0
- package/dist/executors/stream-redactor.d.ts +40 -0
- package/dist/executors/stream-redactor.js +89 -0
- package/dist/executors/stream-redactor.js.map +1 -0
- package/dist/executors/workspace.d.ts +10 -0
- package/dist/executors/workspace.js +47 -0
- package/dist/executors/workspace.js.map +1 -0
- package/dist/filters/evaluate.d.ts +77 -0
- package/dist/filters/evaluate.js +187 -0
- package/dist/filters/evaluate.js.map +1 -0
- package/dist/filters/fields.d.ts +35 -0
- package/dist/filters/fields.js +75 -0
- package/dist/filters/fields.js.map +1 -0
- package/dist/filters/index.d.ts +11 -0
- package/dist/filters/index.js +12 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/iso-date.d.ts +10 -0
- package/dist/filters/iso-date.js +42 -0
- package/dist/filters/iso-date.js.map +1 -0
- package/dist/filters/predicate.d.ts +24 -0
- package/dist/filters/predicate.js +178 -0
- package/dist/filters/predicate.js.map +1 -0
- package/dist/filters/priority.d.ts +51 -0
- package/dist/filters/priority.js +91 -0
- package/dist/filters/priority.js.map +1 -0
- package/dist/filters/pushdown.d.ts +12 -0
- package/dist/filters/pushdown.js +52 -0
- package/dist/filters/pushdown.js.map +1 -0
- package/dist/filters/shell-check.d.ts +110 -0
- package/dist/filters/shell-check.js +304 -0
- package/dist/filters/shell-check.js.map +1 -0
- package/dist/identities/github-app.d.ts +55 -0
- package/dist/identities/github-app.js +160 -0
- package/dist/identities/github-app.js.map +1 -0
- package/dist/identities/index.d.ts +6 -0
- package/dist/identities/index.js +7 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/identities/jwt.d.ts +24 -0
- package/dist/identities/jwt.js +56 -0
- package/dist/identities/jwt.js.map +1 -0
- package/dist/lifecycle/context.d.ts +106 -0
- package/dist/lifecycle/context.js +170 -0
- package/dist/lifecycle/context.js.map +1 -0
- package/dist/lifecycle/engine.d.ts +185 -0
- package/dist/lifecycle/engine.js +551 -0
- package/dist/lifecycle/engine.js.map +1 -0
- package/dist/lifecycle/errors.d.ts +48 -0
- package/dist/lifecycle/errors.js +71 -0
- package/dist/lifecycle/errors.js.map +1 -0
- package/dist/lifecycle/index.d.ts +9 -0
- package/dist/lifecycle/index.js +9 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/performers.d.ts +66 -0
- package/dist/lifecycle/performers.js +179 -0
- package/dist/lifecycle/performers.js.map +1 -0
- package/dist/notifications/index.d.ts +6 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/service.d.ts +115 -0
- package/dist/notifications/service.js +364 -0
- package/dist/notifications/service.js.map +1 -0
- package/dist/persistence/actions.d.ts +101 -0
- package/dist/persistence/actions.js +196 -0
- package/dist/persistence/actions.js.map +1 -0
- package/dist/persistence/blocks.d.ts +85 -0
- package/dist/persistence/blocks.js +140 -0
- package/dist/persistence/blocks.js.map +1 -0
- package/dist/persistence/cron-firings.d.ts +55 -0
- package/dist/persistence/cron-firings.js +70 -0
- package/dist/persistence/cron-firings.js.map +1 -0
- package/dist/persistence/database.d.ts +60 -0
- package/dist/persistence/database.js +124 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/persistence/errors.d.ts +39 -0
- package/dist/persistence/errors.js +67 -0
- package/dist/persistence/errors.js.map +1 -0
- package/dist/persistence/events.d.ts +72 -0
- package/dist/persistence/events.js +83 -0
- package/dist/persistence/events.js.map +1 -0
- package/dist/persistence/index.d.ts +18 -0
- package/dist/persistence/index.js +19 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/instance-lock.d.ts +26 -0
- package/dist/persistence/instance-lock.js +117 -0
- package/dist/persistence/instance-lock.js.map +1 -0
- package/dist/persistence/lock-keys.d.ts +16 -0
- package/dist/persistence/lock-keys.js +41 -0
- package/dist/persistence/lock-keys.js.map +1 -0
- package/dist/persistence/notifications.d.ts +113 -0
- package/dist/persistence/notifications.js +213 -0
- package/dist/persistence/notifications.js.map +1 -0
- package/dist/persistence/persistence.d.ts +46 -0
- package/dist/persistence/persistence.js +42 -0
- package/dist/persistence/persistence.js.map +1 -0
- package/dist/persistence/retention.d.ts +46 -0
- package/dist/persistence/retention.js +68 -0
- package/dist/persistence/retention.js.map +1 -0
- package/dist/persistence/runs.d.ts +215 -0
- package/dist/persistence/runs.js +417 -0
- package/dist/persistence/runs.js.map +1 -0
- package/dist/persistence/schema.d.ts +16 -0
- package/dist/persistence/schema.js +183 -0
- package/dist/persistence/schema.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +49 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/runs/controller.d.ts +307 -0
- package/dist/runs/controller.js +1078 -0
- package/dist/runs/controller.js.map +1 -0
- package/dist/runs/errors.d.ts +20 -0
- package/dist/runs/errors.js +26 -0
- package/dist/runs/errors.js.map +1 -0
- package/dist/runs/event-bus.d.ts +106 -0
- package/dist/runs/event-bus.js +105 -0
- package/dist/runs/event-bus.js.map +1 -0
- package/dist/runs/execution.d.ts +39 -0
- package/dist/runs/execution.js +146 -0
- package/dist/runs/execution.js.map +1 -0
- package/dist/runs/index.d.ts +12 -0
- package/dist/runs/index.js +13 -0
- package/dist/runs/index.js.map +1 -0
- package/dist/runs/retention.d.ts +64 -0
- package/dist/runs/retention.js +232 -0
- package/dist/runs/retention.js.map +1 -0
- package/dist/runs/workspace.d.ts +20 -0
- package/dist/runs/workspace.js +51 -0
- package/dist/runs/workspace.js.map +1 -0
- package/dist/scheduler/checks.d.ts +41 -0
- package/dist/scheduler/checks.js +111 -0
- package/dist/scheduler/checks.js.map +1 -0
- package/dist/scheduler/cron.d.ts +32 -0
- package/dist/scheduler/cron.js +83 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/dry-run.d.ts +42 -0
- package/dist/scheduler/dry-run.js +167 -0
- package/dist/scheduler/dry-run.js.map +1 -0
- package/dist/scheduler/errors.d.ts +22 -0
- package/dist/scheduler/errors.js +22 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/format.d.ts +3 -0
- package/dist/scheduler/format.js +73 -0
- package/dist/scheduler/format.js.map +1 -0
- package/dist/scheduler/index.d.ts +13 -0
- package/dist/scheduler/index.js +14 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/planner.d.ts +88 -0
- package/dist/scheduler/planner.js +255 -0
- package/dist/scheduler/planner.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +160 -0
- package/dist/scheduler/scheduler.js +680 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/state.d.ts +26 -0
- package/dist/scheduler/state.js +25 -0
- package/dist/scheduler/state.js.map +1 -0
- package/dist/scheduler/types.d.ts +197 -0
- package/dist/scheduler/types.js +3 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service/index.d.ts +6 -0
- package/dist/service/index.js +7 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install.d.ts +93 -0
- package/dist/service/install.js +250 -0
- package/dist/service/install.js.map +1 -0
- package/dist/service/unit.d.ts +50 -0
- package/dist/service/unit.js +171 -0
- package/dist/service/unit.js.map +1 -0
- package/dist/sources/github/adapter.d.ts +99 -0
- package/dist/sources/github/adapter.js +336 -0
- package/dist/sources/github/adapter.js.map +1 -0
- package/dist/sources/github/fields.d.ts +8 -0
- package/dist/sources/github/fields.js +72 -0
- package/dist/sources/github/fields.js.map +1 -0
- package/dist/sources/github/http.d.ts +100 -0
- package/dist/sources/github/http.js +288 -0
- package/dist/sources/github/http.js.map +1 -0
- package/dist/sources/github/index.d.ts +6 -0
- package/dist/sources/github/index.js +7 -0
- package/dist/sources/github/index.js.map +1 -0
- package/dist/sources/github/pushdown.d.ts +14 -0
- package/dist/sources/github/pushdown.js +47 -0
- package/dist/sources/github/pushdown.js.map +1 -0
- package/dist/sources/github/refs.d.ts +17 -0
- package/dist/sources/github/refs.js +61 -0
- package/dist/sources/github/refs.js.map +1 -0
- package/dist/sources/index.d.ts +6 -0
- package/dist/sources/index.js +7 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +28 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/public/app.css +239 -0
- package/dist/ui/public/favicon.svg +1 -0
- package/dist/ui/public/index.html +27 -0
- package/dist/ui/public/js/client/api.js +68 -0
- package/dist/ui/public/js/client/app.js +146 -0
- package/dist/ui/public/js/client/dom.js +34 -0
- package/dist/ui/public/js/client/page.js +9 -0
- package/dist/ui/public/js/client/pages/actions.js +35 -0
- package/dist/ui/public/js/client/pages/blocked.js +58 -0
- package/dist/ui/public/js/client/pages/config.js +126 -0
- package/dist/ui/public/js/client/pages/dashboard.js +175 -0
- package/dist/ui/public/js/client/pages/run.js +367 -0
- package/dist/ui/public/js/client/pages/runs.js +72 -0
- package/dist/ui/public/js/client/pages/views.js +80 -0
- package/dist/ui/public/js/client/pages/workflows.js +291 -0
- package/dist/ui/public/js/client/types.js +1 -0
- package/dist/ui/public/js/client/ui.js +152 -0
- package/dist/ui/public/js/shared/dom.js +77 -0
- package/dist/ui/public/js/shared/events.js +88 -0
- package/dist/ui/public/js/shared/format.js +213 -0
- package/dist/ui/public/js/shared/logs.js +136 -0
- package/dist/ui/public/js/shared/params.js +90 -0
- package/dist/ui/public/js/shared/route.js +36 -0
- package/dist/ui/public/js/shared/sort.js +70 -0
- package/dist/ui/public/js/shared/sse.js +193 -0
- package/dist/ui/public/js/shared/throttle.js +65 -0
- package/dist/views/index.d.ts +6 -0
- package/dist/views/index.js +7 -0
- package/dist/views/index.js.map +1 -0
- package/dist/views/service.d.ts +131 -0
- package/dist/views/service.js +264 -0
- package/dist/views/service.js.map +1 -0
- package/docs/api.md +239 -0
- package/docs/configuration-reference.md +1785 -0
- package/docs/cron-semantics.md +96 -0
- package/docs/manual-tests/github-fixture/config.yaml +30 -0
- package/docs/manual-tests/github-fixture/helpers.sh +93 -0
- package/docs/manual-tests/github-fixture/identities.yaml +18 -0
- package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
- package/docs/manual-tests/github-fixture/sources.yaml +13 -0
- package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
- package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
- package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
- package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
- package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
- package/docs/manual-tests/github.md +1308 -0
- package/docs/manual-tests/process-supervision.md +64 -0
- package/docs/manual-tests/systemd.md +68 -0
- package/docs/operations.md +271 -0
- package/docs/worker-protocol.md +145 -0
- package/examples/config/config.yaml +35 -0
- package/examples/config/identities.yaml +18 -0
- package/examples/config/sources.yaml +13 -0
- package/examples/config/views/needs-maintainer.yaml +15 -0
- package/examples/config/workflows/coder-project-a.yaml +86 -0
- package/examples/config/workflows/deploy.yaml +15 -0
- package/examples/config/workflows/nightly-maintenance.yaml +13 -0
- package/package.json +75 -4
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker environment (Spec §9.1, §20.3): workers never inherit the controller
|
|
3
|
+
* environment. They get a minimal set of standard variables, the explicitly
|
|
4
|
+
* declared `env`, resolved secrets and the `ADISPATCH_*` protocol variables.
|
|
5
|
+
*/
|
|
6
|
+
import { ADISPATCH_ENV } from '../core/index.js';
|
|
7
|
+
/** Variables copied from the controller environment (if set). */
|
|
8
|
+
export const MINIMAL_ENV_KEYS = ['PATH', 'HOME', 'LANG', 'TZ', 'USER', 'LOGNAME', 'TMPDIR'];
|
|
9
|
+
/** PATH used when the controller has none. */
|
|
10
|
+
export const FALLBACK_PATH = '/usr/local/bin:/usr/bin:/bin';
|
|
11
|
+
/** Pick the minimal standard variables from `base` (default `process.env`). */
|
|
12
|
+
export function buildMinimalEnv(base = process.env) {
|
|
13
|
+
const env = {};
|
|
14
|
+
for (const key of MINIMAL_ENV_KEYS) {
|
|
15
|
+
const value = base[key];
|
|
16
|
+
if (typeof value === 'string')
|
|
17
|
+
env[key] = value;
|
|
18
|
+
}
|
|
19
|
+
env.PATH ??= FALLBACK_PATH;
|
|
20
|
+
return env;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract a `source` block from any context object (main-worker context or a
|
|
24
|
+
* custom shell-action context). Returns `undefined` unless all fields are strings.
|
|
25
|
+
*/
|
|
26
|
+
export function contextSource(context) {
|
|
27
|
+
const source = context.source;
|
|
28
|
+
if (typeof source !== 'object' || source === null)
|
|
29
|
+
return undefined;
|
|
30
|
+
const { id, type, item_id, url } = source;
|
|
31
|
+
if (typeof id !== 'string' || typeof type !== 'string' || typeof item_id !== 'string' || typeof url !== 'string') {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
return { id, type, item_id, url };
|
|
35
|
+
}
|
|
36
|
+
/** `ADISPATCH_*` variables for a worker (Spec §9.1). */
|
|
37
|
+
export function buildOrchEnv(input) {
|
|
38
|
+
const env = {
|
|
39
|
+
[ADISPATCH_ENV.RUN_ID]: input.runId,
|
|
40
|
+
[ADISPATCH_ENV.WORKFLOW_ID]: input.workflowId,
|
|
41
|
+
[ADISPATCH_ENV.CONTEXT_FILE]: input.contextFile,
|
|
42
|
+
[ADISPATCH_ENV.RESULT_FILE]: input.resultFile,
|
|
43
|
+
[ADISPATCH_ENV.WORKSPACE]: input.workspace,
|
|
44
|
+
};
|
|
45
|
+
const source = contextSource(input.context);
|
|
46
|
+
if (source) {
|
|
47
|
+
env[ADISPATCH_ENV.SOURCE_TYPE] = source.type;
|
|
48
|
+
env[ADISPATCH_ENV.SOURCE_ID] = source.id;
|
|
49
|
+
env[ADISPATCH_ENV.SOURCE_ITEM_ID] = source.item_id;
|
|
50
|
+
env[ADISPATCH_ENV.SOURCE_URL] = source.url;
|
|
51
|
+
}
|
|
52
|
+
return env;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compose the full worker environment. Precedence (later wins): minimal env
|
|
56
|
+
* < declared `env` < `secrets` < `ADISPATCH_*` (protocol variables cannot be overridden).
|
|
57
|
+
*/
|
|
58
|
+
export function buildWorkerEnv(parts) {
|
|
59
|
+
return {
|
|
60
|
+
...buildMinimalEnv(parts.base),
|
|
61
|
+
...parts.env,
|
|
62
|
+
...parts.secrets,
|
|
63
|
+
...parts.orch,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/executors/env.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAAsB,MAAM,kBAAkB,CAAC;AAErE,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAU,CAAC;AAErG,8CAA8C;AAC9C,MAAM,CAAC,MAAM,aAAa,GAAG,8BAA8B,CAAC;AAE5D,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,IAAI,GAAsB,OAAO,CAAC,GAAG;IACnE,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAClD,CAAC;IACD,GAAG,CAAC,IAAI,KAAK,aAAa,CAAC;IAC3B,OAAO,GAAG,CAAC;AACb,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAA0D;IACtF,MAAM,MAAM,GAAI,OAAgC,CAAC,MAAM,CAAC;IACxD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,MAAiC,CAAC;IACrE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACjH,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AACpC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,KAO5B;IACC,MAAM,GAAG,GAA2B;QAClC,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK;QACnC,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,UAAU;QAC7C,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,WAAW;QAC/C,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,UAAU;QAC7C,CAAC,aAAa,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS;KAC3C,CAAC;IACF,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,MAAM,EAAE,CAAC;QACX,GAAG,CAAC,aAAa,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;QAC7C,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;QACzC,GAAG,CAAC,aAAa,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC;QACnD,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC;IAC7C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAK9B;IACC,OAAO;QACL,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC;QAC9B,GAAG,KAAK,CAAC,GAAG;QACZ,GAAG,KAAK,CAAC,OAAO;QAChB,GAAG,KAAK,CAAC,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Result of parsing one complete line. */
|
|
2
|
+
export type EventLineResult = {
|
|
3
|
+
kind: 'none';
|
|
4
|
+
} | {
|
|
5
|
+
kind: 'event';
|
|
6
|
+
type: string;
|
|
7
|
+
data: Record<string, unknown>;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'invalid';
|
|
10
|
+
error: string;
|
|
11
|
+
};
|
|
12
|
+
/** Parse one complete line (without the line terminator). */
|
|
13
|
+
export declare function parseEventLine(line: string): EventLineResult;
|
|
14
|
+
/** Callbacks of an {@link EventLineParser}. */
|
|
15
|
+
export interface EventLineHandlers {
|
|
16
|
+
onEvent(type: string, data: Record<string, unknown>): void;
|
|
17
|
+
onInvalid(error: string, preview: string): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Incremental line splitter + event parser for one stream. Accepts decoded
|
|
21
|
+
* text in arbitrary chunks (lines may span chunks). Memory is bounded: a
|
|
22
|
+
* non-event line is not buffered beyond the prefix length, an event line is
|
|
23
|
+
* buffered up to the payload limit; longer event lines are discarded up to
|
|
24
|
+
* their newline and reported as invalid.
|
|
25
|
+
*/
|
|
26
|
+
export declare class EventLineParser {
|
|
27
|
+
private readonly handlers;
|
|
28
|
+
private buffer;
|
|
29
|
+
/** The current line is known not to be an event; skip until newline. */
|
|
30
|
+
private skipping;
|
|
31
|
+
/** The current event line exceeded the limit; skip until newline, then warn. */
|
|
32
|
+
private overflow;
|
|
33
|
+
private readonly maxLineChars;
|
|
34
|
+
constructor(handlers: EventLineHandlers);
|
|
35
|
+
/** Feed decoded text. */
|
|
36
|
+
push(text: string): void;
|
|
37
|
+
/** Process a final unterminated line (call at end of stream). */
|
|
38
|
+
flush(): void;
|
|
39
|
+
private append;
|
|
40
|
+
private completeLine;
|
|
41
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line buffering and parsing of structured worker events (Spec §9.3).
|
|
3
|
+
*
|
|
4
|
+
* Lines starting with `@@ADISPATCH_EVENT ` carry a JSON object `{type: string, ...}`.
|
|
5
|
+
* Valid events are reported via callback; invalid event lines produce a
|
|
6
|
+
* parser warning. The raw line always stays in the log (this parser only
|
|
7
|
+
* observes the stream).
|
|
8
|
+
*/
|
|
9
|
+
import { MAX_EVENT_LINE_BYTES, ADISPATCH_EVENT_PREFIX, workerEventPayloadSchema } from '../core/index.js';
|
|
10
|
+
/** Maximum length of the line preview included in parser warnings. */
|
|
11
|
+
const PREVIEW_CHARS = 200;
|
|
12
|
+
/** Parse one complete line (without the line terminator). */
|
|
13
|
+
export function parseEventLine(line) {
|
|
14
|
+
if (!line.startsWith(ADISPATCH_EVENT_PREFIX))
|
|
15
|
+
return { kind: 'none' };
|
|
16
|
+
const payload = line.slice(ADISPATCH_EVENT_PREFIX.length);
|
|
17
|
+
if (Buffer.byteLength(payload, 'utf8') > MAX_EVENT_LINE_BYTES) {
|
|
18
|
+
return { kind: 'invalid', error: `event payload exceeds ${MAX_EVENT_LINE_BYTES} bytes` };
|
|
19
|
+
}
|
|
20
|
+
let json;
|
|
21
|
+
try {
|
|
22
|
+
json = JSON.parse(payload);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
return { kind: 'invalid', error: `event is not valid JSON: ${err.message}` };
|
|
26
|
+
}
|
|
27
|
+
const parsed = workerEventPayloadSchema.safeParse(json);
|
|
28
|
+
if (!parsed.success) {
|
|
29
|
+
const issues = parsed.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`).join('; ');
|
|
30
|
+
return { kind: 'invalid', error: `event does not match schema: ${issues}` };
|
|
31
|
+
}
|
|
32
|
+
return { kind: 'event', type: parsed.data.type, data: parsed.data };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Incremental line splitter + event parser for one stream. Accepts decoded
|
|
36
|
+
* text in arbitrary chunks (lines may span chunks). Memory is bounded: a
|
|
37
|
+
* non-event line is not buffered beyond the prefix length, an event line is
|
|
38
|
+
* buffered up to the payload limit; longer event lines are discarded up to
|
|
39
|
+
* their newline and reported as invalid.
|
|
40
|
+
*/
|
|
41
|
+
export class EventLineParser {
|
|
42
|
+
handlers;
|
|
43
|
+
buffer = '';
|
|
44
|
+
/** The current line is known not to be an event; skip until newline. */
|
|
45
|
+
skipping = false;
|
|
46
|
+
/** The current event line exceeded the limit; skip until newline, then warn. */
|
|
47
|
+
overflow = false;
|
|
48
|
+
maxLineChars = ADISPATCH_EVENT_PREFIX.length + MAX_EVENT_LINE_BYTES;
|
|
49
|
+
constructor(handlers) {
|
|
50
|
+
this.handlers = handlers;
|
|
51
|
+
}
|
|
52
|
+
/** Feed decoded text. */
|
|
53
|
+
push(text) {
|
|
54
|
+
let start = 0;
|
|
55
|
+
while (start < text.length) {
|
|
56
|
+
const nl = text.indexOf('\n', start);
|
|
57
|
+
const end = nl === -1 ? text.length : nl;
|
|
58
|
+
this.append(text.slice(start, end));
|
|
59
|
+
if (nl === -1)
|
|
60
|
+
break;
|
|
61
|
+
this.completeLine();
|
|
62
|
+
start = nl + 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Process a final unterminated line (call at end of stream). */
|
|
66
|
+
flush() {
|
|
67
|
+
if (this.buffer !== '' || this.overflow)
|
|
68
|
+
this.completeLine();
|
|
69
|
+
this.buffer = '';
|
|
70
|
+
this.skipping = false;
|
|
71
|
+
this.overflow = false;
|
|
72
|
+
}
|
|
73
|
+
append(part) {
|
|
74
|
+
if (this.skipping || this.overflow || part === '')
|
|
75
|
+
return;
|
|
76
|
+
this.buffer += part;
|
|
77
|
+
const prefixPart = this.buffer.slice(0, ADISPATCH_EVENT_PREFIX.length);
|
|
78
|
+
if (!ADISPATCH_EVENT_PREFIX.startsWith(prefixPart)) {
|
|
79
|
+
this.skipping = true;
|
|
80
|
+
this.buffer = '';
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
// UTF-16 length is a lower bound of the UTF-8 byte length.
|
|
84
|
+
if (this.buffer.length > this.maxLineChars) {
|
|
85
|
+
this.overflow = true;
|
|
86
|
+
this.buffer = this.buffer.slice(0, PREVIEW_CHARS);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
completeLine() {
|
|
90
|
+
if (this.overflow) {
|
|
91
|
+
this.handlers.onInvalid(`event payload exceeds ${MAX_EVENT_LINE_BYTES} bytes`, this.buffer.slice(0, PREVIEW_CHARS));
|
|
92
|
+
}
|
|
93
|
+
else if (!this.skipping && this.buffer !== '') {
|
|
94
|
+
const line = this.buffer.endsWith('\r') ? this.buffer.slice(0, -1) : this.buffer;
|
|
95
|
+
const result = parseEventLine(line);
|
|
96
|
+
if (result.kind === 'event')
|
|
97
|
+
this.handlers.onEvent(result.type, result.data);
|
|
98
|
+
else if (result.kind === 'invalid')
|
|
99
|
+
this.handlers.onInvalid(result.error, line.slice(0, PREVIEW_CHARS));
|
|
100
|
+
}
|
|
101
|
+
this.buffer = '';
|
|
102
|
+
this.skipping = false;
|
|
103
|
+
this.overflow = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=event-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-parser.js","sourceRoot":"","sources":["../../src/executors/event-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component `executors` – public API (WI-05): shell executor, worker
|
|
3
|
+
* protocol helpers, result classification and process start identity.
|
|
4
|
+
* Other components import from this module only.
|
|
5
|
+
*/
|
|
6
|
+
export { ShellExecutor, type ShellExecutorOptions } from './shell-executor.js';
|
|
7
|
+
export { classifyOutcome } from './classify.js';
|
|
8
|
+
export { checkProcessIdentity, createDarwinInspector, createLinuxInspector, defaultProcessInspector, getStartIdentity, isSameProcess, killProcessGroupIfSame, parseProcStat, parsePsOutput, processGroupAlive, processGroupExists, terminateProcessGroupIfSame, type TerminateOptions, type TerminateResult, type CommandRunner, type IdentityCheck, type KillFn, type KillIfSameResult, type ProcessInspector, type ProcessProbe, } from './process-identity.js';
|
|
9
|
+
export { buildMinimalEnv, buildOrchEnv, contextSource, type OrchSourceInfo, buildWorkerEnv, FALLBACK_PATH, MINIMAL_ENV_KEYS } from './env.js';
|
|
10
|
+
export { EventLineParser, parseEventLine, type EventLineHandlers, type EventLineResult } from './event-parser.js';
|
|
11
|
+
export { ensureWorkspaceWithin } from './workspace.js';
|
|
12
|
+
export { MIN_STREAM_SECRET_LENGTH, REDACTION_MARKER, StreamRedactor } from './stream-redactor.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component `executors` – public API (WI-05): shell executor, worker
|
|
3
|
+
* protocol helpers, result classification and process start identity.
|
|
4
|
+
* Other components import from this module only.
|
|
5
|
+
*/
|
|
6
|
+
export { ShellExecutor } from './shell-executor.js';
|
|
7
|
+
export { classifyOutcome } from './classify.js';
|
|
8
|
+
export { checkProcessIdentity, createDarwinInspector, createLinuxInspector, defaultProcessInspector, getStartIdentity, isSameProcess, killProcessGroupIfSame, parseProcStat, parsePsOutput, processGroupAlive, processGroupExists, terminateProcessGroupIfSame, } from './process-identity.js';
|
|
9
|
+
export { buildMinimalEnv, buildOrchEnv, contextSource, buildWorkerEnv, FALLBACK_PATH, MINIMAL_ENV_KEYS } from './env.js';
|
|
10
|
+
export { EventLineParser, parseEventLine } from './event-parser.js';
|
|
11
|
+
export { ensureWorkspaceWithin } from './workspace.js';
|
|
12
|
+
export { MIN_STREAM_SECRET_LENGTH, REDACTION_MARKER, StreamRedactor } from './stream-redactor.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executors/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,aAAa,EACb,sBAAsB,EACtB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,kBAAkB,EAClB,2BAA2B,GAS5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAuB,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC9I,OAAO,EAAE,eAAe,EAAE,cAAc,EAAgD,MAAM,mBAAmB,CAAC;AAClH,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Clock, ExecutorDiagnostic, OutputChunk } from '../core/index.js';
|
|
2
|
+
import type { StreamRedactor } from './stream-redactor.js';
|
|
3
|
+
/** Byte budget shared by all log streams of one run. */
|
|
4
|
+
export declare class LogBudget {
|
|
5
|
+
readonly limit: number | undefined;
|
|
6
|
+
private used;
|
|
7
|
+
constructor(limit: number | undefined);
|
|
8
|
+
/** Reserve up to `bytes`; returns how many bytes may be written. */
|
|
9
|
+
take(bytes: number): number;
|
|
10
|
+
}
|
|
11
|
+
/** Sinks for everything a capture produces. */
|
|
12
|
+
export interface CaptureSinks {
|
|
13
|
+
output(chunk: OutputChunk): void;
|
|
14
|
+
event(type: string, data: Record<string, unknown>, stream: 'stdout' | 'stderr'): void;
|
|
15
|
+
diagnostic(diagnostic: ExecutorDiagnostic): void;
|
|
16
|
+
}
|
|
17
|
+
export interface StreamCaptureOptions {
|
|
18
|
+
stream: 'stdout' | 'stderr';
|
|
19
|
+
/** Log file path; `undefined` disables file output (e.g. directory could not be created). */
|
|
20
|
+
filePath: string | undefined;
|
|
21
|
+
/** Error that prevented opening the file, reported as `log_write_error`. */
|
|
22
|
+
openError?: Error;
|
|
23
|
+
/** Shared per-run budget (default: unlimited). */
|
|
24
|
+
budget?: LogBudget;
|
|
25
|
+
redactor: StreamRedactor;
|
|
26
|
+
clock: Clock;
|
|
27
|
+
sinks: CaptureSinks;
|
|
28
|
+
}
|
|
29
|
+
export declare class StreamCapture {
|
|
30
|
+
private readonly opts;
|
|
31
|
+
private readonly stream;
|
|
32
|
+
private readonly decoder;
|
|
33
|
+
private readonly parser;
|
|
34
|
+
private readonly file;
|
|
35
|
+
private accepted;
|
|
36
|
+
private limitReached;
|
|
37
|
+
private writeFailed;
|
|
38
|
+
private drainWaiter;
|
|
39
|
+
private closed;
|
|
40
|
+
constructor(opts: StreamCaptureOptions);
|
|
41
|
+
/** Bytes handed to the log file (after redaction, within the limit). */
|
|
42
|
+
get bytesWritten(): number;
|
|
43
|
+
/** True if the persisted log is incomplete (size limit or write error). */
|
|
44
|
+
get truncated(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Feed raw bytes. Returns `false` if the source should pause until
|
|
47
|
+
* `onDrain` is called (file buffer full).
|
|
48
|
+
*/
|
|
49
|
+
push(raw: Buffer, onDrain: () => void): boolean;
|
|
50
|
+
/** Flush buffered data, close the file and wait until it is closed. */
|
|
51
|
+
end(): Promise<void>;
|
|
52
|
+
private handle;
|
|
53
|
+
private deliverText;
|
|
54
|
+
private writeFile;
|
|
55
|
+
private releaseDrain;
|
|
56
|
+
private fail;
|
|
57
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture of one output stream (stdout or stderr) of a worker (Spec §9.3, §5.1, §12):
|
|
3
|
+
* raw bytes → secret redaction → log file (size limit) + live output
|
|
4
|
+
* listeners + event line parser.
|
|
5
|
+
*
|
|
6
|
+
* - The log file receives the bytes unchanged except for redacted secrets.
|
|
7
|
+
* - The size limit is a per-run budget shared by stdout and stderr
|
|
8
|
+
* ({@link LogBudget}, Spec §5.1 `max_log_size_per_run`). When a stream hits
|
|
9
|
+
* it, that stream's file is not written any further and a single
|
|
10
|
+
* `log_truncated` diagnostic naming the stream is emitted (no silent overwrite).
|
|
11
|
+
* - Write errors produce a `log_write_error` diagnostic; the log is then
|
|
12
|
+
* reported as incomplete (`truncated`), never as complete.
|
|
13
|
+
* - Backpressure only comes from the file: {@link StreamCapture.push}
|
|
14
|
+
* returns `false` when the file stream's buffer is full, and the caller
|
|
15
|
+
* pauses the source until `onDrain`. Listeners never block (see Dispatcher).
|
|
16
|
+
*/
|
|
17
|
+
import { createWriteStream } from 'node:fs';
|
|
18
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
19
|
+
import { EventLineParser } from './event-parser.js';
|
|
20
|
+
/** Byte budget shared by all log streams of one run. */
|
|
21
|
+
export class LogBudget {
|
|
22
|
+
limit;
|
|
23
|
+
used = 0;
|
|
24
|
+
constructor(limit) {
|
|
25
|
+
this.limit = limit;
|
|
26
|
+
}
|
|
27
|
+
/** Reserve up to `bytes`; returns how many bytes may be written. */
|
|
28
|
+
take(bytes) {
|
|
29
|
+
if (this.limit === undefined)
|
|
30
|
+
return bytes;
|
|
31
|
+
const granted = Math.max(0, Math.min(bytes, this.limit - this.used));
|
|
32
|
+
this.used += granted;
|
|
33
|
+
return granted;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class StreamCapture {
|
|
37
|
+
opts;
|
|
38
|
+
stream;
|
|
39
|
+
decoder = new StringDecoder('utf8');
|
|
40
|
+
parser;
|
|
41
|
+
file;
|
|
42
|
+
accepted = 0;
|
|
43
|
+
limitReached = false;
|
|
44
|
+
writeFailed = false;
|
|
45
|
+
drainWaiter;
|
|
46
|
+
closed;
|
|
47
|
+
constructor(opts) {
|
|
48
|
+
this.opts = opts;
|
|
49
|
+
this.stream = opts.stream;
|
|
50
|
+
this.parser = new EventLineParser({
|
|
51
|
+
onEvent: (type, data) => opts.sinks.event(type, data, this.stream),
|
|
52
|
+
onInvalid: (error, preview) => opts.sinks.diagnostic({
|
|
53
|
+
type: 'event_parse_warning',
|
|
54
|
+
at: opts.clock.now(),
|
|
55
|
+
stream: this.stream,
|
|
56
|
+
message: `invalid worker event line: ${error}`,
|
|
57
|
+
details: { line: preview },
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
if (opts.openError || opts.filePath === undefined) {
|
|
61
|
+
this.fail(opts.openError ?? new Error('log file unavailable'));
|
|
62
|
+
this.closed = Promise.resolve();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const file = createWriteStream(opts.filePath, { flags: 'w', mode: 0o600 });
|
|
66
|
+
this.file = file;
|
|
67
|
+
this.closed = new Promise((resolve) => file.once('close', () => resolve()));
|
|
68
|
+
file.on('error', (err) => this.fail(err));
|
|
69
|
+
}
|
|
70
|
+
/** Bytes handed to the log file (after redaction, within the limit). */
|
|
71
|
+
get bytesWritten() {
|
|
72
|
+
return this.file ? Math.min(this.file.bytesWritten, this.accepted) : 0;
|
|
73
|
+
}
|
|
74
|
+
/** True if the persisted log is incomplete (size limit or write error). */
|
|
75
|
+
get truncated() {
|
|
76
|
+
return this.limitReached || this.writeFailed;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Feed raw bytes. Returns `false` if the source should pause until
|
|
80
|
+
* `onDrain` is called (file buffer full).
|
|
81
|
+
*/
|
|
82
|
+
push(raw, onDrain) {
|
|
83
|
+
return this.handle(this.opts.redactor.push(raw), onDrain);
|
|
84
|
+
}
|
|
85
|
+
/** Flush buffered data, close the file and wait until it is closed. */
|
|
86
|
+
async end() {
|
|
87
|
+
this.handle(this.opts.redactor.flush(), () => { });
|
|
88
|
+
const tail = this.decoder.end();
|
|
89
|
+
if (tail)
|
|
90
|
+
this.deliverText(tail);
|
|
91
|
+
this.parser.flush();
|
|
92
|
+
if (this.file && !this.file.closed && !this.file.destroyed)
|
|
93
|
+
this.file.end();
|
|
94
|
+
await this.closed;
|
|
95
|
+
}
|
|
96
|
+
handle(data, onDrain) {
|
|
97
|
+
if (data.length === 0)
|
|
98
|
+
return true;
|
|
99
|
+
const text = this.decoder.write(data);
|
|
100
|
+
if (text)
|
|
101
|
+
this.deliverText(text);
|
|
102
|
+
return this.writeFile(data, onDrain);
|
|
103
|
+
}
|
|
104
|
+
deliverText(text) {
|
|
105
|
+
this.opts.sinks.output({ stream: this.stream, data: text, at: this.opts.clock.now() });
|
|
106
|
+
this.parser.push(text);
|
|
107
|
+
}
|
|
108
|
+
writeFile(data, onDrain) {
|
|
109
|
+
if (!this.file || this.writeFailed || this.limitReached)
|
|
110
|
+
return true;
|
|
111
|
+
let chunk = data;
|
|
112
|
+
const budget = this.opts.budget;
|
|
113
|
+
const granted = budget ? budget.take(chunk.length) : chunk.length;
|
|
114
|
+
if (granted < chunk.length) {
|
|
115
|
+
chunk = chunk.subarray(0, granted);
|
|
116
|
+
this.limitReached = true;
|
|
117
|
+
this.opts.sinks.diagnostic({
|
|
118
|
+
type: 'log_truncated',
|
|
119
|
+
at: this.opts.clock.now(),
|
|
120
|
+
stream: this.stream,
|
|
121
|
+
message: `run log limit of ${budget?.limit} bytes reached while writing ${this.stream}; further ${this.stream} output is not persisted`,
|
|
122
|
+
details: { limitBytes: budget?.limit, stream: this.stream },
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (chunk.length === 0)
|
|
126
|
+
return true;
|
|
127
|
+
this.accepted += chunk.length;
|
|
128
|
+
const ok = this.file.write(chunk);
|
|
129
|
+
if (ok)
|
|
130
|
+
return true;
|
|
131
|
+
this.drainWaiter = onDrain;
|
|
132
|
+
this.file.once('drain', () => this.releaseDrain());
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
releaseDrain() {
|
|
136
|
+
const waiter = this.drainWaiter;
|
|
137
|
+
this.drainWaiter = undefined;
|
|
138
|
+
waiter?.();
|
|
139
|
+
}
|
|
140
|
+
fail(err) {
|
|
141
|
+
if (this.writeFailed)
|
|
142
|
+
return;
|
|
143
|
+
this.writeFailed = true;
|
|
144
|
+
this.opts.sinks.diagnostic({
|
|
145
|
+
type: 'log_write_error',
|
|
146
|
+
at: this.opts.clock.now(),
|
|
147
|
+
stream: this.stream,
|
|
148
|
+
message: `${this.stream} log could not be written; the persisted log is incomplete: ${err.message}`,
|
|
149
|
+
details: { code: err.code, path: this.opts.filePath },
|
|
150
|
+
});
|
|
151
|
+
// 'drain' will never come after an error; do not leave the source paused.
|
|
152
|
+
this.releaseDrain();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=log-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-capture.js","sourceRoot":"","sources":["../../src/executors/log-capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { type ProcessStartIdentity, type Timers } from '../core/index.js';
|
|
2
|
+
/** Raw identity data of a live process. */
|
|
3
|
+
export interface ProcessProbe {
|
|
4
|
+
pgid: number;
|
|
5
|
+
token: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Platform adapter. `probe` returns `null` if the process does not exist and
|
|
9
|
+
* throws if the state cannot be determined.
|
|
10
|
+
*/
|
|
11
|
+
export interface ProcessInspector {
|
|
12
|
+
readonly platform: string;
|
|
13
|
+
probe(pid: number): Promise<ProcessProbe | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Optional precise check whether group `pgid` has members that are not
|
|
16
|
+
* zombies. Without it, a signal-0 probe is used (zombies count as alive).
|
|
17
|
+
*/
|
|
18
|
+
groupHasLiveMembers?(pgid: number): Promise<boolean>;
|
|
19
|
+
}
|
|
20
|
+
/** Result of comparing a live process with a persisted identity. */
|
|
21
|
+
export type IdentityCheck =
|
|
22
|
+
/** Same process (start token and process group match). */
|
|
23
|
+
'same'
|
|
24
|
+
/** A different process uses this PID now (PID reuse). */
|
|
25
|
+
| 'different'
|
|
26
|
+
/** No process with this PID exists. */
|
|
27
|
+
| 'gone'
|
|
28
|
+
/** Could not be determined (error, unsupported platform, changed group) — never signal. */
|
|
29
|
+
| 'unknown';
|
|
30
|
+
/** Outcome of {@link killProcessGroupIfSame}. */
|
|
31
|
+
export type KillIfSameResult = {
|
|
32
|
+
signalled: true;
|
|
33
|
+
} | {
|
|
34
|
+
signalled: false;
|
|
35
|
+
reason: Exclude<IdentityCheck, 'same'> | 'pgid_mismatch' | 'signal_failed';
|
|
36
|
+
error?: string;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Parse the content of `/proc/<pid>/stat`. The command name (field 2) may
|
|
40
|
+
* contain spaces and parentheses, so fields are counted after the last `)`.
|
|
41
|
+
* Returns process group (field 5) and start time (field 22).
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseProcStat(content: string): {
|
|
44
|
+
state: string;
|
|
45
|
+
pgrp: number;
|
|
46
|
+
starttime: string;
|
|
47
|
+
};
|
|
48
|
+
/** Linux implementation based on procfs. */
|
|
49
|
+
export declare function createLinuxInspector(read?: (path: string) => Promise<string>, list?: (path: string) => Promise<string[]>): ProcessInspector;
|
|
50
|
+
/** Parse the output of `ps -o pgid=,lstart= -p <pid>`. */
|
|
51
|
+
export declare function parsePsOutput(output: string): ProcessProbe | null;
|
|
52
|
+
/** Runs a command, resolving with exit code and stdout. */
|
|
53
|
+
export type CommandRunner = (file: string, args: string[]) => Promise<{
|
|
54
|
+
code: number;
|
|
55
|
+
stdout: string;
|
|
56
|
+
}>;
|
|
57
|
+
/** macOS implementation based on `ps` (lstart = process start time). */
|
|
58
|
+
export declare function createDarwinInspector(run?: CommandRunner): ProcessInspector;
|
|
59
|
+
/** Inspector for the current platform; probing fails on unsupported platforms. */
|
|
60
|
+
export declare function defaultProcessInspector(platform?: NodeJS.Platform): ProcessInspector;
|
|
61
|
+
/**
|
|
62
|
+
* Capture the start identity of `pid`. Returns `undefined` if the process
|
|
63
|
+
* does not exist (anymore) or the identity cannot be determined.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getStartIdentity(pid: number, inspector?: ProcessInspector): Promise<ProcessStartIdentity | undefined>;
|
|
66
|
+
/** Compare the live process `identity.pid` with the persisted identity. */
|
|
67
|
+
export declare function checkProcessIdentity(identity: ProcessStartIdentity, inspector?: ProcessInspector): Promise<IdentityCheck>;
|
|
68
|
+
/** True only if `pid` is verifiably the process described by `identity`. */
|
|
69
|
+
export declare function isSameProcess(pid: number, identity: ProcessStartIdentity, inspector?: ProcessInspector): Promise<boolean>;
|
|
70
|
+
/** Signal sender, injectable for tests (default `process.kill`). */
|
|
71
|
+
export type KillFn = (pid: number, signal: NodeJS.Signals | 0) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Send `signal` to process group `pgid`, but only if its leader
|
|
74
|
+
* (`identity.pid`) is verifiably the same process as recorded in `identity`
|
|
75
|
+
* (Spec §13). Never signals on doubt.
|
|
76
|
+
*
|
|
77
|
+
* Note: if the leader is gone while other group members still run, the group
|
|
78
|
+
* cannot be verified and is not signalled (reason `gone`); use
|
|
79
|
+
* {@link processGroupExists} to detect that case and report it.
|
|
80
|
+
*/
|
|
81
|
+
export declare function killProcessGroupIfSame(pgid: number, identity: ProcessStartIdentity, signal: NodeJS.Signals, deps?: {
|
|
82
|
+
inspector?: ProcessInspector;
|
|
83
|
+
kill?: KillFn;
|
|
84
|
+
}): Promise<KillIfSameResult>;
|
|
85
|
+
/** True if at least one process is in group `pgid` (signal 0 probe; EPERM counts as existing). */
|
|
86
|
+
export declare function processGroupExists(pgid: number): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* True if group `pgid` still has live (non-zombie) members. Falls back to the
|
|
89
|
+
* signal-0 probe if the platform has no precise check or it fails.
|
|
90
|
+
*/
|
|
91
|
+
export declare function processGroupAlive(pgid: number, inspector?: ProcessInspector): Promise<boolean>;
|
|
92
|
+
/** Outcome of {@link terminateProcessGroupIfSame}. */
|
|
93
|
+
export type TerminateResult =
|
|
94
|
+
/** Identity verified, group signalled and confirmed gone. */
|
|
95
|
+
'terminated'
|
|
96
|
+
/** Identity verified and signalled, but the group is still alive after SIGKILL. */
|
|
97
|
+
| 'kill_failed'
|
|
98
|
+
/** A different process uses the leader PID now; nothing signalled. */
|
|
99
|
+
| 'not_same'
|
|
100
|
+
/** Leader and group are gone; nothing to do. */
|
|
101
|
+
| 'gone'
|
|
102
|
+
/** Identity could not be determined (or pgid mismatch); nothing signalled. */
|
|
103
|
+
| 'unknown'
|
|
104
|
+
/**
|
|
105
|
+
* The leader is gone but members of the group are still alive. They cannot
|
|
106
|
+
* be verified, so nothing is signalled — caller should set `recovery_pending`.
|
|
107
|
+
*/
|
|
108
|
+
| 'group_alive_unverifiable';
|
|
109
|
+
/** Options of {@link terminateProcessGroupIfSame}. */
|
|
110
|
+
export interface TerminateOptions {
|
|
111
|
+
inspector?: ProcessInspector;
|
|
112
|
+
kill?: KillFn;
|
|
113
|
+
timers?: Timers;
|
|
114
|
+
/** Wait after SIGKILL before reporting `kill_failed`. Default 5 s. */
|
|
115
|
+
killConfirmMs?: number;
|
|
116
|
+
/** Poll interval while waiting for the group to vanish. Default 25 ms. */
|
|
117
|
+
pollIntervalMs?: number;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Recovery helper (Spec §13, §14 variant A): verify the start identity of the
|
|
121
|
+
* group leader, then SIGTERM the group, SIGKILL after `graceMs` and confirm
|
|
122
|
+
* that no live member remains. Never signals on doubt.
|
|
123
|
+
*/
|
|
124
|
+
export declare function terminateProcessGroupIfSame(identity: ProcessStartIdentity, graceMs: number, options?: TerminateOptions): Promise<TerminateResult>;
|