kifaru 1.0.195 → 1.0.196
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/kifaru-gateway.js +826 -77
- package/kifaru-local-run-worker.js +754 -14
- package/kifaru-pi.js +913 -88
- package/package.json +2 -2
package/kifaru-gateway.js
CHANGED
|
@@ -49488,6 +49488,752 @@ The report should be worthy of maximum payout.
|
|
|
49488
49488
|
})(AtlantisDiversityEnforcer ||= {});
|
|
49489
49489
|
});
|
|
49490
49490
|
|
|
49491
|
+
// ../core/src/entity-graph.ts
|
|
49492
|
+
class EngagementRegistry {
|
|
49493
|
+
graphs = new Map;
|
|
49494
|
+
register(graph) {
|
|
49495
|
+
this.graphs.set(graph.engagement, graph);
|
|
49496
|
+
}
|
|
49497
|
+
get(engagement) {
|
|
49498
|
+
if (!engagement)
|
|
49499
|
+
return;
|
|
49500
|
+
return this.graphs.get(engagement);
|
|
49501
|
+
}
|
|
49502
|
+
list() {
|
|
49503
|
+
return [...this.graphs.keys()].sort();
|
|
49504
|
+
}
|
|
49505
|
+
}
|
|
49506
|
+
function detectEntityMatches(input2) {
|
|
49507
|
+
const hits = [];
|
|
49508
|
+
const seen = new Set;
|
|
49509
|
+
const consider = (field, value) => {
|
|
49510
|
+
if (!value)
|
|
49511
|
+
return;
|
|
49512
|
+
const key = `${field}::${value.toLowerCase()}`;
|
|
49513
|
+
if (seen.has(key))
|
|
49514
|
+
return;
|
|
49515
|
+
if (containsToken(input2.content, value)) {
|
|
49516
|
+
hits.push({ token: value, field, engagement: input2.graph.engagement });
|
|
49517
|
+
seen.add(key);
|
|
49518
|
+
}
|
|
49519
|
+
};
|
|
49520
|
+
for (const value of input2.graph.domains ?? [])
|
|
49521
|
+
consider("domains", value);
|
|
49522
|
+
for (const value of input2.graph.cloud_accounts ?? [])
|
|
49523
|
+
consider("cloud_accounts", value);
|
|
49524
|
+
for (const value of input2.graph.repos ?? [])
|
|
49525
|
+
consider("repos", value);
|
|
49526
|
+
for (const value of input2.graph.team_names ?? [])
|
|
49527
|
+
consider("team_names", value);
|
|
49528
|
+
for (const value of input2.graph.employee_names ?? [])
|
|
49529
|
+
consider("employee_names", value);
|
|
49530
|
+
for (const value of input2.graph.build_jobs ?? [])
|
|
49531
|
+
consider("build_jobs", value);
|
|
49532
|
+
for (const cidr of input2.graph.cidrs ?? []) {
|
|
49533
|
+
for (const ip of extractIPv4(input2.content)) {
|
|
49534
|
+
if (ipInCidr(ip, cidr)) {
|
|
49535
|
+
const key = `cidrs::${ip}::${cidr}`;
|
|
49536
|
+
if (!seen.has(key)) {
|
|
49537
|
+
hits.push({ token: ip, field: "cidrs", engagement: input2.graph.engagement });
|
|
49538
|
+
seen.add(key);
|
|
49539
|
+
}
|
|
49540
|
+
}
|
|
49541
|
+
}
|
|
49542
|
+
}
|
|
49543
|
+
return hits;
|
|
49544
|
+
}
|
|
49545
|
+
function containsToken(haystack, needle) {
|
|
49546
|
+
if (!needle)
|
|
49547
|
+
return false;
|
|
49548
|
+
const escaped = needle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
49549
|
+
const boundary = "(?:^|[^A-Za-z0-9_-])";
|
|
49550
|
+
const tail = "(?:[^A-Za-z0-9_-]|$)";
|
|
49551
|
+
const re = new RegExp(`${boundary}${escaped}${tail}`, "i");
|
|
49552
|
+
return re.test(haystack);
|
|
49553
|
+
}
|
|
49554
|
+
function extractIPv4(content) {
|
|
49555
|
+
const matches = content.match(/\b(?:\d{1,3}\.){3}\d{1,3}\b/g) ?? [];
|
|
49556
|
+
return [...new Set(matches)];
|
|
49557
|
+
}
|
|
49558
|
+
function ipInCidr(ip, cidr) {
|
|
49559
|
+
const [base, prefixStr] = cidr.split("/");
|
|
49560
|
+
if (!base || !prefixStr)
|
|
49561
|
+
return false;
|
|
49562
|
+
const prefix = Number.parseInt(prefixStr, 10);
|
|
49563
|
+
if (!Number.isFinite(prefix) || prefix < 0 || prefix > 32)
|
|
49564
|
+
return false;
|
|
49565
|
+
const ipInt = ipToInt(ip);
|
|
49566
|
+
const baseInt = ipToInt(base);
|
|
49567
|
+
if (ipInt === null || baseInt === null)
|
|
49568
|
+
return false;
|
|
49569
|
+
if (prefix === 0)
|
|
49570
|
+
return true;
|
|
49571
|
+
const mask = prefix === 32 ? 4294967295 : ~0 << 32 - prefix >>> 0;
|
|
49572
|
+
return (ipInt & mask) === (baseInt & mask);
|
|
49573
|
+
}
|
|
49574
|
+
function ipToInt(ip) {
|
|
49575
|
+
const parts = ip.split(".");
|
|
49576
|
+
if (parts.length !== 4)
|
|
49577
|
+
return null;
|
|
49578
|
+
let total = 0;
|
|
49579
|
+
for (const part of parts) {
|
|
49580
|
+
const n = Number.parseInt(part, 10);
|
|
49581
|
+
if (!Number.isFinite(n) || n < 0 || n > 255 || String(n) !== part)
|
|
49582
|
+
return null;
|
|
49583
|
+
total = total << 8 | n;
|
|
49584
|
+
}
|
|
49585
|
+
return total >>> 0;
|
|
49586
|
+
}
|
|
49587
|
+
var init_entity_graph = () => {};
|
|
49588
|
+
|
|
49589
|
+
// ../core/src/pii-detector.ts
|
|
49590
|
+
var PiiDetector;
|
|
49591
|
+
var init_pii_detector = __esm(() => {
|
|
49592
|
+
((PiiDetector) => {
|
|
49593
|
+
function build() {
|
|
49594
|
+
return (content) => {
|
|
49595
|
+
return findMatches(content).length > 0 ? ["pii"] : [];
|
|
49596
|
+
};
|
|
49597
|
+
}
|
|
49598
|
+
PiiDetector.build = build;
|
|
49599
|
+
function findMatches(content) {
|
|
49600
|
+
const matches = [];
|
|
49601
|
+
const push = (value) => {
|
|
49602
|
+
if (value)
|
|
49603
|
+
matches.push({ value, label: "pii" });
|
|
49604
|
+
};
|
|
49605
|
+
for (const m of content.match(EMAIL_REGEX_G) ?? [])
|
|
49606
|
+
push(m);
|
|
49607
|
+
for (const re of PHONE_REGEXES_G) {
|
|
49608
|
+
for (const m of content.match(re) ?? [])
|
|
49609
|
+
push(m);
|
|
49610
|
+
}
|
|
49611
|
+
for (const m of validSsnMatches(content))
|
|
49612
|
+
push(m);
|
|
49613
|
+
for (const m of validCreditCardMatches(content))
|
|
49614
|
+
push(m);
|
|
49615
|
+
for (const m of validIbanMatches(content))
|
|
49616
|
+
push(m);
|
|
49617
|
+
for (const m of content.match(PASSPORT_REGEX_G) ?? [])
|
|
49618
|
+
push(m);
|
|
49619
|
+
for (const m of content.match(DOB_REGEX_G) ?? [])
|
|
49620
|
+
push(m);
|
|
49621
|
+
for (const m of content.match(NATIONAL_ID_REGEX_G) ?? [])
|
|
49622
|
+
push(m);
|
|
49623
|
+
return matches;
|
|
49624
|
+
}
|
|
49625
|
+
PiiDetector.findMatches = findMatches;
|
|
49626
|
+
const EMAIL_REGEX_G = /\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/gi;
|
|
49627
|
+
const PHONE_REGEXES_G = [
|
|
49628
|
+
/(?<![\d-])\+\d{1,3}[\s.-]?\(?\d{1,4}\)?[\s.-]?\d{2,4}[\s.-]?\d{2,4}[\s.-]?\d{2,4}\b/g,
|
|
49629
|
+
/\(\d{3}\)\s?\d{3}[-.\s]?\d{4}/g,
|
|
49630
|
+
/\b\d{3}[-.\s]\d{3}[-.\s]\d{4}\b/g
|
|
49631
|
+
];
|
|
49632
|
+
const SSN_REGEX = /\b(\d{3})-(\d{2})-(\d{4})\b/g;
|
|
49633
|
+
const PASSPORT_REGEX_G = /\b(?:passport(?:\s*(?:no|number|#))?\s*[:#]?\s*[A-Z0-9]{6,9})\b/gi;
|
|
49634
|
+
const DOB_REGEX_G = /\b(?:dob|birth(?:day|date)?)\s*[:#]?\s*\d{1,4}[-/.]\d{1,2}[-/.]\d{1,4}\b/gi;
|
|
49635
|
+
const NATIONAL_ID_REGEX_G = /\b[A-Z]{2}\d{6}[A-Z]\b/g;
|
|
49636
|
+
function validSsnMatches(content) {
|
|
49637
|
+
SSN_REGEX.lastIndex = 0;
|
|
49638
|
+
const out = [];
|
|
49639
|
+
let match;
|
|
49640
|
+
while ((match = SSN_REGEX.exec(content)) !== null) {
|
|
49641
|
+
const [whole, area, group, serial] = match;
|
|
49642
|
+
if (area === "000" || area === "666" || area && Number.parseInt(area, 10) >= 900)
|
|
49643
|
+
continue;
|
|
49644
|
+
if (group === "00")
|
|
49645
|
+
continue;
|
|
49646
|
+
if (serial === "0000")
|
|
49647
|
+
continue;
|
|
49648
|
+
out.push(whole);
|
|
49649
|
+
}
|
|
49650
|
+
return out;
|
|
49651
|
+
}
|
|
49652
|
+
function validCreditCardMatches(content) {
|
|
49653
|
+
const candidates = content.match(/(?:\d[ .-]?){13,}/g) ?? [];
|
|
49654
|
+
const out = [];
|
|
49655
|
+
for (const candidate of candidates) {
|
|
49656
|
+
const found = firstLuhnWindow(candidate);
|
|
49657
|
+
if (found)
|
|
49658
|
+
out.push(found);
|
|
49659
|
+
}
|
|
49660
|
+
return out;
|
|
49661
|
+
}
|
|
49662
|
+
function firstLuhnWindow(run) {
|
|
49663
|
+
const digitPos = [];
|
|
49664
|
+
for (let i = 0;i < run.length; i += 1) {
|
|
49665
|
+
const c = run.charCodeAt(i);
|
|
49666
|
+
if (c >= 48 && c <= 57)
|
|
49667
|
+
digitPos.push(i);
|
|
49668
|
+
}
|
|
49669
|
+
const total = digitPos.length;
|
|
49670
|
+
if (total < 13)
|
|
49671
|
+
return;
|
|
49672
|
+
const tryWindow = (start, len) => {
|
|
49673
|
+
const from = digitPos[start];
|
|
49674
|
+
const to = digitPos[start + len - 1];
|
|
49675
|
+
const slice = run.slice(from, to + 1);
|
|
49676
|
+
const digits = slice.replace(/[ .-]/g, "");
|
|
49677
|
+
if (digits.length === len && luhnValid(digits))
|
|
49678
|
+
return slice.trim();
|
|
49679
|
+
return;
|
|
49680
|
+
};
|
|
49681
|
+
if (total >= 13 && total <= 19) {
|
|
49682
|
+
const whole = tryWindow(0, total);
|
|
49683
|
+
if (whole)
|
|
49684
|
+
return whole;
|
|
49685
|
+
}
|
|
49686
|
+
const startsGroup = (idx) => {
|
|
49687
|
+
const pos = digitPos[idx];
|
|
49688
|
+
if (pos === 0)
|
|
49689
|
+
return true;
|
|
49690
|
+
const prev = run.charCodeAt(pos - 1);
|
|
49691
|
+
return !(prev >= 48 && prev <= 57);
|
|
49692
|
+
};
|
|
49693
|
+
const endsGroup = (idx) => {
|
|
49694
|
+
const pos = digitPos[idx];
|
|
49695
|
+
if (pos === run.length - 1)
|
|
49696
|
+
return true;
|
|
49697
|
+
const nxt = run.charCodeAt(pos + 1);
|
|
49698
|
+
return !(nxt >= 48 && nxt <= 57);
|
|
49699
|
+
};
|
|
49700
|
+
for (let len = Math.min(19, total);len >= 13; len -= 1) {
|
|
49701
|
+
for (let start = 0;start + len <= total; start += 1) {
|
|
49702
|
+
if (!startsGroup(start) || !endsGroup(start + len - 1))
|
|
49703
|
+
continue;
|
|
49704
|
+
const hit = tryWindow(start, len);
|
|
49705
|
+
if (hit)
|
|
49706
|
+
return hit;
|
|
49707
|
+
}
|
|
49708
|
+
}
|
|
49709
|
+
return;
|
|
49710
|
+
}
|
|
49711
|
+
function luhnValid(digits) {
|
|
49712
|
+
let sum = 0;
|
|
49713
|
+
let alternate = false;
|
|
49714
|
+
for (let i = digits.length - 1;i >= 0; i -= 1) {
|
|
49715
|
+
const code = digits.charCodeAt(i) - 48;
|
|
49716
|
+
if (code < 0 || code > 9)
|
|
49717
|
+
return false;
|
|
49718
|
+
let n = code;
|
|
49719
|
+
if (alternate) {
|
|
49720
|
+
n *= 2;
|
|
49721
|
+
if (n > 9)
|
|
49722
|
+
n -= 9;
|
|
49723
|
+
}
|
|
49724
|
+
sum += n;
|
|
49725
|
+
alternate = !alternate;
|
|
49726
|
+
}
|
|
49727
|
+
return sum % 10 === 0;
|
|
49728
|
+
}
|
|
49729
|
+
function validIbanMatches(content) {
|
|
49730
|
+
const candidates = content.match(/\b[A-Za-z]{2}\d{2}[A-Za-z0-9]{10,30}\b/g) ?? [];
|
|
49731
|
+
const out = [];
|
|
49732
|
+
for (const candidate of candidates) {
|
|
49733
|
+
if (ibanMod97(candidate))
|
|
49734
|
+
out.push(candidate);
|
|
49735
|
+
}
|
|
49736
|
+
return out;
|
|
49737
|
+
}
|
|
49738
|
+
function ibanMod97(rawIban) {
|
|
49739
|
+
const iban = rawIban.toUpperCase();
|
|
49740
|
+
const rearranged = iban.slice(4) + iban.slice(0, 4);
|
|
49741
|
+
let numeric = "";
|
|
49742
|
+
for (const ch2 of rearranged) {
|
|
49743
|
+
const code = ch2.charCodeAt(0);
|
|
49744
|
+
if (code >= 48 && code <= 57)
|
|
49745
|
+
numeric += ch2;
|
|
49746
|
+
else if (code >= 65 && code <= 90)
|
|
49747
|
+
numeric += String(code - 55);
|
|
49748
|
+
else
|
|
49749
|
+
return false;
|
|
49750
|
+
}
|
|
49751
|
+
let remainder = 0;
|
|
49752
|
+
for (let i = 0;i < numeric.length; i += 7) {
|
|
49753
|
+
const chunk = String(remainder) + numeric.slice(i, i + 7);
|
|
49754
|
+
remainder = Number.parseInt(chunk, 10) % 97;
|
|
49755
|
+
}
|
|
49756
|
+
return remainder === 1;
|
|
49757
|
+
}
|
|
49758
|
+
function attachTo(flowGateway) {
|
|
49759
|
+
const detector = build();
|
|
49760
|
+
flowGateway.registerDetector((content, ctx) => detector(content, ctx));
|
|
49761
|
+
}
|
|
49762
|
+
PiiDetector.attachTo = attachTo;
|
|
49763
|
+
})(PiiDetector ||= {});
|
|
49764
|
+
});
|
|
49765
|
+
|
|
49766
|
+
// ../core/src/privacy-gateway.ts
|
|
49767
|
+
import { createHash as createHash6 } from "crypto";
|
|
49768
|
+
import { appendFile, mkdir, writeFile as writeFile2 } from "fs/promises";
|
|
49769
|
+
import path7 from "path";
|
|
49770
|
+
var FlowGateway;
|
|
49771
|
+
var init_privacy_gateway = __esm(() => {
|
|
49772
|
+
init_entity_graph();
|
|
49773
|
+
init_pii_detector();
|
|
49774
|
+
((FlowGateway) => {
|
|
49775
|
+
FlowGateway.ROLLOUT_MODES = [
|
|
49776
|
+
"observe",
|
|
49777
|
+
"sanitized_shadow",
|
|
49778
|
+
"zone2_egress",
|
|
49779
|
+
"tool_log",
|
|
49780
|
+
"verifier",
|
|
49781
|
+
"non_bypassable"
|
|
49782
|
+
];
|
|
49783
|
+
FlowGateway.DEFAULT_POLICY = {
|
|
49784
|
+
id: "kifaru.privacy.observe.v1",
|
|
49785
|
+
rolloutMode: "observe"
|
|
49786
|
+
};
|
|
49787
|
+
function rolloutModeRank(mode) {
|
|
49788
|
+
return FlowGateway.ROLLOUT_MODES.indexOf(mode);
|
|
49789
|
+
}
|
|
49790
|
+
FlowGateway.rolloutModeRank = rolloutModeRank;
|
|
49791
|
+
function rolloutAtLeast(mode, gate) {
|
|
49792
|
+
return rolloutModeRank(mode) >= rolloutModeRank(gate);
|
|
49793
|
+
}
|
|
49794
|
+
FlowGateway.rolloutAtLeast = rolloutAtLeast;
|
|
49795
|
+
function shouldEnforce(decision, action, mode) {
|
|
49796
|
+
if (mode === "observe" || mode === "sanitized_shadow")
|
|
49797
|
+
return false;
|
|
49798
|
+
if (decision.decision === "allow")
|
|
49799
|
+
return true;
|
|
49800
|
+
if (action === "model.call.before" || action === "model.call.after" || action === "model.fallback") {
|
|
49801
|
+
return rolloutAtLeast(mode, "zone2_egress");
|
|
49802
|
+
}
|
|
49803
|
+
if (action === "report.export" || action === "report.finding") {
|
|
49804
|
+
return rolloutAtLeast(mode, "zone2_egress");
|
|
49805
|
+
}
|
|
49806
|
+
if (action === "tool.call.before" || action === "tool.result.after" || action === "mcp.tool.call.before" || action === "mcp.tool.result.after" || action === "log.write" || action === "trace.write" || action === "memory.read" || action === "memory.write") {
|
|
49807
|
+
return rolloutAtLeast(mode, "tool_log");
|
|
49808
|
+
}
|
|
49809
|
+
return rolloutAtLeast(mode, "non_bypassable");
|
|
49810
|
+
}
|
|
49811
|
+
FlowGateway.shouldEnforce = shouldEnforce;
|
|
49812
|
+
function stableStringify(input2) {
|
|
49813
|
+
if (input2 === undefined)
|
|
49814
|
+
return "null";
|
|
49815
|
+
if (input2 === null || typeof input2 !== "object")
|
|
49816
|
+
return JSON.stringify(input2);
|
|
49817
|
+
if (Array.isArray(input2))
|
|
49818
|
+
return `[${input2.map((item) => stableStringify(item)).join(",")}]`;
|
|
49819
|
+
const record3 = input2;
|
|
49820
|
+
return `{${Object.keys(record3).sort().filter((key) => record3[key] !== undefined).map((key) => `${JSON.stringify(key)}:${stableStringify(record3[key])}`).join(",")}}`;
|
|
49821
|
+
}
|
|
49822
|
+
FlowGateway.stableStringify = stableStringify;
|
|
49823
|
+
function stableHash(input2) {
|
|
49824
|
+
return createHash6("sha256").update(stableStringify(input2)).digest("hex");
|
|
49825
|
+
}
|
|
49826
|
+
FlowGateway.stableHash = stableHash;
|
|
49827
|
+
function contentHash(content) {
|
|
49828
|
+
return createHash6("sha256").update(content).digest("hex");
|
|
49829
|
+
}
|
|
49830
|
+
FlowGateway.contentHash = contentHash;
|
|
49831
|
+
let registry3 = [];
|
|
49832
|
+
let engagementRegistry;
|
|
49833
|
+
function bindEngagementRegistry(reg) {
|
|
49834
|
+
engagementRegistry = reg;
|
|
49835
|
+
}
|
|
49836
|
+
FlowGateway.bindEngagementRegistry = bindEngagementRegistry;
|
|
49837
|
+
function getEngagementRegistry() {
|
|
49838
|
+
return engagementRegistry;
|
|
49839
|
+
}
|
|
49840
|
+
FlowGateway.getEngagementRegistry = getEngagementRegistry;
|
|
49841
|
+
function getDetectorRegistry() {
|
|
49842
|
+
return registry3;
|
|
49843
|
+
}
|
|
49844
|
+
FlowGateway.getDetectorRegistry = getDetectorRegistry;
|
|
49845
|
+
function setDetectorRegistry(next) {
|
|
49846
|
+
registry3 = [...next];
|
|
49847
|
+
}
|
|
49848
|
+
FlowGateway.setDetectorRegistry = setDetectorRegistry;
|
|
49849
|
+
function registerDetector(detector) {
|
|
49850
|
+
registry3.push(detector);
|
|
49851
|
+
}
|
|
49852
|
+
FlowGateway.registerDetector = registerDetector;
|
|
49853
|
+
function resetDetectorRegistry() {
|
|
49854
|
+
registry3 = [FlowGateway.regexDetector, FlowGateway.entityGraphDetector, FlowGateway.provenanceDetector, FlowGateway.piiDetector];
|
|
49855
|
+
}
|
|
49856
|
+
FlowGateway.resetDetectorRegistry = resetDetectorRegistry;
|
|
49857
|
+
function secretPatterns() {
|
|
49858
|
+
return [
|
|
49859
|
+
/\b(?:sk|ghp|AKIA|ASIA|xox[baprs]|kf_secret)[A-Za-z0-9_\-]{6,}\b/g,
|
|
49860
|
+
/\bGOCSPX-[A-Za-z0-9_\-]{6,}\b/g,
|
|
49861
|
+
/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g,
|
|
49862
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/g,
|
|
49863
|
+
/\bAIza[0-9A-Za-z_-]{35}\b/g,
|
|
49864
|
+
/(?:(?:password|passwd|secret|api[_-]?key|token|bearer|[A-Za-z0-9_-]{0,40}(?:key|secret|token|password))\s*[=:]\s*(?!\$\{)(?!([^\s"',;}\])])\1*(?![^\s"',;}\])]))(?!(?:true|false|verbose|none|null|changeme|example|your_token_here)(?![^\s"',;}\])]))(?=[^\s"',;}\])]*(?:\d|[^\sA-Za-z0-9"',;}\])])|[^\s"',;}\])]{20})[^\s"',;}\])]{6,})|(?:(?:password|passwd|secret|api[_-]?key|token|bearer|[A-Za-z0-9_-]{0,40}(?:key|secret|token|password))\s+(?!\$\{)(?!([^\s"',;}\])])\2*(?![^\s"',;}\])]))(?!(?:true|false|verbose|none|null|changeme|example|your_token_here)(?![^\s"',;}\])]))(?=[^\s"',;}\])]*(?:\d|[^\sA-Za-z0-9"',;}\])])|[^\s"',;}\])]{20})[^\s"',;}\])]{6,})|(?:Authorization\s*:\s*(?:Bearer\s+(?!\$\{)(?!([^\s"',;}\])])\3*(?![^\s"',;}\])]))(?!(?:true|false|verbose|none|null|changeme|example|your_token_here)(?![^\s"',;}\])]))(?=[^\s"',;}\])]*(?:\d|[^\sA-Za-z0-9"',;}\])])|[^\s"',;}\])]{20})|Basic\s+(?!\$\{)(?!([^\s"',;}\])])\4*(?![^\s"',;}\])]))(?!(?:true|false|verbose|none|null|changeme|example|your_token_here)(?![^\s"',;}\])])))[^\s"',;}\])]{6,})/gi
|
|
49865
|
+
];
|
|
49866
|
+
}
|
|
49867
|
+
function cloudAccountPatterns() {
|
|
49868
|
+
return [
|
|
49869
|
+
/arn:aws:[^:\s]*:[^:\s]*:(\d{12})\b/g,
|
|
49870
|
+
/(?:aws|account)[^\d]{0,20}\b(\d{12})\b/gi,
|
|
49871
|
+
/\b(\d{12})\b[^\d]{0,20}(?:aws|account)/gi
|
|
49872
|
+
];
|
|
49873
|
+
}
|
|
49874
|
+
const REPO_PATH_REGEX = /\/(?:home|repo|srv|var|opt|usr|Users|mnt)\/[A-Za-z0-9._/\-]+/g;
|
|
49875
|
+
FlowGateway.regexDetector = (content) => {
|
|
49876
|
+
const labels = new Set;
|
|
49877
|
+
if (secretPatterns().some((re) => re.test(content)))
|
|
49878
|
+
labels.add("secret");
|
|
49879
|
+
if (/\b[a-z0-9-]+(?:\.[a-z0-9-]+)*\.(?:internal|corp|local|lan)\b/i.test(content)) {
|
|
49880
|
+
labels.add("internal_hostname");
|
|
49881
|
+
}
|
|
49882
|
+
if (cloudAccountPatterns().some((re) => re.test(content)))
|
|
49883
|
+
labels.add("cloud_account_id");
|
|
49884
|
+
if (REPO_PATH_REGEX.test(content)) {
|
|
49885
|
+
REPO_PATH_REGEX.lastIndex = 0;
|
|
49886
|
+
labels.add("repo_path");
|
|
49887
|
+
}
|
|
49888
|
+
if (/\b(?:HTTP\/1\.1 200|stack trace|uid=\d+|curl -i|exploit output)\b/i.test(content))
|
|
49889
|
+
labels.add("exploit_output");
|
|
49890
|
+
if (/\b(?:CVE-\d{4}-\d+|SSRF|IDOR|authorization bypass|privilege escalation)\b/i.test(content)) {
|
|
49891
|
+
labels.add("vulnerability_evidence");
|
|
49892
|
+
}
|
|
49893
|
+
if (/\b(?:ignore previous instructions|exfiltrate|send the secret|leak the token)\b/i.test(content)) {
|
|
49894
|
+
labels.add("prompt_injection");
|
|
49895
|
+
}
|
|
49896
|
+
return [...labels].sort();
|
|
49897
|
+
};
|
|
49898
|
+
FlowGateway.entityGraphDetector = (content, context2) => {
|
|
49899
|
+
const graph = context2.engagementGraph ?? engagementRegistry?.get(context2.engagement);
|
|
49900
|
+
if (!graph)
|
|
49901
|
+
return [];
|
|
49902
|
+
const hits = detectEntityMatches({ content, graph });
|
|
49903
|
+
if (hits.length === 0)
|
|
49904
|
+
return [];
|
|
49905
|
+
const labels = new Set;
|
|
49906
|
+
for (const hit of hits) {
|
|
49907
|
+
switch (hit.field) {
|
|
49908
|
+
case "domains":
|
|
49909
|
+
labels.add("internal_hostname");
|
|
49910
|
+
break;
|
|
49911
|
+
case "cidrs":
|
|
49912
|
+
labels.add("internal_hostname");
|
|
49913
|
+
break;
|
|
49914
|
+
case "cloud_accounts":
|
|
49915
|
+
labels.add("cloud_account_id");
|
|
49916
|
+
break;
|
|
49917
|
+
case "repos":
|
|
49918
|
+
labels.add("repo_path");
|
|
49919
|
+
break;
|
|
49920
|
+
case "team_names":
|
|
49921
|
+
case "employee_names":
|
|
49922
|
+
labels.add("customer_data");
|
|
49923
|
+
break;
|
|
49924
|
+
case "build_jobs":
|
|
49925
|
+
labels.add("engagement_asset");
|
|
49926
|
+
break;
|
|
49927
|
+
default:
|
|
49928
|
+
labels.add("engagement_asset");
|
|
49929
|
+
}
|
|
49930
|
+
}
|
|
49931
|
+
return [...labels].sort();
|
|
49932
|
+
};
|
|
49933
|
+
FlowGateway.provenanceSensor = (_content, context2) => {
|
|
49934
|
+
const labels = new Set;
|
|
49935
|
+
const metadata = context2.metadata ?? {};
|
|
49936
|
+
const surface = context2.sourceSurface ?? "";
|
|
49937
|
+
if (typeof metadata.mcpServerId === "string" && metadata.mcpServerId.length > 0) {
|
|
49938
|
+
labels.add("untrusted_provenance");
|
|
49939
|
+
}
|
|
49940
|
+
if (surface.startsWith("mcp.tool")) {
|
|
49941
|
+
labels.add("untrusted_provenance");
|
|
49942
|
+
}
|
|
49943
|
+
if (typeof metadata.sourceUrl === "string" && /^https?:\/\//i.test(metadata.sourceUrl)) {
|
|
49944
|
+
labels.add("untrusted_provenance");
|
|
49945
|
+
}
|
|
49946
|
+
const tool2 = typeof metadata.tool === "string" ? metadata.tool : "";
|
|
49947
|
+
if (tool2 && /(?:browser|fetch|crawl|scrape|wget|curl)/i.test(tool2)) {
|
|
49948
|
+
labels.add("untrusted_provenance");
|
|
49949
|
+
}
|
|
49950
|
+
return [...labels].sort();
|
|
49951
|
+
};
|
|
49952
|
+
FlowGateway.provenanceDetector = FlowGateway.provenanceSensor;
|
|
49953
|
+
FlowGateway.piiDetector = (() => {
|
|
49954
|
+
const detect = PiiDetector.build();
|
|
49955
|
+
return (content, ctx) => detect(content, ctx);
|
|
49956
|
+
})();
|
|
49957
|
+
registry3 = [FlowGateway.regexDetector, FlowGateway.entityGraphDetector, FlowGateway.provenanceDetector, FlowGateway.piiDetector];
|
|
49958
|
+
function detectLabels(content, context2) {
|
|
49959
|
+
const ctx = context2 ?? {};
|
|
49960
|
+
const all = registry3.flatMap((detector) => {
|
|
49961
|
+
try {
|
|
49962
|
+
return detector(content, ctx);
|
|
49963
|
+
} catch {
|
|
49964
|
+
return [];
|
|
49965
|
+
}
|
|
49966
|
+
});
|
|
49967
|
+
return [...new Set(all)].sort();
|
|
49968
|
+
}
|
|
49969
|
+
FlowGateway.detectLabels = detectLabels;
|
|
49970
|
+
function createFlowEvent(input2) {
|
|
49971
|
+
const detectContext = {
|
|
49972
|
+
engagement: typeof input2.metadata?.engagement === "string" ? input2.metadata.engagement : undefined,
|
|
49973
|
+
engagementGraph: input2.metadata?.engagementGraph,
|
|
49974
|
+
metadata: input2.metadata,
|
|
49975
|
+
sourceSurface: input2.sourceSurface
|
|
49976
|
+
};
|
|
49977
|
+
const labels = [...new Set([...input2.labels ?? [], ...detectLabels(input2.content, detectContext)])].sort();
|
|
49978
|
+
const base = {
|
|
49979
|
+
schemaVersion: "kifaru.flow-event.v1",
|
|
49980
|
+
actor: input2.actor,
|
|
49981
|
+
sessionId: input2.sessionId,
|
|
49982
|
+
action: input2.action,
|
|
49983
|
+
purpose: input2.purpose,
|
|
49984
|
+
destination: input2.destination,
|
|
49985
|
+
destinationTrustZone: input2.destinationTrustZone,
|
|
49986
|
+
contentRef: input2.contentRef,
|
|
49987
|
+
inputRefs: input2.inputRefs ?? [],
|
|
49988
|
+
sourceSurface: input2.sourceSurface,
|
|
49989
|
+
sourceTrustZone: input2.sourceTrustZone,
|
|
49990
|
+
representation: input2.representation,
|
|
49991
|
+
labels,
|
|
49992
|
+
metadata: input2.metadata ?? {},
|
|
49993
|
+
contentHash: contentHash(input2.content),
|
|
49994
|
+
contentBytes: new TextEncoder().encode(input2.content).byteLength
|
|
49995
|
+
};
|
|
49996
|
+
return {
|
|
49997
|
+
...base,
|
|
49998
|
+
eventId: stableHash(base)
|
|
49999
|
+
};
|
|
50000
|
+
}
|
|
50001
|
+
FlowGateway.createFlowEvent = createFlowEvent;
|
|
50002
|
+
function hasSensitiveLabel(labels) {
|
|
50003
|
+
return labels.some((label) => [
|
|
50004
|
+
"pii",
|
|
50005
|
+
"secret",
|
|
50006
|
+
"internal_hostname",
|
|
50007
|
+
"cloud_account_id",
|
|
50008
|
+
"repo_path",
|
|
50009
|
+
"exploit_output",
|
|
50010
|
+
"vulnerability_evidence",
|
|
50011
|
+
"customer_data",
|
|
50012
|
+
"unknown_sensitive",
|
|
50013
|
+
"engagement_asset"
|
|
50014
|
+
].includes(label));
|
|
50015
|
+
}
|
|
50016
|
+
function hasUntrustedProvenance(labels) {
|
|
50017
|
+
return labels.includes("untrusted_provenance");
|
|
50018
|
+
}
|
|
50019
|
+
function hasEvidenceIds(event) {
|
|
50020
|
+
const evidenceIds = event.metadata?.evidenceIds;
|
|
50021
|
+
return Array.isArray(evidenceIds) && evidenceIds.length > 0;
|
|
50022
|
+
}
|
|
50023
|
+
function decideFlow(event, policy = FlowGateway.DEFAULT_POLICY) {
|
|
50024
|
+
const obligations = [];
|
|
50025
|
+
const outputRefs = [];
|
|
50026
|
+
let decision = "allow";
|
|
50027
|
+
let representation = event.representation;
|
|
50028
|
+
const sensitive = hasSensitiveLabel(event.labels);
|
|
50029
|
+
const rawSensitive = sensitive && event.representation === "raw";
|
|
50030
|
+
if (event.action === "model.fallback" && event.metadata?.previousRepresentation && event.metadata.previousRepresentation !== "raw" && event.representation === "raw") {
|
|
50031
|
+
decision = "block";
|
|
50032
|
+
obligations.push("fallback_must_not_downgrade_privacy");
|
|
50033
|
+
} else if (event.action === "report.finding" && !hasEvidenceIds(event)) {
|
|
50034
|
+
decision = "require_approval";
|
|
50035
|
+
obligations.push("attach_evidence_ids_before_report");
|
|
50036
|
+
} else if (event.action === "mcp.tool.result.after" && event.labels.includes("prompt_injection")) {
|
|
50037
|
+
decision = "store_raw_return_ref";
|
|
50038
|
+
representation = "reference";
|
|
50039
|
+
obligations.push("vault_raw_mcp_result");
|
|
50040
|
+
obligations.push("return_sanitized_preview");
|
|
50041
|
+
outputRefs.push(`evidence:${event.contentHash.slice(0, 16)}`);
|
|
50042
|
+
} else if (event.action === "mcp.tool.result.after" && hasUntrustedProvenance(event.labels) && event.representation === "raw") {
|
|
50043
|
+
decision = "store_raw_return_ref";
|
|
50044
|
+
representation = "reference";
|
|
50045
|
+
obligations.push("vault_untrusted_mcp_result");
|
|
50046
|
+
obligations.push("return_sanitized_preview");
|
|
50047
|
+
outputRefs.push(`evidence:${event.contentHash.slice(0, 16)}`);
|
|
50048
|
+
} else if (rawSensitive && (event.action === "tool.result.after" || event.action === "mcp.tool.result.after")) {
|
|
50049
|
+
decision = "store_raw_return_ref";
|
|
50050
|
+
representation = "reference";
|
|
50051
|
+
obligations.push("vault_raw_tool_result");
|
|
50052
|
+
obligations.push("return_sanitized_preview");
|
|
50053
|
+
outputRefs.push(`evidence:${event.contentHash.slice(0, 16)}`);
|
|
50054
|
+
} else if (rawSensitive && (event.destinationTrustZone === "zone_2_external" || event.action === "log.write" || event.action === "trace.write" || event.action === "memory.write" || event.action === "memory.read" || event.action === "report.export" || event.action === "agent.message")) {
|
|
50055
|
+
decision = "transform";
|
|
50056
|
+
representation = "sanitized_preview";
|
|
50057
|
+
obligations.push("replace_raw_values_with_aliases");
|
|
50058
|
+
obligations.push("preserve_typed_evidence_refs");
|
|
50059
|
+
}
|
|
50060
|
+
const base = {
|
|
50061
|
+
schemaVersion: "kifaru.flow-decision.v1",
|
|
50062
|
+
eventId: event.eventId,
|
|
50063
|
+
eventHash: stableHash(event),
|
|
50064
|
+
decision,
|
|
50065
|
+
representation,
|
|
50066
|
+
labels: event.labels,
|
|
50067
|
+
policyId: policy.id,
|
|
50068
|
+
obligations,
|
|
50069
|
+
outputRefs
|
|
50070
|
+
};
|
|
50071
|
+
return {
|
|
50072
|
+
...base,
|
|
50073
|
+
decisionId: stableHash(base)
|
|
50074
|
+
};
|
|
50075
|
+
}
|
|
50076
|
+
FlowGateway.decideFlow = decideFlow;
|
|
50077
|
+
function createAuditRecord(event, decision, generatedAt) {
|
|
50078
|
+
const base = {
|
|
50079
|
+
schemaVersion: "kifaru.flow-audit.v1",
|
|
50080
|
+
generatedAt,
|
|
50081
|
+
event,
|
|
50082
|
+
decision
|
|
50083
|
+
};
|
|
50084
|
+
return {
|
|
50085
|
+
...base,
|
|
50086
|
+
auditId: stableHash(base)
|
|
50087
|
+
};
|
|
50088
|
+
}
|
|
50089
|
+
FlowGateway.createAuditRecord = createAuditRecord;
|
|
50090
|
+
|
|
50091
|
+
class AuditLedger {
|
|
50092
|
+
records = [];
|
|
50093
|
+
append(record3) {
|
|
50094
|
+
this.records.push(record3);
|
|
50095
|
+
}
|
|
50096
|
+
list() {
|
|
50097
|
+
return [...this.records];
|
|
50098
|
+
}
|
|
50099
|
+
}
|
|
50100
|
+
FlowGateway.AuditLedger = AuditLedger;
|
|
50101
|
+
async function appendAuditRecord(filepath, record3) {
|
|
50102
|
+
await mkdir(path7.dirname(filepath), { recursive: true });
|
|
50103
|
+
await appendFile(filepath, `${stableStringify(record3)}
|
|
50104
|
+
`, "utf8");
|
|
50105
|
+
}
|
|
50106
|
+
FlowGateway.appendAuditRecord = appendAuditRecord;
|
|
50107
|
+
function aliasFor(input2) {
|
|
50108
|
+
const prefix = {
|
|
50109
|
+
internal_hostname: "HOST",
|
|
50110
|
+
cloud_account_id: "CLOUD_ACCT",
|
|
50111
|
+
repo_path: "REPO_PATH",
|
|
50112
|
+
secret: "SECRET",
|
|
50113
|
+
pii: "PII",
|
|
50114
|
+
customer_data: "CUSTOMER",
|
|
50115
|
+
exploit_output: "EXPLOIT",
|
|
50116
|
+
vulnerability_evidence: "VULN",
|
|
50117
|
+
prompt_injection: "INJECT",
|
|
50118
|
+
unknown_sensitive: "SENSITIVE"
|
|
50119
|
+
};
|
|
50120
|
+
const tag2 = prefix[input2.label] ?? "EVIDENCE";
|
|
50121
|
+
const seed = stableStringify({ engagement: input2.engagement ?? "default", label: input2.label, value: input2.value });
|
|
50122
|
+
const digest2 = createHash6("sha256").update(seed).digest("hex");
|
|
50123
|
+
const num = parseInt(digest2.slice(0, 10), 16) % 1e6;
|
|
50124
|
+
return `${tag2}_${String(num).padStart(6, "0")}`;
|
|
50125
|
+
}
|
|
50126
|
+
FlowGateway.aliasFor = aliasFor;
|
|
50127
|
+
function sanitize(input2) {
|
|
50128
|
+
const aliases = {};
|
|
50129
|
+
let sanitized = input2.content;
|
|
50130
|
+
const tokenRules = [
|
|
50131
|
+
...secretPatterns().map((regex) => ({ regex, label: "secret" })),
|
|
50132
|
+
{
|
|
50133
|
+
regex: /\b[a-z0-9-]+(?:\.[a-z0-9-]+)*\.(?:internal|corp|local|lan)\b/gi,
|
|
50134
|
+
label: "internal_hostname"
|
|
50135
|
+
},
|
|
50136
|
+
{ regex: new RegExp(REPO_PATH_REGEX.source, "g"), label: "repo_path" }
|
|
50137
|
+
];
|
|
50138
|
+
for (const rule of tokenRules) {
|
|
50139
|
+
sanitized = sanitized.replace(rule.regex, (match) => {
|
|
50140
|
+
const alias = aliasFor({ engagement: input2.engagement, label: rule.label, value: match });
|
|
50141
|
+
aliases[alias] = match;
|
|
50142
|
+
return alias;
|
|
50143
|
+
});
|
|
50144
|
+
}
|
|
50145
|
+
for (const regex of cloudAccountPatterns()) {
|
|
50146
|
+
sanitized = sanitized.replace(regex, (match, account) => {
|
|
50147
|
+
if (!account)
|
|
50148
|
+
return match;
|
|
50149
|
+
const alias = aliasFor({ engagement: input2.engagement, label: "cloud_account_id", value: account });
|
|
50150
|
+
aliases[alias] = account;
|
|
50151
|
+
return match.replace(account, alias);
|
|
50152
|
+
});
|
|
50153
|
+
}
|
|
50154
|
+
const piiMatches = [...PiiDetector.findMatches(sanitized)].sort((a, b) => b.value.length - a.value.length);
|
|
50155
|
+
for (const hit of piiMatches) {
|
|
50156
|
+
const alias = aliasFor({ engagement: input2.engagement, label: "pii", value: hit.value });
|
|
50157
|
+
const escaped = hit.value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
50158
|
+
let replaced = false;
|
|
50159
|
+
sanitized = sanitized.replace(new RegExp(escaped, "g"), () => {
|
|
50160
|
+
replaced = true;
|
|
50161
|
+
return alias;
|
|
50162
|
+
});
|
|
50163
|
+
if (replaced)
|
|
50164
|
+
aliases[alias] = hit.value;
|
|
50165
|
+
}
|
|
50166
|
+
const graph = input2.engagementGraph ?? engagementRegistry?.get(input2.engagement);
|
|
50167
|
+
if (graph) {
|
|
50168
|
+
const hits = detectEntityMatches({ content: sanitized, graph });
|
|
50169
|
+
const ranked = [...hits].sort((a, b) => b.token.length - a.token.length);
|
|
50170
|
+
for (const hit of ranked) {
|
|
50171
|
+
const label = entityFieldToLabel(hit.field);
|
|
50172
|
+
const alias = aliasFor({ engagement: input2.engagement, label, value: hit.token });
|
|
50173
|
+
aliases[alias] = hit.token;
|
|
50174
|
+
const escaped = hit.token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
50175
|
+
const re = new RegExp(`(^|[^A-Za-z0-9_-])${escaped}([^A-Za-z0-9_-]|$)`, "gi");
|
|
50176
|
+
sanitized = sanitized.replace(re, (_match, before, after) => `${before}${alias}${after}`);
|
|
50177
|
+
}
|
|
50178
|
+
}
|
|
50179
|
+
return {
|
|
50180
|
+
sanitized,
|
|
50181
|
+
aliases,
|
|
50182
|
+
labels: detectLabels(input2.content, {
|
|
50183
|
+
engagement: input2.engagement,
|
|
50184
|
+
engagementGraph: graph
|
|
50185
|
+
})
|
|
50186
|
+
};
|
|
50187
|
+
}
|
|
50188
|
+
FlowGateway.sanitize = sanitize;
|
|
50189
|
+
function entityFieldToLabel(field) {
|
|
50190
|
+
switch (field) {
|
|
50191
|
+
case "domains":
|
|
50192
|
+
case "cidrs":
|
|
50193
|
+
return "internal_hostname";
|
|
50194
|
+
case "cloud_accounts":
|
|
50195
|
+
return "cloud_account_id";
|
|
50196
|
+
case "repos":
|
|
50197
|
+
return "repo_path";
|
|
50198
|
+
case "team_names":
|
|
50199
|
+
case "employee_names":
|
|
50200
|
+
return "customer_data";
|
|
50201
|
+
case "build_jobs":
|
|
50202
|
+
return "engagement_asset";
|
|
50203
|
+
default:
|
|
50204
|
+
return "engagement_asset";
|
|
50205
|
+
}
|
|
50206
|
+
}
|
|
50207
|
+
async function vaultRaw(input2) {
|
|
50208
|
+
const detectedLabels = [...new Set([...input2.labels ?? [], ...detectLabels(input2.content)])].sort();
|
|
50209
|
+
const { sanitized, aliases } = sanitize({ engagement: input2.engagement, content: input2.content });
|
|
50210
|
+
const hash4 = contentHash(input2.content);
|
|
50211
|
+
const evidenceId = `EV-${hash4.slice(0, 16)}`;
|
|
50212
|
+
const createdAt = new Date().toISOString();
|
|
50213
|
+
const entry = {
|
|
50214
|
+
evidenceId,
|
|
50215
|
+
contentHash: hash4,
|
|
50216
|
+
contentBytes: new TextEncoder().encode(input2.content).byteLength,
|
|
50217
|
+
labels: detectedLabels,
|
|
50218
|
+
aliases,
|
|
50219
|
+
sanitizedPreview: sanitized,
|
|
50220
|
+
trustZone: "zone_0_raw",
|
|
50221
|
+
createdAt
|
|
50222
|
+
};
|
|
50223
|
+
await mkdir(input2.vaultDir, { recursive: true, mode: 448 });
|
|
50224
|
+
const rawPath = path7.join(input2.vaultDir, `${evidenceId}.raw.txt`);
|
|
50225
|
+
const metaPath = path7.join(input2.vaultDir, `${evidenceId}.json`);
|
|
50226
|
+
await writeFile2(rawPath, input2.content, { encoding: "utf8", mode: 384 });
|
|
50227
|
+
await writeFile2(metaPath, stableStringify({
|
|
50228
|
+
...entry,
|
|
50229
|
+
sourceSurface: input2.sourceSurface ?? "unknown"
|
|
50230
|
+
}), { encoding: "utf8", mode: 384 });
|
|
50231
|
+
return entry;
|
|
50232
|
+
}
|
|
50233
|
+
FlowGateway.vaultRaw = vaultRaw;
|
|
50234
|
+
})(FlowGateway ||= {});
|
|
50235
|
+
});
|
|
50236
|
+
|
|
49491
50237
|
// ../core/src/index.ts
|
|
49492
50238
|
var init_src2 = __esm(() => {
|
|
49493
50239
|
init_kifaru_model_router();
|
|
@@ -49503,6 +50249,9 @@ var init_src2 = __esm(() => {
|
|
|
49503
50249
|
init_governed_skill_tool();
|
|
49504
50250
|
init_embedded_skills();
|
|
49505
50251
|
init_embedded_theme();
|
|
50252
|
+
init_privacy_gateway();
|
|
50253
|
+
init_entity_graph();
|
|
50254
|
+
init_pii_detector();
|
|
49506
50255
|
});
|
|
49507
50256
|
|
|
49508
50257
|
// ../headless-runtime/src/policy-gate.ts
|
|
@@ -49711,13 +50460,13 @@ var init_event_sink = __esm(() => {
|
|
|
49711
50460
|
|
|
49712
50461
|
// ../headless-runtime/src/sqlite-event-store.ts
|
|
49713
50462
|
import fs7 from "fs";
|
|
49714
|
-
import
|
|
50463
|
+
import path8 from "path";
|
|
49715
50464
|
import { Database as Database2 } from "bun:sqlite";
|
|
49716
50465
|
|
|
49717
50466
|
class SqliteEventStore {
|
|
49718
50467
|
db;
|
|
49719
50468
|
constructor(dbPath) {
|
|
49720
|
-
fs7.mkdirSync(
|
|
50469
|
+
fs7.mkdirSync(path8.dirname(dbPath), { recursive: true });
|
|
49721
50470
|
this.db = new Database2(dbPath, { create: true });
|
|
49722
50471
|
this.initialize();
|
|
49723
50472
|
}
|
|
@@ -50217,9 +50966,9 @@ var init_run_workflow = __esm(() => {
|
|
|
50217
50966
|
|
|
50218
50967
|
// ../headless-runtime/src/report-files.ts
|
|
50219
50968
|
import fs8 from "fs";
|
|
50220
|
-
import
|
|
50969
|
+
import path9 from "path";
|
|
50221
50970
|
function writeLocalReport(record3, outDir) {
|
|
50222
|
-
const base =
|
|
50971
|
+
const base = path9.join(outDir, record3.runId);
|
|
50223
50972
|
const files = {
|
|
50224
50973
|
json: `${base}.json`,
|
|
50225
50974
|
md: `${base}.md`,
|
|
@@ -50253,10 +51002,10 @@ var init_report_files = __esm(() => {
|
|
|
50253
51002
|
|
|
50254
51003
|
// ../headless-runtime/src/workflow-skill-editor.ts
|
|
50255
51004
|
import fs9 from "fs";
|
|
50256
|
-
import
|
|
50257
|
-
import { createHash as
|
|
51005
|
+
import path10 from "path";
|
|
51006
|
+
import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
|
|
50258
51007
|
function skillRoot() {
|
|
50259
|
-
return
|
|
51008
|
+
return path10.resolve(process.env.KIFARU_WORKFLOW_SKILLS_DIR ?? "data/headless-skill-overrides");
|
|
50260
51009
|
}
|
|
50261
51010
|
function builtIn(workflowKey) {
|
|
50262
51011
|
const workflow = workflowByKey(workflowKey);
|
|
@@ -50270,7 +51019,7 @@ function builtIn(workflowKey) {
|
|
|
50270
51019
|
return { skillName, source, pack };
|
|
50271
51020
|
}
|
|
50272
51021
|
function revision(markdown) {
|
|
50273
|
-
return
|
|
51022
|
+
return createHash7("sha256").update(markdown).digest("hex");
|
|
50274
51023
|
}
|
|
50275
51024
|
function validateMarkdown(markdown) {
|
|
50276
51025
|
const body = markdown.trim();
|
|
@@ -50281,7 +51030,7 @@ function validateMarkdown(markdown) {
|
|
|
50281
51030
|
}
|
|
50282
51031
|
function readWorkflowSkill(workflowKey) {
|
|
50283
51032
|
const { skillName, pack } = builtIn(workflowKey);
|
|
50284
|
-
const filename =
|
|
51033
|
+
const filename = path10.join(skillRoot(), `${workflowKey}.md`);
|
|
50285
51034
|
const customized = fs9.existsSync(filename);
|
|
50286
51035
|
const markdown = customized ? validateMarkdown(fs9.readFileSync(filename, "utf8")) : pack.body;
|
|
50287
51036
|
return { workflowKey, skillName, markdown, revision: revision(markdown), customized };
|
|
@@ -50294,8 +51043,8 @@ function saveWorkflowSkill(workflowKey, markdown, expectedRevision) {
|
|
|
50294
51043
|
}
|
|
50295
51044
|
const root = skillRoot();
|
|
50296
51045
|
fs9.mkdirSync(root, { recursive: true });
|
|
50297
|
-
const filename =
|
|
50298
|
-
const pending =
|
|
51046
|
+
const filename = path10.join(root, `${workflowKey}.md`);
|
|
51047
|
+
const pending = path10.join(root, `${workflowKey}.${randomUUID3()}.pending`);
|
|
50299
51048
|
try {
|
|
50300
51049
|
fs9.writeFileSync(pending, `${body}
|
|
50301
51050
|
`, { flag: "wx" });
|
|
@@ -52891,7 +53640,7 @@ class HttpClient {
|
|
|
52891
53640
|
this.request = async ({
|
|
52892
53641
|
body,
|
|
52893
53642
|
secure,
|
|
52894
|
-
path:
|
|
53643
|
+
path: path12,
|
|
52895
53644
|
type,
|
|
52896
53645
|
query,
|
|
52897
53646
|
format,
|
|
@@ -52904,7 +53653,7 @@ class HttpClient {
|
|
|
52904
53653
|
const queryString = query && this.toQueryString(query);
|
|
52905
53654
|
const payloadFormatter = this.contentFormatters[type || ContentType.Json];
|
|
52906
53655
|
const responseFormat = format || requestParams.format;
|
|
52907
|
-
return this.customFetch(`${baseUrl || this.baseUrl || ""}${
|
|
53656
|
+
return this.customFetch(`${baseUrl || this.baseUrl || ""}${path12}${queryString ? `?${queryString}` : ""}`, {
|
|
52908
53657
|
...requestParams,
|
|
52909
53658
|
headers: {
|
|
52910
53659
|
...requestParams.headers || {},
|
|
@@ -64316,10 +65065,10 @@ function escapeLike(value) {
|
|
|
64316
65065
|
// src/platform/interactive-report.ts
|
|
64317
65066
|
init_src();
|
|
64318
65067
|
init_src3();
|
|
64319
|
-
import
|
|
64320
|
-
import { createHash as
|
|
65068
|
+
import path11 from "path";
|
|
65069
|
+
import { createHash as createHash8 } from "crypto";
|
|
64321
65070
|
function stableUuid(value) {
|
|
64322
|
-
const bytes =
|
|
65071
|
+
const bytes = createHash8("sha256").update(value).digest();
|
|
64323
65072
|
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
64324
65073
|
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
64325
65074
|
const hex5 = bytes.subarray(0, 16).toString("hex");
|
|
@@ -64380,11 +65129,11 @@ function writeInteractiveRunReport(db, workspaceID, platformRunID, outDir) {
|
|
|
64380
65129
|
evidence,
|
|
64381
65130
|
version: 0
|
|
64382
65131
|
});
|
|
64383
|
-
return writeLocalReport(record3,
|
|
65132
|
+
return writeLocalReport(record3, path11.resolve(outDir));
|
|
64384
65133
|
}
|
|
64385
65134
|
|
|
64386
65135
|
// src/platform/repository.ts
|
|
64387
|
-
import { createHash as
|
|
65136
|
+
import { createHash as createHash9, randomUUID as randomUUID4 } from "crypto";
|
|
64388
65137
|
class PlatformRunNotFoundError extends Error {
|
|
64389
65138
|
name = "PlatformRunNotFoundError";
|
|
64390
65139
|
}
|
|
@@ -64823,7 +65572,7 @@ function createPlatformRepository(db) {
|
|
|
64823
65572
|
insertJob.run(id, actor.workspaceID, input2.runID ?? null, input2.kind, input2.priority, JSON.stringify(input2.payload), input2.maxAttempts, input2.availableAt ?? now2, now2, now2, input2.idempotencyKey);
|
|
64824
65573
|
const delivery2 = githubDelivery(input2.kind, input2.payload);
|
|
64825
65574
|
if (delivery2) {
|
|
64826
|
-
upsertWebhookDelivery.run(delivery2.deliveryID, actor.workspaceID, delivery2.eventName, delivery2.action,
|
|
65575
|
+
upsertWebhookDelivery.run(delivery2.deliveryID, actor.workspaceID, delivery2.eventName, delivery2.action, createHash9("sha256").update(JSON.stringify(input2.payload)).digest("hex"), input2.runID ?? null, now2);
|
|
64827
65576
|
}
|
|
64828
65577
|
const created = findJobByID.get(actor.workspaceID, id);
|
|
64829
65578
|
db.exec("COMMIT");
|
|
@@ -64905,7 +65654,7 @@ function createPlatformRepository(db) {
|
|
|
64905
65654
|
try {
|
|
64906
65655
|
for (const finding of inputs) {
|
|
64907
65656
|
const existing = findFinding.get(workspaceID, finding.fingerprint);
|
|
64908
|
-
const id = existing?.id ?? `finding_${
|
|
65657
|
+
const id = existing?.id ?? `finding_${createHash9("sha256").update(`${workspaceID}:${finding.fingerprint}`).digest("hex").slice(0, 24)}`;
|
|
64909
65658
|
const description = finding.description ?? finding.title;
|
|
64910
65659
|
const cwe = finding.cwe ?? (finding.ruleID.startsWith("CWE-") ? finding.ruleID : null);
|
|
64911
65660
|
if (existing) {
|
|
@@ -65133,10 +65882,10 @@ function mapAgentSession(row) {
|
|
|
65133
65882
|
};
|
|
65134
65883
|
}
|
|
65135
65884
|
function operationID(workspaceID, sessionID, toolCallID) {
|
|
65136
|
-
return `operation_${
|
|
65885
|
+
return `operation_${createHash9("sha256").update(`${workspaceID}:${sessionID}:${toolCallID}`).digest("hex").slice(0, 24)}`;
|
|
65137
65886
|
}
|
|
65138
65887
|
function evidenceID(runID, fingerprint) {
|
|
65139
|
-
return `evidence_${
|
|
65888
|
+
return `evidence_${createHash9("sha256").update(`${runID}:${fingerprint}`).digest("hex").slice(0, 24)}`;
|
|
65140
65889
|
}
|
|
65141
65890
|
function redactForStorage(value, depth = 0) {
|
|
65142
65891
|
if (value === undefined || value === null || typeof value === "boolean" || typeof value === "number")
|
|
@@ -65197,11 +65946,11 @@ var getFilePath = (options) => {
|
|
|
65197
65946
|
} else if (!filename.match(/\.[a-zA-Z0-9_-]+$/)) {
|
|
65198
65947
|
filename = filename.concat("/" + defaultDocument);
|
|
65199
65948
|
}
|
|
65200
|
-
const
|
|
65949
|
+
const path12 = getFilePathWithoutDefaultDocument({
|
|
65201
65950
|
root: options.root,
|
|
65202
65951
|
filename
|
|
65203
65952
|
});
|
|
65204
|
-
return
|
|
65953
|
+
return path12;
|
|
65205
65954
|
};
|
|
65206
65955
|
var getFilePathWithoutDefaultDocument = (options) => {
|
|
65207
65956
|
let root = options.root || "";
|
|
@@ -65212,12 +65961,12 @@ var getFilePathWithoutDefaultDocument = (options) => {
|
|
|
65212
65961
|
filename = filename.replace(/^\.?[\/\\]/, "");
|
|
65213
65962
|
filename = filename.replace(/\\/, "/");
|
|
65214
65963
|
root = root.replace(/\/$/, "");
|
|
65215
|
-
let
|
|
65216
|
-
|
|
65217
|
-
if (root[0] !== "/" &&
|
|
65964
|
+
let path12 = root ? root + "/" + filename : filename;
|
|
65965
|
+
path12 = path12.replace(/^\.?\//, "");
|
|
65966
|
+
if (root[0] !== "/" && path12[0] === "/") {
|
|
65218
65967
|
return;
|
|
65219
65968
|
}
|
|
65220
|
-
return
|
|
65969
|
+
return path12;
|
|
65221
65970
|
};
|
|
65222
65971
|
|
|
65223
65972
|
// ../../node_modules/.bun/hono@4.7.10/node_modules/hono/dist/utils/mime.js
|
|
@@ -65300,7 +66049,7 @@ var ENCODINGS = {
|
|
|
65300
66049
|
};
|
|
65301
66050
|
var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
|
|
65302
66051
|
var DEFAULT_DOCUMENT = "index.html";
|
|
65303
|
-
var defaultPathResolve = (
|
|
66052
|
+
var defaultPathResolve = (path12) => path12;
|
|
65304
66053
|
var serveStatic = (options) => {
|
|
65305
66054
|
let isAbsoluteRoot = false;
|
|
65306
66055
|
let root;
|
|
@@ -65328,21 +66077,21 @@ var serveStatic = (options) => {
|
|
|
65328
66077
|
filename += "/";
|
|
65329
66078
|
}
|
|
65330
66079
|
}
|
|
65331
|
-
let
|
|
66080
|
+
let path12 = getFilePath({
|
|
65332
66081
|
filename,
|
|
65333
66082
|
root,
|
|
65334
66083
|
defaultDocument: DEFAULT_DOCUMENT
|
|
65335
66084
|
});
|
|
65336
|
-
if (!
|
|
66085
|
+
if (!path12) {
|
|
65337
66086
|
return await next();
|
|
65338
66087
|
}
|
|
65339
66088
|
if (isAbsoluteRoot) {
|
|
65340
|
-
|
|
66089
|
+
path12 = "/" + path12;
|
|
65341
66090
|
}
|
|
65342
66091
|
const getContent = options.getContent;
|
|
65343
66092
|
const pathResolve = options.pathResolve ?? defaultPathResolve;
|
|
65344
|
-
|
|
65345
|
-
let content = await getContent(
|
|
66093
|
+
path12 = pathResolve(path12);
|
|
66094
|
+
let content = await getContent(path12, c);
|
|
65346
66095
|
if (!content) {
|
|
65347
66096
|
let pathWithoutDefaultDocument = getFilePathWithoutDefaultDocument({
|
|
65348
66097
|
filename,
|
|
@@ -65352,10 +66101,10 @@ var serveStatic = (options) => {
|
|
|
65352
66101
|
return await next();
|
|
65353
66102
|
}
|
|
65354
66103
|
pathWithoutDefaultDocument = pathResolve(pathWithoutDefaultDocument);
|
|
65355
|
-
if (pathWithoutDefaultDocument !==
|
|
66104
|
+
if (pathWithoutDefaultDocument !== path12) {
|
|
65356
66105
|
content = await getContent(pathWithoutDefaultDocument, c);
|
|
65357
66106
|
if (content) {
|
|
65358
|
-
|
|
66107
|
+
path12 = pathWithoutDefaultDocument;
|
|
65359
66108
|
}
|
|
65360
66109
|
}
|
|
65361
66110
|
}
|
|
@@ -65363,7 +66112,7 @@ var serveStatic = (options) => {
|
|
|
65363
66112
|
return c.newResponse(content.body, content);
|
|
65364
66113
|
}
|
|
65365
66114
|
if (content) {
|
|
65366
|
-
const mimeType = options.mimes && getMimeType(
|
|
66115
|
+
const mimeType = options.mimes && getMimeType(path12, options.mimes) || getMimeType(path12);
|
|
65367
66116
|
c.header("Content-Type", mimeType || "application/octet-stream");
|
|
65368
66117
|
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
|
65369
66118
|
const acceptEncodingSet = new Set(c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()));
|
|
@@ -65371,7 +66120,7 @@ var serveStatic = (options) => {
|
|
|
65371
66120
|
if (!acceptEncodingSet.has(encoding)) {
|
|
65372
66121
|
continue;
|
|
65373
66122
|
}
|
|
65374
|
-
const compressedContent = await getContent(
|
|
66123
|
+
const compressedContent = await getContent(path12 + ENCODINGS[encoding], c);
|
|
65375
66124
|
if (compressedContent) {
|
|
65376
66125
|
content = compressedContent;
|
|
65377
66126
|
c.header("Content-Encoding", encoding);
|
|
@@ -65380,10 +66129,10 @@ var serveStatic = (options) => {
|
|
|
65380
66129
|
}
|
|
65381
66130
|
}
|
|
65382
66131
|
}
|
|
65383
|
-
await options.onFound?.(
|
|
66132
|
+
await options.onFound?.(path12, c);
|
|
65384
66133
|
return c.body(content);
|
|
65385
66134
|
}
|
|
65386
|
-
await options.onNotFound?.(
|
|
66135
|
+
await options.onNotFound?.(path12, c);
|
|
65387
66136
|
await next();
|
|
65388
66137
|
return;
|
|
65389
66138
|
};
|
|
@@ -65392,18 +66141,18 @@ var serveStatic = (options) => {
|
|
|
65392
66141
|
// ../../node_modules/.bun/hono@4.7.10/node_modules/hono/dist/adapter/bun/serve-static.js
|
|
65393
66142
|
var serveStatic2 = (options) => {
|
|
65394
66143
|
return async function serveStatic22(c, next) {
|
|
65395
|
-
const getContent = async (
|
|
65396
|
-
|
|
65397
|
-
const file3 = Bun.file(
|
|
66144
|
+
const getContent = async (path12) => {
|
|
66145
|
+
path12 = path12.startsWith("/") ? path12 : `./${path12}`;
|
|
66146
|
+
const file3 = Bun.file(path12);
|
|
65398
66147
|
return await file3.exists() ? file3 : null;
|
|
65399
66148
|
};
|
|
65400
|
-
const pathResolve = (
|
|
65401
|
-
return
|
|
66149
|
+
const pathResolve = (path12) => {
|
|
66150
|
+
return path12.startsWith("/") ? path12 : `./${path12}`;
|
|
65402
66151
|
};
|
|
65403
|
-
const isDir = async (
|
|
66152
|
+
const isDir = async (path12) => {
|
|
65404
66153
|
let isDir2;
|
|
65405
66154
|
try {
|
|
65406
|
-
const stats = await stat(
|
|
66155
|
+
const stats = await stat(path12);
|
|
65407
66156
|
isDir2 = stats.isDirectory();
|
|
65408
66157
|
} catch {}
|
|
65409
66158
|
return isDir2;
|
|
@@ -65459,7 +66208,7 @@ var WSContext = class {
|
|
|
65459
66208
|
// src/app.ts
|
|
65460
66209
|
init_zod();
|
|
65461
66210
|
import fs11, { existsSync as existsSync2 } from "fs";
|
|
65462
|
-
import
|
|
66211
|
+
import path12 from "path";
|
|
65463
66212
|
|
|
65464
66213
|
// src/session-archive/contract.ts
|
|
65465
66214
|
init_zod();
|
|
@@ -66018,7 +66767,7 @@ function escapeLike2(value) {
|
|
|
66018
66767
|
|
|
66019
66768
|
// src/session-archive/writer.ts
|
|
66020
66769
|
init_zod();
|
|
66021
|
-
import { createHash as
|
|
66770
|
+
import { createHash as createHash10 } from "crypto";
|
|
66022
66771
|
var MAX_PREVIEW_LENGTH = 1000;
|
|
66023
66772
|
|
|
66024
66773
|
class SessionArchiveInputError extends Error {
|
|
@@ -66403,7 +67152,7 @@ function logLineID(sessionID, sequence) {
|
|
|
66403
67152
|
return `log_${hash4(`${sessionID}:${sequence}`)}`;
|
|
66404
67153
|
}
|
|
66405
67154
|
function hash4(value) {
|
|
66406
|
-
return
|
|
67155
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, 24);
|
|
66407
67156
|
}
|
|
66408
67157
|
|
|
66409
67158
|
// src/tracing.ts
|
|
@@ -67670,8 +68419,8 @@ Disallow: /
|
|
|
67670
68419
|
const events = store.readEvents(runId);
|
|
67671
68420
|
const job = store.getLocalRun(runId);
|
|
67672
68421
|
let started = events.find((event) => event.eventType === "headless.run.started")?.payload;
|
|
67673
|
-
const outDir =
|
|
67674
|
-
const reportPath =
|
|
68422
|
+
const outDir = path12.resolve(process.env.KIFARU_LOCAL_RUNS_OUT ?? "data/headless-reports");
|
|
68423
|
+
const reportPath = path12.join(outDir, `${runId}.md`);
|
|
67675
68424
|
if (!started && job) {
|
|
67676
68425
|
const workflow = workflowByKey(job.workflowKey);
|
|
67677
68426
|
started = {
|
|
@@ -67682,9 +68431,9 @@ Disallow: /
|
|
|
67682
68431
|
stages: workflow?.stages.map((stage2) => ({ key: stage2.key, name: stage2.name })) ?? []
|
|
67683
68432
|
};
|
|
67684
68433
|
}
|
|
67685
|
-
if (!started && fs11.existsSync(
|
|
68434
|
+
if (!started && fs11.existsSync(path12.join(outDir, `${runId}.json`))) {
|
|
67686
68435
|
try {
|
|
67687
|
-
const record3 = JSON.parse(fs11.readFileSync(
|
|
68436
|
+
const record3 = JSON.parse(fs11.readFileSync(path12.join(outDir, `${runId}.json`), "utf8"));
|
|
67688
68437
|
if (record3.runId === runId && typeof record3.workflowKey === "string" && typeof record3.target === "string") {
|
|
67689
68438
|
const workflow = workflowByKey(record3.workflowKey);
|
|
67690
68439
|
started = {
|
|
@@ -67765,7 +68514,7 @@ Disallow: /
|
|
|
67765
68514
|
if (!localReportsEnabled(c) || context2.actor.role !== "admin")
|
|
67766
68515
|
return c.json({ code: "local_runs_disabled" }, 403);
|
|
67767
68516
|
const { SqliteEventStore: SqliteEventStore2 } = await Promise.resolve().then(() => (init_src3(), exports_src2));
|
|
67768
|
-
const store = new SqliteEventStore2(
|
|
68517
|
+
const store = new SqliteEventStore2(path12.resolve(process.env.KIFARU_LOCAL_RUNS_DB ?? "data/headless-events.sqlite"));
|
|
67769
68518
|
try {
|
|
67770
68519
|
return c.json({ items: store.listLocalRunIds().flatMap((runId) => {
|
|
67771
68520
|
const item = localRunStatus(store, runId);
|
|
@@ -67785,7 +68534,7 @@ Disallow: /
|
|
|
67785
68534
|
if (!/^[0-9a-f-]{36}$/i.test(runId))
|
|
67786
68535
|
return c.json({ code: "invalid_run_id" }, 400);
|
|
67787
68536
|
const { SqliteEventStore: SqliteEventStore2 } = await Promise.resolve().then(() => (init_src3(), exports_src2));
|
|
67788
|
-
const store = new SqliteEventStore2(
|
|
68537
|
+
const store = new SqliteEventStore2(path12.resolve(process.env.KIFARU_LOCAL_RUNS_DB ?? "data/headless-events.sqlite"));
|
|
67789
68538
|
try {
|
|
67790
68539
|
const item = localRunStatus(store, runId);
|
|
67791
68540
|
return item ? c.json({ item }) : c.json({ code: "run_not_found" }, 404);
|
|
@@ -67808,8 +68557,8 @@ Disallow: /
|
|
|
67808
68557
|
if (!workflow)
|
|
67809
68558
|
return c.json({ code: "workflow_not_found", detail: "Workflow was not found." }, 404);
|
|
67810
68559
|
const { SqliteEventStore: SqliteEventStore2 } = await Promise.resolve().then(() => (init_src3(), exports_src2));
|
|
67811
|
-
const dbPath =
|
|
67812
|
-
const outDir =
|
|
68560
|
+
const dbPath = path12.resolve(process.env.KIFARU_LOCAL_RUNS_DB ?? "data/headless-events.sqlite");
|
|
68561
|
+
const outDir = path12.resolve(process.env.KIFARU_LOCAL_RUNS_OUT ?? "data/headless-reports");
|
|
67813
68562
|
const runId = randomUUID6();
|
|
67814
68563
|
const optional3 = new Set(workflow.stages.filter((s) => s.optional).map((s) => s.key));
|
|
67815
68564
|
const selectedOptionalStageKeys = (selectedStageKeys ?? []).filter((key) => optional3.has(key));
|
|
@@ -67833,7 +68582,7 @@ Disallow: /
|
|
|
67833
68582
|
permissionMode,
|
|
67834
68583
|
status: "queued",
|
|
67835
68584
|
dbPath,
|
|
67836
|
-
reportPath:
|
|
68585
|
+
reportPath: path12.join(outDir, `${runId}.md`)
|
|
67837
68586
|
}, 202);
|
|
67838
68587
|
});
|
|
67839
68588
|
const localReportsEnabled = (c) => process.env.KIFARU_LOCAL_RUNS === "1" && (["127.0.0.1", "::1", "localhost"].includes(input2.config.host) || isLoopbackPeer(c));
|
|
@@ -67844,14 +68593,14 @@ Disallow: /
|
|
|
67844
68593
|
return context2;
|
|
67845
68594
|
if (!localReportsEnabled(c))
|
|
67846
68595
|
return c.json({ code: "local_runs_disabled" }, 403);
|
|
67847
|
-
const outDir =
|
|
68596
|
+
const outDir = path12.resolve(process.env.KIFARU_LOCAL_RUNS_OUT ?? "data/headless-reports");
|
|
67848
68597
|
if (!fs11.existsSync(outDir))
|
|
67849
68598
|
return c.json({ items: [] });
|
|
67850
68599
|
const { ReportRecord: ReportRecord2 } = await Promise.resolve().then(() => (init_src(), exports_src));
|
|
67851
68600
|
const permitted = context2.actor.role === "admin" ? null : workspaceReportIDs(context2.workspace.workspaceID);
|
|
67852
68601
|
const items = fs11.readdirSync(outDir).filter((name21) => /^[0-9a-f-]{36}\.json$/i.test(name21)).flatMap((name21) => {
|
|
67853
68602
|
try {
|
|
67854
|
-
const record3 = ReportRecord2.parse(JSON.parse(fs11.readFileSync(
|
|
68603
|
+
const record3 = ReportRecord2.parse(JSON.parse(fs11.readFileSync(path12.join(outDir, name21), "utf8")));
|
|
67855
68604
|
if (record3.runId !== name21.slice(0, -5) || permitted && !permitted.has(record3.runId))
|
|
67856
68605
|
return [];
|
|
67857
68606
|
return [{
|
|
@@ -67881,12 +68630,12 @@ Disallow: /
|
|
|
67881
68630
|
if (!/^[0-9a-f-]{36}$/i.test(runId) || !["json", "md", "xlsx", "pdf"].includes(ext)) {
|
|
67882
68631
|
return c.json({ code: "invalid_report_path" }, 400);
|
|
67883
68632
|
}
|
|
67884
|
-
const outDir =
|
|
67885
|
-
const filename =
|
|
68633
|
+
const outDir = path12.resolve(process.env.KIFARU_LOCAL_RUNS_OUT ?? "data/headless-reports");
|
|
68634
|
+
const filename = path12.join(outDir, `${runId}.${ext}`);
|
|
67886
68635
|
if (!fs11.existsSync(filename))
|
|
67887
68636
|
return c.json({ code: "report_not_found" }, 404);
|
|
67888
68637
|
if (context2.actor.role !== "admin") {
|
|
67889
|
-
const metadata =
|
|
68638
|
+
const metadata = path12.join(outDir, `${runId}.json`);
|
|
67890
68639
|
if (!fs11.existsSync(metadata) || !workspaceReportIDs(context2.workspace.workspaceID).has(runId)) {
|
|
67891
68640
|
return c.json({ code: "report_not_found" }, 404);
|
|
67892
68641
|
}
|
|
@@ -68431,7 +69180,7 @@ import {
|
|
|
68431
69180
|
defineTool as defineTool3,
|
|
68432
69181
|
getAgentDir as getAgentDir2
|
|
68433
69182
|
} from "@earendil-works/pi-coding-agent";
|
|
68434
|
-
import
|
|
69183
|
+
import path14 from "path";
|
|
68435
69184
|
import fs13 from "fs";
|
|
68436
69185
|
init_src();
|
|
68437
69186
|
|
|
@@ -68652,7 +69401,7 @@ import {
|
|
|
68652
69401
|
createWriteToolDefinition
|
|
68653
69402
|
} from "@earendil-works/pi-coding-agent";
|
|
68654
69403
|
import fs12 from "fs";
|
|
68655
|
-
import
|
|
69404
|
+
import path13 from "path";
|
|
68656
69405
|
var APPROVAL_TIMEOUT_MS = 10 * 60000;
|
|
68657
69406
|
var DESTRUCTIVE_COMMANDS = new Set([
|
|
68658
69407
|
"dd",
|
|
@@ -68782,15 +69531,15 @@ Allow it?`,
|
|
|
68782
69531
|
return null;
|
|
68783
69532
|
}
|
|
68784
69533
|
function pathConsentRequest(target, cwd) {
|
|
68785
|
-
const resolved =
|
|
69534
|
+
const resolved = path13.resolve(cwd, target);
|
|
68786
69535
|
let canonical = resolved;
|
|
68787
69536
|
try {
|
|
68788
69537
|
let probe = resolved;
|
|
68789
69538
|
while (!fs12.existsSync(probe))
|
|
68790
|
-
probe =
|
|
68791
|
-
canonical =
|
|
69539
|
+
probe = path13.dirname(probe);
|
|
69540
|
+
canonical = path13.join(fs12.realpathSync(probe), resolved.slice(probe.length));
|
|
68792
69541
|
} catch {}
|
|
68793
|
-
const inside = canonical === cwd || canonical.startsWith(`${cwd}${
|
|
69542
|
+
const inside = canonical === cwd || canonical.startsWith(`${cwd}${path13.sep}`);
|
|
68794
69543
|
if (inside)
|
|
68795
69544
|
return null;
|
|
68796
69545
|
return {
|
|
@@ -73158,7 +73907,7 @@ class WorkbenchAgentService {
|
|
|
73158
73907
|
fs13.mkdirSync(config3.workbenchCwd, { recursive: true });
|
|
73159
73908
|
this.cwd = fs13.realpathSync(config3.workbenchCwd);
|
|
73160
73909
|
this.skillsPath = materializeKifaruSkills();
|
|
73161
|
-
this.registryPath =
|
|
73910
|
+
this.registryPath = path14.join(getAgentDir2(), "workbench-conversations.json");
|
|
73162
73911
|
this.saved = fs13.existsSync(this.registryPath) ? JSON.parse(fs13.readFileSync(this.registryPath, "utf8")) : [];
|
|
73163
73912
|
for (const saved of this.saved) {
|
|
73164
73913
|
for (const status of ["queued", "running"]) {
|
|
@@ -73385,7 +74134,7 @@ class WorkbenchAgentService {
|
|
|
73385
74134
|
this.persistRegistry();
|
|
73386
74135
|
}
|
|
73387
74136
|
persistRegistry() {
|
|
73388
|
-
fs13.mkdirSync(
|
|
74137
|
+
fs13.mkdirSync(path14.dirname(this.registryPath), { recursive: true });
|
|
73389
74138
|
const temporary = `${this.registryPath}.tmp`;
|
|
73390
74139
|
fs13.writeFileSync(temporary, JSON.stringify(this.saved), { mode: 384 });
|
|
73391
74140
|
fs13.renameSync(temporary, this.registryPath);
|
|
@@ -73988,8 +74737,8 @@ class WorkbenchAgentService {
|
|
|
73988
74737
|
function isSharedSessionPath(sessionPath) {
|
|
73989
74738
|
try {
|
|
73990
74739
|
const resolved = fs13.realpathSync(sessionPath);
|
|
73991
|
-
const root = fs13.realpathSync(
|
|
73992
|
-
return resolved.endsWith(".jsonl") && resolved.startsWith(root +
|
|
74740
|
+
const root = fs13.realpathSync(path14.join(getAgentDir2(), "sessions"));
|
|
74741
|
+
return resolved.endsWith(".jsonl") && resolved.startsWith(root + path14.sep) && fs13.statSync(resolved).isFile();
|
|
73993
74742
|
} catch {
|
|
73994
74743
|
return false;
|
|
73995
74744
|
}
|
|
@@ -74298,16 +75047,16 @@ function workbenchSocketHandlers(service) {
|
|
|
74298
75047
|
// src/local-run-supervisor.ts
|
|
74299
75048
|
import { spawn } from "child_process";
|
|
74300
75049
|
import fs14 from "fs";
|
|
74301
|
-
import
|
|
75050
|
+
import path15 from "path";
|
|
74302
75051
|
function localRunConcurrency(value = process.env.KIFARU_LOCAL_RUN_CONCURRENCY) {
|
|
74303
75052
|
const parsed = Number(value ?? "3");
|
|
74304
75053
|
return Number.isInteger(parsed) && parsed > 0 ? Math.min(parsed, 8) : 3;
|
|
74305
75054
|
}
|
|
74306
75055
|
function localRunWorkerEntry(fromDir = import.meta.dir) {
|
|
74307
|
-
const bundled =
|
|
75056
|
+
const bundled = path15.join(fromDir, "kifaru-local-run-worker.js");
|
|
74308
75057
|
if (fs14.existsSync(bundled))
|
|
74309
75058
|
return bundled;
|
|
74310
|
-
const source =
|
|
75059
|
+
const source = path15.join(fromDir, "local-run-worker.ts");
|
|
74311
75060
|
return fs14.existsSync(source) ? source : null;
|
|
74312
75061
|
}
|
|
74313
75062
|
function startLocalRunWorkers(options = {}) {
|