@serve.zone/pallet-bundle 35.3.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 (40) hide show
  1. package/dist_ts_bundle/classes.controlprocess.d.ts +71 -0
  2. package/dist_ts_bundle/classes.controlprocess.js +441 -0
  3. package/dist_ts_bundle/classes.controlstderr.d.ts +36 -0
  4. package/dist_ts_bundle/classes.controlstderr.js +95 -0
  5. package/dist_ts_bundle/classes.releaseclient.d.ts +38 -0
  6. package/dist_ts_bundle/classes.releaseclient.js +285 -0
  7. package/dist_ts_bundle/errors.d.ts +35 -0
  8. package/dist_ts_bundle/errors.js +20 -0
  9. package/dist_ts_bundle/index.d.ts +10 -0
  10. package/dist_ts_bundle/index.js +11 -0
  11. package/dist_ts_bundle/inventory.d.ts +90 -0
  12. package/dist_ts_bundle/inventory.js +78 -0
  13. package/dist_ts_bundle/paths.d.ts +12 -0
  14. package/dist_ts_bundle/paths.js +76 -0
  15. package/dist_ts_bundle/plugins.d.ts +14 -0
  16. package/dist_ts_bundle/plugins.js +19 -0
  17. package/dist_ts_bundle/protocol.d.ts +48 -0
  18. package/dist_ts_bundle/protocol.js +47 -0
  19. package/dist_ts_bundle/units.d.ts +67 -0
  20. package/dist_ts_bundle/units.js +128 -0
  21. package/dist_ts_bundle/verify.d.ts +75 -0
  22. package/dist_ts_bundle/verify.js +263 -0
  23. package/dist_ts_bundle/version.d.ts +7 -0
  24. package/dist_ts_bundle/version.js +17 -0
  25. package/license.md +21 -0
  26. package/package.json +35 -0
  27. package/readme.md +176 -0
  28. package/ts_bundle/classes.controlprocess.ts +453 -0
  29. package/ts_bundle/classes.controlstderr.ts +92 -0
  30. package/ts_bundle/classes.releaseclient.ts +288 -0
  31. package/ts_bundle/errors.ts +40 -0
  32. package/ts_bundle/index.ts +10 -0
  33. package/ts_bundle/inventory.ts +104 -0
  34. package/ts_bundle/paths.ts +74 -0
  35. package/ts_bundle/plugins.ts +25 -0
  36. package/ts_bundle/protocol.ts +56 -0
  37. package/ts_bundle/readme.md +176 -0
  38. package/ts_bundle/units.ts +165 -0
  39. package/ts_bundle/verify.ts +353 -0
  40. package/ts_bundle/version.ts +18 -0
