@kici-dev/orchestrator 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/__test-helpers__/mock-db-query.d.ts +4 -5
  2. package/dist/agent/agent-version.d.ts +5 -5
  3. package/dist/agent/dispatcher.d.ts +26 -0
  4. package/dist/agent/registry.d.ts +7 -9
  5. package/dist/agent-packaging/node-runtime-members.d.ts +14 -0
  6. package/dist/app.d.ts +3 -3
  7. package/dist/approvals/apply-decision.d.ts +1 -1
  8. package/dist/audit/access-log.d.ts +2 -3
  9. package/dist/cli/commands/access-log.d.ts +3 -3
  10. package/dist/cli/commands/agent-service/agent-env.d.ts +20 -0
  11. package/dist/cli/commands/agent-service/status.d.ts +3 -3
  12. package/dist/cli/commands/attestations.d.ts +1 -1
  13. package/dist/cli/commands/context.d.ts +2 -2
  14. package/dist/cli/commands/event-dlq.d.ts +5 -6
  15. package/dist/cli/commands/event-log.d.ts +2 -3
  16. package/dist/cli/commands/execution.d.ts +1 -3
  17. package/dist/cli/commands/orchestrator-service/status.d.ts +10 -3
  18. package/dist/cli/commands/queue.d.ts +1 -2
  19. package/dist/cli/commands/runs.d.ts +2 -3
  20. package/dist/cli/commands/service-health.d.ts +68 -0
  21. package/dist/cli/commands/shared/env-file-mode.d.ts +3 -2
  22. package/dist/cli/commands/shared/upgrade-safety.d.ts +11 -5
  23. package/dist/cli/commands/shared/versioned-upgrade.d.ts +119 -7
  24. package/dist/cli/commands/workflow.d.ts +3 -4
  25. package/dist/cli/open-browser.d.ts +1 -1
  26. package/dist/cli/service/entrypoint.d.ts +18 -0
  27. package/dist/cli/service/image-digests.d.ts +10 -0
  28. package/dist/cli/service/index.d.ts +4 -2
  29. package/dist/cli/service/instance/manifest.d.ts +39 -0
  30. package/dist/cli/service/launchd.d.ts +45 -10
  31. package/dist/cli/service/shutdown-grace.d.ts +35 -0
  32. package/dist/cli/service/types.d.ts +9 -0
  33. package/dist/cli/service/windows-acl.d.ts +40 -0
  34. package/dist/cli/service/windows-env-file.d.ts +45 -0
  35. package/dist/cli/service/windows.d.ts +13 -0
  36. package/dist/cli.js +1620 -551
  37. package/dist/cluster/cluster-identity.d.ts +4 -4
  38. package/dist/cluster/join-token.d.ts +2 -2
  39. package/dist/cluster/leader-gated-scheduler.d.ts +7 -1
  40. package/dist/cluster/peer-credentials.d.ts +1 -1
  41. package/dist/cluster/raft-state.d.ts +6 -0
  42. package/dist/cluster/raft.d.ts +16 -2
  43. package/dist/cold-store/load-access-log-range.d.ts +3 -3
  44. package/dist/cold-store/load-event-log-range.d.ts +1 -1
  45. package/dist/cold-store/load-secret-audit-log-range.d.ts +2 -2
  46. package/dist/cold-store/orchestrator-cold-store.d.ts +9 -11
  47. package/dist/cold-store/tables/access-log.d.ts +2 -2
  48. package/dist/cold-store/tables/event-log.d.ts +4 -10
  49. package/dist/cold-store/tables/execution-jobs.d.ts +1 -1
  50. package/dist/cold-store/tables/execution-runs.d.ts +4 -4
  51. package/dist/cold-store/tables/execution-steps.d.ts +1 -1
  52. package/dist/cold-store/tables/secret-audit-log.d.ts +3 -3
  53. package/dist/config.d.ts +3 -1
  54. package/dist/contexts/held-runs.d.ts +2 -2
  55. package/dist/dashboard/attestation-filters.d.ts +1 -1
  56. package/dist/dashboard/handler.d.ts +8 -8
  57. package/dist/db/deferred-indexes.d.ts +2 -2
  58. package/dist/db/migrations/005_cold_store_chunk_counter.d.ts +2 -4
  59. package/dist/db/migrations/006_runs_jobs_steps_archived_at.d.ts +4 -4
  60. package/dist/db/migrations/007_audit_logs_archived_at.d.ts +6 -9
  61. package/dist/db/migrations/008_event_log_archived_at.d.ts +4 -6
  62. package/dist/db/migrations/010_cold_store_chunks.d.ts +2 -2
  63. package/dist/db/migrations/012_peer_credentials_active_uniq.d.ts +2 -4
  64. package/dist/db/migrations/016_org_settings_allow_http_npm.d.ts +2 -2
  65. package/dist/db/migrations/045_host_properties.d.ts +1 -1
  66. package/dist/db/migrations/046_join_token_consumed_by_instance.d.ts +1 -1
  67. package/dist/db/migrations/048_host_reboot_pending.d.ts +1 -1
  68. package/dist/db/migrations/049_held_runs_payload.d.ts +1 -1
  69. package/dist/db/migrations/050_sources_slug.d.ts +1 -1
  70. package/dist/db/migrations/051_binding_host_pattern.d.ts +1 -1
  71. package/dist/db/migrations/052_host_reach_metadata.d.ts +1 -1
  72. package/dist/db/migrations/053_agent_token_single_use.d.ts +1 -1
  73. package/dist/db/migrations/054_local_working_tree.d.ts +1 -1
  74. package/dist/db/migrations/055_agent_token_mandatory_labels.d.ts +1 -1
  75. package/dist/db/migrations/056_execution_jobs_environments.d.ts +1 -1
  76. package/dist/db/migrations/064_execution_jobs_skipped_environments.d.ts +1 -1
  77. package/dist/db/types.d.ts +12 -13
  78. package/dist/events/types.d.ts +1 -1
  79. package/dist/fault-injection-types.d.ts +2 -2
  80. package/dist/firecracker/host-network.d.ts +21 -3
  81. package/dist/firecracker/net-interfaces.d.ts +1 -1
  82. package/dist/helpers/run-detached.d.ts +12 -0
  83. package/dist/index.js +50 -14
  84. package/dist/oidc/db-signer.d.ts +1 -1
  85. package/dist/pipeline/global-eval-round.d.ts +2 -2
  86. package/dist/pipeline/processor.d.ts +2 -2
  87. package/dist/provenance/retrier-mint.d.ts +1 -1
  88. package/dist/provenance/trust-root.d.ts +3 -3
  89. package/dist/providers/universal-git/clone-token.d.ts +9 -13
  90. package/dist/providers/universal-git/index.d.ts +1 -2
  91. package/dist/providers/universal-git/normalizer.d.ts +2 -3
  92. package/dist/providers/universal-git/ssh-auth.d.ts +4 -4
  93. package/dist/queue/cleanup.d.ts +2 -2
  94. package/dist/queue/job-queue.d.ts +6 -6
  95. package/dist/queue/scheduled-job.d.ts +5 -7
  96. package/dist/registration/extractor.d.ts +1 -1
  97. package/dist/registration/registration-index.d.ts +1 -1
  98. package/dist/reporting/execution-tracker.d.ts +3 -3
  99. package/dist/routes/admin-access-log.d.ts +1 -1
  100. package/dist/routes/admin-auth.d.ts +2 -2
  101. package/dist/routes/admin-event-log.d.ts +2 -2
  102. package/dist/routes/admin-runs.d.ts +3 -3
  103. package/dist/routes/admin-scheduled-jobs.d.ts +2 -3
  104. package/dist/routes/health.d.ts +9 -0
  105. package/dist/scaler/container-backend.d.ts +1 -1
  106. package/dist/scaler/firecracker-backend.d.ts +15 -10
  107. package/dist/scaler/firecracker-extra-hosts.d.ts +20 -0
  108. package/dist/scaler/machine-ledger.d.ts +3 -4
  109. package/dist/scaler/scaler-state-store.d.ts +1 -1
  110. package/dist/scaler/types.d.ts +4 -1
  111. package/dist/secrets/audit-logger.d.ts +2 -2
  112. package/dist/security/reduced-privilege-note.d.ts +2 -3
  113. package/dist/security/trust-policy-store.d.ts +3 -3
  114. package/dist/server.d.ts +2 -1
  115. package/dist/server.js +2736 -2211
  116. package/dist/stale-detector/stale-run-detector.d.ts +1 -1
  117. package/dist/standalone.d.ts +1 -1
  118. package/dist/standalone.js +2105 -1629
  119. package/dist/storage/filesystem.d.ts +1 -1
  120. package/dist/storage/index.d.ts +1 -1
  121. package/dist/storage/sign-url.d.ts +2 -1
  122. package/dist/storage/types.d.ts +2 -2
  123. package/dist/ws/agent-handler.d.ts +34 -3
  124. package/dist/ws/agent-heartbeat.d.ts +2 -3
  125. package/dist/ws/dashboard-context-handler.d.ts +1 -1
  126. package/dist/ws/platform-client.d.ts +44 -32
  127. package/dist/ws/server-options.d.ts +1 -1
  128. package/dist/ws/test-relay-handlers.d.ts +1 -1
  129. package/installer-image-digests.json +3 -3
  130. package/package.json +4 -4
  131. package/sbom.spdx.json +53 -53
