@hasna/machines 0.0.33 → 0.0.35

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/dist/consumer.js CHANGED
@@ -4186,7 +4186,103 @@ var coerce = {
4186
4186
  date: (arg) => ZodDate.create({ ...arg, coerce: true })
4187
4187
  };
4188
4188
  var NEVER = INVALID;
4189
+ // src/redaction.ts
4190
+ var REDACTED_VALUE = "[redacted]";
4191
+ var SENSITIVE_KEY_PATTERN = /(password|passwd|token|credential|private[_-]?key|privateKey|api[_-]?key|github.*key|pem|secret)/i;
4192
+ var SECRET_REFERENCE_KEY_PATTERN = /(secret(ref(erence)?|key)?|secretRef|secretKey)$/i;
4193
+ var SENSITIVE_VALUE_PATTERNS = [
4194
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
4195
+ /\bghp_[A-Za-z0-9_]{20,}\b/,
4196
+ /\bgithub_pat_[A-Za-z0-9_]{20,}\b/,
4197
+ /\bxox[baprs]-[A-Za-z0-9-]{20,}\b/,
4198
+ /\bAKIA[0-9A-Z]{16}\b/,
4199
+ /\bsk-[A-Za-z0-9_-]{20,}\b/
4200
+ ];
4201
+ function isSensitiveKey(key) {
4202
+ return SENSITIVE_KEY_PATTERN.test(key);
4203
+ }
4204
+ function isSecretReferenceKey(key) {
4205
+ return SECRET_REFERENCE_KEY_PATTERN.test(key);
4206
+ }
4207
+ function looksSensitiveString(value) {
4208
+ return SENSITIVE_VALUE_PATTERNS.some((pattern) => pattern.test(value));
4209
+ }
4210
+ function isRecord(value) {
4211
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4212
+ }
4213
+ function redactPath(value) {
4214
+ return value.replace(/\/home\/[^/\s]+/g, "/home/<user>").replace(/\/Users\/[^/\s]+/g, "/Users/<user>").replace(/[A-Za-z]:\\Users\\[^\\\s]+/g, "C:\\Users\\<user>");
4215
+ }
4216
+ function redactPrivateRef(value) {
4217
+ const trimmed = value.trim();
4218
+ const scheme = trimmed.match(/^([a-z][a-z0-9+.-]*:\/\/)/i);
4219
+ if (scheme)
4220
+ return `${scheme[1]}<redacted>`;
4221
+ const colon = trimmed.match(/^([a-z][a-z0-9+.-]*):/i);
4222
+ if (colon)
4223
+ return `${colon[1]}:<redacted>`;
4224
+ return "<private-manifest-ref:redacted>";
4225
+ }
4226
+ function redactIdentifier(value) {
4227
+ return value.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 80) || "adapter";
4228
+ }
4229
+ function redactSensitiveValue(value, key = "") {
4230
+ if (typeof value === "string") {
4231
+ if (isSensitiveKey(key) && !(isSecretReferenceKey(key) && !looksSensitiveString(value))) {
4232
+ return REDACTED_VALUE;
4233
+ }
4234
+ if (looksSensitiveString(value))
4235
+ return REDACTED_VALUE;
4236
+ return redactPath(value);
4237
+ }
4238
+ if (Array.isArray(value)) {
4239
+ return value.map((entry) => redactSensitiveValue(entry, key));
4240
+ }
4241
+ if (isRecord(value)) {
4242
+ const redacted = {};
4243
+ for (const [entryKey, entryValue] of Object.entries(value)) {
4244
+ redacted[entryKey] = redactSensitiveValue(entryValue, entryKey);
4245
+ }
4246
+ return redacted;
4247
+ }
4248
+ return value;
4249
+ }
4250
+ function publicMetadataKeys(metadata) {
4251
+ return Object.keys(metadata ?? {}).filter((key) => !isSensitiveKey(key)).sort();
4252
+ }
4253
+ function redactMetadata(metadata) {
4254
+ return redactSensitiveValue(metadata ?? {});
4255
+ }
4256
+ function redactManifestForDiagnostics(machine) {
4257
+ const metadata = redactMetadata(machine.metadata);
4258
+ for (const key of ["user", "username", "login"]) {
4259
+ if (typeof metadata[key] === "string")
4260
+ metadata[key] = REDACTED_VALUE;
4261
+ }
4262
+ return {
4263
+ id: machine.id,
4264
+ hostname: machine.hostname ? REDACTED_VALUE : undefined,
4265
+ sshAddress: machine.sshAddress ? REDACTED_VALUE : undefined,
4266
+ tailscaleName: machine.tailscaleName ? REDACTED_VALUE : undefined,
4267
+ platform: machine.platform,
4268
+ connection: machine.connection,
4269
+ workspacePath: redactPath(machine.workspacePath),
4270
+ bunPath: machine.bunPath ? redactPath(machine.bunPath) : undefined,
4271
+ tags: machine.tags ?? [],
4272
+ metadata,
4273
+ packages: machine.packages?.map((pkg) => ({ ...pkg })),
4274
+ apps: machine.apps?.map((app) => ({ ...app })),
4275
+ files: machine.files?.map((file) => ({
4276
+ ...file,
4277
+ source: redactPath(file.source),
4278
+ target: redactPath(file.target)
4279
+ }))
4280
+ };
4281
+ }
4282
+
4189
4283
  // src/manifests.ts
