@hasna/machines 0.0.25 → 0.0.27
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 +12 -3
- package/dist/cli/index.js +130 -19
- package/dist/commands/screen.d.ts +31 -0
- package/dist/commands/screen.d.ts.map +1 -1
- package/dist/index.js +77 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -130,6 +130,7 @@ machines screen machine005 --print # print the vnc:// URL instead of ope
|
|
|
130
130
|
machines screen machine005 --json # full resolution detail (route, confidence, user)
|
|
131
131
|
machines screen --all # open every reachable machine
|
|
132
132
|
machines screen --all --print # list resolved vnc:// URLs for the whole fleet
|
|
133
|
+
machines screen-credentials --all --check-secret
|
|
133
134
|
```
|
|
134
135
|
|
|
135
136
|
Enable Remote Management / Screen Sharing on a fresh macOS machine over SSH
|
|
@@ -137,12 +138,20 @@ Enable Remote Management / Screen Sharing on a fresh macOS machine over SSH
|
|
|
137
138
|
Screen Sharing.app and Apple Remote Desktop):
|
|
138
139
|
|
|
139
140
|
```bash
|
|
140
|
-
machines
|
|
141
|
+
secrets set hasna/xyz/opensource/machines/prod/screen-machine005-vnc-password "$VNC_PASSWORD" --type password
|
|
142
|
+
machines screen-enable --machine machine005 --user jo \
|
|
143
|
+
--vnc-password-secret hasna/xyz/opensource/machines/prod/screen-machine005-vnc-password
|
|
141
144
|
machines screen-enable --machine machine005 --user jo --print # show the SSH command, don't run it
|
|
142
145
|
```
|
|
143
146
|
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
The legacy VNC protocol honors only the first 8 password characters. The
|
|
148
|
+
password is read through the `secrets` CLI and piped over SSH stdin; it is not
|
|
149
|
+
embedded in generated command text. If `--vnc-password-secret` is omitted,
|
|
150
|
+
machines defaults to
|
|
151
|
+
`hasna/xyz/opensource/machines/prod/screen-<machine>-vnc-password`. The user
|
|
152
|
+
comes from the manifest (`metadata.user`) when present, or `--user`.
|
|
153
|
+
`screen-credentials` verifies the resolved user and secret key for a machine or
|
|
154
|
+
the full fleet without printing secret values.
|
|
146
155
|
|
|
147
156
|
Consumers that need repo paths can resolve trust-aware workspace mappings
|
|
148
157
|
without importing the full machines app:
|
package/dist/cli/index.js
CHANGED
|
@@ -9153,15 +9153,32 @@ function listPorts(machineId) {
|
|
|
9153
9153
|
}
|
|
9154
9154
|
|
|
9155
9155
|
// src/commands/screen.ts
|
|
9156
|
+
var DEFAULT_SCREEN_SECRET_NAMESPACE = "hasna/xyz/opensource/machines/prod";
|
|
9156
9157
|
function shellQuote6(value) {
|
|
9157
9158
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
9158
9159
|
}
|
|
9160
|
+
function shellCommand2(command) {
|
|
9161
|
+
return command.map(shellQuote6).join(" ");
|
|
9162
|
+
}
|
|
9163
|
+
function metadataString2(metadata, keys) {
|
|
9164
|
+
if (!metadata)
|
|
9165
|
+
return null;
|
|
9166
|
+
for (const key of keys) {
|
|
9167
|
+
const value = metadata[key];
|
|
9168
|
+
if (typeof value === "string" && value.trim())
|
|
9169
|
+
return value.trim();
|
|
9170
|
+
}
|
|
9171
|
+
return null;
|
|
9172
|
+
}
|
|
9159
9173
|
function splitTarget(target) {
|
|
9160
9174
|
const at = target.indexOf("@");
|
|
9161
9175
|
if (at === -1)
|
|
9162
9176
|
return [null, target];
|
|
9163
9177
|
return [target.slice(0, at), target.slice(at + 1)];
|
|
9164
9178
|
}
|
|
9179
|
+
function defaultScreenPasswordSecretKey(machineId) {
|
|
9180
|
+
return `${DEFAULT_SCREEN_SECRET_NAMESPACE}/screen-${machineId}-vnc-password`;
|
|
9181
|
+
}
|
|
9165
9182
|
function resolveScreenTarget(machineId, options = {}) {
|
|
9166
9183
|
const resolved = resolveMachineRoute(machineId, options);
|
|
9167
9184
|
if (!resolved.ok || !resolved.target) {
|
|
@@ -9187,15 +9204,60 @@ function resolveScreenTarget(machineId, options = {}) {
|
|
|
9187
9204
|
warnings: resolved.warnings
|
|
9188
9205
|
};
|
|
9189
9206
|
}
|
|
9190
|
-
function
|
|
9207
|
+
function resolveScreenCredentials(machineId, options = {}) {
|
|
9208
|
+
const topology = options.topology ?? discoverMachineTopology(options);
|
|
9209
|
+
const screen = resolveScreenTarget(machineId, { ...options, topology });
|
|
9210
|
+
const entry = topology.machines.find((machine) => machine.machine_id === screen.machineId);
|
|
9211
|
+
const metadata = entry?.metadata;
|
|
9212
|
+
const metadataUser = metadataString2(metadata, ["screenUser", "screen_user", "user", "username"]);
|
|
9213
|
+
const metadataPasswordSecret = metadataString2(metadata, [
|
|
9214
|
+
"screenPasswordSecret",
|
|
9215
|
+
"screen_password_secret",
|
|
9216
|
+
"screenVncPasswordSecret",
|
|
9217
|
+
"screen_vnc_password_secret",
|
|
9218
|
+
"vncPasswordSecret",
|
|
9219
|
+
"vnc_password_secret"
|
|
9220
|
+
]);
|
|
9221
|
+
const user = options.user ?? screen.user ?? metadataUser;
|
|
9222
|
+
const passwordSecretKey = options.passwordSecretKey ?? metadataPasswordSecret ?? defaultScreenPasswordSecretKey(screen.machineId);
|
|
9223
|
+
return {
|
|
9224
|
+
machineId: screen.machineId,
|
|
9225
|
+
user: user ?? null,
|
|
9226
|
+
userSource: options.user ? "option" : screen.user ? "route" : metadataUser ? "metadata" : "missing",
|
|
9227
|
+
passwordSecretKey,
|
|
9228
|
+
passwordSecretSource: options.passwordSecretKey ? "option" : metadataPasswordSecret ? "metadata" : "default"
|
|
9229
|
+
};
|
|
9230
|
+
}
|
|
9231
|
+
function buildScreenEnableRemoteCommandFromStdin(user) {
|
|
9191
9232
|
const kickstart = "/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart";
|
|
9192
|
-
const
|
|
9193
|
-
|
|
9233
|
+
const script = [
|
|
9234
|
+
"set -euo pipefail",
|
|
9235
|
+
'user="$1"',
|
|
9236
|
+
"IFS= read -r vnc_pw",
|
|
9237
|
+
'if [ -z "$vnc_pw" ]; then echo "missing VNC password on stdin" >&2; exit 1; fi',
|
|
9238
|
+
`kickstart=${shellQuote6(kickstart)}`,
|
|
9239
|
+
'dseditgroup -o edit -a "$user" -t user com.apple.access_screensharing 2>/dev/null || true',
|
|
9194
9240
|
"defaults write /Library/Preferences/com.apple.RemoteManagement AllowSRPForNetworkNodes -bool true",
|
|
9195
|
-
|
|
9196
|
-
|
|
9197
|
-
]
|
|
9198
|
-
|
|
9241
|
+
'"$kickstart" -configure -clientopts -setvnclegacy -vnclegacy yes -setvncpw -vncpw "$vnc_pw"',
|
|
9242
|
+
'"$kickstart" -activate -configure -access -on -users "$user" -privs -all -restart -agent -menu'
|
|
9243
|
+
].join(`
|
|
9244
|
+
`);
|
|
9245
|
+
return `sudo -n -p '' /bin/bash -c ${shellQuote6(script)} -- ${shellQuote6(user)}`;
|
|
9246
|
+
}
|
|
9247
|
+
function buildScreenEnableCommand(machineId, options = {}) {
|
|
9248
|
+
const credentials = resolveScreenCredentials(machineId, options);
|
|
9249
|
+
if (!credentials.user) {
|
|
9250
|
+
throw new Error(`No screen-sharing user known for ${machineId}; pass --user <name> or set metadata.user in the manifest.`);
|
|
9251
|
+
}
|
|
9252
|
+
const secretsCommand = options.secretsCommand || "secrets";
|
|
9253
|
+
const remoteCommand = buildScreenEnableRemoteCommandFromStdin(credentials.user);
|
|
9254
|
+
return {
|
|
9255
|
+
machineId: credentials.machineId,
|
|
9256
|
+
user: credentials.user,
|
|
9257
|
+
passwordSecretKey: credentials.passwordSecretKey,
|
|
9258
|
+
remoteCommand,
|
|
9259
|
+
command: `${shellCommand2([secretsCommand, "get", credentials.passwordSecretKey])} | ${buildSshCommand(machineId, remoteCommand, options)}`
|
|
9260
|
+
};
|
|
9199
9261
|
}
|
|
9200
9262
|
|
|
9201
9263
|
// src/commands/sync.ts
|
|
@@ -11221,6 +11283,19 @@ function renderSelfTestResult(result) {
|
|
|
11221
11283
|
].join(`
|
|
11222
11284
|
`);
|
|
11223
11285
|
}
|
|
11286
|
+
function checkSecretPresence(secretsCommand, key) {
|
|
11287
|
+
const result = Bun.spawnSync([secretsCommand, "get", key], {
|
|
11288
|
+
stdout: "pipe",
|
|
11289
|
+
stderr: "pipe",
|
|
11290
|
+
env: process.env
|
|
11291
|
+
});
|
|
11292
|
+
const stdout = result.stdout.toString().trim();
|
|
11293
|
+
return {
|
|
11294
|
+
checked: true,
|
|
11295
|
+
present: result.exitCode === 0 && stdout.length > 0,
|
|
11296
|
+
error: result.exitCode === 0 ? undefined : result.stderr.toString().trim() || `secrets get exited ${result.exitCode}`
|
|
11297
|
+
};
|
|
11298
|
+
}
|
|
11224
11299
|
function parseCommandSpec(value) {
|
|
11225
11300
|
const [command, expectedVersion] = value.split(":");
|
|
11226
11301
|
return {
|
|
@@ -11362,7 +11437,8 @@ manifestCommand.command("remove").description("Remove a machine from the manifes
|
|
|
11362
11437
|
console.log(JSON.stringify(manifestRemove(id), null, 2));
|
|
11363
11438
|
});
|
|
11364
11439
|
manifestCommand.command("add").description("Add or replace a machine in the fleet manifest").option("--id <id>", "Machine identifier").option("--platform <platform>", "linux | macos | windows").option("--workspace-path <path>", "Primary workspace path").option("--hostname <hostname>", "Machine hostname").option("--ssh-address <sshAddress>", "Machine SSH address").option("--tailscale-name <tailscaleName>", "Machine Tailscale DNS name").option("--connection <connection>", "local | ssh | tailscale").option("--bun-path <path>", "Bun executable directory").option("--tag <tag...>", "Machine tags").option("--package <name...>", "Desired packages").option("--app <spec...>", "Desired apps as name[:manager[:packageName]]").option("--file <spec...>", "File sync spec source:target[:copy|symlink]").option("--metadata <json>", "Machine metadata as JSON").option("--from-stdin", "Read the full MachineManifest JSON from stdin").action((options) => {
|
|
11365
|
-
|
|
11440
|
+
const fromStdin = Boolean(options["fromStdin"] || options["from-stdin"]);
|
|
11441
|
+
if (fromStdin) {
|
|
11366
11442
|
if (process.stdin.isTTY) {
|
|
11367
11443
|
console.error("error: --from-stdin requires piped input");
|
|
11368
11444
|
process.exit(1);
|
|
@@ -11726,23 +11802,58 @@ program2.command("screen").description("Open Screen Sharing (VNC) to a machine u
|
|
|
11726
11802
|
execFileSync("open", [resolved.url], { stdio: "ignore" });
|
|
11727
11803
|
console.log(`Opening Screen Sharing \u2192 ${resolved.url} (route: ${resolved.route})`);
|
|
11728
11804
|
});
|
|
11729
|
-
program2.command("screen-
|
|
11730
|
-
const
|
|
11731
|
-
const
|
|
11732
|
-
if (
|
|
11733
|
-
console.error(
|
|
11805
|
+
program2.command("screen-credentials").description("Inspect screen-sharing user and password secret references without printing secrets").option("--machine <id>", "Machine identifier").option("--all", "Inspect every discovered machine", false).option("--check-secret", "Check whether the password secret exists in the local secrets vault", false).option("--secrets-command <command>", "Secrets CLI command to inspect", "secrets").option("--no-tailscale", "Skip tailscale status probing").option("-j, --json", "Print JSON output", false).action((options) => {
|
|
11806
|
+
const topology = discoverMachineTopology({ includeTailscale: options.tailscale !== false });
|
|
11807
|
+
const machineIds = options.all ? topology.machines.map((machine) => machine.machine_id) : [options.machine].filter((machine) => Boolean(machine));
|
|
11808
|
+
if (machineIds.length === 0) {
|
|
11809
|
+
console.error("Provide --machine <id> or --all");
|
|
11734
11810
|
process.exitCode = 1;
|
|
11735
11811
|
return;
|
|
11736
11812
|
}
|
|
11737
|
-
const
|
|
11738
|
-
|
|
11739
|
-
|
|
11813
|
+
const results = machineIds.map((machineId) => {
|
|
11814
|
+
try {
|
|
11815
|
+
const credentials = resolveScreenCredentials(machineId, { topology });
|
|
11816
|
+
const secret = options.checkSecret ? checkSecretPresence(options.secretsCommand, credentials.passwordSecretKey) : { checked: false, present: null };
|
|
11817
|
+
return { ok: true, ...credentials, passwordSecret: secret };
|
|
11818
|
+
} catch (error) {
|
|
11819
|
+
return { ok: false, machineId, error: error instanceof Error ? error.message : String(error) };
|
|
11820
|
+
}
|
|
11821
|
+
});
|
|
11822
|
+
const hasFailures = results.some((result) => !result.ok || result.ok && result.passwordSecret.checked && !result.passwordSecret.present);
|
|
11823
|
+
if (options.json) {
|
|
11824
|
+
console.log(JSON.stringify(results, null, 2));
|
|
11825
|
+
if (hasFailures)
|
|
11826
|
+
process.exitCode = 1;
|
|
11827
|
+
return;
|
|
11828
|
+
}
|
|
11829
|
+
for (const result of results) {
|
|
11830
|
+
if (!result.ok) {
|
|
11831
|
+
console.log(`\u2717 ${result.machineId.padEnd(14)} ${result.error}`);
|
|
11832
|
+
continue;
|
|
11833
|
+
}
|
|
11834
|
+
const secret = result.passwordSecret.checked ? result.passwordSecret.present ? source_default.green("present") : source_default.red("missing") : source_default.yellow("unchecked");
|
|
11835
|
+
console.log(`${result.machineId.padEnd(14)} user=${result.user ?? "(missing)"} passwordSecret=${result.passwordSecretKey} (${secret})`);
|
|
11836
|
+
}
|
|
11837
|
+
if (hasFailures)
|
|
11838
|
+
process.exitCode = 1;
|
|
11839
|
+
});
|
|
11840
|
+
program2.command("screen-enable").description("Enable Remote Management / Screen Sharing on a macOS machine over SSH").requiredOption("--machine <id>", "Machine identifier").option("--user <user>", "macOS user to grant screen-sharing (overrides manifest)").option("--vnc-password-secret <key>", "Secret key containing the legacy VNC password").option("--secrets-command <command>", "Secrets CLI command to read the password", "secrets").option("--vnc-password <pw>", "Deprecated: use --vnc-password-secret instead", "").option("--print", "Print the remote command instead of running it", false).action((options) => {
|
|
11841
|
+
if (options.vncPassword) {
|
|
11842
|
+
console.error("Direct --vnc-password values are not accepted. Store the password with `secrets set` and pass --vnc-password-secret.");
|
|
11843
|
+
process.exitCode = 1;
|
|
11844
|
+
return;
|
|
11845
|
+
}
|
|
11846
|
+
const plan = buildScreenEnableCommand(options.machine, {
|
|
11847
|
+
user: options.user,
|
|
11848
|
+
passwordSecretKey: options.vncPasswordSecret,
|
|
11849
|
+
secretsCommand: options.secretsCommand
|
|
11850
|
+
});
|
|
11740
11851
|
if (options.print) {
|
|
11741
|
-
console.log(
|
|
11852
|
+
console.log(plan.command);
|
|
11742
11853
|
return;
|
|
11743
11854
|
}
|
|
11744
|
-
console.log(`Run this to enable Screen Sharing on ${options.machine} (
|
|
11745
|
-
console.log(` ${
|
|
11855
|
+
console.log(`Run this to enable Screen Sharing on ${options.machine} (password comes from ${plan.passwordSecretKey}):`);
|
|
11856
|
+
console.log(` ${plan.command}`);
|
|
11746
11857
|
});
|
|
11747
11858
|
program2.command("ports").description("List listening ports on a machine").option("--machine <id>", "Machine identifier").option("-j, --json", "Print JSON output", false).action((options) => {
|
|
11748
11859
|
const result = listPorts(options.machine);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type MachineRouteOptions, type MachineRouteKind, type MachineRouteConfidence } from "../topology.js";
|
|
2
|
+
export declare const DEFAULT_SCREEN_SECRET_NAMESPACE = "hasna/xyz/opensource/machines/prod";
|
|
2
3
|
export interface ResolvedScreenTarget {
|
|
3
4
|
machineId: string;
|
|
4
5
|
user: string | null;
|
|
@@ -8,12 +9,35 @@ export interface ResolvedScreenTarget {
|
|
|
8
9
|
confidence: MachineRouteConfidence;
|
|
9
10
|
warnings: string[];
|
|
10
11
|
}
|
|
12
|
+
export interface ScreenCredentialResolution {
|
|
13
|
+
machineId: string;
|
|
14
|
+
user: string | null;
|
|
15
|
+
userSource: "option" | "route" | "metadata" | "missing";
|
|
16
|
+
passwordSecretKey: string;
|
|
17
|
+
passwordSecretSource: "option" | "metadata" | "default";
|
|
18
|
+
}
|
|
19
|
+
export interface ScreenEnableCommandPlan {
|
|
20
|
+
machineId: string;
|
|
21
|
+
user: string;
|
|
22
|
+
passwordSecretKey: string;
|
|
23
|
+
remoteCommand: string;
|
|
24
|
+
command: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ScreenCredentialOptions extends MachineRouteOptions {
|
|
27
|
+
user?: string;
|
|
28
|
+
passwordSecretKey?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ScreenEnableCommandOptions extends ScreenCredentialOptions {
|
|
31
|
+
secretsCommand?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function defaultScreenPasswordSecretKey(machineId: string): string;
|
|
11
34
|
/**
|
|
12
35
|
* Resolve the best screen-sharing (VNC) target for a machine.
|
|
13
36
|
* Prefers the live LAN route over Tailscale (lower latency for screen sharing),
|
|
14
37
|
* and always produces a `vnc://user@host` URL when a user is known.
|
|
15
38
|
*/
|
|
16
39
|
export declare function resolveScreenTarget(machineId: string, options?: MachineRouteOptions): ResolvedScreenTarget;
|
|
40
|
+
export declare function resolveScreenCredentials(machineId: string, options?: ScreenCredentialOptions): ScreenCredentialResolution;
|
|
17
41
|
/**
|
|
18
42
|
* Build the macOS command that opens Screen Sharing to a machine.
|
|
19
43
|
* `open vnc://user@host` launches Screen Sharing.app pointed at the resolved route.
|
|
@@ -32,4 +56,11 @@ export declare function buildScreenCommand(machineId: string, options?: MachineR
|
|
|
32
56
|
* password or runs under an already-root context).
|
|
33
57
|
*/
|
|
34
58
|
export declare function buildScreenEnableRemoteCommand(user: string, vncPassword: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Build the remote root command used by secure screen-enable plans.
|
|
61
|
+
* The VNC password is read from stdin so it is not embedded in shell history,
|
|
62
|
+
* generated command text, or the SSH remote command arguments.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildScreenEnableRemoteCommandFromStdin(user: string): string;
|
|
65
|
+
export declare function buildScreenEnableCommand(machineId: string, options?: ScreenEnableCommandOptions): ScreenEnableCommandPlan;
|
|
35
66
|
//# sourceMappingURL=screen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/commands/screen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/commands/screen.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,+BAA+B,uCAAuC,CAAC;AAEpF,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,gBAAgB,CAAC;IACxB,UAAU,EAAE,sBAAsB,CAAC;IACnC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACxD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;CACzD;AAED,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA2B,SAAQ,uBAAuB;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA6BD,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,oBAAoB,CA+B9G;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,GAAG,0BAA0B,CAwB7H;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAG/F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAcxF;AAED;;;;GAIG;AACH,wBAAgB,uCAAuC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAe5E;AAED,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,uBAAuB,CAc7H"}
|
package/dist/index.js
CHANGED
|
@@ -13859,15 +13859,32 @@ function runSetup(machineId, options = {}) {
|
|
|
13859
13859
|
return summary;
|
|
13860
13860
|
}
|
|
13861
13861
|
// src/commands/screen.ts
|
|
13862
|
+
var DEFAULT_SCREEN_SECRET_NAMESPACE = "hasna/xyz/opensource/machines/prod";
|
|
13862
13863
|
function shellQuote7(value) {
|
|
13863
13864
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
13864
13865
|
}
|
|
13866
|
+
function shellCommand2(command) {
|
|
13867
|
+
return command.map(shellQuote7).join(" ");
|
|
13868
|
+
}
|
|
13869
|
+
function metadataString2(metadata, keys) {
|
|
13870
|
+
if (!metadata)
|
|
13871
|
+
return null;
|
|
13872
|
+
for (const key of keys) {
|
|
13873
|
+
const value = metadata[key];
|
|
13874
|
+
if (typeof value === "string" && value.trim())
|
|
13875
|
+
return value.trim();
|
|
13876
|
+
}
|
|
13877
|
+
return null;
|
|
13878
|
+
}
|
|
13865
13879
|
function splitTarget(target) {
|
|
13866
13880
|
const at = target.indexOf("@");
|
|
13867
13881
|
if (at === -1)
|
|
13868
13882
|
return [null, target];
|
|
13869
13883
|
return [target.slice(0, at), target.slice(at + 1)];
|
|
13870
13884
|
}
|
|
13885
|
+
function defaultScreenPasswordSecretKey(machineId) {
|
|
13886
|
+
return `${DEFAULT_SCREEN_SECRET_NAMESPACE}/screen-${machineId}-vnc-password`;
|
|
13887
|
+
}
|
|
13871
13888
|
function resolveScreenTarget(machineId, options = {}) {
|
|
13872
13889
|
const resolved = resolveMachineRoute(machineId, options);
|
|
13873
13890
|
if (!resolved.ok || !resolved.target) {
|
|
@@ -13893,6 +13910,30 @@ function resolveScreenTarget(machineId, options = {}) {
|
|
|
13893
13910
|
warnings: resolved.warnings
|
|
13894
13911
|
};
|
|
13895
13912
|
}
|
|
13913
|
+
function resolveScreenCredentials(machineId, options = {}) {
|
|
13914
|
+
const topology = options.topology ?? discoverMachineTopology(options);
|
|
13915
|
+
const screen = resolveScreenTarget(machineId, { ...options, topology });
|
|
13916
|
+
const entry = topology.machines.find((machine) => machine.machine_id === screen.machineId);
|
|
13917
|
+
const metadata = entry?.metadata;
|
|
13918
|
+
const metadataUser = metadataString2(metadata, ["screenUser", "screen_user", "user", "username"]);
|
|
13919
|
+
const metadataPasswordSecret = metadataString2(metadata, [
|
|
13920
|
+
"screenPasswordSecret",
|
|
13921
|
+
"screen_password_secret",
|
|
13922
|
+
"screenVncPasswordSecret",
|
|
13923
|
+
"screen_vnc_password_secret",
|
|
13924
|
+
"vncPasswordSecret",
|
|
13925
|
+
"vnc_password_secret"
|
|
13926
|
+
]);
|
|
13927
|
+
const user = options.user ?? screen.user ?? metadataUser;
|
|
13928
|
+
const passwordSecretKey = options.passwordSecretKey ?? metadataPasswordSecret ?? defaultScreenPasswordSecretKey(screen.machineId);
|
|
13929
|
+
return {
|
|
13930
|
+
machineId: screen.machineId,
|
|
13931
|
+
user: user ?? null,
|
|
13932
|
+
userSource: options.user ? "option" : screen.user ? "route" : metadataUser ? "metadata" : "missing",
|
|
13933
|
+
passwordSecretKey,
|
|
13934
|
+
passwordSecretSource: options.passwordSecretKey ? "option" : metadataPasswordSecret ? "metadata" : "default"
|
|
13935
|
+
};
|
|
13936
|
+
}
|
|
13896
13937
|
function buildScreenCommand(machineId, options = {}) {
|
|
13897
13938
|
const resolved = resolveScreenTarget(machineId, options);
|
|
13898
13939
|
return `open ${resolved.url}`;
|
|
@@ -13907,6 +13948,37 @@ function buildScreenEnableRemoteCommand(user, vncPassword) {
|
|
|
13907
13948
|
];
|
|
13908
13949
|
return lines.join(" && ");
|
|
13909
13950
|
}
|
|
13951
|
+
function buildScreenEnableRemoteCommandFromStdin(user) {
|
|
13952
|
+
const kickstart = "/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart";
|
|
13953
|
+
const script = [
|
|
13954
|
+
"set -euo pipefail",
|
|
13955
|
+
'user="$1"',
|
|
13956
|
+
"IFS= read -r vnc_pw",
|
|
13957
|
+
'if [ -z "$vnc_pw" ]; then echo "missing VNC password on stdin" >&2; exit 1; fi',
|
|
13958
|
+
`kickstart=${shellQuote7(kickstart)}`,
|
|
13959
|
+
'dseditgroup -o edit -a "$user" -t user com.apple.access_screensharing 2>/dev/null || true',
|
|
13960
|
+
"defaults write /Library/Preferences/com.apple.RemoteManagement AllowSRPForNetworkNodes -bool true",
|
|
13961
|
+
'"$kickstart" -configure -clientopts -setvnclegacy -vnclegacy yes -setvncpw -vncpw "$vnc_pw"',
|
|
13962
|
+
'"$kickstart" -activate -configure -access -on -users "$user" -privs -all -restart -agent -menu'
|
|
13963
|
+
].join(`
|
|
13964
|
+
`);
|
|
13965
|
+
return `sudo -n -p '' /bin/bash -c ${shellQuote7(script)} -- ${shellQuote7(user)}`;
|
|
13966
|
+
}
|
|
13967
|
+
function buildScreenEnableCommand(machineId, options = {}) {
|
|
13968
|
+
const credentials = resolveScreenCredentials(machineId, options);
|
|
13969
|
+
if (!credentials.user) {
|
|
13970
|
+
throw new Error(`No screen-sharing user known for ${machineId}; pass --user <name> or set metadata.user in the manifest.`);
|
|
13971
|
+
}
|
|
13972
|
+
const secretsCommand = options.secretsCommand || "secrets";
|
|
13973
|
+
const remoteCommand = buildScreenEnableRemoteCommandFromStdin(credentials.user);
|
|
13974
|
+
return {
|
|
13975
|
+
machineId: credentials.machineId,
|
|
13976
|
+
user: credentials.user,
|
|
13977
|
+
passwordSecretKey: credentials.passwordSecretKey,
|
|
13978
|
+
remoteCommand,
|
|
13979
|
+
command: `${shellCommand2([secretsCommand, "get", credentials.passwordSecretKey])} | ${buildSshCommand(machineId, remoteCommand, options)}`
|
|
13980
|
+
};
|
|
13981
|
+
}
|
|
13910
13982
|
// src/commands/sync.ts
|
|
13911
13983
|
import { existsSync as existsSync7, lstatSync, readFileSync as readFileSync5, symlinkSync, copyFileSync } from "fs";
|
|
13912
13984
|
import { homedir as homedir5 } from "os";
|
|
@@ -23362,6 +23434,7 @@ export {
|
|
|
23362
23434
|
resolveTables,
|
|
23363
23435
|
resolveSshTarget,
|
|
23364
23436
|
resolveScreenTarget,
|
|
23437
|
+
resolveScreenCredentials,
|
|
23365
23438
|
resolveMachineWorkspace,
|
|
23366
23439
|
resolveMachineRoute,
|
|
23367
23440
|
resolveBackupTarget,
|
|
@@ -23425,6 +23498,7 @@ export {
|
|
|
23425
23498
|
diffClaudeCli,
|
|
23426
23499
|
diffApps,
|
|
23427
23500
|
detectCurrentMachineManifest,
|
|
23501
|
+
defaultScreenPasswordSecretKey,
|
|
23428
23502
|
createMcpServer,
|
|
23429
23503
|
createMachineResolverSnapshot,
|
|
23430
23504
|
countRuns,
|
|
@@ -23435,7 +23509,9 @@ export {
|
|
|
23435
23509
|
buildSshCommand,
|
|
23436
23510
|
buildSetupPlan,
|
|
23437
23511
|
buildServer,
|
|
23512
|
+
buildScreenEnableRemoteCommandFromStdin,
|
|
23438
23513
|
buildScreenEnableRemoteCommand,
|
|
23514
|
+
buildScreenEnableCommand,
|
|
23439
23515
|
buildScreenCommand,
|
|
23440
23516
|
buildClaudeInstallPlan,
|
|
23441
23517
|
buildCertPlan,
|
|
@@ -23465,6 +23541,7 @@ export {
|
|
|
23465
23541
|
MACHINES_BACKUP_PREFIX_ENV,
|
|
23466
23542
|
MACHINES_BACKUP_BUCKET_FALLBACK_ENV,
|
|
23467
23543
|
MACHINES_BACKUP_BUCKET_ENV,
|
|
23544
|
+
DEFAULT_SCREEN_SECRET_NAMESPACE,
|
|
23468
23545
|
DEFAULT_MACHINE_RESOLVER_TTL_MS,
|
|
23469
23546
|
DEFAULT_BACKUP_PREFIX,
|
|
23470
23547
|
CROSSREFS_KEY
|