@@ -2,10 +2,9 @@
2
2
  * Workflow registration commands for kici-admin.
3
3
  *
4
4
  * Provides operator-facing read access to the workflow_registrations table
5
- * via the orchestrator's admin HTTP API. This is the dogfooded replacement
6
- * for "let me just psql the registration table" — every CLI subcommand here
7
- * goes through AdminApiClient and the existing /api/v1/admin/registrations
8
- * route.
5
+ * via the orchestrator's admin HTTP API. Use it instead of querying the
6
+ * registration table with psql: every CLI subcommand here goes through
7
+ * AdminApiClient and the existing /api/v1/admin/registrations route.
9
8
  *
10
9
  * workflow list List registered workflows (table or JSON)
11
10
  *
@@ -5,7 +5,7 @@
5
5
  * blocked launcher) just falls back to copy-paste.
6
6
  *
7
7
  * `KICI_BROWSER_CMD` overrides the launcher: `none` suppresses it entirely
8
- * (E2E / headless capture), any other value is run with `{url}` substituted —
8
+ * (automated tests / headless capture), any other value is run with `{url}` substituted —
9
9
  * mirroring the `kici login` convention.
10
10
  */
11
11
  export declare function openBrowserBestEffort(url: string): void;
@@ -33,4 +33,22 @@ export declare function resolveServiceExecutable(opts: {
33
33
  nodePath: string;
34
34
  entryScript?: string;
35
35
  }): ServiceExecutable;
