@codyswann/lisa 4.45.7 → 4.45.9
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/copy-overwrite/scripts/lisa-work-item.mjs +56 -13
- 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 +14 -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 +14 -9
- 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,
|
|
@@ -3173,24 +3173,67 @@ function currentRepository() {
|
|
|
3173
3173
|
return safeJson(result.stdout, "GitHub repository").nameWithOwner;
|
|
3174
3174
|
}
|
|
3175
3175
|
|
|
3176
|
-
|
|
3176
|
+
/**
|
|
3177
|
+
* The pull request a check is about, by number or by the branch in hand.
|
|
3178
|
+
*
|
|
3179
|
+
* `gh pr view` will not infer the current branch once `--repo` is given — it
|
|
3180
|
+
* exits non-zero with "argument required when using the --repo flag" — and
|
|
3181
|
+
* `currentRepository()` resolves in every normal checkout, so `--repo` was
|
|
3182
|
+
* always present. The push path passes no number, so every push made an
|
|
3183
|
+
* invalid call, `allowFailure` turned the usage error into `undefined`, and
|
|
3184
|
+
* the caller concluded no pull request existed.
|
|
3185
|
+
*
|
|
3186
|
+
* That is why gates 4 and 5 were never checked at push time. Not deferred
|
|
3187
|
+
* until a pull request existed — never looked up at all, so the deferral
|
|
3188
|
+
* notice was emitted unconditionally: true by accident before a pull request
|
|
3189
|
+
* existed, false afterwards, and determined in neither case (#3791). The CI
|
|
3190
|
+
* path passed `--pr-number` and so called `gh` correctly, which is why CI
|
|
3191
|
+
* caught what every push had waved through.
|
|
3192
|
+
*
|
|
3193
|
+
* Naming the selector positionally is what makes the lookup resolve while
|
|
3194
|
+
* keeping `--repo` explicit. With no number and no branch — a detached HEAD —
|
|
3195
|
+
* there is genuinely nothing to resolve by, so `--repo` is withheld rather
|
|
3196
|
+
* than sent without the argument it requires.
|
|
3197
|
+
* @param {string|number} [number] Explicit pull-request number, when known.
|
|
3198
|
+
* @param {string} [repository] `owner/name` the pull request belongs to.
|
|
3199
|
+
* @returns {object|undefined} The pull request, or undefined when none resolves.
|
|
3200
|
+
*/
|
|
3201
|
+
/**
|
|
3202
|
+
* The argv for one `gh pr view`, with the selector it cannot do without.
|
|
3203
|
+
*
|
|
3204
|
+
* Extracted and exported because every other test of this file drives the CLI
|
|
3205
|
+
* as a SUBPROCESS, so nothing in-process ever covers argv construction — the
|
|
3206
|
+
* mutation gate reported seven surviving mutants here and no assertion reachable
|
|
3207
|
+
* from a spawned process could have killed one. Argument shape is exactly what
|
|
3208
|
+
* was wrong in #3791, so it is the part that has to be directly testable.
|
|
3209
|
+
* @param {string|number} [number] Explicit pull-request number, when known.
|
|
3210
|
+
* @param {string} [branch] Branch to resolve by when no number is given.
|
|
3211
|
+
* @param {string} [repository] `owner/name` the pull request belongs to.
|
|
3212
|
+
* @param {string} [fields] Comma-separated `gh pr view --json` fields.
|
|
3213
|
+
* @returns {string[]} Arguments for `gh`.
|
|
3214
|
+
*/
|
|
3215
|
+
export function pullRequestViewArgs(
|
|
3177
3216
|
number,
|
|
3178
|
-
|
|
3217
|
+
branch,
|
|
3218
|
+
repository,
|
|
3179
3219
|
fields = "url,body,state"
|
|
3180
3220
|
) {
|
|
3221
|
+
const selector = number ?? branch;
|
|
3181
3222
|
const args = ["pr", "view"];
|
|
3182
|
-
if (
|
|
3183
|
-
// `--repo`
|
|
3184
|
-
//
|
|
3185
|
-
|
|
3186
|
-
// function reads that as "no pull request exists", and the push then takes
|
|
3187
|
-
// the deferral branch on every branch that HAS one. Measured on this
|
|
3188
|
-
// repository: an open pull request, and the push reporting gates 4 and 5 as
|
|
3189
|
-
// unchecked because the flag combination could never have found it. Without
|
|
3190
|
-
// a number `gh` resolves the pull request from the current branch's remote,
|
|
3191
|
-
// which is the answer this caller wants and the only one it can get.
|
|
3192
|
-
if (number && repository) args.push("--repo", repository);
|
|
3223
|
+
if (selector) args.push(String(selector));
|
|
3224
|
+
// `--repo` is withheld without a selector rather than sent alone: `gh` treats
|
|
3225
|
+
// that as a usage error, not as "look it up from the branch".
|
|
3226
|
+
if (repository && selector) args.push("--repo", repository);
|
|
3193
3227
|
args.push("--json", fields);
|
|
3228
|
+
return args;
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
function currentPullRequest(
|
|
3232
|
+
number,
|
|
3233
|
+
repository = currentRepository(),
|
|
3234
|
+
fields = "url,body,state"
|
|
3235
|
+
) {
|
|
3236
|
+
const args = pullRequestViewArgs(number, activeBranch(), repository, fields);
|
|
3194
3237
|
const result = run("gh", args, { allowFailure: true });
|
|
3195
3238
|
return result.status === 0
|
|
3196
3239
|
? safeJson(result.stdout, "GitHub pull request")
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEhD,8DAA8D;AAC9D,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,iDAAiD;AACjD,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC;;;;;;GAMG;AACH,MAAM,UAAU,GAAG,MAAM,CAAC;AAc1B;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAU,EAAE,CAChD,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAEpC;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAc,EAAqB,EAAE,CACjE,MAAM;KACH,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;KACf,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC;KACjC,MAAM,CACL,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;IAClB,GAAG,KAAK;IACR,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;CACxD,EACD,CAAC,IAAI,CAAC,GAAG,CAAC,CACX,CAAC;AAEN;;;;;;;;;;;GAWG;AACH,MAAM,aAAa,GAAG,CACpB,GAAW,EACX,IAAY,EACZ,IAAY,EACQ,EAAE;IACtB,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,CACL,gBAAgB,MAAM,CAAC,GAAG,CAAC,kCAAkC;YAC7D,QAAQ,MAAM,CAAC,IAAI,CAAC,+CAA+C,CACpE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAClE,OAAO,CACL,QAAQ,SAAS,CAAC,IAAI,CAAC,yCAAyC;YAChE,+DAA+D,CAChE,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,kBAAkB,GAAG,CACzB,MAAc,EACd,IAAY,EACmB,EAAE,CACjC,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAC1B,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;IACnB,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QACzC,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACnD,OAAO,MAAM,KAAK,SAAS;YACzB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,SAAS;YACT,GAAG,EAAE,CAAC,CAAC;YACP,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,2BACN,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE;SACH,CAAC;IACJ,CAAC;AACH,CAAC,EACD,SAAS,CACV,CAAC;AAEJ;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,MAAc,EACiB,EAAE;IACjC,MAAM,IAAI,GAAG,MAAM,EAAE,EAAE,CAAC;IAExB,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3E,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,GAAG,GAAsB,EAAE,CAC1C,QAAQ,KAAK,QAAQ;IACnB,CAAC,CAAC;QACE,0CAA0C;QAC1C,yDAAyD;KAC1D;IACH,CAAC,CAAC;QACE,iDAAiD;QACjD,6CAA6C;KAC9C,CAAC;AAER;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,QAAgB,EAChB,QAA2B,EACnB,EAAE,CACV;IACE,sEAAsE;IACtE,EAAE;IACF,yBAAyB,QAAQ,EAAE;IACnC,yBAAyB,QAAQ,CAAC,SAAS,EAAE;IAC7C,6BAA6B,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,SAAS,CAClE,QAAQ,CAAC,IAAI,CACd,EAAE;IACH,yBAAyB,QAAQ,CAAC,MAAM,EAAE;IAC1C,EAAE;IACF,sEAAsE;IACtE,4DAA4D;IAC5D,EAAE;IACF,0EAA0E;IAC1E,yEAAyE;IACzE,yEAAyE;IACzE,2EAA2E;IAC3E,0EAA0E;IAC1E,+DAA+D;IAC/D,EAAE;IACF,kDAAkD;IAClD,GAAG,WAAW,EAAE;CACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEf;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAuB,EAAE;IACjE,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IAEjD,OAAO,QAAQ,KAAK,SAAS;QAC3B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC,CAAC"}
|
|
@@ -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,CA4lCjC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,+BAA+B,EAAE,QAAQ,CACpD,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CA+/BjC,CAAC"}
|