@codyswann/lisa 4.21.3 → 4.21.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/upstream-evidence-manifest.js +4 -4
- package/package.json +2 -2
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +17 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-remote-env/assets/session-start.sh +13 -3
- package/plugins/lisa/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +17 -2
- package/plugins/lisa/skills/lisa-setup-remote-env/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-setup-remote-env/assets/session-start.sh +13 -3
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +17 -2
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-setup-remote-env/assets/session-start.sh +13 -3
- 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/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +17 -2
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-setup-remote-env/assets/session-start.sh +13 -3
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +17 -2
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-setup-remote-env/assets/session-start.sh +13 -3
- 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/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs +17 -2
- package/plugins/src/base/skills/lisa-setup-remote-env/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh +13 -3
- package/scripts/lisa-remote-env/session-start.sh +13 -3
|
@@ -655,7 +655,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
655
655
|
"plugins/src/base/skills/lisa-secrets-access/scripts/preflight-secrets.mjs": "98a0a541041d543fe91e6260da4a25e383123a0eb40bad32a4d59551b7da8db8",
|
|
656
656
|
"plugins/src/base/skills/lisa-secrets-access/scripts/prompt-secret.mjs": "22b28bcdf49b9b0fcd1b15639e031655efacc028b74d48d57e2275f3e1557508",
|
|
657
657
|
"plugins/src/base/skills/lisa-secrets-access/scripts/providers.mjs": "bc0c75528f82f92478b10d75c9c60349c50160594255f5bafd7bfc03e8a54fee",
|
|
658
|
-
"plugins/src/base/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs": "
|
|
658
|
+
"plugins/src/base/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs": "69a614f2bdb7a169dc19561457fc09fb45402d4617e9802004243aeb74abd1db",
|
|
659
659
|
"plugins/src/base/skills/lisa-secrets-access/scripts/read-secret-note.mjs": "735434e25bf1db9f2f7eb3d5ede8361cba01b922d65931393bd36e6f96531654",
|
|
660
660
|
"plugins/src/base/skills/lisa-secrets-access/scripts/resolve-secret.mjs": "4170220c95f410072f3871f58938b7575684254480d0645e3dbb1535cf09d7a7",
|
|
661
661
|
"plugins/src/base/skills/lisa-secrets-access/scripts/rotate-secret.mjs": "adada60f766760395858c69ef784654e9e096943485ed237c395c8fc2ca8e20f",
|
|
@@ -680,8 +680,8 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
680
680
|
"plugins/src/base/skills/lisa-setup-local-env/scripts/local-env.mjs": "6f3713451139d9d4fd8eed8f11f49e472667394c4f9a7cae63897b7702115687",
|
|
681
681
|
"plugins/src/base/skills/lisa-setup-notion/SKILL.md": "63b6a86a85adfbbb389f18ab228883b760a4560d5ed71ac4bc7023c868a59143",
|
|
682
682
|
"plugins/src/base/skills/lisa-setup-remote-aws/SKILL.md": "46b53201c9bcb68b6fa51f220e34b10ec1d5ba4cfc1d471d9e9595db2550d72b",
|
|
683
|
-
"plugins/src/base/skills/lisa-setup-remote-env/SKILL.md": "
|
|
684
|
-
"plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh": "
|
|
683
|
+
"plugins/src/base/skills/lisa-setup-remote-env/SKILL.md": "a753f7c8b413339ee7d4383f87239fae04b75f7dd41e18d9afbcf307c521e363",
|
|
684
|
+
"plugins/src/base/skills/lisa-setup-remote-env/assets/session-start.sh": "862f8096585bfa7639dfecd0b3dc69a1218ee7fd740df4851f6f1da09f17a9fe",
|
|
685
685
|
"plugins/src/base/skills/lisa-setup-remote-env/assets/setup.sh": "c30d98a5645f033fc1d3a723043691b9ad997ae5666df539ff6aa19c563431b2",
|
|
686
686
|
"plugins/src/base/skills/lisa-setup-remote-env/scripts/environment.mjs": "3b9be11691d81a896fc779c37fb6d69e8e7222f95e23f84aa03d4e590f9d9108",
|
|
687
687
|
"plugins/src/base/skills/lisa-setup-remote-env/scripts/preflight-tools.mjs": "eb8ee672fbfdb0ab41dde5f17337dae59912f18eafa6f15a05fd203906d16352",
|
|
@@ -1144,7 +1144,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
1144
1144
|
"scripts/lisa-github-repo-setup.sh": "4717873e339b3e615d0bf22b4cb290b3575df5aba8c3639dc0d3bebc23abf651",
|
|
1145
1145
|
"scripts/lisa-github-rulesets.sh": "a5b81fe09266f1daf181b8031c2b73fa0fd6206a9e7299d42eaa12766fbd51fb",
|
|
1146
1146
|
"scripts/lisa-mutation.mjs": "74603e61f493d700318feb862f61ee1653430700b5edf232e70241ccdedac587",
|
|
1147
|
-
"scripts/lisa-remote-env/session-start.sh": "
|
|
1147
|
+
"scripts/lisa-remote-env/session-start.sh": "862f8096585bfa7639dfecd0b3dc69a1218ee7fd740df4851f6f1da09f17a9fe",
|
|
1148
1148
|
"scripts/lisa-remote-env/setup.sh": "c30d98a5645f033fc1d3a723043691b9ad997ae5666df539ff6aa19c563431b2",
|
|
1149
1149
|
"scripts/lisa-ruleset-payload.mjs": "3e10b5a4c113e3aa895c6a09f063045eb198dbdabb11a00be87bea1477c91fbb",
|
|
1150
1150
|
"scripts/lisa-ruleset-reach.mjs": "e51b12092062379e7317b368c89a789e2067ec302388e557ea84a29a35ffc238",
|
package/package.json
CHANGED
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
"zod-validation-error": "^4.0.0"
|
|
160
160
|
},
|
|
161
161
|
"name": "@codyswann/lisa",
|
|
162
|
-
"version": "4.21.
|
|
162
|
+
"version": "4.21.5",
|
|
163
163
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
164
164
|
"main": "dist/index.js",
|
|
165
165
|
"exports": {
|
|
@@ -298,5 +298,5 @@
|
|
|
298
298
|
"vite": "^8.0.16"
|
|
299
299
|
},
|
|
300
300
|
"type": "module",
|
|
301
|
-
"lisaReleaseCommit": "
|
|
301
|
+
"lisaReleaseCommit": "3058845dd698f4d6fd2bb7356825d96f65e008ce"
|
|
302
302
|
}
|
package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/publish-aws-bootstrap.mjs
CHANGED
|
@@ -126,6 +126,10 @@ export function candidateAwsEnvironment(bundle) {
|
|
|
126
126
|
env.AWS_SECRET_ACCESS_KEY = String(
|
|
127
127
|
bundle.secretAccessKey ?? bundle.aws_secret_access_key
|
|
128
128
|
);
|
|
129
|
+
// STS verification must reach AWS, not an endpoint inherited from the host.
|
|
130
|
+
// A redirected endpoint could otherwise answer the probe and turn a green
|
|
131
|
+
// result into evidence about a local emulator or an attacker-controlled URL.
|
|
132
|
+
env.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS = "true";
|
|
129
133
|
env.AWS_PAGER = "";
|
|
130
134
|
return env;
|
|
131
135
|
}
|
|
@@ -228,12 +232,17 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
228
232
|
* Restore the previous provider value and prove the restoration.
|
|
229
233
|
* @param {object} cfg Resolved configuration.
|
|
230
234
|
* @param {{id: string, value: string}} previous Previous entry.
|
|
235
|
+
* @param {string} candidateRaw Exact value written by this publication.
|
|
231
236
|
* @param {Function} fetch Provider reader.
|
|
232
237
|
* @param {Function} write Provider writer.
|
|
233
238
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
234
239
|
*/
|
|
235
|
-
function rollback(cfg, previous, fetch, write) {
|
|
240
|
+
function rollback(cfg, previous, candidateRaw, fetch, write) {
|
|
236
241
|
try {
|
|
242
|
+
const current = currentEntry(cfg, fetch);
|
|
243
|
+
if (current.value !== candidateRaw) {
|
|
244
|
+
return "rollback skipped because the provider changed after this publication";
|
|
245
|
+
}
|
|
237
246
|
write(cfg, previous.id, previous.value);
|
|
238
247
|
const restored = currentEntry(cfg, fetch);
|
|
239
248
|
if (restored.value !== previous.value) {
|
|
@@ -288,7 +297,13 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
288
297
|
} catch (error) {
|
|
289
298
|
const reason =
|
|
290
299
|
error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
291
|
-
const rollbackOutcome = rollback(
|
|
300
|
+
const rollbackOutcome = rollback(
|
|
301
|
+
cfg,
|
|
302
|
+
previous,
|
|
303
|
+
candidate.raw,
|
|
304
|
+
fetch,
|
|
305
|
+
write
|
|
306
|
+
);
|
|
292
307
|
throw new Error(
|
|
293
308
|
`${BOOTSTRAP_KEY} publication failed: ${reason}; ${rollbackOutcome}`
|
|
294
309
|
);
|
|
@@ -97,7 +97,7 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
|
|
|
97
97
|
A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
|
|
98
98
|
|
|
99
99
|
```sh
|
|
100
|
-
bash scripts/lisa-remote-env/session-start.sh # guard;
|
|
100
|
+
bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|
|
@@ -126,6 +126,10 @@ export function candidateAwsEnvironment(bundle) {
|
|
|
126
126
|
env.AWS_SECRET_ACCESS_KEY = String(
|
|
127
127
|
bundle.secretAccessKey ?? bundle.aws_secret_access_key
|
|
128
128
|
);
|
|
129
|
+
// STS verification must reach AWS, not an endpoint inherited from the host.
|
|
130
|
+
// A redirected endpoint could otherwise answer the probe and turn a green
|
|
131
|
+
// result into evidence about a local emulator or an attacker-controlled URL.
|
|
132
|
+
env.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS = "true";
|
|
129
133
|
env.AWS_PAGER = "";
|
|
130
134
|
return env;
|
|
131
135
|
}
|
|
@@ -228,12 +232,17 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
228
232
|
* Restore the previous provider value and prove the restoration.
|
|
229
233
|
* @param {object} cfg Resolved configuration.
|
|
230
234
|
* @param {{id: string, value: string}} previous Previous entry.
|
|
235
|
+
* @param {string} candidateRaw Exact value written by this publication.
|
|
231
236
|
* @param {Function} fetch Provider reader.
|
|
232
237
|
* @param {Function} write Provider writer.
|
|
233
238
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
234
239
|
*/
|
|
235
|
-
function rollback(cfg, previous, fetch, write) {
|
|
240
|
+
function rollback(cfg, previous, candidateRaw, fetch, write) {
|
|
236
241
|
try {
|
|
242
|
+
const current = currentEntry(cfg, fetch);
|
|
243
|
+
if (current.value !== candidateRaw) {
|
|
244
|
+
return "rollback skipped because the provider changed after this publication";
|
|
245
|
+
}
|
|
237
246
|
write(cfg, previous.id, previous.value);
|
|
238
247
|
const restored = currentEntry(cfg, fetch);
|
|
239
248
|
if (restored.value !== previous.value) {
|
|
@@ -288,7 +297,13 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
288
297
|
} catch (error) {
|
|
289
298
|
const reason =
|
|
290
299
|
error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
291
|
-
const rollbackOutcome = rollback(
|
|
300
|
+
const rollbackOutcome = rollback(
|
|
301
|
+
cfg,
|
|
302
|
+
previous,
|
|
303
|
+
candidate.raw,
|
|
304
|
+
fetch,
|
|
305
|
+
write
|
|
306
|
+
);
|
|
292
307
|
throw new Error(
|
|
293
308
|
`${BOOTSTRAP_KEY} publication failed: ${reason}; ${rollbackOutcome}`
|
|
294
309
|
);
|
|
@@ -97,7 +97,7 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
|
|
|
97
97
|
A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
|
|
98
98
|
|
|
99
99
|
```sh
|
|
100
|
-
bash scripts/lisa-remote-env/session-start.sh # guard;
|
|
100
|
+
bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|
|
@@ -126,6 +126,10 @@ export function candidateAwsEnvironment(bundle) {
|
|
|
126
126
|
env.AWS_SECRET_ACCESS_KEY = String(
|
|
127
127
|
bundle.secretAccessKey ?? bundle.aws_secret_access_key
|
|
128
128
|
);
|
|
129
|
+
// STS verification must reach AWS, not an endpoint inherited from the host.
|
|
130
|
+
// A redirected endpoint could otherwise answer the probe and turn a green
|
|
131
|
+
// result into evidence about a local emulator or an attacker-controlled URL.
|
|
132
|
+
env.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS = "true";
|
|
129
133
|
env.AWS_PAGER = "";
|
|
130
134
|
return env;
|
|
131
135
|
}
|
|
@@ -228,12 +232,17 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
228
232
|
* Restore the previous provider value and prove the restoration.
|
|
229
233
|
* @param {object} cfg Resolved configuration.
|
|
230
234
|
* @param {{id: string, value: string}} previous Previous entry.
|
|
235
|
+
* @param {string} candidateRaw Exact value written by this publication.
|
|
231
236
|
* @param {Function} fetch Provider reader.
|
|
232
237
|
* @param {Function} write Provider writer.
|
|
233
238
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
234
239
|
*/
|
|
235
|
-
function rollback(cfg, previous, fetch, write) {
|
|
240
|
+
function rollback(cfg, previous, candidateRaw, fetch, write) {
|
|
236
241
|
try {
|
|
242
|
+
const current = currentEntry(cfg, fetch);
|
|
243
|
+
if (current.value !== candidateRaw) {
|
|
244
|
+
return "rollback skipped because the provider changed after this publication";
|
|
245
|
+
}
|
|
237
246
|
write(cfg, previous.id, previous.value);
|
|
238
247
|
const restored = currentEntry(cfg, fetch);
|
|
239
248
|
if (restored.value !== previous.value) {
|
|
@@ -288,7 +297,13 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
288
297
|
} catch (error) {
|
|
289
298
|
const reason =
|
|
290
299
|
error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
291
|
-
const rollbackOutcome = rollback(
|
|
300
|
+
const rollbackOutcome = rollback(
|
|
301
|
+
cfg,
|
|
302
|
+
previous,
|
|
303
|
+
candidate.raw,
|
|
304
|
+
fetch,
|
|
305
|
+
write
|
|
306
|
+
);
|
|
292
307
|
throw new Error(
|
|
293
308
|
`${BOOTSTRAP_KEY} publication failed: ${reason}; ${rollbackOutcome}`
|
|
294
309
|
);
|
|
@@ -97,7 +97,7 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
|
|
|
97
97
|
A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
|
|
98
98
|
|
|
99
99
|
```sh
|
|
100
|
-
bash scripts/lisa-remote-env/session-start.sh # guard;
|
|
100
|
+
bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|
|
@@ -126,6 +126,10 @@ export function candidateAwsEnvironment(bundle) {
|
|
|
126
126
|
env.AWS_SECRET_ACCESS_KEY = String(
|
|
127
127
|
bundle.secretAccessKey ?? bundle.aws_secret_access_key
|
|
128
128
|
);
|
|
129
|
+
// STS verification must reach AWS, not an endpoint inherited from the host.
|
|
130
|
+
// A redirected endpoint could otherwise answer the probe and turn a green
|
|
131
|
+
// result into evidence about a local emulator or an attacker-controlled URL.
|
|
132
|
+
env.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS = "true";
|
|
129
133
|
env.AWS_PAGER = "";
|
|
130
134
|
return env;
|
|
131
135
|
}
|
|
@@ -228,12 +232,17 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
228
232
|
* Restore the previous provider value and prove the restoration.
|
|
229
233
|
* @param {object} cfg Resolved configuration.
|
|
230
234
|
* @param {{id: string, value: string}} previous Previous entry.
|
|
235
|
+
* @param {string} candidateRaw Exact value written by this publication.
|
|
231
236
|
* @param {Function} fetch Provider reader.
|
|
232
237
|
* @param {Function} write Provider writer.
|
|
233
238
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
234
239
|
*/
|
|
235
|
-
function rollback(cfg, previous, fetch, write) {
|
|
240
|
+
function rollback(cfg, previous, candidateRaw, fetch, write) {
|
|
236
241
|
try {
|
|
242
|
+
const current = currentEntry(cfg, fetch);
|
|
243
|
+
if (current.value !== candidateRaw) {
|
|
244
|
+
return "rollback skipped because the provider changed after this publication";
|
|
245
|
+
}
|
|
237
246
|
write(cfg, previous.id, previous.value);
|
|
238
247
|
const restored = currentEntry(cfg, fetch);
|
|
239
248
|
if (restored.value !== previous.value) {
|
|
@@ -288,7 +297,13 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
288
297
|
} catch (error) {
|
|
289
298
|
const reason =
|
|
290
299
|
error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
291
|
-
const rollbackOutcome = rollback(
|
|
300
|
+
const rollbackOutcome = rollback(
|
|
301
|
+
cfg,
|
|
302
|
+
previous,
|
|
303
|
+
candidate.raw,
|
|
304
|
+
fetch,
|
|
305
|
+
write
|
|
306
|
+
);
|
|
292
307
|
throw new Error(
|
|
293
308
|
`${BOOTSTRAP_KEY} publication failed: ${reason}; ${rollbackOutcome}`
|
|
294
309
|
);
|
|
@@ -97,7 +97,7 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
|
|
|
97
97
|
A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
|
|
98
98
|
|
|
99
99
|
```sh
|
|
100
|
-
bash scripts/lisa-remote-env/session-start.sh # guard;
|
|
100
|
+
bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|
|
@@ -126,6 +126,10 @@ export function candidateAwsEnvironment(bundle) {
|
|
|
126
126
|
env.AWS_SECRET_ACCESS_KEY = String(
|
|
127
127
|
bundle.secretAccessKey ?? bundle.aws_secret_access_key
|
|
128
128
|
);
|
|
129
|
+
// STS verification must reach AWS, not an endpoint inherited from the host.
|
|
130
|
+
// A redirected endpoint could otherwise answer the probe and turn a green
|
|
131
|
+
// result into evidence about a local emulator or an attacker-controlled URL.
|
|
132
|
+
env.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS = "true";
|
|
129
133
|
env.AWS_PAGER = "";
|
|
130
134
|
return env;
|
|
131
135
|
}
|
|
@@ -228,12 +232,17 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
228
232
|
* Restore the previous provider value and prove the restoration.
|
|
229
233
|
* @param {object} cfg Resolved configuration.
|
|
230
234
|
* @param {{id: string, value: string}} previous Previous entry.
|
|
235
|
+
* @param {string} candidateRaw Exact value written by this publication.
|
|
231
236
|
* @param {Function} fetch Provider reader.
|
|
232
237
|
* @param {Function} write Provider writer.
|
|
233
238
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
234
239
|
*/
|
|
235
|
-
function rollback(cfg, previous, fetch, write) {
|
|
240
|
+
function rollback(cfg, previous, candidateRaw, fetch, write) {
|
|
236
241
|
try {
|
|
242
|
+
const current = currentEntry(cfg, fetch);
|
|
243
|
+
if (current.value !== candidateRaw) {
|
|
244
|
+
return "rollback skipped because the provider changed after this publication";
|
|
245
|
+
}
|
|
237
246
|
write(cfg, previous.id, previous.value);
|
|
238
247
|
const restored = currentEntry(cfg, fetch);
|
|
239
248
|
if (restored.value !== previous.value) {
|
|
@@ -288,7 +297,13 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
288
297
|
} catch (error) {
|
|
289
298
|
const reason =
|
|
290
299
|
error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
291
|
-
const rollbackOutcome = rollback(
|
|
300
|
+
const rollbackOutcome = rollback(
|
|
301
|
+
cfg,
|
|
302
|
+
previous,
|
|
303
|
+
candidate.raw,
|
|
304
|
+
fetch,
|
|
305
|
+
write
|
|
306
|
+
);
|
|
292
307
|
throw new Error(
|
|
293
308
|
`${BOOTSTRAP_KEY} publication failed: ${reason}; ${rollbackOutcome}`
|
|
294
309
|
);
|
|
@@ -97,7 +97,7 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
|
|
|
97
97
|
A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
|
|
98
98
|
|
|
99
99
|
```sh
|
|
100
|
-
bash scripts/lisa-remote-env/session-start.sh # guard;
|
|
100
|
+
bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.21.
|
|
3
|
+
"version": "4.21.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.21.
|
|
3
|
+
"version": "4.21.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.21.
|
|
3
|
+
"version": "4.21.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.21.
|
|
3
|
+
"version": "4.21.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.21.
|
|
3
|
+
"version": "4.21.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -126,6 +126,10 @@ export function candidateAwsEnvironment(bundle) {
|
|
|
126
126
|
env.AWS_SECRET_ACCESS_KEY = String(
|
|
127
127
|
bundle.secretAccessKey ?? bundle.aws_secret_access_key
|
|
128
128
|
);
|
|
129
|
+
// STS verification must reach AWS, not an endpoint inherited from the host.
|
|
130
|
+
// A redirected endpoint could otherwise answer the probe and turn a green
|
|
131
|
+
// result into evidence about a local emulator or an attacker-controlled URL.
|
|
132
|
+
env.AWS_IGNORE_CONFIGURED_ENDPOINT_URLS = "true";
|
|
129
133
|
env.AWS_PAGER = "";
|
|
130
134
|
return env;
|
|
131
135
|
}
|
|
@@ -228,12 +232,17 @@ export function preflightAwsBootstrap(cfg, operations = {}) {
|
|
|
228
232
|
* Restore the previous provider value and prove the restoration.
|
|
229
233
|
* @param {object} cfg Resolved configuration.
|
|
230
234
|
* @param {{id: string, value: string}} previous Previous entry.
|
|
235
|
+
* @param {string} candidateRaw Exact value written by this publication.
|
|
231
236
|
* @param {Function} fetch Provider reader.
|
|
232
237
|
* @param {Function} write Provider writer.
|
|
233
238
|
* @returns {string} Human-readable rollback outcome with no secret material.
|
|
234
239
|
*/
|
|
235
|
-
function rollback(cfg, previous, fetch, write) {
|
|
240
|
+
function rollback(cfg, previous, candidateRaw, fetch, write) {
|
|
236
241
|
try {
|
|
242
|
+
const current = currentEntry(cfg, fetch);
|
|
243
|
+
if (current.value !== candidateRaw) {
|
|
244
|
+
return "rollback skipped because the provider changed after this publication";
|
|
245
|
+
}
|
|
237
246
|
write(cfg, previous.id, previous.value);
|
|
238
247
|
const restored = currentEntry(cfg, fetch);
|
|
239
248
|
if (restored.value !== previous.value) {
|
|
@@ -288,7 +297,13 @@ export function publishAwsBootstrap(raw, cfg, operations = {}) {
|
|
|
288
297
|
} catch (error) {
|
|
289
298
|
const reason =
|
|
290
299
|
error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
291
|
-
const rollbackOutcome = rollback(
|
|
300
|
+
const rollbackOutcome = rollback(
|
|
301
|
+
cfg,
|
|
302
|
+
previous,
|
|
303
|
+
candidate.raw,
|
|
304
|
+
fetch,
|
|
305
|
+
write
|
|
306
|
+
);
|
|
292
307
|
throw new Error(
|
|
293
308
|
`${BOOTSTRAP_KEY} publication failed: ${reason}; ${rollbackOutcome}`
|
|
294
309
|
);
|
|
@@ -97,7 +97,7 @@ A surface that **re-runs this script when a container resumes** — Codex Cloud
|
|
|
97
97
|
A surface that **skips this script whenever a filesystem cache exists** — Claude Code web — must not. Materializing here would write the values once and then never refresh them, so a credential rotated on Tuesday would still be serving Monday's value until the cache expired days later. Those surfaces materialize from a session-start hook instead, which runs every session including a resumed one:
|
|
98
98
|
|
|
99
99
|
```sh
|
|
100
|
-
bash scripts/lisa-remote-env/session-start.sh # guard;
|
|
100
|
+
bash scripts/lisa-remote-env/session-start.sh # guard; reruns toolchain, secrets, then hook
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
The selection comes from the surface's `materializeAt` capability in `lisa-secrets-access`, not from its name, so adding a surface does not mean editing a branch. The hook is committed to the repository, so it also fires on a developer's machine — it exits `0` immediately there rather than failing, because a correct local session must not look broken.
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|
|
@@ -41,7 +41,17 @@ here="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
|
|
|
41
41
|
# of --version calls and nothing else.
|
|
42
42
|
#
|
|
43
43
|
# Before secrets, because materializing needs the provider CLI that this step
|
|
44
|
-
# installs. A failure here
|
|
45
|
-
# a missing credential when the real fault was a missing binary.
|
|
44
|
+
# installs. A failure here terminates this hook for the same reason: continuing
|
|
45
|
+
# would report a missing credential when the real fault was a missing binary.
|
|
46
|
+
# SessionStart hosts are fail-open, so they surface that result and still allow
|
|
47
|
+
# the agent session to continue.
|
|
46
48
|
bash "${here}/setup.sh" --phase=toolchain "$@"
|
|
47
|
-
|
|
49
|
+
bash "${here}/setup.sh" --phase=secrets "$@"
|
|
50
|
+
|
|
51
|
+
# A project hook is part of the remote toolchain contract too. It covers tools
|
|
52
|
+
# that cannot be expressed by the pinned manifest, so skipping it on a cached
|
|
53
|
+
# session can leave fresh credentials with no client capable of using them.
|
|
54
|
+
# Run it last, matching the full setup order, and exec so its failure becomes
|
|
55
|
+
# the SessionStart result the host can surface. SessionStart remains fail-open;
|
|
56
|
+
# this reports an incomplete bootstrap but does not block the agent session.
|
|
57
|
+
exec bash "${here}/setup.sh" --phase=hook "$@"
|