@hasna/hooks 0.11.7 → 0.12.1
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 +129 -4
- package/bin/hooks-mcp.js +39 -7
- package/bin/index.js +739 -129
- package/bin/native-safety-entry.js +15 -1718
- package/bin/serve.js +36 -9
- package/dist/index.js +51 -17
- package/dist/lib/codex-safety-check.d.ts +3 -0
- package/dist/lib/native-safety-registration.d.ts +49 -6
- package/dist/lib/registry.d.ts +15 -0
- package/dist/native-safety.d.ts +4 -0
- package/dist/native-safety.js +8 -4
- package/dist/sdk/index.js +1 -1
- package/hooks/hook-signed-link-guard/README.md +228 -0
- package/hooks/hook-signed-link-guard/package.json +12 -0
- package/hooks/hook-signed-link-guard/src/classify.ts +1280 -0
- package/hooks/hook-signed-link-guard/src/hook.ts +72 -0
- package/hooks/hook-signed-link-guard/src/jq.ts +545 -0
- package/hooks/hook-signed-link-guard/src/links.ts +136 -0
- package/hooks/hook-signed-link-output/README.md +47 -0
- package/hooks/hook-signed-link-output/package.json +12 -0
- package/hooks/hook-signed-link-output/src/hook.ts +111 -0
- package/hooks/hook-trash-guard/src/hook.ts +204 -80
- package/hooks/native-safety-entry.ts +28 -7
- package/package.json +2 -2
- package/scripts/validate-package.ts +12 -2
package/bin/index.js
CHANGED
|
@@ -165,6 +165,9 @@ var init_app_home = __esm(() => {
|
|
|
165
165
|
});
|
|
166
166
|
|
|
167
167
|
// src/lib/registry.ts
|
|
168
|
+
function matcherFor(meta, target) {
|
|
169
|
+
return meta.targetMatchers?.[target] ?? meta.matcher;
|
|
170
|
+
}
|
|
168
171
|
function getHooksByCategory(category) {
|
|
169
172
|
return HOOKS.filter((h) => h.category === category);
|
|
170
173
|
}
|
|
@@ -178,7 +181,7 @@ function searchHooks(query) {
|
|
|
178
181
|
function getHook(name) {
|
|
179
182
|
return HOOKS.find((h) => h.name === name);
|
|
180
183
|
}
|
|
181
|
-
var CATEGORIES, HOOKS;
|
|
184
|
+
var CLAUDE_TRASH_GUARD_MATCHER = "^(Bash|Monitor|apply_patch|ApplyPatch|functions\\.apply_patch)$", CATEGORIES, HOOKS;
|
|
182
185
|
var init_registry = __esm(() => {
|
|
183
186
|
init_app_home();
|
|
184
187
|
CATEGORIES = [
|
|
@@ -243,6 +246,8 @@ var init_registry = __esm(() => {
|
|
|
243
246
|
category: "Git Safety",
|
|
244
247
|
event: "PreToolUse",
|
|
245
248
|
matcher: "^(Bash|Write|Edit|MultiEdit|NotebookEdit|apply_patch|ApplyPatch|functions\\.apply_patch)$",
|
|
249
|
+
targetMatchers: { claude: "^(Bash|Monitor|Write|Edit|MultiEdit|NotebookEdit|apply_patch|ApplyPatch|functions\\.apply_patch)$" },
|
|
250
|
+
legacyMatchers: ["^(Bash|Write|Edit|MultiEdit|NotebookEdit|apply_patch|ApplyPatch|functions\\.apply_patch)$"],
|
|
246
251
|
tags: ["workspace", "repos", "structure", "guard", "safety", "orgs", "multi-agent"]
|
|
247
252
|
},
|
|
248
253
|
{
|
|
@@ -253,6 +258,8 @@ var init_registry = __esm(() => {
|
|
|
253
258
|
category: "Git Safety",
|
|
254
259
|
event: "PreToolUse",
|
|
255
260
|
matcher: "^(Bash|apply_patch|ApplyPatch|functions\\.apply_patch)$",
|
|
261
|
+
targetMatchers: { claude: CLAUDE_TRASH_GUARD_MATCHER },
|
|
262
|
+
legacyMatchers: ["^(Bash|apply_patch|ApplyPatch|functions\\.apply_patch)$"],
|
|
256
263
|
tags: ["rm", "delete", "trash", "recoverable", "guard", "safety", "bash"],
|
|
257
264
|
rewritesInput: true,
|
|
258
265
|
timeoutSeconds: 10
|
|
@@ -357,6 +364,28 @@ var init_registry = __esm(() => {
|
|
|
357
364
|
matcher: "Bash",
|
|
358
365
|
tags: ["security", "credentials", "secrets", "detection", "audit"]
|
|
359
366
|
},
|
|
367
|
+
{
|
|
368
|
+
name: "signed-link-guard",
|
|
369
|
+
displayName: "Signed Link Guard",
|
|
370
|
+
description: "Refuses gh reads that would print composite GitHub content (bodies, comments, reviews, commit messages, check links and details, raw issue/PR/check API objects) where signed action links appear; bounded scalar projections, diffs, lists and writes pass",
|
|
371
|
+
version: "0.1.0",
|
|
372
|
+
category: "Security",
|
|
373
|
+
event: "PreToolUse",
|
|
374
|
+
matcher: "^(Bash|Monitor)$",
|
|
375
|
+
tags: ["github", "gh", "signed-links", "capabilities", "transcript", "guard", "security"],
|
|
376
|
+
timeoutSeconds: 10
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
name: "signed-link-output",
|
|
380
|
+
displayName: "Signed Link Output",
|
|
381
|
+
description: "Claude PostToolUse backstop: replaces signed-link URLs in tool output with a redaction marker (updatedToolOutput, where the running Claude Code supports it) and tells the model not to repeat or store the link. It runs after the tool, so it cannot undo display or other persistence",
|
|
382
|
+
version: "0.1.0",
|
|
383
|
+
category: "Security",
|
|
384
|
+
event: "PostToolUse",
|
|
385
|
+
matcher: "^(Bash|WebFetch|mcp__.*)$",
|
|
386
|
+
tags: ["github", "signed-links", "capabilities", "redaction", "transcript", "security"],
|
|
387
|
+
timeoutSeconds: 10
|
|
388
|
+
},
|
|
360
389
|
{
|
|
361
390
|
name: "phonenotify",
|
|
362
391
|
displayName: "Phone Notify",
|
|
@@ -2520,7 +2549,7 @@ var init_codex_settings = __esm(() => {
|
|
|
2520
2549
|
snapshots = new WeakMap;
|
|
2521
2550
|
});
|
|
2522
2551
|
|
|
2523
|
-
//
|
|
2552
|
+
// ../../node_modules/.bun/@hasna+skills@0.9.17+a00d3064559565bb/node_modules/@hasna/skills/dist/index.js
|
|
2524
2553
|
import { existsSync as existsSync10 } from "fs";
|
|
2525
2554
|
import { homedir as homedir6 } from "os";
|
|
2526
2555
|
import { join as join10, resolve as resolve4 } from "path";
|
|
@@ -33989,6 +34018,7 @@ function registerHook(name, scope = "global", target = "claude", profile, mement
|
|
|
33989
34018
|
if (uniqueEventKeys.length === 0) {
|
|
33990
34019
|
throw new Error(`Hook '${name}' has no installable events for target '${target}'`);
|
|
33991
34020
|
}
|
|
34021
|
+
const matcher = matcherFor(meta3, target);
|
|
33992
34022
|
const settings = readSettings2(scope, target);
|
|
33993
34023
|
if (!settings.hooks)
|
|
33994
34024
|
settings.hooks = {};
|
|
@@ -34023,10 +34053,12 @@ function registerHook(name, scope = "global", target = "claude", profile, mement
|
|
|
34023
34053
|
}
|
|
34024
34054
|
}
|
|
34025
34055
|
if (positions.length) {
|
|
34026
|
-
if (positions.length !== uniqueEventKeys.length || uniqueEventKeys.some((event) => positions.filter((position) => position.event === event).length !== 1) || positions.some((position) => (position.entry.matcher ?? "") !== (meta3.matcher ?? ""))) {
|
|
34056
|
+
if (positions.length !== uniqueEventKeys.length || uniqueEventKeys.some((event) => positions.filter((position) => position.event === event).length !== 1) || positions.some((position) => (position.entry.matcher ?? "") !== matcher && !(meta3.legacyMatchers ?? []).includes(position.entry.matcher ?? ""))) {
|
|
34027
34057
|
throw new Error("Codex hook events, matchers or duplicate registrations require explicit reconciliation; no settings were changed.");
|
|
34028
34058
|
}
|
|
34029
34059
|
for (const { entry, index } of positions) {
|
|
34060
|
+
if (matcher)
|
|
34061
|
+
entry.matcher = matcher;
|
|
34030
34062
|
entry.hooks[index] = { ...entry.hooks[index], type: "command", command: hookCommand };
|
|
34031
34063
|
if (typeof meta3.timeoutSeconds === "number" && meta3.timeoutSeconds > 0)
|
|
34032
34064
|
entry.hooks[index].timeout = meta3.timeoutSeconds;
|
|
@@ -34046,8 +34078,8 @@ function registerHook(name, scope = "global", target = "claude", profile, mement
|
|
|
34046
34078
|
const entry = {
|
|
34047
34079
|
hooks: [hookEntry]
|
|
34048
34080
|
};
|
|
34049
|
-
if (
|
|
34050
|
-
entry.matcher =
|
|
34081
|
+
if (matcher) {
|
|
34082
|
+
entry.matcher = matcher;
|
|
34051
34083
|
}
|
|
34052
34084
|
settings.hooks[eventKey].push(entry);
|
|
34053
34085
|
}
|
|
@@ -34466,11 +34498,16 @@ function syncDirectory(path) {
|
|
|
34466
34498
|
closeSync6(fd);
|
|
34467
34499
|
}
|
|
34468
34500
|
}
|
|
34501
|
+
function nativeSafetyRecordText(command) {
|
|
34502
|
+
const record3 = { schema: "hasna.hooks.native-safety.v1", harness: "sumi", command };
|
|
34503
|
+
return JSON.stringify(record3) + `
|
|
34504
|
+
`;
|
|
34505
|
+
}
|
|
34469
34506
|
function readNativeSafetyRegistration(home = homedir8()) {
|
|
34470
34507
|
try {
|
|
34471
34508
|
home = canonicalHome(home);
|
|
34472
34509
|
const path = join12(home, ".hasna/hooks/native", filename), text3 = readOwned(path);
|
|
34473
|
-
return { record: parseRecord(text3, home), sha256: hash(text3), path };
|
|
34510
|
+
return { record: parseRecord(text3, home), sha256: hash(text3), path, text: text3 };
|
|
34474
34511
|
} catch (error61) {
|
|
34475
34512
|
if (error61 instanceof NativeSafetyError)
|
|
34476
34513
|
throw error61;
|
|
@@ -34496,9 +34533,7 @@ function nativeSafetyBindingIntegrityReason(home = homedir8()) {
|
|
|
34496
34533
|
}
|
|
34497
34534
|
function registerNativeSafety(options = {}) {
|
|
34498
34535
|
const home = canonicalHome(options.home ?? homedir8());
|
|
34499
|
-
const
|
|
34500
|
-
const text3 = JSON.stringify(record3) + `
|
|
34501
|
-
`;
|
|
34536
|
+
const text3 = nativeSafetyRecordText(options.command ?? installedNativeSafetyCommand("trash-guard"));
|
|
34502
34537
|
parseRecord(text3, home);
|
|
34503
34538
|
for (const dir of [join12(home, ".hasna"), join12(home, ".hasna/hooks"), join12(home, ".hasna/hooks/native")]) {
|
|
34504
34539
|
try {
|
|
@@ -34954,13 +34989,115 @@ async function applyRegistration(options, dependencies = {}) {
|
|
|
34954
34989
|
throw new NativeRegistrationError("apply_outcome_uncertain", operationId);
|
|
34955
34990
|
}
|
|
34956
34991
|
}
|
|
34992
|
+
function inspectSumi(dependencies) {
|
|
34993
|
+
let home, command;
|
|
34994
|
+
try {
|
|
34995
|
+
home = realpathSync7(dependencies.home ?? homedir9());
|
|
34996
|
+
} catch {
|
|
34997
|
+
throw new NativeRegistrationError("settings_unsafe");
|
|
34998
|
+
}
|
|
34999
|
+
try {
|
|
35000
|
+
command = dependencies.command ?? installedNativeSafetyCommand("trash-guard");
|
|
35001
|
+
} catch {
|
|
35002
|
+
throw new NativeRegistrationError("guard_failed");
|
|
35003
|
+
}
|
|
35004
|
+
const binding = nativeSafetyCommandBinding(command);
|
|
35005
|
+
need5(binding?.name === "trash-guard" && binding.home === home, "input_invalid");
|
|
35006
|
+
const directory2 = join13(home, ".hasna", "hooks", "native"), path = join13(directory2, "sumi-trash-guard.json");
|
|
35007
|
+
let existing = directory2;
|
|
35008
|
+
while (!lstatSync9(existing, { throwIfNoEntry: false }))
|
|
35009
|
+
existing = dirname11(existing);
|
|
35010
|
+
safeDirectory2(existing);
|
|
35011
|
+
let before;
|
|
35012
|
+
try {
|
|
35013
|
+
before = readNativeSafetyRegistration(home);
|
|
35014
|
+
} catch (error61) {
|
|
35015
|
+
if (!(error61 instanceof NativeSafetyError) || error61.code !== "binding_missing")
|
|
35016
|
+
throw new NativeRegistrationError(nativeSafetyBindingIntegrityReason(home) ? "settings_unsafe" : "settings_invalid");
|
|
35017
|
+
}
|
|
35018
|
+
const beforeSHA256 = before?.sha256 ?? "absent", desiredSHA256 = sha4(nativeSafetyRecordText(command));
|
|
35019
|
+
const base = {
|
|
35020
|
+
schema: "hasna.hooks.native-readiness-registration/v1",
|
|
35021
|
+
target: "sumi",
|
|
35022
|
+
settingsPath: path,
|
|
35023
|
+
resolvedPath: path,
|
|
35024
|
+
beforeSHA256,
|
|
35025
|
+
desiredSHA256,
|
|
35026
|
+
commandSHA256: sha4(command),
|
|
35027
|
+
action: beforeSHA256 === desiredSHA256 ? "unchanged" : "register",
|
|
35028
|
+
guardVerified: true,
|
|
35029
|
+
nativeAdoptionVerified: false
|
|
35030
|
+
};
|
|
35031
|
+
const plan = { ...base, planDigest: sha4(canonical4(base)) };
|
|
35032
|
+
return { home, command, before, plan };
|
|
35033
|
+
}
|
|
35034
|
+
async function planSumiRegistration(dependencies) {
|
|
35035
|
+
const before = inspectSumi(dependencies);
|
|
35036
|
+
try {
|
|
35037
|
+
await (dependencies.verify ?? verifyNativeSafetyCommand)(before.command, before.home);
|
|
35038
|
+
} catch {
|
|
35039
|
+
throw new NativeRegistrationError("guard_failed");
|
|
35040
|
+
}
|
|
35041
|
+
need5(inspectSumi(dependencies).plan.planDigest === before.plan.planDigest, "settings_changed");
|
|
35042
|
+
return before.plan;
|
|
35043
|
+
}
|
|
35044
|
+
async function applySumiRegistration(expectedPlanDigest, dependencies) {
|
|
35045
|
+
need5(typeof expectedPlanDigest === "string" && /^[a-f0-9]{64}$/.test(expectedPlanDigest), "input_invalid");
|
|
35046
|
+
const plan = await planSumiRegistration(dependencies);
|
|
35047
|
+
need5(plan.planDigest === expectedPlanDigest, "settings_changed");
|
|
35048
|
+
if (plan.action === "unchanged")
|
|
35049
|
+
return { ok: true, changed: false, ...plan };
|
|
35050
|
+
const current2 = inspectSumi(dependencies);
|
|
35051
|
+
need5(current2.plan.planDigest === plan.planDigest, "settings_changed");
|
|
35052
|
+
const operationId = randomUUID5();
|
|
35053
|
+
let directory2 = current2.home;
|
|
35054
|
+
for (const part of [".hasna", "hooks", "native", "trash-readiness-registration", operationId]) {
|
|
35055
|
+
directory2 = join13(directory2, part);
|
|
35056
|
+
try {
|
|
35057
|
+
mkdirSync11(directory2, { mode: 448 });
|
|
35058
|
+
syncDirectory2(dirname11(directory2));
|
|
35059
|
+
} catch (error61) {
|
|
35060
|
+
if (error61.code !== "EEXIST")
|
|
35061
|
+
throw new NativeRegistrationError("settings_unsafe");
|
|
35062
|
+
}
|
|
35063
|
+
safeDirectory2(directory2);
|
|
35064
|
+
}
|
|
35065
|
+
if (current2.before)
|
|
35066
|
+
exclusive(join13(directory2, "settings.before"), current2.before.text);
|
|
35067
|
+
exclusive(join13(directory2, "intent.json"), JSON.stringify({ operationId, plan }) + `
|
|
35068
|
+
`);
|
|
35069
|
+
try {
|
|
35070
|
+
need5(inspectSumi(dependencies).plan.planDigest === plan.planDigest, "settings_changed");
|
|
35071
|
+
const registered = registerNativeSafety({ home: current2.home, command: current2.command, expectedSHA256: plan.beforeSHA256 });
|
|
35072
|
+
const after = readNativeSafetyRegistration(current2.home);
|
|
35073
|
+
need5(registered.changed && registered.sha256 === plan.desiredSHA256 && after.sha256 === plan.desiredSHA256 && after.record.command === current2.command, "apply_outcome_uncertain");
|
|
35074
|
+
await (dependencies.verify ?? verifyNativeSafetyCommand)(after.record.command, current2.home);
|
|
35075
|
+
need5(readNativeSafetyRegistration(current2.home).sha256 === plan.desiredSHA256, "apply_outcome_uncertain");
|
|
35076
|
+
const receipt = {
|
|
35077
|
+
ok: true,
|
|
35078
|
+
changed: true,
|
|
35079
|
+
operationId,
|
|
35080
|
+
planDigest: plan.planDigest,
|
|
35081
|
+
settingsSHA256: after.sha256,
|
|
35082
|
+
guardVerified: true,
|
|
35083
|
+
...current2.before ? { backup: plan.settingsPath + ".before-" + plan.beforeSHA256 } : {},
|
|
35084
|
+
nativeAdoptionVerified: false
|
|
35085
|
+
};
|
|
35086
|
+
exclusive(join13(directory2, "receipt.json"), JSON.stringify(receipt) + `
|
|
35087
|
+
`);
|
|
35088
|
+
return receipt;
|
|
35089
|
+
} catch {
|
|
35090
|
+
throw new NativeRegistrationError("apply_outcome_uncertain", operationId);
|
|
35091
|
+
}
|
|
35092
|
+
}
|
|
34957
35093
|
var NativeRegistrationError, need5 = (value, code2) => {
|
|
34958
35094
|
if (!value)
|
|
34959
35095
|
throw new NativeRegistrationError(code2);
|
|
34960
|
-
}, sha4 = (value) => createHash17("sha256").update(value).digest("hex"), planNativeSafetyRegistration = (options, dependencies = {}) => planRegistration({ target: options.target }, dependencies), applyNativeSafetyRegistration = (options, dependencies = {}) => applyRegistration({ target: options.target, expectedPlanDigest: options.expectedPlanDigest }, dependencies), planNativeReadinessRegistration = (options) => planRegistration({ target: options
|
|
35096
|
+
}, sha4 = (value) => createHash17("sha256").update(value).digest("hex"), planNativeSafetyRegistration = (options, dependencies = {}) => planRegistration({ target: options.target }, dependencies), applyNativeSafetyRegistration = (options, dependencies = {}) => applyRegistration({ target: options.target, expectedPlanDigest: options.expectedPlanDigest }, dependencies), planNativeReadinessRegistration = (options, sumiDependencies = {}) => options?.target === "sumi" ? planSumiRegistration(sumiDependencies) : planRegistration({ target: options?.target, readiness: true }), applyNativeReadinessRegistration = (options, sumiDependencies = {}) => options?.target === "sumi" ? applySumiRegistration(options.expectedPlanDigest, sumiDependencies) : applyRegistration({ target: options?.target, expectedPlanDigest: options?.expectedPlanDigest, readiness: true });
|
|
34961
35097
|
var init_native_safety_registration = __esm(() => {
|
|
34962
35098
|
init_installer();
|
|
34963
35099
|
init_native_safety2();
|
|
35100
|
+
init_native_safety();
|
|
34964
35101
|
init_native_readiness_command();
|
|
34965
35102
|
init_registration();
|
|
34966
35103
|
NativeRegistrationError = class NativeRegistrationError extends Error {
|
|
@@ -35248,13 +35385,14 @@ async function verifyCodexNativeSafety(options = {}, dependencies = {}) {
|
|
|
35248
35385
|
await rpc.close();
|
|
35249
35386
|
}
|
|
35250
35387
|
}
|
|
35251
|
-
var versions, matcher = "^(Bash|apply_patch|ApplyPatch|functions\\.apply_patch)$", CodexSafetyError, digest3 = (bytes) => createHash21("sha256").update(bytes).digest("hex");
|
|
35388
|
+
var SUPPORTED_CODEX_SAFETY_VERSIONS, versions, matcher = "^(Bash|apply_patch|ApplyPatch|functions\\.apply_patch)$", CodexSafetyError, digest3 = (bytes) => createHash21("sha256").update(bytes).digest("hex");
|
|
35252
35389
|
var init_codex_safety_check = __esm(() => {
|
|
35253
35390
|
init_native_safety();
|
|
35254
35391
|
init_native_readiness_command();
|
|
35255
35392
|
init_native_safety2();
|
|
35256
35393
|
init_native_readiness();
|
|
35257
|
-
|
|
35394
|
+
SUPPORTED_CODEX_SAFETY_VERSIONS = ["codex-cli 0.153.0", "codex-cli 0.154.0", "codex-cli 0.154.0-alpha.6.1", "codex-cli 0.155.0", "codex-cli 0.155.1", "codex-cli 0.156.1", "codex-cli 0.157.0", "codex-cli 0.157.1", "codex-cli 0.158.0", "codex-cli 0.159.0", "codex-cli 0.159.2"];
|
|
35395
|
+
versions = new Set(SUPPORTED_CODEX_SAFETY_VERSIONS);
|
|
35258
35396
|
CodexSafetyError = class CodexSafetyError extends Error {
|
|
35259
35397
|
code;
|
|
35260
35398
|
constructor(code2) {
|
|
@@ -35495,7 +35633,7 @@ var init_codex_safety_trust = __esm(() => {
|
|
|
35495
35633
|
};
|
|
35496
35634
|
});
|
|
35497
35635
|
|
|
35498
|
-
//
|
|
35636
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
|
|
35499
35637
|
var require_error = __commonJS((exports) => {
|
|
35500
35638
|
class CommanderError extends Error {
|
|
35501
35639
|
constructor(exitCode, code2, message) {
|
|
@@ -35519,7 +35657,7 @@ var require_error = __commonJS((exports) => {
|
|
|
35519
35657
|
exports.InvalidArgumentError = InvalidArgumentError;
|
|
35520
35658
|
});
|
|
35521
35659
|
|
|
35522
|
-
//
|
|
35660
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
|
|
35523
35661
|
var require_argument = __commonJS((exports) => {
|
|
35524
35662
|
var { InvalidArgumentError } = require_error();
|
|
35525
35663
|
|
|
@@ -35598,7 +35736,7 @@ var require_argument = __commonJS((exports) => {
|
|
|
35598
35736
|
exports.humanReadableArgName = humanReadableArgName;
|
|
35599
35737
|
});
|
|
35600
35738
|
|
|
35601
|
-
//
|
|
35739
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
|
|
35602
35740
|
var require_help = __commonJS((exports) => {
|
|
35603
35741
|
var { humanReadableArgName } = require_argument();
|
|
35604
35742
|
|
|
@@ -35847,7 +35985,7 @@ var require_help = __commonJS((exports) => {
|
|
|
35847
35985
|
exports.Help = Help;
|
|
35848
35986
|
});
|
|
35849
35987
|
|
|
35850
|
-
//
|
|
35988
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
|
|
35851
35989
|
var require_option = __commonJS((exports) => {
|
|
35852
35990
|
var { InvalidArgumentError } = require_error();
|
|
35853
35991
|
|
|
@@ -35998,7 +36136,7 @@ var require_option = __commonJS((exports) => {
|
|
|
35998
36136
|
exports.DualOptions = DualOptions;
|
|
35999
36137
|
});
|
|
36000
36138
|
|
|
36001
|
-
//
|
|
36139
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
|
|
36002
36140
|
var require_suggestSimilar = __commonJS((exports) => {
|
|
36003
36141
|
var maxDistance = 3;
|
|
36004
36142
|
function editDistance(a, b) {
|
|
@@ -36071,7 +36209,7 @@ var require_suggestSimilar = __commonJS((exports) => {
|
|
|
36071
36209
|
exports.suggestSimilar = suggestSimilar;
|
|
36072
36210
|
});
|
|
36073
36211
|
|
|
36074
|
-
//
|
|
36212
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
|
|
36075
36213
|
var require_command = __commonJS((exports) => {
|
|
36076
36214
|
var EventEmitter = __require("events").EventEmitter;
|
|
36077
36215
|
var childProcess = __require("child_process");
|
|
@@ -37314,7 +37452,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
37314
37452
|
exports.Command = Command;
|
|
37315
37453
|
});
|
|
37316
37454
|
|
|
37317
|
-
//
|
|
37455
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
|
|
37318
37456
|
var require_commander = __commonJS((exports) => {
|
|
37319
37457
|
var { Argument } = require_argument();
|
|
37320
37458
|
var { Command } = require_command();
|
|
@@ -37334,7 +37472,7 @@ var require_commander = __commonJS((exports) => {
|
|
|
37334
37472
|
exports.InvalidOptionArgumentError = InvalidArgumentError;
|
|
37335
37473
|
});
|
|
37336
37474
|
|
|
37337
|
-
//
|
|
37475
|
+
// ../../node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/spinners.json
|
|
37338
37476
|
var require_spinners = __commonJS((exports, module) => {
|
|
37339
37477
|
module.exports = {
|
|
37340
37478
|
dots: {
|
|
@@ -38960,7 +39098,7 @@ var require_spinners = __commonJS((exports, module) => {
|
|
|
38960
39098
|
};
|
|
38961
39099
|
});
|
|
38962
39100
|
|
|
38963
|
-
//
|
|
39101
|
+
// ../../node_modules/.bun/cli-spinners@2.9.2/node_modules/cli-spinners/index.js
|
|
38964
39102
|
var require_cli_spinners = __commonJS((exports, module) => {
|
|
38965
39103
|
var spinners = Object.assign({}, require_spinners());
|
|
38966
39104
|
var spinnersList = Object.keys(spinners);
|
|
@@ -39041,10 +39179,10 @@ var init_redact = __esm(() => {
|
|
|
39041
39179
|
|
|
39042
39180
|
// src/lib/profiles.ts
|
|
39043
39181
|
import { existsSync as existsSync14, mkdirSync as mkdirSync13, readFileSync as readFileSync19, writeFileSync as writeFileSync12, readdirSync as readdirSync8, rmSync, cpSync as cpSync2 } from "fs";
|
|
39044
|
-
import { join as
|
|
39182
|
+
import { join as join29 } from "path";
|
|
39045
39183
|
function getProfilesDir() {
|
|
39046
|
-
const newDir =
|
|
39047
|
-
const oldDir =
|
|
39184
|
+
const newDir = join29(getEffectiveDataRoot(), "profiles");
|
|
39185
|
+
const oldDir = join29(getHomeDir(), ".hooks", "profiles");
|
|
39048
39186
|
if (!existsSync14(newDir) && existsSync14(oldDir)) {
|
|
39049
39187
|
mkdirSync13(newDir, { recursive: true });
|
|
39050
39188
|
cpSync2(oldDir, newDir, { recursive: true });
|
|
@@ -39058,7 +39196,7 @@ function ensureProfilesDir() {
|
|
|
39058
39196
|
}
|
|
39059
39197
|
}
|
|
39060
39198
|
function profilePath(id) {
|
|
39061
|
-
return
|
|
39199
|
+
return join29(getProfilesDir(), `${id}.json`);
|
|
39062
39200
|
}
|
|
39063
39201
|
function shortUuid() {
|
|
39064
39202
|
return crypto.randomUUID().slice(0, 8);
|
|
@@ -39100,7 +39238,7 @@ function listProfiles() {
|
|
|
39100
39238
|
const profiles = [];
|
|
39101
39239
|
for (const file2 of files) {
|
|
39102
39240
|
try {
|
|
39103
|
-
const content = readFileSync19(
|
|
39241
|
+
const content = readFileSync19(join29(dir, file2), "utf-8");
|
|
39104
39242
|
profiles.push(JSON.parse(content));
|
|
39105
39243
|
} catch {}
|
|
39106
39244
|
}
|
|
@@ -39144,18 +39282,18 @@ var init_profiles = __esm(() => {
|
|
|
39144
39282
|
init_app_home();
|
|
39145
39283
|
});
|
|
39146
39284
|
|
|
39147
|
-
//
|
|
39148
|
-
import { isIP } from "net";
|
|
39285
|
+
// ../../node_modules/.bun/@hasna+contracts@1.2.2+944b86d8024e79fa/node_modules/@hasna/contracts/dist/client/transport.js
|
|
39286
|
+
import { isIP as isIP2 } from "net";
|
|
39149
39287
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
39150
39288
|
import { closeSync as closeSync22, fstatSync as fstatSync22, openSync as openSync22, readFileSync as readFileSync22 } from "fs";
|
|
39151
39289
|
import { O_NOFOLLOW as O_NOFOLLOW2, O_NONBLOCK as O_NONBLOCK2, O_RDONLY as O_RDONLY2 } from "constants";
|
|
39152
39290
|
import { hostname as osHostname } from "os";
|
|
39153
39291
|
import { isAbsolute as isAbsolute21, join as join28 } from "path";
|
|
39154
|
-
import { createRequire as
|
|
39292
|
+
import { createRequire as createRequire3 } from "module";
|
|
39155
39293
|
import { fileURLToPath as fileURLToPath22 } from "url";
|
|
39156
39294
|
import { closeSync as closeSync20, fstatSync as fstatSync19, lstatSync as lstatSync24, openSync as openSync20, readFileSync as readFileSync20, realpathSync as realpathSync12, statSync as statSync2 } from "fs";
|
|
39157
39295
|
import { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } from "constants";
|
|
39158
|
-
import { basename as basename9, dirname as dirname22, join as
|
|
39296
|
+
import { basename as basename9, dirname as dirname22, join as join30, relative as relative5, sep as sep6 } from "path";
|
|
39159
39297
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
39160
39298
|
function envToken2(name) {
|
|
39161
39299
|
return name.toUpperCase().replace(/-/g, "_");
|
|
@@ -39230,11 +39368,11 @@ function o(e2, r2, t2) {
|
|
|
39230
39368
|
}
|
|
39231
39369
|
function entryPoint(directory2) {
|
|
39232
39370
|
const root = realpathSync12(directory2);
|
|
39233
|
-
const fd = openSync20(
|
|
39371
|
+
const fd = openSync20(join30(root, "package.json"), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
|
|
39234
39372
|
let pkg;
|
|
39235
39373
|
try {
|
|
39236
39374
|
const stat2 = fstatSync19(fd);
|
|
39237
|
-
if (!stat2.isFile() || stat2.size >
|
|
39375
|
+
if (!stat2.isFile() || stat2.size > MAX_PACKAGE_BYTES3)
|
|
39238
39376
|
throw new Error("Invalid Secrets package metadata");
|
|
39239
39377
|
pkg = JSON.parse(readFileSync20(fd, "utf8"));
|
|
39240
39378
|
} finally {
|
|
@@ -39250,7 +39388,7 @@ function entryPoint(directory2) {
|
|
|
39250
39388
|
if (/[\\%?#\0]/.test(target) || parts.some((part) => !part || part === "." || part === ".." || part === "node_modules")) {
|
|
39251
39389
|
throw new Error("Invalid Secrets import export");
|
|
39252
39390
|
}
|
|
39253
|
-
const file2 = realpathSync12(
|
|
39391
|
+
const file2 = realpathSync12(join30(root, ...parts));
|
|
39254
39392
|
const within = relative5(root, file2);
|
|
39255
39393
|
if (!within || within === ".." || within.startsWith(`..${sep6}`) || !statSync2(file2).isFile()) {
|
|
39256
39394
|
throw new Error("Secrets import export escapes its package or is not a file");
|
|
@@ -39261,7 +39399,7 @@ function resolveInstalledSecrets(parentUrl) {
|
|
|
39261
39399
|
let directory2 = dirname22(fileURLToPath3(parentUrl));
|
|
39262
39400
|
for (;; ) {
|
|
39263
39401
|
if (basename9(directory2) !== "node_modules") {
|
|
39264
|
-
const candidate =
|
|
39402
|
+
const candidate = join30(directory2, "node_modules", PACKAGE);
|
|
39265
39403
|
let absent = false;
|
|
39266
39404
|
try {
|
|
39267
39405
|
lstatSync24(candidate);
|
|
@@ -39381,7 +39519,7 @@ function readAppConfigFile(path) {
|
|
|
39381
39519
|
const uid2 = process.getuid?.() ?? process.geteuid?.();
|
|
39382
39520
|
if (uid2 !== undefined && before.uid !== uid2)
|
|
39383
39521
|
unsafe("the file is not owned by the current user");
|
|
39384
|
-
if (before.size >
|
|
39522
|
+
if (before.size > MAX_CREDENTIAL_FILE_BYTES3)
|
|
39385
39523
|
unsafe("the file exceeds the size limit");
|
|
39386
39524
|
const bytes = readFileSync22(fd);
|
|
39387
39525
|
const after = fstatSync22(fd);
|
|
@@ -39473,13 +39611,13 @@ function sealCredential(fields) {
|
|
|
39473
39611
|
configurable: false
|
|
39474
39612
|
});
|
|
39475
39613
|
}
|
|
39476
|
-
Object.defineProperty(sealed,
|
|
39614
|
+
Object.defineProperty(sealed, INSPECT_CUSTOM3, {
|
|
39477
39615
|
value: () => ({ ...visible, apiKey: "[redacted]" }),
|
|
39478
39616
|
enumerable: false,
|
|
39479
39617
|
writable: false,
|
|
39480
39618
|
configurable: false
|
|
39481
39619
|
});
|
|
39482
|
-
Object.defineProperty(sealed,
|
|
39620
|
+
Object.defineProperty(sealed, CREDENTIAL_SEAL3, {
|
|
39483
39621
|
value: true,
|
|
39484
39622
|
enumerable: false,
|
|
39485
39623
|
writable: false,
|
|
@@ -39510,7 +39648,7 @@ function firstEnvValue(env, keys2) {
|
|
|
39510
39648
|
return null;
|
|
39511
39649
|
}
|
|
39512
39650
|
function isAmbientEnvironment(env) {
|
|
39513
|
-
return env === process.env || env[
|
|
39651
|
+
return env === process.env || env[AMBIENT_ENVIRONMENT3] === true;
|
|
39514
39652
|
}
|
|
39515
39653
|
function defaultKeychainRunner(argv) {
|
|
39516
39654
|
const result = spawnSync2(KEYCHAIN_SECURITY_BIN, [...argv], {
|
|
@@ -39604,7 +39742,7 @@ function snapshotClientEnvironment(name, env) {
|
|
|
39604
39742
|
snapshot2[key] = descriptor.value;
|
|
39605
39743
|
}
|
|
39606
39744
|
if (ambient) {
|
|
39607
|
-
Object.defineProperty(snapshot2,
|
|
39745
|
+
Object.defineProperty(snapshot2, AMBIENT_ENVIRONMENT3, {
|
|
39608
39746
|
value: true,
|
|
39609
39747
|
enumerable: false,
|
|
39610
39748
|
writable: false,
|
|
@@ -39777,7 +39915,7 @@ async function completePointerCredential(name, pointerResolution, env = process.
|
|
|
39777
39915
|
let secretsSdk;
|
|
39778
39916
|
try {
|
|
39779
39917
|
const sdkUrl = resolveInstalledSecrets(import.meta.url);
|
|
39780
|
-
secretsSdk =
|
|
39918
|
+
secretsSdk = requireSecretsSdk3(fileURLToPath22(sdkUrl));
|
|
39781
39919
|
} catch {
|
|
39782
39920
|
throw new CredentialResolutionError(name, `${pointerEnvKey} names vault item '${vaultKey}', but the secrets SDK (@hasna/secrets) is not installed ` + `in this process. A vault pointer is TERMINAL: install @hasna/secrets to resolve it, or unset ${pointerEnvKey}.`, [pointerEnvKey]);
|
|
39783
39921
|
}
|
|
@@ -39861,7 +39999,7 @@ function canonicalAuthorityHostname(authority) {
|
|
|
39861
39999
|
}
|
|
39862
40000
|
assertCanonicalPort(portSuffix.slice(1));
|
|
39863
40001
|
}
|
|
39864
|
-
if (
|
|
40002
|
+
if (isIP2(rawHostname.slice(1, -1)) !== 6) {
|
|
39865
40003
|
throw new Error("API URL authority must contain a canonical IPv6 literal.");
|
|
39866
40004
|
}
|
|
39867
40005
|
} else {
|
|
@@ -39877,7 +40015,7 @@ function canonicalAuthorityHostname(authority) {
|
|
|
39877
40015
|
} else {
|
|
39878
40016
|
rawHostname = authority;
|
|
39879
40017
|
}
|
|
39880
|
-
const ipVersion =
|
|
40018
|
+
const ipVersion = isIP2(rawHostname);
|
|
39881
40019
|
const numericAddressParts = rawHostname.split(".");
|
|
39882
40020
|
const looksLikeNonCanonicalIpv4 = numericAddressParts.every((part) => /^(?:0x[0-9a-f]+|[0-9]+)$/i.test(part));
|
|
39883
40021
|
if (ipVersion !== 4 && looksLikeNonCanonicalIpv4 || ipVersion !== 4 && !isValidDnsDomain(rawHostname.toLowerCase())) {
|
|
@@ -40013,9 +40151,9 @@ function credentialDiskSourcesForMessage(name, env) {
|
|
|
40013
40151
|
const paths = credentialDiskSources(name, env);
|
|
40014
40152
|
return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
|
|
40015
40153
|
}
|
|
40016
|
-
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets",
|
|
40154
|
+
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", PACKAGE = "@hasna/secrets", MAX_PACKAGE_BYTES3, CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES3, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM3, CREDENTIAL_SEAL3, AMBIENT_ENVIRONMENT3, requireSecretsSdk3, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, ClientTransportConfigurationError, IDEMPOTENT_METHODS3, AUTHORITY_OVERRIDE_HEADERS3;
|
|
40017
40155
|
var init_transport = __esm(() => {
|
|
40018
|
-
|
|
40156
|
+
MAX_PACKAGE_BYTES3 = 1024 * 1024;
|
|
40019
40157
|
CredentialResolutionError = class CredentialResolutionError extends Error {
|
|
40020
40158
|
appName;
|
|
40021
40159
|
attempted;
|
|
@@ -40034,16 +40172,16 @@ var init_transport = __esm(() => {
|
|
|
40034
40172
|
this.path = path;
|
|
40035
40173
|
}
|
|
40036
40174
|
};
|
|
40037
|
-
|
|
40175
|
+
MAX_CREDENTIAL_FILE_BYTES3 = 64 * 1024;
|
|
40038
40176
|
SAFE_APP_SLUG = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
40039
40177
|
SAFE_PROFILE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
|
|
40040
40178
|
ILLEGAL_IN_HEADER_VALUE = /[^\t\x20-\x7e]/;
|
|
40041
40179
|
VAULT_POINTER_SHAPE = /^[a-z0-9][a-z0-9-]*(?:\/[a-z0-9][a-z0-9-_.]*){2,}$/;
|
|
40042
40180
|
CREDENTIAL_SHAPED_KEY = /(?:^|_)(?:API_KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|AUTH)(?:_|$)/;
|
|
40043
|
-
|
|
40044
|
-
|
|
40045
|
-
|
|
40046
|
-
|
|
40181
|
+
INSPECT_CUSTOM3 = Symbol.for("nodejs.util.inspect.custom");
|
|
40182
|
+
CREDENTIAL_SEAL3 = Symbol.for("hasna:contracts:sealedCredential");
|
|
40183
|
+
AMBIENT_ENVIRONMENT3 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
40184
|
+
requireSecretsSdk3 = createRequire3(import.meta.url);
|
|
40047
40185
|
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
40048
40186
|
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
40049
40187
|
ClientTransportConfigurationError = class ClientTransportConfigurationError extends Error {
|
|
@@ -40056,8 +40194,8 @@ var init_transport = __esm(() => {
|
|
|
40056
40194
|
this.sources = Object.freeze([...sources]);
|
|
40057
40195
|
}
|
|
40058
40196
|
};
|
|
40059
|
-
|
|
40060
|
-
|
|
40197
|
+
IDEMPOTENT_METHODS3 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
40198
|
+
AUTHORITY_OVERRIDE_HEADERS3 = new Set([
|
|
40061
40199
|
"host",
|
|
40062
40200
|
":authority",
|
|
40063
40201
|
"forwarded",
|
|
@@ -40568,7 +40706,7 @@ __export(exports_run, {
|
|
|
40568
40706
|
});
|
|
40569
40707
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
40570
40708
|
import { rmSync as rmSync2, writeFileSync as writeFileSync13 } from "fs";
|
|
40571
|
-
import { basename as basename11, dirname as dirname24, isAbsolute as isAbsolute25, join as
|
|
40709
|
+
import { basename as basename11, dirname as dirname24, isAbsolute as isAbsolute25, join as join31 } from "path";
|
|
40572
40710
|
function extensionOf(scriptPath) {
|
|
40573
40711
|
const base = basename11(scriptPath);
|
|
40574
40712
|
const dot = base.lastIndexOf(".");
|
|
@@ -40639,7 +40777,7 @@ async function readPipeWithDeadline(stream, deadlineMs) {
|
|
|
40639
40777
|
async function executeVerifiedScript(options) {
|
|
40640
40778
|
const scriptDir = dirname24(options.scriptPath);
|
|
40641
40779
|
const interpreter = interpreterFor(options.name, options.scriptPath, options.content);
|
|
40642
|
-
const tempPath =
|
|
40780
|
+
const tempPath = join31(scriptDir, `.hooks-verified-${randomBytes2(12).toString("hex")}.${interpreter.tempExt}`);
|
|
40643
40781
|
let proc = null;
|
|
40644
40782
|
let timedOut = false;
|
|
40645
40783
|
const timeoutTimer = options.timeout ? setTimeout(() => {
|
|
@@ -40731,10 +40869,10 @@ __export(exports_custom_install, {
|
|
|
40731
40869
|
ensureCustomDir: () => ensureCustomDir
|
|
40732
40870
|
});
|
|
40733
40871
|
import { existsSync as existsSync16, mkdirSync as mkdirSync14, mkdtempSync, readFileSync as readFileSync21, rmSync as rmSync4 } from "fs";
|
|
40734
|
-
import { join as
|
|
40872
|
+
import { join as join32 } from "path";
|
|
40735
40873
|
import { tmpdir as tmpdir2 } from "os";
|
|
40736
40874
|
function manifestAt(dir) {
|
|
40737
|
-
const path =
|
|
40875
|
+
const path = join32(dir, "manifest.json");
|
|
40738
40876
|
if (!existsSync16(path))
|
|
40739
40877
|
return;
|
|
40740
40878
|
try {
|
|
@@ -40757,8 +40895,8 @@ function writeFromManifest(manifest, srcDir, source, kind) {
|
|
|
40757
40895
|
return { name, version: manifest.version, kind, source, dir, scriptPath };
|
|
40758
40896
|
}
|
|
40759
40897
|
async function cloneToTemp(gitUrl) {
|
|
40760
|
-
const tmp = mkdtempSync(
|
|
40761
|
-
const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl,
|
|
40898
|
+
const tmp = mkdtempSync(join32(tmpdir2(), "hooks-install-"));
|
|
40899
|
+
const proc = Bun.spawn(["git", "clone", "--depth", "1", "--quiet", gitUrl, join32(tmp, "repo")], {
|
|
40762
40900
|
stdout: "pipe",
|
|
40763
40901
|
stderr: "pipe"
|
|
40764
40902
|
});
|
|
@@ -40771,7 +40909,7 @@ async function cloneToTemp(gitUrl) {
|
|
|
40771
40909
|
rmSync4(tmp, { recursive: true, force: true });
|
|
40772
40910
|
throw new Error(`git clone failed (${exitCode}): ${stderr.trim()}`);
|
|
40773
40911
|
}
|
|
40774
|
-
return
|
|
40912
|
+
return join32(tmp, "repo");
|
|
40775
40913
|
}
|
|
40776
40914
|
function isGitUrl(value) {
|
|
40777
40915
|
return value.startsWith("git@") || value.startsWith("ssh://") || value.startsWith("file://") || value.endsWith(".git");
|
|
@@ -42010,11 +42148,11 @@ __export(exports_serve, {
|
|
|
42010
42148
|
DEFAULT_SERVE_PORT: () => DEFAULT_SERVE_PORT
|
|
42011
42149
|
});
|
|
42012
42150
|
import { readFileSync as readFileSync25 } from "fs";
|
|
42013
|
-
import { dirname as dirname25, join as
|
|
42151
|
+
import { dirname as dirname25, join as join33 } from "path";
|
|
42014
42152
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
42015
42153
|
function packageVersion() {
|
|
42016
42154
|
try {
|
|
42017
|
-
const pkgPath =
|
|
42155
|
+
const pkgPath = join33(dirname25(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
42018
42156
|
return JSON.parse(readFileSync25(pkgPath, "utf-8")).version || "0.0.0";
|
|
42019
42157
|
} catch {
|
|
42020
42158
|
return "0.0.0";
|
|
@@ -42316,7 +42454,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
42316
42454
|
import { z as z3 } from "zod";
|
|
42317
42455
|
import { createServer } from "http";
|
|
42318
42456
|
import { existsSync as existsSync17, readFileSync as readFileSync26 } from "fs";
|
|
42319
|
-
import { join as
|
|
42457
|
+
import { join as join34, dirname as dirname26 } from "path";
|
|
42320
42458
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
42321
42459
|
async function runVerifiedHook(name, stdin, timeoutMs) {
|
|
42322
42460
|
const { resolveHook: resolveHook2, resolveScriptPath: resolveScriptPath2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
|
|
@@ -42550,7 +42688,7 @@ function createHooksServer() {
|
|
|
42550
42688
|
continue;
|
|
42551
42689
|
}
|
|
42552
42690
|
const hookDir = getHookPath(name);
|
|
42553
|
-
if (!existsSync17(
|
|
42691
|
+
if (!existsSync17(join34(hookDir, "src", "hook.ts"))) {
|
|
42554
42692
|
issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
|
|
42555
42693
|
hookHealthy = false;
|
|
42556
42694
|
}
|
|
@@ -42558,7 +42696,7 @@ function createHooksServer() {
|
|
|
42558
42696
|
if (meta3 && settingsExist) {
|
|
42559
42697
|
try {
|
|
42560
42698
|
const settings = JSON.parse(readFileSync26(settingsPath, "utf-8"));
|
|
42561
|
-
if (!hookRegisteredInSettings(settings, name, meta3.event, meta3
|
|
42699
|
+
if (!hookRegisteredInSettings(settings, name, meta3.event, matcherFor(meta3, "claude"))) {
|
|
42562
42700
|
const eventName = meta3.event.split(":")[0];
|
|
42563
42701
|
issues.push({ hook: name, issue: `Not registered under correct event (${eventName})`, severity: "error" });
|
|
42564
42702
|
hookHealthy = false;
|
|
@@ -42594,7 +42732,7 @@ function createHooksServer() {
|
|
|
42594
42732
|
return { content: [{ type: "text", text: JSON.stringify({ error: `Hook '${name}' not found` }) }] };
|
|
42595
42733
|
}
|
|
42596
42734
|
const hookPath = getHookPath(name);
|
|
42597
|
-
const readmePath =
|
|
42735
|
+
const readmePath = join34(hookPath, "README.md");
|
|
42598
42736
|
let readme = "";
|
|
42599
42737
|
if (existsSync17(readmePath)) {
|
|
42600
42738
|
readme = readFileSync26(readmePath, "utf-8");
|
|
@@ -43324,7 +43462,7 @@ var init_server = __esm(() => {
|
|
|
43324
43462
|
pkg = { name: "@hasna/hooks", version: "0.0.0" };
|
|
43325
43463
|
try {
|
|
43326
43464
|
for (const rel of ["../../package.json", "../package.json", "../../../package.json"]) {
|
|
43327
|
-
const p =
|
|
43465
|
+
const p = join34(__dirname3, rel);
|
|
43328
43466
|
if (existsSync17(p)) {
|
|
43329
43467
|
pkg = JSON.parse(readFileSync26(p, "utf-8"));
|
|
43330
43468
|
break;
|
|
@@ -43403,7 +43541,7 @@ __export(exports_native_readiness_binding, {
|
|
|
43403
43541
|
import { createHash as createHash25, randomUUID as randomUUID8 } from "crypto";
|
|
43404
43542
|
import { closeSync as closeSync21, constants as constants19, fsyncSync as fsyncSync8, lstatSync as lstatSync25, mkdirSync as mkdirSync15, openSync as openSync21, realpathSync as realpathSync14, writeFileSync as writeFileSync14 } from "fs";
|
|
43405
43543
|
import { homedir as homedir15 } from "os";
|
|
43406
|
-
import { dirname as dirname27, join as
|
|
43544
|
+
import { dirname as dirname27, join as join35 } from "path";
|
|
43407
43545
|
function need10(value, code2) {
|
|
43408
43546
|
if (!value)
|
|
43409
43547
|
throw new ReadinessBindingError(code2);
|
|
@@ -43461,7 +43599,7 @@ async function registerTrashReadinessBinding(input2, expectedSHA256) {
|
|
|
43461
43599
|
const operationId = randomUUID8();
|
|
43462
43600
|
let directory2 = home;
|
|
43463
43601
|
for (const part of [".hasna", "hooks", "native", "trash-readiness"]) {
|
|
43464
|
-
directory2 =
|
|
43602
|
+
directory2 = join35(directory2, part);
|
|
43465
43603
|
try {
|
|
43466
43604
|
mkdirSync15(directory2, { mode: 448 });
|
|
43467
43605
|
syncDirectory4(dirname27(directory2));
|
|
@@ -43471,12 +43609,12 @@ async function registerTrashReadinessBinding(input2, expectedSHA256) {
|
|
|
43471
43609
|
}
|
|
43472
43610
|
safeDirectory4(directory2);
|
|
43473
43611
|
}
|
|
43474
|
-
const operation =
|
|
43612
|
+
const operation = join35(directory2, operationId);
|
|
43475
43613
|
mkdirSync15(operation, { mode: 448 });
|
|
43476
43614
|
syncDirectory4(directory2);
|
|
43477
43615
|
if (before)
|
|
43478
|
-
exclusive3(
|
|
43479
|
-
exclusive3(
|
|
43616
|
+
exclusive3(join35(operation, "binding.before"), before.raw);
|
|
43617
|
+
exclusive3(join35(operation, "intent.json"), JSON.stringify({ operationId, target, expectedSHA256, desiredSHA256: digest4 }) + `
|
|
43480
43618
|
`);
|
|
43481
43619
|
try {
|
|
43482
43620
|
need10((read4()?.sha256 ?? "absent") === expectedSHA256, "binding_changed");
|
|
@@ -43490,7 +43628,7 @@ async function registerTrashReadinessBinding(input2, expectedSHA256) {
|
|
|
43490
43628
|
syncDirectory4(directory2);
|
|
43491
43629
|
need10(read4()?.sha256 === digest4, "binding_changed");
|
|
43492
43630
|
const receipt = { ok: true, changed: true, operationId, path: target, sha256: digest4, configurationReady: true, nativeAdoptionVerified: false };
|
|
43493
|
-
exclusive3(
|
|
43631
|
+
exclusive3(join35(operation, "receipt.json"), JSON.stringify(receipt) + `
|
|
43494
43632
|
`);
|
|
43495
43633
|
return receipt;
|
|
43496
43634
|
} catch {
|
|
@@ -43514,11 +43652,12 @@ var init_native_readiness_binding = __esm(() => {
|
|
|
43514
43652
|
|
|
43515
43653
|
// src/cli/index.tsx
|
|
43516
43654
|
init_native_safety_registration();
|
|
43517
|
-
import { resolve as
|
|
43655
|
+
import { resolve as resolve23 } from "path";
|
|
43518
43656
|
|
|
43519
43657
|
// src/lib/claude-safety-check.ts
|
|
43520
43658
|
init_native_safety();
|
|
43521
43659
|
init_native_safety2();
|
|
43660
|
+
init_registry();
|
|
43522
43661
|
import { constants as constants15, closeSync as closeSync15, fstatSync as fstatSync7, lstatSync as lstatSync10, openSync as openSync15, readFileSync as readFileSync12, realpathSync as realpathSync8 } from "fs";
|
|
43523
43662
|
import { createHash as createHash19 } from "crypto";
|
|
43524
43663
|
import { dirname as dirname17, isAbsolute as isAbsolute17, join as join17, resolve as resolve18 } from "path";
|
|
@@ -43602,7 +43741,7 @@ async function verifyClaudeSafetyConfiguration(options = {}, dependencies = {})
|
|
|
43602
43741
|
need7(!/^(?:hooks run trash-guard|hook-trash-guard)(?:\s|$)/.test(handler.command.trim()), "guard_definition_invalid");
|
|
43603
43742
|
if (binding?.name !== "trash-guard")
|
|
43604
43743
|
continue;
|
|
43605
|
-
need7(binding.home === home && event === "PreToolUse" && handler.type === "command" && group.matcher ===
|
|
43744
|
+
need7(binding.home === home && event === "PreToolUse" && handler.type === "command" && group.matcher === CLAUDE_TRASH_GUARD_MATCHER && handler.timeout === 10 && (handler.async === undefined || handler.async === false) && handler.asyncRewake !== true, "guard_definition_invalid");
|
|
43606
43745
|
guards.push({ command: handler.command, path: file2.path });
|
|
43607
43746
|
}
|
|
43608
43747
|
}
|
|
@@ -43633,16 +43772,25 @@ async function verifyClaudeSafetyConfiguration(options = {}, dependencies = {})
|
|
|
43633
43772
|
// src/cli/index.tsx
|
|
43634
43773
|
init_codex_safety_trust();
|
|
43635
43774
|
|
|
43636
|
-
//
|
|
43775
|
+
// ../events/dist/commander.js
|
|
43637
43776
|
import { chmod, mkdir, readFile as readFile2, rename, writeFile } from "fs/promises";
|
|
43638
43777
|
import { Buffer as Buffer2 } from "buffer";
|
|
43778
|
+
import { existsSync as existsSync22 } from "fs";
|
|
43779
|
+
import { join as join22 } from "path";
|
|
43639
43780
|
import { existsSync as existsSync13 } from "fs";
|
|
43640
43781
|
import { homedir as homedir13 } from "os";
|
|
43641
|
-
import { join as join20 } from "path";
|
|
43782
|
+
import { join as join20, resolve as resolve20 } from "path";
|
|
43783
|
+
import { homedir as pathsResolverHomedir3 } from "os";
|
|
43784
|
+
import { join as pathsResolverJoin3 } from "path";
|
|
43642
43785
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
43786
|
+
import { lookup as dnsLookup } from "dns/promises";
|
|
43787
|
+
import { isIP } from "net";
|
|
43643
43788
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
43644
43789
|
import { spawn as spawn3 } from "child_process";
|
|
43790
|
+
import { request as nodeHttpRequest } from "http";
|
|
43791
|
+
import { request as nodeHttpsRequest } from "https";
|
|
43645
43792
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
43793
|
+
import { createRequire as createRequire2 } from "module";
|
|
43646
43794
|
function getPathValue(input2, path) {
|
|
43647
43795
|
return path.split(".").reduce((value, part) => {
|
|
43648
43796
|
if (value && typeof value === "object" && part in value) {
|
|
@@ -43738,13 +43886,103 @@ function channelMatchesEvent(channel, event) {
|
|
|
43738
43886
|
return true;
|
|
43739
43887
|
return channel.filters.some((filter) => eventMatchesFilter(event, filter));
|
|
43740
43888
|
}
|
|
43889
|
+
var PATHS_RESOLVER_KIND_ENV2 = {
|
|
43890
|
+
config: "HASNA_CONFIG_HOME",
|
|
43891
|
+
data: "HASNA_DATA_HOME",
|
|
43892
|
+
state: "HASNA_STATE_HOME",
|
|
43893
|
+
cache: "HASNA_CACHE_HOME"
|
|
43894
|
+
};
|
|
43895
|
+
var PATHS_RESOLVER_APP_SLUG_RE3 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
43896
|
+
function pathsResolverAssertApp3(app) {
|
|
43897
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
43898
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
43899
|
+
}
|
|
43900
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE3.test(app)) {
|
|
43901
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
43902
|
+
}
|
|
43903
|
+
}
|
|
43904
|
+
function pathsResolverAssertKind2(kind) {
|
|
43905
|
+
if (!Object.keys(PATHS_RESOLVER_KIND_ENV2).includes(kind)) {
|
|
43906
|
+
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV2).join(", ")}`);
|
|
43907
|
+
}
|
|
43908
|
+
}
|
|
43909
|
+
function pathsResolverBaseDir2(kind, options) {
|
|
43910
|
+
pathsResolverAssertKind2(kind);
|
|
43911
|
+
const env = options.env ?? process.env;
|
|
43912
|
+
const override = env[PATHS_RESOLVER_KIND_ENV2[kind]];
|
|
43913
|
+
if (typeof override === "string" && override.length > 0)
|
|
43914
|
+
return override;
|
|
43915
|
+
const home = options.home ?? pathsResolverHomedir3();
|
|
43916
|
+
const platform = options.platform ?? process.platform;
|
|
43917
|
+
if (platform === "darwin") {
|
|
43918
|
+
switch (kind) {
|
|
43919
|
+
case "config":
|
|
43920
|
+
case "data":
|
|
43921
|
+
return pathsResolverJoin3(home, "Library", "Application Support", "Hasna");
|
|
43922
|
+
case "cache":
|
|
43923
|
+
return pathsResolverJoin3(home, "Library", "Caches", "Hasna");
|
|
43924
|
+
case "state":
|
|
43925
|
+
return pathsResolverJoin3(home, "Library", "Logs", "Hasna");
|
|
43926
|
+
}
|
|
43927
|
+
}
|
|
43928
|
+
switch (kind) {
|
|
43929
|
+
case "config":
|
|
43930
|
+
return pathsResolverJoin3(home, ".config", "hasna");
|
|
43931
|
+
case "data":
|
|
43932
|
+
return pathsResolverJoin3(home, ".local", "share", "hasna");
|
|
43933
|
+
case "state":
|
|
43934
|
+
return pathsResolverJoin3(home, ".local", "state", "hasna");
|
|
43935
|
+
case "cache":
|
|
43936
|
+
return pathsResolverJoin3(home, ".cache", "hasna");
|
|
43937
|
+
}
|
|
43938
|
+
}
|
|
43939
|
+
function pathsResolverResolve2(kind, options) {
|
|
43940
|
+
pathsResolverAssertApp3(options.app);
|
|
43941
|
+
const appSegment = options.internal === true ? pathsResolverJoin3("internal", options.app) : options.app;
|
|
43942
|
+
return pathsResolverJoin3(pathsResolverBaseDir2(kind, options), appSegment);
|
|
43943
|
+
}
|
|
43944
|
+
function dataDir3(options) {
|
|
43945
|
+
return pathsResolverResolve2("data", options);
|
|
43946
|
+
}
|
|
43741
43947
|
var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR";
|
|
43742
43948
|
var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
|
|
43949
|
+
var EVENTS_STORE_SENTINEL_FILE = "events.json";
|
|
43950
|
+
function effectiveHome2() {
|
|
43951
|
+
return process.env["HOME"] || process.env["USERPROFILE"] || homedir13();
|
|
43952
|
+
}
|
|
43953
|
+
function legacyHomeDir() {
|
|
43954
|
+
return join20(effectiveHome2(), ".hasna", "events");
|
|
43955
|
+
}
|
|
43956
|
+
function resolverHome() {
|
|
43957
|
+
return dataDir3({ app: "events", home: effectiveHome2() || undefined });
|
|
43958
|
+
}
|
|
43959
|
+
function adoptResolverHome(resolved, env = process.env) {
|
|
43960
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
43961
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
43962
|
+
return true;
|
|
43963
|
+
return existsSync13(join20(resolved, EVENTS_STORE_SENTINEL_FILE));
|
|
43964
|
+
}
|
|
43965
|
+
function exactEventsHome() {
|
|
43966
|
+
const dir = process.env[HASNA_EVENTS_DIR_ENV];
|
|
43967
|
+
if (dir && dir.trim())
|
|
43968
|
+
return dir.trim();
|
|
43969
|
+
const home = process.env[HASNA_EVENTS_HOME_ENV];
|
|
43970
|
+
if (home && home.trim())
|
|
43971
|
+
return home.trim();
|
|
43972
|
+
return;
|
|
43973
|
+
}
|
|
43974
|
+
function getEventsHome() {
|
|
43975
|
+
const exact2 = exactEventsHome();
|
|
43976
|
+
if (exact2)
|
|
43977
|
+
return resolve20(exact2);
|
|
43978
|
+
const resolved = resolverHome();
|
|
43979
|
+
return adoptResolverHome(resolved) ? resolve20(resolved) : resolve20(legacyHomeDir());
|
|
43980
|
+
}
|
|
43743
43981
|
var LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:";
|
|
43744
43982
|
var DEFAULT_EVENT_PAGE_LIMIT = 100;
|
|
43745
43983
|
var MAX_EVENT_PAGE_LIMIT = 1000;
|
|
43746
43984
|
function getEventsDataDir(override) {
|
|
43747
|
-
return override ||
|
|
43985
|
+
return override || getEventsHome();
|
|
43748
43986
|
}
|
|
43749
43987
|
function getActiveEventsDirEnv() {
|
|
43750
43988
|
if (process.env[HASNA_EVENTS_DIR_ENV])
|
|
@@ -43760,12 +43998,12 @@ class JsonEventsStore {
|
|
|
43760
43998
|
channelsPath;
|
|
43761
43999
|
eventsPath;
|
|
43762
44000
|
deliveriesPath;
|
|
43763
|
-
constructor(
|
|
43764
|
-
this.dataDir =
|
|
43765
|
-
this.runtime = localJsonRuntime(
|
|
43766
|
-
this.channelsPath =
|
|
43767
|
-
this.eventsPath =
|
|
43768
|
-
this.deliveriesPath =
|
|
44001
|
+
constructor(dataDir22 = getEventsDataDir()) {
|
|
44002
|
+
this.dataDir = dataDir22;
|
|
44003
|
+
this.runtime = localJsonRuntime(dataDir22);
|
|
44004
|
+
this.channelsPath = join22(dataDir22, "channels.json");
|
|
44005
|
+
this.eventsPath = join22(dataDir22, "events.json");
|
|
44006
|
+
this.deliveriesPath = join22(dataDir22, "deliveries.json");
|
|
43769
44007
|
}
|
|
43770
44008
|
async init() {
|
|
43771
44009
|
await mkdir(this.dataDir, { recursive: true, mode: 448 });
|
|
@@ -43882,7 +44120,7 @@ class JsonEventsStore {
|
|
|
43882
44120
|
};
|
|
43883
44121
|
}
|
|
43884
44122
|
async ensureArrayFile(path) {
|
|
43885
|
-
if (!
|
|
44123
|
+
if (!existsSync22(path)) {
|
|
43886
44124
|
await writeFile(path, `[]
|
|
43887
44125
|
`, { encoding: "utf-8", mode: 384 });
|
|
43888
44126
|
}
|
|
@@ -43912,7 +44150,7 @@ class JsonEventsStore {
|
|
|
43912
44150
|
});
|
|
43913
44151
|
}
|
|
43914
44152
|
}
|
|
43915
|
-
function localJsonRuntime(
|
|
44153
|
+
function localJsonRuntime(dataDir22 = getEventsDataDir()) {
|
|
43916
44154
|
return {
|
|
43917
44155
|
mode: "local-files",
|
|
43918
44156
|
name: "json-events-store",
|
|
@@ -43925,7 +44163,7 @@ function localJsonRuntime(dataDir3 = getEventsDataDir()) {
|
|
|
43925
44163
|
durable: true,
|
|
43926
44164
|
idempotency: "best-effort-local",
|
|
43927
44165
|
replayCursors: true,
|
|
43928
|
-
description: `Local JSON files in ${
|
|
44166
|
+
description: `Local JSON files in ${dataDir22}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
|
|
43929
44167
|
};
|
|
43930
44168
|
}
|
|
43931
44169
|
function encodeLocalJsonEventCursor(offset, options = {}) {
|
|
@@ -43989,8 +44227,8 @@ function assertCursorFilter(name, cursorValue, optionValue) {
|
|
|
43989
44227
|
function findEventByIdentity(events2, identity3) {
|
|
43990
44228
|
return events2.find((event) => identity3.id !== undefined && event.id === identity3.id || identity3.dedupeKey !== undefined && event.dedupeKey === identity3.dedupeKey);
|
|
43991
44229
|
}
|
|
43992
|
-
async function getEventsStatus(
|
|
43993
|
-
const store = new JsonEventsStore(
|
|
44230
|
+
async function getEventsStatus(dataDir22) {
|
|
44231
|
+
const store = new JsonEventsStore(dataDir22);
|
|
43994
44232
|
await store.init();
|
|
43995
44233
|
const [channels, events2, deliveries] = await Promise.all([
|
|
43996
44234
|
store.listChannels(),
|
|
@@ -44032,9 +44270,9 @@ async function getEventsStatus(dataDir3) {
|
|
|
44032
44270
|
}
|
|
44033
44271
|
};
|
|
44034
44272
|
}
|
|
44035
|
-
function statusFile(
|
|
44036
|
-
const path =
|
|
44037
|
-
return { path, exists:
|
|
44273
|
+
function statusFile(dataDir22, fileName, records) {
|
|
44274
|
+
const path = join22(dataDir22, fileName);
|
|
44275
|
+
return { path, exists: existsSync22(path), records };
|
|
44038
44276
|
}
|
|
44039
44277
|
var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
44040
44278
|
function buildSignatureBase(timestamp, body) {
|
|
@@ -44044,6 +44282,214 @@ function signPayload(secret, timestamp, body) {
|
|
|
44044
44282
|
const digest4 = createHmac("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
|
|
44045
44283
|
return `sha256=${digest4}`;
|
|
44046
44284
|
}
|
|
44285
|
+
var DEFAULT_MAX_REDIRECTS = 5;
|
|
44286
|
+
var IPV4_PRIVATE_RANGES = [
|
|
44287
|
+
[0, 16777215],
|
|
44288
|
+
[167772160, 184549375],
|
|
44289
|
+
[1681915904, 1686110207],
|
|
44290
|
+
[2130706432, 2147483647],
|
|
44291
|
+
[2851995648, 2852061183],
|
|
44292
|
+
[2886729728, 2887778303],
|
|
44293
|
+
[3221225472, 3221225727],
|
|
44294
|
+
[3221225984, 3221226239],
|
|
44295
|
+
[3227017984, 3227018239],
|
|
44296
|
+
[3232235520, 3232301055],
|
|
44297
|
+
[3323068416, 3323199487],
|
|
44298
|
+
[3325256704, 3325256959],
|
|
44299
|
+
[3405803776, 3405804031],
|
|
44300
|
+
[3758096384, 4294967295]
|
|
44301
|
+
];
|
|
44302
|
+
var IPV6_SPECIAL_PREFIXES = [
|
|
44303
|
+
{ groups: [0, 0, 0, 0, 0, 0, 0, 0], bits: 128 },
|
|
44304
|
+
{ groups: [0, 0, 0, 0, 0, 0, 0, 1], bits: 128 },
|
|
44305
|
+
{ groups: [0, 0, 0, 0, 0, 65535, 0, 0], bits: 96 },
|
|
44306
|
+
{ groups: [100, 65435, 0, 0, 0, 0, 0, 0], bits: 96 },
|
|
44307
|
+
{ groups: [256, 0, 0, 0, 0, 0, 0, 0], bits: 64 },
|
|
44308
|
+
{ groups: [8193, 0, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
44309
|
+
{ groups: [8193, 2, 0, 0, 0, 0, 0, 0], bits: 48 },
|
|
44310
|
+
{ groups: [8193, 16, 0, 0, 0, 0, 0, 0], bits: 28 },
|
|
44311
|
+
{ groups: [8193, 3512, 0, 0, 0, 0, 0, 0], bits: 32 },
|
|
44312
|
+
{ groups: [8194, 0, 0, 0, 0, 0, 0, 0], bits: 16 },
|
|
44313
|
+
{ groups: [16383, 0, 0, 0, 0, 0, 0, 0], bits: 20 },
|
|
44314
|
+
{ groups: [64512, 0, 0, 0, 0, 0, 0, 0], bits: 7 },
|
|
44315
|
+
{ groups: [65152, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
44316
|
+
{ groups: [65216, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
|
|
44317
|
+
{ groups: [65280, 0, 0, 0, 0, 0, 0, 0], bits: 8 }
|
|
44318
|
+
];
|
|
44319
|
+
function isPrivateAddress(address) {
|
|
44320
|
+
const normalized = stripZoneId(address);
|
|
44321
|
+
const version2 = isIP(normalized);
|
|
44322
|
+
if (version2 === 4) {
|
|
44323
|
+
const integer3 = ipv4ToInt(normalized);
|
|
44324
|
+
if (integer3 === undefined)
|
|
44325
|
+
return true;
|
|
44326
|
+
return IPV4_PRIVATE_RANGES.some(([low, high]) => integer3 >= low && integer3 <= high);
|
|
44327
|
+
}
|
|
44328
|
+
if (version2 === 6) {
|
|
44329
|
+
const groups = ipv6Groups(normalized);
|
|
44330
|
+
if (!groups)
|
|
44331
|
+
return true;
|
|
44332
|
+
for (const prefix3 of IPV6_SPECIAL_PREFIXES) {
|
|
44333
|
+
if (!ipv6MatchesPrefix(groups, prefix3.groups, prefix3.bits))
|
|
44334
|
+
continue;
|
|
44335
|
+
if (prefix3.bits === 96 && groups[5] === 65535) {
|
|
44336
|
+
return isPrivateAddress(ipv4IntToString(groups[6] << 16 | groups[7]));
|
|
44337
|
+
}
|
|
44338
|
+
if (prefix3.bits === 16 && groups[0] === 8194) {
|
|
44339
|
+
return isPrivateAddress(ipv4IntToString(groups[1] << 16 | groups[2]));
|
|
44340
|
+
}
|
|
44341
|
+
return true;
|
|
44342
|
+
}
|
|
44343
|
+
return false;
|
|
44344
|
+
}
|
|
44345
|
+
return true;
|
|
44346
|
+
}
|
|
44347
|
+
async function resolveWebhookTarget(url2, policy = {}) {
|
|
44348
|
+
const hostname3 = normalizeHostname(url2.hostname);
|
|
44349
|
+
const allowlist = (policy.allowPrivateHosts ?? []).map((entry) => normalizeHostname(entry.toLowerCase()));
|
|
44350
|
+
if (allowlist.includes(hostname3)) {
|
|
44351
|
+
const version22 = isIP(hostname3);
|
|
44352
|
+
if (version22 === 4 || version22 === 6) {
|
|
44353
|
+
return { hostname: hostname3, addresses: [hostname3] };
|
|
44354
|
+
}
|
|
44355
|
+
const lookup2 = policy.lookup ?? defaultTargetLookup;
|
|
44356
|
+
let resolved2;
|
|
44357
|
+
try {
|
|
44358
|
+
resolved2 = await lookup2(hostname3);
|
|
44359
|
+
} catch {
|
|
44360
|
+
throw new Error(`Webhook target ${hostname3} could not be resolved`);
|
|
44361
|
+
}
|
|
44362
|
+
if (!Array.isArray(resolved2) || resolved2.length === 0) {
|
|
44363
|
+
throw new Error(`Webhook target ${hostname3} resolved to no addresses`);
|
|
44364
|
+
}
|
|
44365
|
+
const addresses = resolved2.map((entry) => normalizeHostname(entry.address));
|
|
44366
|
+
return { hostname: hostname3, addresses };
|
|
44367
|
+
}
|
|
44368
|
+
const version2 = isIP(hostname3);
|
|
44369
|
+
if (version2 === 4 || version2 === 6) {
|
|
44370
|
+
if (isPrivateAddress(hostname3)) {
|
|
44371
|
+
throw new Error(`Webhook target ${hostname3} is a private or special-use address`);
|
|
44372
|
+
}
|
|
44373
|
+
return { hostname: hostname3, addresses: [hostname3] };
|
|
44374
|
+
}
|
|
44375
|
+
const lookup = policy.lookup ?? defaultTargetLookup;
|
|
44376
|
+
let resolved;
|
|
44377
|
+
try {
|
|
44378
|
+
resolved = await lookup(hostname3);
|
|
44379
|
+
} catch {
|
|
44380
|
+
throw new Error(`Webhook target ${hostname3} could not be resolved`);
|
|
44381
|
+
}
|
|
44382
|
+
if (!Array.isArray(resolved) || resolved.length === 0) {
|
|
44383
|
+
throw new Error(`Webhook target ${hostname3} resolved to no addresses`);
|
|
44384
|
+
}
|
|
44385
|
+
const allowed = [];
|
|
44386
|
+
for (const entry of resolved) {
|
|
44387
|
+
const address = normalizeHostname(entry.address);
|
|
44388
|
+
if (isPrivateAddress(address)) {
|
|
44389
|
+
if (allowlist.includes(address)) {
|
|
44390
|
+
allowed.push(address);
|
|
44391
|
+
continue;
|
|
44392
|
+
}
|
|
44393
|
+
throw new Error(`Webhook target ${hostname3} resolves to private or special-use address ${address}`);
|
|
44394
|
+
}
|
|
44395
|
+
allowed.push(address);
|
|
44396
|
+
}
|
|
44397
|
+
if (allowed.length === 0) {
|
|
44398
|
+
throw new Error(`Webhook target ${hostname3} resolved to no public addresses`);
|
|
44399
|
+
}
|
|
44400
|
+
return { hostname: hostname3, addresses: allowed };
|
|
44401
|
+
}
|
|
44402
|
+
function normalizeMaxRedirects(value) {
|
|
44403
|
+
if (value === undefined)
|
|
44404
|
+
return DEFAULT_MAX_REDIRECTS;
|
|
44405
|
+
if (!Number.isInteger(value) || value < 0)
|
|
44406
|
+
throw new Error("webhookTargetPolicy.maxRedirects must be a non-negative integer");
|
|
44407
|
+
return value;
|
|
44408
|
+
}
|
|
44409
|
+
var defaultTargetLookup = async (hostname3) => {
|
|
44410
|
+
return dnsLookup(hostname3, { all: true, verbatim: false });
|
|
44411
|
+
};
|
|
44412
|
+
function normalizeHostname(hostname3) {
|
|
44413
|
+
const lower = hostname3.toLowerCase();
|
|
44414
|
+
if (lower.startsWith("[") && lower.endsWith("]"))
|
|
44415
|
+
return lower.slice(1, -1);
|
|
44416
|
+
return lower;
|
|
44417
|
+
}
|
|
44418
|
+
function stripZoneId(address) {
|
|
44419
|
+
const percent = address.indexOf("%");
|
|
44420
|
+
return percent === -1 ? address : address.slice(0, percent);
|
|
44421
|
+
}
|
|
44422
|
+
function ipv4ToInt(address) {
|
|
44423
|
+
const parts = address.split(".");
|
|
44424
|
+
if (parts.length !== 4)
|
|
44425
|
+
return;
|
|
44426
|
+
let value = 0;
|
|
44427
|
+
for (const part of parts) {
|
|
44428
|
+
if (!/^\d{1,3}$/.test(part))
|
|
44429
|
+
return;
|
|
44430
|
+
const octet = Number(part);
|
|
44431
|
+
if (octet > 255)
|
|
44432
|
+
return;
|
|
44433
|
+
value = value << 8 | octet;
|
|
44434
|
+
}
|
|
44435
|
+
return value >>> 0;
|
|
44436
|
+
}
|
|
44437
|
+
function ipv4IntToString(integer3) {
|
|
44438
|
+
return [
|
|
44439
|
+
integer3 >>> 24 & 255,
|
|
44440
|
+
integer3 >>> 16 & 255,
|
|
44441
|
+
integer3 >>> 8 & 255,
|
|
44442
|
+
integer3 & 255
|
|
44443
|
+
].join(".");
|
|
44444
|
+
}
|
|
44445
|
+
function ipv6Groups(address) {
|
|
44446
|
+
const raw = stripZoneId(address);
|
|
44447
|
+
const doubleColon = raw.indexOf("::");
|
|
44448
|
+
const headText = doubleColon === -1 ? raw : raw.slice(0, doubleColon);
|
|
44449
|
+
const tailText = doubleColon === -1 ? "" : raw.slice(doubleColon + 2);
|
|
44450
|
+
const parseGroups = (text3) => {
|
|
44451
|
+
if (text3 === "")
|
|
44452
|
+
return [];
|
|
44453
|
+
const out = [];
|
|
44454
|
+
for (const part of text3.split(":")) {
|
|
44455
|
+
if (part.includes(".")) {
|
|
44456
|
+
const v4 = ipv4ToInt(part);
|
|
44457
|
+
if (v4 === undefined)
|
|
44458
|
+
return;
|
|
44459
|
+
out.push(v4 >>> 16 & 65535, v4 & 65535);
|
|
44460
|
+
} else {
|
|
44461
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(part))
|
|
44462
|
+
return;
|
|
44463
|
+
out.push(parseInt(part, 16));
|
|
44464
|
+
}
|
|
44465
|
+
}
|
|
44466
|
+
return out;
|
|
44467
|
+
};
|
|
44468
|
+
const head = parseGroups(headText);
|
|
44469
|
+
if (!head)
|
|
44470
|
+
return;
|
|
44471
|
+
const tail = parseGroups(tailText);
|
|
44472
|
+
if (!tail)
|
|
44473
|
+
return;
|
|
44474
|
+
const total = head.length + tail.length;
|
|
44475
|
+
if (doubleColon === -1) {
|
|
44476
|
+
return total === 8 ? head : undefined;
|
|
44477
|
+
}
|
|
44478
|
+
if (total >= 8)
|
|
44479
|
+
return;
|
|
44480
|
+
return [...head, ...new Array(8 - total).fill(0), ...tail];
|
|
44481
|
+
}
|
|
44482
|
+
function ipv6MatchesPrefix(groups, prefixGroups, prefixBits) {
|
|
44483
|
+
let remaining = prefixBits;
|
|
44484
|
+
for (let index = 0;index < prefixGroups.length && remaining > 0; index += 1) {
|
|
44485
|
+
const take = Math.min(16, remaining);
|
|
44486
|
+
const mask = 65535 << 16 - take & 65535;
|
|
44487
|
+
if ((groups[index] & mask) !== (prefixGroups[index] & mask))
|
|
44488
|
+
return false;
|
|
44489
|
+
remaining -= take;
|
|
44490
|
+
}
|
|
44491
|
+
return true;
|
|
44492
|
+
}
|
|
44047
44493
|
function now() {
|
|
44048
44494
|
return new Date().toISOString();
|
|
44049
44495
|
}
|
|
@@ -44074,9 +44520,18 @@ function buildWebhookRequest(event, channel, options = {}) {
|
|
|
44074
44520
|
}
|
|
44075
44521
|
return { body, headers };
|
|
44076
44522
|
}
|
|
44523
|
+
function normalizeWebhookUrl(raw) {
|
|
44524
|
+
const url2 = new URL(raw);
|
|
44525
|
+
if (url2.username !== "" || url2.password !== "") {
|
|
44526
|
+
url2.username = "";
|
|
44527
|
+
url2.password = "";
|
|
44528
|
+
}
|
|
44529
|
+
return url2.toString();
|
|
44530
|
+
}
|
|
44077
44531
|
async function dispatchWebhook(event, channel, options = {}) {
|
|
44078
44532
|
if (!channel.webhook)
|
|
44079
44533
|
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
44534
|
+
const webhookUrl = normalizeWebhookUrl(channel.webhook.url);
|
|
44080
44535
|
const startedAt = now();
|
|
44081
44536
|
let secret = channel.webhook.secret;
|
|
44082
44537
|
if (channel.webhook.secretRef) {
|
|
@@ -44093,10 +44548,14 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
44093
44548
|
}
|
|
44094
44549
|
const timestamp = (options.now?.() ?? new Date).toISOString();
|
|
44095
44550
|
const { body, headers } = buildWebhookRequest(event, channel, { secret, timestamp });
|
|
44551
|
+
const validateTargets = options.webhookTargetPolicy !== undefined || options.fetchImpl === undefined;
|
|
44552
|
+
if (validateTargets) {
|
|
44553
|
+
return dispatchValidatedWebhook(event, channel, { body, headers, startedAt, options });
|
|
44554
|
+
}
|
|
44096
44555
|
const controller = new AbortController;
|
|
44097
44556
|
const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
|
|
44098
44557
|
try {
|
|
44099
|
-
const response = await (options.fetchImpl ?? fetch)(
|
|
44558
|
+
const response = await (options.fetchImpl ?? fetch)(webhookUrl, {
|
|
44100
44559
|
method: "POST",
|
|
44101
44560
|
headers,
|
|
44102
44561
|
body,
|
|
@@ -44124,6 +44583,130 @@ async function dispatchWebhook(event, channel, options = {}) {
|
|
|
44124
44583
|
clearTimeout(timeout);
|
|
44125
44584
|
}
|
|
44126
44585
|
}
|
|
44586
|
+
function isRedirectStatus(status) {
|
|
44587
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
44588
|
+
}
|
|
44589
|
+
function redirectKeepsBody(status) {
|
|
44590
|
+
return status === 307 || status === 308;
|
|
44591
|
+
}
|
|
44592
|
+
async function pinnedNativeRequest(target, addresses, method, headers, body, signal, tls) {
|
|
44593
|
+
const isHttps = target.protocol === "https:";
|
|
44594
|
+
if (!isHttps && target.protocol !== "http:") {
|
|
44595
|
+
throw new Error(`Webhook target uses unsupported protocol ${target.protocol}`);
|
|
44596
|
+
}
|
|
44597
|
+
const defaultPort = isHttps ? 443 : 80;
|
|
44598
|
+
const port = target.port ? Number(target.port) : defaultPort;
|
|
44599
|
+
const requestOptions = {
|
|
44600
|
+
hostname: target.hostname,
|
|
44601
|
+
port,
|
|
44602
|
+
path: `${target.pathname}${target.search}`,
|
|
44603
|
+
method,
|
|
44604
|
+
headers,
|
|
44605
|
+
...tls?.ca ? { ca: tls.ca } : {},
|
|
44606
|
+
lookup: (hostname3, _options, callback) => {
|
|
44607
|
+
const entries = addresses.map((address) => ({
|
|
44608
|
+
address,
|
|
44609
|
+
family: address.includes(":") ? 6 : 4
|
|
44610
|
+
}));
|
|
44611
|
+
callback(null, entries);
|
|
44612
|
+
}
|
|
44613
|
+
};
|
|
44614
|
+
return new Promise((resolve23, reject) => {
|
|
44615
|
+
const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
|
|
44616
|
+
const onAbort = () => {
|
|
44617
|
+
const error61 = new Error("The operation was aborted.");
|
|
44618
|
+
error61.name = "AbortError";
|
|
44619
|
+
request.destroy(error61);
|
|
44620
|
+
};
|
|
44621
|
+
if (signal.aborted)
|
|
44622
|
+
onAbort();
|
|
44623
|
+
else
|
|
44624
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
44625
|
+
request.on("error", reject);
|
|
44626
|
+
if (body !== undefined)
|
|
44627
|
+
request.write(body);
|
|
44628
|
+
request.end();
|
|
44629
|
+
function onResponse(response) {
|
|
44630
|
+
const chunks = [];
|
|
44631
|
+
response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
44632
|
+
response.on("error", reject);
|
|
44633
|
+
response.on("end", () => {
|
|
44634
|
+
const headersRecord = {};
|
|
44635
|
+
for (const [name, value] of Object.entries(response.headers)) {
|
|
44636
|
+
if (typeof value === "string")
|
|
44637
|
+
headersRecord[name] = value;
|
|
44638
|
+
else if (Array.isArray(value))
|
|
44639
|
+
headersRecord[name] = value.join(", ");
|
|
44640
|
+
}
|
|
44641
|
+
resolve23(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
|
|
44642
|
+
});
|
|
44643
|
+
}
|
|
44644
|
+
});
|
|
44645
|
+
}
|
|
44646
|
+
async function dispatchValidatedWebhook(event, channel, input2) {
|
|
44647
|
+
const { body, headers, startedAt, options } = input2;
|
|
44648
|
+
const webhook = channel.webhook;
|
|
44649
|
+
if (!webhook)
|
|
44650
|
+
throw new Error(`Channel ${channel.id} has no webhook config`);
|
|
44651
|
+
const policy = options.webhookTargetPolicy ?? {};
|
|
44652
|
+
const maxRedirects = normalizeMaxRedirects(policy.maxRedirects);
|
|
44653
|
+
const controller = new AbortController;
|
|
44654
|
+
const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs ?? 15000);
|
|
44655
|
+
try {
|
|
44656
|
+
let target = new URL(normalizeWebhookUrl(webhook.url));
|
|
44657
|
+
let requestHeaders = headers;
|
|
44658
|
+
let method = "POST";
|
|
44659
|
+
let requestBody = body;
|
|
44660
|
+
let redirectsFollowed = 0;
|
|
44661
|
+
for (;; ) {
|
|
44662
|
+
const resolved = await resolveWebhookTarget(target, policy).catch((error61) => {
|
|
44663
|
+
throw new Error(`Webhook target rejected by SSRF guard: ${error61.message}`);
|
|
44664
|
+
});
|
|
44665
|
+
const response = options.fetchImpl ? await options.fetchImpl(target, {
|
|
44666
|
+
method,
|
|
44667
|
+
headers: requestHeaders,
|
|
44668
|
+
body: requestBody,
|
|
44669
|
+
signal: controller.signal,
|
|
44670
|
+
redirect: "manual"
|
|
44671
|
+
}) : await pinnedNativeRequest(target, resolved.addresses, method, requestHeaders, requestBody, controller.signal, options.tls);
|
|
44672
|
+
const location = response.headers.get("location");
|
|
44673
|
+
if (isRedirectStatus(response.status) && location) {
|
|
44674
|
+
if (redirectsFollowed >= maxRedirects) {
|
|
44675
|
+
return failedAttempt(startedAt, `Webhook target exceeded ${maxRedirects} redirects`);
|
|
44676
|
+
}
|
|
44677
|
+
redirectsFollowed += 1;
|
|
44678
|
+
const next = new URL(location, target);
|
|
44679
|
+
target = next;
|
|
44680
|
+
if (!redirectKeepsBody(response.status)) {
|
|
44681
|
+
method = "GET";
|
|
44682
|
+
requestBody = undefined;
|
|
44683
|
+
requestHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => name.toLowerCase() !== "content-type" && name.toLowerCase() !== "content-length"));
|
|
44684
|
+
}
|
|
44685
|
+
continue;
|
|
44686
|
+
}
|
|
44687
|
+
const responseBody = truncate(await response.text());
|
|
44688
|
+
return {
|
|
44689
|
+
attempt: 1,
|
|
44690
|
+
status: response.ok ? "success" : "failed",
|
|
44691
|
+
startedAt,
|
|
44692
|
+
completedAt: now(),
|
|
44693
|
+
responseStatus: response.status,
|
|
44694
|
+
responseBody,
|
|
44695
|
+
error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
|
|
44696
|
+
};
|
|
44697
|
+
}
|
|
44698
|
+
} catch (error61) {
|
|
44699
|
+
return {
|
|
44700
|
+
attempt: 1,
|
|
44701
|
+
status: "failed",
|
|
44702
|
+
startedAt,
|
|
44703
|
+
completedAt: now(),
|
|
44704
|
+
error: error61 instanceof Error ? error61.message : String(error61)
|
|
44705
|
+
};
|
|
44706
|
+
} finally {
|
|
44707
|
+
clearTimeout(timeout);
|
|
44708
|
+
}
|
|
44709
|
+
}
|
|
44127
44710
|
function failedAttempt(startedAt, error61) {
|
|
44128
44711
|
return {
|
|
44129
44712
|
attempt: 1,
|
|
@@ -44152,7 +44735,7 @@ async function dispatchCommand(event, channel) {
|
|
|
44152
44735
|
HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
|
|
44153
44736
|
HASNA_EVENT_JSON: eventJson
|
|
44154
44737
|
};
|
|
44155
|
-
return new Promise((
|
|
44738
|
+
return new Promise((resolve23) => {
|
|
44156
44739
|
const child = spawn3(channel.command.command, channel.command.args ?? [], {
|
|
44157
44740
|
cwd: channel.command.cwd,
|
|
44158
44741
|
env,
|
|
@@ -44170,7 +44753,7 @@ async function dispatchCommand(event, channel) {
|
|
|
44170
44753
|
});
|
|
44171
44754
|
child.on("error", (error61) => {
|
|
44172
44755
|
clearTimeout(timeout);
|
|
44173
|
-
|
|
44756
|
+
resolve23({
|
|
44174
44757
|
attempt: 1,
|
|
44175
44758
|
status: "failed",
|
|
44176
44759
|
startedAt,
|
|
@@ -44183,7 +44766,7 @@ async function dispatchCommand(event, channel) {
|
|
|
44183
44766
|
child.on("close", (code2, signal) => {
|
|
44184
44767
|
clearTimeout(timeout);
|
|
44185
44768
|
const success2 = code2 === 0;
|
|
44186
|
-
|
|
44769
|
+
resolve23({
|
|
44187
44770
|
attempt: 1,
|
|
44188
44771
|
status: success2 ? "success" : "failed",
|
|
44189
44772
|
startedAt,
|
|
@@ -44305,6 +44888,22 @@ function setPath(input2, path, replacement) {
|
|
|
44305
44888
|
if (last && last in cursor)
|
|
44306
44889
|
cursor[last] = replacement;
|
|
44307
44890
|
}
|
|
44891
|
+
var MAX_PACKAGE_BYTES2 = 1024 * 1024;
|
|
44892
|
+
var MAX_CREDENTIAL_FILE_BYTES2 = 64 * 1024;
|
|
44893
|
+
var INSPECT_CUSTOM2 = Symbol.for("nodejs.util.inspect.custom");
|
|
44894
|
+
var CREDENTIAL_SEAL2 = Symbol.for("hasna:contracts:sealedCredential");
|
|
44895
|
+
var AMBIENT_ENVIRONMENT2 = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
44896
|
+
var requireSecretsSdk2 = createRequire2(import.meta.url);
|
|
44897
|
+
var IDEMPOTENT_METHODS2 = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
44898
|
+
var AUTHORITY_OVERRIDE_HEADERS2 = new Set([
|
|
44899
|
+
"host",
|
|
44900
|
+
":authority",
|
|
44901
|
+
"forwarded",
|
|
44902
|
+
"x-forwarded-host",
|
|
44903
|
+
"x-original-host"
|
|
44904
|
+
]);
|
|
44905
|
+
var MAX_ENVELOPE_BYTES = 256 * 1024;
|
|
44906
|
+
var MAX_REQUEST_BYTES = MAX_ENVELOPE_BYTES * 2 + 8192;
|
|
44308
44907
|
function createEvent(input2) {
|
|
44309
44908
|
return {
|
|
44310
44909
|
id: input2.id ?? randomUUID22(),
|
|
@@ -44333,7 +44932,9 @@ class EventsClient {
|
|
|
44333
44932
|
this.transportOptions = {
|
|
44334
44933
|
fetchImpl: options.fetchImpl,
|
|
44335
44934
|
secretResolver: options.secretResolver,
|
|
44336
|
-
now: options.now
|
|
44935
|
+
now: options.now,
|
|
44936
|
+
tls: options.tls,
|
|
44937
|
+
webhookTargetPolicy: options.webhookTargetPolicy
|
|
44337
44938
|
};
|
|
44338
44939
|
this.catalog = options.catalog ?? defaultEventTypeCatalog;
|
|
44339
44940
|
this.validateCatalogTypes = options.validateCatalogTypes ?? false;
|
|
@@ -44620,6 +45221,13 @@ function parseMatcherExpression(value, label) {
|
|
|
44620
45221
|
negated: false
|
|
44621
45222
|
};
|
|
44622
45223
|
}
|
|
45224
|
+
function webhookTargetPolicyFromEnv() {
|
|
45225
|
+
const value = process.env.HASNA_EVENTS_ALLOW_PRIVATE_WEBHOOK_TARGETS;
|
|
45226
|
+
if (!value)
|
|
45227
|
+
return;
|
|
45228
|
+
const hosts = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
45229
|
+
return hosts.length > 0 ? { allowPrivateHosts: hosts } : undefined;
|
|
45230
|
+
}
|
|
44623
45231
|
var DEFAULT_EVENT_LIST_LIMIT = 100;
|
|
44624
45232
|
function parseJsonObject(value, fallback) {
|
|
44625
45233
|
if (!value)
|
|
@@ -44645,7 +45253,7 @@ function parseHeaders(values) {
|
|
|
44645
45253
|
function createClient(options) {
|
|
44646
45254
|
if (options.createClient)
|
|
44647
45255
|
return options.createClient();
|
|
44648
|
-
return new EventsClient({ store: new JsonEventsStore(options.dataDir) });
|
|
45256
|
+
return new EventsClient({ store: new JsonEventsStore(options.dataDir), webhookTargetPolicy: webhookTargetPolicyFromEnv() });
|
|
44649
45257
|
}
|
|
44650
45258
|
function print(value, json2, text3) {
|
|
44651
45259
|
if (json2)
|
|
@@ -44726,6 +45334,8 @@ function registerChannelCommands(program2, options) {
|
|
|
44726
45334
|
metadata: parseJsonObject(actionOptions.metadata, {})
|
|
44727
45335
|
}, { honorFilters: actionOptions.honorFilters });
|
|
44728
45336
|
print(result, json2, `${result.status}: ${result.channelId}`);
|
|
45337
|
+
if (result.status === "failed")
|
|
45338
|
+
process.exitCode = 1;
|
|
44729
45339
|
} catch (error61) {
|
|
44730
45340
|
fail(error61, json2);
|
|
44731
45341
|
}
|
|
@@ -44818,7 +45428,7 @@ function replaySummary(events2, deliveries, nextCursor) {
|
|
|
44818
45428
|
// src/cli/index.tsx
|
|
44819
45429
|
import { render } from "ink";
|
|
44820
45430
|
|
|
44821
|
-
//
|
|
45431
|
+
// ../../node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
|
|
44822
45432
|
var import__ = __toESM(require_commander(), 1);
|
|
44823
45433
|
var {
|
|
44824
45434
|
program: program2,
|
|
@@ -44837,18 +45447,18 @@ var {
|
|
|
44837
45447
|
// src/cli/index.tsx
|
|
44838
45448
|
import chalk2 from "chalk";
|
|
44839
45449
|
import { existsSync as existsSync18, readFileSync as readFileSync27, rmSync as rmSync6 } from "fs";
|
|
44840
|
-
import { join as
|
|
45450
|
+
import { join as join36, dirname as dirname28 } from "path";
|
|
44841
45451
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
44842
45452
|
|
|
44843
45453
|
// src/cli/components/App.tsx
|
|
44844
45454
|
import { useState as useState7 } from "react";
|
|
44845
45455
|
import { Box as Box8, Text as Text10, useApp, useInput as useInput5 } from "ink";
|
|
44846
45456
|
|
|
44847
|
-
//
|
|
45457
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
|
|
44848
45458
|
import React from "react";
|
|
44849
45459
|
import { Box, Text } from "ink";
|
|
44850
45460
|
|
|
44851
|
-
//
|
|
45461
|
+
// ../../node_modules/.bun/is-unicode-supported@2.1.0/node_modules/is-unicode-supported/index.js
|
|
44852
45462
|
import process3 from "process";
|
|
44853
45463
|
function isUnicodeSupported() {
|
|
44854
45464
|
const { env } = process3;
|
|
@@ -44859,7 +45469,7 @@ function isUnicodeSupported() {
|
|
|
44859
45469
|
return Boolean(env.WT_SESSION) || Boolean(env.TERMINUS_SUBLIME) || env.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
44860
45470
|
}
|
|
44861
45471
|
|
|
44862
|
-
//
|
|
45472
|
+
// ../../node_modules/.bun/figures@6.1.0/node_modules/figures/index.js
|
|
44863
45473
|
var common2 = {
|
|
44864
45474
|
circleQuestionMark: "(?)",
|
|
44865
45475
|
questionMarkPrefix: "(?)",
|
|
@@ -45135,23 +45745,23 @@ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
|
|
|
45135
45745
|
var figures_default = figures;
|
|
45136
45746
|
var replacements = Object.entries(specialMainSymbols);
|
|
45137
45747
|
|
|
45138
|
-
//
|
|
45748
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Indicator.js
|
|
45139
45749
|
function Indicator({ isSelected = false }) {
|
|
45140
45750
|
return React.createElement(Box, { marginRight: 1 }, isSelected ? React.createElement(Text, { color: "blue" }, figures_default.pointer) : React.createElement(Text, null, " "));
|
|
45141
45751
|
}
|
|
45142
45752
|
var Indicator_default = Indicator;
|
|
45143
|
-
//
|
|
45753
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/Item.js
|
|
45144
45754
|
import * as React2 from "react";
|
|
45145
45755
|
import { Text as Text2 } from "ink";
|
|
45146
45756
|
function Item({ isSelected = false, label }) {
|
|
45147
45757
|
return React2.createElement(Text2, { color: isSelected ? "blue" : undefined }, label);
|
|
45148
45758
|
}
|
|
45149
45759
|
var Item_default = Item;
|
|
45150
|
-
//
|
|
45760
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
|
|
45151
45761
|
import { isDeepStrictEqual } from "util";
|
|
45152
45762
|
import React3, { useState, useEffect, useRef, useCallback } from "react";
|
|
45153
45763
|
|
|
45154
|
-
//
|
|
45764
|
+
// ../../node_modules/.bun/to-rotated@1.0.0/node_modules/to-rotated/index.js
|
|
45155
45765
|
function toRotated(array3, steps) {
|
|
45156
45766
|
if (!Array.isArray(array3)) {
|
|
45157
45767
|
throw new TypeError(`Expected an array, got \`${typeof array3}\`.`);
|
|
@@ -45173,7 +45783,7 @@ function toRotated(array3, steps) {
|
|
|
45173
45783
|
];
|
|
45174
45784
|
}
|
|
45175
45785
|
|
|
45176
|
-
//
|
|
45786
|
+
// ../../node_modules/.bun/ink-select-input@6.2.0+fa875fef9f949ebd/node_modules/ink-select-input/build/SelectInput.js
|
|
45177
45787
|
import { Box as Box2, useInput } from "ink";
|
|
45178
45788
|
function SelectInput({ items = [], isFocused = true, initialIndex = 0, indicatorComponent = Indicator_default, itemComponent = Item_default, limit: customLimit, onSelect, onHighlight }) {
|
|
45179
45789
|
const hasLimit = typeof customLimit === "number" && items.length > customLimit;
|
|
@@ -45469,7 +46079,7 @@ function HookSelect({
|
|
|
45469
46079
|
import { useState as useState4, useEffect as useEffect3 } from "react";
|
|
45470
46080
|
import { Box as Box6, Text as Text7, useInput as useInput4 } from "ink";
|
|
45471
46081
|
|
|
45472
|
-
//
|
|
46082
|
+
// ../../node_modules/.bun/ink-text-input@6.0.0+fa875fef9f949ebd/node_modules/ink-text-input/build/index.js
|
|
45473
46083
|
import React5, { useState as useState3, useEffect as useEffect2 } from "react";
|
|
45474
46084
|
import { Text as Text6, useInput as useInput3 } from "ink";
|
|
45475
46085
|
import chalk from "chalk";
|
|
@@ -45647,7 +46257,7 @@ function SearchView({
|
|
|
45647
46257
|
import { useState as useState6, useEffect as useEffect5 } from "react";
|
|
45648
46258
|
import { Box as Box7, Text as Text9 } from "ink";
|
|
45649
46259
|
|
|
45650
|
-
//
|
|
46260
|
+
// ../../node_modules/.bun/ink-spinner@5.0.0+fa875fef9f949ebd/node_modules/ink-spinner/build/index.js
|
|
45651
46261
|
var import_cli_spinners = __toESM(require_cli_spinners(), 1);
|
|
45652
46262
|
import React7, { useState as useState5, useEffect as useEffect4 } from "react";
|
|
45653
46263
|
import { Text as Text8 } from "ink";
|
|
@@ -46014,10 +46624,10 @@ init_native_safety();
|
|
|
46014
46624
|
|
|
46015
46625
|
// src/lib/sumi-binding.ts
|
|
46016
46626
|
import { homedir as homedir14 } from "os";
|
|
46017
|
-
import { join as
|
|
46627
|
+
import { join as join27, sep as sep3 } from "path";
|
|
46018
46628
|
|
|
46019
46629
|
// hooks/hook-trash-guard/src/binary.ts
|
|
46020
|
-
import { dirname as dirname21, isAbsolute as isAbsolute20, join as
|
|
46630
|
+
import { dirname as dirname21, isAbsolute as isAbsolute20, join as join24, resolve as resolve21 } from "path";
|
|
46021
46631
|
import { accessSync, closeSync as closeSync19, constants as constants18, fstatSync as fstatSync18, lstatSync as lstatSync23, openSync as openSync19, readFileSync as readFileSync17, readlinkSync as readlinkSync3, readSync as readSync3, realpathSync as realpathSync11, statSync } from "fs";
|
|
46022
46632
|
import { spawnSync } from "child_process";
|
|
46023
46633
|
function trustedOwner(uid2) {
|
|
@@ -46039,7 +46649,7 @@ function safeExecutableFile(path, systemBinAlias = false) {
|
|
|
46039
46649
|
parent = dirname21(parent);
|
|
46040
46650
|
continue;
|
|
46041
46651
|
}
|
|
46042
|
-
const next =
|
|
46652
|
+
const next = join24(parent, part), info2 = lstatSync23(next);
|
|
46043
46653
|
if (systemBinAlias && next === "/bin" && info2.isSymbolicLink() && info2.uid === 0) {
|
|
46044
46654
|
const target = realpathSync11(next);
|
|
46045
46655
|
if (!safeBinaryDirectory(target))
|
|
@@ -46051,7 +46661,7 @@ function safeExecutableFile(path, systemBinAlias = false) {
|
|
|
46051
46661
|
return false;
|
|
46052
46662
|
parent = next;
|
|
46053
46663
|
}
|
|
46054
|
-
const candidate =
|
|
46664
|
+
const candidate = join24(parent, name), info = lstatSync23(candidate);
|
|
46055
46665
|
if (!trustedOwner(info.uid))
|
|
46056
46666
|
return false;
|
|
46057
46667
|
if (info.isSymbolicLink()) {
|
|
@@ -46064,9 +46674,9 @@ function safeExecutableFile(path, systemBinAlias = false) {
|
|
|
46064
46674
|
return false;
|
|
46065
46675
|
}
|
|
46066
46676
|
function safeInterpreterSearchDirectory(path) {
|
|
46067
|
-
if (!isAbsolute20(path) ||
|
|
46677
|
+
if (!isAbsolute20(path) || resolve21(path) !== (path.replace(/\/+$/, "") || "/"))
|
|
46068
46678
|
return false;
|
|
46069
|
-
for (let cursor =
|
|
46679
|
+
for (let cursor = resolve21(path);; cursor = dirname21(cursor)) {
|
|
46070
46680
|
try {
|
|
46071
46681
|
lstatSync23(cursor);
|
|
46072
46682
|
return safeBinaryDirectory(cursor);
|
|
@@ -46098,7 +46708,7 @@ function safeScriptInterpreter(executable2, pathValue) {
|
|
|
46098
46708
|
for (const dir of pathValue.split(":").slice(0, 64)) {
|
|
46099
46709
|
if (!safeInterpreterSearchDirectory(dir))
|
|
46100
46710
|
return false;
|
|
46101
|
-
const interpreter =
|
|
46711
|
+
const interpreter = resolve21(dir, "bun");
|
|
46102
46712
|
try {
|
|
46103
46713
|
if (!statSync(interpreter).isFile())
|
|
46104
46714
|
continue;
|
|
@@ -46133,7 +46743,7 @@ function inspectTrashBinary(env = process.env) {
|
|
|
46133
46743
|
for (const dir of pathValue.split(":").slice(0, 64)) {
|
|
46134
46744
|
if (!isAbsolute20(dir) || Date.now() >= deadline)
|
|
46135
46745
|
continue;
|
|
46136
|
-
const candidate =
|
|
46746
|
+
const candidate = resolve21(dir, "trash");
|
|
46137
46747
|
try {
|
|
46138
46748
|
const stat2 = statSync(candidate);
|
|
46139
46749
|
if (!stat2.isFile() || !trustedOwner(stat2.uid) || (stat2.mode & 73) === 0 || (stat2.mode & 18) !== 0) {
|
|
@@ -46141,7 +46751,7 @@ function inspectTrashBinary(env = process.env) {
|
|
|
46141
46751
|
continue;
|
|
46142
46752
|
}
|
|
46143
46753
|
const executable2 = realpathSync11(candidate);
|
|
46144
|
-
if (!safeBinaryDirectory(
|
|
46754
|
+
if (!safeBinaryDirectory(resolve21(dir)) || !safeBinaryDirectory(dirname21(executable2))) {
|
|
46145
46755
|
reject("unsafe_directory");
|
|
46146
46756
|
continue;
|
|
46147
46757
|
}
|
|
@@ -46149,15 +46759,15 @@ function inspectTrashBinary(env = process.env) {
|
|
|
46149
46759
|
reject("unsafe_directory");
|
|
46150
46760
|
continue;
|
|
46151
46761
|
}
|
|
46152
|
-
const packageRoot =
|
|
46153
|
-
const manifestPath =
|
|
46762
|
+
const packageRoot = resolve21(dirname21(executable2), "../..");
|
|
46763
|
+
const manifestPath = join24(packageRoot, "package.json");
|
|
46154
46764
|
const manifestStat = statSync(manifestPath);
|
|
46155
46765
|
if (!manifestStat.isFile() || !trustedOwner(manifestStat.uid) || manifestStat.size > 16384 || (manifestStat.mode & 18) !== 0 || lstatSync23(manifestPath).isSymbolicLink()) {
|
|
46156
46766
|
reject("unsafe_manifest");
|
|
46157
46767
|
continue;
|
|
46158
46768
|
}
|
|
46159
46769
|
const manifest = JSON.parse(readFileSync17(manifestPath, "utf8"));
|
|
46160
|
-
if (manifest.name !== "@hasna/trash" || typeof manifest.version !== "string" || typeof manifest.bin?.trash !== "string" || realpathSync11(
|
|
46770
|
+
if (manifest.name !== "@hasna/trash" || typeof manifest.version !== "string" || typeof manifest.bin?.trash !== "string" || realpathSync11(resolve21(packageRoot, manifest.bin.trash)) !== executable2) {
|
|
46161
46771
|
reject("unrecognized_package");
|
|
46162
46772
|
continue;
|
|
46163
46773
|
}
|
|
@@ -46202,7 +46812,7 @@ function failure(code2, reason) {
|
|
|
46202
46812
|
return { ok: false, target: "sumi", code: code2, ...reason ? { reason: reason.slice(0, 300) } : {} };
|
|
46203
46813
|
}
|
|
46204
46814
|
function nativeSafetyBindingDurable(worker, home) {
|
|
46205
|
-
return !(worker.startsWith(
|
|
46815
|
+
return !(worker.startsWith(join27(home, ".bun") + sep3) || worker.includes(`${sep3}node_modules${sep3}.bun${sep3}`));
|
|
46206
46816
|
}
|
|
46207
46817
|
async function provisionSumiSafetyBinding(options = {}) {
|
|
46208
46818
|
const home = options.home ?? homedir14();
|
|
@@ -46277,7 +46887,7 @@ init_transport2();
|
|
|
46277
46887
|
init_db();
|
|
46278
46888
|
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
46279
46889
|
var __dirname4 = dirname28(fileURLToPath6(import.meta.url));
|
|
46280
|
-
var pkgPath = existsSync18(
|
|
46890
|
+
var pkgPath = existsSync18(join36(__dirname4, "..", "package.json")) ? join36(__dirname4, "..", "package.json") : join36(__dirname4, "..", "..", "package.json");
|
|
46281
46891
|
var pkg2 = JSON.parse(readFileSync27(pkgPath, "utf-8"));
|
|
46282
46892
|
var program3 = new Command;
|
|
46283
46893
|
function resolveScope(options) {
|
|
@@ -46510,7 +47120,7 @@ program3.command("init").description("Register a new agent profile with a unique
|
|
|
46510
47120
|
if (profile.name) {
|
|
46511
47121
|
console.log(` ${chalk2.dim("Name:")} ${profile.name}`);
|
|
46512
47122
|
}
|
|
46513
|
-
console.log(` ${chalk2.dim("Profile:")} ${
|
|
47123
|
+
console.log(` ${chalk2.dim("Profile:")} ${join36(getProfilesDir(), `${profile.agent_id}.json`)}`);
|
|
46514
47124
|
console.log();
|
|
46515
47125
|
console.log(chalk2.dim(" Install hooks with this profile:"));
|
|
46516
47126
|
console.log(` hooks install gitguard --profile ${profile.agent_id}`);
|
|
@@ -47165,7 +47775,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
|
|
|
47165
47775
|
continue;
|
|
47166
47776
|
}
|
|
47167
47777
|
const hookDir = getHookPath(name);
|
|
47168
|
-
const hookScript =
|
|
47778
|
+
const hookScript = join36(hookDir, "src", "hook.ts");
|
|
47169
47779
|
if (!existsSync18(hookScript)) {
|
|
47170
47780
|
issues.push({ hook: name, issue: "Missing src/hook.ts in package", severity: "error" });
|
|
47171
47781
|
hookHealthy = false;
|
|
@@ -47174,7 +47784,7 @@ program3.command("doctor").option("-g, --global", "Check global settings", false
|
|
|
47174
47784
|
if (meta3 && settingsExist) {
|
|
47175
47785
|
try {
|
|
47176
47786
|
const settings = JSON.parse(readFileSync27(settingsPath, "utf-8"));
|
|
47177
|
-
if (!hookRegisteredInSettings(settings, name, meta3.event, meta3
|
|
47787
|
+
if (!hookRegisteredInSettings(settings, name, meta3.event, matcherFor(meta3, "claude"))) {
|
|
47178
47788
|
const eventName = meta3.event.split(":")[0];
|
|
47179
47789
|
issues.push({ hook: name, issue: `Not registered under correct event (${eventName})`, severity: "error" });
|
|
47180
47790
|
hookHealthy = false;
|
|
@@ -47376,7 +47986,7 @@ program3.command("docs").argument("[hook]", "Hook name (shows general docs if om
|
|
|
47376
47986
|
return;
|
|
47377
47987
|
}
|
|
47378
47988
|
const hookPath = getHookPath(hook);
|
|
47379
|
-
const readmePath =
|
|
47989
|
+
const readmePath = join36(hookPath, "README.md");
|
|
47380
47990
|
let readme = "";
|
|
47381
47991
|
if (existsSync18(readmePath)) {
|
|
47382
47992
|
readme = readFileSync27(readmePath, "utf-8");
|
|
@@ -48042,13 +48652,13 @@ startup.command("check").requiredOption("--target <target>", "codex, claude or s
|
|
|
48042
48652
|
process.exitCode = 1;
|
|
48043
48653
|
});
|
|
48044
48654
|
for (const action of ["registration-plan", "registration-apply"]) {
|
|
48045
|
-
const command = startup.command(action).requiredOption("--target <target>", "codex or
|
|
48655
|
+
const command = startup.command(action).requiredOption("--target <target>", "codex, claude or sumi (Sumi: its native guard record)");
|
|
48046
48656
|
if (action === "registration-apply")
|
|
48047
48657
|
command.requiredOption("--expected-plan-digest <sha256>", "Exact registration-plan digest");
|
|
48048
48658
|
command.action(async (options) => {
|
|
48049
48659
|
try {
|
|
48050
48660
|
const { planNativeReadinessRegistration: planNativeReadinessRegistration2, applyNativeReadinessRegistration: applyNativeReadinessRegistration2 } = await Promise.resolve().then(() => (init_native_safety_registration(), exports_native_safety_registration));
|
|
48051
|
-
if (options.target !== "codex" && options.target !== "claude")
|
|
48661
|
+
if (options.target !== "codex" && options.target !== "claude" && options.target !== "sumi")
|
|
48052
48662
|
throw new NativeRegistrationError("input_invalid");
|
|
48053
48663
|
console.log(JSON.stringify(action === "registration-plan" ? await planNativeReadinessRegistration2({ target: options.target }) : await applyNativeReadinessRegistration2({ target: options.target, expectedPlanDigest: options.expectedPlanDigest })));
|
|
48054
48664
|
} catch (error61) {
|
|
@@ -48174,7 +48784,7 @@ safety.command("verify").requiredOption("--target <target>", "sumi, codex or cla
|
|
|
48174
48784
|
throw new ClaudeSafetyError("settings_invalid");
|
|
48175
48785
|
console.log(JSON.stringify(await verifyClaudeSafetyConfiguration({
|
|
48176
48786
|
cwd: options.cwd,
|
|
48177
|
-
...process.env.CLAUDE_CONFIG_DIR ? { userSettingsPath:
|
|
48787
|
+
...process.env.CLAUDE_CONFIG_DIR ? { userSettingsPath: resolve23(process.env.CLAUDE_CONFIG_DIR, "settings.json") } : {}
|
|
48178
48788
|
})));
|
|
48179
48789
|
} catch (error61) {
|
|
48180
48790
|
console.log(JSON.stringify({ ok: false, target: "claude", code: error61 instanceof ClaudeSafetyError ? error61.code : "settings_invalid", nativeAdoptionVerified: false }));
|