@rallycry/conveyor-k3 0.1.12 → 0.1.13
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/cli.js +1877 -1093
- package/dist/index.d.ts +54 -3
- package/dist/index.js +713 -226
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -101,7 +101,7 @@ function createClusterProof(apiUrl, clusterToken, key) {
|
|
|
101
101
|
const origin = new URL(apiUrl).origin;
|
|
102
102
|
const timestamp = Date.now();
|
|
103
103
|
const nonce = randomBytes(32).toString("base64url");
|
|
104
|
-
const
|
|
104
|
+
const message2 = `conveyor-device-v1
|
|
105
105
|
${origin}
|
|
106
106
|
${clusterToken}
|
|
107
107
|
${timestamp}
|
|
@@ -109,7 +109,7 @@ ${nonce}`;
|
|
|
109
109
|
return {
|
|
110
110
|
timestamp,
|
|
111
111
|
nonce,
|
|
112
|
-
signature: sign(null, Buffer.from(
|
|
112
|
+
signature: sign(null, Buffer.from(message2, "utf8"), key).toString("base64url")
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
function deviceClusterAuth(apiUrl, clusterToken, keyPath = DEVICE_KEY_PATH, ownerUid = 0) {
|
|
@@ -487,104 +487,104 @@ ZodError.create = (issues) => {
|
|
|
487
487
|
|
|
488
488
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
489
489
|
var errorMap = (issue, _ctx) => {
|
|
490
|
-
let
|
|
490
|
+
let message2;
|
|
491
491
|
switch (issue.code) {
|
|
492
492
|
case ZodIssueCode.invalid_type:
|
|
493
493
|
if (issue.received === ZodParsedType.undefined) {
|
|
494
|
-
|
|
494
|
+
message2 = "Required";
|
|
495
495
|
} else {
|
|
496
|
-
|
|
496
|
+
message2 = `Expected ${issue.expected}, received ${issue.received}`;
|
|
497
497
|
}
|
|
498
498
|
break;
|
|
499
499
|
case ZodIssueCode.invalid_literal:
|
|
500
|
-
|
|
500
|
+
message2 = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`;
|
|
501
501
|
break;
|
|
502
502
|
case ZodIssueCode.unrecognized_keys:
|
|
503
|
-
|
|
503
|
+
message2 = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`;
|
|
504
504
|
break;
|
|
505
505
|
case ZodIssueCode.invalid_union:
|
|
506
|
-
|
|
506
|
+
message2 = `Invalid input`;
|
|
507
507
|
break;
|
|
508
508
|
case ZodIssueCode.invalid_union_discriminator:
|
|
509
|
-
|
|
509
|
+
message2 = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`;
|
|
510
510
|
break;
|
|
511
511
|
case ZodIssueCode.invalid_enum_value:
|
|
512
|
-
|
|
512
|
+
message2 = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`;
|
|
513
513
|
break;
|
|
514
514
|
case ZodIssueCode.invalid_arguments:
|
|
515
|
-
|
|
515
|
+
message2 = `Invalid function arguments`;
|
|
516
516
|
break;
|
|
517
517
|
case ZodIssueCode.invalid_return_type:
|
|
518
|
-
|
|
518
|
+
message2 = `Invalid function return type`;
|
|
519
519
|
break;
|
|
520
520
|
case ZodIssueCode.invalid_date:
|
|
521
|
-
|
|
521
|
+
message2 = `Invalid date`;
|
|
522
522
|
break;
|
|
523
523
|
case ZodIssueCode.invalid_string:
|
|
524
524
|
if (typeof issue.validation === "object") {
|
|
525
525
|
if ("includes" in issue.validation) {
|
|
526
|
-
|
|
526
|
+
message2 = `Invalid input: must include "${issue.validation.includes}"`;
|
|
527
527
|
if (typeof issue.validation.position === "number") {
|
|
528
|
-
|
|
528
|
+
message2 = `${message2} at one or more positions greater than or equal to ${issue.validation.position}`;
|
|
529
529
|
}
|
|
530
530
|
} else if ("startsWith" in issue.validation) {
|
|
531
|
-
|
|
531
|
+
message2 = `Invalid input: must start with "${issue.validation.startsWith}"`;
|
|
532
532
|
} else if ("endsWith" in issue.validation) {
|
|
533
|
-
|
|
533
|
+
message2 = `Invalid input: must end with "${issue.validation.endsWith}"`;
|
|
534
534
|
} else {
|
|
535
535
|
util.assertNever(issue.validation);
|
|
536
536
|
}
|
|
537
537
|
} else if (issue.validation !== "regex") {
|
|
538
|
-
|
|
538
|
+
message2 = `Invalid ${issue.validation}`;
|
|
539
539
|
} else {
|
|
540
|
-
|
|
540
|
+
message2 = "Invalid";
|
|
541
541
|
}
|
|
542
542
|
break;
|
|
543
543
|
case ZodIssueCode.too_small:
|
|
544
544
|
if (issue.type === "array")
|
|
545
|
-
|
|
545
|
+
message2 = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
|
|
546
546
|
else if (issue.type === "string")
|
|
547
|
-
|
|
547
|
+
message2 = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
|
|
548
548
|
else if (issue.type === "number")
|
|
549
|
-
|
|
549
|
+
message2 = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
|
|
550
550
|
else if (issue.type === "bigint")
|
|
551
|
-
|
|
551
|
+
message2 = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
|
|
552
552
|
else if (issue.type === "date")
|
|
553
|
-
|
|
553
|
+
message2 = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
|
|
554
554
|
else
|
|
555
|
-
|
|
555
|
+
message2 = "Invalid input";
|
|
556
556
|
break;
|
|
557
557
|
case ZodIssueCode.too_big:
|
|
558
558
|
if (issue.type === "array")
|
|
559
|
-
|
|
559
|
+
message2 = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
|
|
560
560
|
else if (issue.type === "string")
|
|
561
|
-
|
|
561
|
+
message2 = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
|
|
562
562
|
else if (issue.type === "number")
|
|
563
|
-
|
|
563
|
+
message2 = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
|
|
564
564
|
else if (issue.type === "bigint")
|
|
565
|
-
|
|
565
|
+
message2 = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
|
|
566
566
|
else if (issue.type === "date")
|
|
567
|
-
|
|
567
|
+
message2 = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`;
|
|
568
568
|
else
|
|
569
|
-
|
|
569
|
+
message2 = "Invalid input";
|
|
570
570
|
break;
|
|
571
571
|
case ZodIssueCode.custom:
|
|
572
|
-
|
|
572
|
+
message2 = `Invalid input`;
|
|
573
573
|
break;
|
|
574
574
|
case ZodIssueCode.invalid_intersection_types:
|
|
575
|
-
|
|
575
|
+
message2 = `Intersection results could not be merged`;
|
|
576
576
|
break;
|
|
577
577
|
case ZodIssueCode.not_multiple_of:
|
|
578
|
-
|
|
578
|
+
message2 = `Number must be a multiple of ${issue.multipleOf}`;
|
|
579
579
|
break;
|
|
580
580
|
case ZodIssueCode.not_finite:
|
|
581
|
-
|
|
581
|
+
message2 = "Number must be finite";
|
|
582
582
|
break;
|
|
583
583
|
default:
|
|
584
|
-
|
|
584
|
+
message2 = _ctx.defaultError;
|
|
585
585
|
util.assertNever(issue);
|
|
586
586
|
}
|
|
587
|
-
return { message };
|
|
587
|
+
return { message: message2 };
|
|
588
588
|
};
|
|
589
589
|
var en_default = errorMap;
|
|
590
590
|
|
|
@@ -710,8 +710,8 @@ var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
|
710
710
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
711
711
|
var errorUtil;
|
|
712
712
|
(function(errorUtil2) {
|
|
713
|
-
errorUtil2.errToObj = (
|
|
714
|
-
errorUtil2.toString = (
|
|
713
|
+
errorUtil2.errToObj = (message2) => typeof message2 === "string" ? { message: message2 } : message2 || {};
|
|
714
|
+
errorUtil2.toString = (message2) => typeof message2 === "string" ? message2 : message2?.message;
|
|
715
715
|
})(errorUtil || (errorUtil = {}));
|
|
716
716
|
|
|
717
717
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/types.js
|
|
@@ -763,16 +763,16 @@ function processCreateParams(params) {
|
|
|
763
763
|
if (errorMap2)
|
|
764
764
|
return { errorMap: errorMap2, description };
|
|
765
765
|
const customMap = (iss, ctx) => {
|
|
766
|
-
const { message } = params;
|
|
766
|
+
const { message: message2 } = params;
|
|
767
767
|
if (iss.code === "invalid_enum_value") {
|
|
768
|
-
return { message:
|
|
768
|
+
return { message: message2 ?? ctx.defaultError };
|
|
769
769
|
}
|
|
770
770
|
if (typeof ctx.data === "undefined") {
|
|
771
|
-
return { message:
|
|
771
|
+
return { message: message2 ?? required_error ?? ctx.defaultError };
|
|
772
772
|
}
|
|
773
773
|
if (iss.code !== "invalid_type")
|
|
774
774
|
return { message: ctx.defaultError };
|
|
775
|
-
return { message:
|
|
775
|
+
return { message: message2 ?? invalid_type_error ?? ctx.defaultError };
|
|
776
776
|
};
|
|
777
777
|
return { errorMap: customMap, description };
|
|
778
778
|
}
|
|
@@ -898,14 +898,14 @@ var ZodType = class {
|
|
|
898
898
|
const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
|
|
899
899
|
return handleResult(ctx, result);
|
|
900
900
|
}
|
|
901
|
-
refine(check,
|
|
901
|
+
refine(check, message2) {
|
|
902
902
|
const getIssueProperties = (val) => {
|
|
903
|
-
if (typeof
|
|
904
|
-
return { message };
|
|
905
|
-
} else if (typeof
|
|
906
|
-
return
|
|
903
|
+
if (typeof message2 === "string" || typeof message2 === "undefined") {
|
|
904
|
+
return { message: message2 };
|
|
905
|
+
} else if (typeof message2 === "function") {
|
|
906
|
+
return message2(val);
|
|
907
907
|
} else {
|
|
908
|
-
return
|
|
908
|
+
return message2;
|
|
909
909
|
}
|
|
910
910
|
};
|
|
911
911
|
return this._refinement((val, ctx) => {
|
|
@@ -1441,11 +1441,11 @@ var ZodString = class _ZodString extends ZodType {
|
|
|
1441
1441
|
}
|
|
1442
1442
|
return { status: status.value, value: input.data };
|
|
1443
1443
|
}
|
|
1444
|
-
_regex(regex, validation,
|
|
1444
|
+
_regex(regex, validation, message2) {
|
|
1445
1445
|
return this.refinement((data) => regex.test(data), {
|
|
1446
1446
|
validation,
|
|
1447
1447
|
code: ZodIssueCode.invalid_string,
|
|
1448
|
-
...errorUtil.errToObj(
|
|
1448
|
+
...errorUtil.errToObj(message2)
|
|
1449
1449
|
});
|
|
1450
1450
|
}
|
|
1451
1451
|
_addCheck(check) {
|
|
@@ -1454,37 +1454,37 @@ var ZodString = class _ZodString extends ZodType {
|
|
|
1454
1454
|
checks: [...this._def.checks, check]
|
|
1455
1455
|
});
|
|
1456
1456
|
}
|
|
1457
|
-
email(
|
|
1458
|
-
return this._addCheck({ kind: "email", ...errorUtil.errToObj(
|
|
1457
|
+
email(message2) {
|
|
1458
|
+
return this._addCheck({ kind: "email", ...errorUtil.errToObj(message2) });
|
|
1459
1459
|
}
|
|
1460
|
-
url(
|
|
1461
|
-
return this._addCheck({ kind: "url", ...errorUtil.errToObj(
|
|
1460
|
+
url(message2) {
|
|
1461
|
+
return this._addCheck({ kind: "url", ...errorUtil.errToObj(message2) });
|
|
1462
1462
|
}
|
|
1463
|
-
emoji(
|
|
1464
|
-
return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(
|
|
1463
|
+
emoji(message2) {
|
|
1464
|
+
return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message2) });
|
|
1465
1465
|
}
|
|
1466
|
-
uuid(
|
|
1467
|
-
return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(
|
|
1466
|
+
uuid(message2) {
|
|
1467
|
+
return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message2) });
|
|
1468
1468
|
}
|
|
1469
|
-
nanoid(
|
|
1470
|
-
return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(
|
|
1469
|
+
nanoid(message2) {
|
|
1470
|
+
return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message2) });
|
|
1471
1471
|
}
|
|
1472
|
-
cuid(
|
|
1473
|
-
return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(
|
|
1472
|
+
cuid(message2) {
|
|
1473
|
+
return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message2) });
|
|
1474
1474
|
}
|
|
1475
|
-
cuid2(
|
|
1476
|
-
return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(
|
|
1475
|
+
cuid2(message2) {
|
|
1476
|
+
return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message2) });
|
|
1477
1477
|
}
|
|
1478
|
-
ulid(
|
|
1479
|
-
return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(
|
|
1478
|
+
ulid(message2) {
|
|
1479
|
+
return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message2) });
|
|
1480
1480
|
}
|
|
1481
|
-
base64(
|
|
1482
|
-
return this._addCheck({ kind: "base64", ...errorUtil.errToObj(
|
|
1481
|
+
base64(message2) {
|
|
1482
|
+
return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message2) });
|
|
1483
1483
|
}
|
|
1484
|
-
base64url(
|
|
1484
|
+
base64url(message2) {
|
|
1485
1485
|
return this._addCheck({
|
|
1486
1486
|
kind: "base64url",
|
|
1487
|
-
...errorUtil.errToObj(
|
|
1487
|
+
...errorUtil.errToObj(message2)
|
|
1488
1488
|
});
|
|
1489
1489
|
}
|
|
1490
1490
|
jwt(options) {
|
|
@@ -1514,8 +1514,8 @@ var ZodString = class _ZodString extends ZodType {
|
|
|
1514
1514
|
...errorUtil.errToObj(options?.message)
|
|
1515
1515
|
});
|
|
1516
1516
|
}
|
|
1517
|
-
date(
|
|
1518
|
-
return this._addCheck({ kind: "date", message });
|
|
1517
|
+
date(message2) {
|
|
1518
|
+
return this._addCheck({ kind: "date", message: message2 });
|
|
1519
1519
|
}
|
|
1520
1520
|
time(options) {
|
|
1521
1521
|
if (typeof options === "string") {
|
|
@@ -1531,14 +1531,14 @@ var ZodString = class _ZodString extends ZodType {
|
|
|
1531
1531
|
...errorUtil.errToObj(options?.message)
|
|
1532
1532
|
});
|
|
1533
1533
|
}
|
|
1534
|
-
duration(
|
|
1535
|
-
return this._addCheck({ kind: "duration", ...errorUtil.errToObj(
|
|
1534
|
+
duration(message2) {
|
|
1535
|
+
return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message2) });
|
|
1536
1536
|
}
|
|
1537
|
-
regex(regex,
|
|
1537
|
+
regex(regex, message2) {
|
|
1538
1538
|
return this._addCheck({
|
|
1539
1539
|
kind: "regex",
|
|
1540
1540
|
regex,
|
|
1541
|
-
...errorUtil.errToObj(
|
|
1541
|
+
...errorUtil.errToObj(message2)
|
|
1542
1542
|
});
|
|
1543
1543
|
}
|
|
1544
1544
|
includes(value, options) {
|
|
@@ -1549,46 +1549,46 @@ var ZodString = class _ZodString extends ZodType {
|
|
|
1549
1549
|
...errorUtil.errToObj(options?.message)
|
|
1550
1550
|
});
|
|
1551
1551
|
}
|
|
1552
|
-
startsWith(value,
|
|
1552
|
+
startsWith(value, message2) {
|
|
1553
1553
|
return this._addCheck({
|
|
1554
1554
|
kind: "startsWith",
|
|
1555
1555
|
value,
|
|
1556
|
-
...errorUtil.errToObj(
|
|
1556
|
+
...errorUtil.errToObj(message2)
|
|
1557
1557
|
});
|
|
1558
1558
|
}
|
|
1559
|
-
endsWith(value,
|
|
1559
|
+
endsWith(value, message2) {
|
|
1560
1560
|
return this._addCheck({
|
|
1561
1561
|
kind: "endsWith",
|
|
1562
1562
|
value,
|
|
1563
|
-
...errorUtil.errToObj(
|
|
1563
|
+
...errorUtil.errToObj(message2)
|
|
1564
1564
|
});
|
|
1565
1565
|
}
|
|
1566
|
-
min(minLength,
|
|
1566
|
+
min(minLength, message2) {
|
|
1567
1567
|
return this._addCheck({
|
|
1568
1568
|
kind: "min",
|
|
1569
1569
|
value: minLength,
|
|
1570
|
-
...errorUtil.errToObj(
|
|
1570
|
+
...errorUtil.errToObj(message2)
|
|
1571
1571
|
});
|
|
1572
1572
|
}
|
|
1573
|
-
max(maxLength,
|
|
1573
|
+
max(maxLength, message2) {
|
|
1574
1574
|
return this._addCheck({
|
|
1575
1575
|
kind: "max",
|
|
1576
1576
|
value: maxLength,
|
|
1577
|
-
...errorUtil.errToObj(
|
|
1577
|
+
...errorUtil.errToObj(message2)
|
|
1578
1578
|
});
|
|
1579
1579
|
}
|
|
1580
|
-
length(len,
|
|
1580
|
+
length(len, message2) {
|
|
1581
1581
|
return this._addCheck({
|
|
1582
1582
|
kind: "length",
|
|
1583
1583
|
value: len,
|
|
1584
|
-
...errorUtil.errToObj(
|
|
1584
|
+
...errorUtil.errToObj(message2)
|
|
1585
1585
|
});
|
|
1586
1586
|
}
|
|
1587
1587
|
/**
|
|
1588
1588
|
* Equivalent to `.min(1)`
|
|
1589
1589
|
*/
|
|
1590
|
-
nonempty(
|
|
1591
|
-
return this.min(1, errorUtil.errToObj(
|
|
1590
|
+
nonempty(message2) {
|
|
1591
|
+
return this.min(1, errorUtil.errToObj(message2));
|
|
1592
1592
|
}
|
|
1593
1593
|
trim() {
|
|
1594
1594
|
return new _ZodString({
|
|
@@ -1781,19 +1781,19 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
1781
1781
|
}
|
|
1782
1782
|
return { status: status.value, value: input.data };
|
|
1783
1783
|
}
|
|
1784
|
-
gte(value,
|
|
1785
|
-
return this.setLimit("min", value, true, errorUtil.toString(
|
|
1784
|
+
gte(value, message2) {
|
|
1785
|
+
return this.setLimit("min", value, true, errorUtil.toString(message2));
|
|
1786
1786
|
}
|
|
1787
|
-
gt(value,
|
|
1788
|
-
return this.setLimit("min", value, false, errorUtil.toString(
|
|
1787
|
+
gt(value, message2) {
|
|
1788
|
+
return this.setLimit("min", value, false, errorUtil.toString(message2));
|
|
1789
1789
|
}
|
|
1790
|
-
lte(value,
|
|
1791
|
-
return this.setLimit("max", value, true, errorUtil.toString(
|
|
1790
|
+
lte(value, message2) {
|
|
1791
|
+
return this.setLimit("max", value, true, errorUtil.toString(message2));
|
|
1792
1792
|
}
|
|
1793
|
-
lt(value,
|
|
1794
|
-
return this.setLimit("max", value, false, errorUtil.toString(
|
|
1793
|
+
lt(value, message2) {
|
|
1794
|
+
return this.setLimit("max", value, false, errorUtil.toString(message2));
|
|
1795
1795
|
}
|
|
1796
|
-
setLimit(kind, value, inclusive,
|
|
1796
|
+
setLimit(kind, value, inclusive, message2) {
|
|
1797
1797
|
return new _ZodNumber({
|
|
1798
1798
|
...this._def,
|
|
1799
1799
|
checks: [
|
|
@@ -1802,7 +1802,7 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
1802
1802
|
kind,
|
|
1803
1803
|
value,
|
|
1804
1804
|
inclusive,
|
|
1805
|
-
message: errorUtil.toString(
|
|
1805
|
+
message: errorUtil.toString(message2)
|
|
1806
1806
|
}
|
|
1807
1807
|
]
|
|
1808
1808
|
});
|
|
@@ -1813,68 +1813,68 @@ var ZodNumber = class _ZodNumber extends ZodType {
|
|
|
1813
1813
|
checks: [...this._def.checks, check]
|
|
1814
1814
|
});
|
|
1815
1815
|
}
|
|
1816
|
-
int(
|
|
1816
|
+
int(message2) {
|
|
1817
1817
|
return this._addCheck({
|
|
1818
1818
|
kind: "int",
|
|
1819
|
-
message: errorUtil.toString(
|
|
1819
|
+
message: errorUtil.toString(message2)
|
|
1820
1820
|
});
|
|
1821
1821
|
}
|
|
1822
|
-
positive(
|
|
1822
|
+
positive(message2) {
|
|
1823
1823
|
return this._addCheck({
|
|
1824
1824
|
kind: "min",
|
|
1825
1825
|
value: 0,
|
|
1826
1826
|
inclusive: false,
|
|
1827
|
-
message: errorUtil.toString(
|
|
1827
|
+
message: errorUtil.toString(message2)
|
|
1828
1828
|
});
|
|
1829
1829
|
}
|
|
1830
|
-
negative(
|
|
1830
|
+
negative(message2) {
|
|
1831
1831
|
return this._addCheck({
|
|
1832
1832
|
kind: "max",
|
|
1833
1833
|
value: 0,
|
|
1834
1834
|
inclusive: false,
|
|
1835
|
-
message: errorUtil.toString(
|
|
1835
|
+
message: errorUtil.toString(message2)
|
|
1836
1836
|
});
|
|
1837
1837
|
}
|
|
1838
|
-
nonpositive(
|
|
1838
|
+
nonpositive(message2) {
|
|
1839
1839
|
return this._addCheck({
|
|
1840
1840
|
kind: "max",
|
|
1841
1841
|
value: 0,
|
|
1842
1842
|
inclusive: true,
|
|
1843
|
-
message: errorUtil.toString(
|
|
1843
|
+
message: errorUtil.toString(message2)
|
|
1844
1844
|
});
|
|
1845
1845
|
}
|
|
1846
|
-
nonnegative(
|
|
1846
|
+
nonnegative(message2) {
|
|
1847
1847
|
return this._addCheck({
|
|
1848
1848
|
kind: "min",
|
|
1849
1849
|
value: 0,
|
|
1850
1850
|
inclusive: true,
|
|
1851
|
-
message: errorUtil.toString(
|
|
1851
|
+
message: errorUtil.toString(message2)
|
|
1852
1852
|
});
|
|
1853
1853
|
}
|
|
1854
|
-
multipleOf(value,
|
|
1854
|
+
multipleOf(value, message2) {
|
|
1855
1855
|
return this._addCheck({
|
|
1856
1856
|
kind: "multipleOf",
|
|
1857
1857
|
value,
|
|
1858
|
-
message: errorUtil.toString(
|
|
1858
|
+
message: errorUtil.toString(message2)
|
|
1859
1859
|
});
|
|
1860
1860
|
}
|
|
1861
|
-
finite(
|
|
1861
|
+
finite(message2) {
|
|
1862
1862
|
return this._addCheck({
|
|
1863
1863
|
kind: "finite",
|
|
1864
|
-
message: errorUtil.toString(
|
|
1864
|
+
message: errorUtil.toString(message2)
|
|
1865
1865
|
});
|
|
1866
1866
|
}
|
|
1867
|
-
safe(
|
|
1867
|
+
safe(message2) {
|
|
1868
1868
|
return this._addCheck({
|
|
1869
1869
|
kind: "min",
|
|
1870
1870
|
inclusive: true,
|
|
1871
1871
|
value: Number.MIN_SAFE_INTEGER,
|
|
1872
|
-
message: errorUtil.toString(
|
|
1872
|
+
message: errorUtil.toString(message2)
|
|
1873
1873
|
})._addCheck({
|
|
1874
1874
|
kind: "max",
|
|
1875
1875
|
inclusive: true,
|
|
1876
1876
|
value: Number.MAX_SAFE_INTEGER,
|
|
1877
|
-
message: errorUtil.toString(
|
|
1877
|
+
message: errorUtil.toString(message2)
|
|
1878
1878
|
});
|
|
1879
1879
|
}
|
|
1880
1880
|
get minValue() {
|
|
@@ -1997,19 +1997,19 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
1997
1997
|
});
|
|
1998
1998
|
return INVALID;
|
|
1999
1999
|
}
|
|
2000
|
-
gte(value,
|
|
2001
|
-
return this.setLimit("min", value, true, errorUtil.toString(
|
|
2000
|
+
gte(value, message2) {
|
|
2001
|
+
return this.setLimit("min", value, true, errorUtil.toString(message2));
|
|
2002
2002
|
}
|
|
2003
|
-
gt(value,
|
|
2004
|
-
return this.setLimit("min", value, false, errorUtil.toString(
|
|
2003
|
+
gt(value, message2) {
|
|
2004
|
+
return this.setLimit("min", value, false, errorUtil.toString(message2));
|
|
2005
2005
|
}
|
|
2006
|
-
lte(value,
|
|
2007
|
-
return this.setLimit("max", value, true, errorUtil.toString(
|
|
2006
|
+
lte(value, message2) {
|
|
2007
|
+
return this.setLimit("max", value, true, errorUtil.toString(message2));
|
|
2008
2008
|
}
|
|
2009
|
-
lt(value,
|
|
2010
|
-
return this.setLimit("max", value, false, errorUtil.toString(
|
|
2009
|
+
lt(value, message2) {
|
|
2010
|
+
return this.setLimit("max", value, false, errorUtil.toString(message2));
|
|
2011
2011
|
}
|
|
2012
|
-
setLimit(kind, value, inclusive,
|
|
2012
|
+
setLimit(kind, value, inclusive, message2) {
|
|
2013
2013
|
return new _ZodBigInt({
|
|
2014
2014
|
...this._def,
|
|
2015
2015
|
checks: [
|
|
@@ -2018,7 +2018,7 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
2018
2018
|
kind,
|
|
2019
2019
|
value,
|
|
2020
2020
|
inclusive,
|
|
2021
|
-
message: errorUtil.toString(
|
|
2021
|
+
message: errorUtil.toString(message2)
|
|
2022
2022
|
}
|
|
2023
2023
|
]
|
|
2024
2024
|
});
|
|
@@ -2029,43 +2029,43 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
|
|
|
2029
2029
|
checks: [...this._def.checks, check]
|
|
2030
2030
|
});
|
|
2031
2031
|
}
|
|
2032
|
-
positive(
|
|
2032
|
+
positive(message2) {
|
|
2033
2033
|
return this._addCheck({
|
|
2034
2034
|
kind: "min",
|
|
2035
2035
|
value: BigInt(0),
|
|
2036
2036
|
inclusive: false,
|
|
2037
|
-
message: errorUtil.toString(
|
|
2037
|
+
message: errorUtil.toString(message2)
|
|
2038
2038
|
});
|
|
2039
2039
|
}
|
|
2040
|
-
negative(
|
|
2040
|
+
negative(message2) {
|
|
2041
2041
|
return this._addCheck({
|
|
2042
2042
|
kind: "max",
|
|
2043
2043
|
value: BigInt(0),
|
|
2044
2044
|
inclusive: false,
|
|
2045
|
-
message: errorUtil.toString(
|
|
2045
|
+
message: errorUtil.toString(message2)
|
|
2046
2046
|
});
|
|
2047
2047
|
}
|
|
2048
|
-
nonpositive(
|
|
2048
|
+
nonpositive(message2) {
|
|
2049
2049
|
return this._addCheck({
|
|
2050
2050
|
kind: "max",
|
|
2051
2051
|
value: BigInt(0),
|
|
2052
2052
|
inclusive: true,
|
|
2053
|
-
message: errorUtil.toString(
|
|
2053
|
+
message: errorUtil.toString(message2)
|
|
2054
2054
|
});
|
|
2055
2055
|
}
|
|
2056
|
-
nonnegative(
|
|
2056
|
+
nonnegative(message2) {
|
|
2057
2057
|
return this._addCheck({
|
|
2058
2058
|
kind: "min",
|
|
2059
2059
|
value: BigInt(0),
|
|
2060
2060
|
inclusive: true,
|
|
2061
|
-
message: errorUtil.toString(
|
|
2061
|
+
message: errorUtil.toString(message2)
|
|
2062
2062
|
});
|
|
2063
2063
|
}
|
|
2064
|
-
multipleOf(value,
|
|
2064
|
+
multipleOf(value, message2) {
|
|
2065
2065
|
return this._addCheck({
|
|
2066
2066
|
kind: "multipleOf",
|
|
2067
2067
|
value,
|
|
2068
|
-
message: errorUtil.toString(
|
|
2068
|
+
message: errorUtil.toString(message2)
|
|
2069
2069
|
});
|
|
2070
2070
|
}
|
|
2071
2071
|
get minValue() {
|
|
@@ -2188,18 +2188,18 @@ var ZodDate = class _ZodDate extends ZodType {
|
|
|
2188
2188
|
checks: [...this._def.checks, check]
|
|
2189
2189
|
});
|
|
2190
2190
|
}
|
|
2191
|
-
min(minDate,
|
|
2191
|
+
min(minDate, message2) {
|
|
2192
2192
|
return this._addCheck({
|
|
2193
2193
|
kind: "min",
|
|
2194
2194
|
value: minDate.getTime(),
|
|
2195
|
-
message: errorUtil.toString(
|
|
2195
|
+
message: errorUtil.toString(message2)
|
|
2196
2196
|
});
|
|
2197
2197
|
}
|
|
2198
|
-
max(maxDate,
|
|
2198
|
+
max(maxDate, message2) {
|
|
2199
2199
|
return this._addCheck({
|
|
2200
2200
|
kind: "max",
|
|
2201
2201
|
value: maxDate.getTime(),
|
|
2202
|
-
message: errorUtil.toString(
|
|
2202
|
+
message: errorUtil.toString(message2)
|
|
2203
2203
|
});
|
|
2204
2204
|
}
|
|
2205
2205
|
get minDate() {
|
|
@@ -2431,26 +2431,26 @@ var ZodArray = class _ZodArray extends ZodType {
|
|
|
2431
2431
|
get element() {
|
|
2432
2432
|
return this._def.type;
|
|
2433
2433
|
}
|
|
2434
|
-
min(minLength,
|
|
2434
|
+
min(minLength, message2) {
|
|
2435
2435
|
return new _ZodArray({
|
|
2436
2436
|
...this._def,
|
|
2437
|
-
minLength: { value: minLength, message: errorUtil.toString(
|
|
2437
|
+
minLength: { value: minLength, message: errorUtil.toString(message2) }
|
|
2438
2438
|
});
|
|
2439
2439
|
}
|
|
2440
|
-
max(maxLength,
|
|
2440
|
+
max(maxLength, message2) {
|
|
2441
2441
|
return new _ZodArray({
|
|
2442
2442
|
...this._def,
|
|
2443
|
-
maxLength: { value: maxLength, message: errorUtil.toString(
|
|
2443
|
+
maxLength: { value: maxLength, message: errorUtil.toString(message2) }
|
|
2444
2444
|
});
|
|
2445
2445
|
}
|
|
2446
|
-
length(len,
|
|
2446
|
+
length(len, message2) {
|
|
2447
2447
|
return new _ZodArray({
|
|
2448
2448
|
...this._def,
|
|
2449
|
-
exactLength: { value: len, message: errorUtil.toString(
|
|
2449
|
+
exactLength: { value: len, message: errorUtil.toString(message2) }
|
|
2450
2450
|
});
|
|
2451
2451
|
}
|
|
2452
|
-
nonempty(
|
|
2453
|
-
return this.min(1,
|
|
2452
|
+
nonempty(message2) {
|
|
2453
|
+
return this.min(1, message2);
|
|
2454
2454
|
}
|
|
2455
2455
|
};
|
|
2456
2456
|
ZodArray.create = (schema, params) => {
|
|
@@ -2593,17 +2593,17 @@ var ZodObject = class _ZodObject extends ZodType {
|
|
|
2593
2593
|
get shape() {
|
|
2594
2594
|
return this._def.shape();
|
|
2595
2595
|
}
|
|
2596
|
-
strict(
|
|
2596
|
+
strict(message2) {
|
|
2597
2597
|
errorUtil.errToObj;
|
|
2598
2598
|
return new _ZodObject({
|
|
2599
2599
|
...this._def,
|
|
2600
2600
|
unknownKeys: "strict",
|
|
2601
|
-
...
|
|
2601
|
+
...message2 !== void 0 ? {
|
|
2602
2602
|
errorMap: (issue, ctx) => {
|
|
2603
2603
|
const defaultError = this._def.errorMap?.(issue, ctx).message ?? ctx.defaultError;
|
|
2604
2604
|
if (issue.code === "unrecognized_keys")
|
|
2605
2605
|
return {
|
|
2606
|
-
message: errorUtil.errToObj(
|
|
2606
|
+
message: errorUtil.errToObj(message2).message ?? defaultError
|
|
2607
2607
|
};
|
|
2608
2608
|
return {
|
|
2609
2609
|
message: defaultError
|
|
@@ -3359,23 +3359,23 @@ var ZodSet = class _ZodSet extends ZodType {
|
|
|
3359
3359
|
return finalizeSet(elements);
|
|
3360
3360
|
}
|
|
3361
3361
|
}
|
|
3362
|
-
min(minSize,
|
|
3362
|
+
min(minSize, message2) {
|
|
3363
3363
|
return new _ZodSet({
|
|
3364
3364
|
...this._def,
|
|
3365
|
-
minSize: { value: minSize, message: errorUtil.toString(
|
|
3365
|
+
minSize: { value: minSize, message: errorUtil.toString(message2) }
|
|
3366
3366
|
});
|
|
3367
3367
|
}
|
|
3368
|
-
max(maxSize,
|
|
3368
|
+
max(maxSize, message2) {
|
|
3369
3369
|
return new _ZodSet({
|
|
3370
3370
|
...this._def,
|
|
3371
|
-
maxSize: { value: maxSize, message: errorUtil.toString(
|
|
3371
|
+
maxSize: { value: maxSize, message: errorUtil.toString(message2) }
|
|
3372
3372
|
});
|
|
3373
3373
|
}
|
|
3374
|
-
size(size,
|
|
3375
|
-
return this.min(size,
|
|
3374
|
+
size(size, message2) {
|
|
3375
|
+
return this.min(size, message2).max(size, message2);
|
|
3376
3376
|
}
|
|
3377
|
-
nonempty(
|
|
3378
|
-
return this.min(1,
|
|
3377
|
+
nonempty(message2) {
|
|
3378
|
+
return this.min(1, message2);
|
|
3379
3379
|
}
|
|
3380
3380
|
};
|
|
3381
3381
|
ZodSet.create = (valueType, params) => {
|
|
@@ -4162,7 +4162,7 @@ var coerce = {
|
|
|
4162
4162
|
};
|
|
4163
4163
|
var NEVER = INVALID;
|
|
4164
4164
|
|
|
4165
|
-
// ../shared/dist/chunk-
|
|
4165
|
+
// ../shared/dist/chunk-VSUBG7GR.js
|
|
4166
4166
|
var DEFAULT_SONNET_MODEL = "claude-sonnet-5-5";
|
|
4167
4167
|
var DEFAULT_OPUS_MODEL = "claude-opus-5-5";
|
|
4168
4168
|
var DEFAULT_HAIKU_MODEL = "claude-haiku-4-5-20251001";
|
|
@@ -4780,7 +4780,8 @@ var DiscoveredPortSchema = external_exports.object({
|
|
|
4780
4780
|
port: external_exports.number().int().min(1).max(65535),
|
|
4781
4781
|
label: external_exports.string().min(1).max(64).optional(),
|
|
4782
4782
|
protocol: external_exports.enum(["http", "tcp"]).optional(),
|
|
4783
|
-
detectedAt: external_exports.string()
|
|
4783
|
+
detectedAt: external_exports.string(),
|
|
4784
|
+
hidden: external_exports.boolean().optional()
|
|
4784
4785
|
});
|
|
4785
4786
|
var ReportDiscoveredPortsRequestSchema = external_exports.object({
|
|
4786
4787
|
sessionId: external_exports.string(),
|
|
@@ -4927,7 +4928,11 @@ var SubmitCodeReviewResultRequestSchema = external_exports.object({
|
|
|
4927
4928
|
var CycleCodingAgentKeyRequestSchema = external_exports.object({
|
|
4928
4929
|
sessionId: external_exports.string(),
|
|
4929
4930
|
rateLimitType: external_exports.string(),
|
|
4930
|
-
resetsAt: external_exports.string().optional()
|
|
4931
|
+
resetsAt: external_exports.string().optional(),
|
|
4932
|
+
// The key the pod is actually running (CONVEYOR_CODING_AGENT_KEY_ID). Wins
|
|
4933
|
+
// over the session's attribution stamp after owner validation; optional so
|
|
4934
|
+
// older agents keep the session fallback.
|
|
4935
|
+
codingAgentKeyId: external_exports.string().optional()
|
|
4931
4936
|
});
|
|
4932
4937
|
var PostChildChatMessageRequestSchema = external_exports.object({
|
|
4933
4938
|
sessionId: external_exports.string(),
|
|
@@ -5341,11 +5346,12 @@ var QueryProjectGcpLogsRequestSchema = external_exports.object({
|
|
|
5341
5346
|
sqlInstances: external_exports.array(external_exports.string().min(1).max(200)).max(25).optional(),
|
|
5342
5347
|
allServices: external_exports.boolean().optional(),
|
|
5343
5348
|
search: external_exports.string().max(256).optional(),
|
|
5344
|
-
filter: external_exports.string().max(
|
|
5349
|
+
filter: external_exports.string().max(2e3).optional(),
|
|
5345
5350
|
startTime: external_exports.string().optional(),
|
|
5346
5351
|
endTime: external_exports.string().optional(),
|
|
5347
5352
|
limit: external_exports.number().int().min(1).max(200).optional().default(50),
|
|
5348
|
-
pageToken: external_exports.string().max(4096).optional()
|
|
5353
|
+
pageToken: external_exports.string().max(4096).optional(),
|
|
5354
|
+
full: external_exports.boolean().optional()
|
|
5349
5355
|
});
|
|
5350
5356
|
var QueryProjectGrafanaLogsRequestSchema = external_exports.object({
|
|
5351
5357
|
projectId: external_exports.string(),
|
|
@@ -6290,6 +6296,7 @@ var BAKE_COMPONENT_LABEL = "claudespace.rallycry.com/component";
|
|
|
6290
6296
|
var BAKE_COMPONENT_PREBAKE = "prebake";
|
|
6291
6297
|
var BAKE_COMPONENT_STATE_BAKE = "state-bake";
|
|
6292
6298
|
var BAKE_COMPONENT_VALUES = [BAKE_COMPONENT_PREBAKE, BAKE_COMPONENT_STATE_BAKE];
|
|
6299
|
+
var PERSONAL_BAKE_NAMESPACE = "conveyor-bakes";
|
|
6293
6300
|
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
6294
6301
|
var POSTGRES_ENV = {
|
|
6295
6302
|
POSTGRES_HOST_AUTH_METHOD: "trust",
|
|
@@ -6608,6 +6615,8 @@ var REPORT_CARD_TYPES = surfaceTypes("report");
|
|
|
6608
6615
|
var DECISION_CARD_TYPES = surfaceTypes("decision");
|
|
6609
6616
|
|
|
6610
6617
|
// src/daemon/connection.ts
|
|
6618
|
+
var REDIAL_FIRST_MS = 5e3;
|
|
6619
|
+
var REDIAL_MAX_MS = 5 * 6e4;
|
|
6611
6620
|
function unwrap(ack, what) {
|
|
6612
6621
|
if (!ack?.ok || ack.data === void 0) {
|
|
6613
6622
|
throw new Error(`${what} failed: ${ack?.error ?? "no response"}`);
|
|
@@ -6617,6 +6626,8 @@ function unwrap(ack, what) {
|
|
|
6617
6626
|
var ClusterConnection = class {
|
|
6618
6627
|
socket = null;
|
|
6619
6628
|
config;
|
|
6629
|
+
redialDelayMs = REDIAL_FIRST_MS;
|
|
6630
|
+
redialTimer = null;
|
|
6620
6631
|
/** Called when Conveyor says the desired state changed. */
|
|
6621
6632
|
onSyncRequested = null;
|
|
6622
6633
|
/** Called when Conveyor asks the machine to remove itself. */
|
|
@@ -6652,6 +6663,7 @@ var ClusterConnection = class {
|
|
|
6652
6663
|
});
|
|
6653
6664
|
this.socket = socket;
|
|
6654
6665
|
socket.on("connect", () => {
|
|
6666
|
+
this.redialDelayMs = REDIAL_FIRST_MS;
|
|
6655
6667
|
if (!settled) {
|
|
6656
6668
|
settled = true;
|
|
6657
6669
|
resolve();
|
|
@@ -6670,6 +6682,9 @@ var ClusterConnection = class {
|
|
|
6670
6682
|
socket.on("disconnect", (reason) => {
|
|
6671
6683
|
process.stderr.write(`[conveyor-k3] disconnected: ${reason}
|
|
6672
6684
|
`);
|
|
6685
|
+
if (reason === "io server disconnect" && this.config.reconnectWhenReplaced) {
|
|
6686
|
+
this.redial(socket);
|
|
6687
|
+
}
|
|
6673
6688
|
});
|
|
6674
6689
|
socket.on(PERSONAL_CLUSTER_EVENTS.syncRequested, () => {
|
|
6675
6690
|
this.onSyncRequested?.();
|
|
@@ -6731,7 +6746,20 @@ var ClusterConnection = class {
|
|
|
6731
6746
|
} catch {
|
|
6732
6747
|
}
|
|
6733
6748
|
}
|
|
6749
|
+
/** Dial again after the server closed the socket, waiting longer each time. */
|
|
6750
|
+
redial(socket) {
|
|
6751
|
+
if (this.redialTimer) return;
|
|
6752
|
+
const delay = this.redialDelayMs;
|
|
6753
|
+
this.redialDelayMs = Math.min(delay * 2, REDIAL_MAX_MS);
|
|
6754
|
+
this.redialTimer = setTimeout(() => {
|
|
6755
|
+
this.redialTimer = null;
|
|
6756
|
+
if (this.socket === socket && !socket.connected) socket.connect();
|
|
6757
|
+
}, delay);
|
|
6758
|
+
this.redialTimer.unref?.();
|
|
6759
|
+
}
|
|
6734
6760
|
disconnect() {
|
|
6761
|
+
if (this.redialTimer) clearTimeout(this.redialTimer);
|
|
6762
|
+
this.redialTimer = null;
|
|
6735
6763
|
this.socket?.disconnect();
|
|
6736
6764
|
this.socket = null;
|
|
6737
6765
|
}
|
|
@@ -7147,6 +7175,9 @@ async function writeState(fs, state) {
|
|
|
7147
7175
|
await fs.writeFile(STATE_FILE, `${JSON.stringify(state, null, 2)}
|
|
7148
7176
|
`, 384);
|
|
7149
7177
|
}
|
|
7178
|
+
function managesK3s(desired, state) {
|
|
7179
|
+
return desired.isolation === void 0 || state.k3sInstalledByConveyor === true;
|
|
7180
|
+
}
|
|
7150
7181
|
|
|
7151
7182
|
// src/lib/k3s-config.ts
|
|
7152
7183
|
var IMAGE_GC_HIGH = "image-gc-high-threshold";
|
|
@@ -7160,6 +7191,15 @@ var K3S_INSTALL_EXEC = [
|
|
|
7160
7191
|
`--${WRITE_KUBECONFIG_MODE}`,
|
|
7161
7192
|
KUBECONFIG_MODE
|
|
7162
7193
|
].join(" ");
|
|
7194
|
+
function bareToken(token) {
|
|
7195
|
+
let bare = token.trim();
|
|
7196
|
+
if (bare.endsWith("\\")) bare = bare.slice(0, -1).trim();
|
|
7197
|
+
const quote = bare[0];
|
|
7198
|
+
if (bare.length >= 2 && (quote === "'" || quote === '"') && bare.endsWith(quote)) {
|
|
7199
|
+
bare = bare.slice(1, -1);
|
|
7200
|
+
}
|
|
7201
|
+
return bare;
|
|
7202
|
+
}
|
|
7163
7203
|
function ownerConfiguredKubeletFlags(ownerConfig) {
|
|
7164
7204
|
const found = /* @__PURE__ */ new Set();
|
|
7165
7205
|
if (!ownerConfig) return found;
|
|
@@ -7185,7 +7225,7 @@ function ownerImageGcHighThreshold(ownerConfig) {
|
|
|
7185
7225
|
const value = Number.parseInt(match[2] ?? "", 10);
|
|
7186
7226
|
return Number.isInteger(value) && value >= 0 && value <= 100 ? value : null;
|
|
7187
7227
|
}
|
|
7188
|
-
function renderK3sDropIn(kubelet, ownerConfig) {
|
|
7228
|
+
function renderK3sDropIn(kubelet, ownerConfig, options = {}) {
|
|
7189
7229
|
const ownerFlags = ownerConfiguredKubeletFlags(ownerConfig);
|
|
7190
7230
|
const ownerKeys = ownerConfiguredKeys(ownerConfig);
|
|
7191
7231
|
const args = [];
|
|
@@ -7209,8 +7249,10 @@ function renderK3sDropIn(kubelet, ownerConfig) {
|
|
|
7209
7249
|
"# Your own /etc/rancher/k3s/config.yaml is never modified; k3s merges both.",
|
|
7210
7250
|
"# `kubelet-arg+` and `disable+` append rather than replacing a list you set."
|
|
7211
7251
|
];
|
|
7212
|
-
|
|
7213
|
-
|
|
7252
|
+
if (options.disableComponents !== false) {
|
|
7253
|
+
lines2.push("disable+:");
|
|
7254
|
+
for (const component of K3S_DISABLED_COMPONENTS) lines2.push(` - ${component}`);
|
|
7255
|
+
}
|
|
7214
7256
|
if (ownerKeys.has(WRITE_KUBECONFIG_MODE)) {
|
|
7215
7257
|
skipped.push(WRITE_KUBECONFIG_MODE);
|
|
7216
7258
|
} else {
|
|
@@ -7640,6 +7682,231 @@ async function loadRegistryMirror(ctx) {
|
|
|
7640
7682
|
return { restarted: true, warning: null };
|
|
7641
7683
|
}
|
|
7642
7684
|
|
|
7685
|
+
// src/lib/isolation.ts
|
|
7686
|
+
var EGRESS_POLICY_NAME = "conveyor-k3-egress";
|
|
7687
|
+
var MANAGED_BY2 = { "app.kubernetes.io/managed-by": "conveyor-k3" };
|
|
7688
|
+
var NON_ROUTABLE_IPV4 = [
|
|
7689
|
+
"0.0.0.0/8",
|
|
7690
|
+
"10.0.0.0/8",
|
|
7691
|
+
"100.64.0.0/10",
|
|
7692
|
+
"127.0.0.0/8",
|
|
7693
|
+
"169.254.0.0/16",
|
|
7694
|
+
"172.16.0.0/12",
|
|
7695
|
+
"192.0.0.0/24",
|
|
7696
|
+
"192.0.2.0/24",
|
|
7697
|
+
"192.88.99.0/24",
|
|
7698
|
+
"192.168.0.0/16",
|
|
7699
|
+
"198.18.0.0/15",
|
|
7700
|
+
"198.51.100.0/24",
|
|
7701
|
+
"203.0.113.0/24",
|
|
7702
|
+
"224.0.0.0/4",
|
|
7703
|
+
"240.0.0.0/4"
|
|
7704
|
+
];
|
|
7705
|
+
var KUBE_DNS = { namespace: "kube-system", labels: { "k8s-app": "kube-dns" } };
|
|
7706
|
+
var PSA_PREFIX = "pod-security.kubernetes.io";
|
|
7707
|
+
function psaLabels(level) {
|
|
7708
|
+
const advisory = level === "baseline" ? "restricted" : level;
|
|
7709
|
+
return {
|
|
7710
|
+
[`${PSA_PREFIX}/enforce`]: level,
|
|
7711
|
+
[`${PSA_PREFIX}/warn`]: advisory,
|
|
7712
|
+
[`${PSA_PREFIX}/audit`]: advisory
|
|
7713
|
+
};
|
|
7714
|
+
}
|
|
7715
|
+
var PSA_LABEL_KEYS = Object.keys(psaLabels("baseline"));
|
|
7716
|
+
function ipv4Value(address) {
|
|
7717
|
+
const parts = address.split(".");
|
|
7718
|
+
if (parts.length !== 4) return null;
|
|
7719
|
+
let value = 0;
|
|
7720
|
+
for (const part of parts) {
|
|
7721
|
+
if (!/^\d{1,3}$/.test(part)) return null;
|
|
7722
|
+
const octet = Number(part);
|
|
7723
|
+
if (octet > 255) return null;
|
|
7724
|
+
value = value * 256 + octet;
|
|
7725
|
+
}
|
|
7726
|
+
return value;
|
|
7727
|
+
}
|
|
7728
|
+
function inNonRoutableRange(address) {
|
|
7729
|
+
const value = ipv4Value(address);
|
|
7730
|
+
if (value === null) return false;
|
|
7731
|
+
return NON_ROUTABLE_IPV4.some((cidr) => {
|
|
7732
|
+
const [base = "", bits = "32"] = cidr.split("/");
|
|
7733
|
+
const start = ipv4Value(base) ?? 0;
|
|
7734
|
+
return value >= start && value < start + 2 ** (32 - Number(bits));
|
|
7735
|
+
});
|
|
7736
|
+
}
|
|
7737
|
+
function hostAddressExceptions(addresses) {
|
|
7738
|
+
const kept = /* @__PURE__ */ new Set();
|
|
7739
|
+
for (const raw of addresses) {
|
|
7740
|
+
const address = raw.trim();
|
|
7741
|
+
if (ipv4Value(address) === null || inNonRoutableRange(address)) continue;
|
|
7742
|
+
kept.add(`${address}/32`);
|
|
7743
|
+
}
|
|
7744
|
+
return [...kept].sort();
|
|
7745
|
+
}
|
|
7746
|
+
function renderEgressNetworkPolicy(namespace, hostAddresses) {
|
|
7747
|
+
const policy = {
|
|
7748
|
+
apiVersion: "networking.k8s.io/v1",
|
|
7749
|
+
kind: "NetworkPolicy",
|
|
7750
|
+
metadata: {
|
|
7751
|
+
name: EGRESS_POLICY_NAME,
|
|
7752
|
+
namespace: assertK8sName(namespace, "namespace"),
|
|
7753
|
+
labels: MANAGED_BY2
|
|
7754
|
+
},
|
|
7755
|
+
spec: {
|
|
7756
|
+
podSelector: {},
|
|
7757
|
+
policyTypes: ["Egress"],
|
|
7758
|
+
egress: [
|
|
7759
|
+
{
|
|
7760
|
+
to: [
|
|
7761
|
+
{
|
|
7762
|
+
namespaceSelector: {
|
|
7763
|
+
matchLabels: { "kubernetes.io/metadata.name": KUBE_DNS.namespace }
|
|
7764
|
+
},
|
|
7765
|
+
podSelector: { matchLabels: KUBE_DNS.labels }
|
|
7766
|
+
}
|
|
7767
|
+
],
|
|
7768
|
+
ports: [
|
|
7769
|
+
{ protocol: "UDP", port: 53 },
|
|
7770
|
+
{ protocol: "TCP", port: 53 }
|
|
7771
|
+
]
|
|
7772
|
+
},
|
|
7773
|
+
{
|
|
7774
|
+
// kube-router enforces after the Service's DNAT, so the registry is
|
|
7775
|
+
// reached by its pods' labels, never by the service range.
|
|
7776
|
+
to: [
|
|
7777
|
+
{
|
|
7778
|
+
namespaceSelector: {
|
|
7779
|
+
matchLabels: { "kubernetes.io/metadata.name": PERSONAL_LOCAL_REGISTRY_NAMESPACE }
|
|
7780
|
+
},
|
|
7781
|
+
podSelector: { matchLabels: LOCAL_REGISTRY_SELECTOR }
|
|
7782
|
+
}
|
|
7783
|
+
],
|
|
7784
|
+
ports: [{ protocol: "TCP", port: PERSONAL_LOCAL_REGISTRY_PORT }]
|
|
7785
|
+
},
|
|
7786
|
+
{
|
|
7787
|
+
to: [
|
|
7788
|
+
{
|
|
7789
|
+
ipBlock: {
|
|
7790
|
+
cidr: "0.0.0.0/0",
|
|
7791
|
+
except: [...NON_ROUTABLE_IPV4, ...hostAddressExceptions(hostAddresses)]
|
|
7792
|
+
}
|
|
7793
|
+
}
|
|
7794
|
+
]
|
|
7795
|
+
}
|
|
7796
|
+
]
|
|
7797
|
+
}
|
|
7798
|
+
};
|
|
7799
|
+
return `${JSON.stringify(policy, null, 2)}
|
|
7800
|
+
`;
|
|
7801
|
+
}
|
|
7802
|
+
var DISABLE_KEY = /(?:^|[\s{,])(["']?)disable-network-policy\1\s*:([^,}]*)/g;
|
|
7803
|
+
var DISABLE_FLAGS = /* @__PURE__ */ new Set(["--disable-network-policy", "-disable-network-policy"]);
|
|
7804
|
+
var FALSE_VALUES = /* @__PURE__ */ new Set(["false", "no", "off", "n", "f", "0"]);
|
|
7805
|
+
function setsTrue(raw) {
|
|
7806
|
+
const value = bareToken(raw).trim().toLowerCase();
|
|
7807
|
+
return !FALSE_VALUES.has(value);
|
|
7808
|
+
}
|
|
7809
|
+
function uncommented(line) {
|
|
7810
|
+
return /^\s*#/.test(line) ? "" : line.replace(/\s#.*$/, "");
|
|
7811
|
+
}
|
|
7812
|
+
function configSetsKey(text) {
|
|
7813
|
+
return text.split("\n").map(uncommented).some((line) => [...line.matchAll(DISABLE_KEY)].some((match) => setsTrue(match[2] ?? "")));
|
|
7814
|
+
}
|
|
7815
|
+
function unitLines(unitText) {
|
|
7816
|
+
const lines2 = [];
|
|
7817
|
+
let pending = "";
|
|
7818
|
+
for (const raw of unitText.split("\n")) {
|
|
7819
|
+
const line = raw.trimEnd();
|
|
7820
|
+
if (/^\s*[#;]/.test(line)) continue;
|
|
7821
|
+
if (line.endsWith("\\")) {
|
|
7822
|
+
pending += `${line.slice(0, -1)} `;
|
|
7823
|
+
continue;
|
|
7824
|
+
}
|
|
7825
|
+
lines2.push(pending + line);
|
|
7826
|
+
pending = "";
|
|
7827
|
+
}
|
|
7828
|
+
return pending ? [...lines2, pending] : lines2;
|
|
7829
|
+
}
|
|
7830
|
+
function flagSetIn(line) {
|
|
7831
|
+
return line.split(/\s+/).some((raw) => {
|
|
7832
|
+
const token = bareToken(raw).replace(/^["']+|["']+$/g, "");
|
|
7833
|
+
const [name = "", ...value] = token.split("=");
|
|
7834
|
+
return DISABLE_FLAGS.has(name) && (value.length === 0 || setsTrue(value.join("=")));
|
|
7835
|
+
});
|
|
7836
|
+
}
|
|
7837
|
+
function networkPolicyControllerDisabled(sources) {
|
|
7838
|
+
if (sources.configs.some((text) => text !== null && configSetsKey(text))) return true;
|
|
7839
|
+
return unitLines(sources.unitText).some(flagSetIn);
|
|
7840
|
+
}
|
|
7841
|
+
|
|
7842
|
+
// src/daemon/isolation-probes.ts
|
|
7843
|
+
var CONTROLLER_DISABLED_WARNING = "k3s runs with its network policy controller disabled, so the egress policy Conveyor applies here is not enforced. Remove disable-network-policy from the k3s config or unit and restart k3s. Until then this server is not isolated; Conveyor checks again within 10 minutes.";
|
|
7844
|
+
var CONTROLLER_UNKNOWN_WARNING = "Could not read the k3s unit or its config files to check that its network policy controller is on, so this server does not count as isolated. Check `systemctl cat k3s.service` and /etc/rancher/k3s; Conveyor checks again within 10 minutes.";
|
|
7845
|
+
var NODE_ADDRESSES_JSONPATH = '{range .items[*]}{range .status.addresses[?(@.type=="InternalIP")]}{.address}{"\\n"}{end}{range .status.addresses[?(@.type=="ExternalIP")]}{.address}{"\\n"}{end}{end}';
|
|
7846
|
+
var API_ENDPOINTS_JSONPATH = "{.items[*].endpoints[*].addresses[*]}";
|
|
7847
|
+
var IPV4_ON_INTERFACE = /\binet (\d{1,3}(?:\.\d{1,3}){3})(?:\/| peer )/g;
|
|
7848
|
+
async function stdoutOf(exec, bin, args) {
|
|
7849
|
+
const run = await exec(bin, args, { timeoutMs: 1e4 }).catch(() => null);
|
|
7850
|
+
return run && run.exitCode === 0 ? run.stdout : null;
|
|
7851
|
+
}
|
|
7852
|
+
async function readK3sConfigs(ctx) {
|
|
7853
|
+
const listed = await stdoutOf(ctx.exec, "find", [
|
|
7854
|
+
"-L",
|
|
7855
|
+
K3S_CONFIG_DROPIN_DIR,
|
|
7856
|
+
"-maxdepth",
|
|
7857
|
+
"1",
|
|
7858
|
+
"-type",
|
|
7859
|
+
"f",
|
|
7860
|
+
"(",
|
|
7861
|
+
"-iname",
|
|
7862
|
+
"*.yaml",
|
|
7863
|
+
"-o",
|
|
7864
|
+
"-iname",
|
|
7865
|
+
"*.yml",
|
|
7866
|
+
")"
|
|
7867
|
+
]);
|
|
7868
|
+
if (listed === null) return null;
|
|
7869
|
+
const paths = listed.split("\n").map((path) => path.trim()).filter(Boolean).sort();
|
|
7870
|
+
const dropIns = await Promise.all(paths.map((path) => ctx.fs.readFile(path)));
|
|
7871
|
+
if (dropIns.some((text) => text === null)) return null;
|
|
7872
|
+
return [await ctx.fs.readFile(K3S_OWNER_CONFIG), ...dropIns];
|
|
7873
|
+
}
|
|
7874
|
+
async function controllerProblem(ctx) {
|
|
7875
|
+
const unitText = await stdoutOf(ctx.exec, "systemctl", ["cat", "k3s.service"]);
|
|
7876
|
+
const configs = unitText === null ? null : await readK3sConfigs(ctx);
|
|
7877
|
+
if (unitText === null || configs === null) return CONTROLLER_UNKNOWN_WARNING;
|
|
7878
|
+
return networkPolicyControllerDisabled({ configs, unitText }) ? CONTROLLER_DISABLED_WARNING : null;
|
|
7879
|
+
}
|
|
7880
|
+
async function readHostAddresses(exec) {
|
|
7881
|
+
const nodes = await stdoutOf(exec, "k3s", [
|
|
7882
|
+
"kubectl",
|
|
7883
|
+
"get",
|
|
7884
|
+
"nodes",
|
|
7885
|
+
"-o",
|
|
7886
|
+
`jsonpath=${NODE_ADDRESSES_JSONPATH}`
|
|
7887
|
+
]);
|
|
7888
|
+
const interfaces = await stdoutOf(exec, "ip", ["-o", "-4", "addr", "show"]);
|
|
7889
|
+
const api = await stdoutOf(exec, "k3s", [
|
|
7890
|
+
"kubectl",
|
|
7891
|
+
"get",
|
|
7892
|
+
"endpointslices",
|
|
7893
|
+
"-n",
|
|
7894
|
+
"default",
|
|
7895
|
+
"-l",
|
|
7896
|
+
"kubernetes.io/service-name=kubernetes",
|
|
7897
|
+
"-o",
|
|
7898
|
+
`jsonpath=${API_ENDPOINTS_JSONPATH}`
|
|
7899
|
+
]);
|
|
7900
|
+
if (nodes === null || interfaces === null || api === null) return null;
|
|
7901
|
+
const onInterfaces = [...interfaces.matchAll(IPV4_ON_INTERFACE)].map((match) => match[1] ?? "");
|
|
7902
|
+
return [...nodes.split(/\s+/), ...onInterfaces, ...api.split(/\s+/)].filter(Boolean);
|
|
7903
|
+
}
|
|
7904
|
+
async function recheckIsolation(ctx, reconciled) {
|
|
7905
|
+
if (reconciled?.applied !== true) return { isolation: reconciled, warnings: [] };
|
|
7906
|
+
const problem = await controllerProblem(ctx);
|
|
7907
|
+
return problem ? { isolation: { applied: false }, warnings: [problem] } : { isolation: reconciled, warnings: [] };
|
|
7908
|
+
}
|
|
7909
|
+
|
|
7643
7910
|
// src/daemon/prune-namespaces.ts
|
|
7644
7911
|
var POOL_NAMESPACE_PREFIX = "claudespace-";
|
|
7645
7912
|
var WORKSPACE_MANAGER_ROLE = "conveyor-workspace-manager";
|
|
@@ -7702,6 +7969,143 @@ async function pruneStaleNamespaces(ctx, desired, result) {
|
|
|
7702
7969
|
}
|
|
7703
7970
|
}
|
|
7704
7971
|
|
|
7972
|
+
// src/daemon/namespace-upkeep.ts
|
|
7973
|
+
function message(error) {
|
|
7974
|
+
return error instanceof Error ? error.message : String(error);
|
|
7975
|
+
}
|
|
7976
|
+
function renderLimitRange(namespace, limits) {
|
|
7977
|
+
const ns = assertK8sName(namespace, "namespace");
|
|
7978
|
+
const values = [
|
|
7979
|
+
assertQuantity(limits.defaultRequest.cpu, "defaultRequest.cpu"),
|
|
7980
|
+
assertQuantity(limits.defaultRequest.memory, "defaultRequest.memory"),
|
|
7981
|
+
assertQuantity(limits.default.cpu, "default.cpu"),
|
|
7982
|
+
assertQuantity(limits.default.memory, "default.memory")
|
|
7983
|
+
];
|
|
7984
|
+
return [
|
|
7985
|
+
"apiVersion: v1",
|
|
7986
|
+
"kind: LimitRange",
|
|
7987
|
+
"metadata:",
|
|
7988
|
+
" name: conveyor-k3-defaults",
|
|
7989
|
+
` namespace: ${ns}`,
|
|
7990
|
+
"spec:",
|
|
7991
|
+
" limits:",
|
|
7992
|
+
" - type: Container",
|
|
7993
|
+
" defaultRequest:",
|
|
7994
|
+
` cpu: "${values[0]}"`,
|
|
7995
|
+
` memory: "${values[1]}"`,
|
|
7996
|
+
" default:",
|
|
7997
|
+
` cpu: "${values[2]}"`,
|
|
7998
|
+
` memory: "${values[3]}"`,
|
|
7999
|
+
""
|
|
8000
|
+
].join("\n");
|
|
8001
|
+
}
|
|
8002
|
+
async function reconcileNamespaces(ctx, desired, result) {
|
|
8003
|
+
for (const namespace of desired.namespaces) {
|
|
8004
|
+
try {
|
|
8005
|
+
await kubectlApply(ctx.exec, renderLimitRange(namespace.name, namespace.limitRange));
|
|
8006
|
+
} catch (error) {
|
|
8007
|
+
result.warnings.push(
|
|
8008
|
+
`Could not apply resource defaults to ${namespace.name} (${namespace.projectName}): ${message(error)}`
|
|
8009
|
+
);
|
|
8010
|
+
}
|
|
8011
|
+
}
|
|
8012
|
+
}
|
|
8013
|
+
async function ensureBakeNamespace(ctx, desired) {
|
|
8014
|
+
const found = await ctx.exec(
|
|
8015
|
+
"k3s",
|
|
8016
|
+
["kubectl", "get", "namespace", PERSONAL_BAKE_NAMESPACE],
|
|
8017
|
+
KUBECTL_TIMEOUT2
|
|
8018
|
+
);
|
|
8019
|
+
if (found.exitCode !== 0) {
|
|
8020
|
+
await runOrThrow(
|
|
8021
|
+
ctx.exec,
|
|
8022
|
+
"k3s",
|
|
8023
|
+
["kubectl", "create", "namespace", PERSONAL_BAKE_NAMESPACE],
|
|
8024
|
+
KUBECTL_TIMEOUT2
|
|
8025
|
+
);
|
|
8026
|
+
}
|
|
8027
|
+
const limitRange = desired.namespaces[0]?.limitRange;
|
|
8028
|
+
if (limitRange) {
|
|
8029
|
+
await kubectlApply(ctx.exec, renderLimitRange(PERSONAL_BAKE_NAMESPACE, limitRange));
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
function knownStance(isolation) {
|
|
8033
|
+
const { podSecurity, egress, ...rest } = { ...isolation };
|
|
8034
|
+
const extra = Object.keys(rest);
|
|
8035
|
+
if (podSecurity === "baseline" && egress === "no-private" && extra.length === 0) return null;
|
|
8036
|
+
const named = `Pod Security "${String(podSecurity).slice(0, 40)}", egress "${String(egress).slice(0, 40)}"`;
|
|
8037
|
+
return extra.length === 0 ? named : `${named}, and ${extra.slice(0, 3).join(", ").slice(0, 80)}`;
|
|
8038
|
+
}
|
|
8039
|
+
var KUBECTL_TIMEOUT2 = { timeoutMs: 3e4 };
|
|
8040
|
+
var RECHECK = "Conveyor checks again within 10 minutes.";
|
|
8041
|
+
async function isolateNamespace(ctx, namespace, isolation, fail) {
|
|
8042
|
+
const ns = assertK8sName(namespace, "namespace");
|
|
8043
|
+
const labels = Object.entries(psaLabels(isolation.podSecurity)).map(
|
|
8044
|
+
([key, value]) => `${key}=${value}`
|
|
8045
|
+
);
|
|
8046
|
+
const labelled = await ctx.exec(
|
|
8047
|
+
"k3s",
|
|
8048
|
+
["kubectl", "label", "namespace", ns, "--overwrite", ...labels],
|
|
8049
|
+
KUBECTL_TIMEOUT2
|
|
8050
|
+
);
|
|
8051
|
+
if (labelled.exitCode !== 0) {
|
|
8052
|
+
fail(
|
|
8053
|
+
`Could not apply Pod Security labels to ${ns}: ${labelled.stderr.trim().slice(0, 200)} ${RECHECK}`
|
|
8054
|
+
);
|
|
8055
|
+
}
|
|
8056
|
+
if (isolation.hostAddresses === null) return;
|
|
8057
|
+
try {
|
|
8058
|
+
await kubectlApply(ctx.exec, renderEgressNetworkPolicy(ns, isolation.hostAddresses));
|
|
8059
|
+
} catch (error) {
|
|
8060
|
+
fail(`Could not apply the egress policy to ${ns}: ${message(error).slice(0, 200)} ${RECHECK}`);
|
|
8061
|
+
}
|
|
8062
|
+
}
|
|
8063
|
+
async function reconcileIsolation(ctx, desired, result) {
|
|
8064
|
+
try {
|
|
8065
|
+
await ensureBakeNamespace(ctx, desired);
|
|
8066
|
+
} catch (error) {
|
|
8067
|
+
result.warnings.push(
|
|
8068
|
+
`Could not prepare the bake namespace ${PERSONAL_BAKE_NAMESPACE}: ${message(error)}`
|
|
8069
|
+
);
|
|
8070
|
+
}
|
|
8071
|
+
const isolation = desired.isolation;
|
|
8072
|
+
if (!isolation) {
|
|
8073
|
+
result.isolation = void 0;
|
|
8074
|
+
return;
|
|
8075
|
+
}
|
|
8076
|
+
const unknown = knownStance(isolation);
|
|
8077
|
+
if (unknown) {
|
|
8078
|
+
result.warnings.push(
|
|
8079
|
+
`Conveyor asks for pod isolation this version of conveyor-k3 does not know (${unknown}), so nothing was changed and this server does not count as isolated. Run \`sudo conveyor-k3 update\`.`
|
|
8080
|
+
);
|
|
8081
|
+
result.isolation = { applied: false };
|
|
8082
|
+
return;
|
|
8083
|
+
}
|
|
8084
|
+
let applied = true;
|
|
8085
|
+
const fail = (warning) => {
|
|
8086
|
+
applied = false;
|
|
8087
|
+
result.warnings.push(warning);
|
|
8088
|
+
};
|
|
8089
|
+
const problem = await controllerProblem(ctx);
|
|
8090
|
+
if (problem) fail(problem);
|
|
8091
|
+
const hostAddresses = await readHostAddresses(ctx.exec);
|
|
8092
|
+
if (hostAddresses === null) {
|
|
8093
|
+
fail(
|
|
8094
|
+
`Could not read every address this server answers on, so the egress policies in place were left as they are and this server does not count as isolated. ${RECHECK}`
|
|
8095
|
+
);
|
|
8096
|
+
}
|
|
8097
|
+
for (const namespace of desired.namespaces) {
|
|
8098
|
+
await isolateNamespace(ctx, namespace.name, { podSecurity: "baseline", hostAddresses }, fail);
|
|
8099
|
+
}
|
|
8100
|
+
await isolateNamespace(
|
|
8101
|
+
ctx,
|
|
8102
|
+
PERSONAL_BAKE_NAMESPACE,
|
|
8103
|
+
{ podSecurity: "privileged", hostAddresses },
|
|
8104
|
+
fail
|
|
8105
|
+
);
|
|
8106
|
+
result.isolation = { applied };
|
|
8107
|
+
}
|
|
8108
|
+
|
|
7705
8109
|
// src/daemon/registry-tags.ts
|
|
7706
8110
|
var REPO_NAME = /^[a-z0-9]+(?:[._-][a-z0-9]+)*(?:\/[a-z0-9]+(?:[._-][a-z0-9]+)*)*$/;
|
|
7707
8111
|
var TAG_NAME = /^[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/;
|
|
@@ -8285,14 +8689,22 @@ async function collectHeartbeat(ports, state, inventory) {
|
|
|
8285
8689
|
...runnerUsers.length > 0 ? { runnerUsers } : {},
|
|
8286
8690
|
...localImages ? { localImages } : {},
|
|
8287
8691
|
...registry.fields,
|
|
8288
|
-
|
|
8692
|
+
...state.isolation ? { isolation: state.isolation } : {},
|
|
8693
|
+
localWarnings: withinHeartbeatBounds([
|
|
8289
8694
|
...state.localWarnings,
|
|
8290
8695
|
...gcWarning ? [gcWarning] : [],
|
|
8291
8696
|
...ungranted.length > 0 ? [ungrantedRunnersWarning(ungranted)] : [],
|
|
8292
8697
|
...registry.warnings
|
|
8293
|
-
]
|
|
8698
|
+
])
|
|
8294
8699
|
};
|
|
8295
8700
|
}
|
|
8701
|
+
var HEARTBEAT_LIST_MAX = 64;
|
|
8702
|
+
var HEARTBEAT_STRING_MAX = 512;
|
|
8703
|
+
function withinHeartbeatBounds(warnings) {
|
|
8704
|
+
return warnings.slice(0, HEARTBEAT_LIST_MAX).map(
|
|
8705
|
+
(warning) => warning.length > HEARTBEAT_STRING_MAX ? `${warning.slice(0, HEARTBEAT_STRING_MAX - 1)}\u2026` : warning
|
|
8706
|
+
);
|
|
8707
|
+
}
|
|
8296
8708
|
async function readPodIdentities(exec) {
|
|
8297
8709
|
const result = await exec(
|
|
8298
8710
|
"k3s",
|
|
@@ -8374,9 +8786,12 @@ async function runRegistryUpkeep(ports, lastGcAt, maintenanceHour) {
|
|
|
8374
8786
|
}
|
|
8375
8787
|
|
|
8376
8788
|
// src/daemon/reconcile.ts
|
|
8377
|
-
|
|
8789
|
+
function ownerRestartWarning(change) {
|
|
8790
|
+
return `${change} Conveyor did not install this server's k3s, so it never restarts it: run \`sudo systemctl restart k3s\` when no build runs.`;
|
|
8791
|
+
}
|
|
8792
|
+
async function reconcileKubelet(ctx, desired, result, managed) {
|
|
8378
8793
|
const ownerConfig = await ctx.fs.readFile(K3S_OWNER_CONFIG);
|
|
8379
|
-
const rendered = renderK3sDropIn(desired.kubelet, ownerConfig);
|
|
8794
|
+
const rendered = renderK3sDropIn(desired.kubelet, ownerConfig, { disableComponents: managed });
|
|
8380
8795
|
result.skippedKubeletFlags = rendered.skipped;
|
|
8381
8796
|
result.effectiveImageGcHighThreshold = rendered.skipped.includes("image-gc-high-threshold") ? ownerImageGcHighThreshold(ownerConfig) : desired.kubelet.imageGcHighThreshold;
|
|
8382
8797
|
for (const flag of rendered.skipped) {
|
|
@@ -8392,6 +8807,10 @@ async function reconcileKubelet(ctx, desired, result) {
|
|
|
8392
8807
|
if (current === rendered.content) return;
|
|
8393
8808
|
await ctx.fs.ensureDir(K3S_CONFIG_DROPIN.slice(0, K3S_CONFIG_DROPIN.lastIndexOf("/")));
|
|
8394
8809
|
await ctx.fs.writeFile(K3S_CONFIG_DROPIN, rendered.content, 420);
|
|
8810
|
+
if (!managed) {
|
|
8811
|
+
result.warnings.push(ownerRestartWarning("Kubelet settings changed."));
|
|
8812
|
+
return;
|
|
8813
|
+
}
|
|
8395
8814
|
if (!mayDisrupt(ctx.runningConveyorPods)) {
|
|
8396
8815
|
result.warnings.push(
|
|
8397
8816
|
`Kubelet settings changed but ${busyReason(ctx.runningConveyorPods)} \u2014 the restart is deferred until the machine is idle.`
|
|
@@ -8442,43 +8861,6 @@ async function reconcilePriorityClass(ctx, desired, result) {
|
|
|
8442
8861
|
);
|
|
8443
8862
|
}
|
|
8444
8863
|
}
|
|
8445
|
-
function renderLimitRange(namespace, limits) {
|
|
8446
|
-
const ns = assertK8sName(namespace, "namespace");
|
|
8447
|
-
const values = [
|
|
8448
|
-
assertQuantity(limits.defaultRequest.cpu, "defaultRequest.cpu"),
|
|
8449
|
-
assertQuantity(limits.defaultRequest.memory, "defaultRequest.memory"),
|
|
8450
|
-
assertQuantity(limits.default.cpu, "default.cpu"),
|
|
8451
|
-
assertQuantity(limits.default.memory, "default.memory")
|
|
8452
|
-
];
|
|
8453
|
-
return [
|
|
8454
|
-
"apiVersion: v1",
|
|
8455
|
-
"kind: LimitRange",
|
|
8456
|
-
"metadata:",
|
|
8457
|
-
" name: conveyor-k3-defaults",
|
|
8458
|
-
` namespace: ${ns}`,
|
|
8459
|
-
"spec:",
|
|
8460
|
-
" limits:",
|
|
8461
|
-
" - type: Container",
|
|
8462
|
-
" defaultRequest:",
|
|
8463
|
-
` cpu: "${values[0]}"`,
|
|
8464
|
-
` memory: "${values[1]}"`,
|
|
8465
|
-
" default:",
|
|
8466
|
-
` cpu: "${values[2]}"`,
|
|
8467
|
-
` memory: "${values[3]}"`,
|
|
8468
|
-
""
|
|
8469
|
-
].join("\n");
|
|
8470
|
-
}
|
|
8471
|
-
async function reconcileNamespaces(ctx, desired, result) {
|
|
8472
|
-
for (const namespace of desired.namespaces) {
|
|
8473
|
-
try {
|
|
8474
|
-
await kubectlApply(ctx.exec, renderLimitRange(namespace.name, namespace.limitRange));
|
|
8475
|
-
} catch (error) {
|
|
8476
|
-
result.warnings.push(
|
|
8477
|
-
`Could not apply resource defaults to ${namespace.name} (${namespace.projectName}): ${error instanceof Error ? error.message : String(error)}`
|
|
8478
|
-
);
|
|
8479
|
-
}
|
|
8480
|
-
}
|
|
8481
|
-
}
|
|
8482
8864
|
async function step(result, label, run) {
|
|
8483
8865
|
try {
|
|
8484
8866
|
await run();
|
|
@@ -8515,6 +8897,12 @@ async function reconcile(ctx, desired) {
|
|
|
8515
8897
|
"Could not apply namespace defaults",
|
|
8516
8898
|
() => reconcileNamespaces(ctx, desired, result)
|
|
8517
8899
|
);
|
|
8900
|
+
await step(
|
|
8901
|
+
result,
|
|
8902
|
+
"Could not apply pod isolation",
|
|
8903
|
+
() => reconcileIsolation(ctx, desired, result)
|
|
8904
|
+
);
|
|
8905
|
+
if (desired.isolation && result.isolation === void 0) result.isolation = { applied: false };
|
|
8518
8906
|
if (manifestAccepted) {
|
|
8519
8907
|
await step(
|
|
8520
8908
|
result,
|
|
@@ -8523,6 +8911,7 @@ async function reconcile(ctx, desired) {
|
|
|
8523
8911
|
);
|
|
8524
8912
|
}
|
|
8525
8913
|
const registry = desired.localRegistry?.enabled === true;
|
|
8914
|
+
const managed = managesK3s(desired, await readState(ctx.fs).catch(() => ({})));
|
|
8526
8915
|
if (registry) {
|
|
8527
8916
|
await step(result, "Could not reconcile the local image registry", async () => {
|
|
8528
8917
|
await deployLocalRegistry(ctx);
|
|
@@ -8531,10 +8920,15 @@ async function reconcile(ctx, desired) {
|
|
|
8531
8920
|
await step(
|
|
8532
8921
|
result,
|
|
8533
8922
|
"Could not apply kubelet settings",
|
|
8534
|
-
() => reconcileKubelet(ctx, desired, result)
|
|
8923
|
+
() => reconcileKubelet(ctx, desired, result, managed)
|
|
8535
8924
|
);
|
|
8536
8925
|
if (registry && !result.restartedK3s) {
|
|
8537
8926
|
await step(result, "Could not load the local image registry mirror", async () => {
|
|
8927
|
+
if (!managed) {
|
|
8928
|
+
if (await registryMirrorPending(ctx.fs))
|
|
8929
|
+
result.warnings.push(ownerRestartWarning("The local image registry's mirror is new."));
|
|
8930
|
+
return;
|
|
8931
|
+
}
|
|
8538
8932
|
const loaded = await loadRegistryMirror(ctx);
|
|
8539
8933
|
result.restartedK3s = loaded.restarted;
|
|
8540
8934
|
if (loaded.warning) result.warnings.push(loaded.warning);
|
|
@@ -8547,6 +8941,8 @@ async function reconcile(ctx, desired) {
|
|
|
8547
8941
|
var HOUR_MS2 = 60 * 6e4;
|
|
8548
8942
|
var DAY_MS = 24 * HOUR_MS2;
|
|
8549
8943
|
var STORE_MEASURE_INTERVAL_MS = 55 * 6e4;
|
|
8944
|
+
var ISOLATION_RETRY_FIRST_MS = 6e4;
|
|
8945
|
+
var ISOLATION_RETRY_MAX_MS = 10 * 6e4;
|
|
8550
8946
|
var DISK_PRESSURE_FREE_FRACTION = 0.2;
|
|
8551
8947
|
var STRANDED_PRUNE_BYTES = 20 * 1024 ** 3;
|
|
8552
8948
|
function flattenWanted(desired) {
|
|
@@ -8587,12 +8983,22 @@ var ClusterDaemon = class {
|
|
|
8587
8983
|
localImageHashes = /* @__PURE__ */ new Map();
|
|
8588
8984
|
/** How long the in-cluster registry has been not ready, across beats. */
|
|
8589
8985
|
registryWatch = { notReadySince: null };
|
|
8986
|
+
/**
|
|
8987
|
+
* Whether pod isolation is in force, from the last reconcile; undefined
|
|
8988
|
+
* while desired state does not ask for it. Every heartbeat checks it again
|
|
8989
|
+
* against k3s's own settings before reporting it.
|
|
8990
|
+
*/
|
|
8991
|
+
isolation = void 0;
|
|
8590
8992
|
timers = [];
|
|
8591
8993
|
/** When the last store walk started, so one that failed is not retried on every reconcile. */
|
|
8592
8994
|
storeWalkStartedAt = 0;
|
|
8593
8995
|
/** Serializes reconcile against itself — a sync nudge during a reconcile
|
|
8594
8996
|
* must queue, not interleave two kubectl applies of the same manifests. */
|
|
8595
8997
|
reconciling = null;
|
|
8998
|
+
/** The run queued behind the running one, until it starts. At most one waits. */
|
|
8999
|
+
queuedRun = null;
|
|
9000
|
+
/** The next reconcile while pod isolation is not applied; `dueAt` 0 = none. */
|
|
9001
|
+
isolationRetry = { delayMs: ISOLATION_RETRY_FIRST_MS, dueAt: 0 };
|
|
8596
9002
|
constructor(ports) {
|
|
8597
9003
|
this.ports = ports;
|
|
8598
9004
|
}
|
|
@@ -8628,10 +9034,27 @@ var ClusterDaemon = class {
|
|
|
8628
9034
|
}
|
|
8629
9035
|
/** Fetch the desired state and converge to it. Queued, never concurrent. */
|
|
8630
9036
|
syncAndReconcile() {
|
|
8631
|
-
|
|
9037
|
+
if (this.queuedRun) return this.queuedRun;
|
|
9038
|
+
const run = (this.reconciling ?? Promise.resolve()).then(() => {
|
|
9039
|
+
this.queuedRun = null;
|
|
9040
|
+
return this.runReconcile();
|
|
9041
|
+
});
|
|
9042
|
+
this.queuedRun = run;
|
|
8632
9043
|
this.reconciling = run.catch(() => void 0);
|
|
8633
9044
|
return run;
|
|
8634
9045
|
}
|
|
9046
|
+
/** Reconcile again later while pod isolation is not applied; stop once it is. */
|
|
9047
|
+
scheduleIsolationRetry() {
|
|
9048
|
+
if (this.isolation?.applied !== false) {
|
|
9049
|
+
this.isolationRetry = { delayMs: ISOLATION_RETRY_FIRST_MS, dueAt: 0 };
|
|
9050
|
+
return;
|
|
9051
|
+
}
|
|
9052
|
+
const { delayMs } = this.isolationRetry;
|
|
9053
|
+
this.isolationRetry = {
|
|
9054
|
+
delayMs: Math.min(delayMs * 2, ISOLATION_RETRY_MAX_MS),
|
|
9055
|
+
dueAt: Date.now() + delayMs
|
|
9056
|
+
};
|
|
9057
|
+
}
|
|
8635
9058
|
async runReconcile() {
|
|
8636
9059
|
try {
|
|
8637
9060
|
this.desired = await this.ports.connection.requestDesiredState();
|
|
@@ -8647,6 +9070,8 @@ var ClusterDaemon = class {
|
|
|
8647
9070
|
this.desired
|
|
8648
9071
|
);
|
|
8649
9072
|
this.warnings = result.warnings;
|
|
9073
|
+
this.isolation = result.isolation;
|
|
9074
|
+
this.scheduleIsolationRetry();
|
|
8650
9075
|
for (const warning of result.warnings) this.ports.log(warning);
|
|
8651
9076
|
if (result.prunedNamespaces.length > 0) {
|
|
8652
9077
|
this.ports.log(
|
|
@@ -8817,6 +9242,10 @@ var ClusterDaemon = class {
|
|
|
8817
9242
|
const inventory = await readImageInventory(this.ports.exec).catch(() => null);
|
|
8818
9243
|
const registryOn = this.desired?.localRegistry?.enabled === true;
|
|
8819
9244
|
if (!registryOn) this.registryWatch.notReadySince = null;
|
|
9245
|
+
const isolation = await recheckIsolation(
|
|
9246
|
+
{ exec: this.ports.exec, fs: this.ports.fs },
|
|
9247
|
+
this.isolation
|
|
9248
|
+
);
|
|
8820
9249
|
return await collectHeartbeat(
|
|
8821
9250
|
{
|
|
8822
9251
|
exec: this.ports.exec,
|
|
@@ -8831,10 +9260,11 @@ var ClusterDaemon = class {
|
|
|
8831
9260
|
lastPruneAt: this.state?.lastPruneAt ?? null,
|
|
8832
9261
|
lastWarmAt: this.state?.lastWarmAt ?? null,
|
|
8833
9262
|
lastUpdateAt: this.state?.lastUpdateAt ?? null,
|
|
8834
|
-
localWarnings: [...this.warnings, ...this.warmWarnings],
|
|
9263
|
+
localWarnings: [...this.warnings, ...this.warmWarnings, ...isolation.warnings],
|
|
8835
9264
|
imageGcHighThreshold: this.effectiveImageGcHigh,
|
|
8836
9265
|
localImageHashes: this.localImageHashes,
|
|
8837
9266
|
...registryOn ? { localRegistry: this.registryWatch } : {},
|
|
9267
|
+
...isolation.isolation ? { isolation: isolation.isolation } : {},
|
|
8838
9268
|
k3sStoreBytes: this.measuredStoreBytes
|
|
8839
9269
|
},
|
|
8840
9270
|
inventory
|
|
@@ -8859,6 +9289,10 @@ var ClusterDaemon = class {
|
|
|
8859
9289
|
return this.beating;
|
|
8860
9290
|
}
|
|
8861
9291
|
async runBeat() {
|
|
9292
|
+
if (this.isolationRetry.dueAt > 0 && Date.now() >= this.isolationRetry.dueAt) {
|
|
9293
|
+
this.isolationRetry.dueAt = 0;
|
|
9294
|
+
void this.syncAndReconcile();
|
|
9295
|
+
}
|
|
8862
9296
|
try {
|
|
8863
9297
|
const workloads = await this.ports.connection.sendHeartbeat({
|
|
8864
9298
|
...await this.buildHeartbeat(),
|
|
@@ -9017,6 +9451,7 @@ function createMemoryFileSystem(seed = {}) {
|
|
|
9017
9451
|
// src/verbs.ts
|
|
9018
9452
|
var VERBS = [
|
|
9019
9453
|
"vm",
|
|
9454
|
+
"host",
|
|
9020
9455
|
"setup",
|
|
9021
9456
|
"start",
|
|
9022
9457
|
"stop",
|
|
@@ -9049,14 +9484,22 @@ function parseArgs(argv) {
|
|
|
9049
9484
|
}
|
|
9050
9485
|
return { verb, positional, flags };
|
|
9051
9486
|
}
|
|
9052
|
-
var HELP = `conveyor-k3 \u2014
|
|
9487
|
+
var HELP = `conveyor-k3 \u2014 Personal Compute for Conveyor
|
|
9053
9488
|
|
|
9054
9489
|
Usage: conveyor-k3 <command> [options]
|
|
9055
9490
|
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
|
|
9059
|
-
|
|
9491
|
+
One product, two runtimes. Pick the one that fits the machine:
|
|
9492
|
+
|
|
9493
|
+
On your computer or server:
|
|
9494
|
+
vm Personal computer runtime: an isolated VM on macOS or
|
|
9495
|
+
Linux. Run conveyor-k3 vm for its commands.
|
|
9496
|
+
host Dedicated server runtime: k3s and the daemon on this
|
|
9497
|
+
Linux machine, with no VM. Root only. Run
|
|
9498
|
+
conveyor-k3 host for its commands.
|
|
9499
|
+
|
|
9500
|
+
Inside a linked machine (the VM guest, or the server itself):
|
|
9501
|
+
setup VM guest only: install and enrol this machine. Safe
|
|
9502
|
+
to re-run. On a server, use conveyor-k3 host setup.
|
|
9060
9503
|
start Start the tunnel and the daemon.
|
|
9061
9504
|
stop Stop both, and tell Conveyor at once so your next
|
|
9062
9505
|
build goes straight to project compute.
|
|
@@ -9081,10 +9524,12 @@ Commands:
|
|
|
9081
9524
|
into this node and pin it. Writes one file under
|
|
9082
9525
|
/etc/sudoers.d, checked with visudo first. Needed only
|
|
9083
9526
|
when a project has Bake Locally turned on.
|
|
9084
|
-
uninstall
|
|
9085
|
-
registry. Your k3s config, your own
|
|
9086
|
-
entries, your workloads, and the
|
|
9087
|
-
left alone.
|
|
9527
|
+
uninstall VM guest only: remove Conveyor's units, environment,
|
|
9528
|
+
state, and image registry. Your k3s config, your own
|
|
9529
|
+
registries.yaml entries, your workloads, and the
|
|
9530
|
+
registry's data are left alone. On a server, use
|
|
9531
|
+
conveyor-k3 host uninstall: it also removes the
|
|
9532
|
+
device key.
|
|
9088
9533
|
--purge-k3s --yes also remove k3s itself and the
|
|
9089
9534
|
registry's data
|
|
9090
9535
|
daemon Run in the foreground (what the systemd unit calls).
|
|
@@ -9181,6 +9626,47 @@ async function removeLocalRegistry(ports) {
|
|
|
9181
9626
|
`Removed the local image registry's mirror from ${REGISTRIES_FILE} (backup: ${backup}).`
|
|
9182
9627
|
);
|
|
9183
9628
|
}
|
|
9629
|
+
async function removeIsolation(ports) {
|
|
9630
|
+
const [key, value] = Object.entries(MANAGED_BY2)[0] ?? [];
|
|
9631
|
+
const removed = await ports.exec(
|
|
9632
|
+
"k3s",
|
|
9633
|
+
["kubectl", "delete", "networkpolicy", "-A", "-l", `${key}=${value}`, "--ignore-not-found"],
|
|
9634
|
+
{ timeoutMs: 12e4 }
|
|
9635
|
+
);
|
|
9636
|
+
if (removed.exitCode !== 0) {
|
|
9637
|
+
ports.log(
|
|
9638
|
+
`Could not remove Conveyor's network policies: ${removed.stderr.trim().slice(0, 200)}`
|
|
9639
|
+
);
|
|
9640
|
+
}
|
|
9641
|
+
const listed = await ports.exec("k3s", [
|
|
9642
|
+
"kubectl",
|
|
9643
|
+
"get",
|
|
9644
|
+
"namespaces",
|
|
9645
|
+
"-o",
|
|
9646
|
+
"jsonpath={.items[*].metadata.name}"
|
|
9647
|
+
]);
|
|
9648
|
+
if (listed.exitCode !== 0) {
|
|
9649
|
+
ports.log(
|
|
9650
|
+
`Could not list namespaces to remove Conveyor's Pod Security labels: ${listed.stderr.trim().slice(0, 200)}`
|
|
9651
|
+
);
|
|
9652
|
+
return;
|
|
9653
|
+
}
|
|
9654
|
+
const namespaces = listed.stdout.split(/\s+/).filter((name) => name.startsWith("claudespace-") || name === PERSONAL_BAKE_NAMESPACE);
|
|
9655
|
+
for (const namespace of namespaces) {
|
|
9656
|
+
const unlabelled = await ports.exec("k3s", [
|
|
9657
|
+
"kubectl",
|
|
9658
|
+
"label",
|
|
9659
|
+
"namespace",
|
|
9660
|
+
namespace,
|
|
9661
|
+
...PSA_LABEL_KEYS.map((labelKey) => `${labelKey}-`)
|
|
9662
|
+
]);
|
|
9663
|
+
if (unlabelled.exitCode !== 0) {
|
|
9664
|
+
ports.log(
|
|
9665
|
+
`Could not remove Conveyor's Pod Security labels from ${namespace}: ${unlabelled.stderr.trim().slice(0, 200)}`
|
|
9666
|
+
);
|
|
9667
|
+
}
|
|
9668
|
+
}
|
|
9669
|
+
}
|
|
9184
9670
|
async function uninstall(ports, options = {}) {
|
|
9185
9671
|
const result = { stoppedUnits: [], removedFiles: [], purgedK3s: false };
|
|
9186
9672
|
if (options.purgeK3s && !options.confirmed) {
|
|
@@ -9193,6 +9679,7 @@ async function uninstall(ports, options = {}) {
|
|
|
9193
9679
|
result.stoppedUnits.push(unit);
|
|
9194
9680
|
}
|
|
9195
9681
|
await removeLocalRegistry(ports);
|
|
9682
|
+
await removeIsolation(ports);
|
|
9196
9683
|
for (const path of OWNED_FILES) {
|
|
9197
9684
|
await ports.fs.removeFile(path);
|
|
9198
9685
|
result.removedFiles.push(path);
|
|
@@ -9259,12 +9746,6 @@ function readExecStart(unit) {
|
|
|
9259
9746
|
}
|
|
9260
9747
|
return collected.join(" ");
|
|
9261
9748
|
}
|
|
9262
|
-
function bareToken(token) {
|
|
9263
|
-
let bare = token.trim();
|
|
9264
|
-
if (bare.endsWith("\\")) bare = bare.slice(0, -1).trim();
|
|
9265
|
-
if (bare.length >= 2 && bare.startsWith("'") && bare.endsWith("'")) bare = bare.slice(1, -1);
|
|
9266
|
-
return bare;
|
|
9267
|
-
}
|
|
9268
9749
|
function parseForeignExecFlags(execStart) {
|
|
9269
9750
|
const ours = new Set(K3S_INSTALL_EXEC.split(/\s+/).filter((token) => token.startsWith("--")));
|
|
9270
9751
|
const foreign = [];
|
|
@@ -9284,6 +9765,12 @@ async function foreignK3sExecFlags(exec) {
|
|
|
9284
9765
|
return parseForeignExecFlags(readExecStart(unit.stdout));
|
|
9285
9766
|
}
|
|
9286
9767
|
function decideK3sUpgrade(input) {
|
|
9768
|
+
if (input.managesK3s === false) {
|
|
9769
|
+
return {
|
|
9770
|
+
upgrade: false,
|
|
9771
|
+
reason: "Conveyor did not install this server's k3s, so its owner upgrades it"
|
|
9772
|
+
};
|
|
9773
|
+
}
|
|
9287
9774
|
if (!input.autoUpgradeK3s) {
|
|
9288
9775
|
return { upgrade: false, reason: "automatic k3s upgrades are turned off for this machine" };
|
|
9289
9776
|
}
|