@akasecurity/cli 0.9.7 → 0.9.8
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 +5 -1
- package/dist/cli.js +1594 -504
- package/extension/manifest.json +1 -1
- package/native-host/host.js +1824 -309
- package/native-host/scan-worker.js +118 -0
- package/native-host/sync.js +19413 -0
- package/package.json +6 -4
- package/web-ui/rules/core-code-context/localhost-ref.json +2 -2
- package/web-ui/web-ui/.next/BUILD_ID +1 -1
- package/web-ui/web-ui/.next/app-build-manifest.json +88 -88
- package/web-ui/web-ui/.next/app-path-routes-manifest.json +7 -7
- package/web-ui/web-ui/.next/build-manifest.json +2 -2
- package/web-ui/web-ui/.next/prerender-manifest.json +3 -3
- package/web-ui/web-ui/.next/server/app/(app)/activity/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/activity/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/activity/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/data-shares/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/data-shares/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/data-shares/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/detections/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/detections/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/detections/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/exceptions/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/findings/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/findings/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/findings/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/inventory/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/inventory/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/inventory/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/policies/page.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/policies/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/policies/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/scan/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/scan/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/scan/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/security/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/security/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/security/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/settings/page.js +2 -2
- package/web-ui/web-ui/.next/server/app/(app)/settings/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/updates/page.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/updates/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/updates/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/vault/page.js +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/vault/page.js.nft.json +1 -1
- package/web-ui/web-ui/.next/server/app/(app)/vault/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found.html +1 -1
- package/web-ui/web-ui/.next/server/app/_not-found.rsc +1 -1
- package/web-ui/web-ui/.next/server/app/index.html +1 -1
- package/web-ui/web-ui/.next/server/app/index.rsc +1 -1
- package/web-ui/web-ui/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/app-paths-manifest.json +7 -7
- package/web-ui/web-ui/.next/server/chunks/258.js +1 -1
- package/web-ui/web-ui/.next/server/chunks/271.js +2 -2
- package/web-ui/web-ui/.next/server/chunks/314.js +783 -0
- package/web-ui/web-ui/.next/server/chunks/523.js +1 -1
- package/web-ui/web-ui/.next/server/chunks/{477.js → 844.js} +138 -138
- package/web-ui/web-ui/.next/server/chunks/967.js +1 -1
- package/web-ui/web-ui/.next/server/functions-config-manifest.json +4 -4
- package/web-ui/web-ui/.next/server/middleware-manifest.json +5 -5
- package/web-ui/web-ui/.next/server/pages/404.html +1 -1
- package/web-ui/web-ui/.next/server/pages/500.html +1 -1
- package/web-ui/web-ui/.next/server/pages-manifest.json +1 -1
- package/web-ui/web-ui/.next/server/server-reference-manifest.js +1 -1
- package/web-ui/web-ui/.next/server/server-reference-manifest.json +1 -1
- package/web-ui/web-ui/.next/static/chunks/622-0520747def5cc37b.js +62 -0
- package/web-ui/web-ui/.next/static/chunks/699-f5e42f0ed71707d9.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/activity/{page-2011aeec5114533f.js → page-ee3b9956abc7cf1b.js} +1 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/page-9997c04ce4d4a451.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/page-5c9b3e6f6d832127.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/page-5f56a9fa25e7af46.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/page-38dcdc2eb2e47f53.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/page-94d735bc414c9b5c.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/findings/{page-5e9249b49d619cf7.js → page-073d0b64e942914f.js} +1 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/page-71344cf66ee67b51.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/page-24429599495731bf.js +1 -0
- package/web-ui/web-ui/.next/static/chunks/app/(app)/settings/{page-bc4551c2cd096584.js → page-f633645e1112fcb9.js} +1 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/updates/{page-d0b9a88e5cff5d9b.js → page-429f377f34456a96.js} +1 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/vault/{page-de6afbc0036fcb0d.js → page-21c59276737a8b9e.js} +1 -1
- package/web-ui/web-ui/dist/scan-worker.js +118 -0
- package/web-ui/web-ui/.next/server/chunks/129.js +0 -783
- package/web-ui/web-ui/.next/static/chunks/622-e65110f232ad3136.js +0 -62
- package/web-ui/web-ui/.next/static/chunks/699-3a550a0d6101e35c.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/page-e8fbf441cdc78d7e.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/page-0cf86550a9f22cf8.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/page-3b57fa7a28949fdf.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/page-5524f6b8dd008924.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/page-5fcea0008a2c0bfc.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/page-b1676f9a9b4673f1.js +0 -1
- package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/page-3560c03478bda4c7.js +0 -1
- /package/web-ui/web-ui/.next/static/{YqH1rSLTmXzavf3MtB9ZX → zjNAa9qOfKutYwuhfySp_}/_buildManifest.js +0 -0
- /package/web-ui/web-ui/.next/static/{YqH1rSLTmXzavf3MtB9ZX → zjNAa9qOfKutYwuhfySp_}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -51,7 +51,7 @@ var require_ignore = __commonJS({
|
|
|
51
51
|
var REGEX_SPLITALL_CRLF = /\r?\n/g;
|
|
52
52
|
var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
|
|
53
53
|
var REGEX_TEST_TRAILING_SLASH = /\/$/;
|
|
54
|
-
var
|
|
54
|
+
var SLASH2 = "/";
|
|
55
55
|
var TMP_KEY_IGNORE = "node-ignore";
|
|
56
56
|
if (typeof Symbol !== "undefined") {
|
|
57
57
|
TMP_KEY_IGNORE = /* @__PURE__ */ Symbol.for("node-ignore");
|
|
@@ -423,11 +423,11 @@ var require_ignore = __commonJS({
|
|
|
423
423
|
if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
|
|
424
424
|
return this.test(path);
|
|
425
425
|
}
|
|
426
|
-
const slices = path.split(
|
|
426
|
+
const slices = path.split(SLASH2).filter(Boolean);
|
|
427
427
|
slices.pop();
|
|
428
428
|
if (slices.length) {
|
|
429
429
|
const parent = this._t(
|
|
430
|
-
slices.join(
|
|
430
|
+
slices.join(SLASH2) + SLASH2,
|
|
431
431
|
this._testCache,
|
|
432
432
|
true,
|
|
433
433
|
slices
|
|
@@ -443,14 +443,14 @@ var require_ignore = __commonJS({
|
|
|
443
443
|
return cache[path];
|
|
444
444
|
}
|
|
445
445
|
if (!slices) {
|
|
446
|
-
slices = path.split(
|
|
446
|
+
slices = path.split(SLASH2).filter(Boolean);
|
|
447
447
|
}
|
|
448
448
|
slices.pop();
|
|
449
449
|
if (!slices.length) {
|
|
450
450
|
return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE);
|
|
451
451
|
}
|
|
452
452
|
const parent = this._t(
|
|
453
|
-
slices.join(
|
|
453
|
+
slices.join(SLASH2) + SLASH2,
|
|
454
454
|
cache,
|
|
455
455
|
checkUnignored,
|
|
456
456
|
slices
|
|
@@ -16451,6 +16451,125 @@ var ConfigScanRecord = external_exports.object({
|
|
|
16451
16451
|
findings: external_exports.array(ConfigPostureFindingInput).optional()
|
|
16452
16452
|
});
|
|
16453
16453
|
|
|
16454
|
+
// ../packages/schema/src/zod/control-plane.ts
|
|
16455
|
+
var ATTACHED_CREDENTIAL_FILENAME = "control-plane-credential.json";
|
|
16456
|
+
var ATTACHED_CREDENTIAL_SPEC_VERSION = 1;
|
|
16457
|
+
var AttachedCredential = external_exports.object({
|
|
16458
|
+
specVersion: external_exports.literal(ATTACHED_CREDENTIAL_SPEC_VERSION),
|
|
16459
|
+
// The control-plane endpoint this credential was minted against.
|
|
16460
|
+
endpoint: external_exports.string().min(1),
|
|
16461
|
+
// The bearer credential itself. Never logged, never rendered — status
|
|
16462
|
+
// surfaces show `keyPrefix` and nothing else.
|
|
16463
|
+
apiKey: external_exports.string().min(1),
|
|
16464
|
+
// First few characters of the key, safe to display so a user can match the
|
|
16465
|
+
// credential against their organization's key list.
|
|
16466
|
+
keyPrefix: external_exports.string().min(1).max(16).optional(),
|
|
16467
|
+
mintedAt: external_exports.iso.datetime().optional()
|
|
16468
|
+
});
|
|
16469
|
+
var MAX_DATE_MS = 253402300799999;
|
|
16470
|
+
var MAX_INT4 = 2147483647;
|
|
16471
|
+
var StorePosturePack = external_exports.object({
|
|
16472
|
+
packId: external_exports.string().min(1),
|
|
16473
|
+
// 'namespace/packId'
|
|
16474
|
+
version: external_exports.string().min(1),
|
|
16475
|
+
enabled: external_exports.boolean(),
|
|
16476
|
+
// Stringified pass-through of the local store's `installed_packs.updated_at`
|
|
16477
|
+
// — the column format is store-version-dependent (epoch millis vs ISO), so
|
|
16478
|
+
// the wire shape assumes neither.
|
|
16479
|
+
updatedAt: external_exports.string().nullable()
|
|
16480
|
+
}).meta({ id: "StorePosturePack" });
|
|
16481
|
+
var StorePosturePolicyCounts = external_exports.object({
|
|
16482
|
+
total: external_exports.number().int().min(0),
|
|
16483
|
+
disabled: external_exports.number().int().min(0),
|
|
16484
|
+
// Exhaustive per-action map; the builder pre-fills every action with 0.
|
|
16485
|
+
//
|
|
16486
|
+
// Spelled out member-by-member rather than `z.record(ActionTaken, …)`. Zod
|
|
16487
|
+
// enforces exhaustiveness either way, but z.record emits `propertyNames` +
|
|
16488
|
+
// `additionalProperties` into a generated schema document, and a type
|
|
16489
|
+
// generator renders THAT with every key optional — a sender built against
|
|
16490
|
+
// the generated type would typecheck and still be rejected at runtime. An
|
|
16491
|
+
// explicit object emits `properties` + `required`, so generated types
|
|
16492
|
+
// demand all five.
|
|
16493
|
+
//
|
|
16494
|
+
// `satisfies Record<ActionTaken, …>` keeps the link to the enum: adding an
|
|
16495
|
+
// ActionTaken member is a COMPILE error here instead of silent drift.
|
|
16496
|
+
// `.strict()` is load-bearing — it rejects an unknown action key, which a
|
|
16497
|
+
// bare object would silently STRIP, accepting a miscounted map as valid.
|
|
16498
|
+
byAction: external_exports.object({
|
|
16499
|
+
warn: external_exports.number().int().min(0),
|
|
16500
|
+
redact: external_exports.number().int().min(0),
|
|
16501
|
+
block: external_exports.number().int().min(0),
|
|
16502
|
+
allow: external_exports.number().int().min(0),
|
|
16503
|
+
log: external_exports.number().int().min(0)
|
|
16504
|
+
}).strict()
|
|
16505
|
+
}).meta({ id: "StorePosturePolicyCounts" });
|
|
16506
|
+
var StorePosturePlugin = external_exports.object({
|
|
16507
|
+
/** Package name of the reporting plugin. */
|
|
16508
|
+
package: external_exports.string().min(1).max(200),
|
|
16509
|
+
version: external_exports.string().min(1).max(64),
|
|
16510
|
+
/** Version of the bundled core, when the build records one separately. */
|
|
16511
|
+
ossVersion: external_exports.string().max(64).nullable(),
|
|
16512
|
+
/**
|
|
16513
|
+
* `version` of the policy bundle this machine last fetched. Bounded at 200
|
|
16514
|
+
* rather than the 64 a bare sha256 hex digest needs today, so a later
|
|
16515
|
+
* format with an algorithm prefix does not start rejecting the channel.
|
|
16516
|
+
*/
|
|
16517
|
+
policyBundleVersion: external_exports.string().max(200).nullable(),
|
|
16518
|
+
/** Epoch millis, on the CLIENT clock, of that fetch. */
|
|
16519
|
+
policyFetchedAt: external_exports.number().int().min(0).max(MAX_DATE_MS).nullable()
|
|
16520
|
+
}).meta({ id: "StorePosturePlugin" });
|
|
16521
|
+
var StorePostureSnapshot = external_exports.object({
|
|
16522
|
+
deviceId: external_exports.guid(),
|
|
16523
|
+
hostname: external_exports.string().min(1).max(253),
|
|
16524
|
+
// Epoch millis on the CLIENT clock. Bounded by what a receiving store
|
|
16525
|
+
// accepts (see MAX_DATE_MS), not by what a JavaScript Date can hold.
|
|
16526
|
+
capturedAt: external_exports.number().int().min(0).max(MAX_DATE_MS),
|
|
16527
|
+
// False is a measurement, not an error state: "no local store exists on
|
|
16528
|
+
// this machine".
|
|
16529
|
+
storePresent: external_exports.boolean(),
|
|
16530
|
+
schemaVersion: external_exports.number().int().min(0).max(MAX_INT4).nullable(),
|
|
16531
|
+
// PRAGMA user_version
|
|
16532
|
+
findingsTotal: external_exports.number().int().min(0).max(MAX_INT4),
|
|
16533
|
+
// Epoch millis, bounded like `capturedAt` — see MAX_DATE_MS on what that
|
|
16534
|
+
// bound does and does not do. Worth stating for these two specifically:
|
|
16535
|
+
// they are read from the local store's own ROWS rather than from this
|
|
16536
|
+
// machine's clock, so a damaged or hand-edited store is enough to produce
|
|
16537
|
+
// an out-of-range value with no clock skew involved.
|
|
16538
|
+
findingsFirstAt: external_exports.number().int().min(0).max(MAX_DATE_MS).nullable(),
|
|
16539
|
+
findingsLastAt: external_exports.number().int().min(0).max(MAX_DATE_MS).nullable(),
|
|
16540
|
+
packs: external_exports.array(StorePosturePack).max(500),
|
|
16541
|
+
policyCounts: StorePosturePolicyCounts,
|
|
16542
|
+
// OPTIONAL, not nullable: a reporter that predates this member keeps
|
|
16543
|
+
// getting its 200 without a payload change.
|
|
16544
|
+
plugin: StorePosturePlugin.optional()
|
|
16545
|
+
}).meta({ id: "StorePostureSnapshot" });
|
|
16546
|
+
var CAPTURE_VERSION_PREFIX = "capture/";
|
|
16547
|
+
var RecordAuditEventRequest = AuditEventInput.extend({
|
|
16548
|
+
inspections: external_exports.array(ToolCallInspection).default([])
|
|
16549
|
+
}).refine((v) => v.inspections.every((i) => !i.ruleVersion.startsWith(CAPTURE_VERSION_PREFIX)), {
|
|
16550
|
+
message: `inspections[].ruleVersion must not start with \`${CAPTURE_VERSION_PREFIX}\` \u2014 that namespace is reserved for capture definitions the control plane mints itself`,
|
|
16551
|
+
path: ["inspections"]
|
|
16552
|
+
}).meta({ id: "RecordAuditEventRequest" });
|
|
16553
|
+
var IngestAck = external_exports.object({
|
|
16554
|
+
accepted: external_exports.number().int().nonnegative(),
|
|
16555
|
+
duplicates: external_exports.number().int().nonnegative()
|
|
16556
|
+
});
|
|
16557
|
+
var PRINTABLE = /^[^\p{Cc}\p{Cf}]*$/u;
|
|
16558
|
+
var printable = (max) => external_exports.string().max(max).regex(PRINTABLE, "must not contain control characters");
|
|
16559
|
+
var PluginWhoami = external_exports.object({
|
|
16560
|
+
tenantName: printable(200),
|
|
16561
|
+
userEmail: printable(320),
|
|
16562
|
+
role: printable(64),
|
|
16563
|
+
keyKind: printable(64),
|
|
16564
|
+
serverTime: printable(64)
|
|
16565
|
+
});
|
|
16566
|
+
var ControlPlaneErrorBody = external_exports.object({
|
|
16567
|
+
error: external_exports.object({
|
|
16568
|
+
code: external_exports.string().optional(),
|
|
16569
|
+
message: external_exports.string().optional()
|
|
16570
|
+
}).optional()
|
|
16571
|
+
});
|
|
16572
|
+
|
|
16454
16573
|
// ../packages/schema/src/zod/registry.ts
|
|
16455
16574
|
var Namespace = external_exports.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
16456
16575
|
var PackId = external_exports.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
@@ -16753,15 +16872,15 @@ function summaryToDetectionListItem(s) {
|
|
|
16753
16872
|
}
|
|
16754
16873
|
function rowToDetectionDetail(row, findingsLast30d, update) {
|
|
16755
16874
|
const rules = row.rules.flatMap((r) => {
|
|
16756
|
-
const
|
|
16757
|
-
if (!
|
|
16875
|
+
const parsed2 = Matcher.safeParse(r.matcher);
|
|
16876
|
+
if (!parsed2.success) return [];
|
|
16758
16877
|
return [
|
|
16759
16878
|
{
|
|
16760
16879
|
id: r.id,
|
|
16761
16880
|
name: r.name,
|
|
16762
16881
|
category: r.category,
|
|
16763
16882
|
severity: r.severity,
|
|
16764
|
-
matcher:
|
|
16883
|
+
matcher: parsed2.data
|
|
16765
16884
|
}
|
|
16766
16885
|
];
|
|
16767
16886
|
});
|
|
@@ -17419,8 +17538,8 @@ function toApiAction(dbVal) {
|
|
|
17419
17538
|
}
|
|
17420
17539
|
function toApiCategory(dbVal) {
|
|
17421
17540
|
if (dbVal === "code_context") return "source_code";
|
|
17422
|
-
const
|
|
17423
|
-
return
|
|
17541
|
+
const parsed2 = FindingCategory.safeParse(dbVal);
|
|
17542
|
+
return parsed2.success ? parsed2.data : "custom";
|
|
17424
17543
|
}
|
|
17425
17544
|
function toApiProvider(sourceTool) {
|
|
17426
17545
|
return TOOL_TO_HARNESS[sourceTool] ?? HARNESS.Api;
|
|
@@ -18024,6 +18143,9 @@ var ModelJudgeConsent = external_exports.object({
|
|
|
18024
18143
|
acknowledgedAt: external_exports.iso.datetime(),
|
|
18025
18144
|
payloadVersion: external_exports.number().int().positive()
|
|
18026
18145
|
});
|
|
18146
|
+
function isModelJudgeConsentValid(consent) {
|
|
18147
|
+
return consent?.payloadVersion === MODEL_JUDGE_PAYLOAD_VERSION;
|
|
18148
|
+
}
|
|
18027
18149
|
var WorkspaceSettings = external_exports.object({
|
|
18028
18150
|
specVersion: external_exports.number().int().positive().default(WORKSPACE_SETTINGS_SPEC_VERSION),
|
|
18029
18151
|
runMode: RunMode.default("standalone"),
|
|
@@ -18057,6 +18179,12 @@ var WorkspaceSettings = external_exports.object({
|
|
|
18057
18179
|
function defaultWorkspaceSettings() {
|
|
18058
18180
|
return WorkspaceSettings.parse({});
|
|
18059
18181
|
}
|
|
18182
|
+
function isAttached(settings) {
|
|
18183
|
+
return settings.runMode === "attached" && settings.controlPlane !== void 0;
|
|
18184
|
+
}
|
|
18185
|
+
function controlPlaneName(connection) {
|
|
18186
|
+
return connection.label ?? connection.endpoint;
|
|
18187
|
+
}
|
|
18060
18188
|
function toInventoryRow(input, id, now) {
|
|
18061
18189
|
return {
|
|
18062
18190
|
id,
|
|
@@ -18202,6 +18330,7 @@ var ManagedSettings = external_exports.object({
|
|
|
18202
18330
|
// the user may still override. The two are separable on purpose.
|
|
18203
18331
|
lockedFields: external_exports.array(ManagedSettingKey).default([])
|
|
18204
18332
|
}).meta({ id: "ManagedSettings" });
|
|
18333
|
+
var NO_MANAGED_CONTEXT = { present: false, lockedFields: [] };
|
|
18205
18334
|
|
|
18206
18335
|
// ../packages/schema/src/zod/policy.ts
|
|
18207
18336
|
var PolicyScope = external_exports.enum(["global", "repo", "user"]).meta({ id: "PolicyScope" });
|
|
@@ -18324,8 +18453,8 @@ function builtinPolicyIsReversible(id) {
|
|
|
18324
18453
|
return BUILTIN_POLICY_SPECS[id].reversible;
|
|
18325
18454
|
}
|
|
18326
18455
|
function policyIdIsReversible(policyId) {
|
|
18327
|
-
const
|
|
18328
|
-
const id =
|
|
18456
|
+
const parsed2 = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
|
|
18457
|
+
const id = parsed2.success ? parsed2.data : DEFAULT_PACK_POLICY_ID;
|
|
18329
18458
|
return builtinPolicyIsReversible(id);
|
|
18330
18459
|
}
|
|
18331
18460
|
var DEFAULT_ACTIONS = Object.fromEntries(
|
|
@@ -18337,12 +18466,12 @@ var BUILTIN_POLICIES = Object.fromEntries(
|
|
|
18337
18466
|
var DEFAULT_PACK_POLICY_ID = "monitor";
|
|
18338
18467
|
function policyDisplayName(policyId) {
|
|
18339
18468
|
const id = policyId ?? DEFAULT_PACK_POLICY_ID;
|
|
18340
|
-
const
|
|
18341
|
-
return
|
|
18469
|
+
const parsed2 = BuiltinPolicyId.safeParse(id);
|
|
18470
|
+
return parsed2.success ? BUILTIN_POLICIES[parsed2.data].name : id;
|
|
18342
18471
|
}
|
|
18343
18472
|
function policyIdToAction(policyId) {
|
|
18344
|
-
const
|
|
18345
|
-
const id =
|
|
18473
|
+
const parsed2 = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
|
|
18474
|
+
const id = parsed2.success ? parsed2.data : DEFAULT_PACK_POLICY_ID;
|
|
18346
18475
|
return BUILTIN_POLICIES[id].action;
|
|
18347
18476
|
}
|
|
18348
18477
|
var UsedByItem = external_exports.object({
|
|
@@ -19366,8 +19495,8 @@ var installCodexPlugin = manager2.install;
|
|
|
19366
19495
|
var updateCodexPlugin = manager2.update;
|
|
19367
19496
|
|
|
19368
19497
|
// ../packages/local-ops/src/egress-record.ts
|
|
19369
|
-
import { statSync as
|
|
19370
|
-
import { dirname as
|
|
19498
|
+
import { statSync as statSync9 } from "fs";
|
|
19499
|
+
import { dirname as dirname7, relative, resolve as resolve2 } from "path";
|
|
19371
19500
|
|
|
19372
19501
|
// ../packages/detections/src/egress/registry.ts
|
|
19373
19502
|
var EXTRACTOR_VERSION = "1";
|
|
@@ -20160,11 +20289,11 @@ function extractEgress(text) {
|
|
|
20160
20289
|
if (scheme === void 0) continue;
|
|
20161
20290
|
const candidate = matched.replace(TRAILING_PUNCTUATION, "");
|
|
20162
20291
|
if (candidate === "") continue;
|
|
20163
|
-
const
|
|
20164
|
-
if (
|
|
20292
|
+
const parsed2 = parseCandidate(candidate, scheme);
|
|
20293
|
+
if (parsed2 === null) continue;
|
|
20165
20294
|
const index = lineIndexAt(lineStarts, start);
|
|
20166
20295
|
hits.push({
|
|
20167
|
-
...
|
|
20296
|
+
...parsed2,
|
|
20168
20297
|
method: inferMethod(text, start, start + matched.length),
|
|
20169
20298
|
line: index + 1,
|
|
20170
20299
|
snippet: snippetAt(index, start)
|
|
@@ -20174,9 +20303,9 @@ function extractEgress(text) {
|
|
|
20174
20303
|
const start = match.index;
|
|
20175
20304
|
if (isInsideSpan(urlSpans, start)) continue;
|
|
20176
20305
|
const index = lineIndexAt(lineStarts, start);
|
|
20177
|
-
const
|
|
20178
|
-
if (
|
|
20179
|
-
hits.push({ ...
|
|
20306
|
+
const parsed2 = parseBareIp(match[0], ipContextOf(index));
|
|
20307
|
+
if (parsed2 === null) continue;
|
|
20308
|
+
hits.push({ ...parsed2, method: "REF", line: index + 1, snippet: snippetAt(index, start) });
|
|
20180
20309
|
}
|
|
20181
20310
|
return hits.sort(compareHits);
|
|
20182
20311
|
}
|
|
@@ -20188,21 +20317,21 @@ function parseCandidate(candidate, scheme) {
|
|
|
20188
20317
|
placeholders2 += 1;
|
|
20189
20318
|
return VAR_TOKEN;
|
|
20190
20319
|
});
|
|
20191
|
-
let
|
|
20320
|
+
let parsed2;
|
|
20192
20321
|
try {
|
|
20193
|
-
|
|
20322
|
+
parsed2 = new URL(normalized.split(VAR_TOKEN).join(VAR_SENTINEL));
|
|
20194
20323
|
} catch {
|
|
20195
20324
|
return null;
|
|
20196
20325
|
}
|
|
20197
|
-
const host =
|
|
20326
|
+
const host = parsed2.hostname.toLowerCase();
|
|
20198
20327
|
if (host === "" || host.includes(VAR_SENTINEL)) return null;
|
|
20199
|
-
const authority =
|
|
20200
|
-
const path = maskWebhookPath(host,
|
|
20328
|
+
const authority = parsed2.host.toLowerCase();
|
|
20329
|
+
const path = maskWebhookPath(host, parsed2.pathname);
|
|
20201
20330
|
const url2 = `${transport}://${authority}${path}`.split(VAR_SENTINEL).join(VAR_TOKEN);
|
|
20202
20331
|
return {
|
|
20203
20332
|
url: url2,
|
|
20204
20333
|
host,
|
|
20205
|
-
port:
|
|
20334
|
+
port: parsed2.port === "" ? null : Number(parsed2.port),
|
|
20206
20335
|
transport,
|
|
20207
20336
|
template: placeholders2 > 0
|
|
20208
20337
|
};
|
|
@@ -20396,15 +20525,15 @@ function makeHit(ecosystem, pkg, line, rawLine) {
|
|
|
20396
20525
|
return { ecosystem, pkg, line, snippet: redactSnippet(rawLine) };
|
|
20397
20526
|
}
|
|
20398
20527
|
function extractPackageJson(text) {
|
|
20399
|
-
const
|
|
20400
|
-
if (
|
|
20528
|
+
const parsed2 = parseJson(text);
|
|
20529
|
+
if (parsed2 === null) return [];
|
|
20401
20530
|
const seen = /* @__PURE__ */ new Set();
|
|
20402
20531
|
const hits = [];
|
|
20403
|
-
for (const pkg of objectKeys(
|
|
20532
|
+
for (const pkg of objectKeys(parsed2.dependencies)) {
|
|
20404
20533
|
seen.add(pkg);
|
|
20405
20534
|
hits.push(hitAtQuotedKey("npm", pkg, text, "dependencies"));
|
|
20406
20535
|
}
|
|
20407
|
-
for (const pkg of objectKeys(
|
|
20536
|
+
for (const pkg of objectKeys(parsed2.optionalDependencies)) {
|
|
20408
20537
|
if (seen.has(pkg)) continue;
|
|
20409
20538
|
seen.add(pkg);
|
|
20410
20539
|
hits.push(hitAtQuotedKey("npm", pkg, text, "optionalDependencies"));
|
|
@@ -20588,9 +20717,9 @@ function extractCargoToml(text) {
|
|
|
20588
20717
|
return hits;
|
|
20589
20718
|
}
|
|
20590
20719
|
function extractComposerJson(text) {
|
|
20591
|
-
const
|
|
20592
|
-
if (
|
|
20593
|
-
const pkgs = objectKeys(
|
|
20720
|
+
const parsed2 = parseJson(text);
|
|
20721
|
+
if (parsed2 === null) return [];
|
|
20722
|
+
const pkgs = objectKeys(parsed2.require).filter((pkg) => pkg !== "php" && !pkg.startsWith("ext-"));
|
|
20594
20723
|
return pkgs.map((pkg) => hitAtQuotedKey("composer", pkg, text, "require"));
|
|
20595
20724
|
}
|
|
20596
20725
|
var CSPROJ_PACKAGE_REFERENCE = /<PackageReference\s+Include="([^"]+)"/;
|
|
@@ -20643,14 +20772,14 @@ function eachLine(text, fn) {
|
|
|
20643
20772
|
}
|
|
20644
20773
|
}
|
|
20645
20774
|
function parseJson(text) {
|
|
20646
|
-
let
|
|
20775
|
+
let parsed2;
|
|
20647
20776
|
try {
|
|
20648
|
-
|
|
20777
|
+
parsed2 = JSON.parse(text);
|
|
20649
20778
|
} catch {
|
|
20650
20779
|
return null;
|
|
20651
20780
|
}
|
|
20652
|
-
if (typeof
|
|
20653
|
-
const record2 =
|
|
20781
|
+
if (typeof parsed2 !== "object" || parsed2 === null) return null;
|
|
20782
|
+
const record2 = parsed2;
|
|
20654
20783
|
return {
|
|
20655
20784
|
dependencies: record2.dependencies,
|
|
20656
20785
|
optionalDependencies: record2.optionalDependencies,
|
|
@@ -21171,46 +21300,9 @@ var POLYNOMIAL_PROBES = ["abc-", "a.", "a ", "a=", "x", "0", "a@", "a/", "ab"].m
|
|
|
21171
21300
|
var CPU_CORROBORATION_SHARE = 0.2;
|
|
21172
21301
|
var CORROBORATION_FLOOR_MS = BUDGET_MS * CPU_CORROBORATION_SHARE;
|
|
21173
21302
|
|
|
21174
|
-
// ../packages/persistence/src/
|
|
21175
|
-
import {
|
|
21176
|
-
import { join as
|
|
21177
|
-
import { DatabaseSync } from "node:sqlite";
|
|
21178
|
-
|
|
21179
|
-
// ../packages/persistence/src/ids.ts
|
|
21180
|
-
import { createHash } from "crypto";
|
|
21181
|
-
function sha256Hex(input) {
|
|
21182
|
-
return createHash("sha256").update(input).digest("hex");
|
|
21183
|
-
}
|
|
21184
|
-
function inventoryId(objectType, identityKey) {
|
|
21185
|
-
return sha256Hex(canonicalIdentity(["inventory", objectType, identityKey]));
|
|
21186
|
-
}
|
|
21187
|
-
function sourceProjectId(url2) {
|
|
21188
|
-
return sha256Hex(canonicalIdentity(["source_project", url2]));
|
|
21189
|
-
}
|
|
21190
|
-
function classifiedDataId(cls) {
|
|
21191
|
-
return sha256Hex(canonicalIdentity(["classified_data", cls]));
|
|
21192
|
-
}
|
|
21193
|
-
function inspectionDefinitionId(ruleId, version2) {
|
|
21194
|
-
return sha256Hex(canonicalIdentity(["inspection_definition", ruleId, version2]));
|
|
21195
|
-
}
|
|
21196
|
-
function llmCallId(sessionId, messageId) {
|
|
21197
|
-
return sha256Hex(canonicalIdentity(["audit_event_llm_call", sessionId, messageId]));
|
|
21198
|
-
}
|
|
21199
|
-
function toolCallId(sessionId, toolUseId) {
|
|
21200
|
-
return sha256Hex(canonicalIdentity(["audit_event_tool_call", sessionId, toolUseId]));
|
|
21201
|
-
}
|
|
21202
|
-
var NO_SESSION = "no_session";
|
|
21203
|
-
var NO_PATH = "no_path";
|
|
21204
|
-
function captureId(sessionId, contentHash, filePath = null) {
|
|
21205
|
-
return sha256Hex(
|
|
21206
|
-
canonicalIdentity(["capture", sessionId ?? NO_SESSION, contentHash, filePath ?? NO_PATH])
|
|
21207
|
-
);
|
|
21208
|
-
}
|
|
21209
|
-
|
|
21210
|
-
// ../packages/persistence/src/internal/snapshot.ts
|
|
21211
|
-
import { randomUUID } from "crypto";
|
|
21212
|
-
import { existsSync as existsSync3, readdirSync as readdirSync2, renameSync as renameSync2, rmSync as rmSync2, statSync } from "fs";
|
|
21213
|
-
import { basename, dirname as dirname3, join as join3 } from "path";
|
|
21303
|
+
// ../packages/persistence/src/control-plane-credential.ts
|
|
21304
|
+
import { chmodSync as chmodSync2, lstatSync as lstatSync2, readFileSync as readFileSync3, rmSync as rmSync2, statSync } from "fs";
|
|
21305
|
+
import { join as join3 } from "path";
|
|
21214
21306
|
|
|
21215
21307
|
// ../packages/persistence/src/paths.ts
|
|
21216
21308
|
import {
|
|
@@ -21337,7 +21429,131 @@ function publishByLink(tmp, file2, data) {
|
|
|
21337
21429
|
}
|
|
21338
21430
|
}
|
|
21339
21431
|
|
|
21432
|
+
// ../packages/persistence/src/control-plane-credential.ts
|
|
21433
|
+
function controlPlaneCredentialPath(settingsDir2) {
|
|
21434
|
+
return join3(settingsDir2, ATTACHED_CREDENTIAL_FILENAME);
|
|
21435
|
+
}
|
|
21436
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
21437
|
+
function isSafeEndpoint(endpoint) {
|
|
21438
|
+
let parsed2;
|
|
21439
|
+
try {
|
|
21440
|
+
parsed2 = new URL(endpoint);
|
|
21441
|
+
} catch {
|
|
21442
|
+
return false;
|
|
21443
|
+
}
|
|
21444
|
+
if (parsed2.protocol === "https:") return true;
|
|
21445
|
+
return parsed2.protocol === "http:" && LOOPBACK_HOSTS.has(parsed2.hostname);
|
|
21446
|
+
}
|
|
21447
|
+
function repairOrRefuseMode(file2) {
|
|
21448
|
+
const link = lstatSync2(file2, { throwIfNoEntry: false });
|
|
21449
|
+
if (link === void 0) return "absent";
|
|
21450
|
+
if (link.isSymbolicLink()) return "untrusted";
|
|
21451
|
+
const stat = statSync(file2, { throwIfNoEntry: false });
|
|
21452
|
+
if (stat === void 0) return "absent";
|
|
21453
|
+
const uid = process.getuid?.();
|
|
21454
|
+
if (uid !== void 0 && stat.uid !== uid) return "untrusted";
|
|
21455
|
+
if (process.platform !== "win32" && (stat.mode & 511) !== DATA_FILE_MODE) {
|
|
21456
|
+
try {
|
|
21457
|
+
chmodSync2(file2, DATA_FILE_MODE);
|
|
21458
|
+
} catch {
|
|
21459
|
+
return "untrusted";
|
|
21460
|
+
}
|
|
21461
|
+
}
|
|
21462
|
+
return "ok";
|
|
21463
|
+
}
|
|
21464
|
+
function readControlPlaneCredentialState(settingsDir2, connection) {
|
|
21465
|
+
const file2 = controlPlaneCredentialPath(settingsDir2);
|
|
21466
|
+
let raw;
|
|
21467
|
+
const gate = repairOrRefuseMode(file2);
|
|
21468
|
+
if (gate === "absent") return { usable: false, reason: "absent" };
|
|
21469
|
+
if (gate === "untrusted") return { usable: false, reason: "untrusted-file" };
|
|
21470
|
+
try {
|
|
21471
|
+
raw = readFileSync3(file2, "utf8");
|
|
21472
|
+
} catch (err) {
|
|
21473
|
+
const code = err.code;
|
|
21474
|
+
return { usable: false, reason: code === "ENOENT" ? "absent" : "unreadable" };
|
|
21475
|
+
}
|
|
21476
|
+
let parsed2;
|
|
21477
|
+
try {
|
|
21478
|
+
parsed2 = JSON.parse(raw);
|
|
21479
|
+
} catch {
|
|
21480
|
+
return { usable: false, reason: "malformed" };
|
|
21481
|
+
}
|
|
21482
|
+
const result = AttachedCredential.safeParse(parsed2);
|
|
21483
|
+
if (!result.success) return { usable: false, reason: "malformed" };
|
|
21484
|
+
if (!isSafeEndpoint(result.data.endpoint)) {
|
|
21485
|
+
return { usable: false, reason: "unsafe-endpoint" };
|
|
21486
|
+
}
|
|
21487
|
+
if (connection !== void 0 && connection.endpoint !== result.data.endpoint) {
|
|
21488
|
+
return {
|
|
21489
|
+
usable: false,
|
|
21490
|
+
reason: "endpoint-mismatch",
|
|
21491
|
+
credentialEndpoint: result.data.endpoint,
|
|
21492
|
+
settingsEndpoint: connection.endpoint
|
|
21493
|
+
};
|
|
21494
|
+
}
|
|
21495
|
+
return { usable: true, credential: result.data };
|
|
21496
|
+
}
|
|
21497
|
+
function writeControlPlaneCredential(settingsDir2, credential) {
|
|
21498
|
+
if (!isSafeEndpoint(credential.endpoint)) {
|
|
21499
|
+
throw new Error(
|
|
21500
|
+
`refusing to store a control-plane credential for a non-HTTPS endpoint: ${credential.endpoint}`
|
|
21501
|
+
);
|
|
21502
|
+
}
|
|
21503
|
+
ensureDataDirSync(settingsDir2);
|
|
21504
|
+
writeOwnerOnlyFileSync(
|
|
21505
|
+
controlPlaneCredentialPath(settingsDir2),
|
|
21506
|
+
`${JSON.stringify(credential, null, 2)}
|
|
21507
|
+
`
|
|
21508
|
+
);
|
|
21509
|
+
}
|
|
21510
|
+
function removeControlPlaneCredential(settingsDir2) {
|
|
21511
|
+
const file2 = controlPlaneCredentialPath(settingsDir2);
|
|
21512
|
+
const existed = lstatSync2(file2, { throwIfNoEntry: false }) !== void 0;
|
|
21513
|
+
rmSync2(file2, { force: true });
|
|
21514
|
+
return existed;
|
|
21515
|
+
}
|
|
21516
|
+
|
|
21517
|
+
// ../packages/persistence/src/database.ts
|
|
21518
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
21519
|
+
import { join as join5, sep as sep2 } from "path";
|
|
21520
|
+
import { DatabaseSync } from "node:sqlite";
|
|
21521
|
+
|
|
21522
|
+
// ../packages/persistence/src/ids.ts
|
|
21523
|
+
import { createHash } from "crypto";
|
|
21524
|
+
function sha256Hex(input) {
|
|
21525
|
+
return createHash("sha256").update(input).digest("hex");
|
|
21526
|
+
}
|
|
21527
|
+
function inventoryId(objectType, identityKey) {
|
|
21528
|
+
return sha256Hex(canonicalIdentity(["inventory", objectType, identityKey]));
|
|
21529
|
+
}
|
|
21530
|
+
function sourceProjectId(url2) {
|
|
21531
|
+
return sha256Hex(canonicalIdentity(["source_project", url2]));
|
|
21532
|
+
}
|
|
21533
|
+
function classifiedDataId(cls) {
|
|
21534
|
+
return sha256Hex(canonicalIdentity(["classified_data", cls]));
|
|
21535
|
+
}
|
|
21536
|
+
function inspectionDefinitionId(ruleId, version2) {
|
|
21537
|
+
return sha256Hex(canonicalIdentity(["inspection_definition", ruleId, version2]));
|
|
21538
|
+
}
|
|
21539
|
+
function llmCallId(sessionId, messageId) {
|
|
21540
|
+
return sha256Hex(canonicalIdentity(["audit_event_llm_call", sessionId, messageId]));
|
|
21541
|
+
}
|
|
21542
|
+
function toolCallId(sessionId, toolUseId) {
|
|
21543
|
+
return sha256Hex(canonicalIdentity(["audit_event_tool_call", sessionId, toolUseId]));
|
|
21544
|
+
}
|
|
21545
|
+
var NO_SESSION = "no_session";
|
|
21546
|
+
var NO_PATH = "no_path";
|
|
21547
|
+
function captureId(sessionId, contentHash, filePath = null) {
|
|
21548
|
+
return sha256Hex(
|
|
21549
|
+
canonicalIdentity(["capture", sessionId ?? NO_SESSION, contentHash, filePath ?? NO_PATH])
|
|
21550
|
+
);
|
|
21551
|
+
}
|
|
21552
|
+
|
|
21340
21553
|
// ../packages/persistence/src/internal/snapshot.ts
|
|
21554
|
+
import { randomUUID } from "crypto";
|
|
21555
|
+
import { existsSync as existsSync3, readdirSync as readdirSync2, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
21556
|
+
import { basename, dirname as dirname3, join as join4 } from "path";
|
|
21341
21557
|
function backupPath(file2, tag) {
|
|
21342
21558
|
return `${file2}.${tag}.${String(Date.now())}.${randomUUID().slice(0, 8)}.bak`;
|
|
21343
21559
|
}
|
|
@@ -21347,15 +21563,15 @@ var STAGED_NAME_SUFFIX = `.bak${SNAPSHOT_STAGING_SUFFIX}`;
|
|
|
21347
21563
|
var SNAPSHOT_STAGING_COPY = "copy";
|
|
21348
21564
|
function createSnapshotStaging(backup) {
|
|
21349
21565
|
const stage = `${backup}${SNAPSHOT_STAGING_SUFFIX}`;
|
|
21350
|
-
|
|
21566
|
+
rmSync3(stage, { recursive: true, force: true });
|
|
21351
21567
|
mkdirOwnerOnlySync(stage);
|
|
21352
21568
|
tightenDir(stage);
|
|
21353
|
-
return { stage, copy:
|
|
21569
|
+
return { stage, copy: join4(stage, SNAPSHOT_STAGING_COPY) };
|
|
21354
21570
|
}
|
|
21355
21571
|
function idleMs(entry) {
|
|
21356
|
-
for (const candidate of [
|
|
21572
|
+
for (const candidate of [join4(entry, SNAPSHOT_STAGING_COPY), entry]) {
|
|
21357
21573
|
try {
|
|
21358
|
-
return Date.now() -
|
|
21574
|
+
return Date.now() - statSync2(candidate).mtimeMs;
|
|
21359
21575
|
} catch {
|
|
21360
21576
|
}
|
|
21361
21577
|
}
|
|
@@ -21372,11 +21588,11 @@ function reapStalePartials(file2) {
|
|
|
21372
21588
|
}
|
|
21373
21589
|
for (const name of entries) {
|
|
21374
21590
|
if (!name.startsWith(prefix) || !name.endsWith(STAGED_NAME_SUFFIX)) continue;
|
|
21375
|
-
const staging =
|
|
21591
|
+
const staging = join4(dir, name);
|
|
21376
21592
|
try {
|
|
21377
21593
|
const idle = idleMs(staging);
|
|
21378
21594
|
if (idle !== null && idle > STALE_PARTIAL_MS) {
|
|
21379
|
-
|
|
21595
|
+
rmSync3(staging, { recursive: true, force: true });
|
|
21380
21596
|
}
|
|
21381
21597
|
} catch {
|
|
21382
21598
|
}
|
|
@@ -21390,13 +21606,13 @@ function snapshotStore(db, backup) {
|
|
|
21390
21606
|
renameSync2(copy, backup);
|
|
21391
21607
|
} catch (error51) {
|
|
21392
21608
|
try {
|
|
21393
|
-
|
|
21609
|
+
rmSync3(stage, { recursive: true, force: true });
|
|
21394
21610
|
} catch {
|
|
21395
21611
|
}
|
|
21396
21612
|
throw error51;
|
|
21397
21613
|
}
|
|
21398
21614
|
try {
|
|
21399
|
-
|
|
21615
|
+
rmSync3(stage, { recursive: true, force: true });
|
|
21400
21616
|
} catch {
|
|
21401
21617
|
}
|
|
21402
21618
|
}
|
|
@@ -21411,7 +21627,7 @@ function moveStoreAside(file2, backup) {
|
|
|
21411
21627
|
renameSync2(sidecar, moved);
|
|
21412
21628
|
undo.push([moved, sidecar]);
|
|
21413
21629
|
} catch {
|
|
21414
|
-
|
|
21630
|
+
rmSync3(sidecar, { force: true });
|
|
21415
21631
|
}
|
|
21416
21632
|
}
|
|
21417
21633
|
} catch (error51) {
|
|
@@ -21427,14 +21643,14 @@ function moveStoreAside(file2, backup) {
|
|
|
21427
21643
|
}
|
|
21428
21644
|
function discardStore(file2, backup) {
|
|
21429
21645
|
try {
|
|
21430
|
-
|
|
21646
|
+
rmSync3(file2, { force: true });
|
|
21431
21647
|
for (const sidecar of dbSidecars(file2)) {
|
|
21432
|
-
|
|
21648
|
+
rmSync3(sidecar, { force: true });
|
|
21433
21649
|
}
|
|
21434
21650
|
} catch (error51) {
|
|
21435
21651
|
if (existsSync3(file2)) {
|
|
21436
21652
|
try {
|
|
21437
|
-
|
|
21653
|
+
rmSync3(backup, { force: true });
|
|
21438
21654
|
} catch {
|
|
21439
21655
|
}
|
|
21440
21656
|
}
|
|
@@ -21666,10 +21882,31 @@ function applyMigrations(db, file2) {
|
|
|
21666
21882
|
if (drained) applyLegacyDropMigration(db, file2);
|
|
21667
21883
|
}
|
|
21668
21884
|
}
|
|
21885
|
+
function readLegacyTables(db) {
|
|
21886
|
+
let holdsRows = false;
|
|
21887
|
+
const marks = [];
|
|
21888
|
+
for (const table of ["events", "findings"]) {
|
|
21889
|
+
try {
|
|
21890
|
+
const row = db.prepare(`SELECT count(*) AS n, ifnull(max(rowid), -1) AS hi FROM ${table}`).get();
|
|
21891
|
+
if (row === void 0) {
|
|
21892
|
+
holdsRows = true;
|
|
21893
|
+
marks.push(`${table}:unreadable`);
|
|
21894
|
+
continue;
|
|
21895
|
+
}
|
|
21896
|
+
if (row.n > 0) holdsRows = true;
|
|
21897
|
+
marks.push(`${table}:${String(row.n)}:${String(row.hi)}`);
|
|
21898
|
+
} catch {
|
|
21899
|
+
holdsRows = true;
|
|
21900
|
+
marks.push(`${table}:unreadable`);
|
|
21901
|
+
}
|
|
21902
|
+
}
|
|
21903
|
+
return { holdsRows, mark: marks.join("|") };
|
|
21904
|
+
}
|
|
21669
21905
|
function applyLegacyDropMigration(db, file2) {
|
|
21670
21906
|
const migration = SQLITE_MIGRATIONS.find((m) => m.tag === LEGACY_DROP_MIGRATION_TAG);
|
|
21671
21907
|
if (!migration) return;
|
|
21672
|
-
|
|
21908
|
+
const before = file2 === void 0 ? void 0 : readLegacyTables(db);
|
|
21909
|
+
if (file2 !== void 0 && before?.holdsRows === true) {
|
|
21673
21910
|
try {
|
|
21674
21911
|
backupBeforeLegacyDrop(db, file2);
|
|
21675
21912
|
} catch (error51) {
|
|
@@ -21683,6 +21920,12 @@ function applyLegacyDropMigration(db, file2) {
|
|
|
21683
21920
|
() => {
|
|
21684
21921
|
const alreadyDropped = db.prepare("SELECT 1 FROM migration_ledger WHERE tag = ?").get(migration.tag);
|
|
21685
21922
|
if (alreadyDropped) return;
|
|
21923
|
+
if (before !== void 0 && readLegacyTables(db).mark !== before.mark) {
|
|
21924
|
+
akaWarn(
|
|
21925
|
+
"legacy events/findings rows changed after the pre-drop snapshot decision; deferring the drop so the next open can copy them first."
|
|
21926
|
+
);
|
|
21927
|
+
return;
|
|
21928
|
+
}
|
|
21686
21929
|
for (const statement of splitStatements(migration.sql)) {
|
|
21687
21930
|
db.exec(statement);
|
|
21688
21931
|
}
|
|
@@ -22037,8 +22280,8 @@ function safeJson(s, fallback) {
|
|
|
22037
22280
|
function parseJsonObject(s) {
|
|
22038
22281
|
if (s == null) return void 0;
|
|
22039
22282
|
try {
|
|
22040
|
-
const
|
|
22041
|
-
if (typeof
|
|
22283
|
+
const parsed2 = JSON.parse(s);
|
|
22284
|
+
if (typeof parsed2 === "object" && parsed2 !== null) return parsed2;
|
|
22042
22285
|
} catch {
|
|
22043
22286
|
}
|
|
22044
22287
|
return void 0;
|
|
@@ -22049,16 +22292,16 @@ function encodeKeysetCursor(payload) {
|
|
|
22049
22292
|
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
22050
22293
|
}
|
|
22051
22294
|
function decodeKeysetCursor(cursor) {
|
|
22052
|
-
const
|
|
22053
|
-
if (
|
|
22295
|
+
const parsed2 = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
22296
|
+
if (parsed2 !== void 0 && "startedAtMs" in parsed2 && "id" in parsed2 && // `Number.isInteger`, not `typeof === 'number'`. Every timestamp this
|
|
22054
22297
|
// resumes from is epoch millis, and a payload carrying ±Infinity or a
|
|
22055
22298
|
// fraction binds cleanly rather than failing — returning an EMPTY page with
|
|
22056
22299
|
// a null cursor, which a caller reads as "end of list". That is the one
|
|
22057
22300
|
// outcome a cursor that does not decode must never produce, since the
|
|
22058
22301
|
// documented behaviour above is to restart from the top. (`1e999` is valid
|
|
22059
22302
|
// JSON and parses to Infinity; a bare `NaN` is not, so it cannot arrive.)
|
|
22060
|
-
Number.isInteger(
|
|
22061
|
-
return
|
|
22303
|
+
Number.isInteger(parsed2.startedAtMs) && typeof parsed2.id === "string") {
|
|
22304
|
+
return parsed2;
|
|
22062
22305
|
}
|
|
22063
22306
|
return null;
|
|
22064
22307
|
}
|
|
@@ -22123,18 +22366,18 @@ var DB_EVENT_TYPE_TO_KIND = {
|
|
|
22123
22366
|
};
|
|
22124
22367
|
function safeParseStringArray(raw) {
|
|
22125
22368
|
if (!raw) return [];
|
|
22126
|
-
const
|
|
22127
|
-
return Array.isArray(
|
|
22369
|
+
const parsed2 = safeJson(raw, null);
|
|
22370
|
+
return Array.isArray(parsed2) ? parsed2 : [];
|
|
22128
22371
|
}
|
|
22129
22372
|
var DEFAULT_HARNESS = HARNESS.ClaudeCode;
|
|
22130
22373
|
function toHarness(raw) {
|
|
22131
|
-
const
|
|
22132
|
-
return
|
|
22374
|
+
const parsed2 = Harness.safeParse(raw);
|
|
22375
|
+
return parsed2.success ? parsed2.data : DEFAULT_HARNESS;
|
|
22133
22376
|
}
|
|
22134
22377
|
function resolveLifecycle(row, lastActivityMs, nowMs) {
|
|
22135
22378
|
if (row.status) {
|
|
22136
|
-
const
|
|
22137
|
-
if (
|
|
22379
|
+
const parsed2 = SessionStatus.safeParse(row.status);
|
|
22380
|
+
if (parsed2.success) return { status: parsed2.data, endedAtMs: row.ended_at };
|
|
22138
22381
|
}
|
|
22139
22382
|
if (row.ended_at !== null) return { status: "completed", endedAtMs: row.ended_at };
|
|
22140
22383
|
if (lastActivityMs >= nowMs - LIVE_ACTIVITY_WINDOW_MS) {
|
|
@@ -23093,9 +23336,9 @@ var SqliteDetectionsRepository = class {
|
|
|
23093
23336
|
const ruleIds = /* @__PURE__ */ new Set();
|
|
23094
23337
|
for (const r of rows) {
|
|
23095
23338
|
if (intToBool(r.enabled)) active += 1;
|
|
23096
|
-
const
|
|
23097
|
-
rules +=
|
|
23098
|
-
for (const rule of
|
|
23339
|
+
const parsed2 = parseRules(r.rulesJson);
|
|
23340
|
+
rules += parsed2.length;
|
|
23341
|
+
for (const rule of parsed2) {
|
|
23099
23342
|
if (typeof rule.id === "string") ruleIds.add(rule.id);
|
|
23100
23343
|
}
|
|
23101
23344
|
}
|
|
@@ -23629,12 +23872,12 @@ function encodeGroupCursor(group) {
|
|
|
23629
23872
|
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
23630
23873
|
}
|
|
23631
23874
|
function decodeGroupCursor(cursor) {
|
|
23632
|
-
const
|
|
23633
|
-
if (
|
|
23875
|
+
const parsed2 = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
23876
|
+
if (parsed2 !== void 0 && typeof parsed2.sev === "string" && typeof parsed2.t === "string" && typeof parsed2.id === "string") {
|
|
23634
23877
|
return {
|
|
23635
|
-
severity:
|
|
23636
|
-
latestDetectedAt:
|
|
23637
|
-
id:
|
|
23878
|
+
severity: parsed2.sev,
|
|
23879
|
+
latestDetectedAt: parsed2.t,
|
|
23880
|
+
id: parsed2.id
|
|
23638
23881
|
};
|
|
23639
23882
|
}
|
|
23640
23883
|
return null;
|
|
@@ -24768,16 +25011,16 @@ var SqliteInstalledPacksRepository = class {
|
|
|
24768
25011
|
continue;
|
|
24769
25012
|
}
|
|
24770
25013
|
for (const entry of raw) {
|
|
24771
|
-
const
|
|
24772
|
-
if (
|
|
24773
|
-
out.rules.push(
|
|
24774
|
-
out.ruleActions.set(
|
|
24775
|
-
out.ruleVersions.set(
|
|
24776
|
-
if (reversible) out.reversibleRules.add(
|
|
24777
|
-
else out.reversibleRules.delete(
|
|
25014
|
+
const parsed2 = Rule.safeParse(entry);
|
|
25015
|
+
if (parsed2.success) {
|
|
25016
|
+
out.rules.push(parsed2.data);
|
|
25017
|
+
out.ruleActions.set(parsed2.data.id, action);
|
|
25018
|
+
out.ruleVersions.set(parsed2.data.id, row.version);
|
|
25019
|
+
if (reversible) out.reversibleRules.add(parsed2.data.id);
|
|
25020
|
+
else out.reversibleRules.delete(parsed2.data.id);
|
|
24778
25021
|
} else {
|
|
24779
25022
|
out.invalidRules += 1;
|
|
24780
|
-
reject(pack, printableRuleId(entry), firstIssueReason(
|
|
25023
|
+
reject(pack, printableRuleId(entry), firstIssueReason(parsed2.error));
|
|
24781
25024
|
}
|
|
24782
25025
|
}
|
|
24783
25026
|
}
|
|
@@ -26167,15 +26410,15 @@ function encodeReuseCursor(payload) {
|
|
|
26167
26410
|
return Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
26168
26411
|
}
|
|
26169
26412
|
function decodeReuseCursor(cursor) {
|
|
26170
|
-
const
|
|
26171
|
-
if (
|
|
26413
|
+
const parsed2 = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
26414
|
+
if (parsed2 !== void 0 && // `Number.isInteger`, not `typeof === 'number'`: a payload carrying
|
|
26172
26415
|
// ±Infinity or a fraction binds cleanly and returns an EMPTY page with a
|
|
26173
26416
|
// null cursor, which the caller reads as "end of list" — the one outcome a
|
|
26174
26417
|
// malformed cursor must never produce, since restarting from the top is the
|
|
26175
26418
|
// documented behaviour and the only recoverable one. (`1e999` is valid JSON
|
|
26176
26419
|
// and parses to Infinity; a bare `NaN` is not, so it cannot arrive here.)
|
|
26177
|
-
Number.isInteger(
|
|
26178
|
-
return { occurrences:
|
|
26420
|
+
Number.isInteger(parsed2.occurrences) && typeof parsed2.pointerId === "string") {
|
|
26421
|
+
return { occurrences: parsed2.occurrences, pointerId: parsed2.pointerId };
|
|
26179
26422
|
}
|
|
26180
26423
|
return null;
|
|
26181
26424
|
}
|
|
@@ -27904,7 +28147,7 @@ function openAndInitialize(file2) {
|
|
|
27904
28147
|
}
|
|
27905
28148
|
function openLocalDatabase(dir) {
|
|
27906
28149
|
ensureDataDirSync(dir);
|
|
27907
|
-
const file2 =
|
|
28150
|
+
const file2 = join5(dir, DB_FILENAME);
|
|
27908
28151
|
reapStalePartials(file2);
|
|
27909
28152
|
const {
|
|
27910
28153
|
db,
|
|
@@ -28140,9 +28383,9 @@ import {
|
|
|
28140
28383
|
closeSync,
|
|
28141
28384
|
existsSync as existsSync4,
|
|
28142
28385
|
openSync,
|
|
28143
|
-
readFileSync as
|
|
28144
|
-
rmSync as
|
|
28145
|
-
statSync as
|
|
28386
|
+
readFileSync as readFileSync4,
|
|
28387
|
+
rmSync as rmSync4,
|
|
28388
|
+
statSync as statSync3,
|
|
28146
28389
|
writeFileSync as writeFileSync2
|
|
28147
28390
|
} from "fs";
|
|
28148
28391
|
import { hostname as hostname3 } from "os";
|
|
@@ -28176,13 +28419,13 @@ function lockPathFor(file2) {
|
|
|
28176
28419
|
function readLockBody(lock) {
|
|
28177
28420
|
let raw;
|
|
28178
28421
|
try {
|
|
28179
|
-
raw =
|
|
28422
|
+
raw = readFileSync4(lock, "utf8");
|
|
28180
28423
|
} catch {
|
|
28181
28424
|
return null;
|
|
28182
28425
|
}
|
|
28183
28426
|
try {
|
|
28184
|
-
const
|
|
28185
|
-
const { pid, token, at, host } =
|
|
28427
|
+
const parsed2 = JSON.parse(raw);
|
|
28428
|
+
const { pid, token, at, host } = parsed2;
|
|
28186
28429
|
if (typeof pid !== "number" || typeof token !== "string" || typeof at !== "number") return null;
|
|
28187
28430
|
return { pid, token, at, host: typeof host === "string" ? host : "" };
|
|
28188
28431
|
} catch {
|
|
@@ -28207,7 +28450,7 @@ function directoryAcceptsCreates(lock) {
|
|
|
28207
28450
|
return false;
|
|
28208
28451
|
} finally {
|
|
28209
28452
|
try {
|
|
28210
|
-
|
|
28453
|
+
rmSync4(probe, { force: true });
|
|
28211
28454
|
} catch {
|
|
28212
28455
|
}
|
|
28213
28456
|
}
|
|
@@ -28240,7 +28483,7 @@ function tryAcquire(lock, file2) {
|
|
|
28240
28483
|
closeSync(fd);
|
|
28241
28484
|
} catch {
|
|
28242
28485
|
}
|
|
28243
|
-
|
|
28486
|
+
rmSync4(lock, { force: true });
|
|
28244
28487
|
return null;
|
|
28245
28488
|
}
|
|
28246
28489
|
try {
|
|
@@ -28252,7 +28495,7 @@ function tryAcquire(lock, file2) {
|
|
|
28252
28495
|
function isAbandoned(body, lock, staleMs) {
|
|
28253
28496
|
if (!body) {
|
|
28254
28497
|
try {
|
|
28255
|
-
return Date.now() -
|
|
28498
|
+
return Date.now() - statSync3(lock).mtimeMs >= staleMs;
|
|
28256
28499
|
} catch {
|
|
28257
28500
|
return false;
|
|
28258
28501
|
}
|
|
@@ -28276,13 +28519,13 @@ function breakIfStale(lock, staleMs) {
|
|
|
28276
28519
|
}
|
|
28277
28520
|
try {
|
|
28278
28521
|
if (!existsSync4(lock) || !isAbandoned(readLockBody(lock), lock, staleMs)) return false;
|
|
28279
|
-
|
|
28522
|
+
rmSync4(lock, { force: true });
|
|
28280
28523
|
return true;
|
|
28281
28524
|
} catch {
|
|
28282
28525
|
return false;
|
|
28283
28526
|
} finally {
|
|
28284
28527
|
try {
|
|
28285
|
-
|
|
28528
|
+
rmSync4(breaker, { force: true });
|
|
28286
28529
|
} catch {
|
|
28287
28530
|
}
|
|
28288
28531
|
}
|
|
@@ -28290,8 +28533,8 @@ function breakIfStale(lock, staleMs) {
|
|
|
28290
28533
|
var BREAKER_ABANDONED_MS = 1e4;
|
|
28291
28534
|
function reapAbandonedBreaker(breaker) {
|
|
28292
28535
|
try {
|
|
28293
|
-
if (Date.now() -
|
|
28294
|
-
|
|
28536
|
+
if (Date.now() - statSync3(breaker).mtimeMs >= BREAKER_ABANDONED_MS) {
|
|
28537
|
+
rmSync4(breaker, { force: true });
|
|
28295
28538
|
}
|
|
28296
28539
|
} catch {
|
|
28297
28540
|
}
|
|
@@ -28302,7 +28545,7 @@ function abandonWindow(staleMs) {
|
|
|
28302
28545
|
function release(lock, token) {
|
|
28303
28546
|
try {
|
|
28304
28547
|
if (readLockBody(lock)?.token !== token) return;
|
|
28305
|
-
|
|
28548
|
+
rmSync4(lock, { force: true });
|
|
28306
28549
|
} catch {
|
|
28307
28550
|
}
|
|
28308
28551
|
}
|
|
@@ -28360,20 +28603,20 @@ function computeFindingKey(input) {
|
|
|
28360
28603
|
|
|
28361
28604
|
// ../packages/persistence/src/fingerprint.ts
|
|
28362
28605
|
import { createHmac, randomBytes } from "crypto";
|
|
28363
|
-
import { existsSync as existsSync5, readFileSync as
|
|
28364
|
-
import { join as
|
|
28606
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
28607
|
+
import { join as join6 } from "path";
|
|
28365
28608
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
28366
28609
|
var EXCEPTION_KEY_FILENAME = "exception.key";
|
|
28367
28610
|
var KEY_MATERIAL_BYTES = 32;
|
|
28368
28611
|
function keyFilePath(dataDir2) {
|
|
28369
|
-
return
|
|
28612
|
+
return join6(dataDir2, EXCEPTION_KEY_FILENAME);
|
|
28370
28613
|
}
|
|
28371
28614
|
function parseKeyFile(raw) {
|
|
28372
|
-
const
|
|
28373
|
-
if (typeof
|
|
28615
|
+
const parsed2 = JSON.parse(raw);
|
|
28616
|
+
if (typeof parsed2 !== "object" || parsed2 === null) {
|
|
28374
28617
|
throw new Error("exception key file is corrupt: not a JSON object");
|
|
28375
28618
|
}
|
|
28376
|
-
const { version: version2, material } =
|
|
28619
|
+
const { version: version2, material } = parsed2;
|
|
28377
28620
|
if (typeof version2 !== "number" || !Number.isInteger(version2) || version2 < 1) {
|
|
28378
28621
|
throw new Error("exception key file is corrupt: bad version");
|
|
28379
28622
|
}
|
|
@@ -28404,7 +28647,7 @@ var FloorUnreadableError = class extends Error {
|
|
|
28404
28647
|
}
|
|
28405
28648
|
};
|
|
28406
28649
|
function storedKeyVersionFloor(dataDir2) {
|
|
28407
|
-
const file2 =
|
|
28650
|
+
const file2 = join6(dataDir2, DB_FILENAME);
|
|
28408
28651
|
if (!existsSync5(file2)) return 0;
|
|
28409
28652
|
let db;
|
|
28410
28653
|
try {
|
|
@@ -28465,7 +28708,7 @@ function occupantMessage(file2, kind) {
|
|
|
28465
28708
|
function readFingerprintKey(dataDir2) {
|
|
28466
28709
|
let raw;
|
|
28467
28710
|
try {
|
|
28468
|
-
raw =
|
|
28711
|
+
raw = readFileSync5(keyFilePath(dataDir2), "utf8");
|
|
28469
28712
|
} catch (err) {
|
|
28470
28713
|
if (err.code === "ENOENT") return null;
|
|
28471
28714
|
throw err instanceof Error ? err : new Error(String(err));
|
|
@@ -28504,28 +28747,32 @@ function keyStateOf(key) {
|
|
|
28504
28747
|
import { renameSync as renameSync3 } from "fs";
|
|
28505
28748
|
import { mkdir } from "fs/promises";
|
|
28506
28749
|
import { homedir as homedir3 } from "os";
|
|
28507
|
-
import { join as
|
|
28750
|
+
import { join as join7 } from "path";
|
|
28508
28751
|
function defaultDataDir() {
|
|
28509
|
-
return
|
|
28752
|
+
return join7(homedir3(), ".aka");
|
|
28510
28753
|
}
|
|
28511
28754
|
function settingsDir(base = defaultDataDir()) {
|
|
28512
|
-
return
|
|
28755
|
+
return join7(base, "settings");
|
|
28513
28756
|
}
|
|
28514
28757
|
function dataDir(base = defaultDataDir()) {
|
|
28515
|
-
return
|
|
28758
|
+
return join7(base, "data");
|
|
28516
28759
|
}
|
|
28517
28760
|
function dbPath(base = defaultDataDir()) {
|
|
28518
|
-
return
|
|
28761
|
+
return join7(dataDir(base), "aka.db");
|
|
28519
28762
|
}
|
|
28520
28763
|
function keysDir(base = defaultDataDir()) {
|
|
28521
|
-
return
|
|
28764
|
+
return join7(base, "keys");
|
|
28765
|
+
}
|
|
28766
|
+
async function ensureDataDir(dir = defaultDataDir()) {
|
|
28767
|
+
await mkdir(dir, { recursive: true, mode: DATA_DIR_MODE });
|
|
28768
|
+
tightenDir(dir);
|
|
28522
28769
|
}
|
|
28523
28770
|
function ensureLayoutDirSync(dir = defaultDataDir()) {
|
|
28524
28771
|
ensureDataDirSync(dir);
|
|
28525
28772
|
}
|
|
28526
28773
|
|
|
28527
28774
|
// ../packages/persistence/src/managed-settings.ts
|
|
28528
|
-
import { readFileSync as
|
|
28775
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
28529
28776
|
import { posix, win32 } from "path";
|
|
28530
28777
|
function managedSettingsPaths(platform2 = process.platform) {
|
|
28531
28778
|
if (platform2 === "darwin") {
|
|
@@ -28543,17 +28790,25 @@ function readManagedSettings(paths = managedSettingsPaths()) {
|
|
|
28543
28790
|
for (const path of paths) {
|
|
28544
28791
|
let text;
|
|
28545
28792
|
try {
|
|
28546
|
-
text =
|
|
28793
|
+
text = readFileSync6(path, "utf8");
|
|
28547
28794
|
} catch {
|
|
28548
28795
|
continue;
|
|
28549
28796
|
}
|
|
28550
28797
|
const record2 = parseJsonObject(text);
|
|
28551
28798
|
if (!record2) continue;
|
|
28552
|
-
const
|
|
28553
|
-
if (
|
|
28799
|
+
const parsed2 = ManagedSettings.safeParse(record2);
|
|
28800
|
+
if (parsed2.success) return parsed2.data;
|
|
28554
28801
|
}
|
|
28555
28802
|
return null;
|
|
28556
28803
|
}
|
|
28804
|
+
function managedContextOf(managed) {
|
|
28805
|
+
if (!managed) return NO_MANAGED_CONTEXT;
|
|
28806
|
+
return {
|
|
28807
|
+
present: true,
|
|
28808
|
+
...managed.organization === void 0 ? {} : { organization: managed.organization },
|
|
28809
|
+
lockedFields: managed.lockedFields
|
|
28810
|
+
};
|
|
28811
|
+
}
|
|
28557
28812
|
function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ new Date()) {
|
|
28558
28813
|
if (!managed) return settings;
|
|
28559
28814
|
const { values } = managed;
|
|
@@ -28588,16 +28843,20 @@ function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ n
|
|
|
28588
28843
|
}
|
|
28589
28844
|
return merged;
|
|
28590
28845
|
}
|
|
28846
|
+
function lockedAmong(context, requested) {
|
|
28847
|
+
if (!context.present) return [];
|
|
28848
|
+
return requested.filter((key) => context.lockedFields.includes(key));
|
|
28849
|
+
}
|
|
28591
28850
|
|
|
28592
28851
|
// ../packages/persistence/src/settings.ts
|
|
28593
|
-
import { readFileSync as
|
|
28594
|
-
import { join as
|
|
28852
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
28853
|
+
import { join as join8 } from "path";
|
|
28595
28854
|
var SETTINGS_FILENAME = "settings.json";
|
|
28596
28855
|
function readWorkspaceSettings(base = defaultDataDir()) {
|
|
28597
28856
|
return overlayManagedSettings(readUserSettings(base), readManagedSettings());
|
|
28598
28857
|
}
|
|
28599
28858
|
function readUserSettings(base) {
|
|
28600
|
-
const record2 = readJson(
|
|
28859
|
+
const record2 = readJson(join8(settingsDir(base), SETTINGS_FILENAME));
|
|
28601
28860
|
if (!record2) return defaultWorkspaceSettings();
|
|
28602
28861
|
try {
|
|
28603
28862
|
return WorkspaceSettings.parse(record2);
|
|
@@ -28605,16 +28864,153 @@ function readUserSettings(base) {
|
|
|
28605
28864
|
return defaultWorkspaceSettings();
|
|
28606
28865
|
}
|
|
28607
28866
|
}
|
|
28867
|
+
var ManagedFieldError = class extends Error {
|
|
28868
|
+
fields;
|
|
28869
|
+
constructor(fields) {
|
|
28870
|
+
super(`refusing to write administratively locked settings: ${fields.join(", ")}`);
|
|
28871
|
+
this.name = "ManagedFieldError";
|
|
28872
|
+
this.fields = fields;
|
|
28873
|
+
}
|
|
28874
|
+
};
|
|
28875
|
+
function lockableKeysTouched(current, applied) {
|
|
28876
|
+
const keys = [];
|
|
28877
|
+
const changed = (key) => key in applied && applied[key] !== current[key];
|
|
28878
|
+
const descriptorChanged = "controlPlane" in applied && (applied.controlPlane?.endpoint !== current.controlPlane?.endpoint || applied.controlPlane?.label !== current.controlPlane?.label);
|
|
28879
|
+
if (changed("runMode") || descriptorChanged) keys.push("runMode");
|
|
28880
|
+
if (changed("historicalAccess")) keys.push("historicalAccess");
|
|
28881
|
+
if (changed("vaultKeyCustody")) keys.push("vaultKeyCustody");
|
|
28882
|
+
if (changed("vaultInlineReveal")) keys.push("vaultInlineReveal");
|
|
28883
|
+
if (changed("dataSharesInPlace")) keys.push("dataSharesInPlace");
|
|
28884
|
+
if ("vaultConsent" in applied && isVaultConsentValid(applied.vaultConsent) !== isVaultConsentValid(current.vaultConsent)) {
|
|
28885
|
+
keys.push("vaultConsent");
|
|
28886
|
+
}
|
|
28887
|
+
if ("modelJudgeConsent" in applied && isModelJudgeConsentValid(applied.modelJudgeConsent) !== isModelJudgeConsentValid(current.modelJudgeConsent)) {
|
|
28888
|
+
keys.push("modelJudgeConsent");
|
|
28889
|
+
}
|
|
28890
|
+
return keys;
|
|
28891
|
+
}
|
|
28892
|
+
function pinnedKeys(managed) {
|
|
28893
|
+
if (!managed) return [];
|
|
28894
|
+
const { values } = managed;
|
|
28895
|
+
const keys = [];
|
|
28896
|
+
if (values.runMode !== void 0 || values.controlPlane !== void 0) keys.push("runMode");
|
|
28897
|
+
if (values.historicalAccess !== void 0) keys.push("historicalAccess");
|
|
28898
|
+
if (values.vaultConsent !== void 0) keys.push("vaultConsent");
|
|
28899
|
+
if (values.vaultKeyCustody !== void 0) keys.push("vaultKeyCustody");
|
|
28900
|
+
if (values.vaultInlineReveal !== void 0) keys.push("vaultInlineReveal");
|
|
28901
|
+
if (values.modelJudgeConsent !== void 0) keys.push("modelJudgeConsent");
|
|
28902
|
+
if (values.dataSharesInPlace !== void 0) keys.push("dataSharesInPlace");
|
|
28903
|
+
return keys;
|
|
28904
|
+
}
|
|
28905
|
+
function withoutManagedKeys(applied, managed, pinned, touched) {
|
|
28906
|
+
if (!managed.present) return applied;
|
|
28907
|
+
const strip = (key) => (managed.lockedFields.includes(key) || pinned.includes(key)) && !touched.includes(key);
|
|
28908
|
+
const out = { ...applied };
|
|
28909
|
+
if (strip("runMode")) {
|
|
28910
|
+
delete out.runMode;
|
|
28911
|
+
delete out.controlPlane;
|
|
28912
|
+
}
|
|
28913
|
+
if (strip("historicalAccess")) delete out.historicalAccess;
|
|
28914
|
+
if (strip("vaultConsent")) delete out.vaultConsent;
|
|
28915
|
+
if (strip("vaultKeyCustody")) delete out.vaultKeyCustody;
|
|
28916
|
+
if (strip("vaultInlineReveal")) delete out.vaultInlineReveal;
|
|
28917
|
+
if (strip("modelJudgeConsent")) delete out.modelJudgeConsent;
|
|
28918
|
+
if (strip("dataSharesInPlace")) delete out.dataSharesInPlace;
|
|
28919
|
+
return out;
|
|
28920
|
+
}
|
|
28921
|
+
function applyOnboarding(answers, base = defaultDataDir(), managedOverride) {
|
|
28922
|
+
const dir = settingsDir(base);
|
|
28923
|
+
ensureDataDirSync(dir);
|
|
28924
|
+
const file2 = join8(dir, SETTINGS_FILENAME);
|
|
28925
|
+
const managedSettings = managedOverride === void 0 ? readManagedSettings() : managedOverride;
|
|
28926
|
+
const managed = managedContextOf(managedSettings);
|
|
28927
|
+
return withFileLock(file2, () => {
|
|
28928
|
+
const current = readUserSettings(base);
|
|
28929
|
+
const applied = typeof answers === "function" ? answers(current) : answers;
|
|
28930
|
+
const effective = overlayManagedSettings(current, managedSettings);
|
|
28931
|
+
const touched = lockableKeysTouched(effective, applied);
|
|
28932
|
+
const refused = lockedAmong(managed, touched);
|
|
28933
|
+
if (refused.length > 0) throw new ManagedFieldError(refused);
|
|
28934
|
+
const merged = WorkspaceSettings.parse({
|
|
28935
|
+
...current,
|
|
28936
|
+
// Locked keys are stripped rather than merged. Everything still here is,
|
|
28937
|
+
// by the refusal above, an unchanged ECHO of the administrator's value —
|
|
28938
|
+
// so dropping it discards no answer of the user's, and writing it would
|
|
28939
|
+
// persist the pin into their file, where it would outlive the managed
|
|
28940
|
+
// file and read as their own choice once the lock was gone.
|
|
28941
|
+
...withoutManagedKeys(applied, managed, pinnedKeys(managedSettings), touched),
|
|
28942
|
+
// First setup stamps the time; later edits keep the original completion mark.
|
|
28943
|
+
onboardedAt: applied.onboardedAt ?? current.onboardedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
28944
|
+
});
|
|
28945
|
+
writeOwnerOnlyFileSync(file2, `${JSON.stringify(merged, null, 2)}
|
|
28946
|
+
`);
|
|
28947
|
+
return merged;
|
|
28948
|
+
});
|
|
28949
|
+
}
|
|
28608
28950
|
function readJson(file2) {
|
|
28609
28951
|
let text;
|
|
28610
28952
|
try {
|
|
28611
|
-
text =
|
|
28953
|
+
text = readFileSync7(file2, "utf8");
|
|
28612
28954
|
} catch {
|
|
28613
28955
|
return null;
|
|
28614
28956
|
}
|
|
28615
28957
|
return parseJsonObject(text) ?? null;
|
|
28616
28958
|
}
|
|
28617
28959
|
|
|
28960
|
+
// ../packages/persistence/src/store-symlinks.ts
|
|
28961
|
+
import { existsSync as existsSync6, lstatSync as lstatSync3, readlinkSync, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
|
|
28962
|
+
import { dirname as dirname4, join as join9, resolve } from "path";
|
|
28963
|
+
var STORE_DB = "the store database (including the prompt corpus)";
|
|
28964
|
+
var STORE_SETTINGS = "your settings file";
|
|
28965
|
+
function storeContents(home) {
|
|
28966
|
+
return /* @__PURE__ */ new Map([
|
|
28967
|
+
[home, "the store (including the prompt corpus in aka.db)"],
|
|
28968
|
+
[settingsDir(home), STORE_SETTINGS],
|
|
28969
|
+
[dataDir(home), STORE_DB],
|
|
28970
|
+
[keysDir(home), "the vault key"],
|
|
28971
|
+
[join9(settingsDir(home), "settings.json"), STORE_SETTINGS],
|
|
28972
|
+
[dbPath(home), STORE_DB]
|
|
28973
|
+
]);
|
|
28974
|
+
}
|
|
28975
|
+
function storeTargets(home) {
|
|
28976
|
+
return [...storeContents(home).keys()];
|
|
28977
|
+
}
|
|
28978
|
+
function symlinkedStorePaths(home, platform2 = process.platform) {
|
|
28979
|
+
return [...storeContents(home)].flatMap(([path, holds]) => {
|
|
28980
|
+
try {
|
|
28981
|
+
if (!lstatSync3(path).isSymbolicLink()) return [];
|
|
28982
|
+
return [
|
|
28983
|
+
{
|
|
28984
|
+
path,
|
|
28985
|
+
target: linkTarget(path),
|
|
28986
|
+
holds,
|
|
28987
|
+
// existsSync follows the link, so a target that is gone reads as
|
|
28988
|
+
// absent here while lstat above still sees the link itself.
|
|
28989
|
+
missing: !existsSync6(path),
|
|
28990
|
+
mode: targetMode(path, platform2)
|
|
28991
|
+
}
|
|
28992
|
+
];
|
|
28993
|
+
} catch {
|
|
28994
|
+
return [];
|
|
28995
|
+
}
|
|
28996
|
+
});
|
|
28997
|
+
}
|
|
28998
|
+
function linkTarget(path) {
|
|
28999
|
+
try {
|
|
29000
|
+
return realpathSync2(path);
|
|
29001
|
+
} catch {
|
|
29002
|
+
return resolve(dirname4(path), readlinkSync(path));
|
|
29003
|
+
}
|
|
29004
|
+
}
|
|
29005
|
+
function targetMode(path, platform2) {
|
|
29006
|
+
if (platform2 === "win32") return void 0;
|
|
29007
|
+
try {
|
|
29008
|
+
return statSync4(path).mode & 511;
|
|
29009
|
+
} catch {
|
|
29010
|
+
return void 0;
|
|
29011
|
+
}
|
|
29012
|
+
}
|
|
29013
|
+
|
|
28618
29014
|
// ../packages/persistence/src/vault/crypto.ts
|
|
28619
29015
|
import {
|
|
28620
29016
|
createCipheriv,
|
|
@@ -28726,8 +29122,8 @@ function formatPointer(category, keyVersion, pointerId, tag) {
|
|
|
28726
29122
|
// ../packages/persistence/src/vault/key-provider.ts
|
|
28727
29123
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
28728
29124
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
28729
|
-
import { chmodSync as
|
|
28730
|
-
import { join as
|
|
29125
|
+
import { chmodSync as chmodSync3, readFileSync as readFileSync8, renameSync as renameSync4, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
29126
|
+
import { join as join10 } from "path";
|
|
28731
29127
|
var VAULT_OCCUPANT_REASON = {
|
|
28732
29128
|
symlink: "the path is a symlink; remove it so a keyring can be created",
|
|
28733
29129
|
gone: "the path was occupied but holds no keyring (removed while it was being created)",
|
|
@@ -28746,11 +29142,11 @@ var KEY_MATERIAL_BYTES2 = 32;
|
|
|
28746
29142
|
var KEYCHAIN_SERVICE = "aka-vault";
|
|
28747
29143
|
var KEYCHAIN_ACCOUNT = "keyring";
|
|
28748
29144
|
function parseKeyring(raw) {
|
|
28749
|
-
const
|
|
28750
|
-
if (typeof
|
|
29145
|
+
const parsed2 = JSON.parse(raw);
|
|
29146
|
+
if (typeof parsed2 !== "object" || parsed2 === null) {
|
|
28751
29147
|
throw new Error("vault key file is corrupt: not a JSON object");
|
|
28752
29148
|
}
|
|
28753
|
-
const { current, keys } =
|
|
29149
|
+
const { current, keys } = parsed2;
|
|
28754
29150
|
if (typeof current !== "number" || !Number.isInteger(current) || current < 1) {
|
|
28755
29151
|
throw new Error("vault key file is corrupt: bad current version");
|
|
28756
29152
|
}
|
|
@@ -28826,28 +29222,28 @@ function claimRotationLock(lock, owner) {
|
|
|
28826
29222
|
throw asError(err);
|
|
28827
29223
|
}
|
|
28828
29224
|
try {
|
|
28829
|
-
writeFileSync3(
|
|
29225
|
+
writeFileSync3(join10(lock, LOCK_OWNER_FILE), `${owner}
|
|
28830
29226
|
`, { mode: DATA_FILE_MODE });
|
|
28831
29227
|
return true;
|
|
28832
29228
|
} catch (err) {
|
|
28833
|
-
|
|
29229
|
+
rmSync5(lock, { recursive: true, force: true });
|
|
28834
29230
|
throw asError(err);
|
|
28835
29231
|
}
|
|
28836
29232
|
}
|
|
28837
29233
|
function acquireRotationLock(keysDir2) {
|
|
28838
|
-
const lock =
|
|
29234
|
+
const lock = join10(keysDir2, `${VAULT_KEY_FILENAME}.lock`);
|
|
28839
29235
|
const owner = randomBytes2(16).toString("hex");
|
|
28840
29236
|
if (claimRotationLock(lock, owner)) return { lock, owner };
|
|
28841
29237
|
let held;
|
|
28842
29238
|
try {
|
|
28843
|
-
held =
|
|
29239
|
+
held = statSync5(lock);
|
|
28844
29240
|
} catch {
|
|
28845
29241
|
throw new Error(ROTATION_IN_PROGRESS);
|
|
28846
29242
|
}
|
|
28847
29243
|
if (Date.now() - held.mtimeMs < ROTATION_LOCK_STALE_MS) throw new Error(ROTATION_IN_PROGRESS);
|
|
28848
29244
|
const aside = `${lock}.stale.${owner}`;
|
|
28849
29245
|
try {
|
|
28850
|
-
const now =
|
|
29246
|
+
const now = statSync5(lock);
|
|
28851
29247
|
if (now.ino !== held.ino || now.mtimeMs !== held.mtimeMs) {
|
|
28852
29248
|
throw new Error(ROTATION_IN_PROGRESS);
|
|
28853
29249
|
}
|
|
@@ -28856,17 +29252,17 @@ function acquireRotationLock(keysDir2) {
|
|
|
28856
29252
|
if (err instanceof Error && err.message === ROTATION_IN_PROGRESS) throw err;
|
|
28857
29253
|
throw new Error(ROTATION_IN_PROGRESS, { cause: err });
|
|
28858
29254
|
}
|
|
28859
|
-
|
|
29255
|
+
rmSync5(aside, { recursive: true, force: true });
|
|
28860
29256
|
if (!claimRotationLock(lock, owner)) throw new Error(ROTATION_IN_PROGRESS);
|
|
28861
29257
|
return { lock, owner };
|
|
28862
29258
|
}
|
|
28863
29259
|
function releaseRotationLock(lease) {
|
|
28864
29260
|
try {
|
|
28865
|
-
if (
|
|
29261
|
+
if (readFileSync8(join10(lease.lock, LOCK_OWNER_FILE), "utf8").trim() !== lease.owner) return;
|
|
28866
29262
|
} catch {
|
|
28867
29263
|
return;
|
|
28868
29264
|
}
|
|
28869
|
-
|
|
29265
|
+
rmSync5(lease.lock, { recursive: true, force: true });
|
|
28870
29266
|
}
|
|
28871
29267
|
function withRotationLock(keysDir2, work) {
|
|
28872
29268
|
ensureDataDirSync(keysDir2);
|
|
@@ -28883,7 +29279,7 @@ var FileKeyProvider = class {
|
|
|
28883
29279
|
this.#keysDir = keysDir2;
|
|
28884
29280
|
}
|
|
28885
29281
|
get filePath() {
|
|
28886
|
-
return
|
|
29282
|
+
return join10(this.#keysDir, VAULT_KEY_FILENAME);
|
|
28887
29283
|
}
|
|
28888
29284
|
loadOrCreate() {
|
|
28889
29285
|
return asAsync(() => {
|
|
@@ -28913,7 +29309,7 @@ var FileKeyProvider = class {
|
|
|
28913
29309
|
#read() {
|
|
28914
29310
|
let raw;
|
|
28915
29311
|
try {
|
|
28916
|
-
raw =
|
|
29312
|
+
raw = readFileSync8(this.filePath, "utf8");
|
|
28917
29313
|
} catch (err) {
|
|
28918
29314
|
if (err.code === "ENOENT") return null;
|
|
28919
29315
|
throw err instanceof Error ? err : new Error(String(err));
|
|
@@ -28970,7 +29366,7 @@ var FileKeyProvider = class {
|
|
|
28970
29366
|
};
|
|
28971
29367
|
function tightenFileMode(file2) {
|
|
28972
29368
|
try {
|
|
28973
|
-
|
|
29369
|
+
chmodSync3(file2, DATA_FILE_MODE);
|
|
28974
29370
|
} catch {
|
|
28975
29371
|
}
|
|
28976
29372
|
}
|
|
@@ -29235,25 +29631,25 @@ var SecretVault = class {
|
|
|
29235
29631
|
* model. Every call that gets as far as an identified row writes an audit row.
|
|
29236
29632
|
*/
|
|
29237
29633
|
async detokenize(token, opts) {
|
|
29238
|
-
const
|
|
29239
|
-
if (!
|
|
29634
|
+
const parsed2 = parsePointer(token);
|
|
29635
|
+
if (!parsed2) return UNAVAILABLE;
|
|
29240
29636
|
let signKey;
|
|
29241
29637
|
try {
|
|
29242
|
-
const epoch = await this.#keys.materialFor(
|
|
29638
|
+
const epoch = await this.#keys.materialFor(parsed2.keyVersion);
|
|
29243
29639
|
signKey = deriveSubkeys(epoch.material).sign;
|
|
29244
29640
|
} catch {
|
|
29245
29641
|
return UNAVAILABLE;
|
|
29246
29642
|
}
|
|
29247
|
-
if (!verifyPointerTag(signKey,
|
|
29643
|
+
if (!verifyPointerTag(signKey, parsed2.keyVersion, parsed2.pointerId, parsed2.category, parsed2.tag)) {
|
|
29248
29644
|
return UNAVAILABLE;
|
|
29249
29645
|
}
|
|
29250
|
-
const pointerId = base32Encode(
|
|
29646
|
+
const pointerId = base32Encode(parsed2.pointerId);
|
|
29251
29647
|
const row = this.#repo.byPointerId(pointerId);
|
|
29252
29648
|
if (!row) {
|
|
29253
29649
|
this.#audit(pointerId, opts, "unavailable");
|
|
29254
29650
|
return UNAVAILABLE;
|
|
29255
29651
|
}
|
|
29256
|
-
if (row.category !==
|
|
29652
|
+
if (row.category !== parsed2.category) return UNAVAILABLE;
|
|
29257
29653
|
if (opts.target === "model") {
|
|
29258
29654
|
const grantId = opts.grantId;
|
|
29259
29655
|
const verify = this.#verifyGrant;
|
|
@@ -29290,7 +29686,7 @@ var SecretVault = class {
|
|
|
29290
29686
|
// moved the epoch past the one this token names, and a format bump may
|
|
29291
29687
|
// have moved the constant past the generation this row was sealed
|
|
29292
29688
|
// under — the AAD follows the row in both cases, never the token.
|
|
29293
|
-
bindingInput(row.keyVersion,
|
|
29689
|
+
bindingInput(row.keyVersion, parsed2.pointerId, row.category, row.formatVersion)
|
|
29294
29690
|
);
|
|
29295
29691
|
} catch {
|
|
29296
29692
|
raw = null;
|
|
@@ -29508,19 +29904,19 @@ var SecretVault = class {
|
|
|
29508
29904
|
// preview. Verifying needs the historical epoch's key, which is why these
|
|
29509
29905
|
// surfaces are async.
|
|
29510
29906
|
async #rowFor(token) {
|
|
29511
|
-
const
|
|
29512
|
-
if (!
|
|
29907
|
+
const parsed2 = parsePointer(token);
|
|
29908
|
+
if (!parsed2) return null;
|
|
29513
29909
|
try {
|
|
29514
|
-
const epoch = await this.#keys.materialFor(
|
|
29910
|
+
const epoch = await this.#keys.materialFor(parsed2.keyVersion);
|
|
29515
29911
|
const signKey = deriveSubkeys(epoch.material).sign;
|
|
29516
|
-
if (!verifyPointerTag(signKey,
|
|
29912
|
+
if (!verifyPointerTag(signKey, parsed2.keyVersion, parsed2.pointerId, parsed2.category, parsed2.tag)) {
|
|
29517
29913
|
return null;
|
|
29518
29914
|
}
|
|
29519
29915
|
} catch {
|
|
29520
29916
|
return null;
|
|
29521
29917
|
}
|
|
29522
|
-
const row = this.#repo.byPointerId(base32Encode(
|
|
29523
|
-
if (row?.category !==
|
|
29918
|
+
const row = this.#repo.byPointerId(base32Encode(parsed2.pointerId));
|
|
29919
|
+
if (row?.category !== parsed2.category) return null;
|
|
29524
29920
|
return row;
|
|
29525
29921
|
}
|
|
29526
29922
|
#audit(pointerId, opts, outcome) {
|
|
@@ -29540,12 +29936,12 @@ var SecretVault = class {
|
|
|
29540
29936
|
};
|
|
29541
29937
|
|
|
29542
29938
|
// ../packages/persistence/src/warn-era-cap.ts
|
|
29543
|
-
import { existsSync as
|
|
29544
|
-
import { join as
|
|
29939
|
+
import { existsSync as existsSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
29940
|
+
import { join as join11 } from "path";
|
|
29545
29941
|
|
|
29546
29942
|
// ../packages/plugin-sdk/src/config.ts
|
|
29547
|
-
import { existsSync as
|
|
29548
|
-
import { join as
|
|
29943
|
+
import { existsSync as existsSync8 } from "fs";
|
|
29944
|
+
import { join as join12 } from "path";
|
|
29549
29945
|
|
|
29550
29946
|
// ../packages/plugin-sdk/src/provider-env.ts
|
|
29551
29947
|
var booleanish = external_exports.string().optional().transform((v) => {
|
|
@@ -29566,9 +29962,9 @@ var providerEnvShape = {
|
|
|
29566
29962
|
var ProviderEnvSchema = external_exports.object(providerEnvShape);
|
|
29567
29963
|
|
|
29568
29964
|
// ../packages/plugin-sdk/src/config-inventory.ts
|
|
29569
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
29965
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync10, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
|
|
29570
29966
|
import { homedir as homedir4 } from "os";
|
|
29571
|
-
import { basename as basename3, join as
|
|
29967
|
+
import { basename as basename3, join as join14 } from "path";
|
|
29572
29968
|
|
|
29573
29969
|
// ../rules/code-flaws/auth-jwt-no-verify.json
|
|
29574
29970
|
var auth_jwt_no_verify_default = {
|
|
@@ -30291,10 +30687,10 @@ var localhost_ref_default = {
|
|
|
30291
30687
|
severity: "low",
|
|
30292
30688
|
matcher: {
|
|
30293
30689
|
type: "regex",
|
|
30294
|
-
pattern: "
|
|
30690
|
+
pattern: "(?<![A-Za-z0-9_])(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|(?<![A-Za-z0-9_]\\[)::1(?!:|\\.[0-9]))(?![A-Za-z0-9_])",
|
|
30295
30691
|
flags: "g"
|
|
30296
30692
|
},
|
|
30297
|
-
examples: ["localhost", "127.0.0.1"]
|
|
30693
|
+
examples: ["localhost", "127.0.0.1", "0.0.0.0", "::1"]
|
|
30298
30694
|
};
|
|
30299
30695
|
|
|
30300
30696
|
// ../rules/core-code-context/stack-trace.json
|
|
@@ -31603,8 +31999,8 @@ function bundledDetections() {
|
|
|
31603
31999
|
}
|
|
31604
32000
|
|
|
31605
32001
|
// ../packages/plugin-sdk/src/repo.ts
|
|
31606
|
-
import { existsSync as
|
|
31607
|
-
import { basename as basename2, dirname as
|
|
32002
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, statSync as statSync6 } from "fs";
|
|
32003
|
+
import { basename as basename2, dirname as dirname5, isAbsolute, join as join13, sep as sep3 } from "path";
|
|
31608
32004
|
function resolveRepoIdentity(cwd) {
|
|
31609
32005
|
try {
|
|
31610
32006
|
const root = findGitRoot(cwd);
|
|
@@ -31642,36 +32038,36 @@ function resolveHeadRoot(cwd) {
|
|
|
31642
32038
|
function findGitRoot(start) {
|
|
31643
32039
|
let dir = start;
|
|
31644
32040
|
for (; ; ) {
|
|
31645
|
-
if (
|
|
31646
|
-
const parent =
|
|
32041
|
+
if (existsSync9(join13(dir, ".git"))) return dir;
|
|
32042
|
+
const parent = dirname5(dir);
|
|
31647
32043
|
if (parent === dir) return void 0;
|
|
31648
32044
|
dir = parent;
|
|
31649
32045
|
}
|
|
31650
32046
|
}
|
|
31651
32047
|
function resolveGitContext(root) {
|
|
31652
|
-
const dotGit =
|
|
32048
|
+
const dotGit = join13(root, ".git");
|
|
31653
32049
|
try {
|
|
31654
|
-
if (
|
|
31655
|
-
return { configPath:
|
|
32050
|
+
if (statSync6(dotGit).isDirectory()) {
|
|
32051
|
+
return { configPath: join13(dotGit, "config"), headRoot: root };
|
|
31656
32052
|
}
|
|
31657
32053
|
} catch {
|
|
31658
32054
|
return void 0;
|
|
31659
32055
|
}
|
|
31660
32056
|
const target = /^gitdir:\s*(.+?)\s*$/m.exec(safeRead(dotGit) ?? "")?.[1];
|
|
31661
32057
|
if (!target) return void 0;
|
|
31662
|
-
const gitdir = isAbsolute(target) ? target :
|
|
31663
|
-
if (
|
|
31664
|
-
return { configPath:
|
|
32058
|
+
const gitdir = isAbsolute(target) ? target : join13(root, target);
|
|
32059
|
+
if (existsSync9(join13(gitdir, "config"))) {
|
|
32060
|
+
return { configPath: join13(gitdir, "config"), headRoot: root };
|
|
31665
32061
|
}
|
|
31666
|
-
const commonRaw = safeRead(
|
|
32062
|
+
const commonRaw = safeRead(join13(gitdir, "commondir"))?.trim();
|
|
31667
32063
|
if (!commonRaw) return void 0;
|
|
31668
|
-
const commonGitDir = isAbsolute(commonRaw) ? commonRaw :
|
|
31669
|
-
const headRoot = basename2(commonGitDir) === ".git" ?
|
|
31670
|
-
return { configPath:
|
|
32064
|
+
const commonGitDir = isAbsolute(commonRaw) ? commonRaw : join13(gitdir, commonRaw);
|
|
32065
|
+
const headRoot = basename2(commonGitDir) === ".git" ? dirname5(commonGitDir) : root;
|
|
32066
|
+
return { configPath: join13(commonGitDir, "config"), headRoot };
|
|
31671
32067
|
}
|
|
31672
32068
|
function safeRead(path) {
|
|
31673
32069
|
try {
|
|
31674
|
-
return
|
|
32070
|
+
return readFileSync9(path, "utf8");
|
|
31675
32071
|
} catch {
|
|
31676
32072
|
return void 0;
|
|
31677
32073
|
}
|
|
@@ -31712,17 +32108,17 @@ function slugFromUrl(url2) {
|
|
|
31712
32108
|
import { createHash as createHash4, randomUUID as randomUUID13 } from "crypto";
|
|
31713
32109
|
|
|
31714
32110
|
// ../packages/plugin-sdk/src/isolated-scan.ts
|
|
31715
|
-
import { existsSync as
|
|
32111
|
+
import { existsSync as existsSync10 } from "fs";
|
|
31716
32112
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
31717
32113
|
import { Worker } from "worker_threads";
|
|
31718
32114
|
|
|
31719
32115
|
// ../packages/plugin-sdk/src/ignore-layers.ts
|
|
31720
32116
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
31721
|
-
import { readFileSync as
|
|
31722
|
-
import { join as
|
|
32117
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
32118
|
+
import { join as join15 } from "path";
|
|
31723
32119
|
function readIgnoreLayer(dir, filename, anchorLen) {
|
|
31724
32120
|
try {
|
|
31725
|
-
return { matcher: (0, import_ignore.default)().add(
|
|
32121
|
+
return { matcher: (0, import_ignore.default)().add(readFileSync11(join15(dir, filename), "utf8")), anchorLen };
|
|
31726
32122
|
} catch {
|
|
31727
32123
|
return void 0;
|
|
31728
32124
|
}
|
|
@@ -31753,12 +32149,12 @@ function withLayer(layers, layer) {
|
|
|
31753
32149
|
import { arch, hostname as hostname4, platform, release as release2 } from "os";
|
|
31754
32150
|
|
|
31755
32151
|
// ../packages/plugin-sdk/src/nudge.ts
|
|
31756
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
31757
|
-
import { join as
|
|
32152
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
|
|
32153
|
+
import { join as join16 } from "path";
|
|
31758
32154
|
|
|
31759
32155
|
// ../packages/plugin-sdk/src/paths.ts
|
|
31760
|
-
import { readdirSync as readdirSync4, realpathSync as
|
|
31761
|
-
import { basename as basename4, dirname as
|
|
32156
|
+
import { readdirSync as readdirSync4, realpathSync as realpathSync4 } from "fs";
|
|
32157
|
+
import { basename as basename4, dirname as dirname6, sep as sep4 } from "path";
|
|
31762
32158
|
function toPosix(path) {
|
|
31763
32159
|
return path.split(sep4).join("/");
|
|
31764
32160
|
}
|
|
@@ -31768,7 +32164,7 @@ function findProjectRoot(startDir, recognizeMarker) {
|
|
|
31768
32164
|
let root = null;
|
|
31769
32165
|
for (let level = 0; level < MAX_PROJECT_ROOT_LEVELS; level += 1) {
|
|
31770
32166
|
if (directoryHasMarker(dir, recognizeMarker)) root = dir;
|
|
31771
|
-
const parent =
|
|
32167
|
+
const parent = dirname6(dir);
|
|
31772
32168
|
if (parent === dir) break;
|
|
31773
32169
|
dir = parent;
|
|
31774
32170
|
}
|
|
@@ -31786,13 +32182,13 @@ function directoryHasMarker(dir, recognizeMarker) {
|
|
|
31786
32182
|
}
|
|
31787
32183
|
function resolveNonGitProject(startDir, recognizeMarker) {
|
|
31788
32184
|
const projectRoot = findProjectRoot(startDir, recognizeMarker);
|
|
31789
|
-
const realRoot =
|
|
32185
|
+
const realRoot = realpathSync4(projectRoot);
|
|
31790
32186
|
return { root: projectRoot, projectKey: `path:${realRoot}`, project: basename4(realRoot) };
|
|
31791
32187
|
}
|
|
31792
32188
|
|
|
31793
32189
|
// ../packages/plugin-sdk/src/project-files.ts
|
|
31794
|
-
import { existsSync as
|
|
31795
|
-
import { basename as basename5, join as
|
|
32190
|
+
import { existsSync as existsSync11, readdirSync as readdirSync5 } from "fs";
|
|
32191
|
+
import { basename as basename5, join as join17 } from "path";
|
|
31796
32192
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
31797
32193
|
".git",
|
|
31798
32194
|
"node_modules",
|
|
@@ -31889,8 +32285,8 @@ function resolveProjectFiles(cwd, opts = {}) {
|
|
|
31889
32285
|
}
|
|
31890
32286
|
if (entry.isDirectory()) {
|
|
31891
32287
|
if (SKIP_DIRS.has(entry.name) || isIgnored(dirLayers, dirRel, entry.name, true)) continue;
|
|
31892
|
-
const fullPath =
|
|
31893
|
-
if (
|
|
32288
|
+
const fullPath = join17(dir, entry.name);
|
|
32289
|
+
if (existsSync11(join17(fullPath, ".git"))) continue;
|
|
31894
32290
|
if (depth >= bounds.maxDepth) {
|
|
31895
32291
|
walk.omitted = true;
|
|
31896
32292
|
continue;
|
|
@@ -31962,15 +32358,15 @@ import { randomUUID as randomUUID14 } from "crypto";
|
|
|
31962
32358
|
var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
31963
32359
|
|
|
31964
32360
|
// ../packages/plugin-sdk/src/throttle.ts
|
|
31965
|
-
import { mkdirSync as mkdirSync3, statSync as
|
|
31966
|
-
import { join as
|
|
32361
|
+
import { mkdirSync as mkdirSync3, statSync as statSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
32362
|
+
import { join as join18 } from "path";
|
|
31967
32363
|
|
|
31968
32364
|
// ../packages/local-ops/src/egress-record.ts
|
|
31969
32365
|
function recordProjectEgress(db, target, egress, base = defaultDataDir()) {
|
|
31970
32366
|
try {
|
|
31971
32367
|
if (!readWorkspaceSettings(base).dataSharesInPlace) return null;
|
|
31972
|
-
const abs =
|
|
31973
|
-
const targetDir =
|
|
32368
|
+
const abs = resolve2(target);
|
|
32369
|
+
const targetDir = statSync9(abs).isDirectory() ? abs : dirname7(abs);
|
|
31974
32370
|
const identity = resolveRepoIdentity(abs);
|
|
31975
32371
|
const worktreeRoot = resolveWorktreeRoot(abs);
|
|
31976
32372
|
let root;
|
|
@@ -32012,8 +32408,8 @@ function recordProjectEgress(db, target, egress, base = defaultDataDir()) {
|
|
|
32012
32408
|
|
|
32013
32409
|
// ../packages/local-ops/src/fs-scan.ts
|
|
32014
32410
|
import { createHash as createHash5, randomUUID as randomUUID15 } from "crypto";
|
|
32015
|
-
import { readdirSync as readdirSync6, readFileSync as
|
|
32016
|
-
import { basename as basename6, extname, join as
|
|
32411
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync13, statSync as statSync10 } from "fs";
|
|
32412
|
+
import { basename as basename6, extname, join as join19, resolve as resolve3 } from "path";
|
|
32017
32413
|
var AKAIGNORE_FILENAME = ".akaignore";
|
|
32018
32414
|
var SKIP_DIRS2 = /* @__PURE__ */ new Set([
|
|
32019
32415
|
"node_modules",
|
|
@@ -32029,7 +32425,7 @@ var MAX_BYTES = 1e6;
|
|
|
32029
32425
|
function* collectFiles(target) {
|
|
32030
32426
|
let st;
|
|
32031
32427
|
try {
|
|
32032
|
-
st =
|
|
32428
|
+
st = statSync10(target);
|
|
32033
32429
|
} catch {
|
|
32034
32430
|
return;
|
|
32035
32431
|
}
|
|
@@ -32057,7 +32453,7 @@ function* visit(dir, dirRel, markLayers, skipLayers, inIgnoredDir) {
|
|
|
32057
32453
|
readIgnoreLayer(dir, AKAIGNORE_FILENAME, dirRel.length)
|
|
32058
32454
|
);
|
|
32059
32455
|
for (const entry of dirents) {
|
|
32060
|
-
const path =
|
|
32456
|
+
const path = join19(dir, entry.name);
|
|
32061
32457
|
if (entry.isDirectory()) {
|
|
32062
32458
|
const skipState = evaluateIgnore(dirSkipLayers, dirRel, entry.name, true);
|
|
32063
32459
|
if (skipState !== "unignored" && (SKIP_DIRS2.has(entry.name) || entry.name.startsWith(".") || skipState === "ignored")) {
|
|
@@ -32069,7 +32465,7 @@ function* visit(dir, dirRel, markLayers, skipLayers, inIgnoredDir) {
|
|
|
32069
32465
|
if (evaluateIgnore(dirSkipLayers, dirRel, entry.name, false) === "ignored") continue;
|
|
32070
32466
|
let size;
|
|
32071
32467
|
try {
|
|
32072
|
-
size =
|
|
32468
|
+
size = statSync10(path).size;
|
|
32073
32469
|
} catch {
|
|
32074
32470
|
continue;
|
|
32075
32471
|
}
|
|
@@ -32108,10 +32504,10 @@ async function scanPathIntoStore(db, target, opts = {}) {
|
|
|
32108
32504
|
}
|
|
32109
32505
|
return fingerprintKey;
|
|
32110
32506
|
}
|
|
32111
|
-
for (const { path: file2, gitignored } of collectFiles(
|
|
32507
|
+
for (const { path: file2, gitignored } of collectFiles(resolve3(target))) {
|
|
32112
32508
|
let text;
|
|
32113
32509
|
try {
|
|
32114
|
-
text =
|
|
32510
|
+
text = readFileSync13(file2, "utf8");
|
|
32115
32511
|
} catch {
|
|
32116
32512
|
continue;
|
|
32117
32513
|
}
|
|
@@ -32164,12 +32560,12 @@ async function scanPathIntoStore(db, target, opts = {}) {
|
|
|
32164
32560
|
}
|
|
32165
32561
|
|
|
32166
32562
|
// ../packages/local-ops/src/project-inventory.ts
|
|
32167
|
-
import { statSync as
|
|
32168
|
-
import { resolve as
|
|
32563
|
+
import { statSync as statSync11 } from "fs";
|
|
32564
|
+
import { resolve as resolve4 } from "path";
|
|
32169
32565
|
function recordProjectInventory(db, target) {
|
|
32170
32566
|
try {
|
|
32171
|
-
const abs =
|
|
32172
|
-
|
|
32567
|
+
const abs = resolve4(target);
|
|
32568
|
+
statSync11(abs);
|
|
32173
32569
|
const identity = resolveRepoIdentity(abs);
|
|
32174
32570
|
if (!identity) return null;
|
|
32175
32571
|
const sourceProjectId2 = db.sourceProject.upsert({
|
|
@@ -32198,17 +32594,17 @@ function recordProjectInventory(db, target) {
|
|
|
32198
32594
|
|
|
32199
32595
|
// ../packages/local-ops/src/update-cache.ts
|
|
32200
32596
|
import { spawn } from "child_process";
|
|
32201
|
-
import { existsSync as
|
|
32202
|
-
import { join as
|
|
32597
|
+
import { existsSync as existsSync12, readFileSync as readFileSync14, rmSync as rmSync6 } from "fs";
|
|
32598
|
+
import { join as join20 } from "path";
|
|
32203
32599
|
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
32204
32600
|
function cachePath(home) {
|
|
32205
|
-
return
|
|
32601
|
+
return join20(dataDir(home), "update-check.json");
|
|
32206
32602
|
}
|
|
32207
32603
|
function readCache(home) {
|
|
32208
32604
|
const path = cachePath(home);
|
|
32209
|
-
if (!
|
|
32605
|
+
if (!existsSync12(path)) return null;
|
|
32210
32606
|
try {
|
|
32211
|
-
const raw = JSON.parse(
|
|
32607
|
+
const raw = JSON.parse(readFileSync14(path, "utf8"));
|
|
32212
32608
|
if (!isRecord(raw) || typeof raw.checkedAt !== "number" || !isRecord(raw.report)) return null;
|
|
32213
32609
|
return raw;
|
|
32214
32610
|
} catch {
|
|
@@ -32216,7 +32612,7 @@ function readCache(home) {
|
|
|
32216
32612
|
}
|
|
32217
32613
|
}
|
|
32218
32614
|
function writeCache(home, cache) {
|
|
32219
|
-
if (!
|
|
32615
|
+
if (!existsSync12(dataDir(home))) return;
|
|
32220
32616
|
try {
|
|
32221
32617
|
writeOwnerOnlyFileSync(cachePath(home), `${JSON.stringify(cache, null, 2)}
|
|
32222
32618
|
`);
|
|
@@ -32228,7 +32624,7 @@ function isStale(cache, ttlMs = CHECK_TTL_MS) {
|
|
|
32228
32624
|
}
|
|
32229
32625
|
function clearCache(home) {
|
|
32230
32626
|
try {
|
|
32231
|
-
|
|
32627
|
+
rmSync6(cachePath(home), { force: true });
|
|
32232
32628
|
} catch {
|
|
32233
32629
|
}
|
|
32234
32630
|
}
|
|
@@ -32361,6 +32757,16 @@ var COMMAND_SPECS = [
|
|
|
32361
32757
|
summary: "Reveal a vaulted secret by its pointer (every reveal is audited)",
|
|
32362
32758
|
args: ["show"]
|
|
32363
32759
|
},
|
|
32760
|
+
{
|
|
32761
|
+
name: "attach",
|
|
32762
|
+
argHint: "--url <url>",
|
|
32763
|
+
summary: "Register this machine against your organization's AKA deployment"
|
|
32764
|
+
},
|
|
32765
|
+
{ name: "detach", summary: "Stop reporting to a deployment; record locally only" },
|
|
32766
|
+
{
|
|
32767
|
+
name: "status",
|
|
32768
|
+
summary: "Show what this machine is attached to, and whether policy is current"
|
|
32769
|
+
},
|
|
32364
32770
|
{
|
|
32365
32771
|
name: "tui",
|
|
32366
32772
|
argHint: "[view]",
|
|
@@ -32391,18 +32797,872 @@ function commandsHelp() {
|
|
|
32391
32797
|
return COMMAND_SPECS.map((s) => ` ${label(s).padEnd(width)}${s.summary}`).join("\n");
|
|
32392
32798
|
}
|
|
32393
32799
|
|
|
32394
|
-
// src/commands/
|
|
32395
|
-
import {
|
|
32396
|
-
import {
|
|
32800
|
+
// src/commands/attach.ts
|
|
32801
|
+
import { rmSync as rmSync7 } from "fs";
|
|
32802
|
+
import { join as join26 } from "path";
|
|
32803
|
+
|
|
32804
|
+
// ../packages/plugin-runtime/src/attached/forward-drops.ts
|
|
32805
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
32806
|
+
import { join as join21 } from "path";
|
|
32807
|
+
var FORWARD_DROPS_FILENAME = "attached-forward-drops.json";
|
|
32808
|
+
function forwardDropsPath(dataDir2) {
|
|
32809
|
+
return join21(dataDir2, FORWARD_DROPS_FILENAME);
|
|
32810
|
+
}
|
|
32811
|
+
function readForwardDrops(dataDir2) {
|
|
32812
|
+
try {
|
|
32813
|
+
const parsed2 = JSON.parse(readFileSync15(forwardDropsPath(dataDir2), "utf8"));
|
|
32814
|
+
if (typeof parsed2 !== "object" || parsed2 === null) return null;
|
|
32815
|
+
const record2 = parsed2;
|
|
32816
|
+
if (typeof record2.droppedForwards !== "number" || !Number.isFinite(record2.droppedForwards)) {
|
|
32817
|
+
return null;
|
|
32818
|
+
}
|
|
32819
|
+
if (record2.droppedForwards <= 0) return null;
|
|
32820
|
+
if (typeof record2.lastDropAtMs !== "number" || !Number.isFinite(record2.lastDropAtMs)) {
|
|
32821
|
+
return null;
|
|
32822
|
+
}
|
|
32823
|
+
return { droppedForwards: record2.droppedForwards, lastDropAtMs: record2.lastDropAtMs };
|
|
32824
|
+
} catch {
|
|
32825
|
+
return null;
|
|
32826
|
+
}
|
|
32827
|
+
}
|
|
32828
|
+
|
|
32829
|
+
// ../packages/plugin-runtime/src/attached/forward-policy.ts
|
|
32830
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
32831
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
32832
|
+
import { readFile, rename, writeFile } from "fs/promises";
|
|
32833
|
+
import { join as join22 } from "path";
|
|
32834
|
+
var FAILURES = /* @__PURE__ */ new Set([
|
|
32835
|
+
"unauthorized",
|
|
32836
|
+
"forbidden",
|
|
32837
|
+
"unreachable"
|
|
32838
|
+
]);
|
|
32839
|
+
var FORWARD_STATE_FILENAME = "attached-state.json";
|
|
32840
|
+
var STATE_FILENAME = FORWARD_STATE_FILENAME;
|
|
32841
|
+
function parseBreakerState(raw, nowMs) {
|
|
32842
|
+
try {
|
|
32843
|
+
const parsed2 = JSON.parse(raw);
|
|
32844
|
+
if (typeof parsed2 !== "object" || parsed2 === null) return null;
|
|
32845
|
+
const record2 = parsed2;
|
|
32846
|
+
const failures = typeof record2.consecutiveFailures === "number" && record2.consecutiveFailures >= 0 ? record2.consecutiveFailures : 0;
|
|
32847
|
+
const openedAtMs = typeof record2.openedAtMs === "number" && Number.isFinite(record2.openedAtMs) && record2.openedAtMs <= nowMs ? record2.openedAtMs : null;
|
|
32848
|
+
const lastFailure = typeof record2.lastFailure === "string" && FAILURES.has(record2.lastFailure) ? record2.lastFailure : null;
|
|
32849
|
+
return { consecutiveFailures: failures, openedAtMs, lastFailure };
|
|
32850
|
+
} catch {
|
|
32851
|
+
return null;
|
|
32852
|
+
}
|
|
32853
|
+
}
|
|
32854
|
+
function readForwardHealth(dir, nowMs = Date.now()) {
|
|
32855
|
+
try {
|
|
32856
|
+
return parseBreakerState(readFileSync16(join22(dir, STATE_FILENAME), "utf8"), nowMs);
|
|
32857
|
+
} catch {
|
|
32858
|
+
return null;
|
|
32859
|
+
}
|
|
32860
|
+
}
|
|
32861
|
+
|
|
32862
|
+
// ../packages/plugin-runtime/src/attached/policy-store.ts
|
|
32863
|
+
import { randomUUID as randomUUID17 } from "crypto";
|
|
32864
|
+
import { readFile as readFile2, rm, writeFile as writeFile2 } from "fs/promises";
|
|
32865
|
+
import { join as join23 } from "path";
|
|
32866
|
+
|
|
32867
|
+
// ../packages/plugin-runtime/src/attached/atomic-publish.ts
|
|
32868
|
+
import { rename as rename2 } from "fs/promises";
|
|
32869
|
+
var RETRYABLE = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
32870
|
+
var ATTEMPTS = 5;
|
|
32871
|
+
var delay = (ms) => new Promise((resolve6) => {
|
|
32872
|
+
setTimeout(resolve6, ms);
|
|
32873
|
+
});
|
|
32874
|
+
async function publishByRename(tmp, file2, move = rename2) {
|
|
32875
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
32876
|
+
try {
|
|
32877
|
+
await move(tmp, file2);
|
|
32878
|
+
return;
|
|
32879
|
+
} catch (err) {
|
|
32880
|
+
const code = err.code;
|
|
32881
|
+
if (attempt >= ATTEMPTS || code === void 0 || !RETRYABLE.has(code)) throw err;
|
|
32882
|
+
await delay(attempt * 10);
|
|
32883
|
+
}
|
|
32884
|
+
}
|
|
32885
|
+
}
|
|
32886
|
+
|
|
32887
|
+
// ../packages/plugin-runtime/src/attached/policy-store.ts
|
|
32888
|
+
function createPolicyStore(dir = dataDir()) {
|
|
32889
|
+
const file2 = join23(dir, "policy-cache.json");
|
|
32890
|
+
async function read() {
|
|
32891
|
+
try {
|
|
32892
|
+
const raw = await readFile2(file2, "utf8");
|
|
32893
|
+
const parsed2 = JSON.parse(raw);
|
|
32894
|
+
if (typeof parsed2 !== "object" || parsed2 === null) return null;
|
|
32895
|
+
const record2 = parsed2;
|
|
32896
|
+
const bundle = PolicyBundle.parse(record2.bundle);
|
|
32897
|
+
const fetchedAtMs = typeof record2.fetchedAtMs === "number" ? record2.fetchedAtMs : 0;
|
|
32898
|
+
const etag = typeof record2.etag === "string" ? record2.etag : void 0;
|
|
32899
|
+
return { bundle, fetchedAtMs, ...etag === void 0 ? {} : { etag } };
|
|
32900
|
+
} catch {
|
|
32901
|
+
return null;
|
|
32902
|
+
}
|
|
32903
|
+
}
|
|
32904
|
+
async function write(bundle, etag) {
|
|
32905
|
+
await ensureDataDir(dir);
|
|
32906
|
+
const stored = {
|
|
32907
|
+
bundle,
|
|
32908
|
+
fetchedAtMs: Date.now(),
|
|
32909
|
+
...etag === void 0 ? {} : { etag }
|
|
32910
|
+
};
|
|
32911
|
+
const tmp = `${file2}.${randomUUID17()}.tmp`;
|
|
32912
|
+
try {
|
|
32913
|
+
await writeFile2(tmp, JSON.stringify(stored), {
|
|
32914
|
+
encoding: "utf8",
|
|
32915
|
+
mode: DATA_FILE_MODE,
|
|
32916
|
+
flag: "wx"
|
|
32917
|
+
});
|
|
32918
|
+
await publishByRename(tmp, file2);
|
|
32919
|
+
} catch (err) {
|
|
32920
|
+
await rm(tmp, { force: true }).catch(() => void 0);
|
|
32921
|
+
throw err;
|
|
32922
|
+
}
|
|
32923
|
+
}
|
|
32924
|
+
return { read, write, file: file2 };
|
|
32925
|
+
}
|
|
32926
|
+
|
|
32927
|
+
// ../packages/remote/src/http.ts
|
|
32928
|
+
import { request as httpRequest } from "http";
|
|
32929
|
+
import { request as httpsRequest } from "https";
|
|
32930
|
+
var DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
32931
|
+
var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
32932
|
+
var RemoteRequestError = class extends Error {
|
|
32933
|
+
constructor(status) {
|
|
32934
|
+
super(`control-plane request failed with status ${String(status)}`);
|
|
32935
|
+
this.status = status;
|
|
32936
|
+
this.name = "RemoteRequestError";
|
|
32937
|
+
}
|
|
32938
|
+
status;
|
|
32939
|
+
};
|
|
32940
|
+
var RemoteRequestInvalid = class extends Error {
|
|
32941
|
+
constructor(route, cause) {
|
|
32942
|
+
super(`refusing to send a malformed body to ${route}`);
|
|
32943
|
+
this.cause = cause;
|
|
32944
|
+
this.name = "RemoteRequestInvalid";
|
|
32945
|
+
}
|
|
32946
|
+
cause;
|
|
32947
|
+
};
|
|
32948
|
+
var RemoteResponseInvalid = class extends Error {
|
|
32949
|
+
constructor(route, detail) {
|
|
32950
|
+
super(`control plane answered ${route} with ${detail}`);
|
|
32951
|
+
this.name = "RemoteResponseInvalid";
|
|
32952
|
+
}
|
|
32953
|
+
};
|
|
32954
|
+
var RemoteTransportError = class extends Error {
|
|
32955
|
+
/**
|
|
32956
|
+
* The status the peer sent, when headers arrived and only the BODY was
|
|
32957
|
+
* refused.
|
|
32958
|
+
*
|
|
32959
|
+
* Undefined for the ordinary case this class was written for — no answer at
|
|
32960
|
+
* all. It exists because two paths reject after a status has already been
|
|
32961
|
+
* delivered: an oversized body and an aborted response. Discarding it there
|
|
32962
|
+
* reported a deployment answering 401 with a verbose body as a network
|
|
32963
|
+
* outage, which sends the reader to look at their network instead of their
|
|
32964
|
+
* credential.
|
|
32965
|
+
*/
|
|
32966
|
+
constructor(reason, status) {
|
|
32967
|
+
super(`control-plane request did not complete: ${reason}`);
|
|
32968
|
+
this.status = status;
|
|
32969
|
+
this.name = "RemoteTransportError";
|
|
32970
|
+
}
|
|
32971
|
+
status;
|
|
32972
|
+
};
|
|
32973
|
+
async function send(options) {
|
|
32974
|
+
const url2 = new URL(options.url);
|
|
32975
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
32976
|
+
const send_ = url2.protocol === "http:" ? httpRequest : httpsRequest;
|
|
32977
|
+
const requestOptions = {
|
|
32978
|
+
method: options.method,
|
|
32979
|
+
headers: {
|
|
32980
|
+
// CALLER HEADERS FIRST, so this module's own are not overridable. Spread
|
|
32981
|
+
// last they win, and two of the values below are ones no caller may
|
|
32982
|
+
// replace: `x-api-key` is the credential, and `content-length` is the
|
|
32983
|
+
// byte count that stops a multi-byte body being truncated by the
|
|
32984
|
+
// receiver. `SendOptions.headers` is a free-form record on an exported
|
|
32985
|
+
// function, so "no caller does that today" is not the guarantee to rely
|
|
32986
|
+
// on. The one header any caller actually passes — `if-none-match` on the
|
|
32987
|
+
// conditional GET — is untouched by this order.
|
|
32988
|
+
...options.headers,
|
|
32989
|
+
// The credential. One header, matching what the deployment authenticates
|
|
32990
|
+
// on; a second copy in an `Authorization` header would be one more place
|
|
32991
|
+
// it can be logged by an intermediary for no gain.
|
|
32992
|
+
"x-api-key": options.apiKey,
|
|
32993
|
+
accept: "application/json",
|
|
32994
|
+
...options.body === void 0 ? {} : {
|
|
32995
|
+
"content-type": "application/json",
|
|
32996
|
+
// Byte length, not string length: a multi-byte body sent with a
|
|
32997
|
+
// character count is truncated by the receiver.
|
|
32998
|
+
"content-length": String(Buffer.byteLength(options.body))
|
|
32999
|
+
}
|
|
33000
|
+
}
|
|
33001
|
+
};
|
|
33002
|
+
return new Promise((resolve6, reject) => {
|
|
33003
|
+
let settled = false;
|
|
33004
|
+
const fail = (reason, status) => {
|
|
33005
|
+
if (settled) return;
|
|
33006
|
+
settled = true;
|
|
33007
|
+
reject(new RemoteTransportError(reason, status));
|
|
33008
|
+
};
|
|
33009
|
+
const req = send_(url2, requestOptions, (res) => {
|
|
33010
|
+
const chunks = [];
|
|
33011
|
+
let size = 0;
|
|
33012
|
+
res.on("data", (chunk) => {
|
|
33013
|
+
size += chunk.length;
|
|
33014
|
+
if (size > MAX_RESPONSE_BYTES) {
|
|
33015
|
+
fail(`response exceeded ${String(MAX_RESPONSE_BYTES)} bytes`, res.statusCode);
|
|
33016
|
+
res.destroy();
|
|
33017
|
+
req.destroy();
|
|
33018
|
+
return;
|
|
33019
|
+
}
|
|
33020
|
+
chunks.push(chunk);
|
|
33021
|
+
});
|
|
33022
|
+
res.on("aborted", () => {
|
|
33023
|
+
fail("the response was aborted", res.statusCode);
|
|
33024
|
+
});
|
|
33025
|
+
res.on("end", () => {
|
|
33026
|
+
if (settled) return;
|
|
33027
|
+
settled = true;
|
|
33028
|
+
resolve6({
|
|
33029
|
+
status: res.statusCode ?? 0,
|
|
33030
|
+
headers: res.headers,
|
|
33031
|
+
body: Buffer.concat(chunks).toString("utf8")
|
|
33032
|
+
});
|
|
33033
|
+
});
|
|
33034
|
+
});
|
|
33035
|
+
const deadline = setTimeout(() => {
|
|
33036
|
+
fail(`no response within ${String(timeoutMs)}ms`);
|
|
33037
|
+
req.destroy();
|
|
33038
|
+
}, timeoutMs);
|
|
33039
|
+
deadline.unref();
|
|
33040
|
+
req.on("upgrade", (_res, socket) => {
|
|
33041
|
+
fail("the deployment answered with a protocol upgrade");
|
|
33042
|
+
socket.destroy();
|
|
33043
|
+
});
|
|
33044
|
+
req.on("close", () => {
|
|
33045
|
+
fail("the connection closed before a response was read");
|
|
33046
|
+
clearTimeout(deadline);
|
|
33047
|
+
});
|
|
33048
|
+
req.on("error", (err) => {
|
|
33049
|
+
fail(err.message);
|
|
33050
|
+
});
|
|
33051
|
+
if (options.body !== void 0) req.write(options.body);
|
|
33052
|
+
req.end();
|
|
33053
|
+
});
|
|
33054
|
+
}
|
|
33055
|
+
|
|
33056
|
+
// ../packages/remote/src/client.ts
|
|
33057
|
+
var ROUTES = {
|
|
33058
|
+
events: "/v1/events",
|
|
33059
|
+
auditEvents: "/v1/audit-events",
|
|
33060
|
+
inventory: "/v1/inventory",
|
|
33061
|
+
storePosture: "/v1/store-posture",
|
|
33062
|
+
policyBundle: "/v1/policy-bundle",
|
|
33063
|
+
whoami: "/v1/plugin/whoami"
|
|
33064
|
+
};
|
|
33065
|
+
function headerValue(response, name) {
|
|
33066
|
+
const raw = response.headers[name];
|
|
33067
|
+
if (raw === void 0) return void 0;
|
|
33068
|
+
return Array.isArray(raw) ? raw[0] : raw;
|
|
33069
|
+
}
|
|
33070
|
+
function okBody(response) {
|
|
33071
|
+
if (response.status < 200 || response.status >= 300) {
|
|
33072
|
+
throw new RemoteRequestError(response.status);
|
|
33073
|
+
}
|
|
33074
|
+
return response.body;
|
|
33075
|
+
}
|
|
33076
|
+
function parsed(schema, body, route) {
|
|
33077
|
+
let json2;
|
|
33078
|
+
try {
|
|
33079
|
+
json2 = JSON.parse(body);
|
|
33080
|
+
} catch {
|
|
33081
|
+
throw new RemoteResponseInvalid(route, "a body that is not JSON");
|
|
33082
|
+
}
|
|
33083
|
+
const result = schema.safeParse(json2);
|
|
33084
|
+
if (!result.success) {
|
|
33085
|
+
throw new RemoteResponseInvalid(route, "a body this client cannot read");
|
|
33086
|
+
}
|
|
33087
|
+
return result.data;
|
|
33088
|
+
}
|
|
33089
|
+
function withoutTrailingSlashes(endpoint) {
|
|
33090
|
+
let end = endpoint.length;
|
|
33091
|
+
while (end > 0 && endpoint.charCodeAt(end - 1) === SLASH) end -= 1;
|
|
33092
|
+
return endpoint.slice(0, end);
|
|
33093
|
+
}
|
|
33094
|
+
var SLASH = "/".charCodeAt(0);
|
|
33095
|
+
function createRemoteClient(options) {
|
|
33096
|
+
const base = withoutTrailingSlashes(options.endpoint);
|
|
33097
|
+
const url2 = (route) => `${base}${route}`;
|
|
33098
|
+
const common = { apiKey: options.apiKey, timeoutMs: options.timeoutMs };
|
|
33099
|
+
return {
|
|
33100
|
+
async ingestEvents(batch) {
|
|
33101
|
+
const response = await send({
|
|
33102
|
+
...common,
|
|
33103
|
+
method: "POST",
|
|
33104
|
+
url: url2(ROUTES.events),
|
|
33105
|
+
body: JSON.stringify(batch)
|
|
33106
|
+
});
|
|
33107
|
+
return parsed(IngestAck, okBody(response), ROUTES.events);
|
|
33108
|
+
},
|
|
33109
|
+
async ingestInventory(context) {
|
|
33110
|
+
const response = await send({
|
|
33111
|
+
...common,
|
|
33112
|
+
method: "POST",
|
|
33113
|
+
url: url2(ROUTES.inventory),
|
|
33114
|
+
body: JSON.stringify(context)
|
|
33115
|
+
});
|
|
33116
|
+
return parsed(ResolvedInventory, okBody(response), ROUTES.inventory);
|
|
33117
|
+
},
|
|
33118
|
+
async recordAuditEvent(event) {
|
|
33119
|
+
const validated = RecordAuditEventRequest.safeParse(event);
|
|
33120
|
+
if (!validated.success) throw new RemoteRequestInvalid(ROUTES.auditEvents, validated.error);
|
|
33121
|
+
const submission = validated.data;
|
|
33122
|
+
const response = await send({
|
|
33123
|
+
...common,
|
|
33124
|
+
method: "POST",
|
|
33125
|
+
url: url2(ROUTES.auditEvents),
|
|
33126
|
+
body: JSON.stringify(submission)
|
|
33127
|
+
});
|
|
33128
|
+
okBody(response);
|
|
33129
|
+
},
|
|
33130
|
+
async reportStorePosture(snapshot) {
|
|
33131
|
+
const response = await send({
|
|
33132
|
+
...common,
|
|
33133
|
+
method: "POST",
|
|
33134
|
+
url: url2(ROUTES.storePosture),
|
|
33135
|
+
body: JSON.stringify(snapshot)
|
|
33136
|
+
});
|
|
33137
|
+
okBody(response);
|
|
33138
|
+
},
|
|
33139
|
+
async getPolicyBundle(etag) {
|
|
33140
|
+
const response = await send({
|
|
33141
|
+
...common,
|
|
33142
|
+
method: "GET",
|
|
33143
|
+
url: url2(ROUTES.policyBundle),
|
|
33144
|
+
...etag === void 0 ? {} : { headers: { "if-none-match": etag } }
|
|
33145
|
+
});
|
|
33146
|
+
if (response.status === 304) {
|
|
33147
|
+
return { changed: false, etag: headerValue(response, "etag") ?? etag };
|
|
33148
|
+
}
|
|
33149
|
+
const bundle = parsed(PolicyBundle, okBody(response), ROUTES.policyBundle);
|
|
33150
|
+
return { changed: true, bundle, etag: headerValue(response, "etag") };
|
|
33151
|
+
},
|
|
33152
|
+
async whoami() {
|
|
33153
|
+
const response = await send({ ...common, method: "GET", url: url2(ROUTES.whoami) });
|
|
33154
|
+
return parsed(PluginWhoami, okBody(response), ROUTES.whoami);
|
|
33155
|
+
}
|
|
33156
|
+
};
|
|
33157
|
+
}
|
|
33158
|
+
|
|
33159
|
+
// ../packages/plugin-runtime/src/attached/posture-reporter.ts
|
|
33160
|
+
var POSTURE_REPORT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
33161
|
+
|
|
33162
|
+
// ../packages/plugin-runtime/src/attached/posture-snapshot.ts
|
|
33163
|
+
import { statSync as statSync12 } from "fs";
|
|
33164
|
+
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
33165
|
+
|
|
33166
|
+
// ../packages/plugin-runtime/src/attached/posture-store.ts
|
|
33167
|
+
import { randomUUID as randomUUID18 } from "crypto";
|
|
33168
|
+
import { readFile as readFile3, rm as rm2, writeFile as writeFile3 } from "fs/promises";
|
|
33169
|
+
import { join as join24 } from "path";
|
|
33170
|
+
|
|
33171
|
+
// ../packages/plugin-runtime/src/attached/sync-state.ts
|
|
33172
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
33173
|
+
import { join as join25 } from "path";
|
|
33174
|
+
var SYNC_STATE_FILENAME = "attached-sync-state.json";
|
|
33175
|
+
var OUTCOMES = /* @__PURE__ */ new Set([
|
|
33176
|
+
"ok",
|
|
33177
|
+
"not-modified",
|
|
33178
|
+
"unauthorized",
|
|
33179
|
+
"forbidden",
|
|
33180
|
+
"unreachable",
|
|
33181
|
+
"invalid-bundle"
|
|
33182
|
+
]);
|
|
33183
|
+
function syncStatePath(dataDir2) {
|
|
33184
|
+
return join25(dataDir2, SYNC_STATE_FILENAME);
|
|
33185
|
+
}
|
|
33186
|
+
function readSyncState(dataDir2) {
|
|
33187
|
+
try {
|
|
33188
|
+
const parsed2 = JSON.parse(readFileSync17(syncStatePath(dataDir2), "utf8"));
|
|
33189
|
+
if (typeof parsed2 !== "object" || parsed2 === null) return null;
|
|
33190
|
+
const record2 = parsed2;
|
|
33191
|
+
if (typeof record2.outcome !== "string" || !OUTCOMES.has(record2.outcome)) return null;
|
|
33192
|
+
if (typeof record2.atMs !== "number") return null;
|
|
33193
|
+
return { outcome: record2.outcome, atMs: record2.atMs };
|
|
33194
|
+
} catch {
|
|
33195
|
+
return null;
|
|
33196
|
+
}
|
|
33197
|
+
}
|
|
33198
|
+
|
|
33199
|
+
// ../packages/plugin-runtime/src/attached/status.ts
|
|
33200
|
+
var REFUSAL_LINES = {
|
|
33201
|
+
unauthorized: "KEY REJECTED \u2014 re-attach with a valid plugin key",
|
|
33202
|
+
forbidden: "ACCESS REFUSED \u2014 key is valid but not permitted; ask your org admin"
|
|
33203
|
+
};
|
|
33204
|
+
var OUTCOME_LINES = {
|
|
33205
|
+
ok: "policy synced",
|
|
33206
|
+
"not-modified": "policy up to date",
|
|
33207
|
+
unauthorized: REFUSAL_LINES.unauthorized,
|
|
33208
|
+
forbidden: REFUSAL_LINES.forbidden,
|
|
33209
|
+
unreachable: "control plane unreachable at last attempt",
|
|
33210
|
+
"invalid-bundle": "control plane sent a policy bundle this build cannot read"
|
|
33211
|
+
};
|
|
33212
|
+
function ageLine(fromMs, nowMs) {
|
|
33213
|
+
const deltaMs = Math.max(0, nowMs - fromMs);
|
|
33214
|
+
const minutes = Math.floor(deltaMs / 6e4);
|
|
33215
|
+
if (minutes < 1) return "just now";
|
|
33216
|
+
if (minutes < 60) return `${String(minutes)}m ago`;
|
|
33217
|
+
const hours = Math.floor(minutes / 60);
|
|
33218
|
+
if (hours < 24) return `${String(hours)}h ago`;
|
|
33219
|
+
return `${String(Math.floor(hours / 24))}d ago`;
|
|
33220
|
+
}
|
|
33221
|
+
function renderAttachedStatus(deps) {
|
|
33222
|
+
try {
|
|
33223
|
+
const nowMs = (deps.now ?? (() => Date.now()))();
|
|
33224
|
+
const settings = readWorkspaceSettings(deps.base);
|
|
33225
|
+
if (!isAttached(settings) || settings.controlPlane === void 0) {
|
|
33226
|
+
return ["AKA: standalone (not attached)", " no control plane configured"].join("\n");
|
|
33227
|
+
}
|
|
33228
|
+
const connection = settings.controlPlane;
|
|
33229
|
+
const state = readControlPlaneCredentialState(deps.settingsDir, connection);
|
|
33230
|
+
const lines = [
|
|
33231
|
+
// The mismatch case earns its own headline. An administrator can repoint
|
|
33232
|
+
// `controlPlane` across a fleet and cannot write the credential file, so
|
|
33233
|
+
// this is an ordinary migration rather than a fault — and reporting it as
|
|
33234
|
+
// a bare "not attached" would send every affected user looking for a file
|
|
33235
|
+
// that is present and intact.
|
|
33236
|
+
state.usable ? "AKA: attached" : state.reason === "endpoint-mismatch" ? "AKA: attached \u2014 credential is for another deployment, re-attach" : "AKA: attached \u2014 no usable credential, re-attach",
|
|
33237
|
+
// ALLOW-LISTED, field by field. The credential itself is deliberately
|
|
33238
|
+
// absent and must stay that way; `keyPrefix` is the non-secret half.
|
|
33239
|
+
//
|
|
33240
|
+
// And every one of them goes through `printable`, which is about the
|
|
33241
|
+
// field's CONTENT rather than which fields appear. The allow-list above
|
|
33242
|
+
// decides what is rendered; it says nothing about what those strings
|
|
33243
|
+
// hold. None of these is authored by this machine — `label` comes from
|
|
33244
|
+
// `aka attach --label` or from a `settings.json` an administrator can pin
|
|
33245
|
+
// fleet-wide, and the endpoint and `keyPrefix` come off the credential
|
|
33246
|
+
// file — and all of them land in a status block a user reads to decide
|
|
33247
|
+
// whether their machine is managed. An ANSI escape in any of them can
|
|
33248
|
+
// repaint that block or hide a line, which is the same argument
|
|
33249
|
+
// `printable` was written for one field over.
|
|
33250
|
+
` plane ${printable2(controlPlaneName(connection))}`,
|
|
33251
|
+
` attached ${printable2(connection.attachedAt, 40)}`
|
|
33252
|
+
];
|
|
33253
|
+
if (state.usable && state.credential.keyPrefix !== void 0) {
|
|
33254
|
+
lines.push(` key ${printable2(state.credential.keyPrefix, 16)}\u2026`);
|
|
33255
|
+
}
|
|
33256
|
+
if (!state.usable && state.reason === "endpoint-mismatch") {
|
|
33257
|
+
lines.push(` credential ${printable2(state.credentialEndpoint, 200)}`);
|
|
33258
|
+
}
|
|
33259
|
+
return [
|
|
33260
|
+
...lines,
|
|
33261
|
+
...policyLines(deps.dataDir, nowMs),
|
|
33262
|
+
...forwardLines(deps.dataDir, nowMs)
|
|
33263
|
+
].join("\n");
|
|
33264
|
+
} catch {
|
|
33265
|
+
return "AKA: status unavailable";
|
|
33266
|
+
}
|
|
33267
|
+
}
|
|
33268
|
+
function policyLines(dataDir2, nowMs) {
|
|
33269
|
+
const lines = [];
|
|
33270
|
+
const state = readSyncState(dataDir2);
|
|
33271
|
+
if (state) {
|
|
33272
|
+
lines.push(` sync ${OUTCOME_LINES[state.outcome]} (${ageLine(state.atMs, nowMs)})`);
|
|
33273
|
+
} else {
|
|
33274
|
+
lines.push(" sync no attempt recorded yet");
|
|
33275
|
+
}
|
|
33276
|
+
return lines;
|
|
33277
|
+
}
|
|
33278
|
+
function dropLines(dataDir2, nowMs) {
|
|
33279
|
+
const drops = readForwardDrops(dataDir2);
|
|
33280
|
+
if (!drops) return [];
|
|
33281
|
+
return [
|
|
33282
|
+
` at least ${String(drops.droppedForwards)} events dropped past the batch budget, last ${ageLine(drops.lastDropAtMs, nowMs)}`
|
|
33283
|
+
];
|
|
33284
|
+
}
|
|
33285
|
+
function forwardLines(dataDir2, nowMs) {
|
|
33286
|
+
const drops = dropLines(dataDir2, nowMs);
|
|
33287
|
+
const health = readForwardHealth(dataDir2, nowMs);
|
|
33288
|
+
if (!health) return [" forward no failures recorded", ...drops];
|
|
33289
|
+
const { consecutiveFailures, openedAtMs, lastFailure } = health;
|
|
33290
|
+
if (openedAtMs === null && consecutiveFailures === 0) {
|
|
33291
|
+
return [" forward reporting normally", ...drops];
|
|
33292
|
+
}
|
|
33293
|
+
const lines = openedAtMs !== null ? (
|
|
33294
|
+
// `openedAtMs` is re-stamped on every half-open probe, so the gap to now
|
|
33295
|
+
// is bounded by one cooldown however long the control plane has been down — it
|
|
33296
|
+
// dates the last ATTEMPT, never the outage. The failure count is the
|
|
33297
|
+
// part that grows, so that is the number shown as the magnitude.
|
|
33298
|
+
[
|
|
33299
|
+
` forward NOT REPORTING \u2014 ${String(consecutiveFailures)} consecutive failures, last tried ${ageLine(openedAtMs, nowMs)}`
|
|
33300
|
+
]
|
|
33301
|
+
) : (
|
|
33302
|
+
// Closed but non-zero: failing without having reached the threshold yet.
|
|
33303
|
+
[` forward ${String(consecutiveFailures)} failures since the last success`]
|
|
33304
|
+
);
|
|
33305
|
+
if (lastFailure === "unauthorized" || lastFailure === "forbidden") {
|
|
33306
|
+
lines.push(` ${REFUSAL_LINES[lastFailure]}`);
|
|
33307
|
+
}
|
|
33308
|
+
return [...lines, ...drops];
|
|
33309
|
+
}
|
|
33310
|
+
function printable2(value, max = 80) {
|
|
33311
|
+
const stripped = value.replace(/[\p{Cc}\p{Cf}]/gu, "");
|
|
33312
|
+
return stripped.length > max ? `${stripped.slice(0, max)}\u2026` : stripped;
|
|
33313
|
+
}
|
|
33314
|
+
async function renderPolicyLine(dataDir2, nowMs = Date.now()) {
|
|
33315
|
+
try {
|
|
33316
|
+
const cached2 = await createPolicyStore(dataDir2).read();
|
|
33317
|
+
if (!cached2) return " policy none cached";
|
|
33318
|
+
return ` policy ${printable2(cached2.bundle.version)} (fetched ${ageLine(cached2.fetchedAtMs, nowMs)})`;
|
|
33319
|
+
} catch {
|
|
33320
|
+
return " policy unreadable";
|
|
33321
|
+
}
|
|
33322
|
+
}
|
|
33323
|
+
|
|
33324
|
+
// ../packages/plugin-runtime/src/attached/sync-trigger.ts
|
|
33325
|
+
import { spawn as spawn2 } from "child_process";
|
|
33326
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
33327
|
+
var SYNC_THROTTLE_MS = 15 * 60 * 1e3;
|
|
33328
|
+
|
|
33329
|
+
// ../packages/plugin-runtime/src/attached/factory.ts
|
|
33330
|
+
import { hostname as hostname5 } from "os";
|
|
33331
|
+
|
|
33332
|
+
// ../packages/plugin-runtime/src/standalone-gateway.ts
|
|
33333
|
+
import { randomUUID as randomUUID19 } from "crypto";
|
|
33334
|
+
|
|
33335
|
+
// ../packages/plugin-runtime/src/handle-session-start.ts
|
|
33336
|
+
import { randomUUID as randomUUID20 } from "crypto";
|
|
33337
|
+
var EXCEPTION_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
32397
33338
|
|
|
32398
33339
|
// src/lib/args.ts
|
|
32399
|
-
import { resolve as
|
|
33340
|
+
import { resolve as resolve5 } from "path";
|
|
32400
33341
|
var HOME_OPTION = { home: { type: "string" } };
|
|
32401
33342
|
function homeBase(home) {
|
|
32402
|
-
return home === void 0 ? defaultDataDir() :
|
|
33343
|
+
return home === void 0 ? defaultDataDir() : resolve5(home);
|
|
33344
|
+
}
|
|
33345
|
+
|
|
33346
|
+
// src/lib/prompter.ts
|
|
33347
|
+
import { createInterface } from "readline";
|
|
33348
|
+
function processHiddenChar(state, ch) {
|
|
33349
|
+
if (state.done) return state;
|
|
33350
|
+
if (state.esc === "esc") {
|
|
33351
|
+
return ch === "[" || ch === "O" ? { ...state, esc: "seq" } : { ...state, esc: "none" };
|
|
33352
|
+
}
|
|
33353
|
+
if (state.esc === "seq") {
|
|
33354
|
+
return ch >= "@" && ch <= "~" ? { ...state, esc: "none" } : state;
|
|
33355
|
+
}
|
|
33356
|
+
if (ch === "\r" || ch === "\n") return { ...state, done: "submit" };
|
|
33357
|
+
if (ch === "") return { ...state, done: "cancel" };
|
|
33358
|
+
if (ch === "\x7F" || ch === "\b") return { ...state, value: state.value.slice(0, -1) };
|
|
33359
|
+
if (ch === "\x1B") return { ...state, esc: "esc" };
|
|
33360
|
+
if (ch < " ") return state;
|
|
33361
|
+
return { ...state, value: state.value + ch };
|
|
33362
|
+
}
|
|
33363
|
+
var CLEANUP_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
33364
|
+
function processIo() {
|
|
33365
|
+
return {
|
|
33366
|
+
input: process.stdin,
|
|
33367
|
+
output: process.stdout,
|
|
33368
|
+
errorOutput: process.stderr,
|
|
33369
|
+
signals: {
|
|
33370
|
+
once: (signal, handler) => {
|
|
33371
|
+
process.once(signal, handler);
|
|
33372
|
+
},
|
|
33373
|
+
off: (signal, handler) => {
|
|
33374
|
+
process.removeListener(signal, handler);
|
|
33375
|
+
},
|
|
33376
|
+
raise: (signal) => {
|
|
33377
|
+
process.kill(process.pid, signal);
|
|
33378
|
+
}
|
|
33379
|
+
}
|
|
33380
|
+
};
|
|
33381
|
+
}
|
|
33382
|
+
function terminalPrompter(io = processIo()) {
|
|
33383
|
+
return {
|
|
33384
|
+
out: (text) => {
|
|
33385
|
+
io.output.write(text);
|
|
33386
|
+
},
|
|
33387
|
+
err: (text) => {
|
|
33388
|
+
io.errorOutput.write(text);
|
|
33389
|
+
},
|
|
33390
|
+
isInteractive: io.input.isTTY && io.output.isTTY,
|
|
33391
|
+
ask(question) {
|
|
33392
|
+
return new Promise((resolve6) => {
|
|
33393
|
+
const rl = createInterface({ input: io.input, output: io.output });
|
|
33394
|
+
rl.question(question, (answer) => {
|
|
33395
|
+
rl.close();
|
|
33396
|
+
resolve6(answer);
|
|
33397
|
+
});
|
|
33398
|
+
});
|
|
33399
|
+
},
|
|
33400
|
+
// Raw mode so nothing is echoed; characters are folded through
|
|
33401
|
+
// processHiddenChar. The captured value stays in this closure and is
|
|
33402
|
+
// handed to the caller only — never written anywhere. TTY restoration is
|
|
33403
|
+
// guaranteed via a one-shot `restore` that also runs on stdin errors and
|
|
33404
|
+
// fatal signals: a security tool must never brick the terminal it was
|
|
33405
|
+
// invoked from.
|
|
33406
|
+
askHidden(question) {
|
|
33407
|
+
return new Promise((resolve6, reject) => {
|
|
33408
|
+
const stdin = io.input;
|
|
33409
|
+
io.output.write(question);
|
|
33410
|
+
stdin.setRawMode(true);
|
|
33411
|
+
stdin.resume();
|
|
33412
|
+
let state = { value: "", esc: "none" };
|
|
33413
|
+
let restored = false;
|
|
33414
|
+
const restore = () => {
|
|
33415
|
+
if (restored) return;
|
|
33416
|
+
restored = true;
|
|
33417
|
+
stdin.removeListener("data", onData);
|
|
33418
|
+
stdin.removeListener("error", onError);
|
|
33419
|
+
for (const sig of CLEANUP_SIGNALS) io.signals.off(sig, onSignal);
|
|
33420
|
+
try {
|
|
33421
|
+
stdin.setRawMode(false);
|
|
33422
|
+
} catch {
|
|
33423
|
+
}
|
|
33424
|
+
stdin.pause();
|
|
33425
|
+
};
|
|
33426
|
+
const finish = (err) => {
|
|
33427
|
+
restore();
|
|
33428
|
+
io.output.write("\n");
|
|
33429
|
+
if (err) reject(err);
|
|
33430
|
+
else resolve6(state.value);
|
|
33431
|
+
};
|
|
33432
|
+
const onError = (err) => {
|
|
33433
|
+
finish(err);
|
|
33434
|
+
};
|
|
33435
|
+
const onSignal = (sig) => {
|
|
33436
|
+
restore();
|
|
33437
|
+
io.signals.raise(sig);
|
|
33438
|
+
};
|
|
33439
|
+
const onData = (chunk) => {
|
|
33440
|
+
try {
|
|
33441
|
+
for (const ch of chunk.toString("utf8")) {
|
|
33442
|
+
state = processHiddenChar(state, ch);
|
|
33443
|
+
if (state.done === "submit") {
|
|
33444
|
+
finish();
|
|
33445
|
+
return;
|
|
33446
|
+
}
|
|
33447
|
+
if (state.done === "cancel") {
|
|
33448
|
+
finish(new Error("cancelled"));
|
|
33449
|
+
return;
|
|
33450
|
+
}
|
|
33451
|
+
}
|
|
33452
|
+
} catch (err) {
|
|
33453
|
+
finish(err instanceof Error ? err : new Error(String(err)));
|
|
33454
|
+
}
|
|
33455
|
+
};
|
|
33456
|
+
stdin.on("data", onData);
|
|
33457
|
+
stdin.once("error", onError);
|
|
33458
|
+
for (const sig of CLEANUP_SIGNALS) io.signals.once(sig, onSignal);
|
|
33459
|
+
});
|
|
33460
|
+
},
|
|
33461
|
+
async readAllStdin() {
|
|
33462
|
+
const chunks = [];
|
|
33463
|
+
for await (const chunk of io.input) {
|
|
33464
|
+
chunks.push(chunk);
|
|
33465
|
+
}
|
|
33466
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
33467
|
+
}
|
|
33468
|
+
};
|
|
33469
|
+
}
|
|
33470
|
+
|
|
33471
|
+
// src/commands/attach.ts
|
|
33472
|
+
var POLICY_CACHE_FILENAME = "policy-cache.json";
|
|
33473
|
+
var USAGE = `Usage: aka attach --url <https-url> [--label <name>] [--key-stdin]
|
|
33474
|
+
|
|
33475
|
+
Registers this machine against your organization's AKA deployment.
|
|
33476
|
+
|
|
33477
|
+
--url <url> Where the deployment lives. https, or http on loopback.
|
|
33478
|
+
--label <name> What to call it on screen. Defaults to the URL.
|
|
33479
|
+
--key-stdin Read the access key from stdin instead of prompting.
|
|
33480
|
+
--home <dir> Use an alternate AKA home instead of ~/.aka.
|
|
33481
|
+
|
|
33482
|
+
The key is never accepted as a command-line argument \u2014 it would be visible to
|
|
33483
|
+
every process on this machine and recorded in your shell history.`;
|
|
33484
|
+
function parseAttachArgs(argv) {
|
|
33485
|
+
const parsed2 = { keyStdin: false };
|
|
33486
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
33487
|
+
const arg = argv[i];
|
|
33488
|
+
if (arg === "--key" || arg?.startsWith("--key=")) {
|
|
33489
|
+
return {
|
|
33490
|
+
error: "aka attach does not take --key: a key on the command line is visible to every process on this machine and is written to your shell history. Run without it to be prompted, or pipe the key in with --key-stdin."
|
|
33491
|
+
};
|
|
33492
|
+
}
|
|
33493
|
+
if (arg === "--key-stdin") {
|
|
33494
|
+
parsed2.keyStdin = true;
|
|
33495
|
+
} else if (arg === "--url") {
|
|
33496
|
+
parsed2.url = argv[++i];
|
|
33497
|
+
} else if (arg?.startsWith("--url=")) {
|
|
33498
|
+
parsed2.url = arg.slice("--url=".length);
|
|
33499
|
+
} else if (arg === "--label") {
|
|
33500
|
+
parsed2.label = argv[++i];
|
|
33501
|
+
} else if (arg?.startsWith("--label=")) {
|
|
33502
|
+
parsed2.label = arg.slice("--label=".length);
|
|
33503
|
+
} else if (arg === "--home") {
|
|
33504
|
+
parsed2.home = argv[++i];
|
|
33505
|
+
} else if (arg?.startsWith("--home=")) {
|
|
33506
|
+
parsed2.home = arg.slice("--home=".length);
|
|
33507
|
+
} else {
|
|
33508
|
+
return { error: `unknown option ${String(arg)}` };
|
|
33509
|
+
}
|
|
33510
|
+
}
|
|
33511
|
+
if (parsed2.label !== void 0 && CONTROL_CHARS.test(parsed2.label)) {
|
|
33512
|
+
return {
|
|
33513
|
+
error: "aka attach does not take a --label containing control characters. The label is printed into `aka status`, which a user reads to decide whether their machine is managed, and an escape sequence there can repaint or hide lines of that block."
|
|
33514
|
+
};
|
|
33515
|
+
}
|
|
33516
|
+
return parsed2;
|
|
33517
|
+
}
|
|
33518
|
+
var CONTROL_CHARS = /[\p{Cc}\p{Cf}]/u;
|
|
33519
|
+
var isError = (v) => "error" in v;
|
|
33520
|
+
async function runAttach(argv, deps = {}) {
|
|
33521
|
+
const io = deps.prompter ?? terminalPrompter();
|
|
33522
|
+
const exit = deps.exit ?? ((code) => process.exit(code));
|
|
33523
|
+
const args = parseAttachArgs(argv);
|
|
33524
|
+
if (isError(args)) {
|
|
33525
|
+
io.err(`${args.error}
|
|
33526
|
+
|
|
33527
|
+
${USAGE}`);
|
|
33528
|
+
exit(2);
|
|
33529
|
+
return;
|
|
33530
|
+
}
|
|
33531
|
+
const base = deps.base ?? homeBase(args.home);
|
|
33532
|
+
const endpoint = args.url;
|
|
33533
|
+
if (endpoint === void 0 || endpoint === "") {
|
|
33534
|
+
io.err(USAGE);
|
|
33535
|
+
exit(2);
|
|
33536
|
+
return;
|
|
33537
|
+
}
|
|
33538
|
+
if (!isSafeEndpoint(endpoint)) {
|
|
33539
|
+
io.err(
|
|
33540
|
+
`refusing to attach to ${endpoint}: an access key must not travel in the clear. Use an https URL (http is accepted only for a loopback deployment).`
|
|
33541
|
+
);
|
|
33542
|
+
exit(2);
|
|
33543
|
+
return;
|
|
33544
|
+
}
|
|
33545
|
+
const apiKey = (args.keyStdin ? (await io.readAllStdin()).trim() : io.isInteractive ? (await io.askHidden("Access key (input hidden): ")).trim() : "").trim();
|
|
33546
|
+
if (apiKey === "") {
|
|
33547
|
+
io.err(
|
|
33548
|
+
io.isInteractive || args.keyStdin ? "no access key was provided; nothing was changed." : "no terminal to prompt on. Pipe the key in with --key-stdin."
|
|
33549
|
+
);
|
|
33550
|
+
exit(2);
|
|
33551
|
+
return;
|
|
33552
|
+
}
|
|
33553
|
+
let identity;
|
|
33554
|
+
try {
|
|
33555
|
+
identity = await (deps.verify ?? verifyWithControlPlane)(endpoint, apiKey);
|
|
33556
|
+
} catch {
|
|
33557
|
+
io.err(
|
|
33558
|
+
`could not verify that key against ${endpoint}. Nothing was changed \u2014 check the URL and that the key has not been revoked.`
|
|
33559
|
+
);
|
|
33560
|
+
exit(1);
|
|
33561
|
+
return;
|
|
33562
|
+
}
|
|
33563
|
+
const previous = readControlPlaneCredentialState(settingsDir(base));
|
|
33564
|
+
try {
|
|
33565
|
+
writeControlPlaneCredential(settingsDir(base), {
|
|
33566
|
+
specVersion: 1,
|
|
33567
|
+
endpoint,
|
|
33568
|
+
apiKey,
|
|
33569
|
+
mintedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
33570
|
+
});
|
|
33571
|
+
applyOnboarding(
|
|
33572
|
+
{
|
|
33573
|
+
runMode: "attached",
|
|
33574
|
+
controlPlane: {
|
|
33575
|
+
endpoint,
|
|
33576
|
+
attachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33577
|
+
...args.label === void 0 ? {} : { label: args.label }
|
|
33578
|
+
}
|
|
33579
|
+
},
|
|
33580
|
+
base
|
|
33581
|
+
);
|
|
33582
|
+
} catch (err) {
|
|
33583
|
+
try {
|
|
33584
|
+
if (previous.usable) writeControlPlaneCredential(settingsDir(base), previous.credential);
|
|
33585
|
+
else removeControlPlaneCredential(settingsDir(base));
|
|
33586
|
+
} catch {
|
|
33587
|
+
}
|
|
33588
|
+
io.err(
|
|
33589
|
+
err instanceof ManagedFieldError ? "your organization manages this setting on this machine, so it cannot be attached here." : "could not save the attachment; this machine is left as it was."
|
|
33590
|
+
);
|
|
33591
|
+
exit(1);
|
|
33592
|
+
return;
|
|
33593
|
+
}
|
|
33594
|
+
io.out(
|
|
33595
|
+
[
|
|
33596
|
+
`Attached to ${args.label ?? endpoint}.`,
|
|
33597
|
+
` organization ${identity.tenantName}`,
|
|
33598
|
+
` you ${identity.userEmail}`,
|
|
33599
|
+
"",
|
|
33600
|
+
"Policy arrives on the next session. Run `aka status` to see it.",
|
|
33601
|
+
""
|
|
33602
|
+
].join("\n")
|
|
33603
|
+
);
|
|
33604
|
+
}
|
|
33605
|
+
async function verifyWithControlPlane(endpoint, apiKey) {
|
|
33606
|
+
const who = await createRemoteClient({ endpoint, apiKey }).whoami();
|
|
33607
|
+
return { tenantName: who.tenantName, userEmail: who.userEmail };
|
|
33608
|
+
}
|
|
33609
|
+
function runDetach(argv, deps = {}) {
|
|
33610
|
+
const io = deps.prompter ?? terminalPrompter();
|
|
33611
|
+
const exit = deps.exit ?? ((code) => process.exit(code));
|
|
33612
|
+
const args = parseAttachArgs(argv);
|
|
33613
|
+
if (isError(args)) {
|
|
33614
|
+
io.err(args.error);
|
|
33615
|
+
exit(2);
|
|
33616
|
+
return;
|
|
33617
|
+
}
|
|
33618
|
+
const base = deps.base ?? homeBase(args.home);
|
|
33619
|
+
const had = readControlPlaneCredentialState(settingsDir(base)).usable;
|
|
33620
|
+
try {
|
|
33621
|
+
applyOnboarding({ runMode: "standalone", controlPlane: void 0 }, base);
|
|
33622
|
+
} catch (err) {
|
|
33623
|
+
io.err(
|
|
33624
|
+
err instanceof ManagedFieldError ? "your organization manages this setting on this machine, so it cannot be detached here." : "could not clear the attachment; this machine is left as it was."
|
|
33625
|
+
);
|
|
33626
|
+
exit(1);
|
|
33627
|
+
return;
|
|
33628
|
+
}
|
|
33629
|
+
removeControlPlaneCredential(settingsDir(base));
|
|
33630
|
+
clearDerived(dataDir(base));
|
|
33631
|
+
io.out(
|
|
33632
|
+
had ? "Detached. This machine records locally only; that deployment is sent nothing.\n" : "This machine was not attached; nothing to do.\n"
|
|
33633
|
+
);
|
|
33634
|
+
}
|
|
33635
|
+
function clearDerived(dir) {
|
|
33636
|
+
for (const name of [
|
|
33637
|
+
POLICY_CACHE_FILENAME,
|
|
33638
|
+
SYNC_STATE_FILENAME,
|
|
33639
|
+
FORWARD_STATE_FILENAME,
|
|
33640
|
+
FORWARD_DROPS_FILENAME
|
|
33641
|
+
]) {
|
|
33642
|
+
rmSync7(join26(dir, name), { force: true });
|
|
33643
|
+
}
|
|
33644
|
+
}
|
|
33645
|
+
async function runStatus(argv, deps = {}) {
|
|
33646
|
+
const io = deps.prompter ?? terminalPrompter();
|
|
33647
|
+
const args = parseAttachArgs(argv);
|
|
33648
|
+
if (isError(args)) {
|
|
33649
|
+
io.err(args.error);
|
|
33650
|
+
(deps.exit ?? ((code) => process.exit(code)))(2);
|
|
33651
|
+
return;
|
|
33652
|
+
}
|
|
33653
|
+
const base = deps.base ?? homeBase(args.home);
|
|
33654
|
+
const dataDir2 = dataDir(base);
|
|
33655
|
+
const block = renderAttachedStatus({ base, settingsDir: settingsDir(base), dataDir: dataDir2 });
|
|
33656
|
+
const attached = !block.startsWith("AKA: standalone");
|
|
33657
|
+
io.out(attached ? `${block}
|
|
33658
|
+
${await renderPolicyLine(dataDir2)}
|
|
33659
|
+
` : `${block}
|
|
33660
|
+
`);
|
|
32403
33661
|
}
|
|
32404
33662
|
|
|
32405
33663
|
// src/commands/check-updates.ts
|
|
33664
|
+
import { existsSync as existsSync13 } from "fs";
|
|
33665
|
+
import { parseArgs } from "util";
|
|
32406
33666
|
function runCheckUpdates(argv) {
|
|
32407
33667
|
const { values } = parseArgs({ args: argv, options: HOME_OPTION });
|
|
32408
33668
|
const home = homeBase(values.home);
|
|
@@ -32424,7 +33684,7 @@ function runCheckUpdates(argv) {
|
|
|
32424
33684
|
out.write(`${String(ups.length)} update(s) available \u2014 run \`aka update\` to apply.
|
|
32425
33685
|
`);
|
|
32426
33686
|
}
|
|
32427
|
-
if (
|
|
33687
|
+
if (existsSync13(dataDir(home))) {
|
|
32428
33688
|
const notifiedPluginIds = readCache(home)?.notifiedPluginIds ?? [];
|
|
32429
33689
|
writeCache(home, { checkedAt: Date.now(), report, notifiedPluginIds });
|
|
32430
33690
|
}
|
|
@@ -32577,16 +33837,16 @@ function runCompletion(argv) {
|
|
|
32577
33837
|
}
|
|
32578
33838
|
|
|
32579
33839
|
// src/commands/dashboard.ts
|
|
32580
|
-
import { spawn as
|
|
32581
|
-
import { existsSync as
|
|
33840
|
+
import { spawn as spawn4 } from "child_process";
|
|
33841
|
+
import { existsSync as existsSync14 } from "fs";
|
|
32582
33842
|
import { createRequire as createRequire2 } from "module";
|
|
32583
33843
|
import { createServer } from "net";
|
|
32584
|
-
import { dirname as
|
|
32585
|
-
import { fileURLToPath as
|
|
33844
|
+
import { dirname as dirname8, join as join27 } from "path";
|
|
33845
|
+
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
|
|
32586
33846
|
import { parseArgs as parseArgs2 } from "util";
|
|
32587
33847
|
|
|
32588
33848
|
// src/lib/open-url.ts
|
|
32589
|
-
import { spawn as
|
|
33849
|
+
import { spawn as spawn3 } from "child_process";
|
|
32590
33850
|
function openUrlCommand(platform2, url2) {
|
|
32591
33851
|
if (platform2 === "darwin") return { command: "open", args: [url2] };
|
|
32592
33852
|
if (platform2 === "win32") return { command: "cmd", args: ["/c", "start", "", url2] };
|
|
@@ -32596,7 +33856,7 @@ var DETACHED = Object.freeze({ stdio: "ignore", detached: true });
|
|
|
32596
33856
|
function openUrl(url2, deps = {}) {
|
|
32597
33857
|
const { command, args } = openUrlCommand(deps.platform ?? process.platform, url2);
|
|
32598
33858
|
try {
|
|
32599
|
-
const child = (deps.spawn ??
|
|
33859
|
+
const child = (deps.spawn ?? spawn3)(command, [...args], DETACHED);
|
|
32600
33860
|
child.on("error", () => {
|
|
32601
33861
|
});
|
|
32602
33862
|
child.unref();
|
|
@@ -32606,10 +33866,10 @@ function openUrl(url2, deps = {}) {
|
|
|
32606
33866
|
|
|
32607
33867
|
// src/commands/dashboard.ts
|
|
32608
33868
|
var require3 = createRequire2(import.meta.url);
|
|
32609
|
-
var here =
|
|
33869
|
+
var here = dirname8(fileURLToPath4(import.meta.url));
|
|
32610
33870
|
var BIND_HOST = "127.0.0.1";
|
|
32611
33871
|
function pkgBase() {
|
|
32612
|
-
return isSea() ?
|
|
33872
|
+
return isSea() ? dirname8(process.execPath) : join27(here, "..");
|
|
32613
33873
|
}
|
|
32614
33874
|
function isPortFree(port) {
|
|
32615
33875
|
return new Promise((resolve6) => {
|
|
@@ -32663,17 +33923,17 @@ async function runDashboard(argv) {
|
|
|
32663
33923
|
refreshUpdateMirror(dataDir());
|
|
32664
33924
|
const base = pkgBase();
|
|
32665
33925
|
const bundledServer = [
|
|
32666
|
-
|
|
32667
|
-
|
|
32668
|
-
].find((p) =>
|
|
33926
|
+
join27(base, "web-ui", "server.js"),
|
|
33927
|
+
join27(base, "web-ui", "web-ui", "server.js")
|
|
33928
|
+
].find((p) => existsSync14(p));
|
|
32669
33929
|
if (bundledServer) {
|
|
32670
33930
|
launchStandalone(bundledServer, port, shouldOpen, url2);
|
|
32671
33931
|
return;
|
|
32672
33932
|
}
|
|
32673
|
-
const webUiDir =
|
|
33933
|
+
const webUiDir = dirname8(require3.resolve("@akasecurity/web-ui/package.json"));
|
|
32674
33934
|
const nextBin = require3.resolve("next/dist/bin/next", { paths: [webUiDir] });
|
|
32675
33935
|
const startNext = () => {
|
|
32676
|
-
const child =
|
|
33936
|
+
const child = spawn4(
|
|
32677
33937
|
process.execPath,
|
|
32678
33938
|
[nextBin, "start", "--port", port, "--hostname", BIND_HOST],
|
|
32679
33939
|
{
|
|
@@ -32684,12 +33944,12 @@ async function runDashboard(argv) {
|
|
|
32684
33944
|
onReadyOpen(child, shouldOpen, url2, `Starting the AKA dashboard at ${url2}
|
|
32685
33945
|
`);
|
|
32686
33946
|
};
|
|
32687
|
-
if (
|
|
33947
|
+
if (existsSync14(join27(webUiDir, ".next", "BUILD_ID"))) {
|
|
32688
33948
|
startNext();
|
|
32689
33949
|
return;
|
|
32690
33950
|
}
|
|
32691
33951
|
process.stdout.write("Building the web-ui (first run \u2014 this can take a minute)\u2026\n");
|
|
32692
|
-
const build =
|
|
33952
|
+
const build = spawn4(process.execPath, [nextBin, "build"], { cwd: webUiDir, stdio: "inherit" });
|
|
32693
33953
|
build.on("exit", (code) => {
|
|
32694
33954
|
if (code !== 0) {
|
|
32695
33955
|
process.stderr.write("aka dashboard: web-ui build failed\n");
|
|
@@ -32706,8 +33966,8 @@ function launchStandalone(serverJs, port, shouldOpen, url2) {
|
|
|
32706
33966
|
process.exitCode = 1;
|
|
32707
33967
|
return;
|
|
32708
33968
|
}
|
|
32709
|
-
const child =
|
|
32710
|
-
cwd:
|
|
33969
|
+
const child = spawn4(reinvoke.command, reinvoke.args, {
|
|
33970
|
+
cwd: dirname8(serverJs),
|
|
32711
33971
|
stdio: ["inherit", "pipe", "inherit"],
|
|
32712
33972
|
// Inherit the parent env so the child server sees PATH etc.; PORT/HOSTNAME tell
|
|
32713
33973
|
// Next's standalone server where to bind (its only port input).
|
|
@@ -32946,131 +34206,6 @@ function formatTimestamp(iso) {
|
|
|
32946
34206
|
return iso.slice(0, 16).replace("T", " ");
|
|
32947
34207
|
}
|
|
32948
34208
|
|
|
32949
|
-
// src/lib/prompter.ts
|
|
32950
|
-
import { createInterface } from "readline";
|
|
32951
|
-
function processHiddenChar(state, ch) {
|
|
32952
|
-
if (state.done) return state;
|
|
32953
|
-
if (state.esc === "esc") {
|
|
32954
|
-
return ch === "[" || ch === "O" ? { ...state, esc: "seq" } : { ...state, esc: "none" };
|
|
32955
|
-
}
|
|
32956
|
-
if (state.esc === "seq") {
|
|
32957
|
-
return ch >= "@" && ch <= "~" ? { ...state, esc: "none" } : state;
|
|
32958
|
-
}
|
|
32959
|
-
if (ch === "\r" || ch === "\n") return { ...state, done: "submit" };
|
|
32960
|
-
if (ch === "") return { ...state, done: "cancel" };
|
|
32961
|
-
if (ch === "\x7F" || ch === "\b") return { ...state, value: state.value.slice(0, -1) };
|
|
32962
|
-
if (ch === "\x1B") return { ...state, esc: "esc" };
|
|
32963
|
-
if (ch < " ") return state;
|
|
32964
|
-
return { ...state, value: state.value + ch };
|
|
32965
|
-
}
|
|
32966
|
-
var CLEANUP_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
32967
|
-
function processIo() {
|
|
32968
|
-
return {
|
|
32969
|
-
input: process.stdin,
|
|
32970
|
-
output: process.stdout,
|
|
32971
|
-
errorOutput: process.stderr,
|
|
32972
|
-
signals: {
|
|
32973
|
-
once: (signal, handler) => {
|
|
32974
|
-
process.once(signal, handler);
|
|
32975
|
-
},
|
|
32976
|
-
off: (signal, handler) => {
|
|
32977
|
-
process.removeListener(signal, handler);
|
|
32978
|
-
},
|
|
32979
|
-
raise: (signal) => {
|
|
32980
|
-
process.kill(process.pid, signal);
|
|
32981
|
-
}
|
|
32982
|
-
}
|
|
32983
|
-
};
|
|
32984
|
-
}
|
|
32985
|
-
function terminalPrompter(io = processIo()) {
|
|
32986
|
-
return {
|
|
32987
|
-
out: (text) => {
|
|
32988
|
-
io.output.write(text);
|
|
32989
|
-
},
|
|
32990
|
-
err: (text) => {
|
|
32991
|
-
io.errorOutput.write(text);
|
|
32992
|
-
},
|
|
32993
|
-
isInteractive: io.input.isTTY && io.output.isTTY,
|
|
32994
|
-
ask(question) {
|
|
32995
|
-
return new Promise((resolve6) => {
|
|
32996
|
-
const rl = createInterface({ input: io.input, output: io.output });
|
|
32997
|
-
rl.question(question, (answer) => {
|
|
32998
|
-
rl.close();
|
|
32999
|
-
resolve6(answer);
|
|
33000
|
-
});
|
|
33001
|
-
});
|
|
33002
|
-
},
|
|
33003
|
-
// Raw mode so nothing is echoed; characters are folded through
|
|
33004
|
-
// processHiddenChar. The captured value stays in this closure and is
|
|
33005
|
-
// handed to the caller only — never written anywhere. TTY restoration is
|
|
33006
|
-
// guaranteed via a one-shot `restore` that also runs on stdin errors and
|
|
33007
|
-
// fatal signals: a security tool must never brick the terminal it was
|
|
33008
|
-
// invoked from.
|
|
33009
|
-
askHidden(question) {
|
|
33010
|
-
return new Promise((resolve6, reject) => {
|
|
33011
|
-
const stdin = io.input;
|
|
33012
|
-
io.output.write(question);
|
|
33013
|
-
stdin.setRawMode(true);
|
|
33014
|
-
stdin.resume();
|
|
33015
|
-
let state = { value: "", esc: "none" };
|
|
33016
|
-
let restored = false;
|
|
33017
|
-
const restore = () => {
|
|
33018
|
-
if (restored) return;
|
|
33019
|
-
restored = true;
|
|
33020
|
-
stdin.removeListener("data", onData);
|
|
33021
|
-
stdin.removeListener("error", onError);
|
|
33022
|
-
for (const sig of CLEANUP_SIGNALS) io.signals.off(sig, onSignal);
|
|
33023
|
-
try {
|
|
33024
|
-
stdin.setRawMode(false);
|
|
33025
|
-
} catch {
|
|
33026
|
-
}
|
|
33027
|
-
stdin.pause();
|
|
33028
|
-
};
|
|
33029
|
-
const finish = (err) => {
|
|
33030
|
-
restore();
|
|
33031
|
-
io.output.write("\n");
|
|
33032
|
-
if (err) reject(err);
|
|
33033
|
-
else resolve6(state.value);
|
|
33034
|
-
};
|
|
33035
|
-
const onError = (err) => {
|
|
33036
|
-
finish(err);
|
|
33037
|
-
};
|
|
33038
|
-
const onSignal = (sig) => {
|
|
33039
|
-
restore();
|
|
33040
|
-
io.signals.raise(sig);
|
|
33041
|
-
};
|
|
33042
|
-
const onData = (chunk) => {
|
|
33043
|
-
try {
|
|
33044
|
-
for (const ch of chunk.toString("utf8")) {
|
|
33045
|
-
state = processHiddenChar(state, ch);
|
|
33046
|
-
if (state.done === "submit") {
|
|
33047
|
-
finish();
|
|
33048
|
-
return;
|
|
33049
|
-
}
|
|
33050
|
-
if (state.done === "cancel") {
|
|
33051
|
-
finish(new Error("cancelled"));
|
|
33052
|
-
return;
|
|
33053
|
-
}
|
|
33054
|
-
}
|
|
33055
|
-
} catch (err) {
|
|
33056
|
-
finish(err instanceof Error ? err : new Error(String(err)));
|
|
33057
|
-
}
|
|
33058
|
-
};
|
|
33059
|
-
stdin.on("data", onData);
|
|
33060
|
-
stdin.once("error", onError);
|
|
33061
|
-
for (const sig of CLEANUP_SIGNALS) io.signals.once(sig, onSignal);
|
|
33062
|
-
});
|
|
33063
|
-
},
|
|
33064
|
-
async readAllStdin() {
|
|
33065
|
-
const chunks = [];
|
|
33066
|
-
for await (const chunk of io.input) {
|
|
33067
|
-
chunks.push(chunk);
|
|
33068
|
-
}
|
|
33069
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
33070
|
-
}
|
|
33071
|
-
};
|
|
33072
|
-
}
|
|
33073
|
-
|
|
33074
34209
|
// src/commands/exception.ts
|
|
33075
34210
|
var EXCEPTION_HELP = `Manage detection exceptions (explicit, audited bypasses).
|
|
33076
34211
|
|
|
@@ -33854,15 +34989,15 @@ async function runException(argv, io = terminalPrompter()) {
|
|
|
33854
34989
|
|
|
33855
34990
|
// src/commands/extension.ts
|
|
33856
34991
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
33857
|
-
import { existsSync as
|
|
34992
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync18, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
33858
34993
|
import { createRequire as createRequire3 } from "module";
|
|
33859
34994
|
import { homedir as homedir5 } from "os";
|
|
33860
|
-
import { dirname as
|
|
33861
|
-
import { fileURLToPath as
|
|
34995
|
+
import { dirname as dirname9, join as join28 } from "path";
|
|
34996
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
33862
34997
|
var require4 = createRequire3(import.meta.url);
|
|
33863
|
-
var here2 =
|
|
34998
|
+
var here2 = dirname9(fileURLToPath5(import.meta.url));
|
|
33864
34999
|
function cliRoot() {
|
|
33865
|
-
return isSea() ?
|
|
35000
|
+
return isSea() ? dirname9(process.execPath) : join28(here2, "..");
|
|
33866
35001
|
}
|
|
33867
35002
|
var EXTENSION_IDS = [
|
|
33868
35003
|
// Derived from the "key" in plugins/browser-extension/manifest.json.
|
|
@@ -33879,30 +35014,30 @@ function nativeHostManifest(hostPath) {
|
|
|
33879
35014
|
};
|
|
33880
35015
|
}
|
|
33881
35016
|
function resolveHostScript(root = cliRoot()) {
|
|
33882
|
-
const bundled =
|
|
33883
|
-
if (
|
|
35017
|
+
const bundled = join28(root, "native-host", "host.js");
|
|
35018
|
+
if (existsSync15(bundled)) return bundled;
|
|
33884
35019
|
try {
|
|
33885
35020
|
const pkgJson = require4.resolve("@akasecurity/plugin-browser-extension/package.json");
|
|
33886
|
-
const devBuilt =
|
|
33887
|
-
if (
|
|
35021
|
+
const devBuilt = join28(dirname9(pkgJson), "native-host", "host.js");
|
|
35022
|
+
if (existsSync15(devBuilt)) return devBuilt;
|
|
33888
35023
|
} catch {
|
|
33889
35024
|
}
|
|
33890
35025
|
return null;
|
|
33891
35026
|
}
|
|
33892
35027
|
function resolveExtensionDist(root = cliRoot()) {
|
|
33893
|
-
const bundled =
|
|
33894
|
-
if (
|
|
35028
|
+
const bundled = join28(root, "extension");
|
|
35029
|
+
if (existsSync15(bundled)) return bundled;
|
|
33895
35030
|
try {
|
|
33896
35031
|
const pkgJson = require4.resolve("@akasecurity/plugin-browser-extension/package.json");
|
|
33897
|
-
const devDist =
|
|
33898
|
-
if (
|
|
35032
|
+
const devDist = join28(dirname9(pkgJson), "dist");
|
|
35033
|
+
if (existsSync15(devDist)) return devDist;
|
|
33899
35034
|
} catch {
|
|
33900
35035
|
}
|
|
33901
35036
|
return null;
|
|
33902
35037
|
}
|
|
33903
35038
|
function chromeManifestDir(platform2 = process.platform) {
|
|
33904
35039
|
if (platform2 === "darwin") {
|
|
33905
|
-
return
|
|
35040
|
+
return join28(
|
|
33906
35041
|
homedir5(),
|
|
33907
35042
|
"Library",
|
|
33908
35043
|
"Application Support",
|
|
@@ -33912,9 +35047,9 @@ function chromeManifestDir(platform2 = process.platform) {
|
|
|
33912
35047
|
);
|
|
33913
35048
|
}
|
|
33914
35049
|
if (platform2 === "win32") {
|
|
33915
|
-
return
|
|
35050
|
+
return join28(homedir5(), ".aka", "native-messaging");
|
|
33916
35051
|
}
|
|
33917
|
-
return
|
|
35052
|
+
return join28(homedir5(), ".config", "google-chrome", "NativeMessagingHosts");
|
|
33918
35053
|
}
|
|
33919
35054
|
function resolveNodeForLauncher() {
|
|
33920
35055
|
if (!isSea()) return process.execPath;
|
|
@@ -33928,7 +35063,7 @@ function resolveNodeForLauncher() {
|
|
|
33928
35063
|
}
|
|
33929
35064
|
}
|
|
33930
35065
|
function launcherPath(manifestDir, platform2) {
|
|
33931
|
-
return
|
|
35066
|
+
return join28(
|
|
33932
35067
|
manifestDir,
|
|
33933
35068
|
platform2 === "win32" ? `${NATIVE_HOST_NAME}.cmd` : `${NATIVE_HOST_NAME}.sh`
|
|
33934
35069
|
);
|
|
@@ -33978,7 +35113,7 @@ function runExtension(argv) {
|
|
|
33978
35113
|
return;
|
|
33979
35114
|
}
|
|
33980
35115
|
if (sub === "status") {
|
|
33981
|
-
|
|
35116
|
+
runStatus2(chromeManifestDir());
|
|
33982
35117
|
return;
|
|
33983
35118
|
}
|
|
33984
35119
|
process.stderr.write(
|
|
@@ -34005,7 +35140,7 @@ function runInstall(manifestDir, hostScript = resolveHostScript(), extensionDist
|
|
|
34005
35140
|
}
|
|
34006
35141
|
mkdirSync4(manifestDir, { recursive: true });
|
|
34007
35142
|
const launcher = writeLauncher(manifestDir, hostScript, nodePath, process.platform);
|
|
34008
|
-
const manifestPath =
|
|
35143
|
+
const manifestPath = join28(manifestDir, `${NATIVE_HOST_NAME}.json`);
|
|
34009
35144
|
const tmp = `${manifestPath}.tmp`;
|
|
34010
35145
|
writeFileSync7(tmp, `${JSON.stringify(nativeHostManifest(launcher), null, 2)}
|
|
34011
35146
|
`, {
|
|
@@ -34040,21 +35175,21 @@ Next: load the extension in Chrome \u2014
|
|
|
34040
35175
|
);
|
|
34041
35176
|
}
|
|
34042
35177
|
function manifestFault(manifestPath) {
|
|
34043
|
-
let
|
|
35178
|
+
let parsed2;
|
|
34044
35179
|
try {
|
|
34045
|
-
|
|
35180
|
+
parsed2 = JSON.parse(readFileSync18(manifestPath, "utf8"));
|
|
34046
35181
|
} catch (err) {
|
|
34047
35182
|
return `could not be read (${err instanceof Error ? err.message : String(err)})`;
|
|
34048
35183
|
}
|
|
34049
|
-
const granted =
|
|
35184
|
+
const granted = parsed2?.allowed_origins;
|
|
34050
35185
|
if (!Array.isArray(granted)) return "has no allowed_origins list";
|
|
34051
35186
|
const missing = EXTENSION_IDS.filter((id) => !granted.includes(`chrome-extension://${id}/`));
|
|
34052
35187
|
if (missing.length === 0) return null;
|
|
34053
35188
|
return `does not grant ${missing.length === 1 ? "the extension id" : "the extension ids"} ${missing.join(", ")}`;
|
|
34054
35189
|
}
|
|
34055
|
-
function
|
|
34056
|
-
const manifestPath =
|
|
34057
|
-
if (!
|
|
35190
|
+
function runStatus2(manifestDir) {
|
|
35191
|
+
const manifestPath = join28(manifestDir, `${NATIVE_HOST_NAME}.json`);
|
|
35192
|
+
if (!existsSync15(manifestPath)) {
|
|
34058
35193
|
process.stdout.write(
|
|
34059
35194
|
`native-messaging host: not installed
|
|
34060
35195
|
manifest: ${manifestPath}
|
|
@@ -34076,13 +35211,13 @@ function runStatus(manifestDir) {
|
|
|
34076
35211
|
}
|
|
34077
35212
|
|
|
34078
35213
|
// src/commands/init.ts
|
|
34079
|
-
import { existsSync as
|
|
34080
|
-
import {
|
|
35214
|
+
import { existsSync as existsSync17, lstatSync as lstatSync4, readdirSync as readdirSync7, statSync as statSync13 } from "fs";
|
|
35215
|
+
import { join as join29 } from "path";
|
|
34081
35216
|
import * as readline from "readline/promises";
|
|
34082
35217
|
import { parseArgs as parseArgs6 } from "util";
|
|
34083
35218
|
|
|
34084
35219
|
// src/commands/plugins.ts
|
|
34085
|
-
import { existsSync as
|
|
35220
|
+
import { existsSync as existsSync16 } from "fs";
|
|
34086
35221
|
import { parseArgs as parseArgs5 } from "util";
|
|
34087
35222
|
function runPlugins(argv) {
|
|
34088
35223
|
const [sub, ...rest] = argv;
|
|
@@ -34099,7 +35234,7 @@ async function listPlugins(argv) {
|
|
|
34099
35234
|
const { values } = parseArgs5({ args: argv, options: HOME_OPTION });
|
|
34100
35235
|
const home = homeBase(values.home);
|
|
34101
35236
|
const active = /* @__PURE__ */ new Set();
|
|
34102
|
-
if (
|
|
35237
|
+
if (existsSync16(dbPath(home))) {
|
|
34103
35238
|
const db = openLocalDatabase(dataDir(home));
|
|
34104
35239
|
try {
|
|
34105
35240
|
const recent = await db.findings.recentFindings({ limit: 1e3 });
|
|
@@ -34190,28 +35325,13 @@ Then run \`aka init\` to set up the local store.
|
|
|
34190
35325
|
|
|
34191
35326
|
// src/commands/init.ts
|
|
34192
35327
|
var PLUGIN_OFFER_IDENTITY = `${PRODUCT_NAME} \u2014 ${PRODUCT_TAGLINE}`;
|
|
34193
|
-
var STORE_DB = "the store database (including the prompt corpus)";
|
|
34194
|
-
var STORE_SETTINGS = "your settings file";
|
|
34195
|
-
function storeContents(home) {
|
|
34196
|
-
return /* @__PURE__ */ new Map([
|
|
34197
|
-
[home, "the store (including the prompt corpus in aka.db)"],
|
|
34198
|
-
[settingsDir(home), STORE_SETTINGS],
|
|
34199
|
-
[dataDir(home), STORE_DB],
|
|
34200
|
-
[keysDir(home), "the vault key"],
|
|
34201
|
-
[join21(settingsDir(home), "settings.json"), STORE_SETTINGS],
|
|
34202
|
-
[dbPath(home), STORE_DB]
|
|
34203
|
-
]);
|
|
34204
|
-
}
|
|
34205
|
-
function storeTargets(home) {
|
|
34206
|
-
return [...storeContents(home).keys()];
|
|
34207
|
-
}
|
|
34208
35328
|
function storeModeTargets(home) {
|
|
34209
35329
|
const targets = new Set(storeTargets(home));
|
|
34210
35330
|
for (const dir of [dataDir(home), keysDir(home)]) {
|
|
34211
35331
|
try {
|
|
34212
35332
|
for (const entry of readdirSync7(dir, { withFileTypes: true })) {
|
|
34213
35333
|
if (entry.name.endsWith(".partial") && !entry.isDirectory()) continue;
|
|
34214
|
-
targets.add(
|
|
35334
|
+
targets.add(join29(dir, entry.name));
|
|
34215
35335
|
}
|
|
34216
35336
|
} catch {
|
|
34217
35337
|
}
|
|
@@ -34222,48 +35342,13 @@ function looseStorePaths(home) {
|
|
|
34222
35342
|
if (process.platform === "win32") return [];
|
|
34223
35343
|
return storeModeTargets(home).filter((p) => {
|
|
34224
35344
|
try {
|
|
34225
|
-
if (
|
|
34226
|
-
return (
|
|
35345
|
+
if (lstatSync4(p).isSymbolicLink()) return false;
|
|
35346
|
+
return (statSync13(p).mode & 63) !== 0;
|
|
34227
35347
|
} catch {
|
|
34228
35348
|
return false;
|
|
34229
35349
|
}
|
|
34230
35350
|
});
|
|
34231
35351
|
}
|
|
34232
|
-
function symlinkedStorePaths(home, platform2 = process.platform) {
|
|
34233
|
-
return [...storeContents(home)].flatMap(([path, holds]) => {
|
|
34234
|
-
try {
|
|
34235
|
-
if (!lstatSync2(path).isSymbolicLink()) return [];
|
|
34236
|
-
return [
|
|
34237
|
-
{
|
|
34238
|
-
path,
|
|
34239
|
-
target: linkTarget(path),
|
|
34240
|
-
holds,
|
|
34241
|
-
// existsSync follows the link, so a target that is gone reads as
|
|
34242
|
-
// absent here while lstat above still sees the link itself.
|
|
34243
|
-
missing: !existsSync16(path),
|
|
34244
|
-
mode: targetMode(path, platform2)
|
|
34245
|
-
}
|
|
34246
|
-
];
|
|
34247
|
-
} catch {
|
|
34248
|
-
return [];
|
|
34249
|
-
}
|
|
34250
|
-
});
|
|
34251
|
-
}
|
|
34252
|
-
function linkTarget(path) {
|
|
34253
|
-
try {
|
|
34254
|
-
return realpathSync4(path);
|
|
34255
|
-
} catch {
|
|
34256
|
-
return resolve5(dirname9(path), readlinkSync(path));
|
|
34257
|
-
}
|
|
34258
|
-
}
|
|
34259
|
-
function targetMode(path, platform2) {
|
|
34260
|
-
if (platform2 === "win32") return void 0;
|
|
34261
|
-
try {
|
|
34262
|
-
return statSync10(path).mode & 511;
|
|
34263
|
-
} catch {
|
|
34264
|
-
return void 0;
|
|
34265
|
-
}
|
|
34266
|
-
}
|
|
34267
35352
|
function symlinkWarnings(paths, platform2 = process.platform) {
|
|
34268
35353
|
const seeAlso = '(see the "Data at rest" note in SECURITY.md)';
|
|
34269
35354
|
return paths.map(({ path, target, holds, missing, mode }) => {
|
|
@@ -34291,7 +35376,7 @@ function assertStoreLinksResolve(home) {
|
|
|
34291
35376
|
}
|
|
34292
35377
|
function isBrokenLink(path) {
|
|
34293
35378
|
try {
|
|
34294
|
-
return
|
|
35379
|
+
return lstatSync4(path).isSymbolicLink() && !existsSync17(path);
|
|
34295
35380
|
} catch {
|
|
34296
35381
|
return false;
|
|
34297
35382
|
}
|
|
@@ -34305,14 +35390,14 @@ function assertStorePathsAreDirectories(home) {
|
|
|
34305
35390
|
}
|
|
34306
35391
|
function isSymlink2(path) {
|
|
34307
35392
|
try {
|
|
34308
|
-
return
|
|
35393
|
+
return lstatSync4(path).isSymbolicLink();
|
|
34309
35394
|
} catch {
|
|
34310
35395
|
return false;
|
|
34311
35396
|
}
|
|
34312
35397
|
}
|
|
34313
35398
|
function existsAsNonDirectory(path) {
|
|
34314
35399
|
try {
|
|
34315
|
-
return !
|
|
35400
|
+
return !statSync13(path).isDirectory();
|
|
34316
35401
|
} catch {
|
|
34317
35402
|
return false;
|
|
34318
35403
|
}
|
|
@@ -34328,12 +35413,12 @@ async function runInit(argv) {
|
|
|
34328
35413
|
ensureLayoutDirSync(home);
|
|
34329
35414
|
const settings = settingsDir(home);
|
|
34330
35415
|
ensureLayoutDirSync(settings);
|
|
34331
|
-
const settingsFile =
|
|
35416
|
+
const settingsFile = join29(settings, "settings.json");
|
|
34332
35417
|
let settingsCreated = false;
|
|
34333
|
-
if (!
|
|
35418
|
+
if (!existsSync17(settingsFile)) {
|
|
34334
35419
|
try {
|
|
34335
35420
|
settingsCreated = withFileLock(settingsFile, () => {
|
|
34336
|
-
if (
|
|
35421
|
+
if (existsSync17(settingsFile)) return false;
|
|
34337
35422
|
writeOwnerOnlyFileSync(
|
|
34338
35423
|
settingsFile,
|
|
34339
35424
|
`${JSON.stringify(defaultWorkspaceSettings(), null, 2)}
|
|
@@ -34362,7 +35447,7 @@ async function runInit(argv) {
|
|
|
34362
35447
|
const symlinked = symlinkedStorePaths(home);
|
|
34363
35448
|
process.stdout.write(
|
|
34364
35449
|
`\u2713 Initialized AKA at ${home}
|
|
34365
|
-
settings: ${settingsFile}${settingsCreated ? "" :
|
|
35450
|
+
settings: ${settingsFile}${settingsCreated ? "" : existsSync17(settingsFile) ? " (kept existing)" : " (not written \u2014 another process was writing it)"}
|
|
34366
35451
|
database: ${dbPath(home)}
|
|
34367
35452
|
seeded ${String(policyCount)} default policies, ${String(packCount)} detection pack(s)
|
|
34368
35453
|
` + (updatesAvailable > 0 ? ` \u2B06 ${String(updatesAvailable)} detection pack update(s) available \u2014 review with \`aka detections\`, apply with \`aka detections update --all\`
|
|
@@ -34412,7 +35497,7 @@ async function confirm(question) {
|
|
|
34412
35497
|
}
|
|
34413
35498
|
|
|
34414
35499
|
// src/commands/scan.ts
|
|
34415
|
-
import { statSync as
|
|
35500
|
+
import { statSync as statSync14 } from "fs";
|
|
34416
35501
|
import { parseArgs as parseArgs7 } from "util";
|
|
34417
35502
|
function severityRank(s) {
|
|
34418
35503
|
return Severity.options.indexOf(s);
|
|
@@ -34447,8 +35532,8 @@ async function runScan(argv) {
|
|
|
34447
35532
|
}
|
|
34448
35533
|
let failOn;
|
|
34449
35534
|
if (values["fail-on"] !== void 0) {
|
|
34450
|
-
const
|
|
34451
|
-
if (!
|
|
35535
|
+
const parsed2 = Severity.safeParse(values["fail-on"]);
|
|
35536
|
+
if (!parsed2.success) {
|
|
34452
35537
|
process.stderr.write(
|
|
34453
35538
|
`aka scan: invalid --fail-on '${values["fail-on"]}' (expected ${Severity.options.join(", ")})
|
|
34454
35539
|
`
|
|
@@ -34456,10 +35541,10 @@ async function runScan(argv) {
|
|
|
34456
35541
|
process.exitCode = 1;
|
|
34457
35542
|
return;
|
|
34458
35543
|
}
|
|
34459
|
-
failOn =
|
|
35544
|
+
failOn = parsed2.data;
|
|
34460
35545
|
}
|
|
34461
35546
|
try {
|
|
34462
|
-
|
|
35547
|
+
statSync14(target);
|
|
34463
35548
|
} catch {
|
|
34464
35549
|
process.stderr.write(`aka scan: no such file or directory: ${target}
|
|
34465
35550
|
`);
|
|
@@ -35266,10 +36351,10 @@ import { parseArgs as parseArgs10 } from "util";
|
|
|
35266
36351
|
|
|
35267
36352
|
// src/lib/install-origin.ts
|
|
35268
36353
|
import { dirname as dirname10 } from "path";
|
|
35269
|
-
import { fileURLToPath as
|
|
36354
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
35270
36355
|
function cliInstallOrigin() {
|
|
35271
36356
|
try {
|
|
35272
|
-
return { moduleDir: dirname10(
|
|
36357
|
+
return { moduleDir: dirname10(fileURLToPath6(import.meta.url)) };
|
|
35273
36358
|
} catch {
|
|
35274
36359
|
return { moduleDir: void 0 };
|
|
35275
36360
|
}
|
|
@@ -35445,8 +36530,8 @@ async function runShow2(argv, io) {
|
|
|
35445
36530
|
if (candidate === void 0 || candidate === "") {
|
|
35446
36531
|
throw new Error(`usage: aka vault show '[[aka:...]]'`);
|
|
35447
36532
|
}
|
|
35448
|
-
const
|
|
35449
|
-
if (!
|
|
36533
|
+
const parsed2 = PointerToken.safeParse(candidate);
|
|
36534
|
+
if (!parsed2.success) {
|
|
35450
36535
|
throw new Error(
|
|
35451
36536
|
"that is not a vault pointer \u2014 expected the full [[aka:...]] token (quote it in the shell)"
|
|
35452
36537
|
);
|
|
@@ -35461,7 +36546,7 @@ async function runShow2(argv, io) {
|
|
|
35461
36546
|
// Read live so a consent revocation applies to the very next call.
|
|
35462
36547
|
isConsented: () => isVaultConsentValid(readWorkspaceSettings(base).vaultConsent)
|
|
35463
36548
|
});
|
|
35464
|
-
const value = await vault.detokenize(
|
|
36549
|
+
const value = await vault.detokenize(parsed2.data, {
|
|
35465
36550
|
target: "human",
|
|
35466
36551
|
reason: "explicit-reveal"
|
|
35467
36552
|
});
|
|
@@ -35470,7 +36555,7 @@ async function runShow2(argv, io) {
|
|
|
35470
36555
|
}
|
|
35471
36556
|
io.out(`${value}
|
|
35472
36557
|
`);
|
|
35473
|
-
const descriptor = await vault.describePointer(
|
|
36558
|
+
const descriptor = await vault.describePointer(parsed2.data);
|
|
35474
36559
|
if (descriptor) io.out(`${descriptorLine(descriptor)}
|
|
35475
36560
|
`);
|
|
35476
36561
|
} finally {
|
|
@@ -35517,12 +36602,12 @@ function signalExitCode(signal) {
|
|
|
35517
36602
|
return number4 === void 0 ? 1 : 128 + number4;
|
|
35518
36603
|
}
|
|
35519
36604
|
function dispatchExternal(command, argv, deps = {}) {
|
|
35520
|
-
const
|
|
36605
|
+
const spawn5 = deps.spawn ?? spawnSync2;
|
|
35521
36606
|
const platform2 = deps.platform ?? process.platform;
|
|
35522
36607
|
const exists = deps.exists ?? commandOnPath;
|
|
35523
36608
|
if (!externalDispatchSupported(platform2)) return { found: false, status: 1 };
|
|
35524
36609
|
const target = `aka-${command}`;
|
|
35525
|
-
const result =
|
|
36610
|
+
const result = spawn5(target, argv, { stdio: "inherit" });
|
|
35526
36611
|
if (result.error) {
|
|
35527
36612
|
if (result.error.code === "ENOENT" && !exists(target)) return { found: false, status: 1 };
|
|
35528
36613
|
process.stderr.write(`aka: ${target}: ${result.error.message}
|
|
@@ -35548,6 +36633,11 @@ var COMMANDS = {
|
|
|
35548
36633
|
extension: runExtension,
|
|
35549
36634
|
exception: (argv) => runException(argv),
|
|
35550
36635
|
vault: (argv) => runVault(argv),
|
|
36636
|
+
attach: (argv) => runAttach(argv),
|
|
36637
|
+
detach: (argv) => {
|
|
36638
|
+
runDetach(argv);
|
|
36639
|
+
},
|
|
36640
|
+
status: (argv) => runStatus(argv),
|
|
35551
36641
|
tui: runTui,
|
|
35552
36642
|
update: runUpdate,
|
|
35553
36643
|
"check-updates": runCheckUpdates,
|
|
@@ -35570,7 +36660,7 @@ var SKIP_NOTICE = /* @__PURE__ */ new Set([
|
|
|
35570
36660
|
"__dashboard-server",
|
|
35571
36661
|
"completion"
|
|
35572
36662
|
]);
|
|
35573
|
-
var
|
|
36663
|
+
var USAGE2 = `aka \u2014 AI Traffic Control (local-first; see the egress footnote in the README)
|
|
35574
36664
|
|
|
35575
36665
|
Usage: aka <command> [options]
|
|
35576
36666
|
|
|
@@ -35602,7 +36692,7 @@ async function main(argv = process.argv.slice(2), dispatchDeps = {}) {
|
|
|
35602
36692
|
}
|
|
35603
36693
|
const [command, ...rawRest] = argv;
|
|
35604
36694
|
if (!command || command === "-h" || command === "--help") {
|
|
35605
|
-
process.stdout.write(
|
|
36695
|
+
process.stdout.write(USAGE2);
|
|
35606
36696
|
return;
|
|
35607
36697
|
}
|
|
35608
36698
|
const noUpdateCheck = rawRest.includes("--no-update-check");
|
|
@@ -35618,7 +36708,7 @@ async function main(argv = process.argv.slice(2), dispatchDeps = {}) {
|
|
|
35618
36708
|
if (!handler) {
|
|
35619
36709
|
process.stderr.write(`aka: unknown command '${command}'
|
|
35620
36710
|
|
|
35621
|
-
${
|
|
36711
|
+
${USAGE2}`);
|
|
35622
36712
|
process.exitCode = 1;
|
|
35623
36713
|
return;
|
|
35624
36714
|
}
|