@astrasyncai/verification-gateway 5.9.0 → 5.11.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/dist/adapters/express.js +19 -1
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +19 -1
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.js +19 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +19 -1
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.js +19 -1
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +19 -1
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.js +19 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +19 -1
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +540 -10
- package/dist/bin/astrasync-codex-hook.js +540 -10
- package/dist/bin/astrasync-guard.js +629 -65
- package/dist/bin/astrasync.js +673 -66
- package/dist/browser/background.js +19 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +19 -1
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.d.mts +8 -8
- package/dist/cli/index.d.ts +8 -8
- package/dist/cli/index.js +22 -64
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +22 -64
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.d.mts +5 -0
- package/dist/codex/index.d.ts +5 -0
- package/dist/codex/index.js +556 -18
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +558 -20
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.d.mts +9 -2
- package/dist/cursor/extension.d.ts +9 -2
- package/dist/cursor/extension.js +522 -5
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +524 -5
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.js +20 -2
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +20 -2
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/enrolment-store-8DyaIOLe.d.mts +26 -0
- package/dist/enrolment-store-8DyaIOLe.d.ts +26 -0
- package/dist/gateway/gateway.js +19 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +19 -1
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/index.d.mts +100 -3
- package/dist/index.d.ts +100 -3
- package/dist/index.js +3289 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3287 -18
- package/dist/index.mjs.map +1 -1
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/verify.js +19 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +19 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bin/astrasync.js
CHANGED
|
@@ -36,7 +36,7 @@ var SDK_VERSION;
|
|
|
36
36
|
var init_version = __esm({
|
|
37
37
|
"src/version.ts"() {
|
|
38
38
|
"use strict";
|
|
39
|
-
SDK_VERSION = "5.
|
|
39
|
+
SDK_VERSION = "5.11.0";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -4095,7 +4095,6 @@ var init_upgrade = __esm({
|
|
|
4095
4095
|
"src/cli/upgrade.ts"() {
|
|
4096
4096
|
"use strict";
|
|
4097
4097
|
init_http();
|
|
4098
|
-
init_pdlss_parser();
|
|
4099
4098
|
UpgradeFlow = class {
|
|
4100
4099
|
constructor(config, callbacks, trigger) {
|
|
4101
4100
|
this.config = config;
|
|
@@ -4155,27 +4154,23 @@ var init_upgrade = __esm({
|
|
|
4155
4154
|
*/
|
|
4156
4155
|
async continueUpgrade(apiKey, kydId) {
|
|
4157
4156
|
const { print, prompt } = this.callbacks;
|
|
4158
|
-
print("\n[3/5]
|
|
4159
|
-
print(
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
]
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
return uploadResult;
|
|
4176
|
-
}
|
|
4177
|
-
print(" Policy uploaded. Same rules, now with trust scoring and audit.");
|
|
4178
|
-
print(` Agent registered: ${uploadResult.agentId}`);
|
|
4157
|
+
print("\n[3/5] Link your agent");
|
|
4158
|
+
print(
|
|
4159
|
+
` Local policy ${this.config.policyPath} stays on this machine (${this.config.policy.purposes.length} purpose rules).`
|
|
4160
|
+
);
|
|
4161
|
+
print(" Register the agent in the AstraSync dashboard (or with `astrasync register`) and");
|
|
4162
|
+
print(" paste its ASTRA- id so synced decisions are attributed to it.\n");
|
|
4163
|
+
const agentInput = (await prompt(" Agent ASTRA- id (Enter to skip): ")).trim();
|
|
4164
|
+
let agentId;
|
|
4165
|
+
if (agentInput) {
|
|
4166
|
+
if (!/^ASTRA-[A-Za-z0-9_-]+$/.test(agentInput)) {
|
|
4167
|
+
return { success: false, error: `Not an ASTRA- agent id: ${agentInput}` };
|
|
4168
|
+
}
|
|
4169
|
+
agentId = agentInput;
|
|
4170
|
+
print(` Agent: ${agentId}`);
|
|
4171
|
+
} else {
|
|
4172
|
+
print(" No agent linked \u2014 decisions sync under your API key only.");
|
|
4173
|
+
}
|
|
4179
4174
|
if (kydId) {
|
|
4180
4175
|
print(` Developer: ${kydId}`);
|
|
4181
4176
|
}
|
|
@@ -4186,23 +4181,23 @@ var init_upgrade = __esm({
|
|
|
4186
4181
|
const mode = modeInput.trim().toLowerCase() === "online" ? "online" : "hybrid";
|
|
4187
4182
|
print(`
|
|
4188
4183
|
[5/5] Activating ${mode} verification`);
|
|
4189
|
-
await this.writeLocalConfig(apiKey,
|
|
4184
|
+
await this.writeLocalConfig(apiKey, agentId, mode, kydId);
|
|
4190
4185
|
print(` Config written to ${this.configDir}/config`);
|
|
4191
4186
|
print(` Mode: ${mode}`);
|
|
4192
4187
|
print(" Done!\n");
|
|
4193
|
-
print(` Your agent (${
|
|
4188
|
+
if (agentId) print(` Your agent (${agentId}) is verified on the AstraSync network.`);
|
|
4194
4189
|
if (mode === "hybrid") {
|
|
4195
4190
|
print(" Local evaluation active for speed. Cloud sync for audit and trust scoring.");
|
|
4196
4191
|
} else {
|
|
4197
4192
|
print(" Trust scoring, audit trails, and blockchain recording are active.");
|
|
4198
4193
|
}
|
|
4199
4194
|
print(`
|
|
4200
|
-
Dashboard: ${this.platformUrl}/agents
|
|
4195
|
+
Dashboard: ${this.platformUrl}/agents${agentId ? `/${agentId}` : ""}
|
|
4201
4196
|
`);
|
|
4202
4197
|
return {
|
|
4203
4198
|
success: true,
|
|
4204
4199
|
apiKey,
|
|
4205
|
-
agentId
|
|
4200
|
+
agentId,
|
|
4206
4201
|
kydId,
|
|
4207
4202
|
mode
|
|
4208
4203
|
};
|
|
@@ -4255,44 +4250,6 @@ var init_upgrade = __esm({
|
|
|
4255
4250
|
return { valid: true, error: `Could not reach platform (proceeding anyway)` };
|
|
4256
4251
|
}
|
|
4257
4252
|
}
|
|
4258
|
-
/**
|
|
4259
|
-
* Upload local policy to the AstraSync cloud.
|
|
4260
|
-
* YAML -> cloud PDLSS boundary, 1:1 mapping, no lossy transformation.
|
|
4261
|
-
*/
|
|
4262
|
-
async uploadPolicy(apiKey) {
|
|
4263
|
-
const policyYaml = toYaml(this.config.policy);
|
|
4264
|
-
try {
|
|
4265
|
-
const response = await sdkFetch(`${this.platformUrl}/api/v1/agents/policies/upload`, {
|
|
4266
|
-
method: "POST",
|
|
4267
|
-
headers: {
|
|
4268
|
-
"Content-Type": "application/json",
|
|
4269
|
-
Authorization: `Bearer ${apiKey}`
|
|
4270
|
-
},
|
|
4271
|
-
body: JSON.stringify({
|
|
4272
|
-
policy: policyYaml,
|
|
4273
|
-
policyObject: this.config.policy,
|
|
4274
|
-
format: "yaml",
|
|
4275
|
-
source: "local-guard-upgrade",
|
|
4276
|
-
name: this.config.policy.name
|
|
4277
|
-
})
|
|
4278
|
-
});
|
|
4279
|
-
if (!response.ok) {
|
|
4280
|
-
const body = await response.text();
|
|
4281
|
-
return { success: false, error: `Upload failed (${response.status}): ${body}` };
|
|
4282
|
-
}
|
|
4283
|
-
const data = await response.json();
|
|
4284
|
-
return {
|
|
4285
|
-
success: true,
|
|
4286
|
-
agentId: data.agentId || "ASTRA-PENDING",
|
|
4287
|
-
kydId: data.kydId
|
|
4288
|
-
};
|
|
4289
|
-
} catch (err) {
|
|
4290
|
-
return {
|
|
4291
|
-
success: false,
|
|
4292
|
-
error: `Network error: ${err instanceof Error ? err.message : String(err)}`
|
|
4293
|
-
};
|
|
4294
|
-
}
|
|
4295
|
-
}
|
|
4296
4253
|
/**
|
|
4297
4254
|
* Write the config file for the chosen mode.
|
|
4298
4255
|
*/
|
|
@@ -5379,6 +5336,24 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
5379
5336
|
}
|
|
5380
5337
|
};
|
|
5381
5338
|
}
|
|
5339
|
+
if (response.status === 400 && data?.error === "INVALID_AGENT_ID") {
|
|
5340
|
+
const message = typeof data?.message === "string" ? data.message : "Agent identifier must be a canonical ASTRA-* id.";
|
|
5341
|
+
return {
|
|
5342
|
+
success: true,
|
|
5343
|
+
attemptId: typeof data?.attemptId === "string" ? data.attemptId : void 0,
|
|
5344
|
+
access: {
|
|
5345
|
+
allowed: false,
|
|
5346
|
+
reason: "invalid_agent_id",
|
|
5347
|
+
failures: [
|
|
5348
|
+
{
|
|
5349
|
+
dimension: "identity.invalid_agent_id",
|
|
5350
|
+
message,
|
|
5351
|
+
guidance: typeof data?.guidance === "string" ? data.guidance : "Present your canonical ASTRA-* id (discover it via GET /api/agents/request-registration/{requestId} after owner approval)."
|
|
5352
|
+
}
|
|
5353
|
+
]
|
|
5354
|
+
}
|
|
5355
|
+
};
|
|
5356
|
+
}
|
|
5382
5357
|
if (!response.ok) {
|
|
5383
5358
|
if (response.status === 401) {
|
|
5384
5359
|
return {
|
|
@@ -6220,6 +6195,8 @@ var init_src = __esm({
|
|
|
6220
6195
|
init_runtime_signatures();
|
|
6221
6196
|
init_verified_hop();
|
|
6222
6197
|
init_http();
|
|
6198
|
+
init_pdlss_parser();
|
|
6199
|
+
init_schema();
|
|
6223
6200
|
init_version();
|
|
6224
6201
|
}
|
|
6225
6202
|
});
|
|
@@ -7098,7 +7075,15 @@ var init_settings_installer = __esm({
|
|
|
7098
7075
|
"~/.claude/settings.json",
|
|
7099
7076
|
"~/.claude/settings.local.json",
|
|
7100
7077
|
"**/.astrasync/**",
|
|
7101
|
-
"~/.astrasync/**"
|
|
7078
|
+
"~/.astrasync/**",
|
|
7079
|
+
// 5.11.0 fleet mode: enrolment + signed-policy cache (user scope is inside
|
|
7080
|
+
// ~/.astrasync already; listed explicitly so the intent survives edits) and
|
|
7081
|
+
// the machine-scope enrolment dirs. `//` = absolute from filesystem root;
|
|
7082
|
+
// Windows paths are matched in POSIX form (C:\ → /c/).
|
|
7083
|
+
"~/.astrasync/fleet/**",
|
|
7084
|
+
"//etc/astrasync/**",
|
|
7085
|
+
"//Library/Application Support/AstraSync/**",
|
|
7086
|
+
"//c/ProgramData/AstraSync/**"
|
|
7102
7087
|
];
|
|
7103
7088
|
GUARD_PERMISSION_DENY_RULES = PERMISSION_DENY_PATHS.map(
|
|
7104
7089
|
(p) => `Edit(${p})`
|
|
@@ -7140,6 +7125,545 @@ var init_settings_installer2 = __esm({
|
|
|
7140
7125
|
}
|
|
7141
7126
|
});
|
|
7142
7127
|
|
|
7128
|
+
// src/fleet/client.ts
|
|
7129
|
+
function base(url) {
|
|
7130
|
+
return url.replace(/\/+$/, "");
|
|
7131
|
+
}
|
|
7132
|
+
async function call(url, init, timeoutMs) {
|
|
7133
|
+
const controller = new AbortController();
|
|
7134
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
7135
|
+
try {
|
|
7136
|
+
const res = await sdkFetch(url, { ...init, signal: controller.signal });
|
|
7137
|
+
const text = await res.text();
|
|
7138
|
+
let body = text;
|
|
7139
|
+
try {
|
|
7140
|
+
body = text ? JSON.parse(text) : null;
|
|
7141
|
+
} catch {
|
|
7142
|
+
}
|
|
7143
|
+
return { status: res.status, body, headers: res.headers };
|
|
7144
|
+
} finally {
|
|
7145
|
+
clearTimeout(timer);
|
|
7146
|
+
}
|
|
7147
|
+
}
|
|
7148
|
+
function apiError(status, body, what) {
|
|
7149
|
+
const b = body ?? {};
|
|
7150
|
+
const code = b.code ?? (typeof b.error === "string" ? b.error : void 0);
|
|
7151
|
+
return new FleetApiError(`${what} failed (${status}${code ? ` ${code}` : ""})`, status, code);
|
|
7152
|
+
}
|
|
7153
|
+
async function enrolDevice(apiBaseUrl, request2, timeoutMs = 15e3) {
|
|
7154
|
+
const r = await call(
|
|
7155
|
+
`${base(apiBaseUrl)}/fleet/enrol`,
|
|
7156
|
+
{
|
|
7157
|
+
method: "POST",
|
|
7158
|
+
headers: { "Content-Type": "application/json" },
|
|
7159
|
+
body: JSON.stringify(request2)
|
|
7160
|
+
},
|
|
7161
|
+
timeoutMs
|
|
7162
|
+
);
|
|
7163
|
+
if (r.status !== 201 && r.status !== 200) throw apiError(r.status, r.body, "Enrolment");
|
|
7164
|
+
const data = r.body;
|
|
7165
|
+
if (!data?.deviceId || !data.credential || !data.jwks || !data.policyJws) {
|
|
7166
|
+
throw new FleetApiError("Enrolment response is missing required fields", r.status);
|
|
7167
|
+
}
|
|
7168
|
+
return data;
|
|
7169
|
+
}
|
|
7170
|
+
var FleetApiError;
|
|
7171
|
+
var init_client2 = __esm({
|
|
7172
|
+
"src/fleet/client.ts"() {
|
|
7173
|
+
"use strict";
|
|
7174
|
+
init_http();
|
|
7175
|
+
FleetApiError = class extends Error {
|
|
7176
|
+
constructor(message, status, code) {
|
|
7177
|
+
super(message);
|
|
7178
|
+
this.status = status;
|
|
7179
|
+
this.code = code;
|
|
7180
|
+
this.name = "FleetApiError";
|
|
7181
|
+
}
|
|
7182
|
+
};
|
|
7183
|
+
}
|
|
7184
|
+
});
|
|
7185
|
+
|
|
7186
|
+
// src/fleet/enrolment-store.ts
|
|
7187
|
+
function machineScopeDir(platform2 = process.platform, env = process.env) {
|
|
7188
|
+
if (platform2 === "darwin") return "/Library/Application Support/AstraSync";
|
|
7189
|
+
if (platform2 === "win32") return (0, import_path5.join)(env.ProgramData || "C:\\ProgramData", "AstraSync");
|
|
7190
|
+
return "/etc/astrasync";
|
|
7191
|
+
}
|
|
7192
|
+
function fleetPaths(options = {}) {
|
|
7193
|
+
const home = options.home ?? (0, import_os.homedir)();
|
|
7194
|
+
const machineDir = options.machineDir ?? options.env?.ASTRASYNC_FLEET_MACHINE_DIR ?? machineScopeDir(options.platform, options.env);
|
|
7195
|
+
const userDir = (0, import_path5.join)(home, ".astrasync", "fleet");
|
|
7196
|
+
return {
|
|
7197
|
+
machineDevice: (0, import_path5.join)(machineDir, "fleet.json"),
|
|
7198
|
+
machinePolicy: (0, import_path5.join)(machineDir, "policy.jws"),
|
|
7199
|
+
userDir,
|
|
7200
|
+
userDevice: (0, import_path5.join)(userDir, "device.json"),
|
|
7201
|
+
userPolicy: (0, import_path5.join)(userDir, "policy.jws"),
|
|
7202
|
+
userKeyChain: (0, import_path5.join)(userDir, "keychain.json"),
|
|
7203
|
+
state: (0, import_path5.join)(userDir, "state.json")
|
|
7204
|
+
};
|
|
7205
|
+
}
|
|
7206
|
+
function isEnrolment(value) {
|
|
7207
|
+
const v = value;
|
|
7208
|
+
return !!v && typeof v.deviceId === "string" && typeof v.credential === "string" && typeof v.apiBaseUrl === "string" && !!v.org && typeof v.org.ownerId === "string" && !!v.jwks && Array.isArray(v.jwks.keys);
|
|
7209
|
+
}
|
|
7210
|
+
function loadEnrolment(paths) {
|
|
7211
|
+
const candidates = [
|
|
7212
|
+
[paths.machineDevice, "machine"],
|
|
7213
|
+
[paths.userDevice, "user"]
|
|
7214
|
+
];
|
|
7215
|
+
for (const [path2, scope] of candidates) {
|
|
7216
|
+
if (!(0, import_fs6.existsSync)(path2)) continue;
|
|
7217
|
+
try {
|
|
7218
|
+
const parsed = JSON.parse((0, import_fs6.readFileSync)(path2, "utf-8"));
|
|
7219
|
+
if (isEnrolment(parsed)) return { enrolment: parsed, scope };
|
|
7220
|
+
} catch {
|
|
7221
|
+
}
|
|
7222
|
+
return { corrupt: true, path: path2 };
|
|
7223
|
+
}
|
|
7224
|
+
return null;
|
|
7225
|
+
}
|
|
7226
|
+
function writeFileMode(path2, content, mode) {
|
|
7227
|
+
(0, import_fs6.mkdirSync)((0, import_path5.dirname)(path2), { recursive: true, mode: 448 });
|
|
7228
|
+
(0, import_fs6.writeFileSync)(path2, content, { encoding: "utf-8", mode });
|
|
7229
|
+
try {
|
|
7230
|
+
(0, import_fs6.chmodSync)(path2, mode);
|
|
7231
|
+
} catch {
|
|
7232
|
+
}
|
|
7233
|
+
}
|
|
7234
|
+
function saveEnrolment(paths, enrolment, scope) {
|
|
7235
|
+
const path2 = scope === "machine" ? paths.machineDevice : paths.userDevice;
|
|
7236
|
+
writeFileMode(path2, JSON.stringify(enrolment, null, 2), scope === "machine" ? 420 : 384);
|
|
7237
|
+
return path2;
|
|
7238
|
+
}
|
|
7239
|
+
function readCachedPolicies(paths) {
|
|
7240
|
+
const out = [];
|
|
7241
|
+
for (const p of [paths.userPolicy, paths.machinePolicy]) {
|
|
7242
|
+
try {
|
|
7243
|
+
if ((0, import_fs6.existsSync)(p)) out.push((0, import_fs6.readFileSync)(p, "utf-8").trim());
|
|
7244
|
+
} catch {
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7247
|
+
return out.filter(Boolean);
|
|
7248
|
+
}
|
|
7249
|
+
function writeCachedPolicy(paths, jws) {
|
|
7250
|
+
writeFileMode(paths.userPolicy, jws, 384);
|
|
7251
|
+
}
|
|
7252
|
+
function readKeyChain(paths) {
|
|
7253
|
+
try {
|
|
7254
|
+
const parsed = JSON.parse((0, import_fs6.readFileSync)(paths.userKeyChain, "utf-8"));
|
|
7255
|
+
return Array.isArray(parsed) ? parsed.filter((j) => typeof j === "string") : [];
|
|
7256
|
+
} catch {
|
|
7257
|
+
return [];
|
|
7258
|
+
}
|
|
7259
|
+
}
|
|
7260
|
+
function writeKeyChain(paths, chain) {
|
|
7261
|
+
writeFileMode(paths.userKeyChain, JSON.stringify(chain), 384);
|
|
7262
|
+
}
|
|
7263
|
+
function writeMachinePolicy(paths, jws) {
|
|
7264
|
+
writeFileMode(paths.machinePolicy, jws, 420);
|
|
7265
|
+
}
|
|
7266
|
+
function readState(paths) {
|
|
7267
|
+
try {
|
|
7268
|
+
const parsed = JSON.parse((0, import_fs6.readFileSync)(paths.state, "utf-8"));
|
|
7269
|
+
const c = parsed.counts;
|
|
7270
|
+
return {
|
|
7271
|
+
...parsed,
|
|
7272
|
+
counts: { allow: c?.allow ?? 0, deny: c?.deny ?? 0, ask: c?.ask ?? 0 }
|
|
7273
|
+
};
|
|
7274
|
+
} catch {
|
|
7275
|
+
return { counts: { allow: 0, deny: 0, ask: 0 } };
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7278
|
+
function writeState(paths, state) {
|
|
7279
|
+
try {
|
|
7280
|
+
writeFileMode(paths.state, JSON.stringify(state, null, 2), 384);
|
|
7281
|
+
} catch {
|
|
7282
|
+
}
|
|
7283
|
+
}
|
|
7284
|
+
var import_fs6, import_os, import_path5;
|
|
7285
|
+
var init_enrolment_store = __esm({
|
|
7286
|
+
"src/fleet/enrolment-store.ts"() {
|
|
7287
|
+
"use strict";
|
|
7288
|
+
import_fs6 = require("fs");
|
|
7289
|
+
import_os = require("os");
|
|
7290
|
+
import_path5 = require("path");
|
|
7291
|
+
}
|
|
7292
|
+
});
|
|
7293
|
+
|
|
7294
|
+
// src/fleet/types.ts
|
|
7295
|
+
var FLEET_POLICY_TYP, FLEET_POLICY_AUD, FLEET_POLICY_ISS, FLEET_KEYS_TYP, FLEET_KEYS_AUD, DEFAULT_HEARTBEAT_INTERVAL_SEC;
|
|
7296
|
+
var init_types3 = __esm({
|
|
7297
|
+
"src/fleet/types.ts"() {
|
|
7298
|
+
"use strict";
|
|
7299
|
+
FLEET_POLICY_TYP = "fleet-policy+jwt";
|
|
7300
|
+
FLEET_POLICY_AUD = "astrasync:fleet-policy";
|
|
7301
|
+
FLEET_POLICY_ISS = "astrasync.ai";
|
|
7302
|
+
FLEET_KEYS_TYP = "fleet-keys+jwt";
|
|
7303
|
+
FLEET_KEYS_AUD = "astrasync:fleet-keys";
|
|
7304
|
+
DEFAULT_HEARTBEAT_INTERVAL_SEC = 900;
|
|
7305
|
+
}
|
|
7306
|
+
});
|
|
7307
|
+
|
|
7308
|
+
// src/fleet/policy-verify.ts
|
|
7309
|
+
function sha256Hex(text) {
|
|
7310
|
+
return (0, import_crypto.createHash)("sha256").update(text, "utf8").digest("hex");
|
|
7311
|
+
}
|
|
7312
|
+
function parseSettings(raw) {
|
|
7313
|
+
if (!raw || typeof raw !== "object") throw new FleetPolicyError("settings missing");
|
|
7314
|
+
const s = raw;
|
|
7315
|
+
if (s.posture !== "active" && s.posture !== "passive") {
|
|
7316
|
+
throw new FleetPolicyError("settings.posture must be active or passive");
|
|
7317
|
+
}
|
|
7318
|
+
if (s.failOpen !== void 0 && typeof s.failOpen !== "boolean") {
|
|
7319
|
+
throw new FleetPolicyError("settings.failOpen must be a boolean");
|
|
7320
|
+
}
|
|
7321
|
+
if (s.governMcp !== void 0 && typeof s.governMcp !== "boolean") {
|
|
7322
|
+
throw new FleetPolicyError("settings.governMcp must be a boolean");
|
|
7323
|
+
}
|
|
7324
|
+
if (s.skipTools !== void 0 && !(Array.isArray(s.skipTools) && s.skipTools.every((t) => typeof t === "string"))) {
|
|
7325
|
+
throw new FleetPolicyError("settings.skipTools must be a string array");
|
|
7326
|
+
}
|
|
7327
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : void 0;
|
|
7328
|
+
return {
|
|
7329
|
+
posture: s.posture,
|
|
7330
|
+
failOpen: s.failOpen === true,
|
|
7331
|
+
...typeof s.governMcp === "boolean" && { governMcp: s.governMcp },
|
|
7332
|
+
...Array.isArray(s.skipTools) && { skipTools: s.skipTools },
|
|
7333
|
+
...num(s.heartbeatIntervalSec) && { heartbeatIntervalSec: num(s.heartbeatIntervalSec) },
|
|
7334
|
+
...num(s.staleAfterSec) && { staleAfterSec: num(s.staleAfterSec) }
|
|
7335
|
+
};
|
|
7336
|
+
}
|
|
7337
|
+
async function verifyFleetPolicy(jws, jwks, options) {
|
|
7338
|
+
let payloadBytes;
|
|
7339
|
+
let header;
|
|
7340
|
+
try {
|
|
7341
|
+
const keySet = (0, import_jose2.createLocalJWKSet)(jwks);
|
|
7342
|
+
const result = await (0, import_jose2.compactVerify)(jws, keySet, { algorithms: ["ES256"] });
|
|
7343
|
+
payloadBytes = result.payload;
|
|
7344
|
+
header = result.protectedHeader;
|
|
7345
|
+
} catch (err) {
|
|
7346
|
+
throw new FleetPolicyError(
|
|
7347
|
+
`signature verification failed (${err instanceof Error ? err.message : String(err)})`
|
|
7348
|
+
);
|
|
7349
|
+
}
|
|
7350
|
+
if (header.typ !== FLEET_POLICY_TYP) throw new FleetPolicyError(`unexpected typ ${header.typ}`);
|
|
7351
|
+
let claims;
|
|
7352
|
+
try {
|
|
7353
|
+
claims = JSON.parse(new TextDecoder().decode(payloadBytes));
|
|
7354
|
+
} catch {
|
|
7355
|
+
throw new FleetPolicyError("payload is not JSON");
|
|
7356
|
+
}
|
|
7357
|
+
if (claims.aud !== FLEET_POLICY_AUD) throw new FleetPolicyError(`unexpected aud ${claims.aud}`);
|
|
7358
|
+
if (claims.iss !== FLEET_POLICY_ISS) throw new FleetPolicyError(`unexpected iss ${claims.iss}`);
|
|
7359
|
+
if (!options.expectedSubs.includes(claims.sub)) {
|
|
7360
|
+
throw new FleetPolicyError("policy was issued for a different organisation or device");
|
|
7361
|
+
}
|
|
7362
|
+
if (!Number.isInteger(claims.ver) || claims.ver < 1) {
|
|
7363
|
+
throw new FleetPolicyError("ver must be a positive integer");
|
|
7364
|
+
}
|
|
7365
|
+
if (options.minVer !== void 0 && claims.ver < options.minVer) {
|
|
7366
|
+
throw new FleetPolicyError(
|
|
7367
|
+
`policy version ${claims.ver} is older than the accepted version ${options.minVer} (rollback)`
|
|
7368
|
+
);
|
|
7369
|
+
}
|
|
7370
|
+
if (typeof claims.yaml !== "string" || sha256Hex(claims.yaml) !== claims.sha256) {
|
|
7371
|
+
throw new FleetPolicyError("policy hash mismatch");
|
|
7372
|
+
}
|
|
7373
|
+
const settings = parseSettings(claims.settings);
|
|
7374
|
+
const parsed = parseYaml(claims.yaml);
|
|
7375
|
+
if (!parsed.policy) {
|
|
7376
|
+
const first = parsed.validation.errors[0];
|
|
7377
|
+
throw new FleetPolicyError(
|
|
7378
|
+
`signed policy is invalid${first ? ` (${first.path}: ${first.message})` : ""}`
|
|
7379
|
+
);
|
|
7380
|
+
}
|
|
7381
|
+
return { kid: header.kid, claims: { ...claims, settings }, policy: parsed.policy, settings, jws };
|
|
7382
|
+
}
|
|
7383
|
+
async function resolveFleetJwks(pinned, chain, ownerId) {
|
|
7384
|
+
let trusted = pinned;
|
|
7385
|
+
let lastSeq = 0;
|
|
7386
|
+
for (const link of chain) {
|
|
7387
|
+
try {
|
|
7388
|
+
const { payload, protectedHeader } = await (0, import_jose2.compactVerify)(
|
|
7389
|
+
link,
|
|
7390
|
+
(0, import_jose2.createLocalJWKSet)(trusted),
|
|
7391
|
+
{ algorithms: ["ES256"] }
|
|
7392
|
+
);
|
|
7393
|
+
if (protectedHeader.typ !== FLEET_KEYS_TYP) continue;
|
|
7394
|
+
const c = JSON.parse(new TextDecoder().decode(payload));
|
|
7395
|
+
if (c.aud !== FLEET_KEYS_AUD || c.iss !== FLEET_POLICY_ISS || c.sub !== ownerId) continue;
|
|
7396
|
+
if (!Number.isInteger(c.seq) || c.seq <= lastSeq) continue;
|
|
7397
|
+
const keys = Array.isArray(c.keys) ? c.keys.filter((k) => k && k.kty === "EC" && k.crv === "P-256" && !("d" in k)) : [];
|
|
7398
|
+
if (keys.length === 0) continue;
|
|
7399
|
+
trusted = { keys };
|
|
7400
|
+
lastSeq = c.seq;
|
|
7401
|
+
} catch {
|
|
7402
|
+
}
|
|
7403
|
+
}
|
|
7404
|
+
return trusted;
|
|
7405
|
+
}
|
|
7406
|
+
async function pickNewestValid(candidates, jwks, options) {
|
|
7407
|
+
let best = null;
|
|
7408
|
+
let lastError = new FleetPolicyError("no cached fleet policy");
|
|
7409
|
+
for (const jws of candidates) {
|
|
7410
|
+
try {
|
|
7411
|
+
const v = await verifyFleetPolicy(jws, jwks, options);
|
|
7412
|
+
if (!best || v.claims.ver > best.claims.ver) best = v;
|
|
7413
|
+
} catch (err) {
|
|
7414
|
+
lastError = err instanceof Error ? err : new FleetPolicyError(String(err));
|
|
7415
|
+
}
|
|
7416
|
+
}
|
|
7417
|
+
if (!best) throw lastError;
|
|
7418
|
+
return best;
|
|
7419
|
+
}
|
|
7420
|
+
var import_crypto, import_jose2, FleetPolicyError;
|
|
7421
|
+
var init_policy_verify = __esm({
|
|
7422
|
+
"src/fleet/policy-verify.ts"() {
|
|
7423
|
+
"use strict";
|
|
7424
|
+
import_crypto = require("crypto");
|
|
7425
|
+
import_jose2 = require("jose");
|
|
7426
|
+
init_pdlss_parser();
|
|
7427
|
+
init_types3();
|
|
7428
|
+
FleetPolicyError = class extends Error {
|
|
7429
|
+
constructor(message) {
|
|
7430
|
+
super(message);
|
|
7431
|
+
this.name = "FleetPolicyError";
|
|
7432
|
+
}
|
|
7433
|
+
};
|
|
7434
|
+
}
|
|
7435
|
+
});
|
|
7436
|
+
|
|
7437
|
+
// src/fleet/cli.ts
|
|
7438
|
+
function machineFingerprint() {
|
|
7439
|
+
const candidates = ["/etc/machine-id", "/var/lib/dbus/machine-id"];
|
|
7440
|
+
let raw = "";
|
|
7441
|
+
for (const c of candidates) {
|
|
7442
|
+
try {
|
|
7443
|
+
if ((0, import_fs7.existsSync)(c)) {
|
|
7444
|
+
raw = (0, import_fs7.readFileSync)(c, "utf-8").trim();
|
|
7445
|
+
if (raw) break;
|
|
7446
|
+
}
|
|
7447
|
+
} catch {
|
|
7448
|
+
}
|
|
7449
|
+
}
|
|
7450
|
+
if (!raw) raw = `${(0, import_os2.hostname)()}|${(0, import_os2.platform)()}|${(0, import_os2.arch)()}`;
|
|
7451
|
+
return (0, import_crypto2.createHash)("sha256").update(`astrasync-fleet:${raw}`).digest("hex");
|
|
7452
|
+
}
|
|
7453
|
+
async function runEnroll(options) {
|
|
7454
|
+
const print = options.print ?? ((l) => console.log(l));
|
|
7455
|
+
const token = options.token.trim();
|
|
7456
|
+
if (!token)
|
|
7457
|
+
throw new Error("Usage: astrasync guard enroll <token> [--api-base-url <url>] [--system]");
|
|
7458
|
+
const apiBaseUrl = (options.apiBaseUrl ?? DEFAULT_FLEET_API_BASE_URL).replace(/\/+$/, "");
|
|
7459
|
+
const paths = options.paths ?? fleetPaths();
|
|
7460
|
+
const response = await enrolDevice(apiBaseUrl, {
|
|
7461
|
+
token,
|
|
7462
|
+
fingerprint: options.fingerprint ?? machineFingerprint(),
|
|
7463
|
+
hostname: (0, import_os2.hostname)(),
|
|
7464
|
+
os: { platform: (0, import_os2.platform)(), release: (0, import_os2.release)(), arch: (0, import_os2.arch)() },
|
|
7465
|
+
guardVersion: SDK_VERSION,
|
|
7466
|
+
adapters: options.adapters ?? [
|
|
7467
|
+
{ kind: "claude-code", managed: false },
|
|
7468
|
+
{ kind: "codex", managed: false }
|
|
7469
|
+
]
|
|
7470
|
+
});
|
|
7471
|
+
const enrolment = {
|
|
7472
|
+
version: 1,
|
|
7473
|
+
deviceId: response.deviceId,
|
|
7474
|
+
credential: response.credential,
|
|
7475
|
+
org: response.org,
|
|
7476
|
+
apiBaseUrl: response.apiBaseUrl || apiBaseUrl,
|
|
7477
|
+
jwks: response.jwks,
|
|
7478
|
+
heartbeatIntervalSec: response.heartbeatIntervalSec || DEFAULT_HEARTBEAT_INTERVAL_SEC,
|
|
7479
|
+
enrolledAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7480
|
+
};
|
|
7481
|
+
const verified = await verifyFleetPolicy(response.policyJws, enrolment.jwks, {
|
|
7482
|
+
expectedSubs: [enrolment.org.ownerId, enrolment.deviceId]
|
|
7483
|
+
});
|
|
7484
|
+
const scope = options.system ? "machine" : "user";
|
|
7485
|
+
const savedTo = saveEnrolment(paths, enrolment, scope);
|
|
7486
|
+
if (options.system) writeMachinePolicy(paths, response.policyJws);
|
|
7487
|
+
writeCachedPolicy(paths, response.policyJws);
|
|
7488
|
+
writeKeyChain(paths, []);
|
|
7489
|
+
const state = readState(paths);
|
|
7490
|
+
writeState(paths, {
|
|
7491
|
+
...state,
|
|
7492
|
+
appliedSha256: verified.claims.sha256,
|
|
7493
|
+
maxVer: Math.max(state.maxVer ?? 0, verified.claims.ver),
|
|
7494
|
+
revoked: false
|
|
7495
|
+
});
|
|
7496
|
+
print(
|
|
7497
|
+
`Enrolled in ${enrolment.org.name ?? enrolment.org.ownerId} (device ${enrolment.deviceId}).`
|
|
7498
|
+
);
|
|
7499
|
+
print(` Enrolment: ${savedTo} (${scope} scope)`);
|
|
7500
|
+
print(` Policy: v${verified.claims.ver}, posture ${verified.settings.posture}`);
|
|
7501
|
+
print(
|
|
7502
|
+
" Local policy.yaml / guard.json files are now ignored \u2014 the organisation policy governs."
|
|
7503
|
+
);
|
|
7504
|
+
return enrolment;
|
|
7505
|
+
}
|
|
7506
|
+
async function getFleetStatus(paths = fleetPaths()) {
|
|
7507
|
+
const loaded = loadEnrolment(paths);
|
|
7508
|
+
if (!loaded) return { enrolled: false };
|
|
7509
|
+
if ("corrupt" in loaded) return { enrolled: true, corrupt: loaded.path };
|
|
7510
|
+
const { enrolment, scope } = loaded;
|
|
7511
|
+
const state = readState(paths);
|
|
7512
|
+
let policy;
|
|
7513
|
+
try {
|
|
7514
|
+
const jwks = await resolveFleetJwks(enrolment.jwks, readKeyChain(paths), enrolment.org.ownerId);
|
|
7515
|
+
const v = await pickNewestValid(readCachedPolicies(paths), jwks, {
|
|
7516
|
+
expectedSubs: [enrolment.org.ownerId, enrolment.deviceId],
|
|
7517
|
+
minVer: state.maxVer
|
|
7518
|
+
});
|
|
7519
|
+
policy = {
|
|
7520
|
+
ver: v.claims.ver,
|
|
7521
|
+
sha256: v.claims.sha256,
|
|
7522
|
+
posture: v.settings.posture,
|
|
7523
|
+
failOpen: v.settings.failOpen
|
|
7524
|
+
};
|
|
7525
|
+
} catch (err) {
|
|
7526
|
+
policy = { error: err instanceof Error ? err.message : String(err) };
|
|
7527
|
+
}
|
|
7528
|
+
return {
|
|
7529
|
+
enrolled: true,
|
|
7530
|
+
scope,
|
|
7531
|
+
org: enrolment.org,
|
|
7532
|
+
deviceId: enrolment.deviceId,
|
|
7533
|
+
apiBaseUrl: enrolment.apiBaseUrl,
|
|
7534
|
+
policy,
|
|
7535
|
+
lastHeartbeatAt: state.lastHeartbeatAt,
|
|
7536
|
+
revoked: state.revoked === true,
|
|
7537
|
+
lastError: state.lastError,
|
|
7538
|
+
pendingCounts: state.counts
|
|
7539
|
+
};
|
|
7540
|
+
}
|
|
7541
|
+
function formatFleetStatus(status) {
|
|
7542
|
+
if (!status.enrolled) return ["Fleet: not enrolled (local policy mode)."];
|
|
7543
|
+
if (status.corrupt) {
|
|
7544
|
+
return [`Fleet: enrolment file ${status.corrupt} is unreadable \u2014 the guard fails closed.`];
|
|
7545
|
+
}
|
|
7546
|
+
const lines = [
|
|
7547
|
+
`Fleet: enrolled in ${status.org?.name ?? status.org?.ownerId} (${status.scope} scope)`,
|
|
7548
|
+
` Device: ${status.deviceId}`,
|
|
7549
|
+
` Platform: ${status.apiBaseUrl}`
|
|
7550
|
+
];
|
|
7551
|
+
if (status.policy && "error" in status.policy) {
|
|
7552
|
+
lines.push(` Policy: NO VALID SIGNED POLICY \u2014 ${status.policy.error} (guard denies)`);
|
|
7553
|
+
} else if (status.policy) {
|
|
7554
|
+
lines.push(
|
|
7555
|
+
` Policy: v${status.policy.ver} (${status.policy.sha256.slice(0, 12)}\u2026), posture ${status.policy.posture}${status.policy.failOpen ? ", fail-open" : ""}`
|
|
7556
|
+
);
|
|
7557
|
+
}
|
|
7558
|
+
lines.push(` Heartbeat: ${status.lastHeartbeatAt ?? "never"}`);
|
|
7559
|
+
if (status.revoked) {
|
|
7560
|
+
lines.push(" Status: REVOKED by the organisation \u2014 enforcing the last good policy");
|
|
7561
|
+
}
|
|
7562
|
+
if (status.lastError) lines.push(` Last sync error: ${status.lastError}`);
|
|
7563
|
+
return lines;
|
|
7564
|
+
}
|
|
7565
|
+
function managedHookCommand(target, os2) {
|
|
7566
|
+
const bin = target === "claude" ? "astrasync-claude-hook" : "astrasync-codex-hook";
|
|
7567
|
+
if (os2 === "win32") return `"C:\\Program Files\\nodejs\\${bin}.cmd"`;
|
|
7568
|
+
return `/usr/local/bin/${bin}`;
|
|
7569
|
+
}
|
|
7570
|
+
function buildClaudeManagedSettings(os2) {
|
|
7571
|
+
return {
|
|
7572
|
+
allowManagedHooksOnly: true,
|
|
7573
|
+
env: { ASTRASYNC_FLEET_REQUIRED: "1" },
|
|
7574
|
+
hooks: {
|
|
7575
|
+
PreToolUse: [
|
|
7576
|
+
{
|
|
7577
|
+
matcher: HOOK_MATCHER,
|
|
7578
|
+
hooks: [{ type: "command", command: managedHookCommand("claude", os2), timeout: 10 }]
|
|
7579
|
+
}
|
|
7580
|
+
]
|
|
7581
|
+
},
|
|
7582
|
+
permissions: { deny: [...GUARD_PERMISSION_DENY_RULES] }
|
|
7583
|
+
};
|
|
7584
|
+
}
|
|
7585
|
+
function tomlString(value) {
|
|
7586
|
+
return JSON.stringify(value);
|
|
7587
|
+
}
|
|
7588
|
+
function buildCodexRequirementsToml(os2) {
|
|
7589
|
+
const command = os2 === "win32" ? `set ASTRASYNC_FLEET_REQUIRED=1&& ${managedHookCommand("codex", os2)}` : `ASTRASYNC_FLEET_REQUIRED=1 ${managedHookCommand("codex", os2)}`;
|
|
7590
|
+
return [
|
|
7591
|
+
"# AstraSync Local Guard \u2014 managed hook (generated by `astrasync guard managed-settings --codex`)",
|
|
7592
|
+
`# Install at: ${MANAGED_SETTINGS_LOCATIONS.codex[os2]}`,
|
|
7593
|
+
"allow_managed_hooks_only = true",
|
|
7594
|
+
"",
|
|
7595
|
+
"[features]",
|
|
7596
|
+
"hooks = true",
|
|
7597
|
+
"",
|
|
7598
|
+
"[[hooks.PreToolUse]]",
|
|
7599
|
+
`matcher = ${tomlString(CODEX_HOOK_MATCHER)}`,
|
|
7600
|
+
"",
|
|
7601
|
+
"[[hooks.PreToolUse.hooks]]",
|
|
7602
|
+
'type = "command"',
|
|
7603
|
+
`command = ${tomlString(command)}`,
|
|
7604
|
+
"timeout = 10",
|
|
7605
|
+
'statusMessage = "AstraSync Local Guard"',
|
|
7606
|
+
""
|
|
7607
|
+
].join("\n");
|
|
7608
|
+
}
|
|
7609
|
+
function buildManagedSettingsFiles(targets) {
|
|
7610
|
+
const out = [];
|
|
7611
|
+
for (const target of targets) {
|
|
7612
|
+
for (const os2 of ["darwin", "linux", "win32"]) {
|
|
7613
|
+
const content = target === "claude" ? `${JSON.stringify(buildClaudeManagedSettings(os2), null, 2)}
|
|
7614
|
+
` : buildCodexRequirementsToml(os2);
|
|
7615
|
+
out.push({
|
|
7616
|
+
target,
|
|
7617
|
+
os: os2,
|
|
7618
|
+
installPath: MANAGED_SETTINGS_LOCATIONS[target][os2],
|
|
7619
|
+
fileName: `${target}-${os2}-${target === "claude" ? "managed-settings.json" : "requirements.toml"}`,
|
|
7620
|
+
content
|
|
7621
|
+
});
|
|
7622
|
+
}
|
|
7623
|
+
}
|
|
7624
|
+
return out;
|
|
7625
|
+
}
|
|
7626
|
+
function writeManagedSettings(files, outDir) {
|
|
7627
|
+
(0, import_fs7.mkdirSync)(outDir, { recursive: true });
|
|
7628
|
+
return files.map((f) => {
|
|
7629
|
+
const p = (0, import_path6.join)(outDir, f.fileName);
|
|
7630
|
+
(0, import_fs7.writeFileSync)(p, f.content, "utf-8");
|
|
7631
|
+
return p;
|
|
7632
|
+
});
|
|
7633
|
+
}
|
|
7634
|
+
var import_crypto2, import_fs7, import_os2, import_path6, DEFAULT_FLEET_API_BASE_URL, MANAGED_SETTINGS_LOCATIONS;
|
|
7635
|
+
var init_cli = __esm({
|
|
7636
|
+
"src/fleet/cli.ts"() {
|
|
7637
|
+
"use strict";
|
|
7638
|
+
import_crypto2 = require("crypto");
|
|
7639
|
+
import_fs7 = require("fs");
|
|
7640
|
+
import_os2 = require("os");
|
|
7641
|
+
import_path6 = require("path");
|
|
7642
|
+
init_settings_installer();
|
|
7643
|
+
init_settings_installer2();
|
|
7644
|
+
init_version();
|
|
7645
|
+
init_client2();
|
|
7646
|
+
init_enrolment_store();
|
|
7647
|
+
init_policy_verify();
|
|
7648
|
+
init_types3();
|
|
7649
|
+
DEFAULT_FLEET_API_BASE_URL = "https://astrasync.ai/api";
|
|
7650
|
+
MANAGED_SETTINGS_LOCATIONS = {
|
|
7651
|
+
// code.claude.com/docs/en/managed-settings
|
|
7652
|
+
claude: {
|
|
7653
|
+
darwin: "/Library/Application Support/ClaudeCode/managed-settings.json",
|
|
7654
|
+
linux: "/etc/claude-code/managed-settings.json",
|
|
7655
|
+
win32: "C:\\Program Files\\ClaudeCode\\managed-settings.json"
|
|
7656
|
+
},
|
|
7657
|
+
// learn.chatgpt.com/docs/enterprise/managed-configuration
|
|
7658
|
+
codex: {
|
|
7659
|
+
darwin: "/etc/codex/requirements.toml",
|
|
7660
|
+
linux: "/etc/codex/requirements.toml",
|
|
7661
|
+
win32: "%ProgramData%\\OpenAI\\Codex\\requirements.toml"
|
|
7662
|
+
}
|
|
7663
|
+
};
|
|
7664
|
+
}
|
|
7665
|
+
});
|
|
7666
|
+
|
|
7143
7667
|
// src/cli/guard.ts
|
|
7144
7668
|
var guard_exports = {};
|
|
7145
7669
|
function createPrompt() {
|
|
@@ -7278,6 +7802,9 @@ async function cmdStatus() {
|
|
|
7278
7802
|
}
|
|
7279
7803
|
});
|
|
7280
7804
|
console.log("\nAstraSync Local Guard Status\n");
|
|
7805
|
+
for (const line of formatFleetStatus(await getFleetStatus(fleetPaths()))) {
|
|
7806
|
+
console.log(` ${line}`);
|
|
7807
|
+
}
|
|
7281
7808
|
if (upgraded) {
|
|
7282
7809
|
const config = JSON.parse(fs.readFileSync(`${DEFAULT_CONFIG_DIR}/config`, "utf-8"));
|
|
7283
7810
|
console.log(` Mode: ${config.mode}`);
|
|
@@ -7633,6 +8160,66 @@ function printClaudeCodeStatus() {
|
|
|
7633
8160
|
}
|
|
7634
8161
|
}
|
|
7635
8162
|
}
|
|
8163
|
+
function flagValue(flag) {
|
|
8164
|
+
const i = process.argv.indexOf(flag);
|
|
8165
|
+
return i !== -1 ? process.argv[i + 1] : void 0;
|
|
8166
|
+
}
|
|
8167
|
+
function positionalAfter(command) {
|
|
8168
|
+
const argv = process.argv;
|
|
8169
|
+
const start = argv.indexOf(command) + 1;
|
|
8170
|
+
for (let i = start; i < argv.length; i++) {
|
|
8171
|
+
if (argv[i].startsWith("--")) {
|
|
8172
|
+
if (argv[i] === "--api-base-url" || argv[i] === "--out") i++;
|
|
8173
|
+
continue;
|
|
8174
|
+
}
|
|
8175
|
+
return argv[i];
|
|
8176
|
+
}
|
|
8177
|
+
return void 0;
|
|
8178
|
+
}
|
|
8179
|
+
async function cmdEnroll() {
|
|
8180
|
+
const token = positionalAfter("enroll") ?? "";
|
|
8181
|
+
try {
|
|
8182
|
+
await runEnroll({
|
|
8183
|
+
token,
|
|
8184
|
+
apiBaseUrl: flagValue("--api-base-url"),
|
|
8185
|
+
system: process.argv.includes("--system")
|
|
8186
|
+
});
|
|
8187
|
+
} catch (err) {
|
|
8188
|
+
console.error(`Enrolment failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8189
|
+
if (process.argv.includes("--system")) {
|
|
8190
|
+
console.error(
|
|
8191
|
+
" (--system writes the machine-scope enrolment and needs administrator rights)"
|
|
8192
|
+
);
|
|
8193
|
+
}
|
|
8194
|
+
process.exit(1);
|
|
8195
|
+
}
|
|
8196
|
+
}
|
|
8197
|
+
async function cmdFleetStatus() {
|
|
8198
|
+
const status = await getFleetStatus(fleetPaths());
|
|
8199
|
+
for (const line of formatFleetStatus(status)) console.log(line);
|
|
8200
|
+
}
|
|
8201
|
+
async function cmdManagedSettings() {
|
|
8202
|
+
const targets = [];
|
|
8203
|
+
if (process.argv.includes("--claude")) targets.push("claude");
|
|
8204
|
+
if (process.argv.includes("--codex")) targets.push("codex");
|
|
8205
|
+
if (targets.length === 0) targets.push("claude", "codex");
|
|
8206
|
+
const files = buildManagedSettingsFiles(targets);
|
|
8207
|
+
const outDir = flagValue("--out");
|
|
8208
|
+
if (outDir) {
|
|
8209
|
+
const written = writeManagedSettings(files, outDir);
|
|
8210
|
+
console.log("Managed-settings templates written:");
|
|
8211
|
+
files.forEach((f, i) => console.log(` ${written[i]} \u2192 deploy to ${f.installPath}`));
|
|
8212
|
+
} else {
|
|
8213
|
+
for (const f of files) {
|
|
8214
|
+
console.log(`===== ${f.target} \xB7 ${f.os} \u2192 ${f.installPath}`);
|
|
8215
|
+
console.log(f.content);
|
|
8216
|
+
}
|
|
8217
|
+
}
|
|
8218
|
+
console.log(
|
|
8219
|
+
"Hook commands assume npm\u2019s default global prefix; adjust if your MDM installs elsewhere."
|
|
8220
|
+
);
|
|
8221
|
+
console.log("Machines must also be enrolled: astrasync guard enroll <token> --system");
|
|
8222
|
+
}
|
|
7636
8223
|
async function main() {
|
|
7637
8224
|
const command = process.argv[2] === "guard" ? process.argv[3] : process.argv[2];
|
|
7638
8225
|
switch (command) {
|
|
@@ -7669,6 +8256,16 @@ async function main() {
|
|
|
7669
8256
|
case "uninstall-codex":
|
|
7670
8257
|
await cmdUninstallCodex();
|
|
7671
8258
|
break;
|
|
8259
|
+
case "enroll":
|
|
8260
|
+
case "enrol":
|
|
8261
|
+
await cmdEnroll();
|
|
8262
|
+
break;
|
|
8263
|
+
case "fleet-status":
|
|
8264
|
+
await cmdFleetStatus();
|
|
8265
|
+
break;
|
|
8266
|
+
case "managed-settings":
|
|
8267
|
+
await cmdManagedSettings();
|
|
8268
|
+
break;
|
|
7672
8269
|
default:
|
|
7673
8270
|
console.log("AstraSync Local Guard\n");
|
|
7674
8271
|
console.log("Usage: astrasync guard <command>\n");
|
|
@@ -7689,6 +8286,10 @@ async function main() {
|
|
|
7689
8286
|
console.log(" install-codex Install the Local Guard hook for OpenAI Codex CLI");
|
|
7690
8287
|
console.log(" (same flags; policy shared with Claude Code)");
|
|
7691
8288
|
console.log(" uninstall-codex Remove the Codex hook (--project for project scope)");
|
|
8289
|
+
console.log(" enroll <token> Enrol this machine in your organisation fleet");
|
|
8290
|
+
console.log(" (--api-base-url <url>, --system for machine scope)");
|
|
8291
|
+
console.log(" fleet-status Show fleet enrolment, signed policy and heartbeat");
|
|
8292
|
+
console.log(" managed-settings Print MDM templates (--claude, --codex, --out <dir>)");
|
|
7692
8293
|
console.log("");
|
|
7693
8294
|
process.exit(command ? 1 : 0);
|
|
7694
8295
|
}
|
|
@@ -7709,6 +8310,8 @@ var init_guard = __esm({
|
|
|
7709
8310
|
init_git_hooks();
|
|
7710
8311
|
init_settings_installer();
|
|
7711
8312
|
init_settings_installer2();
|
|
8313
|
+
init_cli();
|
|
8314
|
+
init_enrolment_store();
|
|
7712
8315
|
DEFAULT_POLICY_PATH = "./local-policy.yaml";
|
|
7713
8316
|
DEFAULT_CONFIG_DIR = ".astrasync";
|
|
7714
8317
|
main().catch((err) => {
|
|
@@ -7741,6 +8344,10 @@ COMMANDS:
|
|
|
7741
8344
|
verify <id> Look up an agent by ASTRA ID or UUID
|
|
7742
8345
|
health Check API health
|
|
7743
8346
|
guard <subcommand> Local Guard CLI (setup, start, status, install-claude-code, ...)
|
|
8347
|
+
guard enroll <token> Enrol this machine in your organisation's fleet
|
|
8348
|
+
(--api-base-url <url>, --system for machine scope)
|
|
8349
|
+
guard fleet-status Fleet enrolment, signed policy and heartbeat state
|
|
8350
|
+
guard managed-settings MDM templates for Claude Code / Codex (--claude, --codex, --out <dir>)
|
|
7744
8351
|
|
|
7745
8352
|
REGISTER OPTIONS:
|
|
7746
8353
|
--name <name> Agent name (required)
|