paratix 0.10.0 → 0.12.2

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.
@@ -1,4 +1,319 @@
1
- import { M as Module } from './types-Cl2Muw1x.js';
1
+ /**
2
+ * A scalar env value, or a lazy function that returns one.
3
+ * Functions may be async, allowing secrets to be fetched on demand.
4
+ */
5
+ type EnvironmentValue = (() => boolean | number | string) | (() => Promise<boolean | number | string>) | boolean | number | string;
6
+ /** A key-value map of environment values available to modules and templates. */
7
+ type Environment = Record<string, EnvironmentValue>;
8
+ /** Environment values that can be emitted through the typed meta system. */
9
+ type MetaEnvironmentValue = EnvironmentValue;
10
+ /** Generic meta entry that propagates a value into the downstream environment. */
11
+ type EnvironmentMetaEntry = {
12
+ kind: "env";
13
+ name: string;
14
+ resolve: () => Promise<boolean | number | string>;
15
+ valueType: "boolean" | "number" | "string";
16
+ valueTypeExplicit?: boolean;
17
+ };
18
+ /** Runner control-plane meta entry emitted when sshd changed its listen port. */
19
+ type SshdPortMetaEntry = {
20
+ kind: "sshd.port";
21
+ port: number;
22
+ };
23
+ /** Runner control-plane meta entry emitted when the target host changed. */
24
+ type SystemHostMetaEntry = {
25
+ host: string;
26
+ kind: "system.host";
27
+ };
28
+ /** Runner control-plane meta entry emitted when a reboot should trigger reconnect logic. */
29
+ type SystemRebootMetaEntry = {
30
+ kind: "system.reboot";
31
+ };
32
+ /** Any meta entry that modules may emit. */
33
+ type ModuleMetaEntry = EnvironmentMetaEntry | SshdPortMetaEntry | SystemHostMetaEntry | SystemRebootMetaEntry;
34
+ /** Check result indicating the module's desired state is not yet present. */
35
+ declare const NEEDS_APPLY: "needs-apply";
36
+ /** Execution status emitted by a module apply step. */
37
+ type ModuleStatus = "changed" | "failed" | "ok" | "skipped";
38
+ /** The outcome of a module's apply step. */
39
+ type ModuleResult = {
40
+ /**
41
+ * Optional internal dry-run detail shown instead of the generic `(dry-run)`
42
+ * suffix when a module performed custom dry-run verification.
43
+ * @internal
44
+ */
45
+ _dryRunDetail?: string;
46
+ /**
47
+ * Optional internal control-plane marker that tells the current scope to
48
+ * execute all pending signals immediately at this point in the run.
49
+ * @internal
50
+ */
51
+ _flushSignals?: true;
52
+ /**
53
+ * Optional internal control-plane marker that tells the runner to stop the
54
+ * current run successfully after this module completed.
55
+ * @internal
56
+ */
57
+ _stopRun?: true;
58
+ /** Optional short detail appended to the printed module status line. */
59
+ detail?: string;
60
+ /**
61
+ * Optional multi-line unified-diff string rendered below the module status
62
+ * line when the runner was started with the `--diff` CLI flag (or with
63
+ * the runner option `diff`). Modules that participate in diff output produce
64
+ * the string in their `_applyDryRun` hook and mark themselves with
65
+ * `_dryRunDiffProducer: true`. The runner never modifies the string; the
66
+ * output layer applies registered-secret masking and terminal sanitizing
67
+ * before printing each line.
68
+ *
69
+ * Renders independently of `_dryRunDetail` — both fields may be set at the
70
+ * same time, and the runner shows both (detail inline next to the status,
71
+ * diff in a block beneath it).
72
+ */
73
+ diff?: string;
74
+ /** Optional error details consumed by the runner for centralized CLI output. */
75
+ error?: Error;
76
+ /** Optional typed meta entries for env propagation and runner control-plane updates. */
77
+ meta?: ModuleMetaEntry[];
78
+ /** Execution status of the module. */
79
+ status: ModuleStatus;
80
+ };
81
+ /**
82
+ * Internal orchestration step shape shared between runner and recipe execution.
83
+ * Contains the merged downstream environment after a single apply step.
84
+ * @internal
85
+ */
86
+ type OrchestrationStep = {
87
+ /** @internal */
88
+ _flushSignals?: true;
89
+ /** @internal */
90
+ _stopRun?: true;
91
+ env: Environment;
92
+ meta?: ModuleMetaEntry[];
93
+ status: ModuleStatus;
94
+ };
95
+ /**
96
+ * Optional internal apply hooks used by composite modules to expose child
97
+ * orchestration steps to their surrounding runner scope.
98
+ * @internal
99
+ */
100
+ type ModuleApplyOptions = {
101
+ onChildStep?: (step: OrchestrationStep) => Promise<void>;
102
+ shutdownSignal?: () => null | ShutdownSignal;
103
+ };
104
+ /**
105
+ * Shutdown signal names observed by Paratix orchestration hooks.
106
+ *
107
+ * This intentionally mirrors Node's process signal strings without referencing
108
+ * the ambient `NodeJS` namespace, so published declarations remain usable in
109
+ * consumers that do not install `@types/node`.
110
+ */
111
+ type ShutdownSignal = "SIGABRT" | "SIGALRM" | "SIGBREAK" | "SIGBUS" | "SIGCHLD" | "SIGCONT" | "SIGFPE" | "SIGHUP" | "SIGILL" | "SIGINFO" | "SIGINT" | "SIGIO" | "SIGIOT" | "SIGKILL" | "SIGLOST" | "SIGPIPE" | "SIGPOLL" | "SIGPROF" | "SIGPWR" | "SIGQUIT" | "SIGSEGV" | "SIGSTKFLT" | "SIGSTOP" | "SIGSYS" | "SIGTERM" | "SIGTRAP" | "SIGTSTP" | "SIGTTIN" | "SIGTTOU" | "SIGUNUSED" | "SIGURG" | "SIGUSR1" | "SIGUSR2" | "SIGVTALRM" | "SIGWINCH" | "SIGXCPU" | "SIGXFSZ";
112
+ /**
113
+ * A single idempotent unit of work that can be checked and applied.
114
+ * Modules form the building blocks of a server recipe.
115
+ */
116
+ type Module = {
117
+ /**
118
+ * Optional internal dry-run apply hook for modules that need custom dry-run
119
+ * execution semantics beyond the generic blocker/meta-producer markers.
120
+ * @internal
121
+ */
122
+ _applyDryRun?: (ssh: null | SshConnection, environment: Environment, options?: ModuleApplyOptions) => Promise<ModuleResult>;
123
+ /**
124
+ * Internal marker for modules that must still execute their apply step in dry-run mode
125
+ * because they act as run blockers rather than mutating state.
126
+ * @internal
127
+ */
128
+ _dryRunBlocker?: true;
129
+ /**
130
+ * Internal marker for modules that can produce a {@link ModuleResult.diff}
131
+ * during dry-run by running their `_applyDryRun` hook. The runner only
132
+ * dispatches `_applyDryRun` for diff production when the user passed the
133
+ * `--diff` CLI flag (i.e. the runner option `diff` is `true`); otherwise the
134
+ * generic `(dry-run)` suffix is shown without any extra remote round-trips.
135
+ * @internal
136
+ */
137
+ _dryRunDiffProducer?: true;
138
+ /**
139
+ * Internal marker for non-mutating modules whose apply step emits meta that must
140
+ * still be materialized during dry-run so downstream modules see the same environment.
141
+ * @internal
142
+ */
143
+ _dryRunMetaProducer?: true;
144
+ /**
145
+ * Internal marker for composite modules that can expose child orchestration
146
+ * steps to the surrounding runner scope.
147
+ * @internal
148
+ */
149
+ _supportsChildStepHook?: true;
150
+ /**
151
+ * Enforce the desired state.
152
+ * @returns A {@link ModuleResult} describing what happened.
153
+ */
154
+ apply: (ssh: null | SshConnection, environment: Environment, options?: ModuleApplyOptions) => Promise<ModuleResult>;
155
+ /**
156
+ * Determine whether the module needs to run.
157
+ * @returns `"ok"` if the desired state is already present, `"needs-apply"` otherwise.
158
+ */
159
+ check: (ssh: null | SshConnection, environment: Environment) => Promise<"needs-apply" | "ok">;
160
+ /**
161
+ * When true the module runs locally instead of over SSH.
162
+ * The `ssh` parameter will be `null` in check/apply.
163
+ */
164
+ local?: boolean;
165
+ /** Human-readable name shown in the run output. */
166
+ name: string;
167
+ };
168
+ /** Raw output from a remote or local command execution. */
169
+ type ExecResult = {
170
+ /** Exit code of the process. */
171
+ code: number;
172
+ /** Captured standard error. */
173
+ stderr: string;
174
+ /** Captured standard output. */
175
+ stdout: string;
176
+ };
177
+ /** Options that control how a command is executed. */
178
+ type ExecOptions = {
179
+ /** Additional environment variables to inject into the process. */
180
+ env?: Record<string, string>;
181
+ /** Return a result even when the exit code is non-zero instead of throwing. */
182
+ ignoreExitCode?: boolean;
183
+ /**
184
+ * Optional payload written to the remote command's stdin before EOF is
185
+ * signalled. Used to pass secret material (password hashes, signed URLs,
186
+ * Authorization headers) to a remote tool without exposing it on the
187
+ * command line, where it would otherwise leak into `/var/log/auth.log`,
188
+ * `ps -ef`, or `/proc/<pid>/cmdline`.
189
+ */
190
+ input?: string;
191
+ /**
192
+ * Maximum number of UTF-8 bytes captured per output stream for `stdout` and
193
+ * `stderr`. Live output still streams fully; only the stored ExecResult and
194
+ * CommandError output are capped.
195
+ */
196
+ maxOutputBytes?: number;
197
+ /** Strings to mask in error messages (e.g. tokens, passwords). */
198
+ secrets?: string[];
199
+ /** Suppress stdout/stderr from the console while running. */
200
+ silent?: boolean;
201
+ /** Abort the command after this many milliseconds. */
202
+ timeout?: number;
203
+ };
204
+ /**
205
+ * Abstraction over an active SSH session.
206
+ * All methods that accept a `command` string run it on the remote host.
207
+ */
208
+ type SshConnection = {
209
+ /** Register an additional port that was opened on the remote host. Returns `true` when added. */
210
+ addPort: (port: number) => boolean;
211
+ /** Close the SSH connection and free resources. */
212
+ disconnect: () => void;
213
+ /** Download a remote file to the local filesystem. */
214
+ downloadFile: (remotePath: string, localPath: string) => Promise<void>;
215
+ /** Run a command and return the full result including exit code and output. */
216
+ exec: (command: string, options?: ExecOptions) => Promise<ExecResult>;
217
+ /** Return `true` if the remote path exists. */
218
+ exists: (remotePath: string) => Promise<boolean>;
219
+ /**
220
+ * Return the low-level connection parameters for this session.
221
+ * `privateKeyPath` and `agentSocket` reflect the authentication method that
222
+ * was actually used for the current session. `privateKeyPath` is returned as
223
+ * an expanded filesystem path.
224
+ */
225
+ getConnectionInfo: () => {
226
+ agentSocket?: string;
227
+ authMethod?: "agent" | "password" | "privateKey";
228
+ configuredPorts: number[];
229
+ host: string;
230
+ port: number;
231
+ privateKeyPath?: string;
232
+ user: string;
233
+ verifiedHostPublicKey?: string;
234
+ };
235
+ /** Run a command and return stdout split into lines. */
236
+ lines: (command: string) => Promise<string[]>;
237
+ /** Run a command and return trimmed stdout. */
238
+ output: (command: string) => Promise<string>;
239
+ /** Probe whether passwordless sudo works; prompt interactively if not and cache the password. */
240
+ probeSudo: () => Promise<void>;
241
+ /** Read the full contents of a remote file as a string. */
242
+ readFile: (remotePath: string) => Promise<string>;
243
+ /** Reconnect the SSH session using the current host and registered port candidates. */
244
+ reconnect: () => Promise<void>;
245
+ /** Remove a previously registered port from the reconnect candidate list. */
246
+ removePort: (port: number) => void;
247
+ /** Return the SHA-256 hex digest of a remote file, or `null` if not found. */
248
+ sha256: (remotePath: string) => Promise<null | string>;
249
+ /** Run a command and return `true` if the exit code is zero. */
250
+ test: (command: string) => Promise<boolean>;
251
+ /** Update the target host address (e.g. after a reboot with new IP). */
252
+ updateHost: (host: string) => void;
253
+ /** Upload a local file to the remote host via SFTP. */
254
+ uploadFile: (localPath: string, remotePath: string, options?: {
255
+ mode?: string;
256
+ }) => Promise<void>;
257
+ /** Write a string to a remote file, creating or overwriting it. */
258
+ writeFile: (remotePath: string, content: string, options: {
259
+ mode: string;
260
+ }) => Promise<void>;
261
+ };
262
+ /** SSH connection parameters for a server. */
263
+ type SshConfig = {
264
+ /** Forward the local SSH agent to the remote host. */
265
+ agentForward?: boolean;
266
+ /** Expected SHA256 host fingerprint used as a pinned trust anchor. */
267
+ expectedHostFingerprint?: string;
268
+ /** Expected OpenSSH public key (`"<algorithm> <base64>"`) used as a pinned trust anchor. */
269
+ expectedHostPublicKey?: string;
270
+ /** Maximum number of reconnection attempts before giving up. */
271
+ maxReconnectAttempts?: number;
272
+ /** Fall back to password authentication if key auth fails. */
273
+ passwordFallback?: boolean;
274
+ /** Ordered list of candidate ports -- the runner tries each until one connects. */
275
+ ports: number[];
276
+ /**
277
+ * Absolute path to the private key file used for authentication.
278
+ * When omitted, the SSH agent referenced by `SSH_AUTH_SOCK` is used instead.
279
+ * Exactly one of `privateKey` or a running SSH agent must be available.
280
+ */
281
+ privateKey?: string;
282
+ /** Maximum time in milliseconds to spend attempting reconnection before giving up. */
283
+ reconnectTimeout?: number;
284
+ /**
285
+ * Host key verification strategy.
286
+ * - `"accept-new"` — explicit TOFU opt-in: accept unknown keys and append them to `~/.ssh/known_hosts`.
287
+ * - `"yes"` — reject unknown keys; only connect when the key is already in `known_hosts`.
288
+ * - `"no"` — skip host key verification entirely.
289
+ *
290
+ * When omitted, Paratix now defaults to `"yes"`. To connect to a new host
291
+ * safely without TOFU, set `expectedHostFingerprint` or `expectedHostPublicKey`.
292
+ */
293
+ strictHostKeyChecking?: "accept-new" | "no" | "yes";
294
+ /** Password used for `sudo` escalation on the remote host. */
295
+ sudoPassword?: string;
296
+ /** Username to authenticate as. */
297
+ user: string;
298
+ };
299
+ /** Top-level definition of a server and the modules to run on it. */
300
+ type ServerDefinition = {
301
+ /** Server-level env values merged with global env before running modules. */
302
+ env?: Environment;
303
+ /** Hostname or IP address. */
304
+ host: string;
305
+ /** Display name for the server. */
306
+ name: string;
307
+ /** Ordered list of modules (or recipes) to apply. */
308
+ run: Module[];
309
+ /**
310
+ * Modules triggered as signals after the run completes with status `"changed"`.
311
+ * Typically used for service reloads or notifications.
312
+ */
313
+ signals?: Module[];
314
+ /** SSH connection parameters. */
315
+ ssh: SshConfig;
316
+ };
2
317
 