@@ -0,0 +1,78 @@
1
+ import * as plugins from './plugins.js';
2
+ /**
3
+ * What a Pallet control bundle is made of, stated once.
4
+ *
5
+ * Pallet's own build (`scripts/build-control.mjs`) writes its control record with these paths and
6
+ * keys, and its packaging (`scripts/control-package.mjs`) runs this package's verifier over every
7
+ * build before sealing it, so a bundle that disagrees with this description is never released. The
8
+ * files of each component (clock, DNS, VPN, containerd, notices and sources) are not listed here:
9
+ * the bundle states them itself in its control record and in the manifests of those components,
10
+ * and the verifier checks every file against them.
11
+ */
12
+ /** The tspack bundle name, the package that builds it and the Gitea repository that releases it. */
13
+ export const palletControlBundleName = 'pallet-control';
14
+ export const palletControlPackageName = '@serve.zone/pallet';
15
+ export const palletControlRepository = 'serve.zone/pallet';
16
+ /** The platforms a release carries, as tspack bundle ids. */
17
+ export const palletControlTargets = ['linux-amd64', 'linux-arm64'];
18
+ export const isPalletControlTarget = (valueArg) => palletControlTargets.some((target) => target === valueArg);
19
+ /** The tsrust target every native executable of a bundle was built for. */
20
+ export const palletNativeTarget = (targetArg) => `${targetArg.replace('-', '_')}_musl`;
21
+ /** The fixed host paths a control build compiles in; its control record repeats them. */
22
+ export const palletControlPaths = Object.freeze({
23
+ /** The node's store, created only by explicit provisioning. */
24
+ dataRoot: '/var/lib/serve.zone/pallet',
25
+ /** The Cloudly enrollment control socket (`enrollment-serve`, `enrollment-provision`). */
26
+ socketPath: plugins.interfaces.data.palletNodeEnrollmentContract.socketPath,
27
+ /** The local controller socket a node bound to a controller on its own host serves. */
28
+ localControllerSocketPath: plugins.interfaces.data.nodeRuntimeLocalControllerContract.socketPath,
29
+ /** The CRI socket of Pallet's own containerd, never the host's shared one. */
30
+ runtimeSocketPath: '/run/pallet/containerd/containerd.sock',
31
+ /** The uid every Pallet process and every installed file belongs to. */
32
+ expectedUid: 0,
33
+ });
34
+ /** Every key of a bundle's `control-build.json`, and nothing else. */
35
+ export const palletControlRecordKeys = Object.freeze([
36
+ 'packageName', 'version', 'sourceCommit', 'sourceDirty', 'target', 'compiler', 'lockSha256', 'dataRoot',
37
+ 'socketPath', 'runtimeSocketPath', 'expectedUid', 'clockManifestSha256', 'dnsManifestSha256',
38
+ 'vpnInventorySha256', 'containerdManifestSha256', 'files',
39
+ ]);
40
+ export const palletControlRecordName = 'control-build.json';
41
+ /** The executables `pallet-control` starts by name, each verified against the digest it compiles in. */
42
+ export const palletControlRoles = Object.freeze({
43
+ control: { path: 'pallet-control' },
44
+ store: { path: 'pallet-smartdb', provenance: { path: 'pallet-smartdb.tsrust-build.json',
45
+ projectName: '@lossless.org/nosqldb', binary: 'rustdb' } },
46
+ runtime: { path: 'pallet-runtime', provenance: { path: 'pallet-runtime.tsrust-build.json',
47
+ projectName: palletControlPackageName, binary: 'pallet' } },
48
+ guard: { path: 'pallet-guard', provenance: { path: 'pallet-guard.tsrust-build.json',
49
+ projectName: '@push.rocks/smartnftables', binary: 'smartnftables' } },
50
+ dns: { path: 'pallet-dns', provenance: { path: 'pallet-dns.tsrust-build.json',
51
+ projectName: '@push.rocks/smartdns', binary: 'rustdns' } },
52
+ vpn: { path: 'pallet-vpn', provenance: { path: 'pallet-vpn.tsrust-build.json',
53
+ projectName: '@push.rocks/smartvpn', binary: 'smartvpn_daemon' } },
54
+ });
55
+ /**
56
+ * The components whose files a manifest inside the bundle lists, and the control record key that
57
+ * pins that manifest's digest. `listing` components state every file below `directory` by path,
58
+ * size, SHA-256 and mode; the others are pinned by digest only and their files are declared in the
59
+ * control record.
60
+ */
61
+ export const palletControlComponents = Object.freeze({
62
+ clock: { manifest: 'pallet-clock/manifest.json', recordKey: 'clockManifestSha256', directory: 'pallet-clock/' },
63
+ containerd: { manifest: 'pallet-containerd/manifest.json', recordKey: 'containerdManifestSha256',
64
+ directory: 'pallet-containerd/' },
65
+ dns: { manifest: 'notices/coredns/manifest.json', recordKey: 'dnsManifestSha256', directory: null },
66
+ vpn: { manifest: 'notices/smartvpn/notices/inventory.json', recordKey: 'vpnInventorySha256', directory: null },
67
+ });
68
+ /** Notice trees in the `tsrust.native-notices` format: a manifest naming every file below it. */
69
+ export const palletControlNoticeTrees = Object.freeze(['native-notices/', 'notices/smartnftables/']);
70
+ /**
71
+ * Notice and corresponding-source inventories: a manifest whose `files` list every file below both
72
+ * prefixes by path, size and SHA-256.
73
+ */
74
+ export const palletControlSourceInventories = Object.freeze([
75
+ { manifest: 'notices/clock/manifest.json', prefixes: ['notices/clock/', 'sources/clock/'] },
76
+ { manifest: 'notices/containerd/manifest.json', prefixes: ['notices/containerd/', 'sources/containerd/'] },
77
+ ]);
78
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW52ZW50b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfYnVuZGxlL2ludmVudG9yeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4Qzs7Ozs7Ozs7O0dBU0c7QUFFSCxvR0FBb0c7QUFDcEcsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsZ0JBQWdCLENBQUM7QUFDeEQsTUFBTSxDQUFDLE1BQU0sd0JBQXdCLEdBQUcsb0JBQW9CLENBQUM7QUFDN0QsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsbUJBQW1CLENBQUM7QUFFM0QsNkRBQTZEO0FBQzdELE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHLENBQUMsYUFBYSxFQUFFLGFBQWEsQ0FBVSxDQUFDO0FBRzVFLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLENBQUMsUUFBaUIsRUFBb0MsRUFBRSxDQUMzRixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUMsQ0FBQztBQUU3RCwyRUFBMkU7QUFDM0UsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxTQUErQixFQUFVLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxPQUFPLENBQUM7QUFFckgseUZBQXlGO0FBQ3pGLE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDOUMsK0RBQStEO0lBQy9ELFFBQVEsRUFBRSw0QkFBNEI7SUFDdEMsMEZBQTBGO0lBQzFGLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxVQUFVO0lBQzNFLHVGQUF1RjtJQUN2Rix5QkFBeUIsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQyxVQUFVO0lBQ2hHLDhFQUE4RTtJQUM5RSxpQkFBaUIsRUFBRSx3Q0FBd0M7SUFDM0Qsd0VBQXdFO0lBQ3hFLFdBQVcsRUFBRSxDQUFDO0NBQ2YsQ0FBQyxDQUFDO0FBRUgsc0VBQXNFO0FBQ3RFLE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDbkQsYUFBYSxFQUFFLFNBQVMsRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFVBQVU7SUFDdkcsWUFBWSxFQUFFLG1CQUFtQixFQUFFLGFBQWEsRUFBRSxxQkFBcUIsRUFBRSxtQkFBbUI7SUFDNUYsb0JBQW9CLEVBQUUsMEJBQTBCLEVBQUUsT0FBTztDQUNqRCxDQUFDLENBQUM7QUFFWixNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxvQkFBb0IsQ0FBQztBQWU1RCx3R0FBd0c7QUFDeEcsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQXdFLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDbkgsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFO0lBQ25DLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxVQUFVLEVBQUUsRUFBRSxJQUFJLEVBQUUsa0NBQWtDO1lBQ3JGLFdBQVcsRUFBRSx1QkFBdUIsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEVBQUU7SUFDNUQsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSxrQ0FBa0M7WUFDdkYsV0FBVyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsRUFBRTtJQUM3RCxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsY0FBYyxFQUFFLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSxnQ0FBZ0M7WUFDakYsV0FBVyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sRUFBRSxlQUFlLEVBQUUsRUFBRTtJQUN2RSxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSw4QkFBOEI7WUFDM0UsV0FBVyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsRUFBRTtJQUM1RCxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSw4QkFBOEI7WUFDM0UsV0FBVyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxFQUFFO0NBQ3JFLENBQUMsQ0FBQztBQUVIOzs7OztHQUtHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNuRCxLQUFLLEVBQUUsRUFBRSxRQUFRLEVBQUUsNEJBQTRCLEVBQUUsU0FBUyxFQUFFLHFCQUFxQixFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUU7SUFDL0csVUFBVSxFQUFFLEVBQUUsUUFBUSxFQUFFLGlDQUFpQyxFQUFFLFNBQVMsRUFBRSwwQkFBMEI7UUFDOUYsU0FBUyxFQUFFLG9CQUFvQixFQUFFO0lBQ25DLEdBQUcsRUFBRSxFQUFFLFFBQVEsRUFBRSwrQkFBK0IsRUFBRSxTQUFTLEVBQUUsbUJBQW1CLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRTtJQUNuRyxHQUFHLEVBQUUsRUFBRSxRQUFRLEVBQUUseUNBQXlDLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUU7Q0FDdEcsQ0FBQyxDQUFDO0FBRVosaUdBQWlHO0FBQ2pHLE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSx3QkFBd0IsQ0FBVSxDQUFDLENBQUM7QUFFOUc7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUMxRCxFQUFFLFFBQVEsRUFBRSw2QkFBNkIsRUFBRSxRQUFRLEVBQUUsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxFQUFFO0lBQzNGLEVBQUUsUUFBUSxFQUFFLGtDQUFrQyxFQUFFLFFBQVEsRUFBRSxDQUFDLHFCQUFxQixFQUFFLHFCQUFxQixDQUFDLEVBQUU7Q0FDbEcsQ0FBQyxDQUFDIn0=
@@ -0,0 +1,12 @@
1
+ /** An absolute, normalized path without a trailing slash; `/` itself is refused. */
2
+ export declare function canonicalPath(valueArg: unknown): string;
3
+ /** No symlink ancestor, foreign owner or group/other writer can replace the protected leaf. */
4
+ export declare function checkAncestors(pathArg: string, uidArg: number): Promise<void>;
5
+ /**
6
+ * Proves the executable at a protected path carries the digest trusted metadata states. The file is
7
+ * read through one descriptor opened without following links, and its identity must not change
8
+ * while it is read.
9
+ */
10
+ export declare function verifyExecutable(pathArg: string, digestArg: string, uidArg: number, signalArg?: AbortSignal): Promise<void>;
11
+ /** A directory that is canonical (its real path is itself) and a directory. */
12
+ export declare function requireCanonicalDirectory(pathArg: string): Promise<void>;
@@ -0,0 +1,76 @@
1
+ import * as plugins from './plugins.js';
2
+ import { PalletBundleError } from './errors.js';
3
+ /** An absolute, normalized path without a trailing slash; `/` itself is refused. */
4
+ export function canonicalPath(valueArg) {
5
+ if (typeof valueArg !== 'string' || valueArg.length > 4096 || valueArg.includes('\0') ||
6
+ !plugins.path.isAbsolute(valueArg) || valueArg === '/' || plugins.path.normalize(valueArg) !== valueArg ||
7
+ valueArg.endsWith('/')) {
8
+ throw new PalletBundleError('invalid_options');
9
+ }
10
+ return valueArg;
11
+ }
12
+ const unsafe = () => { throw new PalletBundleError('unsafe_path'); };
13
+ /** No symlink ancestor, foreign owner or group/other writer can replace the protected leaf. */
14
+ export async function checkAncestors(pathArg, uidArg) {
15
+ let current = plugins.path.dirname(pathArg);
16
+ for (;;) {
17
+ const info = await plugins.fs.lstat(current);
18
+ const rootSticky = info.uid === 0 && (info.mode & 0o1000) !== 0;
19
+ if (!info.isDirectory() || info.isSymbolicLink() || (info.uid !== uidArg && info.uid !== 0) ||
20
+ ((info.mode & 0o022) !== 0 && !rootSticky))
21
+ unsafe();
22
+ if (current === '/')
23
+ return;
24
+ current = plugins.path.dirname(current);
25
+ }
26
+ }
27
+ const checkExecutable = (infoArg, uidArg) => {
28
+ if (!infoArg.isFile() || infoArg.isSymbolicLink() || infoArg.uid !== uidArg || infoArg.nlink !== 1 ||
29
+ (infoArg.mode & 0o6022) !== 0 || (infoArg.mode & 0o100) === 0)
30
+ unsafe();
31
+ };
32
+ /**
33
+ * Proves the executable at a protected path carries the digest trusted metadata states. The file is
34
+ * read through one descriptor opened without following links, and its identity must not change
35
+ * while it is read.
36
+ */
37
+ export async function verifyExecutable(pathArg, digestArg, uidArg, signalArg) {
38
+ signalArg?.throwIfAborted();
39
+ await checkAncestors(pathArg, uidArg);
40
+ checkExecutable(await plugins.fs.lstat(pathArg), uidArg);
41
+ const file = await plugins.fs.open(pathArg, plugins.fsConstants.O_RDONLY | plugins.fsConstants.O_NOFOLLOW);
42
+ try {
43
+ const before = await file.stat();
44
+ checkExecutable(before, uidArg);
45
+ if (before.size < 1 || before.size > 1024 ** 3)
46
+ unsafe();
47
+ const hash = plugins.crypto.createHash('sha256');
48
+ const buffer = Buffer.alloc(1024 * 1024);
49
+ let position = 0;
50
+ while (position < before.size) {
51
+ signalArg?.throwIfAborted();
52
+ const { bytesRead } = await file.read(buffer, 0, Math.min(buffer.length, before.size - position), position);
53
+ if (bytesRead === 0)
54
+ unsafe();
55
+ hash.update(buffer.subarray(0, bytesRead));
56
+ position += bytesRead;
57
+ }
58
+ const after = await file.stat();
59
+ if (after.size !== before.size || after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs ||
60
+ after.ino !== before.ino || after.dev !== before.dev)
61
+ unsafe();
62
+ if (hash.digest('hex') !== digestArg)
63
+ throw new PalletBundleError('artifact_mismatch');
64
+ }
65
+ finally {
66
+ await file.close();
67
+ }
68
+ }
69
+ /** A directory that is canonical (its real path is itself) and a directory. */
70
+ export async function requireCanonicalDirectory(pathArg) {
71
+ canonicalPath(pathArg);
72
+ const info = await plugins.fs.lstat(pathArg).catch(() => unsafe());
73
+ if (!info.isDirectory() || await plugins.fs.realpath(pathArg) !== pathArg)
74
+ unsafe();
75
+ }
76
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19idW5kbGUvcGF0aHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRWhELG9GQUFvRjtBQUNwRixNQUFNLFVBQVUsYUFBYSxDQUFDLFFBQWlCO0lBQzdDLElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsSUFBSSxJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQ25GLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLElBQUksUUFBUSxLQUFLLEdBQUcsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxRQUFRO1FBQ3ZHLFFBQVEsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN6QixNQUFNLElBQUksaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQztBQUVELE1BQU0sTUFBTSxHQUFHLEdBQVUsRUFBRSxHQUFHLE1BQU0sSUFBSSxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUU1RSwrRkFBK0Y7QUFDL0YsTUFBTSxDQUFDLEtBQUssVUFBVSxjQUFjLENBQUMsT0FBZSxFQUFFLE1BQWM7SUFDbEUsSUFBSSxPQUFPLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDNUMsU0FBUyxDQUFDO1FBQ1IsTUFBTSxJQUFJLEdBQUcsTUFBTSxPQUFPLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QyxNQUFNLFVB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
@@ -0,0 +1,14 @@
1
+ import * as childProcess from 'node:child_process';
2
+ import * as crypto from 'node:crypto';
3
+ import * as fs from 'node:fs/promises';
4
+ import { constants as fsConstants } from 'node:fs';
5
+ import * as nodeUtil from 'node:util';
6
+ import * as os from 'node:os';
7
+ import * as path from 'node:path';
8
+ export { childProcess, crypto, fs, fsConstants, nodeUtil, os, path };
9
+ import * as tspack from '@git.zone/tspack';
10
+ export { tspack };
11
+ import * as smartdaemon from '@push.rocks/smartdaemon';
12
+ export { smartdaemon };
13
+ import * as interfaces from '@serve.zone/interfaces';
14
+ export { interfaces };
@@ -0,0 +1,19 @@
1
+ // node native scope
2
+ import * as childProcess from 'node:child_process';
3
+ import * as crypto from 'node:crypto';
4
+ import * as fs from 'node:fs/promises';
5
+ import { constants as fsConstants } from 'node:fs';
6
+ import * as nodeUtil from 'node:util';
7
+ import * as os from 'node:os';
8
+ import * as path from 'node:path';
9
+ export { childProcess, crypto, fs, fsConstants, nodeUtil, os, path };
10
+ // @git.zone scope
11
+ import * as tspack from '@git.zone/tspack';
12
+ export { tspack };
13
+ // @push.rocks scope
14
+ import * as smartdaemon from '@push.rocks/smartdaemon';
15
+ export { smartdaemon };
16
+ // @serve.zone scope
17
+ import * as interfaces from '@serve.zone/interfaces';
18
+ export { interfaces };
19
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX2J1bmRsZS9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssWUFBWSxNQUFNLG9CQUFvQixDQUFDO0FBQ25ELE9BQU8sS0FBSyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ3RDLE9BQU8sS0FBSyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDdkMsT0FBTyxFQUFFLFNBQVMsSUFBSSxXQUFXLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbkQsT0FBTyxLQUFLLFFBQVEsTUFBTSxXQUFXLENBQUM7QUFDdEMsT0FBTyxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDOUIsT0FBTyxLQUFLLElBQUksTUFBTSxXQUFXLENBQUM7QUFFbEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDO0FBRXJFLGtCQUFrQjtBQUNsQixPQUFPLEtBQUssTUFBTSxNQUFNLGtCQUFrQixDQUFDO0FBRTNDLE9BQU8sRUFBRSxNQUFNLEVBQUUsQ0FBQztBQUVsQixvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUV2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLENBQUM7QUFFdkIsb0JBQW9CO0FBQ3BCLE9BQU8sS0FBSyxVQUFVLE1BQU0sd0JBQXdCLENBQUM7QUFFckQsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDIn0=
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The process protocol of `pallet-control`: its modes, the protocol each mode reports on standard
3
+ * output and the reasons a `failed` line names. `pallet-control` itself reports with these names
4
+ * (`ts/control/process-cli.ts`), and the supervisors in this package read them. This module has no
5
+ * dependencies, so the compiled control can import it.
6
+ */
7
+ /** Every line of the protocol starts with this prefix, followed by one JSON object. */
8
+ export declare const palletControlLinePrefix = "PALLET_CONTROL ";
9
+ export declare const palletControlProtocols: Readonly<{
10
+ readonly enrollment: "pallet.enrollment.process";
11
+ readonly node: "pallet.node.process";
12
+ readonly guard: "pallet.guard.process";
13
+ readonly acquisition: "pallet.network.acquisition";
14
+ readonly containerd: "pallet.containerd.process";
15
+ readonly storageImport: "pallet.storage.import";
16
+ readonly storeProvision: "pallet.store.provision";
17
+ }>;
18
+ /**
19
+ * Modes a supervisor holds for its lifetime through a stdin pipe: the child stops when that pipe
20
+ * closes. `runtime-serve` is the node process as a supervised child.
21
+ */
22
+ export declare const palletControlLifetimeModes: Readonly<{
23
+ readonly 'enrollment-serve': "pallet.enrollment.process";
24
+ readonly 'enrollment-provision': "pallet.enrollment.process";
25
+ readonly 'runtime-serve': "pallet.node.process";
26
+ }>;
27
+ export type TPalletControlLifetimeMode = keyof typeof palletControlLifetimeModes;
28
+ /** Oneshot modes: null stdin is valid, and `ready` followed by `stopped` is their success. */
29
+ export declare const palletControlOneshotModes: Readonly<{
30
+ readonly 'guard-recover': "pallet.guard.process";
31
+ readonly 'guard-commission': "pallet.guard.process";
32
+ readonly 'network-acquire': "pallet.network.acquisition";
33
+ readonly 'network-acquire-local': "pallet.network.acquisition";
34
+ readonly 'store-provision': "pallet.store.provision";
35
+ }>;
36
+ export type TPalletControlOneshotMode = keyof typeof palletControlOneshotModes;
37
+ /**
38
+ * Service unit main processes. Their stdin is null and a signal stops them; the service manager,
39
+ * not a supervisor in this package, runs them.
40
+ */
41
+ export declare const palletControlUnitModes: Readonly<{
42
+ readonly 'containerd-serve': "pallet.containerd.process";
43
+ readonly 'runtime-unit': "pallet.node.process";
44
+ }>;
45
+ export type TPalletControlUnitMode = keyof typeof palletControlUnitModes;
46
+ /** The reasons a `failed` line names. */
47
+ export declare const palletControlFailureReasons: readonly ["invalid_arguments", "invalid_ca_store", "invalid_stdin", "owner_failed", "unsupported_kernel"];
48
+ export type TPalletControlFailureReason = typeof palletControlFailureReasons[number];
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The process protocol of `pallet-control`: its modes, the protocol each mode reports on standard
3
+ * output and the reasons a `failed` line names. `pallet-control` itself reports with these names
4
+ * (`ts/control/process-cli.ts`), and the supervisors in this package read them. This module has no
5
+ * dependencies, so the compiled control can import it.
6
+ */
7
+ /** Every line of the protocol starts with this prefix, followed by one JSON object. */
8
+ export const palletControlLinePrefix = 'PALLET_CONTROL ';
9
+ export const palletControlProtocols = Object.freeze({
10
+ enrollment: 'pallet.enrollment.process',
11
+ node: 'pallet.node.process',
12
+ guard: 'pallet.guard.process',
13
+ acquisition: 'pallet.network.acquisition',
14
+ containerd: 'pallet.containerd.process',
15
+ storageImport: 'pallet.storage.import',
16
+ storeProvision: 'pallet.store.provision',
17
+ });
18
+ /**
19
+ * Modes a supervisor holds for its lifetime through a stdin pipe: the child stops when that pipe
20
+ * closes. `runtime-serve` is the node process as a supervised child.
21
+ */
22
+ export const palletControlLifetimeModes = Object.freeze({
23
+ 'enrollment-serve': palletControlProtocols.enrollment,
24
+ 'enrollment-provision': palletControlProtocols.enrollment,
25
+ 'runtime-serve': palletControlProtocols.node,
26
+ });
27
+ /** Oneshot modes: null stdin is valid, and `ready` followed by `stopped` is their success. */
28
+ export const palletControlOneshotModes = Object.freeze({
29
+ 'guard-recover': palletControlProtocols.guard,
30
+ 'guard-commission': palletControlProtocols.guard,
31
+ 'network-acquire': palletControlProtocols.acquisition,
32
+ 'network-acquire-local': palletControlProtocols.acquisition,
33
+ 'store-provision': palletControlProtocols.storeProvision,
34
+ });
35
+ /**
36
+ * Service unit main processes. Their stdin is null and a signal stops them; the service manager,
37
+ * not a supervisor in this package, runs them.
38
+ */
39
+ export const palletControlUnitModes = Object.freeze({
40
+ 'containerd-serve': palletControlProtocols.containerd,
41
+ 'runtime-unit': palletControlProtocols.node,
42
+ });
43
+ /** The reasons a `failed` line names. */
44
+ export const palletControlFailureReasons = Object.freeze([
45
+ 'invalid_arguments', 'invalid_ca_store', 'invalid_stdin', 'owner_failed', 'unsupported_kernel',
46
+ ]);
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19idW5kbGUvcHJvdG9jb2wudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCx1RkFBdUY7QUFDdkYsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsaUJBQWlCLENBQUM7QUFFekQsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNsRCxVQUFVLEVBQUUsMkJBQTJCO0lBQ3ZDLElBQUksRUFBRSxxQkFBcUI7SUFDM0IsS0FBSyxFQUFFLHNCQUFzQjtJQUM3QixXQUFXLEVBQUUsNEJBQTRCO0lBQ3pDLFVBQVUsRUFBRSwyQkFBMkI7SUFDdkMsYUFBYSxFQUFFLHVCQUF1QjtJQUN0QyxjQUFjLEVBQUUsd0JBQXdCO0NBQ2hDLENBQUMsQ0FBQztBQUVaOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDdEQsa0JBQWtCLEVBQUUsc0JBQXNCLENBQUMsVUFBVTtJQUNyRCxzQkFBc0IsRUFBRSxzQkFBc0IsQ0FBQyxVQUFVO0lBQ3pELGVBQWUsRUFBRSxzQkFBc0IsQ0FBQyxJQUFJO0NBQ3BDLENBQUMsQ0FBQztBQUdaLDhGQUE4RjtBQUM5RixNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3JELGVBQWUsRUFBRSxzQkFBc0IsQ0FBQyxLQUFLO0lBQzdDLGtCQUFrQixFQUFFLHNCQUFzQixDQUFDLEtBQUs7SUFDaEQsaUJBQWlCLEVBQUUsc0JBQXNCLENBQUMsV0FBVztJQUNyRCx1QkFBdUIsRUFBRSxzQkFBc0IsQ0FBQyxXQUFXO0lBQzNELGlCQUFpQixFQUFFLHNCQUFzQixDQUFDLGNBQWM7Q0FDaEQsQ0FBQyxDQUFDO0FBR1o7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUNsRCxrQkFBa0IsRUFBRSxzQkFBc0IsQ0FBQyxVQUFVO0lBQ3JELGNBQWMsRUFBRSxzQkFBc0IsQ0FBQyxJQUFJO0NBQ25DLENBQUMsQ0FBQztBQUdaLHlDQUF5QztBQUN6QyxNQUFNLENBQUMsTUFBTSwyQkFBMkIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3ZELG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsb0JBQW9CO0NBQ3RGLENBQUMsQ0FBQyJ9
@@ -0,0 +1,67 @@
1
+ import * as plugins from './plugins.js';
2
+ /**
3
+ * The service units an installer writes for Pallet, to the "Service unit contract" in Pallet's readme.
4
+ * Pallet never writes a unit file itself: Spark on fleet nodes and Onebox on its own host install
5
+ * these definitions under their own unit names and install roots.
6
+ */
7
+ /** The one network provider the guard's supported host profile orders itself before. */
8
+ export declare const palletGuardNetworkProviderName = "systemd-networkd.service";
9
+ /** How long a stop of the node may take: a five-minute native operation, then the database joins. */
10
+ export declare const palletNodeStopTimeoutSeconds = 360;
11
+ export interface IPalletGuardUnitOptions {
12
+ unitName: string;
13
+ /**
14
+ * The boot command's executable. It runs `guard-recover`: `pallet-control` itself, or an
15
+ * installer's own executable that verifies the installed bundle before it starts that mode.
16
+ */
17
+ executable: string;
18
+ workingDirectory: string;
19
+ }
20
+ export interface IPalletContainerdUnitOptions {
21
+ unitName: string;
22
+ /** `<bundle>/pallet-control` of the selected installation. */
23
+ controlExecutable: string;
24
+ workingDirectory: string;
25
+ guardUnitName: string;
26
+ /** The node unit, the only CRI client, which this unit starts before. */
27
+ nodeUnitName: string;
28
+ }
29
+ export interface IPalletNodeUnitOptions {
30
+ unitName: string;
31
+ /** `<bundle>/pallet-control` of the selected installation. */
32
+ controlExecutable: string;
33
+ workingDirectory: string;
34
+ guardUnitName: string;
35
+ containerdUnitName: string;
36
+ }
37
+ /**
38
+ * The retained allocation-pool guard's boot unit: a oneshot that recovers the commissioned guard
39
+ * before networkd, required by `network-pre.target` and by networkd itself. The installer installs it
40
+ * only after the first `guard-commission`, and never replaces an installed one with other bytes.
41
+ */
42
+ export declare const createPalletGuardServiceDefinition: (optionsArg: IPalletGuardUnitOptions) => plugins.smartdaemon.SystemdServiceDefinition;
43
+ /**
44
+ * Pallet's containerd unit: `pallet-control containerd-serve` as the root main process with null stdin,
45
+ * ready on the `READY=1` its native owner (a child of the main process) sends. Stopping the unit
46
+ * signals only `containerd-serve`, which stops containerd itself; every shim and workload keeps
47
+ * running and is reattached by the next containerd. containerd's exit fails the process and the
48
+ * service manager restarts it — Pallet never restarts containerd inside the process.
49
+ */
50
+ export declare const createPalletContainerdServiceDefinition: (optionsArg: IPalletContainerdUnitOptions) => plugins.smartdaemon.SystemdServiceDefinition;
51
+ /**
52
+ * The node unit: `pallet-control runtime-unit` as the root main process with null stdin. It runs the
53
+ * same node lifetime as `runtime-serve`, but standard input is not its parent's lifetime: SIGTERM or
54
+ * SIGINT stops it. `KillMode=mixed` signals only the main process, which joins every owner and child
55
+ * it started, and the service manager removes whatever remains of the unit's cgroup when the stop
56
+ * timeout ends, before any successor starts. A failed lifetime is restarted by the service manager,
57
+ * never inside the process.
58
+ */
59
+ export declare const createPalletNodeServiceDefinition: (optionsArg: IPalletNodeUnitOptions) => plugins.smartdaemon.SystemdServiceDefinition;
60
+ /**
61
+ * Whether the service manager's own reading of the containerd unit, drop-ins included, is the
62
+ * contract. Admission and activation read the loaded unit rather than the file, so a drop-in that
63
+ * weakens the contract is refused whatever file produced it.
64
+ */
65
+ export declare const palletContainerdServiceSettingsMatch: (settingsArg: plugins.smartdaemon.ISystemdServiceSettings, unitNameArg: string) => boolean;
66
+ /** The same reading of the node unit: no restart inside a stop, and a stop long enough to join. */
67
+ export declare const palletNodeServiceSettingsMatch: (settingsArg: plugins.smartdaemon.ISystemdServiceSettings, unitNameArg: string) => boolean;
@@ -0,0 +1,128 @@
1
+ import * as plugins from './plugins.js';
2
+ import { PalletBundleError } from './errors.js';
3
+ /**
4
+ * The service units an installer writes for Pallet, to the "Service unit contract" in Pallet's readme.
5
+ * Pallet never writes a unit file itself: Spark on fleet nodes and Onebox on its own host install
6
+ * these definitions under their own unit names and install roots.
7
+ */
8
+ /** The one network provider the guard's supported host profile orders itself before. */
9
+ export const palletGuardNetworkProviderName = 'systemd-networkd.service';
10
+ /** How long a stop of the node may take: a five-minute native operation, then the database joins. */
11
+ export const palletNodeStopTimeoutSeconds = 360;
12
+ const definition = (optionsArg) => {
13
+ try {
14
+ return new plugins.smartdaemon.SystemdServiceDefinition(optionsArg);
15
+ }
16
+ catch (error) {
17
+ throw new PalletBundleError('invalid_options', { cause: error });
18
+ }
19
+ };
20
+ /**
21
+ * The retained allocation-pool guard's boot unit: a oneshot that recovers the commissioned guard
22
+ * before networkd, required by `network-pre.target` and by networkd itself. The installer installs it
23
+ * only after the first `guard-commission`, and never replaces an installed one with other bytes.
24
+ */
25
+ export const createPalletGuardServiceDefinition = (optionsArg) => definition({
26
+ unitName: optionsArg.unitName,
27
+ description: 'serve.zone retained allocation-pool guard',
28
+ executable: optionsArg.executable,
29
+ args: ['guard-recover'],
30
+ workingDirectory: optionsArg.workingDirectory,
31
+ user: 'root',
32
+ group: 'root',
33
+ restart: 'no',
34
+ killMode: 'mixed',
35
+ timeoutStopSeconds: 360,
36
+ startup: { type: 'oneshot', remainAfterExit: true, timeoutStartSeconds: 600 },
37
+ dependencies: {
38
+ defaultDependencies: false,
39
+ after: [],
40
+ before: ['network-pre.target', palletGuardNetworkProviderName, 'shutdown.target'],
41
+ requires: [],
42
+ wants: ['network-pre.target'],
43
+ conflicts: ['shutdown.target'],
44
+ },
45
+ install: { wantedBy: [], requiredBy: ['network-pre.target', palletGuardNetworkProviderName] },
46
+ });
47
+ /**
48
+ * Pallet's containerd unit: `pallet-control containerd-serve` as the root main process with null stdin,
49
+ * ready on the `READY=1` its native owner (a child of the main process) sends. Stopping the unit
50
+ * signals only `containerd-serve`, which stops containerd itself; every shim and workload keeps
51
+ * running and is reattached by the next containerd. containerd's exit fails the process and the
52
+ * service manager restarts it — Pallet never restarts containerd inside the process.
53
+ */
54
+ export const createPalletContainerdServiceDefinition = (optionsArg) => definition({
55
+ unitName: optionsArg.unitName,
56
+ description: 'serve.zone Pallet containerd',
57
+ executable: optionsArg.controlExecutable,
58
+ args: ['containerd-serve'],
59
+ workingDirectory: optionsArg.workingDirectory,
60
+ user: 'root',
61
+ group: 'root',
62
+ restart: 'always',
63
+ restartSeconds: 2,
64
+ killMode: 'process',
65
+ // Pallet's 30 s containerd grace plus the owner's joins; the contract's floor is 45 s.
66
+ timeoutStopSeconds: 60,
67
+ // containerd-serve waits up to 60 s for CRI readiness, then imports the pause image.
68
+ startup: { type: 'notify', notifyAccess: 'all', timeoutStartSeconds: 120 },
69
+ delegate: true,
70
+ limitNoFile: 'infinity',
71
+ tasksMax: 'infinity',
72
+ oomScoreAdjust: -999,
73
+ dependencies: {
74
+ defaultDependencies: true,
75
+ after: [optionsArg.guardUnitName],
76
+ before: [optionsArg.nodeUnitName],
77
+ requires: [optionsArg.guardUnitName],
78
+ wants: [],
79
+ conflicts: [],
80
+ },
81
+ });
82
+ /**
83
+ * The node unit: `pallet-control runtime-unit` as the root main process with null stdin. It runs the
84
+ * same node lifetime as `runtime-serve`, but standard input is not its parent's lifetime: SIGTERM or
85
+ * SIGINT stops it. `KillMode=mixed` signals only the main process, which joins every owner and child
86
+ * it started, and the service manager removes whatever remains of the unit's cgroup when the stop
87
+ * timeout ends, before any successor starts. A failed lifetime is restarted by the service manager,
88
+ * never inside the process.
89
+ */
90
+ export const createPalletNodeServiceDefinition = (optionsArg) => definition({
91
+ unitName: optionsArg.unitName,
92
+ description: 'serve.zone Pallet node',
93
+ executable: optionsArg.controlExecutable,
94
+ args: ['runtime-unit'],
95
+ workingDirectory: optionsArg.workingDirectory,
96
+ user: 'root',
97
+ group: 'root',
98
+ restart: 'on-failure',
99
+ restartSeconds: 5,
100
+ killMode: 'mixed',
101
+ timeoutStopSeconds: palletNodeStopTimeoutSeconds,
102
+ dependencies: {
103
+ defaultDependencies: true,
104
+ after: [optionsArg.guardUnitName, optionsArg.containerdUnitName],
105
+ before: [],
106
+ requires: [optionsArg.guardUnitName],
107
+ wants: [optionsArg.containerdUnitName],
108
+ conflicts: [],
109
+ },
110
+ });
111
+ /**
112
+ * Whether the service manager's own reading of the containerd unit, drop-ins included, is the
113
+ * contract. Admission and activation read the loaded unit rather than the file, so a drop-in that
114
+ * weakens the contract is refused whatever file produced it.
115
+ */
116
+ export const palletContainerdServiceSettingsMatch = (settingsArg, unitNameArg) => settingsArg.unitName === unitNameArg && settingsArg.type === 'notify' && settingsArg.notifyAccess === 'all' &&
117
+ settingsArg.restart === 'always' && typeof settingsArg.restartMicroseconds === 'number' &&
118
+ settingsArg.restartMicroseconds > 0 && settingsArg.restartMicroseconds <= 10_000_000 && settingsArg.killMode === 'process' &&
119
+ settingsArg.delegate && typeof settingsArg.timeoutStopMicroseconds === 'number' &&
120
+ settingsArg.timeoutStopMicroseconds >= 45_000_000 && settingsArg.limitNoFile === 'infinity' &&
121
+ settingsArg.limitNoFileSoft === 'infinity' && settingsArg.tasksMax === 'infinity' && settingsArg.oomScoreAdjust === -999;
122
+ /** The same reading of the node unit: no restart inside a stop, and a stop long enough to join. */
123
+ export const palletNodeServiceSettingsMatch = (settingsArg, unitNameArg) => settingsArg.unitName === unitNameArg && settingsArg.type === 'exec' && settingsArg.killMode === 'mixed' &&
124
+ settingsArg.restart === 'on-failure' &&
125
+ typeof settingsArg.timeoutStopMicroseconds === 'number' &&
126
+ settingsArg.timeoutStopMicroseconds >= palletNodeStopTimeoutSeconds * 1_000_000 && !settingsArg.delegate &&
127
+ Object.keys(settingsArg.environment).length === 0;
128
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5pdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19idW5kbGUvdW5pdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRWhEOzs7O0dBSUc7QUFFSCx3RkFBd0Y7QUFDeEYsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsMEJBQTBCLENBQUM7QUFFekUscUdBQXFHO0FBQ3JHLE1BQU0sQ0FBQyxNQUFNLDRCQUE0QixHQUFHLEdBQUcsQ0FBQztBQStCaEQsTUFBTSxVQUFVLEdBQUcsQ0FBQyxVQUFnRSxFQUFFLEVBQUU7SUFDdEYsSUFBSSxDQUFDO1FBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsd0JBQXdCLENBQUMsVUFBVSxDQUFDLENBQUM7SUFBQyxDQUFDO0lBQzVFLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFBQyxNQUFNLElBQUksaUJBQWlCLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUFDLENBQUM7QUFDckYsQ0FBQyxDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGtDQUFrQyxHQUFHLENBQUMsVUFBbUMsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDO0lBQ3BHLFFBQVEsRUFBRSxVQUFVLENBQUMsUUFBUTtJQUM3QixXQUFXLEVBQUUsMkNBQTJDO0lBQ3hELFVBQVUsRUFBRSxVQUFVLENBQUMsVUFBVTtJQUNqQyxJQUFJLEVBQUUsQ0FBQyxlQUFlLENBQUM7SUFDdkIsZ0JBQWdCLEVBQUUsVUFBVSxDQUFDLGdCQUFnQjtJQUM3QyxJQUFJLEVBQUUsTUFBTTtJQUNaLEtBQUssRUFBRSxNQUFNO0lBQ2IsT0FBTyxFQUFFLElBQUk7SUFDYixRQUFRLEVBQUUsT0FBTztJQUNqQixrQkFBa0IsRUFBRSxH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
@@ -0,0 +1,75 @@
1
+ import * as plugins from './plugins.js';
2
+ import { type TPalletControlRole, type TPalletControlTarget } from './inventory.js';
3
+ /** The trusted identity of one Pallet release, as a consumer pins it. */
4
+ export interface IPalletBundlePin {
5
+ readonly version: string;
6
+ readonly sourceCommit: string;
7
+ /** SHA-256 of the release's `tspack-manifest.json`, which pins every file of every bundle. */
8
+ readonly manifestSha256: string;
9
+ }
10
+ /** A bundle's files as its sealed tspack manifest records them. */
11
+ export type TPalletSealedFiles = Readonly<Record<string, plugins.tspack.ITsPackFileRecord>>;
12
+ export interface IPalletControlExecutable {
13
+ /** Absolute path inside the verified bundle directory. */
14
+ readonly path: string;
15
+ readonly sha256: string;
16
+ }
17
+ /** Who built a native executable, from its tsrust provenance. */
18
+ export interface IPalletControlProvenance {
19
+ readonly projectName: string;
20
+ readonly projectVersion: string;
21
+ readonly gitCommit: string;
22
+ }
23
+ export interface IPalletControlBundle {
24
+ readonly directory: string;
25
+ readonly target: TPalletControlTarget;
26
+ readonly version: string;
27
+ readonly sourceCommit: string;
28
+ readonly sourceDirty: boolean;
29
+ /** The Deno the control executable was compiled with. */
30
+ readonly denoVersion: string;
31
+ readonly lockSha256: string;
32
+ readonly executables: Readonly<Record<TPalletControlRole, IPalletControlExecutable>>;
33
+ readonly provenance: Readonly<Record<Exclude<TPalletControlRole, 'control'>, IPalletControlProvenance>>;
34
+ readonly clockManifestSha256: string;
35
+ readonly dnsManifestSha256: string;
36
+ readonly vpnInventorySha256: string;
37
+ /** The digest `containerd-serve` compiles in; it pins containerd, its shim, runc and the pause image. */
38
+ readonly containerdManifestSha256: string;
39
+ readonly containerdVersion: string;
40
+ readonly runcVersion: string;
41
+ readonly files: TPalletSealedFiles;
42
+ }
43
+ /** A released bundle: every file verified against the pinned release manifest. */
44
+ export interface IPalletVerifiedControlBundle extends IPalletControlBundle {
45
+ readonly manifestSha256: string;
46
+ }
47
+ /** What a build is expected to be; the consumer's pin, or the packaging step's own source identity. */
48
+ export interface IPalletControlBuildExpectation {
49
+ readonly version: string;
50
+ readonly sourceCommit: string;
51
+ readonly sourceDirty: boolean;
52
+ readonly target: TPalletControlTarget;
53
+ }
54
+ export declare const validPalletBundlePin: (valueArg: unknown) => valueArg is IPalletBundlePin;
55
+ /** Refuses a malformed pin, and a pin of another Pallet version than this package states. */
56
+ export declare function requirePalletBundlePin(pinArg: unknown): Promise<IPalletBundlePin>;
57
+ /**
58
+ * Checks a control build directory against the sealed records of its files: the control record,
59
+ * every executable's role and provenance, the component manifests and the notice and source
60
+ * inventories. Pallet's packaging runs this over every build before sealing it, with the build's
61
+ * own source identity; consumers use {@link verifyPalletControlBundle}, which also binds the pin.
62
+ */
63
+ export declare function inspectPalletControlBuild(directoryArg: string, filesArg: TPalletSealedFiles, expectedArg: IPalletControlBuildExpectation): Promise<IPalletControlBundle>;
64
+ /**
65
+ * Verifies an extracted release bundle of the pinned version: `filesArg` are the records of the
66
+ * sealed release manifest whose digest the pin states (tspack's `extractBundle` result), and the
67
+ * pin must name this package's own Pallet version.
68
+ */
69
+ export declare function verifyPalletControlBundle(directoryArg: string, filesArg: TPalletSealedFiles, pinArg: IPalletBundlePin, targetArg: TPalletControlTarget): Promise<IPalletVerifiedControlBundle>;
70
+ /**
71
+ * Extracts and verifies the pinned bundle from a download directory that holds the release's
72
+ * `tspack-manifest.json`, `SHA256SUMS.txt` and the target's archive. The bundle is extracted into a
73
+ * fresh private directory below `stagingParentArg`, which the caller owns from then on.
74
+ */
75
+ export declare function extractPalletControlBundle(downloadDirectoryArg: string, targetArg: TPalletControlTarget, stagingParentArg: string, pinArg: IPalletBundlePin, signalArg?: AbortSignal): Promise<IPalletVerifiedControlBundle>;