terminalhire 0.42.40 → 0.42.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/jpi-claim.js +413 -30
- package/dist/bin/jpi-dispatch.js +413 -30
- package/dist/bin/jpi-mcp.js +413 -30
- package/dist/bin/jpi-run.js +424 -41
- package/package.json +1 -1
package/dist/bin/jpi-claim.js
CHANGED
|
@@ -26435,7 +26435,19 @@ function isGreen(outcome) {
|
|
|
26435
26435
|
function isOurFault(outcome) {
|
|
26436
26436
|
return LIMIT_OWNER[outcome] === "ours";
|
|
26437
26437
|
}
|
|
26438
|
-
|
|
26438
|
+
function readStoppedAt(stdout, stderr = "") {
|
|
26439
|
+
return lastStepMarker(stdout) ?? lastStepMarker(stderr);
|
|
26440
|
+
}
|
|
26441
|
+
function isStepName(value) {
|
|
26442
|
+
return value.length > 0 && value.length <= STOPPED_AT_MAX && SCRIPT_NAME.test(value);
|
|
26443
|
+
}
|
|
26444
|
+
function lastStepMarker(text) {
|
|
26445
|
+
let last = null;
|
|
26446
|
+
for (const m of text.replace(/\r\n/g, "\n").matchAll(NPM_STEP_MARKER))
|
|
26447
|
+
last = m[1];
|
|
26448
|
+
return last !== null && isStepName(last) ? last : null;
|
|
26449
|
+
}
|
|
26450
|
+
var VERIFICATION_OUTCOMES, int, withSuiteFailures, countLines, READERS, SUPPORTED_RUNNERS, COVERAGE_TABLE, EXEC_FAILURE, SUITE_REPORTED_FAILURE, MISSING_SYSTEM_DEPENDENCY, OFFLINE_BUILD_GAP, LIMIT_OWNER, NPM_STEP_MARKER, STOPPED_AT_MAX, SCRIPT_NAME;
|
|
26439
26451
|
var init_classify2 = __esm({
|
|
26440
26452
|
"../../packages/envrun/dist/classify.js"() {
|
|
26441
26453
|
"use strict";
|
|
@@ -26858,6 +26870,9 @@ var init_classify2 = __esm({
|
|
|
26858
26870
|
"environment-exhausted": "ours",
|
|
26859
26871
|
"budget-exceeded": "ours"
|
|
26860
26872
|
};
|
|
26873
|
+
NPM_STEP_MARKER = /^> (?:@[^\s@/]+\/)?[^\s@]+@\S+ (\S+)/gm;
|
|
26874
|
+
STOPPED_AT_MAX = 200;
|
|
26875
|
+
SCRIPT_NAME = /^[A-Za-z0-9:_.\-/+@]+$/;
|
|
26861
26876
|
}
|
|
26862
26877
|
});
|
|
26863
26878
|
|
|
@@ -31033,7 +31048,8 @@ var init_result = __esm({
|
|
|
31033
31048
|
"leaksClean",
|
|
31034
31049
|
"leakState",
|
|
31035
31050
|
"venue",
|
|
31036
|
-
"refusalOrigin"
|
|
31051
|
+
"refusalOrigin",
|
|
31052
|
+
"stoppedAt"
|
|
31037
31053
|
];
|
|
31038
31054
|
RENDER_NONE = null;
|
|
31039
31055
|
FIELD_VIEWS = {
|
|
@@ -31096,7 +31112,9 @@ var init_result = __esm({
|
|
|
31096
31112
|
venue: (r) => r.venue === null ? null : renderVenueLine(r.venue),
|
|
31097
31113
|
// For the worker and the baseline intake, not the terminal: `reason` already says which
|
|
31098
31114
|
// side refused in words a developer reads.
|
|
31099
|
-
refusalOrigin: RENDER_NONE
|
|
31115
|
+
refusalOrigin: RENDER_NONE,
|
|
31116
|
+
// Only when the run did not pass: on a green run "the last step" is just the last step.
|
|
31117
|
+
stoppedAt: (r) => r.stoppedAt === null || r.outcome === "completed" ? null : `last step ${r.stoppedAt} (the last package script named in the output)`
|
|
31100
31118
|
};
|
|
31101
31119
|
}
|
|
31102
31120
|
});
|
|
@@ -31472,6 +31490,317 @@ var init_lockfileCheck = __esm({
|
|
|
31472
31490
|
}
|
|
31473
31491
|
});
|
|
31474
31492
|
|
|
31493
|
+
// ../../packages/envrun/dist/binaryPatch.js
|
|
31494
|
+
import { createHash as createHash11 } from "crypto";
|
|
31495
|
+
import { inflateSync } from "zlib";
|
|
31496
|
+
function decodeBase85Line(line) {
|
|
31497
|
+
const first = line.charCodeAt(0);
|
|
31498
|
+
let length;
|
|
31499
|
+
if (first >= 65 && first <= 90)
|
|
31500
|
+
length = first - 64;
|
|
31501
|
+
else if (first >= 97 && first <= 122)
|
|
31502
|
+
length = first - 96 + 26;
|
|
31503
|
+
else
|
|
31504
|
+
return null;
|
|
31505
|
+
const groups = Math.ceil(length / 4);
|
|
31506
|
+
if (line.length !== 1 + groups * 5)
|
|
31507
|
+
return null;
|
|
31508
|
+
const out = new Uint8Array(groups * 4);
|
|
31509
|
+
for (let g = 0; g < groups; g += 1) {
|
|
31510
|
+
let acc = 0;
|
|
31511
|
+
for (let k = 0; k < 5; k += 1) {
|
|
31512
|
+
const code = line.charCodeAt(1 + g * 5 + k);
|
|
31513
|
+
const value = code < 128 ? B85_VALUE[code] ?? -1 : -1;
|
|
31514
|
+
if (value < 0)
|
|
31515
|
+
return null;
|
|
31516
|
+
acc = acc * 85 + value;
|
|
31517
|
+
}
|
|
31518
|
+
if (acc > 4294967295)
|
|
31519
|
+
return null;
|
|
31520
|
+
out[g * 4] = acc >>> 24 & 255;
|
|
31521
|
+
out[g * 4 + 1] = acc >>> 16 & 255;
|
|
31522
|
+
out[g * 4 + 2] = acc >>> 8 & 255;
|
|
31523
|
+
out[g * 4 + 3] = acc & 255;
|
|
31524
|
+
}
|
|
31525
|
+
return out.subarray(0, length);
|
|
31526
|
+
}
|
|
31527
|
+
function readBinaryPayload(lines) {
|
|
31528
|
+
const blocks = [];
|
|
31529
|
+
let i = 0;
|
|
31530
|
+
while (i < lines.length) {
|
|
31531
|
+
const line = lines[i] ?? "";
|
|
31532
|
+
if (line === "") {
|
|
31533
|
+
i += 1;
|
|
31534
|
+
continue;
|
|
31535
|
+
}
|
|
31536
|
+
if (blocks.length === 2)
|
|
31537
|
+
return null;
|
|
31538
|
+
const header = BLOCK_HEADER.exec(line);
|
|
31539
|
+
if (header === null)
|
|
31540
|
+
return null;
|
|
31541
|
+
const size = Number(header[2]);
|
|
31542
|
+
if (!Number.isSafeInteger(size))
|
|
31543
|
+
return null;
|
|
31544
|
+
i += 1;
|
|
31545
|
+
const parts = [];
|
|
31546
|
+
let total = 0;
|
|
31547
|
+
while (i < lines.length && (lines[i] ?? "") !== "") {
|
|
31548
|
+
const decoded = decodeBase85Line(lines[i] ?? "");
|
|
31549
|
+
if (decoded === null)
|
|
31550
|
+
return null;
|
|
31551
|
+
total += decoded.length;
|
|
31552
|
+
if (total > MAX_BINARY_DEFLATED_BLOCK_BYTES)
|
|
31553
|
+
return null;
|
|
31554
|
+
parts.push(decoded);
|
|
31555
|
+
i += 1;
|
|
31556
|
+
}
|
|
31557
|
+
if (parts.length === 0)
|
|
31558
|
+
return null;
|
|
31559
|
+
if (i >= lines.length)
|
|
31560
|
+
return null;
|
|
31561
|
+
const deflated = new Uint8Array(total);
|
|
31562
|
+
let at = 0;
|
|
31563
|
+
for (const p of parts) {
|
|
31564
|
+
deflated.set(p, at);
|
|
31565
|
+
at += p.length;
|
|
31566
|
+
}
|
|
31567
|
+
blocks.push({ kind: header[1] === "delta" ? "delta" : "literal", size, deflated });
|
|
31568
|
+
}
|
|
31569
|
+
const forward = blocks[0];
|
|
31570
|
+
if (forward === void 0)
|
|
31571
|
+
return null;
|
|
31572
|
+
return { forward, reverse: blocks[1] ?? null };
|
|
31573
|
+
}
|
|
31574
|
+
function inflateExact(block, limit2) {
|
|
31575
|
+
if (block.size > limit2)
|
|
31576
|
+
return null;
|
|
31577
|
+
try {
|
|
31578
|
+
const out = inflateSync(block.deflated, { maxOutputLength: block.size + 1 });
|
|
31579
|
+
return out.length === block.size ? new Uint8Array(out) : null;
|
|
31580
|
+
} catch {
|
|
31581
|
+
return null;
|
|
31582
|
+
}
|
|
31583
|
+
}
|
|
31584
|
+
function readVarint(delta, from) {
|
|
31585
|
+
let value = 0;
|
|
31586
|
+
let shift = 0;
|
|
31587
|
+
let pos = from;
|
|
31588
|
+
for (; ; ) {
|
|
31589
|
+
const byte = delta[pos];
|
|
31590
|
+
if (byte === void 0 || shift > 42)
|
|
31591
|
+
return null;
|
|
31592
|
+
value += (byte & 127) * 2 ** shift;
|
|
31593
|
+
pos += 1;
|
|
31594
|
+
shift += 7;
|
|
31595
|
+
if ((byte & 128) === 0)
|
|
31596
|
+
return { value, next: pos };
|
|
31597
|
+
}
|
|
31598
|
+
}
|
|
31599
|
+
function deltaHeader(delta) {
|
|
31600
|
+
const source = readVarint(delta, 0);
|
|
31601
|
+
if (source === null)
|
|
31602
|
+
return null;
|
|
31603
|
+
const target = readVarint(delta, source.next);
|
|
31604
|
+
if (target === null)
|
|
31605
|
+
return null;
|
|
31606
|
+
return { source: source.value, target: target.value, opsAt: target.next };
|
|
31607
|
+
}
|
|
31608
|
+
function deltaLeadingInserts(delta, opsAt) {
|
|
31609
|
+
const parts = [];
|
|
31610
|
+
let pos = opsAt;
|
|
31611
|
+
while (pos < delta.length && parts.length < 64) {
|
|
31612
|
+
const op = delta[pos] ?? 0;
|
|
31613
|
+
if (op === 0 || (op & 128) !== 0)
|
|
31614
|
+
break;
|
|
31615
|
+
const end = Math.min(pos + 1 + op, delta.length);
|
|
31616
|
+
for (let i = pos + 1; i < end; i += 1)
|
|
31617
|
+
parts.push(delta[i] ?? 0);
|
|
31618
|
+
pos = end;
|
|
31619
|
+
}
|
|
31620
|
+
return Uint8Array.from(parts);
|
|
31621
|
+
}
|
|
31622
|
+
function startsWith(bytes, magic, at = 0) {
|
|
31623
|
+
if (bytes.length < at + magic.length)
|
|
31624
|
+
return false;
|
|
31625
|
+
return magic.every((b, i) => bytes[at + i] === b);
|
|
31626
|
+
}
|
|
31627
|
+
function sniffBinaryType(bytes) {
|
|
31628
|
+
if (startsWith(bytes, [127, 69, 76, 70]))
|
|
31629
|
+
return { label: "ELF", program: true };
|
|
31630
|
+
for (const magic of [
|
|
31631
|
+
[254, 237, 250, 206],
|
|
31632
|
+
[254, 237, 250, 207],
|
|
31633
|
+
[206, 250, 237, 254],
|
|
31634
|
+
[207, 250, 237, 254],
|
|
31635
|
+
[202, 254, 186, 191],
|
|
31636
|
+
[190, 186, 254, 202],
|
|
31637
|
+
[191, 186, 254, 202]
|
|
31638
|
+
]) {
|
|
31639
|
+
if (startsWith(bytes, magic))
|
|
31640
|
+
return { label: "Mach-O", program: true };
|
|
31641
|
+
}
|
|
31642
|
+
if (startsWith(bytes, [202, 254, 186, 190])) {
|
|
31643
|
+
const major = bytes.length >= 8 ? (bytes[6] ?? 0) << 8 | (bytes[7] ?? 0) : 0;
|
|
31644
|
+
return { label: major >= 45 ? "Java class" : "Mach-O", program: true };
|
|
31645
|
+
}
|
|
31646
|
+
if (startsWith(bytes, [0, 97, 115, 109]))
|
|
31647
|
+
return { label: "WebAssembly", program: true };
|
|
31648
|
+
if (startsWith(bytes, [77, 90]))
|
|
31649
|
+
return { label: "PE", program: true };
|
|
31650
|
+
if (startsWith(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
31651
|
+
return { label: "PNG", program: false };
|
|
31652
|
+
}
|
|
31653
|
+
if (startsWith(bytes, [255, 216, 255]))
|
|
31654
|
+
return { label: "JPEG", program: false };
|
|
31655
|
+
if (startsWith(bytes, [71, 73, 70, 56, 55, 97]) || startsWith(bytes, [71, 73, 70, 56, 57, 97])) {
|
|
31656
|
+
return { label: "GIF", program: false };
|
|
31657
|
+
}
|
|
31658
|
+
if (startsWith(bytes, [82, 73, 70, 70]) && startsWith(bytes, [87, 69, 66, 80], 8)) {
|
|
31659
|
+
return { label: "WebP", program: false };
|
|
31660
|
+
}
|
|
31661
|
+
if (startsWith(bytes, [37, 80, 68, 70, 45]))
|
|
31662
|
+
return { label: "PDF", program: false };
|
|
31663
|
+
if (startsWith(bytes, [119, 79, 70, 70]))
|
|
31664
|
+
return { label: "WOFF", program: false };
|
|
31665
|
+
if (startsWith(bytes, [119, 79, 70, 50]))
|
|
31666
|
+
return { label: "WOFF2", program: false };
|
|
31667
|
+
if (startsWith(bytes, [0, 1, 0, 0]) || startsWith(bytes, [116, 114, 117, 101])) {
|
|
31668
|
+
return { label: "TTF", program: false };
|
|
31669
|
+
}
|
|
31670
|
+
if (startsWith(bytes, [79, 84, 84, 79]))
|
|
31671
|
+
return { label: "OTF", program: false };
|
|
31672
|
+
if (startsWith(bytes, [80, 75, 3, 4]) || startsWith(bytes, [80, 75, 5, 6]) || startsWith(bytes, [80, 75, 7, 8])) {
|
|
31673
|
+
return { label: "ZIP", program: false };
|
|
31674
|
+
}
|
|
31675
|
+
return { label: "unknown binary", program: false };
|
|
31676
|
+
}
|
|
31677
|
+
function formatByteSize(bytes) {
|
|
31678
|
+
if (bytes < 1024)
|
|
31679
|
+
return `${bytes} B`;
|
|
31680
|
+
if (bytes < 1024 * 1024)
|
|
31681
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
31682
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
31683
|
+
}
|
|
31684
|
+
function parseFullIndexLine(line) {
|
|
31685
|
+
const m = /^index ([0-9a-f]+)\.\.([0-9a-f]+)(?: ([0-7]{6}))?$/.exec(line);
|
|
31686
|
+
if (m === null)
|
|
31687
|
+
return null;
|
|
31688
|
+
const pre = m[1] ?? "";
|
|
31689
|
+
const post = m[2] ?? "";
|
|
31690
|
+
if (!FULL_ID.test(pre) || !FULL_ID.test(post))
|
|
31691
|
+
return null;
|
|
31692
|
+
return { pre, post, mode: m[3] ?? null };
|
|
31693
|
+
}
|
|
31694
|
+
function isZeroId(id) {
|
|
31695
|
+
return id === ZERO_ID;
|
|
31696
|
+
}
|
|
31697
|
+
function refuse4(code, detail) {
|
|
31698
|
+
return { kind: "refuse", code, detail };
|
|
31699
|
+
}
|
|
31700
|
+
function judgeBinaryEntry(input) {
|
|
31701
|
+
const { path: path5 } = input;
|
|
31702
|
+
if (input.stub) {
|
|
31703
|
+
return refuse4("binary-content-missing", `${path5} is a binary file, but the patch leaves out its contents. Update terminalhire (npm install -g terminalhire@latest) and submit again.`);
|
|
31704
|
+
}
|
|
31705
|
+
if (input.textContent || input.indexLines.length !== 1)
|
|
31706
|
+
return { kind: "unreadable" };
|
|
31707
|
+
const index = parseFullIndexLine(input.indexLines[0] ?? "");
|
|
31708
|
+
if (index === null)
|
|
31709
|
+
return { kind: "unreadable" };
|
|
31710
|
+
if (isZeroId(index.pre) !== input.createsFile)
|
|
31711
|
+
return { kind: "unreadable" };
|
|
31712
|
+
if (isZeroId(index.post) !== input.deletesFile)
|
|
31713
|
+
return { kind: "unreadable" };
|
|
31714
|
+
const payload = readBinaryPayload(input.payload);
|
|
31715
|
+
if (payload === null)
|
|
31716
|
+
return { kind: "unreadable" };
|
|
31717
|
+
if (input.deletesFile) {
|
|
31718
|
+
const forward2 = payload.forward;
|
|
31719
|
+
if (forward2.kind !== "literal" || inflateExact(forward2, 0) === null) {
|
|
31720
|
+
return { kind: "unreadable" };
|
|
31721
|
+
}
|
|
31722
|
+
const reverse = payload.reverse;
|
|
31723
|
+
const removed = reverse !== null && reverse.kind === "literal" ? inflateExact(reverse, MAX_BINARY_FILE_BYTES) : null;
|
|
31724
|
+
return {
|
|
31725
|
+
kind: "hold",
|
|
31726
|
+
type: removed === null ? "unknown binary" : sniffBinaryType(removed).label,
|
|
31727
|
+
size: reverse !== null && reverse.kind === "literal" ? reverse.size : 0,
|
|
31728
|
+
writes: 0,
|
|
31729
|
+
hash: index.pre
|
|
31730
|
+
};
|
|
31731
|
+
}
|
|
31732
|
+
const mode = input.newMode ?? index.mode ?? "100644";
|
|
31733
|
+
if (mode === "100755")
|
|
31734
|
+
return refuse4("binary-executable", binaryExecutableDetail(path5));
|
|
31735
|
+
if (mode !== "100644")
|
|
31736
|
+
return refuse4("binary-mode", unsupportedModeDetail(path5, mode));
|
|
31737
|
+
const tooLarge = (size2) => refuse4("binary-too-large", `${path5} is ${formatByteSize(size2)}. One binary file can be at most 2 MB.`);
|
|
31738
|
+
let size;
|
|
31739
|
+
let head;
|
|
31740
|
+
const forward = payload.forward;
|
|
31741
|
+
if (forward.kind === "literal") {
|
|
31742
|
+
if (forward.size > MAX_BINARY_FILE_BYTES) {
|
|
31743
|
+
return tooLarge(forward.size);
|
|
31744
|
+
}
|
|
31745
|
+
const bytes = inflateExact(forward, MAX_BINARY_FILE_BYTES);
|
|
31746
|
+
if (bytes === null)
|
|
31747
|
+
return { kind: "unreadable" };
|
|
31748
|
+
size = bytes.length;
|
|
31749
|
+
head = bytes;
|
|
31750
|
+
} else {
|
|
31751
|
+
if (input.createsFile)
|
|
31752
|
+
return { kind: "unreadable" };
|
|
31753
|
+
const delta = inflateExact(forward, 2 * MAX_BINARY_FILE_BYTES);
|
|
31754
|
+
if (delta === null)
|
|
31755
|
+
return { kind: "unreadable" };
|
|
31756
|
+
const header = deltaHeader(delta);
|
|
31757
|
+
if (header === null)
|
|
31758
|
+
return { kind: "unreadable" };
|
|
31759
|
+
if (header.target > MAX_BINARY_FILE_BYTES)
|
|
31760
|
+
return tooLarge(header.target);
|
|
31761
|
+
size = header.target;
|
|
31762
|
+
head = deltaLeadingInserts(delta, header.opsAt);
|
|
31763
|
+
}
|
|
31764
|
+
const type = sniffBinaryType(head);
|
|
31765
|
+
if (type.program) {
|
|
31766
|
+
return refuse4("binary-program", binaryProgramDetail(path5, type.label));
|
|
31767
|
+
}
|
|
31768
|
+
return { kind: "hold", type: type.label, size, writes: size, hash: index.post };
|
|
31769
|
+
}
|
|
31770
|
+
function binaryTotalRefusal(totalBytes) {
|
|
31771
|
+
if (totalBytes <= MAX_BINARY_PATCH_BYTES)
|
|
31772
|
+
return null;
|
|
31773
|
+
return `The binary files in this patch add up to ${formatByteSize(totalBytes)}. A patch can carry at most 3 MB of binary files.`;
|
|
31774
|
+
}
|
|
31775
|
+
function binaryExecutableDetail(path5) {
|
|
31776
|
+
return `${path5} is a binary file marked executable. Binary files can't be marked executable in a patch.`;
|
|
31777
|
+
}
|
|
31778
|
+
function unsupportedModeDetail(path5, mode) {
|
|
31779
|
+
return `The patch changes ${path5} to a file type this platform will not apply on your behalf (mode ${mode}). Nothing on your repository was changed.`;
|
|
31780
|
+
}
|
|
31781
|
+
function binaryProgramDetail(path5, label) {
|
|
31782
|
+
return `${path5} is a program (${label}). Patches can't add or change programs, because the install or test step could run them.`;
|
|
31783
|
+
}
|
|
31784
|
+
var MAX_BINARY_FILE_BYTES, MAX_BINARY_PATCH_BYTES, MAX_BINARY_DEFLATED_BLOCK_BYTES, FULL_ID, ZERO_ID, B85_ALPHABET, B85_VALUE, BLOCK_HEADER;
|
|
31785
|
+
var init_binaryPatch = __esm({
|
|
31786
|
+
"../../packages/envrun/dist/binaryPatch.js"() {
|
|
31787
|
+
"use strict";
|
|
31788
|
+
MAX_BINARY_FILE_BYTES = 2 * 1024 * 1024;
|
|
31789
|
+
MAX_BINARY_PATCH_BYTES = 3 * 1024 * 1024;
|
|
31790
|
+
MAX_BINARY_DEFLATED_BLOCK_BYTES = 2 * MAX_BINARY_FILE_BYTES + 64 * 1024;
|
|
31791
|
+
FULL_ID = /^[0-9a-f]{40}$/;
|
|
31792
|
+
ZERO_ID = "0".repeat(40);
|
|
31793
|
+
B85_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
|
|
31794
|
+
B85_VALUE = (() => {
|
|
31795
|
+
const table = new Array(128).fill(-1);
|
|
31796
|
+
for (let i = 0; i < B85_ALPHABET.length; i += 1)
|
|
31797
|
+
table[B85_ALPHABET.charCodeAt(i)] = i;
|
|
31798
|
+
return table;
|
|
31799
|
+
})();
|
|
31800
|
+
BLOCK_HEADER = /^(literal|delta) (0|[1-9][0-9]{0,15})$/;
|
|
31801
|
+
}
|
|
31802
|
+
});
|
|
31803
|
+
|
|
31475
31804
|
// ../../packages/envrun/dist/boundary.js
|
|
31476
31805
|
function lockfileRefusal(base) {
|
|
31477
31806
|
const kind = LOCKFILE_KINDS[base];
|
|
@@ -31596,6 +31925,11 @@ function parsePatchPaths(patch) {
|
|
|
31596
31925
|
entry = {
|
|
31597
31926
|
rawPaths: [],
|
|
31598
31927
|
binary: false,
|
|
31928
|
+
binaryStub: false,
|
|
31929
|
+
binaryPayload: [],
|
|
31930
|
+
indexLines: [],
|
|
31931
|
+
newMode: null,
|
|
31932
|
+
textContent: false,
|
|
31599
31933
|
headerOld: null,
|
|
31600
31934
|
headerNew: null,
|
|
31601
31935
|
plusPath: null,
|
|
@@ -31629,8 +31963,10 @@ function parsePatchPaths(patch) {
|
|
|
31629
31963
|
}
|
|
31630
31964
|
if (entry === null)
|
|
31631
31965
|
continue;
|
|
31632
|
-
if (skippingBinary)
|
|
31966
|
+
if (skippingBinary) {
|
|
31967
|
+
entry.binaryPayload.push(line);
|
|
31633
31968
|
continue;
|
|
31969
|
+
}
|
|
31634
31970
|
if (inHunk) {
|
|
31635
31971
|
const marker = line === "" ? " " : line[0];
|
|
31636
31972
|
if (marker === "\\")
|
|
@@ -31657,6 +31993,7 @@ function parsePatchPaths(patch) {
|
|
|
31657
31993
|
if (line === "-- " || line === "--")
|
|
31658
31994
|
break;
|
|
31659
31995
|
if (line.startsWith("@@")) {
|
|
31996
|
+
entry.textContent = true;
|
|
31660
31997
|
const m = HUNK_HEADER.exec(line);
|
|
31661
31998
|
if (m === null) {
|
|
31662
31999
|
return fail3("a change block header is malformed, so we cannot tell which lines belong to it");
|
|
@@ -31673,13 +32010,20 @@ function parsePatchPaths(patch) {
|
|
|
31673
32010
|
const mode = /^(?:old mode|new mode|new file mode|deleted file mode) (\d+)$/.exec(line)?.[1] ?? /^index [0-9a-f]+\.\.[0-9a-f]+ (\d+)$/.exec(line)?.[1];
|
|
31674
32011
|
if (mode !== void 0)
|
|
31675
32012
|
entry.modes.push(mode);
|
|
32013
|
+
if (line.startsWith("index "))
|
|
32014
|
+
entry.indexLines.push(line);
|
|
32015
|
+
if (line.startsWith("new file mode ") || line.startsWith("new mode ")) {
|
|
32016
|
+
entry.newMode = line.slice(line.lastIndexOf(" ") + 1).trim();
|
|
32017
|
+
}
|
|
31676
32018
|
if (line === "GIT binary patch" || line.startsWith("Binary files ")) {
|
|
31677
32019
|
entry.binary = true;
|
|
32020
|
+
entry.binaryStub = line !== "GIT binary patch";
|
|
31678
32021
|
skippingBinary = true;
|
|
31679
32022
|
continue;
|
|
31680
32023
|
}
|
|
31681
32024
|
const sideMarker = line.startsWith("--- ") ? "a/" : line.startsWith("+++ ") ? "b/" : null;
|
|
31682
32025
|
if (sideMarker !== null) {
|
|
32026
|
+
entry.textContent = true;
|
|
31683
32027
|
const rest = line.slice(4);
|
|
31684
32028
|
const tab = rest.indexOf(" ");
|
|
31685
32029
|
const token = tab === -1 ? rest : rest.slice(0, tab);
|
|
@@ -31754,16 +32098,14 @@ function preflightBoundary(input) {
|
|
|
31754
32098
|
const changedManifests = /* @__PURE__ */ new Set();
|
|
31755
32099
|
const deniedPaths = /* @__PURE__ */ new Set();
|
|
31756
32100
|
const nonFileLockfiles = /* @__PURE__ */ new Set();
|
|
32101
|
+
let binaryBytes = 0;
|
|
31757
32102
|
for (const entry of parsed.entries) {
|
|
31758
|
-
|
|
31759
|
-
const name = entry.rawPaths[0] ?? "a file";
|
|
31760
|
-
refusals.push(refusal("binary-patch", normalizePath(name)?.path ?? null, `${name} is changed as binary content, which nobody can review line by line. Binary changes are refused.`));
|
|
31761
|
-
continue;
|
|
31762
|
-
}
|
|
32103
|
+
let refusedByPath = false;
|
|
31763
32104
|
const entryPaths = [];
|
|
31764
32105
|
for (const raw of entry.rawPaths) {
|
|
31765
32106
|
const normalized = normalizePath(raw);
|
|
31766
32107
|
if (normalized === null) {
|
|
32108
|
+
refusedByPath = true;
|
|
31767
32109
|
if (!seenPaths.has(raw)) {
|
|
31768
32110
|
seenPaths.add(raw);
|
|
31769
32111
|
refusals.push(refusal("unsafe-path", raw, `${raw} is not a file name a patch may name \u2014 it points outside the repository, or it is written in a form we cannot check.`));
|
|
@@ -31781,6 +32123,7 @@ function preflightBoundary(input) {
|
|
|
31781
32123
|
seenPaths.add(path5);
|
|
31782
32124
|
const denied = DENY_RULES.find((rule) => rule.matches(path5, segments, base));
|
|
31783
32125
|
if (denied !== void 0) {
|
|
32126
|
+
refusedByPath = true;
|
|
31784
32127
|
deniedPaths.add(path5);
|
|
31785
32128
|
const why = typeof denied.why === "string" ? denied.why : denied.why(base);
|
|
31786
32129
|
refusals.push(refusal(denied.code, path5, `${path5} ${why}.`));
|
|
@@ -31806,7 +32149,29 @@ function preflightBoundary(input) {
|
|
|
31806
32149
|
if (contentPath !== null && contentPath.split("/").pop() === "package.json" && entry.changed) {
|
|
31807
32150
|
changedManifests.add(contentPath);
|
|
31808
32151
|
}
|
|
32152
|
+
if (entry.binary && !refusedByPath && contentPath !== null) {
|
|
32153
|
+
const verdict = judgeBinaryEntry({
|
|
32154
|
+
path: contentPath,
|
|
32155
|
+
stub: entry.binaryStub,
|
|
32156
|
+
payload: entry.binaryPayload,
|
|
32157
|
+
indexLines: entry.indexLines,
|
|
32158
|
+
newMode: entry.newMode,
|
|
32159
|
+
createsFile: entry.createsFile,
|
|
32160
|
+
deletesFile: entry.deletesFile,
|
|
32161
|
+
textContent: entry.textContent
|
|
32162
|
+
});
|
|
32163
|
+
if (verdict.kind === "refuse") {
|
|
32164
|
+
refusals.push(refusal(verdict.code, contentPath, verdict.detail));
|
|
32165
|
+
} else if (verdict.kind === "unreadable") {
|
|
32166
|
+
refusals.push(refusal("unparseable", contentPath, `The patch could not be read: the entry for ${contentPath} carries no changes we can apply. A patch we cannot read in full is refused rather than applied in part.`));
|
|
32167
|
+
} else {
|
|
32168
|
+
binaryBytes += verdict.writes;
|
|
32169
|
+
}
|
|
32170
|
+
}
|
|
31809
32171
|
}
|
|
32172
|
+
const overBinaryCap = binaryTotalRefusal(binaryBytes);
|
|
32173
|
+
if (overBinaryCap !== null)
|
|
32174
|
+
refusals.push(refusal("binary-too-large", null, overBinaryCap));
|
|
31810
32175
|
for (const [path5, { touches, edits }] of lockfileTouches) {
|
|
31811
32176
|
if (deniedPaths.has(path5))
|
|
31812
32177
|
continue;
|
|
@@ -31830,10 +32195,18 @@ var init_boundary = __esm({
|
|
|
31830
32195
|
"../../packages/envrun/dist/boundary.js"() {
|
|
31831
32196
|
"use strict";
|
|
31832
32197
|
init_lockfileCheck();
|
|
32198
|
+
init_binaryPatch();
|
|
31833
32199
|
PATH_REFUSAL_CODES = [
|
|
31834
32200
|
"empty-patch",
|
|
31835
32201
|
"unparseable",
|
|
31836
32202
|
"binary-patch",
|
|
32203
|
+
// Not path-derived, but refused on both sides for the same bytes, so they belong on the
|
|
32204
|
+
// surface `boundary-oracle.test.mjs` compares (TERM-1342).
|
|
32205
|
+
"binary-content-missing",
|
|
32206
|
+
"binary-executable",
|
|
32207
|
+
"binary-mode",
|
|
32208
|
+
"binary-program",
|
|
32209
|
+
"binary-too-large",
|
|
31837
32210
|
"unsafe-path",
|
|
31838
32211
|
"out-of-slice",
|
|
31839
32212
|
"ci-config",
|
|
@@ -32190,7 +32563,7 @@ var init_emptyGitConfig = __esm({
|
|
|
32190
32563
|
|
|
32191
32564
|
// ../../packages/envrun/dist/hostedVenue.js
|
|
32192
32565
|
import { spawn as spawn4, spawnSync as spawnSync5 } from "child_process";
|
|
32193
|
-
import { createHash as
|
|
32566
|
+
import { createHash as createHash12, X509Certificate } from "crypto";
|
|
32194
32567
|
import { chmodSync as chmodSync3, existsSync as existsSync12, mkdtempSync as mkdtempSync3, readFileSync as readFileSync12, rmSync as rmSync8, writeFileSync as writeFileSync14 } from "fs";
|
|
32195
32568
|
import { request as httpsRequest } from "https";
|
|
32196
32569
|
import { createServer } from "net";
|
|
@@ -32860,7 +33233,7 @@ function iapPortTunnelArgv(vm, project, zone, remotePort, localPort) {
|
|
|
32860
33233
|
}
|
|
32861
33234
|
function spkiSha256Hex(certDer) {
|
|
32862
33235
|
const spki = new X509Certificate(certDer).publicKey.export({ type: "spki", format: "der" });
|
|
32863
|
-
return
|
|
33236
|
+
return createHash12("sha256").update(spki).digest("hex");
|
|
32864
33237
|
}
|
|
32865
33238
|
function certMetadataValue(pem) {
|
|
32866
33239
|
return new X509Certificate(pem).raw.toString("base64url");
|
|
@@ -37304,7 +37677,9 @@ function refusedRun(fields) {
|
|
|
37304
37677
|
// reasoning as `leaksClean` above: null because nothing happened, and it must
|
|
37305
37678
|
// not read as a venue we looked at and could not name.
|
|
37306
37679
|
venue: null,
|
|
37307
|
-
refusalOrigin: fields.origin
|
|
37680
|
+
refusalOrigin: fields.origin,
|
|
37681
|
+
// No test step ran, so there is no output to read a step from.
|
|
37682
|
+
stoppedAt: null
|
|
37308
37683
|
};
|
|
37309
37684
|
}
|
|
37310
37685
|
function refusalOriginOf(refusal2) {
|
|
@@ -37755,7 +38130,9 @@ async function runVerification(req, ctx) {
|
|
|
37755
38130
|
// reasoning and the #735 failure that makes the distinction load-bearing.
|
|
37756
38131
|
venue: describeVenue(lease),
|
|
37757
38132
|
// A run that reached a verdict was not refused, so neither side refused it.
|
|
37758
|
-
refusalOrigin: null
|
|
38133
|
+
refusalOrigin: null,
|
|
38134
|
+
// Read from the full test output, not `outputTail`, which is an excerpt.
|
|
38135
|
+
stoppedAt: readStoppedAt(verdict.test?.stdout ?? "", verdict.test?.stderr ?? "")
|
|
37759
38136
|
};
|
|
37760
38137
|
let later = null;
|
|
37761
38138
|
if (req.screenshots !== void 0) {
|
|
@@ -37962,6 +38339,7 @@ var init_thrun = __esm({
|
|
|
37962
38339
|
init_screenshots();
|
|
37963
38340
|
init_dist3();
|
|
37964
38341
|
init_attestation2();
|
|
38342
|
+
init_classify2();
|
|
37965
38343
|
init_boundary();
|
|
37966
38344
|
init_lockfileCheck();
|
|
37967
38345
|
init_emptyGitConfig();
|
|
@@ -38971,6 +39349,7 @@ __export(dist_exports, {
|
|
|
38971
39349
|
readAlembicChain: () => readAlembicChain,
|
|
38972
39350
|
readCounts: () => readCounts,
|
|
38973
39351
|
readSchema: () => readSchema,
|
|
39352
|
+
readStoppedAt: () => readStoppedAt,
|
|
38974
39353
|
recordedApplied: () => recordedApplied,
|
|
38975
39354
|
refuseSshTransport: () => refuseSshTransport,
|
|
38976
39355
|
refuseUnbuildableSpec: () => refuseUnbuildableSpec,
|
|
@@ -39314,7 +39693,7 @@ import {
|
|
|
39314
39693
|
closeSync as closeSync6
|
|
39315
39694
|
} from "fs";
|
|
39316
39695
|
import { join as join31, dirname as dirname9, isAbsolute as isAbsolute5, resolve as pathResolve } from "path";
|
|
39317
|
-
import { createHash as
|
|
39696
|
+
import { createHash as createHash13 } from "crypto";
|
|
39318
39697
|
import { homedir as homedir14, hostname as osHostname } from "os";
|
|
39319
39698
|
import { execFile as execFile3, execFileSync as execFileSync2, spawnSync as spawnSync8 } from "child_process";
|
|
39320
39699
|
import { promisify as promisify3 } from "util";
|
|
@@ -41127,7 +41506,7 @@ async function registerFounderClaim(b) {
|
|
|
41127
41506
|
let clearedLocalCredential = false;
|
|
41128
41507
|
let refusedForPurpose = false;
|
|
41129
41508
|
let preserveBackgroundToken = false;
|
|
41130
|
-
const
|
|
41509
|
+
const refuse5 = (reason) => {
|
|
41131
41510
|
console.error(
|
|
41132
41511
|
`
|
|
41133
41512
|
terminalhire claim: refusing to record \u2014 ${reason}
|
|
@@ -41152,7 +41531,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41152
41531
|
try {
|
|
41153
41532
|
expectLogin = await localLoginForPaidBrowserClaim();
|
|
41154
41533
|
} catch (err) {
|
|
41155
|
-
|
|
41534
|
+
refuse5(
|
|
41156
41535
|
`could not verify which GitHub account this machine is signed in as: ${err instanceof Error ? err.message : String(err)}.
|
|
41157
41536
|
Run \`terminalhire login\`, then retry this claim. Browser verification was
|
|
41158
41537
|
not opened and no claim was sent.`
|
|
@@ -41168,16 +41547,16 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41168
41547
|
claimRef: opportunityShortToken(b.bountyId)
|
|
41169
41548
|
});
|
|
41170
41549
|
if (!proofToken) {
|
|
41171
|
-
|
|
41550
|
+
refuse5("could not verify your GitHub identity with terminalhire (see above).");
|
|
41172
41551
|
}
|
|
41173
41552
|
const verifiedLogin = proofTokenLogin(proofToken);
|
|
41174
41553
|
if (!verifiedLogin) {
|
|
41175
|
-
|
|
41554
|
+
refuse5(
|
|
41176
41555
|
"the browser verification response did not name a GitHub account, so it could not be compared with this machine\u2019s sign-in. Nothing was sent; retry the claim."
|
|
41177
41556
|
);
|
|
41178
41557
|
}
|
|
41179
41558
|
if (verifiedLogin.toLowerCase() !== expectLogin.toLowerCase()) {
|
|
41180
|
-
|
|
41559
|
+
refuse5(
|
|
41181
41560
|
`you verified in the browser as @${verifiedLogin}, but this machine is signed in as @${expectLogin}.
|
|
41182
41561
|
Nothing was sent. Sign the browser into @${expectLogin} and run this again, or
|
|
41183
41562
|
run \`terminalhire login\` if you meant to work as @${verifiedLogin}.`
|
|
@@ -41209,7 +41588,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41209
41588
|
try {
|
|
41210
41589
|
res = await sendRegistration(true);
|
|
41211
41590
|
} catch (err) {
|
|
41212
|
-
|
|
41591
|
+
refuse5(
|
|
41213
41592
|
`terminalhire is unreachable (${err instanceof Error ? err.message : String(err)}), so the posting could not be revalidated.`
|
|
41214
41593
|
);
|
|
41215
41594
|
}
|
|
@@ -41260,7 +41639,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41260
41639
|
try {
|
|
41261
41640
|
res = await sendRegistration(true);
|
|
41262
41641
|
} catch (err) {
|
|
41263
|
-
|
|
41642
|
+
refuse5(
|
|
41264
41643
|
`terminalhire is unreachable (${err instanceof Error ? err.message : String(err)}), so the posting could not be revalidated.`
|
|
41265
41644
|
);
|
|
41266
41645
|
}
|
|
@@ -41271,14 +41650,14 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41271
41650
|
res = await sendRegistration(false);
|
|
41272
41651
|
refusalBody = await readRefusal(res);
|
|
41273
41652
|
} catch (err) {
|
|
41274
|
-
|
|
41653
|
+
refuse5(
|
|
41275
41654
|
`terminalhire is unreachable (${err instanceof Error ? err.message : String(err)}), so the posting could not be revalidated.`
|
|
41276
41655
|
);
|
|
41277
41656
|
}
|
|
41278
41657
|
}
|
|
41279
41658
|
if (!res.ok) {
|
|
41280
41659
|
const detail = refusalBody?.message || refusalBody?.error || "";
|
|
41281
|
-
|
|
41660
|
+
refuse5(
|
|
41282
41661
|
detail ? `the server refused this claim (${res.status}): ${detail}` : `the server refused this claim (${res.status}).`
|
|
41283
41662
|
);
|
|
41284
41663
|
}
|
|
@@ -41289,7 +41668,7 @@ terminalhire claim: refusing to record \u2014 ${reason}
|
|
|
41289
41668
|
body = null;
|
|
41290
41669
|
}
|
|
41291
41670
|
if (!body || body.ok !== true) {
|
|
41292
|
-
|
|
41671
|
+
refuse5("malformed registration response from the server.");
|
|
41293
41672
|
}
|
|
41294
41673
|
const mintedToken = typeof body.pushToken === "string" && body.pushToken.length > 0 ? body.pushToken : null;
|
|
41295
41674
|
if (refusedForPurpose && mintedToken && !preserveBackgroundToken) {
|
|
@@ -42821,7 +43200,7 @@ function writePackFile(destDir, relPath, content, what) {
|
|
|
42821
43200
|
return { written: true, reason: null, sha256: sha256OfUtf8(content) };
|
|
42822
43201
|
}
|
|
42823
43202
|
function sha256OfUtf8(content) {
|
|
42824
|
-
return
|
|
43203
|
+
return createHash13("sha256").update(content, "utf8").digest("hex");
|
|
42825
43204
|
}
|
|
42826
43205
|
function writeWorkspacePack(destDir, spec, claim, delivery) {
|
|
42827
43206
|
if (delivery !== "full" && delivery !== "sparse") {
|
|
@@ -43724,7 +44103,7 @@ function loadClaimScreenshots(specArg) {
|
|
|
43724
44103
|
items.push({
|
|
43725
44104
|
file,
|
|
43726
44105
|
caption: shot.caption,
|
|
43727
|
-
sha256:
|
|
44106
|
+
sha256: createHash13("sha256").update(bytes).digest("hex"),
|
|
43728
44107
|
bytes: bytes.byteLength,
|
|
43729
44108
|
width,
|
|
43730
44109
|
height
|
|
@@ -43809,10 +44188,14 @@ async function submitFounderPatch({ claims, claim, id, wt, flags }) {
|
|
|
43809
44188
|
const base = roots[0];
|
|
43810
44189
|
let patch;
|
|
43811
44190
|
try {
|
|
43812
|
-
({ stdout: patch } = await pExecFile(
|
|
43813
|
-
|
|
43814
|
-
|
|
43815
|
-
|
|
44191
|
+
({ stdout: patch } = await pExecFile(
|
|
44192
|
+
"git",
|
|
44193
|
+
["-C", wt, "diff", "--binary", "--full-index", base, "HEAD"],
|
|
44194
|
+
{
|
|
44195
|
+
shell: false,
|
|
44196
|
+
maxBuffer: 16 * 1024 * 1024
|
|
44197
|
+
}
|
|
44198
|
+
));
|
|
43816
44199
|
patch = String(patch);
|
|
43817
44200
|
} catch (err) {
|
|
43818
44201
|
console.error(
|