36
+ /**
37
+ * The path of a server entry script installed beside this CLI, for a service
38
+ * that runs `node <script>`. `resolve` is the calling module's
39
+ * `import.meta.resolve`, or undefined where the CLI has none: a kici-admin from a
40
+ * standalone package is a single CommonJS bundle that carries no orchestrator
41
+ * or agent server. Either way the error names `--binary`, the launcher the
42
+ * service runs instead.
43
+ */
44
+ export declare function resolveServerScript(specifier: string, component: ServerComponent, resolve: ModuleResolver | undefined): string;
45
+ /**
46
+ * Refuse an install without `--binary` on a kici-admin that cannot resolve
47
+ * installed packages, before the wizard runs or any file is written.
48
+ */
49
+ export declare function assertServerResolvable(component: ServerComponent, binary: string | undefined, resolve: ModuleResolver | undefined): void;
50
+ type ServerComponent = 'orchestrator' | 'agent';
51
+ /** A module's `import.meta.resolve`. */
52
+ export type ModuleResolver = (specifier: string) => string;
53
+ export {};
36
54
  //# sourceMappingURL=entrypoint.d.ts.map
@@ -11,6 +11,16 @@
11
11
  * layouts: the source tree (`src/cli/service/` → the JSON is three dirs up at
12
12
  * the package root) and the single-file bundle (`dist/cli.js` → one dir up).