4284
+ var PRIVATE_MANIFEST_REF_ENV = "HASNA_MACHINES_PRIVATE_MANIFEST_REF";
4285
+ var PRIVATE_MANIFEST_BACKEND_ENV = "HASNA_MACHINES_PRIVATE_MANIFEST_BACKEND";
4190
4286
  var packageSchema = exports_external.object({
4191
4287
  name: exports_external.string(),
4192
4288
  manager: exports_external.enum(["bun", "brew", "apt", "custom"]).optional(),
@@ -4239,6 +4335,42 @@ function normalizePlatform() {
4239
4335
  function normalizeMachines(machines) {
4240
4336
  return [...machines].sort((left, right) => left.id.localeCompare(right.id));
4241
4337
  }
4338
+ function inferPrivateBackend(rawRef, explicitBackend) {
4339
+ if (explicitBackend?.trim())
4340
+ return explicitBackend.trim();
4341
+ const scheme = rawRef.trim().match(/^([a-z][a-z0-9+.-]*)(?::\/\/|:)/i);
4342
+ return scheme?.[1] ?? null;
4343
+ }
4344
+ function fileSourceRef(path) {
4345
+ return {
4346
+ kind: "file",
4347
+ ref: redactPath(path),
4348
+ backend: "file",
4349
+ private: false,
4350
+ publicSafe: true
4351
+ };
4352
+ }
4353
+ function privateSourceRef(rawRef, backend) {
4354
+ return {
4355
+ kind: "private-ref",
4356
+ ref: redactPrivateRef(rawRef),
4357
+ backend: inferPrivateBackend(rawRef, backend),
4358
+ private: true,
4359
+ publicSafe: true
4360
+ };
4361
+ }
4362
+ function privateRefFromOptions(options) {
4363
+ const env = options.env ?? process.env;
4364
+ return options.privateRef?.trim() || env[PRIVATE_MANIFEST_REF_ENV]?.trim() || env["MACHINES_PRIVATE_MANIFEST_REF"]?.trim() || null;
4365
+ }
4366
+ function getManifestSourceRef(options = {}) {
4367
+ const rawPrivateRef = privateRefFromOptions(options);
4368
+ if (rawPrivateRef) {
4369
+ const env = options.env ?? process.env;
4370
+ return privateSourceRef(rawPrivateRef, options.privateBackend ?? env[PRIVATE_MANIFEST_BACKEND_ENV]);
4371
+ }
4372
+ return fileSourceRef(options.path ?? getManifestPath());
4373
+ }
4242
4374
  function getDefaultManifest() {
4243
4375
  return {
4244
4376
  version: 1,
@@ -4253,6 +4385,53 @@ function readManifest(path = getManifestPath()) {
4253
4385
  const raw = JSON.parse(readFileSync(path, "utf8"));
4254
4386
  return fleetSchema.parse(raw);
4255
4387
  }
4388
+ function readManifestWithSource(options = {}) {
4389
+ const path = options.path ?? getManifestPath();
4390
+ const source = getManifestSourceRef(options);
4391
+ const warnings = [];
4392
+ if (source.kind === "private-ref") {
4393
+ const rawRef = privateRefFromOptions(options);
4394
+ if (rawRef && options.adapter) {
4395
+ try {
4396
+ const manifest2 = options.adapter.readManifest({ source, rawRef });
4397
+ if (manifest2) {
4398
+ return {
4399
+ manifest: fleetSchema.parse(manifest2),
4400
+ info: {
4401
+ source,
4402
+ loadedFrom: "private-ref",
4403
+ warnings
4404
+ }
4405
+ };
4406
+ }
4407
+ warnings.push(`private_manifest_adapter_empty:${redactIdentifier(options.adapter.id)}`);
4408
+ } catch (error) {
4409
+ warnings.push(`private_manifest_adapter_failed:${redactIdentifier(options.adapter.id)}`);
4410
+ }
4411
+ } else {
4412
+ warnings.push("private_manifest_ref_without_adapter");
4413
+ }
4414
+ const fallbackSource = fileSourceRef(path);
4415
+ const manifest = readManifest(path);
4416
+ return {
4417
+ manifest,
4418
+ info: {
4419
+ source,
4420
+ loadedFrom: existsSync2(path) ? "fallback" : "default",
4421
+ fallbackSource,
4422
+ warnings
4423
+ }
4424
+ };
4425
+ }
4426
+ return {
4427
+ manifest: readManifest(path),
4428
+ info: {
4429
+ source,
4430
+ loadedFrom: existsSync2(path) ? "file" : "default",
4431
+ warnings
4432
+ }
4433
+ };
4434
+ }
4256
4435
  function validateManifest(path = getManifestPath()) {
4257
4436
  return readManifest(path);
4258
4437
  }
@@ -4487,6 +4666,19 @@ function manifestHostReachable(target) {
4487
4666
  return null;
4488
4667
  return overrides.has(target);
4489
4668
  }
4669
+ function userFromSshAddress(address) {
4670
+ if (!address)
4671
+ return null;
4672
+ const at = address.indexOf("@");
4673
+ if (at <= 0)
4674
+ return null;
4675
+ return address.slice(0, at);
4676
+ }
4677
+ function commandTargetForRoute(target, user) {
4678
+ if (target.kind === "local" || target.target.includes("@") || !user)
4679
+ return target.target;
4680
+ return `${user}@${target.target}`;
4681
+ }
4490
4682
  function routeHints(input) {
4491
4683
  const hints = [];
4492
4684
  if (input.machineId === input.localMachineId) {
@@ -4537,6 +4729,7 @@ function buildEntry(input) {
4537
4729
  });
4538
4730
  const selectedRoute = selectRouteHint(hints);
4539
4731
  const route = selectedRoute?.kind === "ssh" ? "ssh" : selectedRoute?.kind ?? "unknown";
4732
+ const routeUser = userFromSshAddress(manifest?.sshAddress) ?? (typeof manifest?.metadata?.user === "string" ? manifest.metadata.user : null);
4540
4733
  return {
4541
4734
  machine_id: input.machineId,
4542
4735
  hostname: manifest?.hostname ?? peer?.HostName ?? null,
@@ -4557,11 +4750,11 @@ function buildEntry(input) {
4557
4750
  ssh: {
4558
4751
  address: manifest?.sshAddress ?? null,
4559
4752
  route,
4560
- command_target: selectedRoute?.target ?? null
4753
+ command_target: selectedRoute ? commandTargetForRoute(selectedRoute, routeUser) : null
4561
4754
  },
4562
4755
  route_hints: hints,
4563
4756
  tags: manifest?.tags ?? [],
4564
- metadata: manifest?.metadata ?? {}
4757
+ metadata: redactMetadata(manifest?.metadata)
4565
4758
  };
4566
4759
  }
4567
4760
  function discoverMachineTopology(options = {}) {
@@ -4796,6 +4989,7 @@ function resolveMachineRoute(machineId, options = {}) {
4796
4989
  const local = route === "local" || machine.machine_id === topology.local_machine_id;
4797
4990
  const confidence = routeConfidence({ machine, hint: selectedHint, matchedBy });
4798
4991
  const ok = Boolean(selectedHint?.target);
4992
+ const commandTarget = selectedHint ? commandTargetForRoute(selectedHint, userFromSshAddress(machine.ssh.address) ?? machine.user) : null;
4799
4993
  return {
4800
4994
  schema_version: MACHINES_CONSUMER_CONTRACT_VERSION,
4801
4995
  package: topology.package,
@@ -4806,7 +5000,7 @@ function resolveMachineRoute(machineId, options = {}) {
4806
5000
  route,
4807
5001
  source: route,
4808
5002
  target: selectedHint?.target ?? null,
4809
- command_target: selectedHint?.target ?? null,
5003
+ command_target: commandTarget,
4810
5004
  confidence,
4811
5005
  local,
4812
5006
  evidence: {
@@ -4829,7 +5023,7 @@ function resolveMachineRoute(machineId, options = {}) {
4829
5023
  warnings
4830
5024
  };
4831
5025
  }
4832
- function isRecord(value) {
5026
+ function isRecord2(value) {
4833
5027
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4834
5028
  }
4835
5029
  function metadataString(metadata, keys) {
@@ -4859,13 +5053,13 @@ function metadataStringArray(metadata, keys) {
4859
5053
  function readMappedPath(input) {
4860
5054
  for (const containerName of input.containers) {
4861
5055
  const container = input.metadata[containerName];
4862
- if (!isRecord(container))
5056
+ if (!isRecord2(container))
4863
5057
  continue;
4864
5058
  for (const key of input.keys) {
4865
5059
  const value = container[key];
4866
5060
  if (typeof value === "string" && value.trim())
4867
5061
  return value.trim();
4868
- if (isRecord(value)) {
5062
+ if (isRecord2(value)) {
4869
5063
  const path = metadataString(value, ["path", "root", "workspacePath", "workspace_path"]);
4870
5064
  if (path)
4871
5065
  return path;
@@ -5119,7 +5313,7 @@ function primaryMachine(machine, projectId, primaryMachineId) {
5119
5313
  return machine.tags.includes("primary");
5120
5314
  }
5121
5315
  function metadataKeysForDiagnostics(metadata) {
5122
- return Object.keys(metadata).filter((key) => !/(secret|token|key|password|credential)/i.test(key)).sort();
5316
+ return publicMetadataKeys(metadata);
5123
5317
  }
5124
5318
  function resolveMachineWorkspace(options) {
5125
5319
  const now = options.now ?? new Date;
@@ -5469,21 +5663,21 @@ var MACHINES_CONSUMER_SCHEMA_BUNDLE = {
5469
5663
  }
5470
5664
  }
5471
5665
  };
5472
- function isRecord2(value) {
5666
+ function isRecord3(value) {
5473
5667
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5474
5668
  }
5475
5669
  function hasString(value, key) {
5476
5670
  return typeof value[key] === "string" && value[key].length > 0;
5477
5671
  }
5478
5672
  function hasObject(value, key) {
5479
- return isRecord2(value[key]);
5673
+ return isRecord3(value[key]);
5480
5674
  }
5481
5675
  function hasArray(value, key) {
5482
5676
  return Array.isArray(value[key]);
5483
5677
  }
5484
5678
  function hasCacheability(value, key = "cacheability") {
5485
5679
  const cache = value[key];
5486
- return isRecord2(cache) && hasString(cache, "observed_at") && typeof cache.cacheable === "boolean" && typeof cache.stale === "boolean" && hasArray(cache, "reasons");
5680
+ return isRecord3(cache) && hasString(cache, "observed_at") && typeof cache.cacheable === "boolean" && typeof cache.stale === "boolean" && hasArray(cache, "reasons");
5487
5681
  }
5488
5682
  function requireFields(value, fields, errors2) {
5489
5683
  for (const field of fields) {
@@ -5496,7 +5690,7 @@ function getMachinesConsumerSchemaBundle() {
5496
5690
  }
5497
5691
  function validateMachinesConsumerEnvelope(envelope, value) {
5498
5692
  const errors2 = [];
5499
- if (!isRecord2(value)) {
5693
+ if (!isRecord3(value)) {
5500
5694
  return { ok: false, envelope, schema_id: MACHINES_CONSUMER_SCHEMA_URI, errors: ["not_object"] };
5501
5695
  }
5502
5696
  if (value.schema_version !== MACHINES_CONSUMER_CONTRACT_VERSION)
@@ -5584,7 +5778,7 @@ function resolveSshTarget(machineId, options = {}) {
5584
5778
  }
5585
5779
  return {
5586
5780
  machineId: resolved.machine_id ?? machineId,
5587
- target: resolved.target,
5781
+ target: resolved.command_target ?? resolved.target,
5588
5782
  route: resolved.route,
5589
5783
  confidence: resolved.confidence,
5590
5784
  warnings: resolved.warnings
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from "./cross-project-types.js";
3
3
  export * from "./paths.js";
4
4
  export * from "./db.js";
5
5
  export * from "./manifests.js";
6
+ export * from "./redaction.js";
6
7
  export * from "./topology.js";
7
8
  export * from "./compatibility.js";
8
9
  export * from "./agent/runtime.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,yBAAyB,EACzB,kCAAkC,EAClC,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtH,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,yBAAyB,EACzB,kCAAkC,EAClC,uBAAuB,EACvB,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,IAAI,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtH,cAAc,cAAc,CAAC"}