@codyswann/lisa 3.11.9 → 3.13.0
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-command-envelope.mjs +10 -0
- package/all/copy-overwrite/scripts/lisa-destructive-guard.mjs +267 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +15 -2
- package/all/create-only/scripts/remote-agent-aws-setup.sh +3 -0
- package/cdk/create-only/.github/workflows/deploy.yml +2 -1
- package/cdk/create-only/vitest.config.local.ts +3 -0
- package/dist/cli/doctor-lisa-owned-artifacts.d.ts +11 -2
- package/dist/cli/doctor-lisa-owned-artifacts.d.ts.map +1 -1
- package/dist/cli/doctor-lisa-owned-artifacts.js +60 -15
- package/dist/cli/doctor-lisa-owned-artifacts.js.map +1 -1
- package/dist/core/config.d.ts +21 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +1 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/guard-capabilities.d.ts +60 -0
- package/dist/core/guard-capabilities.d.ts.map +1 -0
- package/dist/core/guard-capabilities.js +102 -0
- package/dist/core/guard-capabilities.js.map +1 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts +11 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -0
- package/dist/core/lisa-owned-hash-ledger.js +127 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -0
- package/dist/core/lisa-owned-provenance.d.ts +75 -0
- package/dist/core/lisa-owned-provenance.d.ts.map +1 -0
- package/dist/core/lisa-owned-provenance.js +127 -0
- package/dist/core/lisa-owned-provenance.js.map +1 -0
- package/dist/core/lisa.d.ts +18 -0
- package/dist/core/lisa.d.ts.map +1 -1
- package/dist/core/lisa.js +38 -0
- package/dist/core/lisa.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +66 -53
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/strategies/copy-overwrite.d.ts +28 -1
- package/dist/strategies/copy-overwrite.d.ts.map +1 -1
- package/dist/strategies/copy-overwrite.js +53 -3
- package/dist/strategies/copy-overwrite.js.map +1 -1
- package/dist/strategies/strategy.interface.d.ts +13 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -1
- package/expo/create-only/.github/workflows/ci.yml +3 -0
- package/expo/create-only/.github/workflows/deploy.yml +2 -1
- package/expo/create-only/.github/workflows/maestro-e2e.yml +3 -0
- package/expo/create-only/.github/workflows/nightly-e2e-bypass-reaper.yml +3 -0
- package/expo/create-only/.github/workflows/nightly-e2e-health.yml +3 -0
- package/expo/create-only/.github/workflows/nightly-e2e-report.yml +3 -0
- package/expo/create-only/babel.config.js +3 -0
- package/expo/create-only/jest.config.local.ts +3 -0
- package/expo/create-only/jest.config.react-native-mock.js +3 -0
- package/expo/create-only/jest.setup.local.ts +3 -0
- package/expo/create-only/jest.setup.pre.local.js +3 -0
- package/expo/create-only/scripts/zap-baseline.sh +3 -0
- package/harper-fabric/create-only/.github/workflows/deploy.yml +3 -0
- package/harper-fabric/create-only/.github/workflows/zap-baseline.yml +3 -0
- package/harper-fabric/create-only/scripts/zap-baseline.sh +3 -0
- package/nestjs/create-only/.github/workflows/deploy.yml +3 -0
- package/nestjs/create-only/scripts/zap-baseline.sh +3 -0
- package/nestjs/create-only/vitest.config.local.ts +3 -0
- package/npm-package/create-only/.github/workflows/publish-to-npm.yml +2 -1
- package/package.json +3 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/block-no-verify.sh +15 -2
- package/plugins/lisa/rules/eager/reset-seed-coverage.md +2 -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 +1 -1
- package/plugins/lisa-copilot/hooks/block-no-verify.sh +15 -2
- package/plugins/lisa-copilot/rules/eager/reset-seed-coverage.md +2 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-no-verify.sh +15 -2
- package/plugins/lisa-cursor/rules/reset-seed-coverage.mdc +2 -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/hooks/block-no-verify.sh +15 -2
- package/plugins/src/base/rules/eager/reset-seed-coverage.md +2 -0
- package/rails/create-only/.github/workflows/claude-code-review-response.yml +2 -1
- package/rails/create-only/.github/workflows/claude-nightly-code-complexity.yml +2 -1
- package/rails/create-only/.github/workflows/claude-nightly-test-coverage.yml +2 -1
- package/rails/create-only/.github/workflows/claude-nightly-test-improvement.yml +2 -1
- package/rails/create-only/.github/workflows/claude-sync-down-branches.yml +2 -1
- package/rails/create-only/.github/workflows/deploy.yml +2 -1
- package/rails/create-only/.mutant.yml +3 -0
- package/rails/create-only/.reek.yml +3 -0
- package/rails/create-only/.rubocop_todo.yml +3 -0
- package/rails/create-only/mutation.gate.yml +3 -0
- package/rails/create-only/rubocop.thresholds.yml +3 -0
- package/rails/create-only/spec/rails_helper.rb +2 -0
- package/rails/create-only/spec/spec_helper.rb +2 -0
- package/scripts/generate-lisa-owned-hash-ledger.mjs +226 -0
- package/typescript/create-only/.github/workflows/auto-update-pr-branches-dispatch.yml +2 -1
- package/typescript/create-only/.github/workflows/auto-update-pr-branches.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-ci-auto-fix.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-code-review-response.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-deploy-auto-fix.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-nightly-code-complexity.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-nightly-test-coverage.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-nightly-test-improvement.yml +2 -1
- package/typescript/create-only/.github/workflows/claude-sync-down-branches.yml +2 -1
- package/typescript/create-only/.github/workflows/claude.yml +2 -1
- package/typescript/create-only/.github/workflows/required-checks-drift.yml +2 -1
- package/typescript/create-only/eslint.config.local.ts +3 -0
- package/typescript/create-only/jest.config.local.ts +3 -0
- package/typescript/create-only/vitest.config.local.ts +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard-capabilities.d.ts","sourceRoot":"","sources":["../../src/core/guard-capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAsBH,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAQlE;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,aAAa,GAClB,SAAS,MAAM,EAAE,CAInB"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability marker a Lisa-owned guard uses to declare what it defends
|
|
3
|
+
* against, so refresh can compare two copies by *what they stop* rather than by
|
|
4
|
+
* bytes.
|
|
5
|
+
*
|
|
6
|
+
* A byte comparison answers "are these the same?" and nothing else. It cannot
|
|
7
|
+
* answer the only question refresh actually needs answered — "is the host's copy
|
|
8
|
+
* behind mine, or ahead of it?" — and guessing "behind" is how a host's stronger
|
|
9
|
+
* guard gets silently replaced by a weaker upstream one.
|
|
10
|
+
*
|
|
11
|
+
* The marker is one comment line in the guard's header:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* # lisa-guard-capabilities: no-verify-abbrev, hookspath-allowlist, config-env
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Deliberately a *set*, not a version number. A monotonic `lisa-guard-version: N`
|
|
18
|
+
* is easier to compare but lies the moment two hosts harden different vectors
|
|
19
|
+
* independently — which is exactly what happened: `propswapllc/frontend` closed
|
|
20
|
+
* the `GIT_CONFIG_KEY_<n>` bypass while `tunnl-infrastructure` closed a different
|
|
21
|
+
* one. Both would have bumped to the same number and one would have silently
|
|
22
|
+
* won. Two sets stay two sets, and set difference names precisely what each copy
|
|
23
|
+
* has that the other does not.
|
|
24
|
+
*
|
|
25
|
+
* Only the header window is scanned. A guard whose *body* greps for the marker
|
|
26
|
+
* string, or a test fixture that quotes one, must not be read as declaring it.
|
|
27
|
+
* @module core/guard-capabilities
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* How much of a file counts as its header.
|
|
31
|
+
*
|
|
32
|
+
* Generous enough for the long rationale comments Lisa's guards carry, small
|
|
33
|
+
* enough that the marker cannot be smuggled in from a file's body.
|
|
34
|
+
*/
|
|
35
|
+
const HEADER_BYTES = 4096;
|
|
36
|
+
/** The token that introduces a declaration. */
|
|
37
|
+
const MARKER = "lisa-guard-capabilities:";
|
|
38
|
+
/**
|
|
39
|
+
* Characters allowed between the start of a line and the marker.
|
|
40
|
+
*
|
|
41
|
+
* Covers every comment syntax Lisa's owned artifacts use: `#` for shell, `//`
|
|
42
|
+
* and `*` for JS/TS. Requiring the marker to be preceded by nothing else is what
|
|
43
|
+
* makes it a declaration rather than a mention inside prose or a quoted string.
|
|
44
|
+
*/
|
|
45
|
+
const COMMENT_PREFIX = new Set([" ", "\t", "#", "/", "*"]);
|
|
46
|
+
/**
|
|
47
|
+
* Read the capabilities a guard's header declares.
|
|
48
|
+
*
|
|
49
|
+
* Absence is not an error and not a failure signal — it means the artifact has
|
|
50
|
+
* not been enrolled, and every caller treats that as "no declaration made"
|
|
51
|
+
* rather than "declares nothing dangerous". That is what lets the marker roll
|
|
52
|
+
* out one guard at a time with no flag day.
|
|
53
|
+
* Scanned line by line with plain string operations rather than a regular
|
|
54
|
+
* expression. A header is untrusted input — it arrives from whatever repository
|
|
55
|
+
* the "host" copy came from — and a linear scan cannot be made to backtrack.
|
|
56
|
+
* @param bytes - Full contents of the guard file
|
|
57
|
+
* @returns The declared capabilities, lower-cased and de-duplicated
|
|
58
|
+
*/
|
|
59
|
+
export function readGuardCapabilities(bytes) {
|
|
60
|
+
const header = bytes.subarray(0, HEADER_BYTES).toString("utf8");
|
|
61
|
+
const declared = header
|
|
62
|
+
.split("\n")
|
|
63
|
+
.flatMap(line => declarationOn(line))
|
|
64
|
+
.map(entry => entry.trim().toLowerCase())
|
|
65
|
+
.filter(entry => entry.length > 0);
|
|
66
|
+
return new Set(declared);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The capabilities one line declares, if it is a declaration at all.
|
|
70
|
+
* @param line - A single line from the header
|
|
71
|
+
* @returns Raw comma-separated entries, or nothing when the line declares none
|
|
72
|
+
*/
|
|
73
|
+
function declarationOn(line) {
|
|
74
|
+
const at = line.indexOf(MARKER);
|
|
75
|
+
if (at === -1)
|
|
76
|
+
return [];
|
|
77
|
+
for (const character of line.slice(0, at)) {
|
|
78
|
+
if (!COMMENT_PREFIX.has(character))
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return line.slice(at + MARKER.length).split(",");
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The capabilities the host declares that Lisa's copy does not.
|
|
85
|
+
*
|
|
86
|
+
* A non-empty result is the whole signal: the host copy defends something
|
|
87
|
+
* upstream does not, so overwriting it removes protection. This is set
|
|
88
|
+
* *difference*, not a strict-superset test, on purpose — a host that hardened
|
|
89
|
+
* vector A while upstream hardened vector B is not a superset of upstream, yet
|
|
90
|
+
* overwriting it still deletes A. Asking only "is the host a superset?" would
|
|
91
|
+
* clobber precisely the divergent-hardening case the set representation exists
|
|
92
|
+
* to handle.
|
|
93
|
+
* @param host - Capabilities declared by the installed copy
|
|
94
|
+
* @param lisa - Capabilities declared by the packaged copy
|
|
95
|
+
* @returns Capabilities present on the host and absent upstream, sorted
|
|
96
|
+
*/
|
|
97
|
+
export function capabilitiesOnlyOnHost(host, lisa) {
|
|
98
|
+
return [...host]
|
|
99
|
+
.filter(capability => !lisa.has(capability))
|
|
100
|
+
.sort((left, right) => left.localeCompare(right));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=guard-capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard-capabilities.js","sourceRoot":"","sources":["../../src/core/guard-capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;GAKG;AACH,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B,+CAA+C;AAC/C,MAAM,MAAM,GAAG,0BAA0B,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAK3D;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,MAAM;SACpB,KAAK,CAAC,IAAI,CAAC;SACX,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;SACpC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;SACxC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrC,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IACzB,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAmB,EACnB,IAAmB;IAEnB,OAAO,CAAC,GAAG,IAAI,CAAC;SACb,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;SAC3C,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Generated by scripts/generate-lisa-owned-hash-ledger.mjs. Do not edit. */
|
|
2
|
+
/**
|
|
3
|
+
* Every content hash Lisa has published at each Lisa-owned destination path.
|
|
4
|
+
*
|
|
5
|
+
* A host copy whose hash appears here is provably an older Lisa artifact and may
|
|
6
|
+
* be refreshed. One that appears nowhere here was edited downstream, and refresh
|
|
7
|
+
* refuses rather than risk deleting a stronger guard. See
|
|
8
|
+
* `src/core/lisa-owned-provenance.ts`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const LISA_OWNED_HASH_LEDGER: Readonly<Record<string, readonly string[]>>;
|
|
11
|
+
//# sourceMappingURL=lisa-owned-hash-ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lisa-owned-hash-ledger.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAC3C,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAqHjC,CAAC"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/** Generated by scripts/generate-lisa-owned-hash-ledger.mjs. Do not edit. */
|
|
2
|
+
/**
|
|
3
|
+
* Every content hash Lisa has published at each Lisa-owned destination path.
|
|
4
|
+
*
|
|
5
|
+
* A host copy whose hash appears here is provably an older Lisa artifact and may
|
|
6
|
+
* be refreshed. One that appears nowhere here was edited downstream, and refresh
|
|
7
|
+
* refuses rather than risk deleting a stronger guard. See
|
|
8
|
+
* `src/core/lisa-owned-provenance.ts`.
|
|
9
|
+
*/
|
|
10
|
+
export const LISA_OWNED_HASH_LEDGER = Object.freeze({
|
|
11
|
+
"scripts/lisa-clean-git-env.sh": Object.freeze([
|
|
12
|
+
"d15af6f13eedbca41046070972380e69fc0af8f7d903aac12b8644389b9a0c91",
|
|
13
|
+
"e7121a0ee9e1bf7c01cd2ab55f563dd6d9ab75990739bb6ddf571a513efa10e9",
|
|
14
|
+
]),
|
|
15
|
+
"scripts/lisa-command-envelope.mjs": Object.freeze([
|
|
16
|
+
"2011331056b1c86bd181649713a395dbfd2768f9fcd7e37b521d6ad2a9318ea9",
|
|
17
|
+
"4f76bb7d466eb153a4e1414d06f12856a1242de2cfa4cb4b1b942cf29d8b7f37",
|
|
18
|
+
"6b198f088cd3cd862d4357fbb069b1ad5d3afeb7be594f2bf1ff603b092a8354",
|
|
19
|
+
"e06cb11f1418fe94564cea527a22b039f53b7ab10c1cd182264a31e52bba9fa8",
|
|
20
|
+
]),
|
|
21
|
+
"scripts/lisa-destructive-guard.mjs": Object.freeze([
|
|
22
|
+
"4fb431a3c58f443e303d613934d023d9e95ddae5c42710bb7009f7c080c82a64",
|
|
23
|
+
]),
|
|
24
|
+
"scripts/lisa-enforcement-fallback.sh": Object.freeze([
|
|
25
|
+
"1bec5f3c284b3febdc471487ee6a23ffb72bd4e7b293f9e26b0188f32318c722",
|
|
26
|
+
"3049c2f1051c7c02dd60b62355964651e1565ebe6bdcb5e37634cd686cf1deb1",
|
|
27
|
+
"8dc942ac4edc2017d6b8277296c8f80542e7c024eef1bb65de609979d0ca9a0e",
|
|
28
|
+
"9cab71562d01421d57c6719318a4d03a6249a45c1aea434db3ff26e3065eeb66",
|
|
29
|
+
"d7d88e44763694bed5eae998cd3663922c957e49f9f9621d9201f0417a4128ad",
|
|
30
|
+
"e17c45f7cadf0fb55dd07270776caf211af99b7d4771a4fde75aafe5919e8dbe",
|
|
31
|
+
]),
|
|
32
|
+
"scripts/lisa-floor-collisions.mjs": Object.freeze([
|
|
33
|
+
"2d11968f6852ab745cba939de03c6d6cb5f413975d2cfc8fc447bdd0b218e91a",
|
|
34
|
+
"3c7a0234b4f5609fce49e44711d2ec86af8cf7fb82b0831e4450e3347ecefe45",
|
|
35
|
+
"a612f172282d13ba9318fe5e03689d7c6ff42a0122d0c9d5d39051e1967b93dc",
|
|
36
|
+
]),
|
|
37
|
+
"scripts/lisa-hooks/block-direct-issue-create.sh": Object.freeze([
|
|
38
|
+
"22184f1dd1b96e818741bd4ae659446299535d7ce594817155edebac4172a7ba",
|
|
39
|
+
"60a4f94ec671b2372f7492680ab327d97aff686588ce85791f54e0fbd098b0ca",
|
|
40
|
+
"73e94b73830d8961026947d99bf4ac5f959b5bca025203b913d8a6363cbe2b9f",
|
|
41
|
+
"847dfca48823a495fc3de47dfdb4b26e49d6808c6570c46d024a99793df1d370",
|
|
42
|
+
]),
|
|
43
|
+
"scripts/lisa-hooks/block-instruction-file-edits.sh": Object.freeze([
|
|
44
|
+
"6f52076e3488821d638b6dd45b5faca527d92b181cc12e6e5033859e0786c8a7",
|
|
45
|
+
"850cfc23852eb752114ae1e938a1c7bcf34bc50c85d3aaca0c02311cc8c0ef70",
|
|
46
|
+
"8996e0bcbf1db085a5d99734e797c91f5025997bd967bc374efff8348dac14c2",
|
|
47
|
+
"be1e77fb0ddb246eddae71ebac25e972c3c9e8079514e0dc78d0b73df919464c",
|
|
48
|
+
"d47314b66d6ce85f77d6e058f861eede4462b2b0a33d54e82ff1c931167ec3f7",
|
|
49
|
+
]),
|
|
50
|
+
"scripts/lisa-hooks/block-no-verify.sh": Object.freeze([
|
|
51
|
+
"031ef7a53fc49cb18665105b834b7b50ad6a43317e0821949809e877e0562ce4",
|
|
52
|
+
"18b7bb8867c5e6f719a9c503a38525f4c05e3d611717c3e1a503cf58dfb2832f",
|
|
53
|
+
"2df476aacebcb2544a12f459a0092e88eb28c0d00e45fd7ed909c75dfe441027",
|
|
54
|
+
"33e2bd341eb992036059b0c4606db35a218adcfeca7e44d174fedf8ebdff29d2",
|
|
55
|
+
"3b93a0affab6413e3c14a6f43de5acb586286ed1819ece0a66b30429b4d00490",
|
|
56
|
+
"3ff7255f395a9552366faaac34d383f4c95fecfb39882cd1d57854356422fe61",
|
|
57
|
+
"7790a560850c9d38709dbaccdaa10733e632c1bd4d975cbec7e3cc5a8650b36a",
|
|
58
|
+
"a6ed91576efebb6ba40cfa4e9d8a3e8566314909210ae8d5860be62a3feb4cff",
|
|
59
|
+
"aa95a84f9f9224914947a09b858535aa8bd052199ff64cb53768cf78fb69b687",
|
|
60
|
+
"b9f299cb9d3ad75b71296376ae2c40eb207a3b2706dafdaa41fc586050a53aad",
|
|
61
|
+
"dd1aea1b9fdd0da023bf704b331b350bc14620f4364afa5001c6690fcbc940cc",
|
|
62
|
+
"e3407d63eae16662923d46b75b6a41e7ca7ab206b428ea2cbb0b4fee226f6516",
|
|
63
|
+
]),
|
|
64
|
+
"scripts/lisa-hooks/block-shell-json-parsing.sh": Object.freeze([
|
|
65
|
+
"1934a15e154fda3c2a40979a5cd6225661b14fe7bc77328a69ce499bea85dba7",
|
|
66
|
+
"3b5f074f3ab5708030af507eea962389f3b067c5dbdc76580bd9e44d3ac6c603",
|
|
67
|
+
"90601e31603c440d8f19d213d63bfef8d18596c60f88cb6e28c93d12453c5c0c",
|
|
68
|
+
]),
|
|
69
|
+
"scripts/lisa-hooks/parity-safety-net.sh": Object.freeze([
|
|
70
|
+
"062c69eea85157f1e941ec3626d8912aa9f182af6ccdbe19687588a6074db5ce",
|
|
71
|
+
"07002535de10d89f6d73e8922517550a02a8974549aaf200c9c314e6f4f83c70",
|
|
72
|
+
"1162ffd16cef3b23282d2f5207abcb88429462a74a9df1035f0df4968f6dd456",
|
|
73
|
+
"14fc5e292aebf83dd24fec12fb32e2beb509a9324f127a24a64d5c5d4d05c576",
|
|
74
|
+
"1bf3512bb94923a6cb25b1e7a619a3fc8e1336bffa16f499b459aaee3eaed66d",
|
|
75
|
+
"388cf8847581d96a1ff8ea98290a33a5f96d67cdd502ea807a0b8d88efe90e19",
|
|
76
|
+
"64546813f168fb446f39e34bc674fd3af85b15bd5e7f4f6bf4503463e701a7b9",
|
|
77
|
+
"772202ddd42d626625ff719666afbbe83445d8bae1bc7c0fb5ffdcb402be83f8",
|
|
78
|
+
"7f55986eb29f8ace8616595da4bbe60d80a96f9f29b24fb72efd66bb96b22464",
|
|
79
|
+
"8e19d5f1ba7abe3d22fbee47ff8e0fad76b965ccca20b8849e3c43ab07d9a4ef",
|
|
80
|
+
"a22fd1b7c483f1a538202353ee85c82be17a8910e03c0a930635ce8cb3595c64",
|
|
81
|
+
"b83c5043a0f29b2d8851258acfe6906aab7922cd80f486e25220e55f26a8c0a5",
|
|
82
|
+
"caea02a07027fc1c74d47e08b36299d369c5c9f7c4043da8828fbca3c64eb2aa",
|
|
83
|
+
"d12583803e8ff5e4b64e68eafc8d3c377af4c400d8b7ecd1c7fe699d8f92784a",
|
|
84
|
+
"d9ea58150aa27e7f0aa9a4ef155ed446d30bdfc932d01c64e2b8ca211aa0de7b",
|
|
85
|
+
"f740f600b255742a50f28e5c9d09427c5783c4084e84052dca46bc1f0c94a187",
|
|
86
|
+
"fa8f4a6517eacd9266feb7afd62398cdf2075d4824cac24b45bb64ad0cd18c86",
|
|
87
|
+
]),
|
|
88
|
+
"scripts/lisa-hooks/sonar-secrets.sh": Object.freeze([
|
|
89
|
+
"7a408788975a6351d53e14aa32bb9a5d161f33df9dfea59ba32784ae33a62e67",
|
|
90
|
+
"945453fb275a58aa7185e150e6b05e5810739750928ab5bd6edfbf87d1c8aa0d",
|
|
91
|
+
"bf4132e49ba18e2f7e941520c299c15aeeacfd220e489f3d2eb8397f2048157b",
|
|
92
|
+
]),
|
|
93
|
+
"scripts/lisa-mutation.mjs": Object.freeze([
|
|
94
|
+
"7d8d24dea151ef2178807046e97aea7ebfadd9c88eb50347feb7bb4bb190227d",
|
|
95
|
+
"8e0bdb491dfaea04e88be1c1e2c6cc7cd34fa4ca18adddf5fecc43d7de8ffded",
|
|
96
|
+
"a630bde6cddae283776b8d34763a3642edbea8096d583a90ec6d43a9588ca8a6",
|
|
97
|
+
]),
|
|
98
|
+
"scripts/lisa-schema-validate.mjs": Object.freeze([
|
|
99
|
+
"2ace82daacdebbbb00a7eceb09fbe82cabec04330a083ca10417b2ee4e0a63eb",
|
|
100
|
+
"4a05a0ed70a274827fd2f0fd0c98890c66bee2fde70785b8379943ebe6650473",
|
|
101
|
+
"9dd145c0f9dac6ed252b13d32e130dbab964da6cd357981b58541780ecb2f981",
|
|
102
|
+
]),
|
|
103
|
+
"scripts/lisa-work-item.mjs": Object.freeze([
|
|
104
|
+
"238dc2da29938edd92518c2b08192d14c6f2751ed175c07d6e882814829b7b7e",
|
|
105
|
+
"2d9ca0841db9e75ddfd95e3a4d485fd01aa639a512ef648996f565b7991d8e2b",
|
|
106
|
+
"4c263fef48c03b3b6c623ea8a6cd55505bfaf28197e5072226ea35f9f3d26885",
|
|
107
|
+
"5eb31c284e820a51312d4484f0669128007326af55ee515923fec33700d003a1",
|
|
108
|
+
"6a8be8577242588f14ab52b25b2a22b6def53aefa9513b4d3d7c49f4d8027079",
|
|
109
|
+
"9223856be4618fb1e3e731b259ae5bf5328decc322f0b4a0d0fd18d6b12cd45a",
|
|
110
|
+
"96a87c131606b3edd43e52485e68f8ffbf5c528cb4beb7a1185263519a9632ce",
|
|
111
|
+
"ab0dede91c5c8a07984ae13aa48ec70cdcd2fa691b59617bc4b57998dc79a51c",
|
|
112
|
+
"c78df9d5f0f3fc388ff60a7db5898478a2a4d6d7325833f10384b5a8c62bb34a",
|
|
113
|
+
"e30016a49deff1c3cd3ae7951262aeb2ef3d472bce76bbbe2a177db6017c7cad",
|
|
114
|
+
"e41e9534988ce69a836664437a78f3a3f3dc7ebbe396c86cdab0ea63fb7c19da",
|
|
115
|
+
"f12006df4ed9974f65d955718af7dcc8a079799d02c58bd38b2d9c49f271db72",
|
|
116
|
+
"f88f69d44693084428f44e3f2b80afecda08c7ee8747588f40277fdc9396fd8f",
|
|
117
|
+
"fc0d92739e620d8fd70f7aa4a12d3e0b3a8f790d47c4a8322040f32c30b9445a",
|
|
118
|
+
"fe064a2bd11200ed256fb36e203978f858fccbcaf40708496c066383345900ef",
|
|
119
|
+
]),
|
|
120
|
+
"scripts/schemas/lisa-command-envelope.v1.schema.json": Object.freeze([
|
|
121
|
+
"d153b7c2953a30f180e38f09e98240c63327f5196eeba9bdf545e5a1f125a879",
|
|
122
|
+
]),
|
|
123
|
+
"scripts/schemas/lisa-state-contract.v1.schema.json": Object.freeze([
|
|
124
|
+
"6b7afe4ffeba8aaa53871d8855172f7eacde05953b1321145218ec638ff5c1c4",
|
|
125
|
+
]),
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=lisa-owned-hash-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lisa-owned-hash-ledger.js","sourceRoot":"","sources":["../../src/core/lisa-owned-hash-ledger.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAE/B,MAAM,CAAC,MAAM,CAAC;IAChB,+BAA+B,EAAE,MAAM,CAAC,MAAM,CAAC;QAC7C,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,mCAAmC,EAAE,MAAM,CAAC,MAAM,CAAC;QACjD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,oCAAoC,EAAE,MAAM,CAAC,MAAM,CAAC;QAClD,kEAAkE;KACnE,CAAC;IACF,sCAAsC,EAAE,MAAM,CAAC,MAAM,CAAC;QACpD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,mCAAmC,EAAE,MAAM,CAAC,MAAM,CAAC;QACjD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,iDAAiD,EAAE,MAAM,CAAC,MAAM,CAAC;QAC/D,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,oDAAoD,EAAE,MAAM,CAAC,MAAM,CAAC;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,uCAAuC,EAAE,MAAM,CAAC,MAAM,CAAC;QACrD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,gDAAgD,EAAE,MAAM,CAAC,MAAM,CAAC;QAC9D,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,yCAAyC,EAAE,MAAM,CAAC,MAAM,CAAC;QACvD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,qCAAqC,EAAE,MAAM,CAAC,MAAM,CAAC;QACnD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,2BAA2B,EAAE,MAAM,CAAC,MAAM,CAAC;QACzC,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,kCAAkC,EAAE,MAAM,CAAC,MAAM,CAAC;QAChD,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,4BAA4B,EAAE,MAAM,CAAC,MAAM,CAAC;QAC1C,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;QAClE,kEAAkE;KACnE,CAAC;IACF,sDAAsD,EAAE,MAAM,CAAC,MAAM,CAAC;QACpE,kEAAkE;KACnE,CAAC;IACF,oDAAoD,EAAE,MAAM,CAAC,MAAM,CAAC;QAClE,kEAAkE;KACnE,CAAC;CACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Known-good hashes per Lisa-owned destination path. */
|
|
2
|
+
export type HashLedger = Readonly<Record<string, readonly string[]>>;
|
|
3
|
+
/** What refresh concluded about a host's copy of a Lisa-owned artifact. */
|
|
4
|
+
export type ProvenanceVerdict =
|
|
5
|
+
/** Byte-identical to Lisa's copy; there is nothing to decide. */
|
|
6
|
+
{
|
|
7
|
+
readonly kind: "identical";
|
|
8
|
+
}
|
|
9
|
+
/** Declares hardening Lisa lacks. Preserve, and name what would be lost. */
|
|
10
|
+
| {
|
|
11
|
+
readonly kind: "host-ahead";
|
|
12
|
+
readonly extraCapabilities: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
/** Content Lisa never shipped, with nothing declared. Preserve and report. */
|
|
15
|
+
| {
|
|
16
|
+
readonly kind: "host-modified";
|
|
17
|
+
}
|
|
18
|
+
/** Declared hardening that upstream now also has. Safe to refresh. */
|
|
19
|
+
| {
|
|
20
|
+
readonly kind: "absorbed-upstream";
|
|
21
|
+
}
|
|
22
|
+
/** Hash matches a Lisa release. Genuinely stale, so refresh it. */
|
|
23
|
+
| {
|
|
24
|
+
readonly kind: "provably-stale";
|
|
25
|
+
}
|
|
26
|
+
/** Artifact carries no provenance yet; behave exactly as before this change. */
|
|
27
|
+
| {
|
|
28
|
+
readonly kind: "unenrolled";
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The verdicts under which the host's copy is kept.
|
|
32
|
+
*
|
|
33
|
+
* Derived from `ProvenanceVerdict` rather than restated, so a verdict added
|
|
34
|
+
* later cannot quietly go unhandled: `mayRefreshLisaOwned` must classify it, and
|
|
35
|
+
* anything it declines to refresh has to be describable here.
|
|
36
|
+
*/
|
|
37
|
+
export type PreservedVerdict = Extract<ProvenanceVerdict, {
|
|
38
|
+
readonly kind: "host-ahead" | "host-modified";
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Decide whether a host's copy of a Lisa-owned artifact may be overwritten.
|
|
42
|
+
*
|
|
43
|
+
* Order matters. Capabilities are consulted before the ledger because a
|
|
44
|
+
* declaration is an explicit statement of intent by whoever edited the file, and
|
|
45
|
+
* an explicit statement outranks an inference drawn from a hash table.
|
|
46
|
+
* @param relativePath - Repo-relative destination path of the artifact
|
|
47
|
+
* @param hostBytes - Contents currently installed in the host project
|
|
48
|
+
* @param lisaBytes - Contents Lisa ships for that path
|
|
49
|
+
* @param ledger - Known-good hash ledger (injected by tests)
|
|
50
|
+
* @returns The verdict describing which side is ahead
|
|
51
|
+
*/
|
|
52
|
+
export declare function classifyHostCopy(relativePath: string, hostBytes: Buffer, lisaBytes: Buffer, ledger?: HashLedger): ProvenanceVerdict;
|
|
53
|
+
/**
|
|
54
|
+
* Whether refresh is allowed to replace the host's copy.
|
|
55
|
+
*
|
|
56
|
+
* The default is deliberately asymmetric. Failing closed leaves a stale file in
|
|
57
|
+
* place and tells somebody about it; failing open deletes a security control and
|
|
58
|
+
* tells nobody. Those costs are not comparable, so anything short of proof that
|
|
59
|
+
* the host is behind means the host's copy stays.
|
|
60
|
+
* @param verdict - Result of `classifyHostCopy`
|
|
61
|
+
* @returns True when the host copy is provably not ahead
|
|
62
|
+
*/
|
|
63
|
+
export declare function mayRefreshLisaOwned(verdict: ProvenanceVerdict): verdict is Exclude<ProvenanceVerdict, PreservedVerdict>;
|
|
64
|
+
/**
|
|
65
|
+
* Explain a preserved file to whoever is reading the apply output.
|
|
66
|
+
*
|
|
67
|
+
* Written for an operator who did not make the change and may not be an
|
|
68
|
+
* engineer: it names the file, says plainly that theirs is the stronger copy,
|
|
69
|
+
* and gives the two actions that end the standoff.
|
|
70
|
+
* @param relativePath - Repo-relative destination path of the artifact
|
|
71
|
+
* @param verdict - Result of `classifyHostCopy`
|
|
72
|
+
* @returns One operator-readable sentence, or undefined when nothing was held back
|
|
73
|
+
*/
|
|
74
|
+
export declare function describePreserved(relativePath: string, verdict: PreservedVerdict): string;
|
|
75
|
+
//# sourceMappingURL=lisa-owned-provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lisa-owned-provenance.d.ts","sourceRoot":"","sources":["../../src/core/lisa-owned-provenance.ts"],"names":[],"mappings":"AAsDA,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAQrE,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB;AAC3B,iEAAiE;AAC/D;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AAChC,4EAA4E;GAC1E;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C;AACH,8EAA8E;GAC5E;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AACpC,sEAAsE;GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;CAAE;AACxC,mEAAmE;GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE;AACrC,gFAAgF;GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAEpC;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,CACpC,iBAAiB,EACjB;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,CAAA;CAAE,CAClD,CAAC;AAWF;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,UAAmC,GAC1C,iBAAiB,CAkBnB;AAWD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,GACzB,OAAO,IAAI,OAAO,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAEzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAIR"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a host's copy of a Lisa-owned artifact is *behind* Lisa's or *ahead*
|
|
3
|
+
* of it — the question byte comparison cannot answer.
|
|
4
|
+
*
|
|
5
|
+
* Refresh (#2436) decided whether to overwrite a host's copy by comparing bytes.
|
|
6
|
+
* Unequal bytes were read as "the host is out of date", which is one of two
|
|
7
|
+
* possibilities and not the dangerous one. When the host copy is ahead —
|
|
8
|
+
* a guard hardened downstream before upstream caught up — the same comparison
|
|
9
|
+
* produces the same answer, and the overwrite silently deletes a security
|
|
10
|
+
* control. `propswapllc/frontend` closed the `GIT_CONFIG_KEY_<n>` hooks-path
|
|
11
|
+
* bypass before Lisa did; a `bun install` regenerated the file and reverted the
|
|
12
|
+
* hardening with no warning and no failure. Their own tests caught it. Nothing
|
|
13
|
+
* in Lisa would have.
|
|
14
|
+
*
|
|
15
|
+
* ## How "behind" gets proved
|
|
16
|
+
*
|
|
17
|
+
* The primary signal is provenance by content hash. Lisa ships a ledger of every
|
|
18
|
+
* sha256 it has ever published at each Lisa-owned destination path (see
|
|
19
|
+
* `scripts/generate-lisa-owned-hash-ledger.mjs`). A host's copy came from some
|
|
20
|
+
* past Lisa, so if its hash is in the ledger it is *provably* an older Lisa
|
|
21
|
+
* artifact and refreshing it is correct. If the hash appears nowhere in Lisa's
|
|
22
|
+
* shipping history, somebody downstream edited it, and refresh has no basis to
|
|
23
|
+
* call that stale.
|
|
24
|
+
*
|
|
25
|
+
* Hashes are the primary signal rather than capability markers because markers
|
|
26
|
+
* only protect a host that *declared*. propswap did not declare; they edited the
|
|
27
|
+
* guard. A marker-only design would still have clobbered the very incident that
|
|
28
|
+
* motivated this. The ledger protects undeclared hardening, retroactively, with
|
|
29
|
+
* no host-side action required.
|
|
30
|
+
*
|
|
31
|
+
* A ledger beats a receipt file written at apply time for the same reason: a
|
|
32
|
+
* receipt has to be written by a *prior* apply to arm the mechanism, so the first
|
|
33
|
+
* apply after the change is the one that clobbers — it fails exactly once, on the
|
|
34
|
+
* case that matters most.
|
|
35
|
+
*
|
|
36
|
+
* ## How the standoff ends
|
|
37
|
+
*
|
|
38
|
+
* Refusing forever is its own failure: genuine drift would accumulate and never
|
|
39
|
+
* be fixed. Capability markers are the release valve. When the host declares
|
|
40
|
+
* capabilities and Lisa's copy declares all of them, upstream has absorbed the
|
|
41
|
+
* host's hardening, so overwriting restores parity instead of removing
|
|
42
|
+
* protection — and refresh resumes automatically, with no operator action. A
|
|
43
|
+
* host that hardened without declaring gets told to do one of the two things
|
|
44
|
+
* that end the standoff: land it upstream, or declare it.
|
|
45
|
+
* @module core/lisa-owned-provenance
|
|
46
|
+
*/
|
|
47
|
+
import { createHash } from "node:crypto";
|
|
48
|
+
import { capabilitiesOnlyOnHost, readGuardCapabilities, } from "./guard-capabilities.js";
|
|
49
|
+
import { LISA_OWNED_HASH_LEDGER } from "./lisa-owned-hash-ledger.js";
|
|
50
|
+
/** The verdict for content Lisa has no record of ever having shipped. */
|
|
51
|
+
const HOST_MODIFIED = "host-modified";
|
|
52
|
+
/** The verdict for a copy declaring hardening Lisa's copy does not. */
|
|
53
|
+
const HOST_AHEAD = "host-ahead";
|
|
54
|
+
/**
|
|
55
|
+
* Hex sha256 of a file's contents.
|
|
56
|
+
* @param bytes - File contents
|
|
57
|
+
* @returns Lower-case hex digest
|
|
58
|
+
*/
|
|
59
|
+
function digest(bytes) {
|
|
60
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Decide whether a host's copy of a Lisa-owned artifact may be overwritten.
|
|
64
|
+
*
|
|
65
|
+
* Order matters. Capabilities are consulted before the ledger because a
|
|
66
|
+
* declaration is an explicit statement of intent by whoever edited the file, and
|
|
67
|
+
* an explicit statement outranks an inference drawn from a hash table.
|
|
68
|
+
* @param relativePath - Repo-relative destination path of the artifact
|
|
69
|
+
* @param hostBytes - Contents currently installed in the host project
|
|
70
|
+
* @param lisaBytes - Contents Lisa ships for that path
|
|
71
|
+
* @param ledger - Known-good hash ledger (injected by tests)
|
|
72
|
+
* @returns The verdict describing which side is ahead
|
|
73
|
+
*/
|
|
74
|
+
export function classifyHostCopy(relativePath, hostBytes, lisaBytes, ledger = LISA_OWNED_HASH_LEDGER) {
|
|
75
|
+
if (hostBytes.equals(lisaBytes))
|
|
76
|
+
return { kind: "identical" };
|
|
77
|
+
const hostCapabilities = readGuardCapabilities(hostBytes);
|
|
78
|
+
const extraCapabilities = capabilitiesOnlyOnHost(hostCapabilities, readGuardCapabilities(lisaBytes));
|
|
79
|
+
if (extraCapabilities.length > 0) {
|
|
80
|
+
return { kind: HOST_AHEAD, extraCapabilities };
|
|
81
|
+
}
|
|
82
|
+
if (hostCapabilities.size > 0)
|
|
83
|
+
return { kind: "absorbed-upstream" };
|
|
84
|
+
const known = ledger[normalise(relativePath)];
|
|
85
|
+
if (known === undefined || known.length === 0)
|
|
86
|
+
return { kind: "unenrolled" };
|
|
87
|
+
return known.includes(digest(hostBytes))
|
|
88
|
+
? { kind: "provably-stale" }
|
|
89
|
+
: { kind: HOST_MODIFIED };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Normalise a destination path to the ledger's key form.
|
|
93
|
+
* @param relativePath - Repo-relative destination path
|
|
94
|
+
* @returns The path with forward slashes
|
|
95
|
+
*/
|
|
96
|
+
function normalise(relativePath) {
|
|
97
|
+
return relativePath.replaceAll("\\", "/");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Whether refresh is allowed to replace the host's copy.
|
|
101
|
+
*
|
|
102
|
+
* The default is deliberately asymmetric. Failing closed leaves a stale file in
|
|
103
|
+
* place and tells somebody about it; failing open deletes a security control and
|
|
104
|
+
* tells nobody. Those costs are not comparable, so anything short of proof that
|
|
105
|
+
* the host is behind means the host's copy stays.
|
|
106
|
+
* @param verdict - Result of `classifyHostCopy`
|
|
107
|
+
* @returns True when the host copy is provably not ahead
|
|
108
|
+
*/
|
|
109
|
+
export function mayRefreshLisaOwned(verdict) {
|
|
110
|
+
return verdict.kind !== HOST_AHEAD && verdict.kind !== HOST_MODIFIED;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Explain a preserved file to whoever is reading the apply output.
|
|
114
|
+
*
|
|
115
|
+
* Written for an operator who did not make the change and may not be an
|
|
116
|
+
* engineer: it names the file, says plainly that theirs is the stronger copy,
|
|
117
|
+
* and gives the two actions that end the standoff.
|
|
118
|
+
* @param relativePath - Repo-relative destination path of the artifact
|
|
119
|
+
* @param verdict - Result of `classifyHostCopy`
|
|
120
|
+
* @returns One operator-readable sentence, or undefined when nothing was held back
|
|
121
|
+
*/
|
|
122
|
+
export function describePreserved(relativePath, verdict) {
|
|
123
|
+
return verdict.kind === HOST_AHEAD
|
|
124
|
+
? `${relativePath}: your copy guards against ${verdict.extraCapabilities.join(", ")}, which Lisa's copy does not. Kept yours. To take Lisa's copy later, contribute your hardening upstream — refresh resumes on its own once Lisa declares it too.`
|
|
125
|
+
: `${relativePath}: this file was edited in your project — its contents match no Lisa release, so Lisa cannot tell whether it is out of date or deliberately stronger. Kept yours. Review the difference, then either contribute the change upstream or add a \`lisa-guard-capabilities:\` line naming what it defends.`;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=lisa-owned-provenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lisa-owned-provenance.js","sourceRoot":"","sources":["../../src/core/lisa-owned-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAKrE,yEAAyE;AACzE,MAAM,aAAa,GAAG,eAAwB,CAAC;AAE/C,uEAAuE;AACvE,MAAM,UAAU,GAAG,YAAqB,CAAC;AAgCzC;;;;GAIG;AACH,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAAoB,EACpB,SAAiB,EACjB,SAAiB,EACjB,SAAqB,sBAAsB;IAE3C,IAAI,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAE9D,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAC1D,MAAM,iBAAiB,GAAG,sBAAsB,CAC9C,gBAAgB,EAChB,qBAAqB,CAAC,SAAS,CAAC,CACjC,CAAC;IACF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC;IACjD,CAAC;IACD,IAAI,gBAAgB,CAAC,IAAI,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;IAEpE,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAC7E,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE;QAC5B,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,YAAoB;IACrC,OAAO,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA0B;IAE1B,OAAO,OAAO,CAAC,IAAI,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,CAAC;AACvE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAoB,EACpB,OAAyB;IAEzB,OAAO,OAAO,CAAC,IAAI,KAAK,UAAU;QAChC,CAAC,CAAC,GAAG,YAAY,8BAA8B,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,iKAAiK;QACpP,CAAC,CAAC,GAAG,YAAY,uSAAuS,CAAC;AAC7T,CAAC"}
|
package/dist/core/lisa.d.ts
CHANGED
|
@@ -33,6 +33,15 @@ export declare class Lisa {
|
|
|
33
33
|
* back to the silence this exists to end.
|
|
34
34
|
*/
|
|
35
35
|
private readonly stalePaths;
|
|
36
|
+
/**
|
|
37
|
+
* Lisa-owned artifacts this apply deliberately did not replace, each with the
|
|
38
|
+
* reason spelled out for whoever reads the output.
|
|
39
|
+
*
|
|
40
|
+
* Full sentences rather than paths, because this is the one outcome an
|
|
41
|
+
* operator cannot act on from the filename: "we left yours alone because it
|
|
42
|
+
* defends something ours does not" is the entire message.
|
|
43
|
+
*/
|
|
44
|
+
private readonly hostAheadNotes;
|
|
36
45
|
private detectedTypes;
|
|
37
46
|
private ignorePatterns;
|
|
38
47
|
/**
|
|
@@ -663,6 +672,15 @@ export declare class Lisa {
|
|
|
663
672
|
* that stayed on its old version while the release notes said otherwise.
|
|
664
673
|
*/
|
|
665
674
|
private printStaleDetail;
|
|
675
|
+
/**
|
|
676
|
+
* Report Lisa-owned artifacts this apply chose not to replace.
|
|
677
|
+
*
|
|
678
|
+
* Reported as good news, not as a warning about the project: keeping a guard
|
|
679
|
+
* that is stronger than Lisa's is the correct outcome, and phrasing it as a
|
|
680
|
+
* problem would push an operator to "fix" it by discarding their own
|
|
681
|
+
* hardening — the exact loss the check exists to prevent.
|
|
682
|
+
*/
|
|
683
|
+
private printHostAheadDetail;
|
|
666
684
|
/**
|
|
667
685
|
* Print summary statistics
|
|
668
686
|
*/
|
package/dist/core/lisa.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lisa.d.ts","sourceRoot":"","sources":["../../src/core/lisa.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AA2BnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAOzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,iBAAiB,EAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAwB,MAAM,wBAAwB,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAe9D,OAAO,KAAK,EAIV,UAAU,EACV,UAAU,EAGX,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAsBpD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;IACvC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAUD;;GAEG;AACH,qBAAa,IAAI;
|
|
1
|
+
{"version":3,"file":"lisa.d.ts","sourceRoot":"","sources":["../../src/core/lisa.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AA2BnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAOzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,iBAAiB,EAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAwB,MAAM,wBAAwB,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAe9D,OAAO,KAAK,EAIV,UAAU,EACV,UAAU,EAGX,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAsBpD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC;IACvC,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;CAC/C;AAUD;;GAEG;AACH,qBAAa,IAAI;IAqGb,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IArGvB,OAAO,CAAC,QAAQ,CAA8C;IAE9D;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,cAAc,CAGpB;IACF;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB,CAA0B;IAClD;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,mBAAmB,CAAkC;IAC7D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAAO,CAAC,sBAAsB,CAAkC;IAChE,2EAA2E;IAC3E,OAAO,CAAC,oBAAoB,CAAmC;IAC/D,4EAA4E;IAC5E,OAAO,CAAC,kCAAkC,CAAS;IACnD;;;;;OAKG;IACH,OAAO,CAAC,kCAAkC,CAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8C;IACxE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IAEpD;;;;OAIG;IACH,OAAO,CAAC,SAAS,CAAS;IAE1B;;;;OAIG;gBAEgB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,gBAAgB;IAGzC;;;;;;;;OAQG;IACH,OAAO,CAAC,oCAAoC;IAI5C;;OAEG;YACW,YAAY;IAQ1B;;OAEG;YACW,WAAW;IAUzB;;;;;;OAMG;YACW,eAAe;IAa7B;;OAEG;YACW,qBAAqB;IAyBnC;;;;;;;;;;;;;;;OAeG;YACW,oBAAoB;IAWlC;;;;OAIG;YACW,wBAAwB;IAoBtC;;;;;;;;;;;;;;;;;;;;;;OAsBG;YACW,uBAAuB;IAsCrC;;;;;;;;;;;OAWG;YACW,0BAA0B;IAqBxC;;;;;;;OAOG;YACW,2BAA2B;IAyBzC;;OAEG;YACW,gBAAgB;IAoB9B;;;OAGG;YACW,oBAAoB;IA2BlC;;;OAGG;YACW,qBAAqB;IAoDnC;;;OAGG;YACW,6BAA6B;IAc3C;;OAEG;YACW,iBAAiB;IAgB/B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAW/B;;OAEG;YACW,eAAe;IA+C7B;;;;;;;;;;;;;;OAcG;YACW,kCAAkC;IAqDhD;;;;;;;;;;;;;;;;;;;;OAoBG;YACW,qBAAqB;IAuCnC;;;;;;OAMG;YACW,qBAAqB;IAoBnC;;;;;OAKG;YACW,aAAa;IAgB3B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;;;;;;OAOG;YACW,sBAAsB;IA0BpC;;;;;;;;;;;;;;;OAeG;YACW,qBAAqB;IAYnC;;;OAGG;YACW,QAAQ;IAQtB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;;OAIG;YACW,gBAAgB;IAqB9B;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAiDlC;;;;;;;;;;;;;;;;;;;OAmBG;YACW,2BAA2B;IAqBzC;;;;;;;;;OASG;YACW,gBAAgB;IAoC9B;;;;;;;;OAQG;YACW,iBAAiB;IA0B/B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;YACW,cAAc;IA+E5B;;;;;;;;;;;OAWG;YACW,uBAAuB;IAqCrC;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;;;;;OASG;YACW,kBAAkB;IAoDhC;;;;;;;;;;;;;;OAcG;YACW,mBAAmB;IAsGjC;;;;;;;;;;;;;OAaG;YACW,0BAA0B;IAaxC;;;;;;;;;;;;;;;;OAgBG;YACW,gCAAgC;IAoB9C;;;;;;;;;;;;;;;;;;;OAmBG;YACW,iCAAiC;IA8B/C;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;IAKrC;;;OAGG;YACW,kBAAkB;IAuBhC;;;;;;;OAOG;YACW,gBAAgB;IAuD9B;;;;;;;OAOG;IACH,OAAO,CAAC,0BAA0B;IAelC;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,iBAAiB;IA+BzB;;;;;;OAMG;IACH,OAAO,CAAC,OAAO;IAaf;;;;;;OAMG;YACW,qBAAqB;IAyBnC;;;;OAIG;YACW,QAAQ;IAatB;;;OAGG;IACH,OAAO,CAAC,cAAc;IA+BtB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAKlB;;;OAGG;IACH,OAAO,CAAC,SAAS;IAmDjB;;OAEG;YACW,mBAAmB;IAajC;;OAEG;YACW,gBAAgB;IA+B9B;;OAEG;IACH,OAAO,CAAC,WAAW;IA4BnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAgB1B;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqCxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAyCvB;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB;IAoBxB;;;;;;;OAOG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAezB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAazB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;;;;OAKG;YACW,WAAW;IAQzB;;;;;OAKG;YACW,qBAAqB;CAqDpC"}
|
package/dist/core/lisa.js
CHANGED
|
@@ -53,6 +53,15 @@ export class Lisa {
|
|
|
53
53
|
* back to the silence this exists to end.
|
|
54
54
|
*/
|
|
55
55
|
stalePaths = [];
|
|
56
|
+
/**
|
|
57
|
+
* Lisa-owned artifacts this apply deliberately did not replace, each with the
|
|
58
|
+
* reason spelled out for whoever reads the output.
|
|
59
|
+
*
|
|
60
|
+
* Full sentences rather than paths, because this is the one outcome an
|
|
61
|
+
* operator cannot act on from the filename: "we left yours alone because it
|
|
62
|
+
* defends something ours does not" is the entire message.
|
|
63
|
+
*/
|
|
64
|
+
hostAheadNotes = [];
|
|
56
65
|
detectedTypes = [];
|
|
57
66
|
ignorePatterns = {
|
|
58
67
|
patterns: [],
|
|
@@ -1489,6 +1498,10 @@ export class Lisa {
|
|
|
1489
1498
|
this.counters.stale++;
|
|
1490
1499
|
this.stalePaths.push(result.relativePath);
|
|
1491
1500
|
break;
|
|
1501
|
+
case "host-ahead":
|
|
1502
|
+
this.counters.hostAhead++;
|
|
1503
|
+
this.hostAheadNotes.push(result.note ?? `${result.relativePath}: kept your copy.`);
|
|
1504
|
+
break;
|
|
1492
1505
|
case "overwritten":
|
|
1493
1506
|
this.counters.overwritten++;
|
|
1494
1507
|
break;
|
|
@@ -1529,6 +1542,11 @@ export class Lisa {
|
|
|
1529
1542
|
? `Out of date, would not be updated: ${result.relativePath}`
|
|
1530
1543
|
: `Out of date, not updated: ${result.relativePath}`);
|
|
1531
1544
|
break;
|
|
1545
|
+
case "host-ahead":
|
|
1546
|
+
this.deps.logger.warn(this.config.dryRun
|
|
1547
|
+
? `Would keep your copy: ${result.relativePath}`
|
|
1548
|
+
: `Kept your copy: ${result.relativePath}`);
|
|
1549
|
+
break;
|
|
1532
1550
|
case "overwritten":
|
|
1533
1551
|
this.logMessage(`Would prompt to overwrite: ${result.relativePath}`, `Overwritten: ${result.relativePath}`);
|
|
1534
1552
|
break;
|
|
@@ -1669,6 +1687,7 @@ export class Lisa {
|
|
|
1669
1687
|
this.printStatLine("Would ignore: ", ignored, pc.magenta, this.lisaignoreSuffix);
|
|
1670
1688
|
}
|
|
1671
1689
|
this.printStaleDetail();
|
|
1690
|
+
this.printHostAheadDetail();
|
|
1672
1691
|
}
|
|
1673
1692
|
/**
|
|
1674
1693
|
* Print summary statistics for apply mode
|
|
@@ -1690,6 +1709,7 @@ export class Lisa {
|
|
|
1690
1709
|
this.printStatLine("Ignored: ", ignored, pc.magenta, this.lisaignoreSuffix);
|
|
1691
1710
|
}
|
|
1692
1711
|
this.printStaleDetail();
|
|
1712
|
+
this.printHostAheadDetail();
|
|
1693
1713
|
}
|
|
1694
1714
|
/**
|
|
1695
1715
|
* Name the out-of-date managed files and say how to update them.
|
|
@@ -1712,6 +1732,24 @@ export class Lisa {
|
|
|
1712
1732
|
logger.info("A non-interactive apply will not replace a file your project may have customised.");
|
|
1713
1733
|
logger.info("Review the differences and run `lisa apply .` interactively to take them, or add paths to .lisaignore to keep yours.");
|
|
1714
1734
|
}
|
|
1735
|
+
/**
|
|
1736
|
+
* Report Lisa-owned artifacts this apply chose not to replace.
|
|
1737
|
+
*
|
|
1738
|
+
* Reported as good news, not as a warning about the project: keeping a guard
|
|
1739
|
+
* that is stronger than Lisa's is the correct outcome, and phrasing it as a
|
|
1740
|
+
* problem would push an operator to "fix" it by discarding their own
|
|
1741
|
+
* hardening — the exact loss the check exists to prevent.
|
|
1742
|
+
*/
|
|
1743
|
+
printHostAheadDetail() {
|
|
1744
|
+
if (this.counters.hostAhead === 0)
|
|
1745
|
+
return;
|
|
1746
|
+
const { logger } = this.deps;
|
|
1747
|
+
logger.info(`${this.counters.hostAhead} Lisa-owned file(s) look stronger in your project than in Lisa, so your version was kept:`);
|
|
1748
|
+
for (const note of this.hostAheadNotes) {
|
|
1749
|
+
logger.info(` ${note}`);
|
|
1750
|
+
}
|
|
1751
|
+
logger.info("Nothing is broken. Lisa only replaces one of its own files when it can prove your copy came from an older Lisa.");
|
|
1752
|
+
}
|
|
1715
1753
|
/**
|
|
1716
1754
|
* Print summary statistics
|
|
1717
1755
|
*/
|