@codyswann/lisa 4.45.7 → 4.45.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +21 -2
- package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +68 -0
- package/all/merge/.claude/settings.json +10 -0
- package/dist/configs/vitest/scratch-global-setup.d.ts +9 -3
- package/dist/configs/vitest/scratch-global-setup.d.ts.map +1 -1
- package/dist/configs/vitest/scratch-global-setup.js +23 -10
- package/dist/configs/vitest/scratch-global-setup.js.map +1 -1
- package/dist/configs/vitest/scratch-tmpdir-trust.d.ts +48 -0
- package/dist/configs/vitest/scratch-tmpdir-trust.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-tmpdir-trust.js +194 -0
- package/dist/configs/vitest/scratch-tmpdir-trust.js.map +1 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +6 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +13 -8
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +5 -5
- package/plugins/lisa/.claude-plugin/plugin.json +9 -1
- package/plugins/lisa/.codex-plugin/hooks.json +8 -0
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/worktree-binding-guard.mjs +68 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +9 -1
- package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +68 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/hooks.json +3 -0
- package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +68 -0
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/.claude-plugin/plugin.json +8 -0
- package/plugins/src/base/hooks/worktree-binding-guard.mjs +68 -0
- package/scripts/check-shell-guard-refusal-coverage.mjs +49 -3
- package/scripts/lib/shell-guard-trace.mjs +26 -8
- package/scripts/lisa-enforcement-fallback.sh +21 -2
- package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +244 -3
|
@@ -483,6 +483,25 @@ notice_marker=""
|
|
|
483
483
|
# non-sticky shared TMPDIR: another user could replace that parent between the
|
|
484
484
|
# checks below. Root- or caller-owned parents are acceptable; any parent that
|
|
485
485
|
# grants group or other write access must also carry the sticky bit.
|
|
486
|
+
#
|
|
487
|
+
# The two `stat` spellings must be asked for the SAME twelve bits, and getting
|
|
488
|
+
# that wrong is invisible because each platform only ever runs its own branch.
|
|
489
|
+
# BSD `%Lp` renders the low NINE bits and drops setuid/setgid/sticky entirely:
|
|
490
|
+
#
|
|
491
|
+
# stat -f '%Lp' <a 1777 dir> -> 777 <- sticky gone
|
|
492
|
+
# stat -f '%p' <a 1777 dir> -> 41777 <- sticky present, plus file type
|
|
493
|
+
# stat -c '%a' <a 1777 dir> -> 1777 <- sticky present (GNU includes it)
|
|
494
|
+
#
|
|
495
|
+
# So under `%Lp` the sticky test below is `777 & 1000`, which is zero for every
|
|
496
|
+
# directory on the machine — the exemption was unreachable on macOS and the
|
|
497
|
+
# whole `&& [ ... 8#1000 ] -eq 0` clause was dead code there. The same logical
|
|
498
|
+
# root was therefore trusted on Linux and rejected on macOS, and since CI is
|
|
499
|
+
# Linux the stricter platform was the one nobody specified and nobody tests on
|
|
500
|
+
# (CodySwannGT/lisa#3691).
|
|
501
|
+
#
|
|
502
|
+
# `%p` restores the bit and adds the file type above it, so the mask normalizes
|
|
503
|
+
# both spellings to one value and the arithmetic below has a single meaning:
|
|
504
|
+
# `41777 & 7777` and `1777 & 7777` are both 1777.
|
|
486
505
|
notice_directory_trusted() {
|
|
487
506
|
local directory="$1"
|
|
488
507
|
local directory_stat=""
|
|
@@ -490,7 +509,7 @@ notice_directory_trusted() {
|
|
|
490
509
|
local directory_mode=""
|
|
491
510
|
local directory_mode_value=0
|
|
492
511
|
|
|
493
|
-
directory_stat="$(stat -f '%u %
|
|
512
|
+
directory_stat="$(stat -f '%u %p' "$directory" 2>/dev/null)" || \
|
|
494
513
|
directory_stat="$(stat -c '%u %a' "$directory" 2>/dev/null)" || return 1
|
|
495
514
|
directory_owner="${directory_stat%% *}"
|
|
496
515
|
directory_mode="${directory_stat#* }"
|
|
@@ -498,7 +517,7 @@ notice_directory_trusted() {
|
|
|
498
517
|
*[!0-9:]* | :* | *: ) return 1 ;;
|
|
499
518
|
esac
|
|
500
519
|
[ "$directory_owner" = "0" ] || [ "$directory_owner" = "$notice_uid" ] || return 1
|
|
501
|
-
directory_mode_value=$((8#$directory_mode))
|
|
520
|
+
directory_mode_value=$((8#$directory_mode & 8#7777))
|
|
502
521
|
if [ $((directory_mode_value & 8#0022)) -ne 0 ] && \
|
|
503
522
|
[ $((directory_mode_value & 8#1000)) -eq 0 ]; then
|
|
504
523
|
return 1
|
|
@@ -550,6 +550,63 @@ function claimedRoot(toolInput, cwd) {
|
|
|
550
550
|
return null;
|
|
551
551
|
}
|
|
552
552
|
|
|
553
|
+
/**
|
|
554
|
+
* Record where the session STARTED, so its first guarded call is checked
|
|
555
|
+
* against a baseline rather than establishing one.
|
|
556
|
+
*
|
|
557
|
+
* ## Why the first call could not be checked before
|
|
558
|
+
*
|
|
559
|
+
* It established the baseline instead of testing one, which is
|
|
560
|
+
* trust-on-first-use — and TOFU is only as safe as its first use. Here the
|
|
561
|
+
* first use is assigned by the harness, unasked (CodySwannGT/lisa#3864), so the
|
|
562
|
+
* one moment the guard trusted was the moment the session had least control
|
|
563
|
+
* over. A session already sitting in a foreign worktree when it first acted
|
|
564
|
+
* bound to that tree and was never refused, and every later call was then
|
|
565
|
+
* checked faithfully against the wrong baseline — defending the session INTO
|
|
566
|
+
* the wrong worktree rather than out of it (CodySwannGT/lisa#3955).
|
|
567
|
+
*
|
|
568
|
+
* ## Why an earlier observation separates what a cleverer check cannot
|
|
569
|
+
*
|
|
570
|
+
* At the first guarded call, "I was displaced before I acted" and "I
|
|
571
|
+
* legitimately started here" present identically: one session id, one observed
|
|
572
|
+
* root, no prior state. No comparison can tell them apart, because the
|
|
573
|
+
* information is not in the hook's inputs at that instant.
|
|
574
|
+
*
|
|
575
|
+
* At session start it is. The displacement mechanism actually observed is a
|
|
576
|
+
* PEER's `EnterWorktree` moving this session (CodySwannGT/lisa#3712), which
|
|
577
|
+
* happens during the session — after it has started. A baseline taken at start
|
|
578
|
+
* is therefore recorded BEFORE the event that moves it, and the first guarded
|
|
579
|
+
* call becomes an ordinary comparison against a baseline that already exists.
|
|
580
|
+
* It reaches the same refusal a later displacement produces, because by then it
|
|
581
|
+
* is one.
|
|
582
|
+
*
|
|
583
|
+
* ## What this does NOT achieve
|
|
584
|
+
*
|
|
585
|
+
* #3955 asks for a baseline from the ASSIGNER rather than from observation.
|
|
586
|
+
* That is not what this is and Lisa cannot build it: Lisa does not own
|
|
587
|
+
* `EnterWorktree`, and nothing the harness writes names a session's assigned
|
|
588
|
+
* worktree in a form a hook can read. This is still an observation, just an
|
|
589
|
+
* earlier one. It closes the window between session start and the first guarded
|
|
590
|
+
* call; it leaves open a session LAUNCHED already displaced, where start
|
|
591
|
+
* observes the foreign tree and trust-on-first-use still applies.
|
|
592
|
+
*
|
|
593
|
+
* Returns nothing on purpose, like its sibling below: SessionStart has no call
|
|
594
|
+
* to refuse, so every path through it allows.
|
|
595
|
+
* @param sessionId - The session this baseline belongs to
|
|
596
|
+
* @param observed - The worktree root the session started in
|
|
597
|
+
*/
|
|
598
|
+
function recordBaseline(sessionId, observed) {
|
|
599
|
+
// Never overwrite. A resumed session, a reconnect, or anything else that
|
|
600
|
+
// fires the event twice must not be able to launder a displaced binding into
|
|
601
|
+
// a fresh baseline — which is the whole failure this exists to close.
|
|
602
|
+
if (readState(sessionId)?.boundRoot) return;
|
|
603
|
+
writeState(sessionId, {
|
|
604
|
+
boundRoot: observed,
|
|
605
|
+
claimedRoot: null,
|
|
606
|
+
updatedAt: new Date().toISOString(),
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
553
610
|
/**
|
|
554
611
|
* Record what `EnterWorktree` just claimed, for the next tool call to check.
|
|
555
612
|
*
|
|
@@ -651,6 +708,10 @@ function evaluate(payload) {
|
|
|
651
708
|
const observed = worktreeRoot(cwd);
|
|
652
709
|
if (!observed) return 0;
|
|
653
710
|
|
|
711
|
+
if (payload.hook_event_name === "SessionStart") {
|
|
712
|
+
recordBaseline(sessionId, observed);
|
|
713
|
+
return 0;
|
|
714
|
+
}
|
|
654
715
|
if (payload.tool_name === "EnterWorktree") {
|
|
655
716
|
recordClaim(payload, observed);
|
|
656
717
|
return 0;
|
|
@@ -662,6 +723,13 @@ function evaluate(payload) {
|
|
|
662
723
|
|
|
663
724
|
const state = readState(sessionId);
|
|
664
725
|
if (!state?.boundRoot) {
|
|
726
|
+
// No baseline means SessionStart did not run for this session — an older
|
|
727
|
+
// install, a runtime that fires no such event, a harness that skips it.
|
|
728
|
+
// Absence of a baseline is absence of evidence, not evidence of
|
|
729
|
+
// displacement, so this records one exactly as it always did rather than
|
|
730
|
+
// refusing. Treating it as a refusal would turn a floor into a wall on
|
|
731
|
+
// every surface where the event does not fire, and a wall gets switched
|
|
732
|
+
// off, which costs the whole guard.
|
|
665
733
|
writeState(sessionId, {
|
|
666
734
|
boundRoot: observed,
|
|
667
735
|
claimedRoot: null,
|
|
@@ -224,13 +224,19 @@ export declare const armRefusalSummary: (failure: string, write?: (text: string)
|
|
|
224
224
|
*/
|
|
225
225
|
export declare const announceRefusal: (failure: string, writeNotice?: (text: string) => void) => void;
|
|
226
226
|
/**
|
|
227
|
-
*
|
|
228
|
-
* that is accumulating.
|
|
227
|
+
* Refuses to start into an untrusted temp root or an accumulating namespace.
|
|
229
228
|
*
|
|
230
229
|
* A refusal speaks twice — a banner before collection and a summary line at
|
|
231
230
|
* exit — and the two are not redundant. They are the top and the bottom of a
|
|
232
231
|
* transcript nobody reads in full.
|
|
233
|
-
*
|
|
232
|
+
*
|
|
233
|
+
* The TMPDIR trust check runs FIRST, and the order is load-bearing rather than
|
|
234
|
+
* arbitrary. An untrusted root is the more fundamental fault: it is a property
|
|
235
|
+
* of the environment the run was launched in, it is what every rung of the
|
|
236
|
+
* namespace audit is then inspected THROUGH, and it is the one whose absence
|
|
237
|
+
* of a message cost four separate investigations (CodySwannGT/lisa#3691).
|
|
238
|
+
* Reporting a namespace symptom first would name the second-order fact.
|
|
239
|
+
* @throws {Error} When the temp root is untrusted, or residue the sweep cannot or did not reclaim is present.
|
|
234
240
|
*/
|
|
235
241
|
export declare const setup: () => void;
|
|
236
242
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scratch-global-setup.d.ts","sourceRoot":"","sources":["../../../src/configs/vitest/scratch-global-setup.ts"],"names":[],"mappings":"AAmDA,OAAO,EAGL,+BAA+B,EAGhC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"scratch-global-setup.d.ts","sourceRoot":"","sources":["../../../src/configs/vitest/scratch-global-setup.ts"],"names":[],"mappings":"AAmDA,OAAO,EAGL,+BAA+B,EAGhC,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB;AAC5B,kDAAkD;AAChD,eAAe;AACjB,0EAA0E;GACxE,mBAAmB;AACrB,kEAAkE;GAChE,mBAAmB;AACrB,mDAAmD;GACjD,iBAAiB,CAAC;AAEtB,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,+DAA+D;IAC/D,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,gEAAgE;IAChE,QAAQ,CAAC,kBAAkB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC1D,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AA+ED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAK,MAA8B,EACnC,QAAO,CAAC,GAAG,EAAE,MAAM,KAAK,OAAwB,EAChD,QAAO,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,SAAmC,KACnE,gBAoBF,CAAC;AAwEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GACjC,KAAK,MAAM,EACX,SAAS,gBAAgB,KACxB,MAAM,GAAG,SAuCX,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAO,CAAC,GAAG,EAAE,MAAM,KAAK,OAAwB,EAChD,WAAU,OAAO,+BAAiE,KACjF,gBAQF,CAAC;AAgBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,MAcxC,CAAC;AAKf;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,MAG/B,CAAC;AAEzB;;;;;GAKG;AACH,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAQhD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,EACf,QAAO,CAAC,IAAI,EAAE,MAAM,KAAK,IAExB,KACA,IAIF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EACf,cAAa,CAAC,IAAI,EAAE,MAAM,KAAK,IAE9B,KACA,IAMF,CAAC;AAgBF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK,QAAO,IASxB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,QAAO,IAE3B,CAAC"}
|
|
@@ -42,6 +42,7 @@ import * as path from "node:path";
|
|
|
42
42
|
import { env } from "node:process";
|
|
43
43
|
import { isProcessAlive, liveOwnerBirthProbe, readNamespaceEntries, scratchNamespaceDir, sweepScratchNamespace, } from "./scratch.js";
|
|
44
44
|
import { classifyScratchOwner, processBirthFingerprint, processBirthFingerprintSnapshot, readScratchOwnerRecord, } from "./scratch-owner.js";
|
|
45
|
+
import { describeTmpdirTrustFailure } from "./scratch-tmpdir-trust.js";
|
|
45
46
|
/**
|
|
46
47
|
* Upper bound on entries the namespace may hold that **nobody owns**.
|
|
47
48
|
*
|
|
@@ -448,22 +449,34 @@ export const announceRefusal = (failure, writeNotice = text => {
|
|
|
448
449
|
armRefusalSummary(failure);
|
|
449
450
|
};
|
|
450
451
|
/**
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
* A refusal speaks twice — a banner before collection and a summary line at
|
|
455
|
-
* exit — and the two are not redundant. They are the top and the bottom of a
|
|
456
|
-
* transcript nobody reads in full.
|
|
457
|
-
* @throws {Error} When residue is present that the sweep cannot or did not reclaim.
|
|
452
|
+
* Why the namespace must be refused, or `undefined` when it is usable.
|
|
453
|
+
* @returns Refusal text, or undefined
|
|
458
454
|
*/
|
|
459
|
-
|
|
455
|
+
const describeNamespaceFailure = () => {
|
|
460
456
|
// The namespace directory is not created here. `createRunRoot` makes it
|
|
461
457
|
// recursively in whichever worker allocates first, and both the sweep and the
|
|
462
458
|
// inspection treat an absent namespace as an empty one — so creating it would
|
|
463
459
|
// be a side effect ahead of the audit that buys nothing.
|
|
464
460
|
const dir = scratchNamespaceDir();
|
|
465
|
-
|
|
466
|
-
|
|
461
|
+
return describeResidueFailure(dir, auditNamespace());
|
|
462
|
+
};
|
|
463
|
+
/**
|
|
464
|
+
* Refuses to start into an untrusted temp root or an accumulating namespace.
|
|
465
|
+
*
|
|
466
|
+
* A refusal speaks twice — a banner before collection and a summary line at
|
|
467
|
+
* exit — and the two are not redundant. They are the top and the bottom of a
|
|
468
|
+
* transcript nobody reads in full.
|
|
469
|
+
*
|
|
470
|
+
* The TMPDIR trust check runs FIRST, and the order is load-bearing rather than
|
|
471
|
+
* arbitrary. An untrusted root is the more fundamental fault: it is a property
|
|
472
|
+
* of the environment the run was launched in, it is what every rung of the
|
|
473
|
+
* namespace audit is then inspected THROUGH, and it is the one whose absence
|
|
474
|
+
* of a message cost four separate investigations (CodySwannGT/lisa#3691).
|
|
475
|
+
* Reporting a namespace symptom first would name the second-order fact.
|
|
476
|
+
* @throws {Error} When the temp root is untrusted, or residue the sweep cannot or did not reclaim is present.
|
|
477
|
+
*/
|
|
478
|
+
export const setup = () => {
|
|
479
|
+
const failure = describeTmpdirTrustFailure() ?? describeNamespaceFailure();
|
|
467
480
|
if (failure !== undefined) {
|
|
468
481
|
// Both halves of the announcement happen before the throw, because the
|
|
469
482
|
// throw is what ends this function.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scratch-global-setup.js","sourceRoot":"","sources":["../../../src/configs/vitest/scratch-global-setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,+BAA+B,EAC/B,sBAAsB,GAEvB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"scratch-global-setup.js","sourceRoot":"","sources":["../../../src/configs/vitest/scratch-global-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** The rung of the chain that failed the trust test, and why it failed. */
|
|
2
|
+
export interface UntrustedAncestor {
|
|
3
|
+
/** Absolute path of the rejected directory. */
|
|
4
|
+
readonly directory: string;
|
|
5
|
+
/** Owning uid, as reported by `stat`. */
|
|
6
|
+
readonly uid: number;
|
|
7
|
+
/** Permission, setuid/setgid and sticky bits. */
|
|
8
|
+
readonly mode: number;
|
|
9
|
+
/** Operator-readable statement of which property failed. */
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Render a mode the way `ls` and `chmod` spell it, so it can be compared.
|
|
14
|
+
* @param mode - Permission bits
|
|
15
|
+
* @returns Four-digit octal string
|
|
16
|
+
*/
|
|
17
|
+
export declare const octalMode: (mode: number) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Every ancestor of an absolute path, root first and the path itself last.
|
|
20
|
+
* @param target - Absolute, symlink-resolved path
|
|
21
|
+
* @returns The chain to walk, in the order the shell walks it
|
|
22
|
+
*/
|
|
23
|
+
export declare const ancestorChain: (target: string) => readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* The first untrusted ancestor of a path, if any.
|
|
26
|
+
*
|
|
27
|
+
* Platforms without uid ownership have nothing to check and are never refused.
|
|
28
|
+
* @param target - Absolute, symlink-resolved path to walk
|
|
29
|
+
* @returns The first failing rung, or undefined
|
|
30
|
+
*/
|
|
31
|
+
export declare const findUntrustedAncestor: (target: string) => UntrustedAncestor | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* The refusal text: what was rejected, which rung rejected it, and the fix.
|
|
34
|
+
* @param resolved - The symlink-resolved TMPDIR that was walked
|
|
35
|
+
* @param ancestor - The rung that failed
|
|
36
|
+
* @returns Operator-readable failure text
|
|
37
|
+
*/
|
|
38
|
+
export declare const describeUntrustedTmpdir: (resolved: string, ancestor: UntrustedAncestor) => string;
|
|
39
|
+
/**
|
|
40
|
+
* Why this run's TMPDIR must be refused, or `undefined` when it is trusted.
|
|
41
|
+
*
|
|
42
|
+
* Read through `realpathSync` because the shell resolves with `cd -P` before it
|
|
43
|
+
* walks: the chain that matters is the physical one, and a symlinked TMPDIR
|
|
44
|
+
* whose logical spelling looks fine can resolve onto a rung that is not.
|
|
45
|
+
* @returns Refusal text, or undefined when the chain is trusted
|
|
46
|
+
*/
|
|
47
|
+
export declare const describeTmpdirTrustFailure: () => string | undefined;
|
|
48
|
+
//# sourceMappingURL=scratch-tmpdir-trust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratch-tmpdir-trust.d.ts","sourceRoot":"","sources":["../../../src/configs/vitest/scratch-tmpdir-trust.ts"],"names":[],"mappings":"AA0DA,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MACN,CAAC;AAEpC;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,KAAG,SAAS,MAAM,EAUzD,CAAC;AAuEN;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,MAAM,KACb,iBAAiB,GAAG,SAItB,CAAC;AAqBF;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,MAAM,EAChB,UAAU,iBAAiB,KAC1B,MAuBW,CAAC;AAEf;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,QAAO,MAAM,GAAG,SAOtD,CAAC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vitest Configuration - TMPDIR ancestor-chain trust (refusal)
|
|
3
|
+
*
|
|
4
|
+
* A test run under a `TMPDIR` whose ancestor chain is untrusted produces four
|
|
5
|
+
* failing assertions about enforcement rate-limiting and says nothing about the
|
|
6
|
+
* environment that caused them. Nobody's first hypothesis is "my temp
|
|
7
|
+
* directory's ancestor has the wrong mode bits", so the failure reads as a
|
|
8
|
+
* defect in the rate limiter — measured at four separate investigations, two of
|
|
9
|
+
* which escalated claiming `main` was red (CodySwannGT/lisa#3691).
|
|
10
|
+
*
|
|
11
|
+
* The mechanism is `scripts/lisa-enforcement-fallback.sh`, which walks every
|
|
12
|
+
* ancestor of the resolved `TMPDIR` before it writes its once-per-session
|
|
13
|
+
* marker. When a rung fails the walk the marker is never created, the rate
|
|
14
|
+
* limit stands down, and the notice speaks on every call. THAT STAND-DOWN IS
|
|
15
|
+
* CORRECT — the guard is designed to fail open rather than write into an
|
|
16
|
+
* untrusted state directory, and it should keep doing that. What was missing is
|
|
17
|
+
* anything telling the operator why, which is what this module supplies.
|
|
18
|
+
*
|
|
19
|
+
* The verdict is deliberately a REFUSAL rather than a warning, and it is wired
|
|
20
|
+
* into `globalSetup` rather than `setupFiles` for a measured reason: a throw
|
|
21
|
+
* from a `setupFiles` module fails collection, so the suite reports zero tests
|
|
22
|
+
* and the gate goes red having evaluated nothing — a result that looks like a
|
|
23
|
+
* verdict and is not one. Installing that failure to fix a failure that names
|
|
24
|
+
* nothing would reproduce the defect one level up. `scratch-global-setup`
|
|
25
|
+
* already refuses from `setup`, where vitest honours the throw and exits 1.
|
|
26
|
+
*
|
|
27
|
+
* The predicate below is a second expression of the shell's arithmetic, which
|
|
28
|
+
* is a real risk: two copies can drift, and the copy that decides behaviour is
|
|
29
|
+
* the shell's. That risk is priced by a case in
|
|
30
|
+
* `tests/unit/config/scratch-tmpdir-trust.test.ts` asserting the two agree on a
|
|
31
|
+
* table of representative roots, real directories rather than fabricated modes.
|
|
32
|
+
* Sharing the shell predicate directly was rejected: that script is the
|
|
33
|
+
* PreToolUse dispatcher that runs on EVERY tool call and consumes stdin, so a
|
|
34
|
+
* probe mode would put a test-serving branch on the hottest path in the repo.
|
|
35
|
+
* @see {@link module:configs/vitest/scratch-global-setup} for the refusal path
|
|
36
|
+
* @module configs/vitest/scratch-tmpdir-trust
|
|
37
|
+
*/
|
|
38
|
+
import { realpathSync, statSync } from "node:fs";
|
|
39
|
+
import { tmpdir } from "node:os";
|
|
40
|
+
import * as path from "node:path";
|
|
41
|
+
import { getuid, platform } from "node:process";
|
|
42
|
+
/** Permission, setuid/setgid and sticky bits of `st_mode`. */
|
|
43
|
+
const PERMISSION_BITS = 0o7777;
|
|
44
|
+
/** Write access granted to group or to other. */
|
|
45
|
+
const SHARED_WRITE_BITS = 0o022;
|
|
46
|
+
/**
|
|
47
|
+
* The sticky bit.
|
|
48
|
+
*
|
|
49
|
+
* It is what makes a shared, world-writable temp root safe to hold per-user
|
|
50
|
+
* state: another uid can still CREATE a name there, but cannot unlink or rename
|
|
51
|
+
* one that is not theirs. That is the whole basis on which `/tmp` is trusted.
|
|
52
|
+
*/
|
|
53
|
+
const STICKY_BIT = 0o1000;
|
|
54
|
+
/**
|
|
55
|
+
* Render a mode the way `ls` and `chmod` spell it, so it can be compared.
|
|
56
|
+
* @param mode - Permission bits
|
|
57
|
+
* @returns Four-digit octal string
|
|
58
|
+
*/
|
|
59
|
+
export const octalMode = (mode) => mode.toString(8).padStart(4, "0");
|
|
60
|
+
/**
|
|
61
|
+
* Every ancestor of an absolute path, root first and the path itself last.
|
|
62
|
+
* @param target - Absolute, symlink-resolved path
|
|
63
|
+
* @returns The chain to walk, in the order the shell walks it
|
|
64
|
+
*/
|
|
65
|
+
export const ancestorChain = (target) => target
|
|
66
|
+
.split(path.sep)
|
|
67
|
+
.filter(segment => segment !== "")
|
|
68
|
+
.reduce((chain, segment) => [
|
|
69
|
+
...chain,
|
|
70
|
+
path.join(chain[chain.length - 1] ?? path.sep, segment),
|
|
71
|
+
], [path.sep]);
|
|
72
|
+
/**
|
|
73
|
+
* Why one directory is untrusted, or `undefined` when it is trusted.
|
|
74
|
+
*
|
|
75
|
+
* Ownership is checked as "root or me" rather than "mine". A valid chain is
|
|
76
|
+
* MOSTLY root-owned — on macOS four of the six rungs above the per-user temp
|
|
77
|
+
* root are uid 0 — so a check written as "is this mine?" would reject every
|
|
78
|
+
* valid root on the machine. The discriminating property is the MODE.
|
|
79
|
+
* @param uid - Owning uid of the directory
|
|
80
|
+
* @param mode - Its permission, setuid/setgid and sticky bits
|
|
81
|
+
* @param self - The current uid
|
|
82
|
+
* @returns The failing property, or undefined
|
|
83
|
+
*/
|
|
84
|
+
const untrustReason = (uid, mode, self) => {
|
|
85
|
+
if (uid !== 0 && uid !== self) {
|
|
86
|
+
return (`owned by uid ${String(uid)}, which is neither root nor you ` +
|
|
87
|
+
`(uid ${String(self)}), so its owner can replace it underneath you`);
|
|
88
|
+
}
|
|
89
|
+
if ((mode & SHARED_WRITE_BITS) !== 0 && (mode & STICKY_BIT) === 0) {
|
|
90
|
+
return (`mode ${octalMode(mode)} grants write access to group or other ` +
|
|
91
|
+
`WITHOUT the sticky bit, so any user can replace entries in it`);
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* The first rung of a chain that fails the trust test.
|
|
97
|
+
*
|
|
98
|
+
* A rung that cannot be inspected at all counts as untrusted, matching the
|
|
99
|
+
* shell, whose `stat` failure returns the same verdict as a bad mode.
|
|
100
|
+
* @param target - Absolute, symlink-resolved path to walk
|
|
101
|
+
* @param self - The current uid
|
|
102
|
+
* @returns The first failing rung, or undefined when every rung passes
|
|
103
|
+
*/
|
|
104
|
+
const firstUntrustedRung = (target, self) => ancestorChain(target).reduce((found, directory) => {
|
|
105
|
+
if (found !== undefined)
|
|
106
|
+
return found;
|
|
107
|
+
try {
|
|
108
|
+
const stat = statSync(directory);
|
|
109
|
+
const mode = stat.mode & PERMISSION_BITS;
|
|
110
|
+
const reason = untrustReason(stat.uid, mode, self);
|
|
111
|
+
return reason === undefined
|
|
112
|
+
? undefined
|
|
113
|
+
: { directory, uid: stat.uid, mode, reason };
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
return {
|
|
117
|
+
directory,
|
|
118
|
+
uid: -1,
|
|
119
|
+
mode: 0,
|
|
120
|
+
reason: `could not be inspected: ${error instanceof Error ? error.message : String(error)}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}, undefined);
|
|
124
|
+
/**
|
|
125
|
+
* The first untrusted ancestor of a path, if any.
|
|
126
|
+
*
|
|
127
|
+
* Platforms without uid ownership have nothing to check and are never refused.
|
|
128
|
+
* @param target - Absolute, symlink-resolved path to walk
|
|
129
|
+
* @returns The first failing rung, or undefined
|
|
130
|
+
*/
|
|
131
|
+
export const findUntrustedAncestor = (target) => {
|
|
132
|
+
const self = getuid?.();
|
|
133
|
+
return self === undefined ? undefined : firstUntrustedRung(target, self);
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* The remedy lines, spelled for the platform the operator is actually on.
|
|
137
|
+
*
|
|
138
|
+
* A remedy that cannot be followed is worse than none: it reads as the guard
|
|
139
|
+
* being wrong rather than the environment being wrong, and the available move
|
|
140
|
+
* then is to route around the guard.
|
|
141
|
+
* @returns Shell lines that produce a trusted TMPDIR
|
|
142
|
+
*/
|
|
143
|
+
const remedyLines = () => platform === "darwin"
|
|
144
|
+
? [
|
|
145
|
+
' root="$(getconf DARWIN_USER_TEMP_DIR)"',
|
|
146
|
+
' mkdir -p "${root}lisa" && export TMPDIR="${root}lisa"',
|
|
147
|
+
]
|
|
148
|
+
: [
|
|
149
|
+
' root="${XDG_RUNTIME_DIR:-/tmp}/lisa-$(id -u)"',
|
|
150
|
+
' mkdir -p "$root" && export TMPDIR="$root"',
|
|
151
|
+
];
|
|
152
|
+
/**
|
|
153
|
+
* The refusal text: what was rejected, which rung rejected it, and the fix.
|
|
154
|
+
* @param resolved - The symlink-resolved TMPDIR that was walked
|
|
155
|
+
* @param ancestor - The rung that failed
|
|
156
|
+
* @returns Operator-readable failure text
|
|
157
|
+
*/
|
|
158
|
+
export const describeUntrustedTmpdir = (resolved, ancestor) => [
|
|
159
|
+
"Lisa test scratch requires a TMPDIR whose ancestor chain is trusted.",
|
|
160
|
+
"",
|
|
161
|
+
` TMPDIR resolves to ${resolved}`,
|
|
162
|
+
` rejected at ${ancestor.directory}`,
|
|
163
|
+
` uid ${String(ancestor.uid)}, mode ${octalMode(ancestor.mode)}`,
|
|
164
|
+
` ${ancestor.reason}`,
|
|
165
|
+
"",
|
|
166
|
+
"A directory is trusted when it is owned by root or by you AND is not",
|
|
167
|
+
"group- or world-writable unless it carries the sticky bit.",
|
|
168
|
+
"",
|
|
169
|
+
"This is the same chain scripts/lisa-enforcement-fallback.sh walks before",
|
|
170
|
+
"it writes per-session state. A TMPDIR refused here would silently stand",
|
|
171
|
+
"that rate limit down instead, which surfaces as four assertion failures",
|
|
172
|
+
"in tests/unit/hooks/enforcement-fallback-notice-rate.test.ts that read as",
|
|
173
|
+
"defects in the rate limiter and say nothing about your environment. That",
|
|
174
|
+
"is the failure this refusal replaces (CodySwannGT/lisa#3691).",
|
|
175
|
+
"",
|
|
176
|
+
"Point TMPDIR at a directory of your own instead:",
|
|
177
|
+
...remedyLines(),
|
|
178
|
+
].join("\n");
|
|
179
|
+
/**
|
|
180
|
+
* Why this run's TMPDIR must be refused, or `undefined` when it is trusted.
|
|
181
|
+
*
|
|
182
|
+
* Read through `realpathSync` because the shell resolves with `cd -P` before it
|
|
183
|
+
* walks: the chain that matters is the physical one, and a symlinked TMPDIR
|
|
184
|
+
* whose logical spelling looks fine can resolve onto a rung that is not.
|
|
185
|
+
* @returns Refusal text, or undefined when the chain is trusted
|
|
186
|
+
*/
|
|
187
|
+
export const describeTmpdirTrustFailure = () => {
|
|
188
|
+
const resolved = realpathSync(tmpdir());
|
|
189
|
+
const ancestor = findUntrustedAncestor(resolved);
|
|
190
|
+
return ancestor === undefined
|
|
191
|
+
? undefined
|
|
192
|
+
: describeUntrustedTmpdir(resolved, ancestor);
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=scratch-tmpdir-trust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratch-tmpdir-trust.js","sourceRoot":"","sources":["../../../src/configs/vitest/scratch-tmpdir-trust.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AACA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAwlCjC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CACpD,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA2/BjC,CAAC"}
|
|
@@ -449,6 +449,7 @@ export const LISA_OWNED_HASH_LEDGER = Object.freeze({
|
|
|
449
449
|
"7caa48fcba51e1e4bf21b909e51474be3b929907ffc35896b6de13aac6cb6782",
|
|
450
450
|
"7d333dc10be8c810b9b5aca35ab7f6f60413134414d82bf0cdaedb4e6e3ca8da",
|
|
451
451
|
"8dc942ac4edc2017d6b8277296c8f80542e7c024eef1bb65de609979d0ca9a0e",
|
|
452
|
+
"916b2b48a2b55c2090468c48c972b6c7c5fad39fb53956ceffebdd1ff0c69230",
|
|
452
453
|
"9cab71562d01421d57c6719318a4d03a6249a45c1aea434db3ff26e3065eeb66",
|
|
453
454
|
"9cfad1d691235fa70ccf97603eea2ef177bbded4a34d85aeedc41018c894b591",
|
|
454
455
|
"aafd027c4b6092da15d0389f9e8dcedbd9105e9083057e2da39f78fd5f72e0df",
|
|
@@ -802,6 +803,7 @@ export const LISA_OWNED_HASH_LEDGER = Object.freeze({
|
|
|
802
803
|
"6b0c13bf89dd62577baebb7e6e8ff7a0bbcb1e83b32c5a1b878a64c76d83d822",
|
|
803
804
|
"822e4f9d2c3ad8fb184ff7fc880f6811004852fb731c7878b5a8a1a9532bceb8",
|
|
804
805
|
"bc1118b05eaea3fc7b3409c96979d64e3dee0907118f3e84d735163f473f632a",
|
|
806
|
+
"cccc2f5ba33bc3abe03b850d3dd747c27553f985b9213d1b1a35297312fa1586",
|
|
805
807
|
"e121219bbee1960a6bf88d1e2ba0b50587d63013e7872c56619c04182e8a7561",
|
|
806
808
|
"efbf0d770c5547e9b7465eac4650c4ff01d427dee86fdb623a463a32023bcabf",
|
|
807
809
|
]),
|
|
@@ -813,6 +815,7 @@ export const LISA_OWNED_HASH_LEDGER = Object.freeze({
|
|
|
813
815
|
]),
|
|
814
816
|
"scripts/lisa-mutation.mjs": Object.freeze([
|
|
815
817
|
"03dda43b5813b5b6a083c1e0302ce3e9fec13818864ed38dce180cbdaa4e2de2",
|
|
818
|
+
"08855e056f353392e8072e8f868335f7fe4bde4f83a5affed4765ff53eea1129",
|
|
816
819
|
"0cd013a51a81d8eeebced9f2646bdb3fe0a9247fcd74b57c03e95cc2db3fe7de",
|
|
817
820
|
"0f5d9027e95d47745827adcd979e3c2355271066b6b84d661215dc6e895b3ac2",
|
|
818
821
|
"0fe73e162ece6c4a8270b0d5d675d6927a62962e0ae9275239c6acfacd0ef6c8",
|
|
@@ -1551,6 +1554,7 @@ export const LISA_OWNED_HASH_HISTORY_DERIVED = Object.freeze({
|
|
|
1551
1554
|
"7caa48fcba51e1e4bf21b909e51474be3b929907ffc35896b6de13aac6cb6782",
|
|
1552
1555
|
"7d333dc10be8c810b9b5aca35ab7f6f60413134414d82bf0cdaedb4e6e3ca8da",
|
|
1553
1556
|
"8dc942ac4edc2017d6b8277296c8f80542e7c024eef1bb65de609979d0ca9a0e",
|
|
1557
|
+
"916b2b48a2b55c2090468c48c972b6c7c5fad39fb53956ceffebdd1ff0c69230",
|
|
1554
1558
|
"9cab71562d01421d57c6719318a4d03a6249a45c1aea434db3ff26e3065eeb66",
|
|
1555
1559
|
"9cfad1d691235fa70ccf97603eea2ef177bbded4a34d85aeedc41018c894b591",
|
|
1556
1560
|
"aafd027c4b6092da15d0389f9e8dcedbd9105e9083057e2da39f78fd5f72e0df",
|
|
@@ -1858,6 +1862,7 @@ export const LISA_OWNED_HASH_HISTORY_DERIVED = Object.freeze({
|
|
|
1858
1862
|
"6b0c13bf89dd62577baebb7e6e8ff7a0bbcb1e83b32c5a1b878a64c76d83d822",
|
|
1859
1863
|
"822e4f9d2c3ad8fb184ff7fc880f6811004852fb731c7878b5a8a1a9532bceb8",
|
|
1860
1864
|
"bc1118b05eaea3fc7b3409c96979d64e3dee0907118f3e84d735163f473f632a",
|
|
1865
|
+
"cccc2f5ba33bc3abe03b850d3dd747c27553f985b9213d1b1a35297312fa1586",
|
|
1861
1866
|
"e121219bbee1960a6bf88d1e2ba0b50587d63013e7872c56619c04182e8a7561",
|
|
1862
1867
|
"efbf0d770c5547e9b7465eac4650c4ff01d427dee86fdb623a463a32023bcabf",
|
|
1863
1868
|
]),
|
|
@@ -1868,6 +1873,7 @@ export const LISA_OWNED_HASH_HISTORY_DERIVED = Object.freeze({
|
|
|
1868
1873
|
"ce4bc224a102e3ac2bc29d8f2038eefd619129d4639c25954c93f05011f7f977",
|
|
1869
1874
|
]),
|
|
1870
1875
|
"scripts/lisa-mutation.mjs": Object.freeze([
|
|
1876
|
+
"08855e056f353392e8072e8f868335f7fe4bde4f83a5affed4765ff53eea1129",
|
|
1871
1877
|
"0cd013a51a81d8eeebced9f2646bdb3fe0a9247fcd74b57c03e95cc2db3fe7de",
|
|
1872
1878
|
"0f5d9027e95d47745827adcd979e3c2355271066b6b84d661215dc6e895b3ac2",
|
|
1873
1879
|
"0fe73e162ece6c4a8270b0d5d675d6927a62962e0ae9275239c6acfacd0ef6c8",
|