@hasna/machines 0.0.47 → 0.0.49
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 +19 -0
- package/dist/agent/index.js +34 -12
- package/dist/cli/index.js +523 -390
- package/dist/commands/hosts.d.ts +2 -1
- package/dist/commands/mutation-approval.d.ts +11 -0
- package/dist/commands/runtime.d.ts +1 -0
- package/dist/consumer.js +0 -81
- package/dist/index.d.ts +57 -29
- package/dist/index.js +9202 -25314
- package/dist/mcp/index.js +120 -22
- package/dist/remote-storage.d.ts +5 -1
- package/dist/sdk-mutations.d.ts +54 -0
- package/dist/storage.d.ts +18 -3
- package/dist/storage.js +392 -92
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,6 +76,8 @@ instead of importing private dependencies.
|
|
|
76
76
|
It also reports noninteractive sudo readiness, SSH certificate support, and
|
|
77
77
|
GitHub App secret-reference readiness without printing credentials or private
|
|
78
78
|
keys.
|
|
79
|
+
`machines self-test --json` includes `overall` and `counts` fields so agents
|
|
80
|
+
can branch on readiness without scanning every check.
|
|
79
81
|
|
|
80
82
|
Apple device management belongs in the private deployment layer. The public
|
|
81
83
|
setup plan can report enrollment status with `profiles status -type enrollment`,
|
|
@@ -288,6 +290,13 @@ Configure database storage with `HASNA_MACHINES_DATABASE_URL` or fallback
|
|
|
288
290
|
`HASNA_MACHINES_STORAGE_MODE` or `MACHINES_STORAGE_MODE` with `local`,
|
|
289
291
|
`hybrid`, or `remote`.
|
|
290
292
|
|
|
293
|
+
Remote PostgreSQL storage is fail-closed for TLS. Non-loopback database hosts
|
|
294
|
+
default to verified TLS, and `sslmode=disable`, `ssl=false`,
|
|
295
|
+
`sslmode=no-verify`, or `HASNA_MACHINES_DATABASE_SSL_REJECT_UNAUTHORIZED=0`
|
|
296
|
+
are rejected. For loopback development databases only, set
|
|
297
|
+
`HASNA_MACHINES_ALLOW_INSECURE_DATABASE_TLS=1` to permit disabled or
|
|
298
|
+
non-verified TLS.
|
|
299
|
+
|
|
291
300
|
## Fleet daemon
|
|
292
301
|
|
|
293
302
|
`machines-agent` can run as a managed heartbeat daemon. The daemon writes local
|
|
@@ -444,6 +453,16 @@ back to the tailnet IP. The local machine is skipped. The managed block is delim
|
|
|
444
453
|
by markers, so re-running `apply` only rewrites that block and leaves the rest of
|
|
445
454
|
`/etc/hosts` untouched.
|
|
446
455
|
|
|
456
|
+
### Direct @hasna/events bins
|
|
457
|
+
|
|
458
|
+
`@hasna/events` is a dependency of `@hasna/machines` and publishes its own
|
|
459
|
+
dependency-owned `events` and `hasna-events` binaries. Package managers may
|
|
460
|
+
install those aliases into an application's top-level `node_modules/.bin`, but
|
|
461
|
+
they are not part of the `@hasna/machines` command surface, release scripts,
|
|
462
|
+
daemon plans, MCP tools, or approval model. Use `machines events` and
|
|
463
|
+
`machines webhooks` for machines-scoped event operations; those commands enforce
|
|
464
|
+
machines mutation approval and bind scoped tokens to canonical arguments.
|
|
465
|
+
|
|
447
466
|
## Dashboard
|
|
448
467
|
|
|
449
468
|
```bash
|
package/dist/agent/index.js
CHANGED
|
@@ -992,7 +992,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
992
992
|
this._exitCallback = (err) => {
|
|
993
993
|
if (err.code !== "commander.executeSubCommandAsync") {
|
|
994
994
|
throw err;
|
|
995
|
-
}
|
|
995
|
+
}
|
|
996
996
|
};
|
|
997
997
|
}
|
|
998
998
|
return this;
|
|
@@ -12399,6 +12399,8 @@ var defaults = import_lib.default.defaults;
|
|
|
12399
12399
|
var esm_default = import_lib.default;
|
|
12400
12400
|
|
|
12401
12401
|
// src/remote-storage.ts
|
|
12402
|
+
var MACHINES_DATABASE_ALLOW_INSECURE_TLS_ENV = "HASNA_MACHINES_ALLOW_INSECURE_DATABASE_TLS";
|
|
12403
|
+
var MACHINES_DATABASE_SSL_REJECT_UNAUTHORIZED_ENV = "HASNA_MACHINES_DATABASE_SSL_REJECT_UNAUTHORIZED";
|
|
12402
12404
|
function translatePlaceholders(sql) {
|
|
12403
12405
|
let index = 0;
|
|
12404
12406
|
return sql.replace(/\?/g, () => `$${++index}`);
|
|
@@ -12407,7 +12409,18 @@ function normalizeParams(params) {
|
|
|
12407
12409
|
const flat = params.length === 1 && Array.isArray(params[0]) ? params[0] : params;
|
|
12408
12410
|
return flat.map((value) => value === undefined ? null : value);
|
|
12409
12411
|
}
|
|
12410
|
-
function
|
|
12412
|
+
function envFlag(env, name) {
|
|
12413
|
+
const value = env[name]?.trim().toLowerCase();
|
|
12414
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
12415
|
+
}
|
|
12416
|
+
function isLoopbackHost(hostname4) {
|
|
12417
|
+
const normalized = hostname4.replace(/^\[|\]$/g, "").toLowerCase();
|
|
12418
|
+
return normalized === "localhost" || normalized === "::1" || normalized === "0:0:0:0:0:0:0:1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
|
|
12419
|
+
}
|
|
12420
|
+
function allowsLocalInsecureTls(url, env) {
|
|
12421
|
+
return isLoopbackHost(url.hostname) && envFlag(env, MACHINES_DATABASE_ALLOW_INSECURE_TLS_ENV);
|
|
12422
|
+
}
|
|
12423
|
+
function sslConfigFor(connectionString, env = process.env) {
|
|
12411
12424
|
let url;
|
|
12412
12425
|
try {
|
|
12413
12426
|
url = new URL(connectionString);
|
|
@@ -12416,12 +12429,21 @@ function sslConfigFor(connectionString) {
|
|
|
12416
12429
|
}
|
|
12417
12430
|
const sslMode = url.searchParams.get("sslmode")?.toLowerCase();
|
|
12418
12431
|
const ssl = url.searchParams.get("ssl")?.toLowerCase();
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12432
|
+
const rejectUnauthorizedOverride = env[MACHINES_DATABASE_SSL_REJECT_UNAUTHORIZED_ENV]?.trim() === "0";
|
|
12433
|
+
if (sslMode === "disable" || ssl === "false") {
|
|
12434
|
+
if (allowsLocalInsecureTls(url, env))
|
|
12435
|
+
return;
|
|
12436
|
+
throw new Error(`Insecure PostgreSQL TLS mode is rejected for remote storage; use sslmode=require or set ${MACHINES_DATABASE_ALLOW_INSECURE_TLS_ENV}=1 only for loopback development databases.`);
|
|
12437
|
+
}
|
|
12438
|
+
if (sslMode === "no-verify" || rejectUnauthorizedOverride) {
|
|
12439
|
+
if (!allowsLocalInsecureTls(url, env)) {
|
|
12440
|
+
throw new Error(`PostgreSQL TLS certificate verification cannot be disabled for remote storage; set ${MACHINES_DATABASE_ALLOW_INSECURE_TLS_ENV}=1 only for loopback development databases.`);
|
|
12441
|
+
}
|
|
12422
12442
|
return { rejectUnauthorized: false };
|
|
12423
12443
|
}
|
|
12424
|
-
|
|
12444
|
+
if (sslMode || ssl === "true")
|
|
12445
|
+
return { rejectUnauthorized: true };
|
|
12446
|
+
return isLoopbackHost(url.hostname) ? undefined : { rejectUnauthorized: true };
|
|
12425
12447
|
}
|
|
12426
12448
|
|
|
12427
12449
|
class PgAdapterAsync {
|
|
@@ -12653,12 +12675,12 @@ function summarizeTailscale(privateMetadata) {
|
|
|
12653
12675
|
}
|
|
12654
12676
|
return sanitizeRecord(summary, privateMetadata);
|
|
12655
12677
|
}
|
|
12656
|
-
function
|
|
12678
|
+
function envFlag2(name) {
|
|
12657
12679
|
const value = process.env[name]?.trim().toLowerCase();
|
|
12658
12680
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
12659
12681
|
}
|
|
12660
12682
|
function shouldCollectDoctorSummary(value) {
|
|
12661
|
-
return value ??
|
|
12683
|
+
return value ?? envFlag2("HASNA_MACHINES_AGENT_DOCTOR_SUMMARY");
|
|
12662
12684
|
}
|
|
12663
12685
|
function collectDoctorSummary(machineId, enabled) {
|
|
12664
12686
|
if (!enabled)
|
|
@@ -12853,7 +12875,7 @@ function getAgentStatus(machineId, options = {}) {
|
|
|
12853
12875
|
|
|
12854
12876
|
// src/agent/index.ts
|
|
12855
12877
|
var program2 = new Command;
|
|
12856
|
-
function
|
|
12878
|
+
function envFlag3(name) {
|
|
12857
12879
|
const value = process.env[name]?.trim().toLowerCase();
|
|
12858
12880
|
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
12859
12881
|
}
|
|
@@ -12862,9 +12884,9 @@ var options = program2.parse(process.argv).opts();
|
|
|
12862
12884
|
var parsedIntervalSeconds = options.interval ? Number.parseFloat(options.interval) : NaN;
|
|
12863
12885
|
var parsedIntervalMs = Number.parseInt(options.intervalMs, 10);
|
|
12864
12886
|
var intervalMs = Number.isFinite(parsedIntervalSeconds) ? Math.max(1, Math.floor(parsedIntervalSeconds * 1000)) : Number.isFinite(parsedIntervalMs) ? Math.max(1, parsedIntervalMs) : 30000;
|
|
12865
|
-
var storagePushEnabled = options.storagePush ||
|
|
12866
|
-
var privateMetadataEnabled = options.privateMetadata ||
|
|
12867
|
-
var doctorSummaryEnabled = options.doctorSummary ||
|
|
12887
|
+
var storagePushEnabled = options.storagePush || envFlag3("HASNA_MACHINES_AGENT_STORAGE_PUSH");
|
|
12888
|
+
var privateMetadataEnabled = options.privateMetadata || envFlag3("HASNA_MACHINES_PRIVATE_METADATA") || envFlag3("MACHINES_PRIVATE_METADATA");
|
|
12889
|
+
var doctorSummaryEnabled = options.doctorSummary || envFlag3("HASNA_MACHINES_AGENT_DOCTOR_SUMMARY");
|
|
12868
12890
|
var storagePushRetries = Math.max(0, Number.parseInt(options.storagePushRetries, 10) || 0);
|
|
12869
12891
|
var storagePushBackoffMs = Math.max(0, Number.parseInt(options.storagePushBackoffMs, 10) || 0);
|
|
12870
12892
|
async function tick() {
|