13
13
  */
14
+ import type { Component } from './instance/types.js';
15
+ /** The published image a component runs, whatever the service is named. */
16
+ export declare function installerImageName(component: Component): string;
17
+ /**
18
+ * The release {@link resolveImageRef} pins `name` at, or null when it falls
19
+ * back to the moving `:latest` tag.
20
+ */
21
+ export declare function pinnedImageVersion(name: string, opts?: {
22
+ filePath?: string;
23
+ }): string | null;
14
24
  /**
15
25
  * Resolve `quay.io/kici-dev/<name>:<version>@sha256:<digest>` for an installer
16
26
  * image. Falls back to `:latest` (with a warning) when no recorded digest exists.
@@ -7,12 +7,14 @@
7
7
  * platform-specific code on every platform.
8
8
  */
9
9
  export type { ServiceManager, ServiceConfig, LaunchSpec, ServiceStatus, ServiceState, ServicePlatform, RestartPolicy, LogOptions, } from './types.js';
10
- export { DEFAULT_RESTART_POLICY } from './types.js';
10
+ export { DEFAULT_RESTART_POLICY, SERVICE_TEXT } from './types.js';
11
11
  export { detectPlatform, isRoot, kiciConfigRoot, getConfigDir, getLogDir, getCacheDir, } from './platform-detect.js';
12
12
  export { resolveUserLevel, type PrivilegeOpts } from './privilege.js';
13
+ export { restrictEnvFileAccess } from './windows-acl.js';
14
+ export { ENV_FILE_LOADER_EXPORT, envFileRefusal, launchReadsEnvFile, launchedRelease, } from './windows-env-file.js';
13
15
  export type { Component, InstanceManifest, IndexEntry, ResolveOptions, ResolvedInstance, } from './instance/types.js';
14
16
  export { COMPONENTS, isComponent } from './instance/types.js';
15
- export { manifestFilename, manifestPath, readManifest, writeManifest, readKiciVersion, resolveVersionFromLaunchSpec, resolveNpmInstallTarget, type NpmInstallTarget, } from './instance/manifest.js';
17
+ export { manifestFilename, manifestPath, readManifest, writeManifest, readKiciVersion, resolveVersionFromLaunchSpec, resolveLauncherVersion, writeInstallManifest, type InstallManifestWrite, resolveNpmInstallTarget, type NpmInstallTarget, } from './instance/manifest.js';
16
18
  export { indexPath, readIndex, writeIndex, appendIndexEntry, removeIndexEntry, } from './instance/index-file.js';
17
19
  export { candidatePlatforms, listInstances, resolveInstance, resolveInstanceTarget, formatRefusal, InstanceNotFoundError, } from './instance/resolve.js';
18
20
  export type { ListedInstance, ResolveArgs, ListInstancesArgs, ResolveTargetArgs, ResolvedTarget, } from './instance/resolve.js';
@@ -39,6 +39,45 @@ export declare function readKiciVersion(): string;
39
39
  * stand behind.
40
40
  */
41
41
  export declare function resolveVersionFromLaunchSpec(spec: LaunchSpec, component: Component): string | null;