3
318
  /** Per-call overrides for package operations that can take a long time. */
4
319
  type UpgradeOptions = {
@@ -217,7 +532,7 @@ declare const archive: {
217
532
  * @param source - Path to the archive (remote path, or local path when upload is true).
218
533
  * @param destination - The destination directory on the remote host.
219
534
  * @param options - Optional settings.
220
- * @param options.owner - Run chown -R after extraction.
535
+ * @param options.owner - Set ownership on extracted archive members after extraction.
221
536
  * @param options.upload - Upload a local file to the remote host before extracting.
222
537
  * @returns A Module that manages the archive extraction.
223
538
  */
@@ -238,6 +553,11 @@ declare const command: {
238
553
  * with a shell expression that exits `0` when the desired state is already
239
554
  * present -- in that case the command is skipped.
240
555
  *
556
+ * Security: `cmd` and `options.check` are executed verbatim by the remote shell.
557
+ * Never interpolate untrusted input into these strings. NUL, CR, and LF are
558
+ * rejected up front because they can split or corrupt the line-based protocol
559
+ * between the orchestrator and the remote shell.
560
+ *
241
561
  * @param cmd - The shell command to execute.
242
562
  * @param options - Optional configuration for the command.
243
563
  * @param options.check - An optional shell expression used as the idempotency guard.
@@ -369,6 +689,16 @@ declare const compose: {
369
689
 
370
690
  /** Options for `cron.job`. */
371
691
  type CronJobOptions = {
692
+ /**
693
+ * R-0000697: opt-in to splicing the marker in front of an existing
694
+ * crontab line that exactly matches `job` when no marker is present.
695
+ * Without this flag, `state="present"` appends a fresh marker + job
696
+ * and never silently adopts an identical user-authored line. Set this
697
+ * to `true` only when knowingly recovering from a `cron.absent` on a
698
+ * legacy marker that left the original job line as an orphan
699
+ * (R-0000567/R-0000676). Defaults to `false`.
700
+ */
701
+ adoptOrphans?: boolean;
372
702
  /** The crontab line to manage (e.g. `"0 * * * * /usr/bin/backup"`). */
373
703
  job: string;
374
704
  /** Whether the job should be `"present"` or `"absent"`. Defaults to `"present"`. */
@@ -411,6 +741,27 @@ declare const cron: {
411
741
  * @param options - Job content and desired state.
412
742
  * @param options.job - The crontab line to manage (e.g. `"0 * * * * /usr/bin/backup"`).
413
743
  * @param options.state - Whether the job should be `"present"` or `"absent"`. Defaults to `"present"`.
744
+ * @param options.adoptOrphans - R-0000697: opt-in to splicing the marker
745
+ * in front of an existing crontab line that exactly matches `job` when
746
+ * no marker is present. Defaults to `false`. Set to `true` only when
747
+ * knowingly recovering from a `cron.absent` on a legacy marker.
748
+ *
749
+ * R-0000804: concurrency semantics.
750
+ *
751
+ * Each `cron.job` / `cron.absent` apply is serialised by the per-user
752
+ * mutex `crontab-<user>` (see `crontabMutexLockName`). All cron modules
753
+ * targeting the same user therefore share the same flag-lock directory:
754
+ * only one apply can hold the mutex at a time and writers never
755
+ * interleave their `crontab -u <user> -` calls.
756
+ *
757
+ * `check` does NOT take the mutex — it issues a plain `crontab -u <user>
758
+ * -l` and inspects the output, which is safe because cron's own crontab
759
+ * file is read atomically. As a result, `check` may briefly observe a
760
+ * snapshot that does not yet reflect a concurrent apply on the same
761
+ * user. The verdict in that case is `NEEDS_APPLY`, and the subsequent
762
+ * apply re-runs under the mutex against the current crontab state, so a
763
+ * stale `check` cannot cause a divergent write.
764
+ *
414
765
  * @returns A Module that manages the cron job entry.
415
766
  */
416
767
  job(user: string, name: string, options: CronJobOptions): Module;
@@ -424,6 +775,8 @@ type BaseDownloadOptions = {
424
775
  allowInsecureHttp?: boolean;
425
776
  /** Explicitly opt out of integrity verification for trusted sources. */
426
777
  allowUnverifiedDownload?: boolean;
778
+ /** Maximum time to establish the curl connection, in milliseconds. */
779
+ connectTimeout?: number;
427
780
  /** Group owner to set on the downloaded file via `chown`. */
428
781
  group?: string;
429
782
  /** File mode to set via `chmod` (e.g. `"0755"`). */
@@ -432,6 +785,8 @@ type BaseDownloadOptions = {
432
785
  owner?: string;
433
786
  /** Expected SHA-256 hex digest for integrity verification. */
434
787
  sha256?: string;
788
+ /** Maximum time for the full curl transfer, in milliseconds. */
789
+ timeout?: number;
435
790
  };
436
791
  /**
437
792
  * Modules for downloading files to remote servers via `curl`.
@@ -447,6 +802,13 @@ declare const download: {
447
802
  * Idempotency follows the same rules as {@link download.url}: SHA-256
448
803
  * comparison when a digest is given, otherwise file-existence check.
449
804
  *
805
+ * R-0000805: same caveat as `download.url` — `allowUnverifiedDownload`
806
+ * stores the post-download sha256 in a read-only sibling marker
807
+ * (`<destination>.sha256`, mode 0o444) to detect later tampering, but a
808
+ * root-equivalent attacker can replace both the payload and the marker
809
+ * together. Prefer providing an explicit `sha256` from the GitHub
810
+ * release notes whenever it is available.
811
+ *
450
812
  * @param destination - Absolute path on the remote server where the asset is saved.
451
813
  * @param options - Repository coordinates and optional download settings.
452
814
  * @param options.repo - GitHub repository in `owner/repo` format (e.g. `"hashicorp/terraform"`).
@@ -482,10 +844,13 @@ declare const download: {
482
844
  * @param url - The URL to download from.
483
845
  * @param options - Optional settings for ownership, permissions, and headers.
484
846
  * @param options.allowInsecureHttp - Allow unencrypted `http://` downloads explicitly.
847
+ * @param options.allowInsecureHttpHeaders - Allow sending sensitive headers over unencrypted `http://` explicitly.
848
+ * @param options.connectTimeout - Maximum time to establish the curl connection, in milliseconds.
485
849
  * @param options.group - Group owner to set on the downloaded file via `chown`.
486
850
  * @param options.mode - File mode to set via `chmod` (e.g. `"0755"`).
487
851
  * @param options.owner - User owner to set on the downloaded file via `chown`.
488
852
  * @param options.sha256 - Expected SHA-256 hex digest for integrity verification.
853
+ * @param options.timeout - Maximum time for the full curl transfer, in milliseconds.
489
854
  * @param options.allowUnverifiedDownload - Explicitly opt out of integrity verification.
490
855
  * @param options.headers - Additional HTTP headers sent with the curl request.
491
856
  * @returns A Module that manages the large file download.
@@ -493,8 +858,12 @@ declare const download: {
493
858
  large(destination: string, url: string, options?: {
494
859
  /** Allow unencrypted `http://` downloads explicitly. */
495
860
  allowInsecureHttp?: boolean;
861
+ /** Allow sending sensitive headers over unencrypted `http://` explicitly. */
862
+ allowInsecureHttpHeaders?: boolean;
496
863
  /** Explicitly opt out of integrity verification for trusted sources. */
497
864
  allowUnverifiedDownload?: boolean;
865
+ /** Maximum time to establish the curl connection, in milliseconds. */
866
+ connectTimeout?: number;
498
867
  /** Group owner to set on the downloaded file via `chown`. */
499
868
  group?: string;
500
869
  /** Additional HTTP headers sent with the curl request. */
@@ -505,6 +874,8 @@ declare const download: {
505
874
  owner?: string;
506
875
  /** Expected SHA-256 hex digest for integrity verification. */
507
876
  sha256?: string;
877
+ /** Maximum time for the full curl transfer, in milliseconds. */
878
+ timeout?: number;
508
879
  }): Module;
509
880
  /**
510
881
  * Download a file from a URL to the remote server via `curl -fsSL`.
@@ -513,15 +884,31 @@ declare const download: {
513
884
  * provided), file existence (when no digest is given), or skipped entirely
514
885
  * when `force` is `true`.
515
886
  *
887
+ * R-0000805: when `allowUnverifiedDownload: true` is set, paratix stores
888
+ * the sha256 of the downloaded payload in a sibling marker file
889
+ * `<destination>.sha256` (mode 0o444) and re-verifies the destination
890
+ * against the marker on subsequent runs. The marker is a tampering
891
+ * detector, not a tampering preventer: an attacker with write access to
892
+ * the destination directory and root privileges can swap both the
893
+ * payload and the marker simultaneously, and the next `check` will then
894
+ * conclude the file is "in sync". The read-only mode raises the bar for
895
+ * an unprivileged attacker but does not substitute for a verified
896
+ * `sha256` digest. Provide `sha256` whenever an authoritative digest is
897
+ * known.
898
+ *
516
899
  * @param destination - Absolute path on the remote server where the file is saved.
517
900
  * @param url - The URL to download from.
518
901
  * @param options - Optional settings for integrity, ownership, and headers.
902
+ * @param options.allowInsecureHttp - Allow unencrypted `http://` downloads explicitly.
903
+ * @param options.allowInsecureHttpHeaders - Allow sending sensitive headers over unencrypted `http://` explicitly.
519
904
  * @param options.allowUnverifiedDownload - Explicitly opt out of integrity verification.
520
905
  * @returns A Module that manages the file download.
521
906
  */
522
907
  url(destination: string, url: string, options?: {
523
908
  /** Allow unencrypted `http://` downloads explicitly. */
524
909
  allowInsecureHttp?: boolean;
910
+ /** Allow sending sensitive headers over unencrypted `http://` explicitly. */
911
+ allowInsecureHttpHeaders?: boolean;
525
912
  /** Explicitly opt out of integrity verification for trusted sources. */
526
913
  allowUnverifiedDownload?: boolean;
527
914
  /** Force re-download even if the file already exists. */
@@ -571,9 +958,19 @@ declare function assemble(remotePath: string, fragments: string[], options?: {
571
958
  * @returns A Module that ensures the block is present with the correct content.
572
959
  */
573
960
  declare function block(remotePath: string, options: BlockOptions): Module;
961
+ /** Desired settings passed by the caller. */
962
+ type PropertiesOptions = {
963
+ group?: string;
964
+ mode?: string;
965
+ owner?: string;
966
+ };
574
967
  /**
575
968
  * Set file or directory ownership and permissions on the remote host.
576
- * Only the attributes specified in `options` are checked and applied.
969
+ * Only the attributes specified in `options` are checked and applied. Drift
970
+ * is detected via `stat -c '%a %U %G'` so `apply` only invokes the relevant
971
+ * `chmod`/`chown`/`chgrp` for fields that actually differ from the desired
972
+ * state. When all desired fields already match, `apply` returns `status: "ok"`
973
+ * instead of falsely reporting a change.
577
974
  *
578
975
  * @param remotePath - Path to the file or directory on the remote host.
579
976
  * @param options - Attributes to enforce.
@@ -582,14 +979,14 @@ declare function block(remotePath: string, options: BlockOptions): Module;
582
979
  * @param options.owner - Optional owner name.
583
980
  * @returns A Module that ensures the properties match.
584
981
  */
585
- declare function properties(remotePath: string, options: {
586
- group?: string;
587
- mode?: string;
588
- owner?: string;
589
- }): Module;
982
+ declare function properties(remotePath: string, options: PropertiesOptions): Module;
590
983
  /**
591
984
  * Replace all occurrences of a regex pattern in a remote file.
592
- * `check` uses `grep -E` to detect whether the pattern still exists in the file.
985
+ * `check` reads the file, applies the same replacement that `apply` would
986
+ * perform, and reports `needs-apply` only when the resulting content differs
987
+ * from the current content. This makes the module idempotent for cases where
988
+ * the replacement string still matches the pattern (e.g. pattern `"foo"` and
989
+ * replacement `"foobar"`).
593
990
  * `apply` reads the file, performs the replacement in TypeScript and writes it back.
594
991
  *
595
992
  * @param remotePath - Path to the file on the remote host.
@@ -639,7 +1036,10 @@ declare const file: {
639
1036
  * @param remotePath - Destination path on the remote host.
640
1037
  * @param localPath - Source path on the local filesystem.
641
1038
  * @param options - Optional file attributes.
642
- * @param options.mode - Optional chmod mode string (e.g. `"0644"`).
1039
+ * @param options.mode - Optional chmod mode string (e.g. `"0644"`). When omitted,
1040
+ * the file is created with the documented default `"0644"`
1041
+ * (`"0644"`) instead of inheriting whatever default `ssh.uploadFile` happens
1042
+ * to choose for its temp file.
643
1043
  * @param options.owner - Optional chown owner string (e.g. `"www-data:www-data"`).
644
1044
  * @returns A Module that copies the file to the remote host.
645
1045
  */
@@ -666,7 +1066,7 @@ declare const file: {
666
1066
  * with the new `line` value instead of appending.
667
1067
  *
668
1068
  * @param remotePath - Path to the file on the remote host.
669
- * @param line - The exact line content to ensure is present.
1069
+ * @param line - The exact single-line content to ensure is present.
670
1070
  * @param options - Optional match configuration.
671
1071
  * @param options.match - A regex pattern; when matched, the line is replaced rather than appended.
672
1072
  * @returns A Module that ensures the line is present.
@@ -706,8 +1106,8 @@ declare const git: {
706
1106
  *
707
1107
  * If the destination directory does not yet contain a `.git` folder, the
708
1108
  * repository is cloned from scratch. If it already exists, the repository is
709
- * updated instead (fetch + checkout + reset). When no `ref` is specified, a
710
- * plain `git pull` is performed on an existing clone.
1109
+ * updated instead (fetch + checkout + reset). When no `ref` is specified,
1110
+ * the existing clone is reset to the current remote default branch HEAD.
711
1111
  *
712
1112
  * @param repo - The repository URL to clone.
713
1113
  * @param destination - The destination path on the remote host.
@@ -732,7 +1132,9 @@ declare const group: {
732
1132
  */
733
1133
  absent(name: string): Module;
734
1134
  /**
735
- * Ensure a group exists. Creates it via `groupadd` if absent.
1135
+ * Ensure a group exists. Creates it via `groupadd` if absent. When the
1136
+ * group already exists but its GID differs from `options.gid`, the GID
1137
+ * is healed via `groupmod -g <gid>` so the drift becomes recoverable.
736
1138
  *
737
1139
  * @param name - The group name.
738
1140
  * @param options - Optional group configuration.
@@ -783,11 +1185,10 @@ declare const mount: {
783
1185
  * Ensure a filesystem is mounted at the given path. Creates the mountpoint
784
1186
  * directory if it does not exist. Optionally persists the mount in `/etc/fstab`.
785
1187
  *
786
- * The check phase verifies that the mountpoint is active (via `findmnt`) and,
787
- * when `persist` is `true`, that the fstab entry matches the desired line
788
- * exactly. It does **not** compare the currently mounted source, filesystem
789
- * type, or options against the desired values — a remount is only triggered
790
- * when the mountpoint is absent entirely.
1188
+ * The check phase verifies that the mountpoint is active (via `findmnt`), that
1189
+ * its live source / filesystem type / normalized options match the desired
1190
+ * values, and, when `persist` is `true`, that the fstab entry matches the
1191
+ * desired line exactly.
791
1192
  *
792
1193
  * @param options - Configuration for the mount.
793
1194
  * @param options.fstype - The filesystem type (e.g. `"ext4"`, `"tmpfs"`, `"nfs"`).
@@ -858,17 +1259,23 @@ declare const net: {
858
1259
  *
859
1260
  * @param url - The URL to request.
860
1261
  * @param options - Optional request settings.
1262
+ * @param options.allowInsecureHttpHeaders - When `true`, allow sending sensitive headers (e.g. `Authorization`, `Cookie`) over plaintext `http://`. Default `false` rejects such combinations to prevent credential leakage.
861
1263
  * @param options.body - Expected string in the response body.
1264
+ * @param options.connectTimeout - Maximum time to establish the curl connection, in milliseconds.
862
1265
  * @param options.headers - Additional HTTP headers.
863
1266
  * @param options.method - HTTP method (default: `"GET"`).
864
1267
  * @param options.status - Expected HTTP status code (default: `200`).
1268
+ * @param options.timeout - Maximum time for the full curl request, in milliseconds.
865
1269
  * @returns A Module that checks the HTTP endpoint.
866
1270
  */
867
1271
  request(url: string, options?: {
1272
+ allowInsecureHttpHeaders?: boolean;
868
1273
  body?: string;
1274
+ connectTimeout?: number;
869
1275
  headers?: Record<string, string>;
870
1276
  method?: string;
871
1277
  status?: number;
1278
+ timeout?: number;
872
1279
  }): Module;
873
1280
  /**
874
1281
  * Manage /etc/resolv.conf (nameservers and search domains).
@@ -912,7 +1319,7 @@ declare const op: {
912
1319
  /**
913
1320
  * Resolve 1Password secret references into environment values.
914
1321
  *
915
- * Regular references are resolved in bulk via `op inject`.
1322
+ * Regular references are resolved via `op read`.
916
1323
  * References ending in `/one-time-password` or `/otp` are resolved individually
917
1324
  * via `op read` and returned as lazy functions that compute a fresh TOTP code
918
1325
  * on each call.
@@ -1040,6 +1447,28 @@ declare const quadlet: {
1040
1447
  updateImage(options: QuadletImageUpdateOptions): Module;
1041
1448
  };
1042
1449
 
1450
+ /**
1451
+ * Shared helper for the `resolveHost` callback used by reboot-style modules
1452
+ * (`system.reboot`, `releaseUpgrade.upgrade`). Wraps the caller-supplied
1453
+ * resolver in a wall-clock timeout so a hanging DNS/cloud lookup cannot
1454
+ * stall the entire playbook indefinitely.
1455
+ *
1456
+ * R-0000243: previously the resolver was awaited unconditionally — a stuck
1457
+ * cloud-metadata or DNS request would keep the module pending forever
1458
+ * because the runner has no inherent timeout for module callbacks.
1459
+ */
1460
+
1461
+ /**
1462
+ * R-0000575: callable shape for `resolveHost`. The optional `AbortSignal`
1463
+ * argument lets callers like `resolveHostWithTimeout` signal cancellation
1464
+ * when the wall-clock timeout elapses, so a long-running DNS/cloud lookup
1465
+ * can drop its in-flight work instead of running to completion in the
1466
+ * background. The argument is optional to keep existing zero-arg callbacks
1467
+ * source-compatible — callers that don't care can keep their current
1468
+ * signature.
1469
+ */
1470
+ type ResolveHostCallback = (signal?: AbortSignal) => Promise<string>;
1471
+
1043
1472
  /**
1044
1473
  * Options for the {@link releaseUpgrade.upgrade} module.
1045
1474
  */
@@ -1054,8 +1483,20 @@ type ReleaseUpgradeOptions = {
1054
1483
  * post-upgrade reboot. Useful when the server's IP address may change
1055
1484
  * (e.g. DHCP or cloud environments). The resolved value is emitted as
1056
1485
  * `system.host` meta so the runner can reconnect to the correct address.
1486
+ *
1487
+ * R-0000575: the callback receives an `AbortSignal` that fires when the
1488
+ * configured timeout elapses. Honoring the signal lets DNS/cloud lookups
1489
+ * abort their in-flight work promptly.
1490
+ */
1491
+ resolveHost?: ResolveHostCallback;
1492
+ /**
1493
+ * Wall-clock timeout (ms) applied to {@link ReleaseUpgradeOptions.resolveHost}.
1494
+ * Defaults to 30 seconds (R-0000243) so a hanging DNS/cloud lookup cannot
1495
+ * stall the playbook indefinitely.
1057
1496
  */
1058
- resolveHost?: () => Promise<string>;
1497
+ resolveHostTimeoutMs?: number;
1498
+ /** Override the per-step command timeout (ms). Default: 30 minutes. */
1499
+ timeout?: number;
1059
1500
  };
1060
1501
  /**
1061
1502
  * Modules for upgrading the operating system to the next major release.
@@ -1130,6 +1571,8 @@ type SyncOptions = {
1130
1571
  * (not recommended for production).
1131
1572
  */
1132
1573
  strictHostKeyChecking?: "accept-new" | "no" | "off" | "yes";
1574
+ /** Maximum runtime for a single rsync process in milliseconds. */
1575
+ timeout?: number;
1133
1576
  };
1134
1577
  /**
1135
1578
  * Modules for synchronizing files to a remote host using rsync.
@@ -1246,7 +1689,12 @@ type KnownHostsOptions = {
1246
1689
  expectedFingerprint?: string;
1247
1690
  port?: number;
1248
1691
  publicKey?: string;
1249
- state?: "absent" | "present";
1692
+ state?: KnownHostsState;
1693
+ };
1694
+ type KnownHostsState = "absent" | "present";
1695
+ type AuthorizedKeysState = "absent" | "present";
1696
+ type AuthorizedKeysOptions = {
1697
+ state?: AuthorizedKeysState;
1250
1698
  };
1251
1699
  /**
1252
1700
  * Modules for managing SSH client-side resources such as known hosts
@@ -1266,14 +1714,12 @@ declare const ssh: {
1266
1714
  * @param options.state - Whether the key should be `"present"` or `"absent"`. Defaults to `"present"`.
1267
1715
  * @returns A Module that manages the authorized key entry.
1268
1716
  */
1269
- authorizedKeys(user: string, key: string, options?: {
1270
- state?: "absent" | "present";
1271
- }): Module;
1717
+ authorizedKeys(user: string, key: string, options?: AuthorizedKeysOptions): Module;
1272
1718
  /**
1273
1719
  * Ensure a host is present in (or absent from) the connecting user's `~/.ssh/known_hosts`.
1274
1720
  *
1275
1721
  * When `state` is `"present"` (the default), the host's public keys are fetched
1276
- * via `ssh-keyscan` and appended to `~/.ssh/known_hosts`. When `state` is
1722
+ * via `ssh-keyscan` and written to `~/.ssh/known_hosts`. When `state` is
1277
1723
  * `"absent"`, the host entry is removed via `ssh-keygen -R`.
1278
1724
  *
1279
1725
  * @param host - The hostname or IP address to manage.
@@ -1310,6 +1756,61 @@ declare const sshd: {
1310
1756
  port(targetPort: number): Module;
1311
1757
  };
1312
1758
 
1759
+ /**
1760
+ * Modules for managing swap files and common swap-related kernel tuning.
1761
+ */
1762
+ declare const swap: {
1763
+ /**
1764
+ * Ensure a file-backed swap area exists, is activated, and is persisted in `/etc/fstab`.
1765
+ *
1766
+ * @param options - Configuration for the swap file.
1767
+ * @param options.mode - File mode applied to the swap file. Defaults to `0600`.
1768
+ * @param options.path - Absolute path to the swap file, e.g. `/swapfile`.
1769
+ * @param options.priority - Optional swap priority written into the fstab entry.
1770
+ * @param options.size - Desired file size as bytes or a shell-friendly size string such as `2G`.
1771
+ * @param options.state - Whether the swap file should be `present` (default) or `absent`.
1772
+ * @returns A Module that manages the swap file lifecycle.
1773
+ */
1774
+ file(options: {
1775
+ mode?: string;
1776
+ path: string;
1777
+ priority?: number;
1778
+ size: number | string;
1779
+ state?: "absent" | "present";
1780
+ }): Module;
1781
+ /**
1782
+ * Persist `vm.swappiness`.
1783
+ *
1784
+ * @param value - Desired swappiness value.
1785
+ * @returns A Module that manages `vm.swappiness`.
1786
+ */
1787
+ swappiness(value: number): Module;
1788
+ /**
1789
+ * Persist `vm.vfs_cache_pressure`.
1790
+ *
1791
+ * @param value - Desired VFS cache pressure value.
1792
+ * @returns A Module that manages `vm.vfs_cache_pressure`.
1793
+ */
1794
+ vfsCachePressure(value: number): Module;
1795
+ };
1796
+
1797
+ /**
1798
+ * Options for {@link sysctl.set}.
1799
+ */
1800
+ type SysctlSetOptions = {
1801
+ /**
1802
+ * When `state` is `"absent"`, optionally restore this live runtime value
1803
+ * after removing the persistence file. Without `resetValue`, only the
1804
+ * persistence file is removed and the live kernel value remains unchanged
1805
+ * until the next reboot.
1806
+ *
1807
+ * Use this for security-relevant parameters (e.g. resetting
1808
+ * `net.ipv4.ip_forward` to `"0"`) where leaving the live value in place
1809
+ * would silently violate the desired absent state.
1810
+ */
1811
+ resetValue?: string;
1812
+ state?: "absent" | "present";
1813
+ };
1313
1814
  /**
1314
1815
  * Modules for managing kernel parameters via sysctl on the remote host.
1315
1816
  */
@@ -1318,21 +1819,24 @@ declare const sysctl: {
1318
1819
  * Set a sysctl kernel parameter and persist it across reboots.
1319
1820
  *
1320
1821
  * The live value is applied immediately via `sysctl -w` and a configuration
1321
- * file is written to `/etc/sysctl.d/99-paratix-<sanitized-key>.conf` for
1322
- * persistence.
1822
+ * file is written to `/etc/sysctl.d/99-paratix-<sanitized-key>-<hash>.conf`
1823
+ * for persistence.
1323
1824
  *
1324
- * When `state` is `"absent"`, the persistence file is removed but the live
1325
- * value is not reverted (a reboot will restore the default).
1825
+ * When `state` is `"absent"`, the persistence file is removed. By default
1826
+ * the live value is not reverted (a reboot will restore the default). Pass
1827
+ * `resetValue` to additionally write the desired runtime value back to the
1828
+ * kernel via `sysctl -w` so the absent state converges on the live system
1829
+ * as well.
1326
1830
  *
1327
1831
  * @param key - The sysctl key (e.g. "net.ipv4.ip_forward").
1328
1832
  * @param value - The desired value (e.g. "1").
1329
1833
  * @param options - Optional settings.
1330
1834
  * @param options.state - Whether the parameter should be "present" (default) or "absent".
1835
+ * @param options.resetValue - Live runtime value to restore when `state` is `"absent"`.
1836
+ * Ignored when `state` is `"present"`.
1331
1837
  * @returns A Module that manages the sysctl parameter.
1332
1838
  */
1333
- set(key: string, value: string, options?: {
1334
- state?: "absent" | "present";
1335
- }): Module;
1839
+ set(key: string, value: string, options?: SysctlSetOptions): Module;
1336
1840
  };
1337
1841
 
1338
1842
  /**
@@ -1342,8 +1846,19 @@ type RebootOptions = {
1342
1846
  /**
1343
1847
  * Optional async function to resolve the new host address after a reboot.
1344
1848
  * Useful when the server's IP address may change (e.g. DHCP or cloud environments).
1849
+ *
1850
+ * R-0000575: the callback receives an `AbortSignal` that fires when the
1851
+ * configured timeout elapses. Honoring the signal lets DNS/cloud lookups
1852
+ * abort their in-flight work promptly.
1853
+ */
1854
+ resolveHost?: ResolveHostCallback;
1855
+ /**
1856
+ * Wall-clock timeout (ms) applied to {@link RebootOptions.resolveHost}.
1857
+ * Defaults to 30 seconds. Mirrors R-0000243 in
1858
+ * {@link import("./releaseUpgrade.js")} so a stuck resolver cannot stall
1859
+ * the runner indefinitely.
1345
1860
  */
1346
- resolveHost?: () => Promise<string>;
1861
+ resolveHostTimeoutMs?: number;
1347
1862
  };
1348
1863
  /**
1349
1864
  * Modules for managing system-level operations.
@@ -1421,6 +1936,74 @@ declare const systemd: {
1421
1936
  unmasked(name: string): Module;
1422
1937
  };
1423
1938
 
1939
+ /** Options for `timer.scheduled`. */
1940
+ type TimerScheduledOptions = {
1941
+ /** Optional `AccuracySec=` for the `[Timer]` section. */
1942
+ accuracySec?: number | string;
1943
+ /** Description used in both unit `[Unit]` sections. Defaults to `Paratix scheduled task: <name>`. */
1944
+ description?: string;
1945
+ /** Extra environment variables rendered as `Environment=KEY=VAL` lines in `[Service]`. */
1946
+ environment?: Record<string, string>;
1947
+ /** The single command line written as `ExecStart=` in the generated `.service`. */
1948
+ exec: string;
1949
+ /** Optional `Group=` for the `[Service]` section. */
1950
+ group?: string;
1951
+ /** Calendar specification(s) written as one or more `OnCalendar=` lines. */
1952
+ onCalendar: string | string[];
1953
+ /** Whether `Persistent=true` is written into the `[Timer]` section. Defaults to `true`. */
1954
+ persistent?: boolean;
1955
+ /** Optional `RandomizedDelaySec=` for the `[Timer]` section. */
1956
+ randomizedDelaySec?: number | string;
1957
+ /** Whether the timer should be `"present"` or `"absent"`. Defaults to `"present"`. */
1958
+ state?: "absent" | "present";
1959
+ /** Optional `User=` for the `[Service]` section. */
1960
+ user?: string;
1961
+ /** Optional `WorkingDirectory=` for the `[Service]` section. */
1962
+ workingDirectory?: string;
1963
+ };
1964
+
1965
+ declare const timer: {
1966
+ /**
1967
+ * Ensure a systemd timer-driven scheduled task does not exist.
1968
+ *
1969
+ * Disables and stops `<name>.timer`, removes both `<name>.service` and
1970
+ * `<name>.timer` from `/etc/systemd/system/`, and reloads systemd. The
1971
+ * `disable --now` step also removes the timer's `wants/` symlink. Failure
1972
+ * to disable a unit that does not exist is ignored, so this method is
1973
+ * safe to apply repeatedly.
1974
+ *
1975
+ * Behaves like `timer.scheduled(name, { exec: "<unused>", onCalendar: "<unused>", state: "absent" })`,
1976
+ * but does not require placeholder values for `exec` or `onCalendar` and
1977
+ * reports failures with a `timer.absent` prefix instead of `timer.scheduled`.
1978
+ *
1979
+ * @param name - Base unit name without extension. Must match
1980
+ * `^[A-Za-z0-9_\-]+$`.
1981
+ * @returns A Module that ensures the timer-driven scheduled task is absent.
1982
+ */
1983
+ absent(name: string): Module;
1984
+ /**
1985
+ * Ensure a systemd timer-driven scheduled task is present (or absent).
1986
+ *
1987
+ * Generates `<name>.service` (`Type=oneshot`, no `[Install]` section since
1988
+ * it is triggered exclusively by the timer) and `<name>.timer` under
1989
+ * `/etc/systemd/system/`, reloads systemd, and runs
1990
+ * `systemctl enable --now <name>.timer`. When the timer unit content
1991
+ * changed, the timer is restarted so a new `OnCalendar=` schedule is picked
1992
+ * up immediately. With `state: "absent"`, the timer is disabled and
1993
+ * stopped, both unit files are removed, and systemd is reloaded.
1994
+ *
1995
+ * Validation of `exec`, `description`, `user`, `group`, `workingDirectory`,
1996
+ * `environment` and `onCalendar` only runs when `state` is `"present"`,
1997
+ * so callers can pass placeholder values when removing a timer.
1998
+ *
1999
+ * @param name - Base unit name without extension. Used as `<name>.service`
2000
+ * and `<name>.timer`. Must match `^[A-Za-z0-9_\-]+$`.
2001
+ * @param options - Schedule, command, optional service hardening, and state.
2002
+ * @returns A Module that manages the timer-driven scheduled task.
2003
+ */
2004
+ scheduled(name: string, options: TimerScheduledOptions): Module;
2005
+ };
2006
+
1424
2007
  /**
1425
2008
  * Modules for managing the UFW (Uncomplicated Firewall) on Debian/Ubuntu hosts.
1426
2009
  */
@@ -1451,6 +2034,7 @@ declare const ufw: {
1451
2034
  type UserOptions = {
1452
2035
  groups?: string[];
1453
2036
  home?: string;
2037
+ homeMode?: string;
1454
2038
  password?: string;
1455
2039
  shell?: string;
1456
2040
  uid?: number;
@@ -1474,16 +2058,33 @@ declare const user: {
1474
2058
  * Ensure a user account exists. Creates the account if absent, or runs
1475
2059
  * `usermod` to update attributes if the user already exists.
1476
2060
  *
2061
+ * Supplementary group membership is additive: when `options.groups` is set
2062
+ * and the user already exists, `usermod --append --groups <list>` is used so
2063
+ * preexisting memberships not managed by Paratix (e.g. `sudo`, `docker`,
2064
+ * manually added groups) are preserved across re-applies. The `groups`
2065
+ * option therefore expresses "ensure the user is a member of these groups",
2066
+ * not "the user must be a member of exactly these supplementary groups".
2067
+ *
2068
+ * When `home` is provided, `usermod --move-home` migrates the existing
2069
+ * contents to the new path (instead of leaving the user pointing at an
2070
+ * empty directory with the old contents stranded on disk). The home
2071
+ * directory's permission bits are then enforced via `chmod`; the default
2072
+ * mode is `0700` so dot-files in a freshly created home cannot be read
2073
+ * by other local accounts even on hosts where `/etc/login.defs` sets
2074
+ * `HOME_MODE=0755`.
2075
+ *
1477
2076
  * @param name - The username.
1478
2077
  * @param options - Optional user account configuration.
1479
2078
  * @param options.uid - Desired numeric UID.
1480
2079
  * @param options.shell - Login shell path (e.g. `"/bin/bash"`).
1481
2080
  * @param options.home - Home directory path.
1482
- * @param options.groups - Supplementary groups to add the user to.
2081
+ * @param options.homeMode - Octal permission bits for the home directory
2082
+ * (e.g. `"0700"`, `"750"`). Requires `home`. Defaults to `"0700"`.
2083
+ * @param options.groups - Supplementary groups to add the user to (additive).
1483
2084
  * @param options.password - Pre-hashed password (e.g. SHA-512 `$6$...`) set via `chpasswd -e`.
1484
2085
  * @returns A Module that ensures the user account is present.
1485
2086
  */
1486
2087
  present(name: string, options?: UserOptions): Module;
1487
2088
  };
1488
2089
 
1489
- export { type UpgradeOptions as U, apt as a, archive as b, command as c, compose as d, cron as e, download as f, file as g, git as h, group as i, hostname as j, rsync as k, service as l, mount as m, net as n, op as o, pkg as p, quadlet as q, releaseUpgrade as r, script as s, ssh as t, sshd as u, sysctl as v, system as w, systemd as x, ufw as y, user as z };
2090
+ export { op as A, pkg as B, quadlet as C, releaseUpgrade as D, type Environment as E, rsync as F, script as G, service as H, ssh as I, sshd as J, swap as K, sysctl as L, type Module as M, NEEDS_APPLY as N, type OrchestrationStep as O, system as P, systemd as Q, timer as R, type SshdPortMetaEntry as S, ufw as T, user as U, type UpgradeOptions as V, type ModuleMetaEntry as a, type MetaEnvironmentValue as b, type EnvironmentMetaEntry as c, type SystemHostMetaEntry as d, type SystemRebootMetaEntry as e, type ModuleResult as f, type ExecResult as g, type ModuleStatus as h, type SshConnection as i, type ShutdownSignal as j, type ServerDefinition as k, type EnvironmentValue as l, type ExecOptions as m, type SshConfig as n, apt as o, archive as p, command as q, compose as r, cron as s, download as t, file as u, git as v, group as w, hostname as x, mount as y, net as z };