@homeflare/alchemy 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -48
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/launchd/fake-runner.d.ts +36 -0
- package/dist/launchd/fake-runner.d.ts.map +1 -0
- package/dist/launchd/host-effect.d.ts +19 -0
- package/dist/launchd/host-effect.d.ts.map +1 -0
- package/dist/launchd/host-file-form.d.ts +24 -0
- package/dist/launchd/host-file-form.d.ts.map +1 -0
- package/dist/launchd/host-file-lifecycle.d.ts +29 -0
- package/dist/launchd/host-file-lifecycle.d.ts.map +1 -0
- package/dist/launchd/host-file.d.ts +25 -0
- package/dist/launchd/host-file.d.ts.map +1 -0
- package/dist/launchd/host-lookup.d.ts +27 -0
- package/dist/launchd/host-lookup.d.ts.map +1 -0
- package/dist/launchd/index.d.ts +21 -0
- package/dist/launchd/index.d.ts.map +1 -0
- package/dist/launchd/index.js +969 -0
- package/dist/launchd/index.js.map +25 -0
- package/dist/launchd/job-form.d.ts +90 -0
- package/dist/launchd/job-form.d.ts.map +1 -0
- package/dist/launchd/job-lifecycle.d.ts +34 -0
- package/dist/launchd/job-lifecycle.d.ts.map +1 -0
- package/dist/launchd/job-preflight.d.ts +50 -0
- package/dist/launchd/job-preflight.d.ts.map +1 -0
- package/dist/launchd/job-validate.d.ts +25 -0
- package/dist/launchd/job-validate.d.ts.map +1 -0
- package/dist/launchd/job.d.ts +34 -0
- package/dist/launchd/job.d.ts.map +1 -0
- package/dist/launchd/launchctl.d.ts +62 -0
- package/dist/launchd/launchctl.d.ts.map +1 -0
- package/dist/launchd/local-runner.d.ts +7 -0
- package/dist/launchd/local-runner.d.ts.map +1 -0
- package/dist/launchd/plist.d.ts +41 -0
- package/dist/launchd/plist.d.ts.map +1 -0
- package/dist/launchd/providers.d.ts +15 -0
- package/dist/launchd/providers.d.ts.map +1 -0
- package/dist/launchd/runner.d.ts +91 -0
- package/dist/launchd/runner.d.ts.map +1 -0
- package/dist/launchd/secret-tripwire.d.ts +23 -0
- package/dist/launchd/secret-tripwire.d.ts.map +1 -0
- package/dist/openbao/auth-method-form.d.ts +7 -0
- package/dist/openbao/auth-method-form.d.ts.map +1 -1
- package/dist/openbao/auth-method-reconcile.d.ts +15 -0
- package/dist/openbao/auth-method-reconcile.d.ts.map +1 -0
- package/dist/openbao/auth-method.d.ts +6 -0
- package/dist/openbao/auth-method.d.ts.map +1 -1
- package/dist/openbao/auth-role-form.d.ts +9 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role.d.ts.map +1 -1
- package/dist/openbao/auth-token-form.d.ts +48 -0
- package/dist/openbao/auth-token-form.d.ts.map +1 -0
- package/dist/openbao/bao-identity.d.ts +81 -0
- package/dist/openbao/bao-identity.d.ts.map +1 -0
- package/dist/openbao/bao-namespace.d.ts +20 -0
- package/dist/openbao/bao-namespace.d.ts.map +1 -0
- package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -1
- package/dist/openbao/host-approles.d.ts +62 -0
- package/dist/openbao/host-approles.d.ts.map +1 -0
- package/dist/openbao/index.d.ts +19 -0
- package/dist/openbao/index.d.ts.map +1 -1
- package/dist/openbao/index.js +1433 -305
- package/dist/openbao/index.js.map +34 -13
- package/dist/openbao/jwt-config-form.d.ts +51 -0
- package/dist/openbao/jwt-config-form.d.ts.map +1 -0
- package/dist/openbao/jwt-config.d.ts +25 -0
- package/dist/openbao/jwt-config.d.ts.map +1 -0
- package/dist/openbao/jwt-role-form.d.ts +91 -0
- package/dist/openbao/jwt-role-form.d.ts.map +1 -0
- package/dist/openbao/jwt-role.d.ts +31 -0
- package/dist/openbao/jwt-role.d.ts.map +1 -0
- package/dist/openbao/kubernetes-role-form.d.ts +68 -0
- package/dist/openbao/kubernetes-role-form.d.ts.map +1 -0
- package/dist/openbao/kubernetes-role.d.ts +25 -0
- package/dist/openbao/kubernetes-role.d.ts.map +1 -0
- package/dist/openbao/mfa-enforcement-form.d.ts +46 -0
- package/dist/openbao/mfa-enforcement-form.d.ts.map +1 -0
- package/dist/openbao/mfa-enforcement.d.ts +41 -0
- package/dist/openbao/mfa-enforcement.d.ts.map +1 -0
- package/dist/openbao/mfa-totp-form.d.ts +52 -0
- package/dist/openbao/mfa-totp-form.d.ts.map +1 -0
- package/dist/openbao/mfa-totp.d.ts +33 -0
- package/dist/openbao/mfa-totp.d.ts.map +1 -0
- package/dist/openbao/mfa-wire.d.ts +63 -0
- package/dist/openbao/mfa-wire.d.ts.map +1 -0
- package/dist/openbao/mount-form.d.ts +7 -0
- package/dist/openbao/mount-form.d.ts.map +1 -1
- package/dist/openbao/mount-move.d.ts +49 -0
- package/dist/openbao/mount-move.d.ts.map +1 -0
- package/dist/openbao/mount-path.d.ts +8 -4
- package/dist/openbao/mount-path.d.ts.map +1 -1
- package/dist/openbao/mount-reconcile.d.ts +16 -0
- package/dist/openbao/mount-reconcile.d.ts.map +1 -0
- package/dist/openbao/mount.d.ts +9 -0
- package/dist/openbao/mount.d.ts.map +1 -1
- package/dist/openbao/pki-role-canonical.d.ts +46 -0
- package/dist/openbao/pki-role-canonical.d.ts.map +1 -0
- package/dist/openbao/pki-role-form.d.ts +38 -30
- package/dist/openbao/pki-role-form.d.ts.map +1 -1
- package/dist/openbao/pki-role.d.ts.map +1 -1
- package/dist/openbao/remount-wire.d.ts +44 -0
- package/dist/openbao/remount-wire.d.ts.map +1 -0
- package/dist/openbao/role-reconcile.d.ts +40 -0
- package/dist/openbao/role-reconcile.d.ts.map +1 -0
- package/docs/launchd.md +167 -0
- package/package.json +7 -2
- package/src/index.ts +1 -0
- package/src/launchd/fake-runner.ts +176 -0
- package/src/launchd/host-effect.ts +28 -0
- package/src/launchd/host-file-form.ts +71 -0
- package/src/launchd/host-file-lifecycle.test.ts +198 -0
- package/src/launchd/host-file-lifecycle.ts +164 -0
- package/src/launchd/host-file.ts +64 -0
- package/src/launchd/host-lookup.test.ts +92 -0
- package/src/launchd/host-lookup.ts +94 -0
- package/src/launchd/index.ts +26 -0
- package/src/launchd/job-form.test.ts +171 -0
- package/src/launchd/job-form.ts +180 -0
- package/src/launchd/job-identity.test.ts +147 -0
- package/src/launchd/job-lifecycle.test.ts +220 -0
- package/src/launchd/job-lifecycle.ts +194 -0
- package/src/launchd/job-preflight.ts +152 -0
- package/src/launchd/job-validate.ts +134 -0
- package/src/launchd/job.ts +96 -0
- package/src/launchd/launchctl.test.ts +181 -0
- package/src/launchd/launchctl.ts +188 -0
- package/src/launchd/local-runner.test.ts +125 -0
- package/src/launchd/local-runner.ts +143 -0
- package/src/launchd/plist.test.ts +186 -0
- package/src/launchd/plist.ts +156 -0
- package/src/launchd/providers.test.ts +222 -0
- package/src/launchd/providers.ts +21 -0
- package/src/launchd/runner.ts +95 -0
- package/src/launchd/secret-tripwire.test.ts +110 -0
- package/src/launchd/secret-tripwire.ts +81 -0
- package/src/openbao/README.md +181 -0
- package/src/openbao/REPLACE.md +87 -0
- package/src/openbao/auth-method-form.ts +7 -0
- package/src/openbao/auth-method-reconcile.ts +74 -0
- package/src/openbao/auth-method.ts +20 -41
- package/src/openbao/auth-role-form.test.ts +16 -1
- package/src/openbao/auth-role-form.ts +11 -0
- package/src/openbao/auth-role.ts +12 -0
- package/src/openbao/auth-token-form.ts +161 -0
- package/src/openbao/bao-identity.test.ts +131 -0
- package/src/openbao/bao-identity.ts +188 -0
- package/src/openbao/bao-namespace.ts +32 -0
- package/src/openbao/cloudflare-roles-expand.ts +2 -5
- package/src/openbao/host-approles.test.ts +121 -0
- package/src/openbao/host-approles.ts +126 -0
- package/src/openbao/index.ts +19 -0
- package/src/openbao/jwt-config-form.ts +161 -0
- package/src/openbao/jwt-config.ts +85 -0
- package/src/openbao/jwt-role-form.test.ts +130 -0
- package/src/openbao/jwt-role-form.ts +231 -0
- package/src/openbao/jwt-role.ts +102 -0
- package/src/openbao/kubernetes-role-form.test.ts +82 -0
- package/src/openbao/kubernetes-role-form.ts +149 -0
- package/src/openbao/kubernetes-role.ts +94 -0
- package/src/openbao/mfa-enforcement-form.ts +147 -0
- package/src/openbao/mfa-enforcement.ts +143 -0
- package/src/openbao/mfa-totp-form.ts +155 -0
- package/src/openbao/mfa-totp.ts +118 -0
- package/src/openbao/mfa-wire.ts +117 -0
- package/src/openbao/mfa.test.ts +200 -0
- package/src/openbao/mount-form.ts +9 -1
- package/src/openbao/mount-move.test.ts +164 -0
- package/src/openbao/mount-move.ts +113 -0
- package/src/openbao/mount-path.test.ts +11 -1
- package/src/openbao/mount-path.ts +17 -11
- package/src/openbao/mount-reconcile.ts +75 -0
- package/src/openbao/mount.ts +26 -43
- package/src/openbao/pki-role-canonical.ts +163 -0
- package/src/openbao/pki-role-form.test.ts +112 -0
- package/src/openbao/pki-role-form.ts +76 -110
- package/src/openbao/pki-role.ts +12 -27
- package/src/openbao/remount-wire.test.ts +87 -0
- package/src/openbao/remount-wire.ts +112 -0
- package/src/openbao/role-reconcile.test.ts +104 -0
- package/src/openbao/role-reconcile.ts +84 -0
package/README.md
CHANGED
|
@@ -66,60 +66,29 @@ is the one operation this resource exists to make hard. It retains on destroy.
|
|
|
66
66
|
|
|
67
67
|
## OpenBao — `@homeflare/alchemy/openbao`
|
|
68
68
|
|
|
69
|
-
Vault objects as resources —
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`
|
|
69
|
+
Vault objects as resources — mounts (with `remountFrom` moves), auth methods, policies, AppRole,
|
|
70
|
+
JWT/OIDC and Kubernetes roles, JWT auth config, login MFA (TOTP method + enforcement), PKI, SSH,
|
|
71
|
+
Cloudflare and Proxmox roles, plugins — plus `assertBaoIdentity` (call it first), the pure
|
|
72
|
+
`hostAppRoles` generator, and an AppRole login for scripts. A stack provides each
|
|
73
73
|
`Bao*Provider()` it uses, plus `FetchHttpClient.layer`.
|
|
74
74
|
|
|
75
|
-
⛔ **Metadata only.** Alchemy stores props and attributes unencrypted, so no secret, CA key
|
|
76
|
-
plugin `env` is declarable. Every family defaults to `retain` on destroy.
|
|
75
|
+
⛔ **Metadata only.** Alchemy stores props and attributes unencrypted, so no secret, CA key,
|
|
76
|
+
plugin `env` or OIDC client secret is declarable. Every family defaults to `retain` on destroy.
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
★ **Usage lives beside the code**, so it ships in the tarball with it:
|
|
79
|
+
[src/openbao/README.md](./src/openbao/README.md). What each resource does on a rename is in
|
|
80
|
+
[src/openbao/REPLACE.md](./src/openbao/REPLACE.md) — read it before changing a path or name.
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
import { BaoLoginError, appRoleLogin, revokeSelf } from '@homeflare/alchemy/openbao';
|
|
82
|
-
|
|
83
|
-
const login = await appRoleLogin({ roleId, secretId }); // mount defaults to `approle`
|
|
84
|
-
try {
|
|
85
|
-
use(login.clientToken, login.accessor, login.policies, login.leaseDurationSeconds);
|
|
86
|
-
} finally {
|
|
87
|
-
await revokeSelf(login.clientToken);
|
|
88
|
-
}
|
|
89
|
-
```
|
|
82
|
+
## launchd — `@homeflare/alchemy/launchd`
|
|
90
83
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- ⚠️ A value with leading or trailing whitespace is refused, not trimmed. `Bun.file().text()`
|
|
96
|
-
keeps a file's trailing newline.
|
|
97
|
-
- `reason` is `input`, `refused`, `unreachable` or `response`. Pass `env` to use something other
|
|
98
|
-
than `process.env`. `appRoleLoginEffect` / `revokeSelfEffect` are the same calls as Effects.
|
|
99
|
-
|
|
100
|
-
### BaoPlugin
|
|
101
|
-
|
|
102
|
-
```ts
|
|
103
|
-
import { BaoPlugin } from '@homeflare/alchemy/openbao';
|
|
104
|
-
import * as Effect from 'effect/Effect';
|
|
105
|
-
|
|
106
|
-
export const plugins = Effect.gen(function* () {
|
|
107
|
-
yield* BaoPlugin('plugin-example', {
|
|
108
|
-
name: 'openbao-plugin-secrets-example',
|
|
109
|
-
type: 'secret', // 'secret' | 'auth' | 'database'
|
|
110
|
-
command: 'openbao-plugin-secrets-example', // a bare file name in plugin_directory
|
|
111
|
-
sha256: '<hex sha256 of that file>',
|
|
112
|
-
version: 'v0.1.2', // canonical semver
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
```
|
|
84
|
+
`LaunchdJob` and `HostFile` declare a Mac host's daemons and their config files. launchd has no SDK,
|
|
85
|
+
so the provider renders the plist and drives `launchctl`, all through one injectable `HostRunner`;
|
|
86
|
+
`launchdProviders()` provides both. An update restarts the job; a `label`/`domain` change replaces it
|
|
87
|
+
delete-first.
|
|
116
88
|
|
|
117
|
-
- ⛔
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
one, so reconcile then refuses because the read-back finds nothing.
|
|
121
|
-
- ⚠️ A new `sha256` does not restart running mounts. Reload with `sys/plugins/reload/backend`.
|
|
122
|
-
- The deploying token needs `sudo` on `sys/plugins/catalog/*`.
|
|
89
|
+
- ⛔ **No secrets in props** (state is unencrypted): declare the path a secret renderer writes.
|
|
90
|
+
- ⛔ **No silent sudo:** the system domain needs a deploy started as root, or a `privileged` runner.
|
|
91
|
+
- ⚠️ `org.nixos.*` jobs are never adopted. Guide and nix-darwin cutover: [docs/launchd.md](./docs/launchd.md).
|
|
123
92
|
|
|
124
93
|
## Credentials
|
|
125
94
|
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* import { BaoMount } from '@homeflare/alchemy/openbao';
|
|
10
10
|
* import { TalosCluster } from '@homeflare/alchemy/talos';
|
|
11
11
|
* import { ProxmoxAcl } from '@homeflare/alchemy/proxmox';
|
|
12
|
+
* import { LaunchdJob } from '@homeflare/alchemy/launchd';
|
|
12
13
|
*
|
|
13
14
|
* ★ WHY THESE EXIST AT ALL. When Alchemy has no resource for something, the alternative
|
|
14
15
|
* is a runbook step a human runs once — and a plan can never show a missing runbook
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ExecResult, FileStat, HostRunner, HostUser } from './runner.ts';
|
|
2
|
+
type Entry = {
|
|
3
|
+
bytes: Uint8Array;
|
|
4
|
+
mode: number;
|
|
5
|
+
uid: number;
|
|
6
|
+
gid: number;
|
|
7
|
+
kind: FileStat['kind'];
|
|
8
|
+
};
|
|
9
|
+
export type FakeOptions = {
|
|
10
|
+
euid?: number;
|
|
11
|
+
privileged?: boolean;
|
|
12
|
+
/** Directories that exist, and their owner uid. */
|
|
13
|
+
dirs?: Record<string, number>;
|
|
14
|
+
users?: Record<string, HostUser>;
|
|
15
|
+
groups?: Record<string, number>;
|
|
16
|
+
};
|
|
17
|
+
export declare const fakeRunner: (options?: FakeOptions) => {
|
|
18
|
+
calls: string[][];
|
|
19
|
+
disabled: Set<string>;
|
|
20
|
+
dirs: Map<string, number>;
|
|
21
|
+
files: Map<string, Entry>;
|
|
22
|
+
loaded: Map<string, number | undefined>;
|
|
23
|
+
runner: HostRunner;
|
|
24
|
+
state: {
|
|
25
|
+
lingerPrints: number;
|
|
26
|
+
nextPid: number;
|
|
27
|
+
bootstrapFailure: ExecResult | undefined;
|
|
28
|
+
/** Returned by bootout in place of success. The job still goes, unless `bootoutKeepsJob`. */
|
|
29
|
+
bootoutFailure: ExecResult | undefined;
|
|
30
|
+
bootoutKeepsJob: boolean;
|
|
31
|
+
/** gui uids with no login session: every launchctl call into `gui/<uid>` exits 112. */
|
|
32
|
+
loggedOut: Set<number>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=fake-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-runner.d.ts","sourceRoot":"","sources":["../../src/launchd/fake-runner.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAgB,MAAM,aAAa,CAAC;AAE5F,KAAK,KAAK,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAEnG,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AA0BF,eAAO,MAAM,UAAU,aAAa,WAAW;;;;;;;;;;0BAaZ,UAAU,GAAG,SAAS;QACrD,6FAA6F;wBAChE,UAAU,GAAG,SAAS;;QAEnD,uFAAuF;;;CA4G1F,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one place a HostRunner's promises become Effects — plus the one probe of an unresolved
|
|
3
|
+
* `news` both providers' diffs share.
|
|
4
|
+
*
|
|
5
|
+
* ★ The lifecycle files are plain async functions over a HostRunner (see runner.ts for why the
|
|
6
|
+
* runner is promise-based), so each provider handler is a single `lift(() => step(runner, …))`.
|
|
7
|
+
* ⚠️ A thrown Error stays that Error — its message is the refusal a deploy prints. Anything else
|
|
8
|
+
* thrown is wrapped, so the failure channel is always an Error with a readable message.
|
|
9
|
+
*/
|
|
10
|
+
import * as Effect from 'effect/Effect';
|
|
11
|
+
export declare const lift: <A>(step: () => Promise<A>) => Effect.Effect<A, Error>;
|
|
12
|
+
/**
|
|
13
|
+
* A string prop of a diff's `news`, when that one prop is already resolved; `undefined` while it
|
|
14
|
+
* is still an Output (a function-typed proxy), an Effect or a Config.
|
|
15
|
+
* ★ For the identity props a diff must see even when the rest of `news` is unresolved — a plain
|
|
16
|
+
* string is resolved by definition, so `typeof` is the whole test.
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolvedString: (news: unknown, key: string) => string | undefined;
|
|
19
|
+
//# sourceMappingURL=host-effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-effect.d.ts","sourceRoot":"","sources":["../../src/launchd/host-effect.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,eAAO,MAAM,IAAI,GAAI,CAAC,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAInE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,cAAc,SAAU,OAAO,OAAO,MAAM,KAAG,MAAM,GAAG,SAIpE,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface HostFileProps {
|
|
2
|
+
/** Absolute path. The parent directory must already exist. */
|
|
3
|
+
path: string;
|
|
4
|
+
/** UTF-8 text. ⛔ Never a secret — see the file header. */
|
|
5
|
+
content: string;
|
|
6
|
+
/** Permission bits. @default 0o644 */
|
|
7
|
+
mode?: number;
|
|
8
|
+
/** User name or numeric uid. Omitted: whoever the runner writes as (a rewrite keeps no owner). */
|
|
9
|
+
owner?: string | number;
|
|
10
|
+
/** Group name or numeric gid. Omitted: the directory's default group. */
|
|
11
|
+
group?: string | number;
|
|
12
|
+
}
|
|
13
|
+
export interface HostFileAttributes {
|
|
14
|
+
path: string;
|
|
15
|
+
/** SHA-256 of the bytes on disk. */
|
|
16
|
+
sha256: string;
|
|
17
|
+
mode: number;
|
|
18
|
+
uid: number;
|
|
19
|
+
gid: number;
|
|
20
|
+
size: number;
|
|
21
|
+
}
|
|
22
|
+
export declare const DEFAULT_MODE = 420;
|
|
23
|
+
export declare const fileProblems: (props: HostFileProps) => string[];
|
|
24
|
+
//# sourceMappingURL=host-file-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-file-form.d.ts","sourceRoot":"","sources":["../../src/launchd/host-file-form.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,YAAY,MAAQ,CAAC;AAclC,eAAO,MAAM,YAAY,UAAW,aAAa,KAAG,MAAM,EAsBzD,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HostFile's read / diff / reconcile / delete as plain async functions over a HostRunner, so the
|
|
3
|
+
* lifecycle runs against fake-runner.ts in tests.
|
|
4
|
+
*
|
|
5
|
+
* ⛔ SYMLINKS AND DIRECTORIES ARE REFUSED, NOT REPLACED. rename(2) over a symlink replaces the LINK,
|
|
6
|
+
* so a path that is a symlink (nix-darwin's /etc entries point into /nix/store) would be quietly
|
|
7
|
+
* taken from the tool that owns it — which puts it back, or refuses its next activation. Remove
|
|
8
|
+
* the path from its owner first, then declare it here.
|
|
9
|
+
*/
|
|
10
|
+
import type { Diff } from 'alchemy/Diff';
|
|
11
|
+
import { type HostFileAttributes, type HostFileProps } from './host-file-form.ts';
|
|
12
|
+
import { type HostRunner } from './runner.ts';
|
|
13
|
+
type Desired = {
|
|
14
|
+
readonly bytes: Uint8Array;
|
|
15
|
+
readonly sha256: string;
|
|
16
|
+
readonly mode: number;
|
|
17
|
+
readonly uid?: number;
|
|
18
|
+
readonly gid?: number;
|
|
19
|
+
};
|
|
20
|
+
/** Validate, then resolve owner/group names to ids through the runner. */
|
|
21
|
+
export declare const desiredFile: (runner: HostRunner, props: HostFileProps) => Promise<Desired>;
|
|
22
|
+
/** The file as it is now, or `undefined` when nothing is at the path. Non-files read with no digest. */
|
|
23
|
+
export declare const readFileAttributes: (runner: HostRunner, path: string) => Promise<HostFileAttributes | undefined>;
|
|
24
|
+
export declare const diffFile: (runner: HostRunner, news: HostFileProps, output: HostFileAttributes) => Promise<Diff>;
|
|
25
|
+
export declare const reconcileFile: (runner: HostRunner, props: HostFileProps, output?: HostFileAttributes) => Promise<HostFileAttributes>;
|
|
26
|
+
/** Remove the file. Idempotent. ⛔ Refuses a path that has since become a symlink or directory. */
|
|
27
|
+
export declare const deleteFile: (runner: HostRunner, output: HostFileAttributes) => Promise<void>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=host-file-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-file-lifecycle.d.ts","sourceRoot":"","sources":["../../src/launchd/host-file-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,UAAU,EAAgB,MAAM,aAAa,CAAC;AAE5D,KAAK,OAAO,GAAG;IACb,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAOF,0EAA0E;AAC1E,eAAO,MAAM,WAAW,WAAkB,UAAU,SAAS,aAAa,KAAG,OAAO,CAAC,OAAO,CAqB3F,CAAC;AAEF,wGAAwG;AACxG,eAAO,MAAM,kBAAkB,WACrB,UAAU,QACZ,MAAM,KACX,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAYxC,CAAC;AAQF,eAAO,MAAM,QAAQ,WACX,UAAU,QACZ,aAAa,UACX,kBAAkB,KACzB,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF,eAAO,MAAM,aAAa,WAChB,UAAU,SACX,aAAa,WACX,kBAAkB,KAC1B,OAAO,CAAC,kBAAkB,CA0D5B,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,UAAU,WAAkB,UAAU,UAAU,kBAAkB,KAAG,OAAO,CAAC,IAAI,CAK7F,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Host.File` — one text file on the host, declared: content, mode, owner, group.
|
|
3
|
+
*
|
|
4
|
+
* - create / update — atomic write (temp file in the same directory, mode and owner set, rename),
|
|
5
|
+
* skipped when the file already matches; then read back and compared.
|
|
6
|
+
* - read — lstat plus the SHA-256 of the bytes.
|
|
7
|
+
* - diff — declared SHA-256 against the stored and on-disk digest, plus mode and owner.
|
|
8
|
+
* - replace — only when `path` changes; create-before-delete.
|
|
9
|
+
* - delete — removes the file.
|
|
10
|
+
*
|
|
11
|
+
* ⛔ NEVER A SECRET — see host-file-form.ts. Secret files stay rendered by openbao-agent.
|
|
12
|
+
* ⚠️ NOTHING IS ADOPTED WITHOUT `--adopt`: a file already at the path reads as `Unowned`.
|
|
13
|
+
* ★ IT LIVES IN THE launchd SUBPATH because the two travel together: a Mac host stack declares a
|
|
14
|
+
* daemon's config file and the daemon that reads it, through the same HostRunner.
|
|
15
|
+
*/
|
|
16
|
+
import { Resource } from 'alchemy';
|
|
17
|
+
import * as Provider from 'alchemy/Provider';
|
|
18
|
+
import type { HostFileAttributes, HostFileProps } from './host-file-form.ts';
|
|
19
|
+
import { HostRunnerService } from './runner.ts';
|
|
20
|
+
export type { HostFileAttributes, HostFileProps } from './host-file-form.ts';
|
|
21
|
+
export interface HostFile extends Resource<'Host.File', HostFileProps, HostFileAttributes> {
|
|
22
|
+
}
|
|
23
|
+
export declare const HostFile: import("alchemy").ResourceClass<HostFile>;
|
|
24
|
+
export declare const HostFileProvider: () => import("effect/Layer").Layer<Provider.Provider<HostFile>, never, HostRunnerService>;
|
|
25
|
+
//# sourceMappingURL=host-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-file.d.ts","sourceRoot":"","sources":["../../src/launchd/host-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,MAAM,WAAW,QAAS,SAAQ,QAAQ,CAAC,WAAW,EAAE,aAAa,EAAE,kBAAkB,CAAC;CAAG;AAE7F,eAAO,MAAM,QAAQ,2CAAkC,CAAC;AAExD,eAAO,MAAM,gBAAgB,2FAgC1B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User and group lookups, as argv plus a parser — split out so the parsing is tested against the
|
|
3
|
+
* real output shapes without running anything.
|
|
4
|
+
*
|
|
5
|
+
* ★ macOS FIRST, getent ELSEWHERE. macOS has no `getent`; its directory service answers through
|
|
6
|
+
* `dscacheutil`. Shape MEASURED 2026-09-21 on macOS 27.2 (read-only query):
|
|
7
|
+
*
|
|
8
|
+
* name: someone
|
|
9
|
+
* password: ********
|
|
10
|
+
* uid: 501
|
|
11
|
+
* gid: 20
|
|
12
|
+
* dir: /Users/someone
|
|
13
|
+
* shell: /bin/zsh
|
|
14
|
+
*
|
|
15
|
+
* An unknown uid printed NOTHING and exited 0 — so "no record" is an empty parse, never an
|
|
16
|
+
* exit code. `getent` exits 2 for an unknown key; that also parses as no record.
|
|
17
|
+
* ⛔ NEVER PARSE OR KEEP THE `password:` LINE. It is a placeholder on macOS, but a parser that
|
|
18
|
+
* copies every field would carry a hash from any host where it is not.
|
|
19
|
+
*/
|
|
20
|
+
import type { HostUser } from './runner.ts';
|
|
21
|
+
/** argv for looking up a user, by name or numeric id. */
|
|
22
|
+
export declare const userQuery: (platform: string, nameOrId: string) => readonly string[];
|
|
23
|
+
/** argv for looking up a group, by name or numeric id. */
|
|
24
|
+
export declare const groupQuery: (platform: string, nameOrId: string) => readonly string[];
|
|
25
|
+
export declare const parseUser: (platform: string, stdout: string) => HostUser | undefined;
|
|
26
|
+
export declare const parseGroup: (platform: string, stdout: string) => number | undefined;
|
|
27
|
+
//# sourceMappingURL=host-lookup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-lookup.d.ts","sourceRoot":"","sources":["../../src/launchd/host-lookup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,yDAAyD;AACzD,eAAO,MAAM,SAAS,aAAc,MAAM,YAAY,MAAM,KAAG,SAAS,MAAM,EAU1C,CAAC;AAErC,0DAA0D;AAC1D,eAAO,MAAM,UAAU,aAAc,MAAM,YAAY,MAAM,KAAG,SAAS,MAAM,EAU5C,CAAC;AAsBpC,eAAO,MAAM,SAAS,aAAc,MAAM,UAAU,MAAM,KAAG,QAAQ,GAAG,SAkBvE,CAAC;AAEF,eAAO,MAAM,UAAU,aAAc,MAAM,UAAU,MAAM,KAAG,MAAM,GAAG,SAItE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* launchd providers for Alchemy — declare a Mac host's jobs and their config files.
|
|
3
|
+
*
|
|
4
|
+
* ⛔ THIS BARREL IS THE PUBLIC API, AND IT IS DELIBERATELY SMALLER THAN THE DIRECTORY. The
|
|
5
|
+
* lifecycle files, the launchctl parsers and the fake runner are internals; an `export *` would
|
|
6
|
+
* publish them as API and make the next refactor a breaking change.
|
|
7
|
+
* ⛔ macOS HOSTS ONLY for LaunchdJob. HostFile and the runner work on any POSIX host, but the
|
|
8
|
+
* subpath exists for the Mac: see docs/launchd.md for the cutover from nix-darwin.
|
|
9
|
+
*/
|
|
10
|
+
export type { HostFileAttributes, HostFileProps } from './host-file.ts';
|
|
11
|
+
export { HostFile, HostFileProvider } from './host-file.ts';
|
|
12
|
+
export type { CalendarInterval, KeepAlive, LaunchdDomain, LaunchdJobAttributes, LaunchdJobProps, } from './job.ts';
|
|
13
|
+
export { LaunchdJob, LaunchdJobProvider } from './job.ts';
|
|
14
|
+
export type { LocalRunnerOptions } from './local-runner.ts';
|
|
15
|
+
export { localRunner } from './local-runner.ts';
|
|
16
|
+
export type { PlistDict, PlistValue } from './plist.ts';
|
|
17
|
+
export { PlistError, renderPlist } from './plist.ts';
|
|
18
|
+
export { launchdProviders } from './providers.ts';
|
|
19
|
+
export type { ExecResult, FileStat, HostRunner, HostUser, WriteOptions } from './runner.ts';
|
|
20
|
+
export { HostRunnerService, canActAsRoot, hostRunnerLayer } from './runner.ts';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/launchd/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|