42
+ /**
43
+ * The version of the launcher a service definition starts, or null when the
44
+ * launch command does not show one.
45
+ *
46
+ * An npm-installed entry script names its version in its package.json
47
+ * ({@link resolveVersionFromLaunchSpec}). A launcher under the instance's
48
+ * install base resolves into the `<component>-<version>` folder an archive
49
+ * upgrade extracted: through the `<component>` symlink on Linux and macOS, or
50
+ * directly where Windows registers it. A `--binary` anywhere else shows none.
51
+ */
52
+ export declare function resolveLauncherVersion(spec: LaunchSpec, component: Component, installBase: string): string | null;
53
+ /** What {@link writeInstallManifest} wrote. */
54
+ export interface InstallManifestWrite {
55
+ file: string;
56
+ manifest: InstanceManifest;
57
+ /** Set when the folder held a manifest the install replaced instead of updating. */
58
+ warning?: string;
59
+ }
60
+ /**
61
+ * Write the manifest `install` built into `instanceDir`.
62
+ *
63
+ * A first install writes `fresh` as it is. A re-install of the same instance
64
+ * (the folder holds a readable manifest of this component and name) updates
65
+ * that manifest: it keeps what the instance recorded over time — `createdAt`,
66
+ * the `migrationHeads` the rollback schema guard reads, and any field a newer
67
+ * CLI wrote — and takes every other field from `fresh`. Its `kiciVersion` is
68
+ * the version of the launcher `launch` starts; when the launcher shows none,
69
+ * the recorded version stands, because the CLI that ran `install` need not
70
+ * be the version the service runs. A compose service runs the image its
71
+ * compose file pins, whatever `launch` names, so a compose re-install records
72
+ * the release of that image (`opts.digestRecordPath` overrides the digest
73
+ * record it reads, for tests).
74
+ *
75
+ * A manifest that cannot be read, or that names another instance, is
76
+ * replaced, and the result carries a warning.
77
+ */
78
+ export declare function writeInstallManifest(instanceDir: string, fresh: InstanceManifest, launch: LaunchSpec, opts?: {
79
+ digestRecordPath?: string;
80
+ }): InstallManifestWrite;
42
81
  /**
43
82
  * The global npm package + node runtime an npm-source upgrade must install
44
83
  * into, derived from a unit's launch spec. `owningPackage` is the top-level
@@ -18,8 +18,24 @@ export declare class LaunchdServiceManager implements ServiceManager {
18
18
  private label;
19
19
  /** Resolve the log directory based on service level. */
20
20
  private logDir;
21
- /** Resolve the plist file path based on service level. */
22
- private plistPath;
21
+ /** The directory launchd loads this service level's plists from. */
22
+ private plistDir;
23
+ /** The job `install` writes: `dev.kici.<name>`. */
24
+ private installJob;
25
+ /**
26
+ * An installed job for this name under another label: a `com.kici.<name>`
27
+ * plist, or a plist named after the service itself — each one `list()`
28
+ * reports as this instance. Only a plist that carries the KiCI component
29
+ * marker counts, and the job is addressed by the Label the plist declares.
30
+ */
31
+ private otherLabelJob;
32
+ /**
33
+ * The job a lifecycle command acts on: the `dev.kici.<name>` plist when it
34
+ * is installed, otherwise a job this name was installed under with another
35
+ * label, so every instance `list()` reports can be stopped, started and
36
+ * removed. With neither installed, the `dev.kici.<name>` job.
37
+ */
38
+ private resolveJob;
23
39
  /** Parse a .env file into key-value pairs. */
24
40
  private parseEnvFile;
25
41
  /** Escape XML special characters. */
