@lifeaitools/clauth 1.30.23 → 1.30.24
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/.clauth-skill/SKILL.md +111 -111
- package/README.md +25 -0
- package/cli/api.classify.test.js +75 -75
- package/cli/assets/codevelop/launcher-active.cmd.template +20 -20
- package/cli/assets/codevelop/launcher-static.cmd.template +7 -7
- package/cli/assets/codevelop/windows-terminal.profiles.json +48 -48
- package/cli/assets/watchdog.ps1 +42 -42
- package/cli/commands/agent-cron.js +396 -396
- package/cli/commands/agent-pool.js +1962 -1962
- package/cli/commands/codevelop.js +1190 -1190
- package/cli/commands/doctor.js +302 -302
- package/cli/commands/install.js +10 -10
- package/cli/commands/invite.js +175 -175
- package/cli/commands/join.js +179 -179
- package/cli/commands/npm.js +182 -182
- package/cli/commands/scrub.js +327 -327
- package/cli/commands/scrub.test.js +115 -115
- package/cli/commands/serve.js +41 -95
- package/cli/commands/watchdog.js +209 -209
- package/cli/conf-path.js +21 -21
- package/cli/enrollment-script.js +82 -82
- package/cli/fingerprint.js +143 -143
- package/cli/index.js +1053 -1053
- package/cli/lib/fs-git.js +282 -282
- package/cli/recovery.js +101 -101
- package/cli/studio-debug.js +1095 -1095
- package/cli/supervisor-registry.js +594 -589
- package/cli/supervisor-registry.test.js +397 -397
- package/cli/supervisor-ui.test.js +5 -83
- package/cli/watchdog-registry.js +209 -209
- package/cli/watchdog-registry.test.js +89 -89
- package/install.ps1 +21 -21
- package/package.json +2 -2
- package/scripts/bin/bootstrap-linux +0 -0
- package/scripts/bin/bootstrap-macos +0 -0
- package/scripts/bin/bootstrap-win.exe +0 -0
- package/supabase/migrations/001_clauth_schema.sql +12 -12
- package/supabase/migrations/003_clauth_config.sql +13 -13
- package/supabase/migrations/003_machine_enrollments.sql +39 -39
- package/cli/served-script-syntax.test.mjs +0 -54
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
import test from "node:test";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
getRegistryPath,
|
|
9
|
-
loadRegistry,
|
|
10
|
-
registerWatchdogManifest,
|
|
11
|
-
restartWatchdogService,
|
|
12
|
-
validateWatchdogManifest,
|
|
13
|
-
validateWatchdogService,
|
|
14
|
-
} from "./watchdog-registry.js";
|
|
15
|
-
|
|
16
|
-
function withTempRegistry(fn) {
|
|
17
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clauth-watchdog-"));
|
|
18
|
-
const old = process.env.CLAUTH_WATCHDOG_DIR;
|
|
19
|
-
process.env.CLAUTH_WATCHDOG_DIR = dir;
|
|
20
|
-
try {
|
|
21
|
-
return fn(dir);
|
|
22
|
-
} finally {
|
|
23
|
-
if (old === undefined) delete process.env.CLAUTH_WATCHDOG_DIR;
|
|
24
|
-
else process.env.CLAUTH_WATCHDOG_DIR = old;
|
|
25
|
-
fs.rmSync(dir, { recursive: true, force: true });
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
test("validateWatchdogService accepts a localhost HTTP service", () => {
|
|
30
|
-
const service = validateWatchdogService({
|
|
31
|
-
id: "codeflow-explorer",
|
|
32
|
-
label: "CodeFlow Explorer",
|
|
33
|
-
owner: "codeflow",
|
|
34
|
-
kind: "http",
|
|
35
|
-
health: { url: "http://127.0.0.1:3109/health" },
|
|
36
|
-
restart: { cmd: "pnpm", args: ["--filter", "@regen/codeflow-explorer", "dev"] },
|
|
37
|
-
});
|
|
38
|
-
assert.equal(service.id, "codeflow-explorer");
|
|
39
|
-
assert.equal(service.approvalRequired, true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test("validateWatchdogService rejects non-local health URLs and shell syntax commands", () => {
|
|
43
|
-
assert.throws(() => validateWatchdogService({
|
|
44
|
-
id: "bad",
|
|
45
|
-
label: "Bad",
|
|
46
|
-
kind: "http",
|
|
47
|
-
health: { url: "https://example.com/health" },
|
|
48
|
-
}), /localhost-only/);
|
|
49
|
-
|
|
50
|
-
assert.throws(() => validateWatchdogService({
|
|
51
|
-
id: "bad",
|
|
52
|
-
label: "Bad",
|
|
53
|
-
kind: "process",
|
|
54
|
-
restart: { cmd: "cmd.exe & del" },
|
|
55
|
-
}), /not shell syntax/);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("registerWatchdogManifest upserts services by id", () => withTempRegistry(() => {
|
|
59
|
-
const manifest = validateWatchdogManifest({
|
|
60
|
-
source: "test",
|
|
61
|
-
services: [
|
|
62
|
-
{ id: "clauth", label: "clauth", kind: "http", health: { url: "http://127.0.0.1:52437/ping" } },
|
|
63
|
-
{ id: "codeflow", label: "CodeFlow", kind: "http", health: { url: "http://localhost:3109/health" } },
|
|
64
|
-
],
|
|
65
|
-
});
|
|
66
|
-
const result = registerWatchdogManifest(manifest);
|
|
67
|
-
assert.equal(result.registered, 2);
|
|
68
|
-
assert.ok(fs.existsSync(getRegistryPath()));
|
|
69
|
-
assert.deepEqual(loadRegistry().services.map((service) => service.id), ["clauth", "codeflow"]);
|
|
70
|
-
|
|
71
|
-
registerWatchdogManifest({
|
|
72
|
-
services: [
|
|
73
|
-
{ id: "codeflow", label: "CodeFlow Updated", kind: "http", health: { url: "http://localhost:3109/health" } },
|
|
74
|
-
],
|
|
75
|
-
});
|
|
76
|
-
const registry = loadRegistry();
|
|
77
|
-
assert.equal(registry.services.length, 2);
|
|
78
|
-
assert.equal(registry.services.find((service) => service.id === "codeflow").label, "CodeFlow Updated");
|
|
79
|
-
}));
|
|
80
|
-
|
|
81
|
-
test("restartWatchdogService rejects missing and unapproved services", () => withTempRegistry(() => {
|
|
82
|
-
assert.deepEqual(restartWatchdogService("missing"), { ok: false, error: "service_not_registered" });
|
|
83
|
-
registerWatchdogManifest({
|
|
84
|
-
services: [
|
|
85
|
-
{ id: "dev-center", label: "Dev Center", kind: "process", restart: { cmd: "node", args: ["--version"] } },
|
|
86
|
-
],
|
|
87
|
-
});
|
|
88
|
-
assert.deepEqual(restartWatchdogService("dev-center"), { ok: false, error: "approval_required" });
|
|
89
|
-
}));
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getRegistryPath,
|
|
9
|
+
loadRegistry,
|
|
10
|
+
registerWatchdogManifest,
|
|
11
|
+
restartWatchdogService,
|
|
12
|
+
validateWatchdogManifest,
|
|
13
|
+
validateWatchdogService,
|
|
14
|
+
} from "./watchdog-registry.js";
|
|
15
|
+
|
|
16
|
+
function withTempRegistry(fn) {
|
|
17
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clauth-watchdog-"));
|
|
18
|
+
const old = process.env.CLAUTH_WATCHDOG_DIR;
|
|
19
|
+
process.env.CLAUTH_WATCHDOG_DIR = dir;
|
|
20
|
+
try {
|
|
21
|
+
return fn(dir);
|
|
22
|
+
} finally {
|
|
23
|
+
if (old === undefined) delete process.env.CLAUTH_WATCHDOG_DIR;
|
|
24
|
+
else process.env.CLAUTH_WATCHDOG_DIR = old;
|
|
25
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test("validateWatchdogService accepts a localhost HTTP service", () => {
|
|
30
|
+
const service = validateWatchdogService({
|
|
31
|
+
id: "codeflow-explorer",
|
|
32
|
+
label: "CodeFlow Explorer",
|
|
33
|
+
owner: "codeflow",
|
|
34
|
+
kind: "http",
|
|
35
|
+
health: { url: "http://127.0.0.1:3109/health" },
|
|
36
|
+
restart: { cmd: "pnpm", args: ["--filter", "@regen/codeflow-explorer", "dev"] },
|
|
37
|
+
});
|
|
38
|
+
assert.equal(service.id, "codeflow-explorer");
|
|
39
|
+
assert.equal(service.approvalRequired, true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("validateWatchdogService rejects non-local health URLs and shell syntax commands", () => {
|
|
43
|
+
assert.throws(() => validateWatchdogService({
|
|
44
|
+
id: "bad",
|
|
45
|
+
label: "Bad",
|
|
46
|
+
kind: "http",
|
|
47
|
+
health: { url: "https://example.com/health" },
|
|
48
|
+
}), /localhost-only/);
|
|
49
|
+
|
|
50
|
+
assert.throws(() => validateWatchdogService({
|
|
51
|
+
id: "bad",
|
|
52
|
+
label: "Bad",
|
|
53
|
+
kind: "process",
|
|
54
|
+
restart: { cmd: "cmd.exe & del" },
|
|
55
|
+
}), /not shell syntax/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("registerWatchdogManifest upserts services by id", () => withTempRegistry(() => {
|
|
59
|
+
const manifest = validateWatchdogManifest({
|
|
60
|
+
source: "test",
|
|
61
|
+
services: [
|
|
62
|
+
{ id: "clauth", label: "clauth", kind: "http", health: { url: "http://127.0.0.1:52437/ping" } },
|
|
63
|
+
{ id: "codeflow", label: "CodeFlow", kind: "http", health: { url: "http://localhost:3109/health" } },
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
const result = registerWatchdogManifest(manifest);
|
|
67
|
+
assert.equal(result.registered, 2);
|
|
68
|
+
assert.ok(fs.existsSync(getRegistryPath()));
|
|
69
|
+
assert.deepEqual(loadRegistry().services.map((service) => service.id), ["clauth", "codeflow"]);
|
|
70
|
+
|
|
71
|
+
registerWatchdogManifest({
|
|
72
|
+
services: [
|
|
73
|
+
{ id: "codeflow", label: "CodeFlow Updated", kind: "http", health: { url: "http://localhost:3109/health" } },
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
const registry = loadRegistry();
|
|
77
|
+
assert.equal(registry.services.length, 2);
|
|
78
|
+
assert.equal(registry.services.find((service) => service.id === "codeflow").label, "CodeFlow Updated");
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
test("restartWatchdogService rejects missing and unapproved services", () => withTempRegistry(() => {
|
|
82
|
+
assert.deepEqual(restartWatchdogService("missing"), { ok: false, error: "service_not_registered" });
|
|
83
|
+
registerWatchdogManifest({
|
|
84
|
+
services: [
|
|
85
|
+
{ id: "dev-center", label: "Dev Center", kind: "process", restart: { cmd: "node", args: ["--version"] } },
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
assert.deepEqual(restartWatchdogService("dev-center"), { ok: false, error: "approval_required" });
|
|
89
|
+
}));
|
package/install.ps1
CHANGED
|
@@ -100,24 +100,24 @@ if (Test-Path $autostartScript) {
|
|
|
100
100
|
$lnk.Save()
|
|
101
101
|
Write-Host " + Autostart registered via Startup folder (15s delay, crash-recovery loop active)." -ForegroundColor Green
|
|
102
102
|
}
|
|
103
|
-
} else {
|
|
104
|
-
Write-Host ""
|
|
105
|
-
Write-Host " ! autostart.ps1 not found - skipping autostart registration." -ForegroundColor Yellow
|
|
106
|
-
Write-Host " Run: clauth autostart install" -ForegroundColor Gray
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
Write-Host ""
|
|
110
|
-
Write-Host " Installing co-development Windows Terminal profiles..." -ForegroundColor Cyan
|
|
111
|
-
try {
|
|
112
|
-
& clauth codevelop install-terminal --repo "C:\Dev\regen-root"
|
|
113
|
-
if ($LASTEXITCODE -eq 0) {
|
|
114
|
-
Write-Host " + Co-development terminal profiles installed." -ForegroundColor Green
|
|
115
|
-
} else {
|
|
116
|
-
Write-Host " ! Co-development terminal profile install returned exit code $LASTEXITCODE." -ForegroundColor Yellow
|
|
117
|
-
}
|
|
118
|
-
} catch {
|
|
119
|
-
Write-Host " ! Co-development terminal profile install skipped: $($_.Exception.Message)" -ForegroundColor Yellow
|
|
120
|
-
Write-Host " Run later: clauth codevelop install-terminal --repo C:\Dev\regen-root" -ForegroundColor Gray
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
exit $LASTEXITCODE
|
|
103
|
+
} else {
|
|
104
|
+
Write-Host ""
|
|
105
|
+
Write-Host " ! autostart.ps1 not found - skipping autostart registration." -ForegroundColor Yellow
|
|
106
|
+
Write-Host " Run: clauth autostart install" -ForegroundColor Gray
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
Write-Host ""
|
|
110
|
+
Write-Host " Installing co-development Windows Terminal profiles..." -ForegroundColor Cyan
|
|
111
|
+
try {
|
|
112
|
+
& clauth codevelop install-terminal --repo "C:\Dev\regen-root"
|
|
113
|
+
if ($LASTEXITCODE -eq 0) {
|
|
114
|
+
Write-Host " + Co-development terminal profiles installed." -ForegroundColor Green
|
|
115
|
+
} else {
|
|
116
|
+
Write-Host " ! Co-development terminal profile install returned exit code $LASTEXITCODE." -ForegroundColor Yellow
|
|
117
|
+
}
|
|
118
|
+
} catch {
|
|
119
|
+
Write-Host " ! Co-development terminal profile install skipped: $($_.Exception.Message)" -ForegroundColor Yellow
|
|
120
|
+
Write-Host " Run later: clauth codevelop install-terminal --repo C:\Dev\regen-root" -ForegroundColor Gray
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
exit $LASTEXITCODE
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifeaitools/clauth",
|
|
3
|
-
"version": "1.30.
|
|
3
|
+
"version": "1.30.24",
|
|
4
4
|
"description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "bash scripts/build.sh",
|
|
11
|
-
"test": "node --test cli/commands/scrub.test.js cli/api.classify.test.js
|
|
11
|
+
"test": "node --test cli/commands/scrub.test.js cli/api.classify.test.js test/studio-debug.test.mjs test/dashboard-key-generator.test.mjs && node test-auth-verdict.mjs",
|
|
12
12
|
"test:studio-debug": "node --test test/studio-debug.test.mjs",
|
|
13
13
|
"test:agent-pool": "node test/agent-pool.test.mjs",
|
|
14
14
|
"test:call-agent-10": "node test/call-agent-10-skills.test.mjs",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -27,18 +27,18 @@ create table if not exists public.clauth_services (
|
|
|
27
27
|
-- ============================================================
|
|
28
28
|
-- Machine Registry (hardware fingerprints — hashed only)
|
|
29
29
|
-- ============================================================
|
|
30
|
-
create table if not exists public.clauth_machines (
|
|
31
|
-
id uuid primary key default gen_random_uuid(),
|
|
32
|
-
install_id text not null default 'default', -- logical vault install / owner group
|
|
33
|
-
machine_hash text not null unique, -- SHA256(machine_id + os_install_id)
|
|
34
|
-
label text, -- e.g. 'Dave-Desktop-Win11'
|
|
35
|
-
hmac_seed_hash text not null, -- SHA256 of the HMAC seed stored in vault
|
|
36
|
-
enabled boolean not null default true,
|
|
37
|
-
fail_count integer not null default 0,
|
|
38
|
-
locked boolean not null default false,
|
|
39
|
-
created_at timestamptz not null default now(),
|
|
40
|
-
last_seen timestamptz
|
|
41
|
-
);
|
|
30
|
+
create table if not exists public.clauth_machines (
|
|
31
|
+
id uuid primary key default gen_random_uuid(),
|
|
32
|
+
install_id text not null default 'default', -- logical vault install / owner group
|
|
33
|
+
machine_hash text not null unique, -- SHA256(machine_id + os_install_id)
|
|
34
|
+
label text, -- e.g. 'Dave-Desktop-Win11'
|
|
35
|
+
hmac_seed_hash text not null, -- SHA256 of the HMAC seed stored in vault
|
|
36
|
+
enabled boolean not null default true,
|
|
37
|
+
fail_count integer not null default 0,
|
|
38
|
+
locked boolean not null default false,
|
|
39
|
+
created_at timestamptz not null default now(),
|
|
40
|
+
last_seen timestamptz
|
|
41
|
+
);
|
|
42
42
|
|
|
43
43
|
-- ============================================================
|
|
44
44
|
-- Audit Log
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
-- clauth_config: key/value store for daemon configuration
|
|
2
|
-
-- Used to persist tunnel hostname and other daemon settings
|
|
3
|
-
CREATE TABLE IF NOT EXISTS clauth_config (
|
|
4
|
-
key text PRIMARY KEY,
|
|
5
|
-
value jsonb NOT NULL,
|
|
6
|
-
updated_at timestamptz DEFAULT now()
|
|
7
|
-
);
|
|
8
|
-
|
|
9
|
-
-- RLS: only service role can access (same pattern as other clauth tables)
|
|
10
|
-
ALTER TABLE clauth_config ENABLE ROW LEVEL SECURITY;
|
|
11
|
-
|
|
12
|
-
-- Seed: no tunnel by default (user must run clauth tunnel setup)
|
|
13
|
-
-- INSERT INTO clauth_config (key, value) VALUES ('tunnel_hostname', 'null');
|
|
1
|
+
-- clauth_config: key/value store for daemon configuration
|
|
2
|
+
-- Used to persist tunnel hostname and other daemon settings
|
|
3
|
+
CREATE TABLE IF NOT EXISTS clauth_config (
|
|
4
|
+
key text PRIMARY KEY,
|
|
5
|
+
value jsonb NOT NULL,
|
|
6
|
+
updated_at timestamptz DEFAULT now()
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
-- RLS: only service role can access (same pattern as other clauth tables)
|
|
10
|
+
ALTER TABLE clauth_config ENABLE ROW LEVEL SECURITY;
|
|
11
|
+
|
|
12
|
+
-- Seed: no tunnel by default (user must run clauth tunnel setup)
|
|
13
|
+
-- INSERT INTO clauth_config (key, value) VALUES ('tunnel_hostname', 'null');
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
-- ============================================================
|
|
2
|
-
-- clauth machine enrollment
|
|
3
|
-
-- Migration: 003_machine_enrollments.sql
|
|
4
|
-
-- ============================================================
|
|
5
|
-
|
|
6
|
-
alter table public.clauth_machines
|
|
7
|
-
add column if not exists install_id text not null default 'default';
|
|
8
|
-
|
|
9
|
-
create index if not exists clauth_machines_install_id_idx
|
|
10
|
-
on public.clauth_machines (install_id);
|
|
11
|
-
|
|
12
|
-
create table if not exists public.clauth_machine_enrollments (
|
|
13
|
-
id uuid primary key default gen_random_uuid(),
|
|
14
|
-
install_id text not null default 'default',
|
|
15
|
-
token_hash text not null unique,
|
|
16
|
-
label text,
|
|
17
|
-
created_by_machine_hash text not null references public.clauth_machines(machine_hash) on delete cascade,
|
|
18
|
-
redeemed_by_machine_hash text references public.clauth_machines(machine_hash) on delete set null,
|
|
19
|
-
expires_at timestamptz not null,
|
|
20
|
-
consumed_at timestamptz,
|
|
21
|
-
created_at timestamptz not null default now()
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
create index if not exists clauth_machine_enrollments_install_idx
|
|
25
|
-
on public.clauth_machine_enrollments (install_id, expires_at);
|
|
26
|
-
|
|
27
|
-
alter table public.clauth_machine_enrollments enable row level security;
|
|
28
|
-
|
|
29
|
-
do $$ begin
|
|
30
|
-
if not exists (
|
|
31
|
-
select 1
|
|
32
|
-
from pg_policies
|
|
33
|
-
where policyname = 'no_anon_machine_enrollments'
|
|
34
|
-
and tablename = 'clauth_machine_enrollments'
|
|
35
|
-
) then
|
|
36
|
-
create policy "no_anon_machine_enrollments"
|
|
37
|
-
on public.clauth_machine_enrollments for all using (false);
|
|
38
|
-
end if;
|
|
39
|
-
end $$;
|
|
1
|
+
-- ============================================================
|
|
2
|
+
-- clauth machine enrollment
|
|
3
|
+
-- Migration: 003_machine_enrollments.sql
|
|
4
|
+
-- ============================================================
|
|
5
|
+
|
|
6
|
+
alter table public.clauth_machines
|
|
7
|
+
add column if not exists install_id text not null default 'default';
|
|
8
|
+
|
|
9
|
+
create index if not exists clauth_machines_install_id_idx
|
|
10
|
+
on public.clauth_machines (install_id);
|
|
11
|
+
|
|
12
|
+
create table if not exists public.clauth_machine_enrollments (
|
|
13
|
+
id uuid primary key default gen_random_uuid(),
|
|
14
|
+
install_id text not null default 'default',
|
|
15
|
+
token_hash text not null unique,
|
|
16
|
+
label text,
|
|
17
|
+
created_by_machine_hash text not null references public.clauth_machines(machine_hash) on delete cascade,
|
|
18
|
+
redeemed_by_machine_hash text references public.clauth_machines(machine_hash) on delete set null,
|
|
19
|
+
expires_at timestamptz not null,
|
|
20
|
+
consumed_at timestamptz,
|
|
21
|
+
created_at timestamptz not null default now()
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
create index if not exists clauth_machine_enrollments_install_idx
|
|
25
|
+
on public.clauth_machine_enrollments (install_id, expires_at);
|
|
26
|
+
|
|
27
|
+
alter table public.clauth_machine_enrollments enable row level security;
|
|
28
|
+
|
|
29
|
+
do $$ begin
|
|
30
|
+
if not exists (
|
|
31
|
+
select 1
|
|
32
|
+
from pg_policies
|
|
33
|
+
where policyname = 'no_anon_machine_enrollments'
|
|
34
|
+
and tablename = 'clauth_machine_enrollments'
|
|
35
|
+
) then
|
|
36
|
+
create policy "no_anon_machine_enrollments"
|
|
37
|
+
on public.clauth_machine_enrollments for all using (false);
|
|
38
|
+
end if;
|
|
39
|
+
end $$;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import test from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import vm from 'node:vm';
|
|
4
|
-
import { spawn } from 'node:child_process';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
|
|
8
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const cliEntry = path.join(here, 'index.js');
|
|
10
|
-
const PORT = 52499;
|
|
11
|
-
|
|
12
|
-
function waitForPort(url, timeoutMs) {
|
|
13
|
-
const deadline = Date.now() + timeoutMs;
|
|
14
|
-
const attempt = async () => {
|
|
15
|
-
try {
|
|
16
|
-
const r = await fetch(url);
|
|
17
|
-
if (r.ok) return true;
|
|
18
|
-
} catch {}
|
|
19
|
-
if (Date.now() > deadline) throw new Error('timed out waiting for ' + url);
|
|
20
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
21
|
-
return attempt();
|
|
22
|
-
};
|
|
23
|
-
return attempt();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Regression coverage for the 2026-08-06 incident: a stray tool-authoring
|
|
27
|
-
// artifact ("[char]0x2192" -- PowerShell character-literal syntax, never
|
|
28
|
-
// evaluated because it was written inside a single-quoted PowerShell string)
|
|
29
|
-
// landed as literal text inside the embedded dashboard <script> block. That
|
|
30
|
-
// produced a real SyntaxError in every browser that loaded the page, so the
|
|
31
|
-
// ENTIRE inline script failed to parse -- meaning unlock(), unlockWrites(),
|
|
32
|
-
// runSupervisorSurface(), and every other function on the page silently
|
|
33
|
-
// never existed. `node --check` on serve.js itself never catches this class
|
|
34
|
-
// of bug: the broken text lives inside a JS string/template FOR the browser,
|
|
35
|
-
// which is opaque to Node's own parser. This test extracts the actual served
|
|
36
|
-
// script -- the same bytes a real browser executes -- and parses it for real.
|
|
37
|
-
test('the served dashboard script has no syntax errors (would have caught the 2026-08-06 incident)', async () => {
|
|
38
|
-
const child = spawn(process.execPath, [cliEntry, 'serve', 'start', '--isolated', '--port', String(PORT)], {
|
|
39
|
-
stdio: 'ignore',
|
|
40
|
-
windowsHide: true,
|
|
41
|
-
});
|
|
42
|
-
try {
|
|
43
|
-
await waitForPort('http://127.0.0.1:' + PORT + '/ping', 15000);
|
|
44
|
-
const html = await fetch('http://127.0.0.1:' + PORT + '/').then((r) => r.text());
|
|
45
|
-
const start = html.indexOf('<script>');
|
|
46
|
-
const end = html.lastIndexOf('</script>');
|
|
47
|
-
assert.ok(start !== -1 && end !== -1, 'expected an inline <script> block in the served dashboard');
|
|
48
|
-
const js = html.slice(start + 8, end);
|
|
49
|
-
assert.doesNotThrow(() => new vm.Script(js), 'the served dashboard script must be syntactically valid JavaScript');
|
|
50
|
-
} finally {
|
|
51
|
-
await fetch('http://127.0.0.1:' + PORT + '/shutdown').catch(() => {});
|
|
52
|
-
child.kill();
|
|
53
|
-
}
|
|
54
|
-
});
|