@astrasyncai/verification-gateway 5.15.0 → 5.17.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/README.md +9 -1
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +17 -2
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +17 -2
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +4 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +4 -1
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +17 -2
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +17 -2
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +1 -1
- package/dist/adapters/sdk.d.ts +1 -1
- package/dist/adapters/sdk.js +4 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +4 -1
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.d.mts +69 -54
- package/dist/agent/index.d.ts +69 -54
- package/dist/agent/index.js +24 -14
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +24 -14
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +4 -1
- package/dist/bin/astrasync-codex-hook.js +4 -1
- package/dist/bin/astrasync-guard.js +544 -25
- package/dist/bin/astrasync.js +590 -33
- package/dist/browser/background.js +4 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +4 -1
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +4 -1
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +4 -1
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +4 -1
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +4 -1
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +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.d.mts +1 -1
- package/dist/edge-core/index.d.ts +1 -1
- package/dist/edge-core/index.js +5 -2
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +5 -2
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +4 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +4 -1
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +96 -57
- package/dist/index.d.ts +96 -57
- package/dist/index.js +43 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -15
- 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/{types-Dxf9DBpr.d.mts → types-Blz520bR.d.mts} +10 -0
- package/dist/{types-Dxf9DBpr.d.ts → types-Blz520bR.d.ts} +10 -0
- package/dist/{types-DtJjlW4O.d.ts → types-Bm1QvGqI.d.ts} +10 -0
- package/dist/{types-Eg6VoBNH.d.mts → types-DBe4hgfT.d.mts} +10 -0
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +4 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +4 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -233,9 +233,9 @@ function requireType() {
|
|
|
233
233
|
}
|
|
234
234
|
function Type2(tag, options) {
|
|
235
235
|
options = options || {};
|
|
236
|
-
Object.keys(options).forEach(function(
|
|
237
|
-
if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(
|
|
238
|
-
throw new YAMLException2('Unknown option "' +
|
|
236
|
+
Object.keys(options).forEach(function(name2) {
|
|
237
|
+
if (TYPE_CONSTRUCTOR_OPTIONS.indexOf(name2) === -1) {
|
|
238
|
+
throw new YAMLException2('Unknown option "' + name2 + '" is met in definition of "' + tag + '" YAML type.');
|
|
239
239
|
}
|
|
240
240
|
});
|
|
241
241
|
this.options = options;
|
|
@@ -268,9 +268,9 @@ function requireSchema() {
|
|
|
268
268
|
hasRequiredSchema = 1;
|
|
269
269
|
const YAMLException2 = requireException();
|
|
270
270
|
const Type2 = requireType();
|
|
271
|
-
function compileList(schema2,
|
|
271
|
+
function compileList(schema2, name2) {
|
|
272
272
|
const result = [];
|
|
273
|
-
schema2[
|
|
273
|
+
schema2[name2].forEach(function(currentType) {
|
|
274
274
|
let newIndex = result.length;
|
|
275
275
|
result.forEach(function(previousType, previousIndex) {
|
|
276
276
|
if (previousType.tag === currentType.tag && previousType.kind === currentType.kind && previousType.multi === currentType.multi) {
|
|
@@ -1179,18 +1179,18 @@ function requireLoader() {
|
|
|
1179
1179
|
state.onWarning.call(null, generateError(state, message));
|
|
1180
1180
|
}
|
|
1181
1181
|
}
|
|
1182
|
-
function storeAnchor(state,
|
|
1182
|
+
function storeAnchor(state, name2, value) {
|
|
1183
1183
|
const transactions = state.anchorMapTransactions;
|
|
1184
1184
|
if (transactions.length !== 0) {
|
|
1185
1185
|
const transaction = transactions[transactions.length - 1];
|
|
1186
|
-
if (!_hasOwnProperty.call(transaction,
|
|
1187
|
-
transaction[
|
|
1188
|
-
existed: _hasOwnProperty.call(state.anchorMap,
|
|
1189
|
-
value: state.anchorMap[
|
|
1186
|
+
if (!_hasOwnProperty.call(transaction, name2)) {
|
|
1187
|
+
transaction[name2] = {
|
|
1188
|
+
existed: _hasOwnProperty.call(state.anchorMap, name2),
|
|
1189
|
+
value: state.anchorMap[name2]
|
|
1190
1190
|
};
|
|
1191
1191
|
}
|
|
1192
1192
|
}
|
|
1193
|
-
state.anchorMap[
|
|
1193
|
+
state.anchorMap[name2] = value;
|
|
1194
1194
|
}
|
|
1195
1195
|
function beginAnchorTransaction(state) {
|
|
1196
1196
|
state.anchorMapTransactions.push(/* @__PURE__ */ Object.create(null));
|
|
@@ -1202,9 +1202,9 @@ function requireLoader() {
|
|
|
1202
1202
|
const parent = transactions[transactions.length - 1];
|
|
1203
1203
|
const names = Object.keys(transaction);
|
|
1204
1204
|
for (let index = 0, length = names.length; index < length; index += 1) {
|
|
1205
|
-
const
|
|
1206
|
-
if (!_hasOwnProperty.call(parent,
|
|
1207
|
-
parent[
|
|
1205
|
+
const name2 = names[index];
|
|
1206
|
+
if (!_hasOwnProperty.call(parent, name2)) {
|
|
1207
|
+
parent[name2] = transaction[name2];
|
|
1208
1208
|
}
|
|
1209
1209
|
}
|
|
1210
1210
|
}
|
|
@@ -1245,7 +1245,7 @@ function requireLoader() {
|
|
|
1245
1245
|
state.result = snapshot.result;
|
|
1246
1246
|
}
|
|
1247
1247
|
const directiveHandlers = {
|
|
1248
|
-
YAML: function handleYamlDirective(state,
|
|
1248
|
+
YAML: function handleYamlDirective(state, name2, args) {
|
|
1249
1249
|
if (state.version !== null) {
|
|
1250
1250
|
throwError(state, "duplication of %YAML directive");
|
|
1251
1251
|
}
|
|
@@ -1267,7 +1267,7 @@ function requireLoader() {
|
|
|
1267
1267
|
throwWarning(state, "unsupported YAML version of the document");
|
|
1268
1268
|
}
|
|
1269
1269
|
},
|
|
1270
|
-
TAG: function handleTagDirective(state,
|
|
1270
|
+
TAG: function handleTagDirective(state, name2, args) {
|
|
1271
1271
|
let prefix;
|
|
1272
1272
|
if (args.length !== 2) {
|
|
1273
1273
|
throwError(state, "TAG directive accepts exactly two arguments");
|
|
@@ -3573,10 +3573,10 @@ ${category.label}
|
|
|
3573
3573
|
scope.blockedResources = additionalBlocked;
|
|
3574
3574
|
}
|
|
3575
3575
|
this.print("");
|
|
3576
|
-
const
|
|
3576
|
+
const name2 = (await this.ask("Policy name [default: local-guard]: ")).trim() || "local-guard";
|
|
3577
3577
|
const policy = {
|
|
3578
3578
|
version: "1.0",
|
|
3579
|
-
name,
|
|
3579
|
+
name: name2,
|
|
3580
3580
|
purposes,
|
|
3581
3581
|
...scope && { scope },
|
|
3582
3582
|
...limits && { limits },
|
|
@@ -3713,7 +3713,7 @@ Policy saved to ${outputPath}`);
|
|
|
3713
3713
|
};
|
|
3714
3714
|
|
|
3715
3715
|
// src/version.ts
|
|
3716
|
-
var SDK_VERSION = "5.
|
|
3716
|
+
var SDK_VERSION = "5.17.0";
|
|
3717
3717
|
|
|
3718
3718
|
// src/http.ts
|
|
3719
3719
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -3725,10 +3725,10 @@ function withUserAgent(initHeaders) {
|
|
|
3725
3725
|
return copy;
|
|
3726
3726
|
}
|
|
3727
3727
|
if (Array.isArray(initHeaders)) {
|
|
3728
|
-
const has2 = initHeaders.some(([
|
|
3728
|
+
const has2 = initHeaders.some(([name2]) => name2.toLowerCase() === "user-agent");
|
|
3729
3729
|
return has2 ? initHeaders : [...initHeaders, ["user-agent", SDK_USER_AGENT]];
|
|
3730
3730
|
}
|
|
3731
|
-
const has = Object.keys(initHeaders).some((
|
|
3731
|
+
const has = Object.keys(initHeaders).some((name2) => name2.toLowerCase() === "user-agent");
|
|
3732
3732
|
return has ? initHeaders : { "user-agent": SDK_USER_AGENT, ...initHeaders };
|
|
3733
3733
|
}
|
|
3734
3734
|
var sdkFetch = (input, init) => fetch(input, { ...init, headers: withUserAgent(init?.headers) });
|
|
@@ -4303,8 +4303,8 @@ function extractBacktickSubstitutions(text, collect) {
|
|
|
4303
4303
|
}
|
|
4304
4304
|
function basename(token) {
|
|
4305
4305
|
const slash = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
|
|
4306
|
-
const
|
|
4307
|
-
return
|
|
4306
|
+
const name2 = slash === -1 ? token : token.slice(slash + 1);
|
|
4307
|
+
return name2.replace(/\.(exe|cmd|bat|ps1)$/i, "");
|
|
4308
4308
|
}
|
|
4309
4309
|
function matchSegment(segment, list) {
|
|
4310
4310
|
const tokens = segment.split(/\s+/).filter((t) => /[a-z0-9]/.test(t));
|
|
@@ -4754,6 +4754,8 @@ function getCacheKey(request2, counterpartyId) {
|
|
|
4754
4754
|
request2.durationRequired ?? "",
|
|
4755
4755
|
request2.invocationProtocol || "",
|
|
4756
4756
|
request2.enableRuntimeChallenge ? "1" : "0",
|
|
4757
|
+
// 5.16.0: route policy changes the verdict (owners / challenge).
|
|
4758
|
+
request2.routePolicy ? JSON.stringify(request2.routePolicy) : "",
|
|
4757
4759
|
// callerMetadata fields contribute to risk model; include the ones
|
|
4758
4760
|
// backend reads. sourceIp/userAgent/forwardedFor change per-request
|
|
4759
4761
|
// so their inclusion effectively forces a re-check for any varying
|
|
@@ -4926,6 +4928,7 @@ async function callVerifyAccessAPI(config, request2) {
|
|
|
4926
4928
|
if (requestData.subAgentDepth !== void 0) body.subAgentDepth = requestData.subAgentDepth;
|
|
4927
4929
|
if (requestData.enableRuntimeChallenge)
|
|
4928
4930
|
body.enableRuntimeChallenge = requestData.enableRuntimeChallenge;
|
|
4931
|
+
if (requestData.routePolicy) body.routePolicy = requestData.routePolicy;
|
|
4929
4932
|
if (requestData.createSession) body.createSession = requestData.createSession;
|
|
4930
4933
|
if (requestData.durationRequired) body.durationRequired = requestData.durationRequired;
|
|
4931
4934
|
if (requestData.counterpartyType) body.counterpartyType = requestData.counterpartyType;
|
|
@@ -6426,7 +6429,7 @@ function ensureGuardSelfProtection(policyPath) {
|
|
|
6426
6429
|
(0, import_fs5.writeFileSync)(policyPath, toYaml(parsed.policy), "utf-8");
|
|
6427
6430
|
return true;
|
|
6428
6431
|
}
|
|
6429
|
-
function buildDefaultClaudeCodePolicy(
|
|
6432
|
+
function buildDefaultClaudeCodePolicy(name2 = "claude-code-local-guard") {
|
|
6430
6433
|
const recommendedCommands = DEFAULT_BLOCKED_COMMANDS.filter((c) => c.recommended).map(
|
|
6431
6434
|
(c) => c.pattern
|
|
6432
6435
|
);
|
|
@@ -6434,7 +6437,7 @@ function buildDefaultClaudeCodePolicy(name = "claude-code-local-guard") {
|
|
|
6434
6437
|
const permissive = RISK_PRESETS.find((p) => p.name === "permissive");
|
|
6435
6438
|
return {
|
|
6436
6439
|
version: "1.0",
|
|
6437
|
-
name,
|
|
6440
|
+
name: name2,
|
|
6438
6441
|
description: "AstraSync Local Guard for Claude Code \u2014 default coding-agent policy. Edit freely; the hook re-reads this file on every tool call.",
|
|
6439
6442
|
purposes: [
|
|
6440
6443
|
{
|
|
@@ -6981,6 +6984,454 @@ function writeManagedSettings(files, outDir) {
|
|
|
6981
6984
|
});
|
|
6982
6985
|
}
|
|
6983
6986
|
|
|
6987
|
+
// src/fleet/git-route.ts
|
|
6988
|
+
var import_child_process2 = require("child_process");
|
|
6989
|
+
var realGit = (args) => (0, import_child_process2.execFileSync)("git", args, { encoding: "utf-8" });
|
|
6990
|
+
function gitRouteConfig(opts) {
|
|
6991
|
+
const base2 = opts.checkpoint.replace(/\/+$/, "");
|
|
6992
|
+
if (!/^https:\/\//.test(base2) && !/^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/.test(base2)) {
|
|
6993
|
+
throw new Error("--checkpoint must be an https:// URL");
|
|
6994
|
+
}
|
|
6995
|
+
if (!/^ASTRA-[A-Za-z0-9_-]{8,64}$/.test(opts.agent))
|
|
6996
|
+
throw new Error("--agent must be an ASTRA-id");
|
|
6997
|
+
if (!/^[A-Za-z0-9_-]{4,120}$/.test(opts.slug))
|
|
6998
|
+
throw new Error("--slug must be the connector slug");
|
|
6999
|
+
const upstream = opts.upstream ?? "github";
|
|
7000
|
+
return [
|
|
7001
|
+
[`url.${base2}/a/${opts.slug}/git/${upstream}/.insteadOf`, opts.host ?? "https://github.com/"],
|
|
7002
|
+
[`credential.${base2}.helper`, "!astrasync guard git-credential"],
|
|
7003
|
+
["astrasync.agent", opts.agent],
|
|
7004
|
+
["astrasync.checkpoint", base2]
|
|
7005
|
+
];
|
|
7006
|
+
}
|
|
7007
|
+
function applyGitRoute(opts, git = realGit) {
|
|
7008
|
+
const entries = gitRouteConfig(opts);
|
|
7009
|
+
for (const [key, value] of entries) git(["config", "--global", key, value]);
|
|
7010
|
+
return entries.map(([k, v]) => `${k} = ${v}`);
|
|
7011
|
+
}
|
|
7012
|
+
function removeGitRoute(git = realGit) {
|
|
7013
|
+
let base2 = "";
|
|
7014
|
+
try {
|
|
7015
|
+
base2 = git(["config", "--global", "--get", "astrasync.checkpoint"]).trim();
|
|
7016
|
+
} catch {
|
|
7017
|
+
return [];
|
|
7018
|
+
}
|
|
7019
|
+
const removed = [];
|
|
7020
|
+
const unset = (args) => {
|
|
7021
|
+
try {
|
|
7022
|
+
git(["config", "--global", ...args]);
|
|
7023
|
+
removed.push(args[args.length - 1]);
|
|
7024
|
+
} catch {
|
|
7025
|
+
}
|
|
7026
|
+
};
|
|
7027
|
+
let urls = "";
|
|
7028
|
+
try {
|
|
7029
|
+
urls = git(["config", "--global", "--get-regexp", "^url\\..*\\.insteadof$"]);
|
|
7030
|
+
} catch {
|
|
7031
|
+
}
|
|
7032
|
+
for (const line of urls.split("\n")) {
|
|
7033
|
+
const key = line.split(" ")[0];
|
|
7034
|
+
if (key && key.toLowerCase().startsWith(`url.${base2}/`.toLowerCase())) unset(["--unset", key]);
|
|
7035
|
+
}
|
|
7036
|
+
unset(["--unset", `credential.${base2}.helper`]);
|
|
7037
|
+
unset(["--unset", "astrasync.agent"]);
|
|
7038
|
+
unset(["--unset", "astrasync.checkpoint"]);
|
|
7039
|
+
return removed;
|
|
7040
|
+
}
|
|
7041
|
+
function gitCredentialAnswer(action, input, deps) {
|
|
7042
|
+
if (action !== "get" || !deps.agent || !deps.checkpoint || !deps.deviceCredential) return "";
|
|
7043
|
+
const fields = Object.fromEntries(
|
|
7044
|
+
input.split("\n").map((l) => l.split("=")).filter((p) => p.length >= 2).map(([k, ...v]) => [k, v.join("=")])
|
|
7045
|
+
);
|
|
7046
|
+
const host = new URL(deps.checkpoint).host;
|
|
7047
|
+
if (fields.host && fields.host !== host) return "";
|
|
7048
|
+
return `username=${deps.agent}
|
|
7049
|
+
password=${deps.deviceCredential}
|
|
7050
|
+
`;
|
|
7051
|
+
}
|
|
7052
|
+
function runGitCredential(action, input, git = realGit) {
|
|
7053
|
+
const read = (key) => {
|
|
7054
|
+
try {
|
|
7055
|
+
return git(["config", "--global", "--get", key]).trim();
|
|
7056
|
+
} catch {
|
|
7057
|
+
return void 0;
|
|
7058
|
+
}
|
|
7059
|
+
};
|
|
7060
|
+
const loaded = loadEnrolment(fleetPaths());
|
|
7061
|
+
const deviceCredential = loaded && "enrolment" in loaded ? loaded.enrolment.credential : void 0;
|
|
7062
|
+
return gitCredentialAnswer(action, input, {
|
|
7063
|
+
agent: read("astrasync.agent"),
|
|
7064
|
+
checkpoint: read("astrasync.checkpoint"),
|
|
7065
|
+
deviceCredential
|
|
7066
|
+
});
|
|
7067
|
+
}
|
|
7068
|
+
|
|
7069
|
+
// src/fleet/browse-proxy.ts
|
|
7070
|
+
var import_node_http = __toESM(require("http"));
|
|
7071
|
+
var import_node_https = __toESM(require("https"));
|
|
7072
|
+
var import_node_net = __toESM(require("net"));
|
|
7073
|
+
var import_node_tls = __toESM(require("tls"));
|
|
7074
|
+
|
|
7075
|
+
// src/fleet/local-cert.ts
|
|
7076
|
+
var import_node_crypto5 = __toESM(require("crypto"));
|
|
7077
|
+
function len(n) {
|
|
7078
|
+
if (n < 128) return Buffer.from([n]);
|
|
7079
|
+
const bytes = [];
|
|
7080
|
+
while (n > 0) {
|
|
7081
|
+
bytes.unshift(n & 255);
|
|
7082
|
+
n >>= 8;
|
|
7083
|
+
}
|
|
7084
|
+
return Buffer.from([128 | bytes.length, ...bytes]);
|
|
7085
|
+
}
|
|
7086
|
+
var tlv = (tag, body) => Buffer.concat([Buffer.from([tag]), len(body.length), body]);
|
|
7087
|
+
var seq2 = (...parts) => tlv(48, Buffer.concat(parts));
|
|
7088
|
+
var set2 = (...parts) => tlv(49, Buffer.concat(parts));
|
|
7089
|
+
var ctx = (n, body) => tlv(160 + n, body);
|
|
7090
|
+
function oid(dotted) {
|
|
7091
|
+
const parts = dotted.split(".").map(Number);
|
|
7092
|
+
const out = [parts[0] * 40 + parts[1]];
|
|
7093
|
+
for (const p of parts.slice(2)) {
|
|
7094
|
+
const enc = [p & 127];
|
|
7095
|
+
let v = p >> 7;
|
|
7096
|
+
while (v > 0) {
|
|
7097
|
+
enc.unshift(v & 127 | 128);
|
|
7098
|
+
v >>= 7;
|
|
7099
|
+
}
|
|
7100
|
+
out.push(...enc);
|
|
7101
|
+
}
|
|
7102
|
+
return tlv(6, Buffer.from(out));
|
|
7103
|
+
}
|
|
7104
|
+
function integer(buf) {
|
|
7105
|
+
const b = buf[0] & 128 ? Buffer.concat([Buffer.from([0]), buf]) : buf;
|
|
7106
|
+
return tlv(2, b);
|
|
7107
|
+
}
|
|
7108
|
+
function utcTime(d) {
|
|
7109
|
+
const s = d.toISOString().replace(/[-:T]/g, "").slice(2, 14) + "Z";
|
|
7110
|
+
return tlv(23, Buffer.from(s, "ascii"));
|
|
7111
|
+
}
|
|
7112
|
+
var ECDSA_SHA256 = seq2(oid("1.2.840.10045.4.3.2"));
|
|
7113
|
+
function name(cn) {
|
|
7114
|
+
return seq2(set2(seq2(oid("2.5.4.3"), tlv(12, Buffer.from(cn, "utf8")))));
|
|
7115
|
+
}
|
|
7116
|
+
function createLocalCert(hosts, days = 30) {
|
|
7117
|
+
const { privateKey, publicKey } = import_node_crypto5.default.generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
7118
|
+
const spki = publicKey.export({ type: "spki", format: "der" });
|
|
7119
|
+
const now = Date.now();
|
|
7120
|
+
const san = seq2(...hosts.map((h) => tlv(130, Buffer.from(h, "ascii"))));
|
|
7121
|
+
const extensions = ctx(
|
|
7122
|
+
3,
|
|
7123
|
+
seq2(
|
|
7124
|
+
seq2(oid("2.5.29.17"), tlv(4, san)),
|
|
7125
|
+
// subjectAltName
|
|
7126
|
+
seq2(oid("2.5.29.19"), tlv(4, seq2()))
|
|
7127
|
+
// basicConstraints: not a CA
|
|
7128
|
+
)
|
|
7129
|
+
);
|
|
7130
|
+
const subject = name("AstraSync Local Guard (browse)");
|
|
7131
|
+
const tbs = seq2(
|
|
7132
|
+
ctx(0, integer(Buffer.from([2]))),
|
|
7133
|
+
// v3
|
|
7134
|
+
integer(import_node_crypto5.default.randomBytes(16)),
|
|
7135
|
+
ECDSA_SHA256,
|
|
7136
|
+
subject,
|
|
7137
|
+
seq2(utcTime(new Date(now - 6e4)), utcTime(new Date(now + days * 864e5))),
|
|
7138
|
+
subject,
|
|
7139
|
+
spki,
|
|
7140
|
+
extensions
|
|
7141
|
+
);
|
|
7142
|
+
const signature = import_node_crypto5.default.sign("sha256", tbs, privateKey);
|
|
7143
|
+
const der = seq2(tbs, ECDSA_SHA256, tlv(3, Buffer.concat([Buffer.from([0]), signature])));
|
|
7144
|
+
const b64 = der.toString("base64").match(/.{1,64}/g).join("\n");
|
|
7145
|
+
return {
|
|
7146
|
+
cert: `-----BEGIN CERTIFICATE-----
|
|
7147
|
+
${b64}
|
|
7148
|
+
-----END CERTIFICATE-----
|
|
7149
|
+
`,
|
|
7150
|
+
key: privateKey.export({ type: "pkcs8", format: "pem" }).toString()
|
|
7151
|
+
};
|
|
7152
|
+
}
|
|
7153
|
+
|
|
7154
|
+
// src/fleet/browse-proxy.ts
|
|
7155
|
+
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
7156
|
+
"connection",
|
|
7157
|
+
"proxy-connection",
|
|
7158
|
+
"keep-alive",
|
|
7159
|
+
"transfer-encoding",
|
|
7160
|
+
"upgrade",
|
|
7161
|
+
"te",
|
|
7162
|
+
"trailer",
|
|
7163
|
+
"proxy-authorization"
|
|
7164
|
+
]);
|
|
7165
|
+
function cleanHeaders(h) {
|
|
7166
|
+
const out = {};
|
|
7167
|
+
for (const [k, v] of Object.entries(h)) if (!HOP_BY_HOP.has(k) && v !== void 0) out[k] = v;
|
|
7168
|
+
return out;
|
|
7169
|
+
}
|
|
7170
|
+
async function startBrowseProxy(opts) {
|
|
7171
|
+
const hosts = new Set(opts.hosts.map((h) => h.toLowerCase()));
|
|
7172
|
+
const deviceHeader = `Device ${opts.deviceCredential}`;
|
|
7173
|
+
const { cert, key } = createLocalCert([...hosts]);
|
|
7174
|
+
function forward(req, res, target) {
|
|
7175
|
+
const headers = cleanHeaders(req.headers);
|
|
7176
|
+
headers["x-astra-device"] = deviceHeader;
|
|
7177
|
+
const mod = target.protocol === "https:" ? import_node_https.default : import_node_http.default;
|
|
7178
|
+
const upstream = mod.request(
|
|
7179
|
+
{
|
|
7180
|
+
host: target.host,
|
|
7181
|
+
port: target.port,
|
|
7182
|
+
method: req.method,
|
|
7183
|
+
path: target.path,
|
|
7184
|
+
headers,
|
|
7185
|
+
servername: target.protocol === "https:" ? String(req.headers.host ?? target.host).split(":")[0] : void 0,
|
|
7186
|
+
rejectUnauthorized: target.rejectUnauthorized ?? true
|
|
7187
|
+
},
|
|
7188
|
+
(up) => {
|
|
7189
|
+
res.writeHead(up.statusCode ?? 502, cleanHeaders(up.headers));
|
|
7190
|
+
up.pipe(res);
|
|
7191
|
+
}
|
|
7192
|
+
);
|
|
7193
|
+
upstream.on("error", () => {
|
|
7194
|
+
if (!res.headersSent) res.writeHead(502, { "content-type": "text/plain" });
|
|
7195
|
+
res.end("AstraSync browse proxy: upstream unreachable");
|
|
7196
|
+
});
|
|
7197
|
+
req.pipe(upstream);
|
|
7198
|
+
}
|
|
7199
|
+
function forwardUpgrade(req, socket, head, target) {
|
|
7200
|
+
const headers = { ...req.headers };
|
|
7201
|
+
delete headers["proxy-connection"];
|
|
7202
|
+
delete headers["proxy-authorization"];
|
|
7203
|
+
delete headers["x-astra-device"];
|
|
7204
|
+
if (target.addDevice) headers["x-astra-device"] = deviceHeader;
|
|
7205
|
+
const lines = [`${req.method} ${target.path} HTTP/1.1`];
|
|
7206
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
7207
|
+
if (v === void 0) continue;
|
|
7208
|
+
for (const one of Array.isArray(v) ? v : [v]) lines.push(`${k}: ${one}`);
|
|
7209
|
+
}
|
|
7210
|
+
const onConnect = () => {
|
|
7211
|
+
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
7212
|
+
if (head.length) upstream.write(head);
|
|
7213
|
+
upstream.pipe(socket);
|
|
7214
|
+
socket.pipe(upstream);
|
|
7215
|
+
};
|
|
7216
|
+
const upstream = target.protocol === "https:" ? import_node_tls.default.connect(
|
|
7217
|
+
{
|
|
7218
|
+
host: target.host,
|
|
7219
|
+
port: target.port,
|
|
7220
|
+
servername: String(req.headers.host ?? target.host).split(":")[0],
|
|
7221
|
+
rejectUnauthorized: target.rejectUnauthorized ?? true
|
|
7222
|
+
},
|
|
7223
|
+
onConnect
|
|
7224
|
+
) : import_node_net.default.connect(target.port, target.host, onConnect);
|
|
7225
|
+
upstream.on("error", () => socket.destroy());
|
|
7226
|
+
socket.on("error", () => upstream.destroy());
|
|
7227
|
+
}
|
|
7228
|
+
const inner = import_node_http.default.createServer((req, res) => {
|
|
7229
|
+
const hostHeader = String(req.headers.host ?? "");
|
|
7230
|
+
const [h, p] = hostHeader.split(":");
|
|
7231
|
+
const port2 = Number(p) || 443;
|
|
7232
|
+
const up = opts.upstreamFor?.(h, port2) ?? { host: h, port: port2 };
|
|
7233
|
+
forward(req, res, {
|
|
7234
|
+
protocol: "https:",
|
|
7235
|
+
host: up.host,
|
|
7236
|
+
port: up.port,
|
|
7237
|
+
path: req.url ?? "/",
|
|
7238
|
+
rejectUnauthorized: up.rejectUnauthorized
|
|
7239
|
+
});
|
|
7240
|
+
});
|
|
7241
|
+
const plainInner = import_node_http.default.createServer((req, res) => {
|
|
7242
|
+
const [h, p] = String(req.headers.host ?? "").split(":");
|
|
7243
|
+
forward(req, res, { protocol: "http:", host: h, port: Number(p) || 80, path: req.url ?? "/" });
|
|
7244
|
+
});
|
|
7245
|
+
plainInner.on("upgrade", (req, socket, head) => {
|
|
7246
|
+
const [h, p] = String(req.headers.host ?? "").split(":");
|
|
7247
|
+
forwardUpgrade(req, socket, head, {
|
|
7248
|
+
protocol: "http:",
|
|
7249
|
+
host: h,
|
|
7250
|
+
port: Number(p) || 80,
|
|
7251
|
+
path: req.url ?? "/",
|
|
7252
|
+
addDevice: true
|
|
7253
|
+
});
|
|
7254
|
+
});
|
|
7255
|
+
const server = import_node_http.default.createServer((req, res) => {
|
|
7256
|
+
let url;
|
|
7257
|
+
try {
|
|
7258
|
+
url = new URL(req.url ?? "");
|
|
7259
|
+
} catch {
|
|
7260
|
+
res.writeHead(400).end("absolute URL required");
|
|
7261
|
+
return;
|
|
7262
|
+
}
|
|
7263
|
+
if (hosts.has(url.hostname.toLowerCase())) {
|
|
7264
|
+
forward(req, res, {
|
|
7265
|
+
protocol: "http:",
|
|
7266
|
+
host: url.hostname,
|
|
7267
|
+
port: Number(url.port) || 80,
|
|
7268
|
+
path: `${url.pathname}${url.search}`
|
|
7269
|
+
});
|
|
7270
|
+
return;
|
|
7271
|
+
}
|
|
7272
|
+
const upstream = import_node_http.default.request(
|
|
7273
|
+
{
|
|
7274
|
+
host: url.hostname,
|
|
7275
|
+
port: Number(url.port) || 80,
|
|
7276
|
+
method: req.method,
|
|
7277
|
+
path: `${url.pathname}${url.search}`,
|
|
7278
|
+
headers: cleanHeaders(req.headers)
|
|
7279
|
+
},
|
|
7280
|
+
(up) => {
|
|
7281
|
+
res.writeHead(up.statusCode ?? 502, cleanHeaders(up.headers));
|
|
7282
|
+
up.pipe(res);
|
|
7283
|
+
}
|
|
7284
|
+
);
|
|
7285
|
+
upstream.on("error", () => res.writeHead(502).end());
|
|
7286
|
+
req.pipe(upstream);
|
|
7287
|
+
});
|
|
7288
|
+
inner.on("upgrade", (req, socket, head) => {
|
|
7289
|
+
const [h, p] = String(req.headers.host ?? "").split(":");
|
|
7290
|
+
const port2 = Number(p) || 443;
|
|
7291
|
+
const up = opts.upstreamFor?.(h, port2) ?? { host: h, port: port2 };
|
|
7292
|
+
forwardUpgrade(req, socket, head, {
|
|
7293
|
+
protocol: "https:",
|
|
7294
|
+
host: up.host,
|
|
7295
|
+
port: up.port,
|
|
7296
|
+
path: req.url ?? "/",
|
|
7297
|
+
addDevice: true,
|
|
7298
|
+
rejectUnauthorized: up.rejectUnauthorized
|
|
7299
|
+
});
|
|
7300
|
+
});
|
|
7301
|
+
server.on("upgrade", (req, socket, head) => {
|
|
7302
|
+
let url;
|
|
7303
|
+
try {
|
|
7304
|
+
url = new URL(req.url ?? "");
|
|
7305
|
+
} catch {
|
|
7306
|
+
socket.destroy();
|
|
7307
|
+
return;
|
|
7308
|
+
}
|
|
7309
|
+
forwardUpgrade(req, socket, head, {
|
|
7310
|
+
protocol: "http:",
|
|
7311
|
+
host: url.hostname,
|
|
7312
|
+
port: Number(url.port) || 80,
|
|
7313
|
+
path: `${url.pathname}${url.search}`,
|
|
7314
|
+
addDevice: hosts.has(url.hostname.toLowerCase())
|
|
7315
|
+
});
|
|
7316
|
+
});
|
|
7317
|
+
server.on("connect", (req, socket, head) => {
|
|
7318
|
+
const [host, portStr] = String(req.url ?? "").split(":");
|
|
7319
|
+
const port2 = Number(portStr) || 443;
|
|
7320
|
+
if (hosts.has(host.toLowerCase())) {
|
|
7321
|
+
socket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
7322
|
+
const start = (first) => {
|
|
7323
|
+
const s = socket;
|
|
7324
|
+
s.pause();
|
|
7325
|
+
s.unshift(first);
|
|
7326
|
+
if (first[0] === 22) {
|
|
7327
|
+
const tlsSocket = new import_node_tls.default.TLSSocket(s, {
|
|
7328
|
+
isServer: true,
|
|
7329
|
+
secureContext: import_node_tls.default.createSecureContext({ cert, key })
|
|
7330
|
+
});
|
|
7331
|
+
inner.emit("connection", tlsSocket);
|
|
7332
|
+
tlsSocket.on("error", () => socket.destroy());
|
|
7333
|
+
} else {
|
|
7334
|
+
plainInner.emit("connection", s);
|
|
7335
|
+
s.resume();
|
|
7336
|
+
}
|
|
7337
|
+
};
|
|
7338
|
+
if (head.length) start(head);
|
|
7339
|
+
else socket.once("data", (chunk) => start(chunk));
|
|
7340
|
+
return;
|
|
7341
|
+
}
|
|
7342
|
+
const upstream = import_node_net.default.connect(port2, host, () => {
|
|
7343
|
+
socket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
7344
|
+
if (head.length) upstream.write(head);
|
|
7345
|
+
upstream.pipe(socket);
|
|
7346
|
+
socket.pipe(upstream);
|
|
7347
|
+
});
|
|
7348
|
+
upstream.on("error", () => socket.destroy());
|
|
7349
|
+
socket.on("error", () => upstream.destroy());
|
|
7350
|
+
});
|
|
7351
|
+
await new Promise((resolve) => server.listen(opts.port ?? 0, "127.0.0.1", resolve));
|
|
7352
|
+
const port = server.address().port;
|
|
7353
|
+
return {
|
|
7354
|
+
port,
|
|
7355
|
+
close: () => new Promise((resolve) => {
|
|
7356
|
+
inner.close();
|
|
7357
|
+
plainInner.close();
|
|
7358
|
+
server.close(() => resolve());
|
|
7359
|
+
server.closeAllConnections?.();
|
|
7360
|
+
})
|
|
7361
|
+
};
|
|
7362
|
+
}
|
|
7363
|
+
|
|
7364
|
+
// src/fleet/browse.ts
|
|
7365
|
+
async function runBrowse(paths, opts) {
|
|
7366
|
+
const log = opts.log ?? ((l) => console.log(l));
|
|
7367
|
+
const f = opts.fetchImpl ?? fetch;
|
|
7368
|
+
const loaded = loadEnrolment(paths);
|
|
7369
|
+
if (!loaded || !("enrolment" in loaded)) {
|
|
7370
|
+
throw new Error("This machine is not enrolled. Run: astrasync guard enroll <token>");
|
|
7371
|
+
}
|
|
7372
|
+
const { credential, apiBaseUrl } = loaded.enrolment;
|
|
7373
|
+
if (!opts.checkpoint || !opts.slug) throw new Error("--checkpoint and --slug are required");
|
|
7374
|
+
const appOrigin = new URL(apiBaseUrl).origin;
|
|
7375
|
+
const hosts = [new URL(apiBaseUrl).hostname, ...opts.extraHosts ?? []];
|
|
7376
|
+
const device = `Device ${credential}`;
|
|
7377
|
+
const proxy = await startBrowseProxy({ hosts, deviceCredential: credential, port: opts.port });
|
|
7378
|
+
try {
|
|
7379
|
+
const base2 = opts.checkpoint.replace(/\/+$/, "");
|
|
7380
|
+
const signin = await f(
|
|
7381
|
+
`${base2}/a/${encodeURIComponent(opts.slug)}/h/${encodeURIComponent(opts.upstream ?? "astrasync-api")}/agent-sessions`,
|
|
7382
|
+
{
|
|
7383
|
+
method: "POST",
|
|
7384
|
+
headers: { authorization: device, "content-type": "application/json" },
|
|
7385
|
+
body: "{}"
|
|
7386
|
+
}
|
|
7387
|
+
);
|
|
7388
|
+
const body = await signin.json().catch(() => ({}));
|
|
7389
|
+
if (signin.status !== 201 && signin.status !== 202) {
|
|
7390
|
+
throw new Error(
|
|
7391
|
+
`Sign-in refused (${signin.status}${body.code ? ` ${body.code}` : ""}): ${body.message ?? "no detail"}`
|
|
7392
|
+
);
|
|
7393
|
+
}
|
|
7394
|
+
const sessionId = String(body.data?.sessionId ?? "");
|
|
7395
|
+
let code = body.data?.code;
|
|
7396
|
+
if (!code) {
|
|
7397
|
+
log("Waiting for the owner to approve this sign-in with their passkey\u2026");
|
|
7398
|
+
const deadline = Date.now() + (opts.waitMs ?? 10 * 6e4);
|
|
7399
|
+
while (!code) {
|
|
7400
|
+
if (Date.now() > deadline) throw new Error("The owner did not approve in time.");
|
|
7401
|
+
await new Promise((r) => setTimeout(r, opts.pollIntervalMs ?? 3e3));
|
|
7402
|
+
const poll = await f(
|
|
7403
|
+
`${apiBaseUrl.replace(/\/+$/, "")}/agent-sessions/${sessionId}/status`,
|
|
7404
|
+
{
|
|
7405
|
+
headers: { "x-astra-device": device }
|
|
7406
|
+
}
|
|
7407
|
+
);
|
|
7408
|
+
const p = await poll.json().catch(() => ({}));
|
|
7409
|
+
const status = p.data?.status;
|
|
7410
|
+
if (status === "approved") code = p.data?.code;
|
|
7411
|
+
else if (status === "denied" || status === "ended")
|
|
7412
|
+
throw new Error(`Sign-in ${status === "denied" ? "was not approved" : "ended"}.`);
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
const openUrl = `${appOrigin}/agent-session#code=${code}`;
|
|
7416
|
+
log("");
|
|
7417
|
+
log(`Signed in. Open this once (within 2 minutes), through the proxy:`);
|
|
7418
|
+
log(` ${openUrl}`);
|
|
7419
|
+
log("");
|
|
7420
|
+
log(
|
|
7421
|
+
`Device proxy: http://127.0.0.1:${proxy.port} (adds this machine's credential for ${hosts.join(", ")})`
|
|
7422
|
+
);
|
|
7423
|
+
log("Playwright:");
|
|
7424
|
+
log(
|
|
7425
|
+
` chromium.launch({ proxy: { server: 'http://127.0.0.1:${proxy.port}' } }) + newContext({ ignoreHTTPSErrors: true })`
|
|
7426
|
+
);
|
|
7427
|
+
log("Requests that skip the proxy end the session. Ctrl-C stops the proxy.");
|
|
7428
|
+
return { proxy, openUrl, sessionId };
|
|
7429
|
+
} catch (err) {
|
|
7430
|
+
await proxy.close();
|
|
7431
|
+
throw err;
|
|
7432
|
+
}
|
|
7433
|
+
}
|
|
7434
|
+
|
|
6984
7435
|
// src/cli/guard.ts
|
|
6985
7436
|
var DEFAULT_POLICY_PATH = "./local-policy.yaml";
|
|
6986
7437
|
var DEFAULT_CONFIG_DIR = ".astrasync";
|
|
@@ -7516,6 +7967,54 @@ async function cmdFleetStatus() {
|
|
|
7516
7967
|
const status = await getFleetStatus(fleetPaths());
|
|
7517
7968
|
for (const line of formatFleetStatus(status)) console.log(line);
|
|
7518
7969
|
}
|
|
7970
|
+
async function cmdBrowse() {
|
|
7971
|
+
try {
|
|
7972
|
+
const port = flagValue("--port");
|
|
7973
|
+
const { proxy } = await runBrowse(fleetPaths(), {
|
|
7974
|
+
checkpoint: flagValue("--checkpoint") ?? "",
|
|
7975
|
+
slug: flagValue("--slug") ?? "",
|
|
7976
|
+
upstream: flagValue("--upstream"),
|
|
7977
|
+
port: port ? Number(port) : void 0,
|
|
7978
|
+
extraHosts: flagValue("--host") ? [flagValue("--host")] : []
|
|
7979
|
+
});
|
|
7980
|
+
const stop = async () => {
|
|
7981
|
+
await proxy.close();
|
|
7982
|
+
process.exit(0);
|
|
7983
|
+
};
|
|
7984
|
+
process.on("SIGINT", stop);
|
|
7985
|
+
process.on("SIGTERM", stop);
|
|
7986
|
+
await new Promise(() => void 0);
|
|
7987
|
+
} catch (err) {
|
|
7988
|
+
console.error(`browse failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
7989
|
+
process.exit(1);
|
|
7990
|
+
}
|
|
7991
|
+
}
|
|
7992
|
+
async function cmdGitRoute() {
|
|
7993
|
+
try {
|
|
7994
|
+
if (process.argv.includes("--undo")) {
|
|
7995
|
+
const removed = removeGitRoute();
|
|
7996
|
+
console.log(removed.length ? `Removed: ${removed.join(", ")}` : "No git route was set.");
|
|
7997
|
+
return;
|
|
7998
|
+
}
|
|
7999
|
+
const lines = applyGitRoute({
|
|
8000
|
+
checkpoint: flagValue("--checkpoint") ?? "",
|
|
8001
|
+
slug: flagValue("--slug") ?? "",
|
|
8002
|
+
agent: flagValue("--agent") ?? "",
|
|
8003
|
+
upstream: flagValue("--upstream")
|
|
8004
|
+
});
|
|
8005
|
+
console.log("git now fetches and pushes github.com through your Workforce Guard checkpoint:");
|
|
8006
|
+
for (const l of lines) console.log(` ${l}`);
|
|
8007
|
+
console.log("Commits still run your local hooks. Undo with: astrasync guard git-route --undo");
|
|
8008
|
+
} catch (err) {
|
|
8009
|
+
console.error(`git-route failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8010
|
+
process.exit(1);
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
async function cmdGitCredential() {
|
|
8014
|
+
const action = process.argv[process.argv.indexOf("git-credential") + 1] ?? "";
|
|
8015
|
+
const input = fs.readFileSync(0, "utf-8");
|
|
8016
|
+
process.stdout.write(runGitCredential(action, input));
|
|
8017
|
+
}
|
|
7519
8018
|
async function cmdManagedSettings() {
|
|
7520
8019
|
const targets = [];
|
|
7521
8020
|
if (process.argv.includes("--claude")) targets.push("claude");
|
|
@@ -7584,6 +8083,15 @@ async function main() {
|
|
|
7584
8083
|
case "managed-settings":
|
|
7585
8084
|
await cmdManagedSettings();
|
|
7586
8085
|
break;
|
|
8086
|
+
case "git-route":
|
|
8087
|
+
await cmdGitRoute();
|
|
8088
|
+
break;
|
|
8089
|
+
case "browse":
|
|
8090
|
+
await cmdBrowse();
|
|
8091
|
+
break;
|
|
8092
|
+
case "git-credential":
|
|
8093
|
+
await cmdGitCredential();
|
|
8094
|
+
break;
|
|
7587
8095
|
default:
|
|
7588
8096
|
console.log("AstraSync Local Guard\n");
|
|
7589
8097
|
console.log("Usage: astrasync guard <command>\n");
|
|
@@ -7604,10 +8112,21 @@ async function main() {
|
|
|
7604
8112
|
console.log(" install-codex Install the Local Guard hook for OpenAI Codex CLI");
|
|
7605
8113
|
console.log(" (same flags; policy shared with Claude Code)");
|
|
7606
8114
|
console.log(" uninstall-codex Remove the Codex hook (--project for project scope)");
|
|
8115
|
+
console.log(
|
|
8116
|
+
" browse Sign an agent in to your dashboard from this machine and"
|
|
8117
|
+
);
|
|
8118
|
+
console.log(
|
|
8119
|
+
" run its device proxy (--checkpoint <url> --slug <agent>)"
|
|
8120
|
+
);
|
|
7607
8121
|
console.log(" enroll <token> Enrol this machine in your organisation fleet");
|
|
7608
8122
|
console.log(" (--api-base-url <url>, --system for machine scope)");
|
|
7609
8123
|
console.log(" fleet-status Show fleet enrolment, signed policy and heartbeat");
|
|
7610
8124
|
console.log(" managed-settings Print MDM templates (--claude, --codex, --out <dir>)");
|
|
8125
|
+
console.log(" git-route Route git through your Workforce Guard checkpoint");
|
|
8126
|
+
console.log(
|
|
8127
|
+
" (--checkpoint <url> --slug <connector> --agent <ASTRA-id>;"
|
|
8128
|
+
);
|
|
8129
|
+
console.log(" --undo to remove)");
|
|
7611
8130
|
console.log("");
|
|
7612
8131
|
process.exit(command ? 1 : 0);
|
|
7613
8132
|
}
|