@@ -41,20 +57,29 @@ export declare class LaunchdServiceManager implements ServiceManager {
41
57
  * domain from the plist's filesystem location, but they fail silently on
42
58
  * headless macOS hosts where no GUI session exists (the `gui/<uid>` domain
43
59
  * is not available without a console login). The modern `bootstrap` /
44
- * `bootout` / `kickstart` / `kill` verbs take the domain explicitly, so a
60
+ * `bootout` / `kickstart` / `print` verbs take the domain explicitly, so a
45
61
  * system-level LaunchDaemon loads regardless of whether anyone is logged
46
62
  * in at the console — exactly what we need for headless deploy targets.
47
63
  */
48
64
  private domain;
49
- /** `<domain>/<label>` — the target string for kickstart/kill/print/enable. */
65
+ /** `<domain>/<label>` — the target string for bootout/kickstart/print. */
50
66
  private domainTarget;
51
- /** Is the service currently loaded in its target domain? */
67
+ /**
68
+ * `launchctl print <domain>/<label>`: the job's description while it is
69
+ * loaded, or null when launchd reports it not loaded. Unlike `launchctl
70
+ * list`, which lists only the caller's own domain, this reads a system
71
+ * daemon without root. Any other failure throws, so a job that could not be
72
+ * inspected is never mistaken for a stopped one.
73
+ */
74
+ private printJob;
75
+ /** Is the job currently loaded in its target domain? */
52
76
  private isLoaded;
53
77
  install(config: ServiceConfig): Promise<void>;
54
78
  /**
55
- * Poll until the service is no longer loaded in its target domain, or a
56
- * short deadline elapses. `launchctl bootout` is asynchronous — it returns
57
- * before launchd has finished releasing the service — so a bootstrap issued
79
+ * Poll until the job is no longer loaded in its target domain, or the
80
+ * deadline elapses. Resolves true once the job has left the domain,
81
+ * false on timeout. `launchctl bootout` is asynchronous — it returns before
82
+ * launchd has finished releasing the job — so a bootstrap issued
58
83
  * immediately afterward races the teardown and fails with EIO. Waiting for
59
84
  * the unload to complete closes that race for the common case; the residual
60
85
  * window is covered by bootstrapWithRetry.
@@ -64,13 +89,23 @@ export declare class LaunchdServiceManager implements ServiceManager {
64
89
  * Bootstrap into the target domain, retrying on the transient EIO
65
90
  * ("5: Input/output error") launchd returns when a just-removed service has
66
91
  * not finished tearing down. A genuine, non-transient failure (bad plist,
67
- * permission denied) is re-thrown on the first attempt. If a stale instance
68
- * reappears between attempts, it is booted out before the next try.
92
+ * permission denied) is re-thrown on the first attempt.
93
+ *
94
+ * launchd answers a bootstrap of a job that is already loaded with the same
95
+ * EIO. With `replaceLoaded` (install, which just wrote a new plist) such a
96
+ * job is booted out before the next try. Without it (start), a job that
97
+ * another caller loaded meanwhile is the outcome start wanted: RunAtLoad has
98
+ * started it, so the call succeeds and leaves it running.
69
99
  */
70
100
  private bootstrapWithRetry;
71
101
  uninstall(config: ServiceConfig): Promise<void>;
72
102
  start(config: ServiceConfig): Promise<void>;
73
103
  stop(config: ServiceConfig): Promise<void>;
104
+ /**
105
+ * Boot the job out of its domain and wait until launchd has finished the
106
+ * teardown. Does nothing when no job is loaded.
107
+ */
108
+ private unload;
74
109
  restart(config: ServiceConfig): Promise<void>;
75
110
  status(config: ServiceConfig): Promise<ServiceStatus>;
76
111
  logs(config: ServiceConfig, options: LogOptions): Promise<void>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * How long an init system waits for a KiCI service to shut down.
3
+ */
4
+ import type { ServiceConfig } from './types.js';
5
+ /**
6
+ * Seconds an init system must wait after SIGTERM before it SIGKILLs the service.
7
+ *
8
+ * The runtime defaults are shorter than either component's own graceful-shutdown
9
+ * budget: Compose waits 10s, launchd's default ExitTimeOut is 5s, and shawl's
10
+ * default `--stop-timeout` on Windows is 3s. A teardown that
11
+ * takes longer is killed partway through: the orchestrator never broadcasts
12
+ * `peer.leaving` and never closes its agent sockets, and the agent never
13
+ * finishes draining. That window is reached exactly when it matters most — the
14
+ * orchestrator's scaler stops each managed agent with its own grace, so an
15
+ * orchestrator with agents in flight routinely needs more than 10s.
16
+ *
17
+ * Each value is its component's force-exit budget plus headroom, so the
18
+ * process always reaches its own timer first and the runtime's kill stays the
19
+ * last resort it is meant to be:
20
+ * - orchestrator: 30s (`setupGracefulShutdown` default) plus up to 2s of log
21
+ * file flush -> 45s
22
+ * - agent: 10s plus a ~1s abort delay in its `onForceExit` -> 20s
23
+ *
24
+ * An unrecognised component gets the larger value: over-waiting costs a few
25
+ * seconds on shutdown, under-waiting corrupts it.
26
+ */
27
+ export declare function shutdownGraceSeconds(config: ServiceConfig): number;
28
+ /**
29
+ * Seconds a `stop` waits for the init system to report the service stopped.
30
+ *
31
+ * The init system kills the process once its grace elapses, so a service still
32
+ * running after the grace plus this margin is hung, not slow.
33
+ */
34
+ export declare function stopWaitSeconds(config: ServiceConfig): number;
35
+ //# sourceMappingURL=shutdown-grace.d.ts.map
@@ -20,6 +20,15 @@ export interface RestartPolicy {
20
20
  }
21
21
  /** Default restart policy: backoff 1s, 5s, 15s, 30s; max 5 failures in 5 minutes. */
22
22
  export declare const DEFAULT_RESTART_POLICY: RestartPolicy;
23
+ /**
24
+ * The display name and description a component's service is registered with.
25
+ * `install` and every upgrade that registers a service again use it, so an
26
+ * upgraded registration carries the same text as a fresh one.
27
+ */
28
+ export declare const SERVICE_TEXT: Record<'orchestrator' | 'agent', {
29
+ displayName: string;
30
+ description: string;
31
+ }>;
23
32
  /** Configuration for installing a service. */
24
33
  export interface ServiceConfig {
25
34
  /** Service identifier (e.g., "kici-orchestrator"). */
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Restricting a Windows service's env file to the service account and to
3
+ * Administrators.
4
+ *
5
+ * Node maps a file mode onto Windows by toggling the read-only attribute and
6
+ * changes no ACL, so ENV_FILE_MODE protects nothing there. The instance folder
7
+ * under C:\ProgramData\kici\ inherits read access for BUILTIN\Users from
8
+ * C:\ProgramData. Its ACL is replaced with full control for LocalSystem (the
9
+ * account the shawl service runs as) and Administrators, inherited by
10
+ * everything created in it: the env file, the temporary file a secure write
11
+ * stages it through, and the service logs are unreadable to other accounts
12
+ * from the moment they exist.
13
+ *
14
+ * Every call passes `/L` and none recurses, so icacls acts on the folder and on
15
+ * the env file themselves and never on what a link there points at. A
16
+ * recursive `/reset` or `/setowner` descends into the target of a junction or
17
+ * of a symbolic link, even with `/L`, and rewrites the ACL of the files there.
18
+ * The new folder ACL still reaches every entry that inherits from the folder.
19
+ */
20
+ /** NT AUTHORITY\SYSTEM, the account a shawl service runs as. */
21
+ export declare const LOCAL_SYSTEM_SID = "S-1-5-18";
22
+ /** BUILTIN\Administrators. */
23
+ export declare const ADMINISTRATORS_SID = "S-1-5-32-544";
24
+ /** Runs `icacls` with the given arguments; throws when it fails. */
25
+ export type IcaclsRunner = (args: string[]) => void;
26
+ /**
27
+ * The icacls arguments that remove every inherited ACE from `dir` and grant
28
+ * full control, inherited by files and folders, to LocalSystem and
29
+ * Administrators. SIDs rather than names, so a localized Windows resolves them.
30
+ */
31
+ export declare function restrictDirArgs(dir: string): string[];
32
+ /** The icacls arguments that reset `file` to inherit only from its folder. */
33
+ export declare function resetFileArgs(file: string): string[];
34
+ /**
35
+ * Restrict the folder that holds `envFilePath`, then reset an existing env
36
+ * file to inherit only from it, which also drops any explicit ACE on the file.
37
+ * Run it before the first secret is written into the folder.
38
+ */
39
+ export declare function restrictEnvFileAccess(envFilePath: string, run?: IcaclsRunner, exists?: (filePath: string) => boolean): void;
40
+ //# sourceMappingURL=windows-acl.d.ts.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Whether a Windows service launch runs a release that reads KICI_ENV_FILE.
3
+ *
4
+ * A Windows service is registered with the path of its env file in
5
+ * KICI_ENV_FILE, never with the values in the file: any local account reads the
6
+ * command line of a service with `sc.exe qc`. A release from before
7
+ * KICI_ENV_FILE ignores the path and starts without its configuration, and the
8
+ * only registration that would run it puts the values back on the command line.
9
+ * So every command that registers a Windows service, or switches one to another
10
+ * release, refuses such a release before it changes anything.
11
+ */
12
+ /**
13
+ * The `@kici-dev/shared` export that loads the env file KICI_ENV_FILE names. A
14
+ * release publishes it, and imports it first in each entry, only when it reads
15
+ * KICI_ENV_FILE.
16
+ */
17
+ export declare const ENV_FILE_LOADER_EXPORT = "./load-service-env-file";
18
+ /**
19
+ * The file that names a launch's release: the npm entry among its arguments,
20
+ * or else the executable itself.
21
+ */
22
+ export declare function launchedRelease(launch: {
23
+ executablePath: string;
24
+ args?: string[];
25
+ }): string;
26
+ /**
27
+ * Whether the process a Windows service launch starts reads KICI_ENV_FILE.
28
+ *
29
+ * A KiCI package runs as `<dir>\<name>.cmd` beside its bundle
30
+ * `<dir>\lib\<name>.cjs`, which names KICI_ENV_FILE when the release reads it.
31
+ * An npm install runs node with the `@kici-dev/<component>/dist/<entry>.js`
32
+ * entry, which then imports the env-file loader. Any other launch, such as a
33
+ * batch file with no KiCI bundle beside it or a custom executable, is taken to
34
+ * read it.
35
+ */
36
+ export declare function launchReadsEnvFile(launch: {
37
+ executablePath: string;
38
+ args?: string[];
39
+ }): boolean;
40
+ /**
41
+ * Why a Windows service may not run `release`, a release from before
42
+ * KICI_ENV_FILE, and what the operator can do instead.
43
+ */
44
+ export declare function envFileRefusal(release: string, envFilePath: string): string;
45
+ //# sourceMappingURL=windows-env-file.d.ts.map
@@ -30,6 +30,8 @@ export declare class WindowsServiceManager implements ServiceManager {
30
30
  * not exist; exit 0 means it exists (possibly pending-delete).
31
31
  */
32
32
  private serviceExists;
33
+ /** The service's STATE code from `sc.exe query`, or undefined when the query fails. */
34
+ private queryStateCode;
33
35
  install(config: ServiceConfig): Promise<void>;
34
36
  uninstall(config: ServiceConfig): Promise<void>;
35
37
  start(config: ServiceConfig): Promise<void>;
@@ -39,6 +41,17 @@ export declare class WindowsServiceManager implements ServiceManager {
39
41
  logs(config: ServiceConfig, _options: LogOptions): Promise<void>;
40
42
  isInstalled(config: ServiceConfig): Promise<boolean>;
41
43
  list(isUserLevel: boolean): Promise<DiscoveredInstance[]>;
44
+ /**
45
+ * The command line a service is registered with.
46
+ *
47
+ * `sc.exe qc` answers most registrations, but it fails (error 1734) once the
48
+ * line is longer than about 4000 characters, as an older CLI's registration
49
+ * with every env-file value on it can be. It also prints in the console code
50
+ * page, so a path outside ASCII, such as one under the profile of a user
51
+ * named Jürgen, decodes to U+FFFD. In either case the registry value it reads
52
+ * (`ImagePath`) is read through PowerShell, printed as UTF-8.
53
+ */
54
+ private registeredCommandLine;
42
55
  readLaunchSpec(config: ServiceConfig): Promise<LaunchSpec | null>;
43
56
  }
44
57
  //# sourceMappingURL=windows.d.ts.map