@codyswann/lisa 4.84.6 → 4.84.7
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/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +7 -3
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/block-host-name-leak.mjs +25 -13
- package/plugins/lisa/hooks/host-name-command-context.mjs +16 -4
- package/plugins/lisa-agy/hooks/block-host-name-leak.mjs +25 -13
- package/plugins/lisa-agy/hooks/host-name-command-context.mjs +16 -4
- 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-cdk-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/block-host-name-leak.mjs +25 -13
- package/plugins/lisa-copilot/hooks/host-name-command-context.mjs +16 -4
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-host-name-leak.mjs +25 -13
- package/plugins/lisa-cursor/hooks/host-name-command-context.mjs +16 -4
- package/plugins/lisa-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/lisa-devin/hooks/block-host-name-leak.mjs +25 -13
- package/plugins/lisa-devin/hooks/host-name-command-context.mjs +16 -4
- 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-expo-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-devin/.devin-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-harper-fabric-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-devin/.devin-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-nestjs-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-devin/.devin-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-openclaw-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-devin/.devin-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-phaser-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-devin/.devin-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-rails-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-devin/.devin-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-typescript-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-devin/.devin-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/lisa-wiki-devin/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-devin/.devin-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/block-host-name-leak.mjs +25 -13
- package/plugins/src/base/hooks/host-name-command-context.mjs +16 -4
- package/scripts/lib/host-name-expanded-command-cases.mjs +286 -0
- package/scripts/lib/host-name-field-occurrence-cases.mjs +60 -0
- package/scripts/verify-host-name-target-scope.mjs +27 -1
|
@@ -103,6 +103,7 @@ function words(command) {
|
|
|
103
103
|
*/
|
|
104
104
|
function argumentsOf(input) {
|
|
105
105
|
const flags = new Map(),
|
|
106
|
+
fieldOccurrences = [],
|
|
106
107
|
positional = [],
|
|
107
108
|
tokens = [];
|
|
108
109
|
// Any expansion can add/replace routing arguments after shell word splitting.
|
|
@@ -139,23 +140,34 @@ function argumentsOf(input) {
|
|
|
139
140
|
flag === "-R" ? "--repo" : flag === "-X" ? "--method" : flag,
|
|
140
141
|
value
|
|
141
142
|
);
|
|
143
|
+
// API fields are additive even though routing options use last values.
|
|
144
|
+
if (FIELD_FLAGS.has(flag)) fieldOccurrences.push([flag, value]);
|
|
142
145
|
tokens.push(value.value);
|
|
143
146
|
} else if (!word.value.startsWith("-")) positional.push(word);
|
|
144
147
|
else if (!word.literal) certain = false;
|
|
145
148
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
149
|
+
const nounWord = positional[0],
|
|
150
|
+
verbWord = positional[1];
|
|
151
|
+
const noun = nounWord?.literal ? nounWord.value : undefined,
|
|
152
|
+
verb = verbWord?.value;
|
|
153
|
+
// Command-name expansions can supply several argv words. A following
|
|
154
|
+
// read-looking literal does not prove that the expanded command is a read.
|
|
155
|
+
const uncertainName =
|
|
156
|
+
nounWord?.literal === false ||
|
|
157
|
+
(["issue", "pr"].includes(noun) && verbWord?.literal === false);
|
|
148
158
|
const method = flags.get("--method");
|
|
149
159
|
const writes =
|
|
150
|
-
|
|
160
|
+
uncertainName ||
|
|
161
|
+
(noun === "api"
|
|
151
162
|
? method
|
|
152
163
|
? !method.literal || METHODS.has(method.value.toUpperCase())
|
|
153
164
|
: [...FIELD_FLAGS].some(flag => flags.has(flag)) ||
|
|
154
165
|
Boolean(flags.get("--input")?.value)
|
|
155
166
|
: ["issue", "pr"].includes(noun) &&
|
|
156
|
-
["create", "comment", "edit"].includes(verb);
|
|
167
|
+
["create", "comment", "edit"].includes(verb));
|
|
157
168
|
return {
|
|
158
169
|
flags,
|
|
170
|
+
fieldOccurrences,
|
|
159
171
|
positional,
|
|
160
172
|
tokens: ["gh", ...tokens],
|
|
161
173
|
noun,
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/** Direct expanded command-name regressions; all identities are synthetic. */
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { boundedExecFileSync } from "./bounded-spawn.mjs";
|
|
4
|
+
|
|
5
|
+
/** @param {object} context Isolated actual-wrapper fixtures. @returns {Array[]} Named cases. */
|
|
6
|
+
export function hostNameExpandedCommandCases(context) {
|
|
7
|
+
const { lisaCwd, unknownCwd, hostCwd, lisa, host, fixtureName, body } =
|
|
8
|
+
context;
|
|
9
|
+
const cases = [];
|
|
10
|
+
for (const [target, cwd, repo] of [
|
|
11
|
+
["protected", lisaCwd, ` --repo ${lisa}`],
|
|
12
|
+
["unknown", unknownCwd, ""],
|
|
13
|
+
]) {
|
|
14
|
+
for (const [name, noun] of [
|
|
15
|
+
["unquoted", "$N"],
|
|
16
|
+
["double quoted", '"$N"'],
|
|
17
|
+
["braced", '"${N}"'],
|
|
18
|
+
["concatenated", 'is"$SUFFIX"'],
|
|
19
|
+
]) {
|
|
20
|
+
cases.push([
|
|
21
|
+
`expanded noun ${name} ${target} write`,
|
|
22
|
+
cwd,
|
|
23
|
+
`gh ${noun} create${repo} --body '${fixtureName}'`,
|
|
24
|
+
2,
|
|
25
|
+
]);
|
|
26
|
+
}
|
|
27
|
+
for (const [name, verb] of [
|
|
28
|
+
["unquoted", "$V"],
|
|
29
|
+
["double quoted", '"$V"'],
|
|
30
|
+
["braced", '"${V}"'],
|
|
31
|
+
["concatenated", 'cre"$TAIL"'],
|
|
32
|
+
]) {
|
|
33
|
+
cases.push([
|
|
34
|
+
`expanded verb ${name} ${target} write`,
|
|
35
|
+
cwd,
|
|
36
|
+
`gh issue ${verb}${repo} --body '${fixtureName}'`,
|
|
37
|
+
2,
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
for (const [name, prefix] of [
|
|
41
|
+
["multiple-word noun", "gh $N"],
|
|
42
|
+
["multiple-word verb", "gh issue $V"],
|
|
43
|
+
["noun before read-looking word", "gh $N view"],
|
|
44
|
+
["verb before read-looking word", "gh issue $V view"],
|
|
45
|
+
]) {
|
|
46
|
+
cases.push([
|
|
47
|
+
`expanded ${name} ${target} write`,
|
|
48
|
+
cwd,
|
|
49
|
+
`${prefix}${repo} --body '${fixtureName}'`,
|
|
50
|
+
2,
|
|
51
|
+
]);
|
|
52
|
+
}
|
|
53
|
+
for (const [name, args] of [
|
|
54
|
+
["API field text", `-F body=${fixtureName}`],
|
|
55
|
+
["API field file", `-F body=@${body}`],
|
|
56
|
+
["API attached field file", `-Fbody=@${body}`],
|
|
57
|
+
["API raw field", `-f body=${fixtureName}`],
|
|
58
|
+
["API input file", `--input ${body}`],
|
|
59
|
+
]) {
|
|
60
|
+
cases.push([
|
|
61
|
+
`expanded noun possible ${name} ${target} write`,
|
|
62
|
+
cwd,
|
|
63
|
+
`gh "$N" repos/${lisa}/issues ${args}`,
|
|
64
|
+
2,
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
cases.push(
|
|
68
|
+
[
|
|
69
|
+
`expanded noun issue body-file ${target} write`,
|
|
70
|
+
cwd,
|
|
71
|
+
`gh "$N" create${repo} -F ${body}`,
|
|
72
|
+
2,
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
`expanded both command positions ${target} write`,
|
|
76
|
+
cwd,
|
|
77
|
+
`gh${repo} "$N" "$V" --body '${fixtureName}'`,
|
|
78
|
+
2,
|
|
79
|
+
]
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
cases.push(
|
|
83
|
+
[
|
|
84
|
+
"expanded PR verb protected body-file write",
|
|
85
|
+
lisaCwd,
|
|
86
|
+
`gh pr "$V" --repo ${lisa} --body-file ${body}`,
|
|
87
|
+
2,
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
"expanded PR verb unknown body-file write",
|
|
91
|
+
unknownCwd,
|
|
92
|
+
`gh pr "$V" --body-file ${body}`,
|
|
93
|
+
2,
|
|
94
|
+
],
|
|
95
|
+
[
|
|
96
|
+
"expanded noun literal host flag cannot certify target",
|
|
97
|
+
hostCwd,
|
|
98
|
+
`gh "$N" create --repo ${host} --body '${fixtureName}'`,
|
|
99
|
+
2,
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
"expanded-name API GET prose with dynamic filter control",
|
|
103
|
+
lisaCwd,
|
|
104
|
+
`gh api repos/${lisa}/issues -X GET -F body=${fixtureName} -q "$FILTER"`,
|
|
105
|
+
0,
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
"expanded-name API GET input with dynamic filter control",
|
|
109
|
+
lisaCwd,
|
|
110
|
+
`gh api repos/${lisa}/issues -X GET --input ${body} -q "$FILTER"`,
|
|
111
|
+
0,
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
"expanded-name literal host control",
|
|
115
|
+
hostCwd,
|
|
116
|
+
`gh issue create --repo ${host} --body '${fixtureName}'`,
|
|
117
|
+
0,
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
"expanded-name literal protected control",
|
|
121
|
+
lisaCwd,
|
|
122
|
+
`gh issue create --repo ${lisa} --body '${fixtureName}'`,
|
|
123
|
+
2,
|
|
124
|
+
],
|
|
125
|
+
[
|
|
126
|
+
"expanded-name literal unknown control",
|
|
127
|
+
unknownCwd,
|
|
128
|
+
`gh issue create --body '${fixtureName}'`,
|
|
129
|
+
2,
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
"expanded-name dynamic read filter control",
|
|
133
|
+
lisaCwd,
|
|
134
|
+
`gh issue list --repo ${lisa} --json title --jq "$FILTER"`,
|
|
135
|
+
0,
|
|
136
|
+
],
|
|
137
|
+
[
|
|
138
|
+
"expanded-name dynamic read selector control",
|
|
139
|
+
lisaCwd,
|
|
140
|
+
`gh issue view "$NUMBER" --repo ${lisa} --json title --jq '${fixtureName}'`,
|
|
141
|
+
0,
|
|
142
|
+
],
|
|
143
|
+
[
|
|
144
|
+
"expanded-name API GET dynamic filter control",
|
|
145
|
+
lisaCwd,
|
|
146
|
+
`gh api repos/${lisa}/issues -X GET -q "$FILTER"`,
|
|
147
|
+
0,
|
|
148
|
+
],
|
|
149
|
+
[
|
|
150
|
+
"expanded-name single-quoted noun control",
|
|
151
|
+
lisaCwd,
|
|
152
|
+
`gh '$N' create --repo ${lisa} --body '${fixtureName}'`,
|
|
153
|
+
0,
|
|
154
|
+
],
|
|
155
|
+
[
|
|
156
|
+
"expanded-name single-quoted verb control",
|
|
157
|
+
lisaCwd,
|
|
158
|
+
`gh issue '$V' --repo ${lisa} --body '${fixtureName}'`,
|
|
159
|
+
0,
|
|
160
|
+
],
|
|
161
|
+
[
|
|
162
|
+
"expanded-name escaped noun control",
|
|
163
|
+
lisaCwd,
|
|
164
|
+
`gh \\$N create --repo ${lisa} --body '${fixtureName}'`,
|
|
165
|
+
0,
|
|
166
|
+
],
|
|
167
|
+
[
|
|
168
|
+
"expanded-name quoted non-command control",
|
|
169
|
+
lisaCwd,
|
|
170
|
+
`printf '%s' 'gh $N create --repo ${lisa} --body ${fixtureName}'`,
|
|
171
|
+
0,
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
"expanded-name clean prose control",
|
|
175
|
+
lisaCwd,
|
|
176
|
+
`gh "$N" create --repo ${lisa} --body 'A clean report.'`,
|
|
177
|
+
0,
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
"expanded-name options before noun preserve prose boundaries",
|
|
181
|
+
lisaCwd,
|
|
182
|
+
`gh --repo ${lisa} --title 'view list' "$N" create --body '${fixtureName}'`,
|
|
183
|
+
2,
|
|
184
|
+
],
|
|
185
|
+
[
|
|
186
|
+
"expanded-name literal host API control",
|
|
187
|
+
hostCwd,
|
|
188
|
+
`gh api repos/${host}/issues -F body=${fixtureName}`,
|
|
189
|
+
0,
|
|
190
|
+
]
|
|
191
|
+
);
|
|
192
|
+
return cases;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Establish expansion premises with a Bash function that only prints argv.
|
|
197
|
+
* @param {object} context Synthetic fixtures.
|
|
198
|
+
* @param {object} env Isolated child environment.
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
201
|
+
export function verifyExpandedCommandArgv(context, env) {
|
|
202
|
+
const { lisaCwd, lisa, fixtureName, body } = context;
|
|
203
|
+
const suffix = ` --repo ${lisa} --body '${fixtureName}'`;
|
|
204
|
+
for (const [name, command, values, expected] of [
|
|
205
|
+
[
|
|
206
|
+
"unquoted noun",
|
|
207
|
+
`gh $N create${suffix}`,
|
|
208
|
+
{ N: "issue" },
|
|
209
|
+
["issue", "create", "--repo", lisa, "--body", fixtureName],
|
|
210
|
+
],
|
|
211
|
+
[
|
|
212
|
+
"quoted braced noun",
|
|
213
|
+
`gh "${"${N}"}" create${suffix}`,
|
|
214
|
+
{ N: "issue" },
|
|
215
|
+
["issue", "create", "--repo", lisa, "--body", fixtureName],
|
|
216
|
+
],
|
|
217
|
+
[
|
|
218
|
+
"concatenated noun",
|
|
219
|
+
`gh is"$SUFFIX" create${suffix}`,
|
|
220
|
+
{ SUFFIX: "sue" },
|
|
221
|
+
["issue", "create", "--repo", lisa, "--body", fixtureName],
|
|
222
|
+
],
|
|
223
|
+
[
|
|
224
|
+
"concatenated verb",
|
|
225
|
+
`gh issue cre"$TAIL"${suffix}`,
|
|
226
|
+
{ TAIL: "ate" },
|
|
227
|
+
["issue", "create", "--repo", lisa, "--body", fixtureName],
|
|
228
|
+
],
|
|
229
|
+
[
|
|
230
|
+
"multiword noun before read-looking word",
|
|
231
|
+
`gh $N view${suffix}`,
|
|
232
|
+
{ N: "issue create --title" },
|
|
233
|
+
[
|
|
234
|
+
"issue",
|
|
235
|
+
"create",
|
|
236
|
+
"--title",
|
|
237
|
+
"view",
|
|
238
|
+
"--repo",
|
|
239
|
+
lisa,
|
|
240
|
+
"--body",
|
|
241
|
+
fixtureName,
|
|
242
|
+
],
|
|
243
|
+
],
|
|
244
|
+
[
|
|
245
|
+
"multiword verb before read-looking word",
|
|
246
|
+
`gh issue $V view${suffix}`,
|
|
247
|
+
{ V: "create --title" },
|
|
248
|
+
[
|
|
249
|
+
"issue",
|
|
250
|
+
"create",
|
|
251
|
+
"--title",
|
|
252
|
+
"view",
|
|
253
|
+
"--repo",
|
|
254
|
+
lisa,
|
|
255
|
+
"--body",
|
|
256
|
+
fixtureName,
|
|
257
|
+
],
|
|
258
|
+
],
|
|
259
|
+
[
|
|
260
|
+
"possible API field file",
|
|
261
|
+
`gh "$N" repos/${lisa}/issues -F body=@${body}`,
|
|
262
|
+
{ N: "api" },
|
|
263
|
+
["api", `repos/${lisa}/issues`, "-F", `body=@${body}`],
|
|
264
|
+
],
|
|
265
|
+
]) {
|
|
266
|
+
const argv = boundedExecFileSync(
|
|
267
|
+
"/bin/bash",
|
|
268
|
+
["-c", `gh() { printf '%s\\0' "$@"; }; ${command}`],
|
|
269
|
+
{ cwd: lisaCwd, env: { ...env, ...values }, encoding: "utf8" }
|
|
270
|
+
)
|
|
271
|
+
.split("\0")
|
|
272
|
+
.slice(0, -1);
|
|
273
|
+
assert.deepEqual(argv, expected, name);
|
|
274
|
+
console.log(
|
|
275
|
+
JSON.stringify({
|
|
276
|
+
localExpandedArgvControl: {
|
|
277
|
+
name,
|
|
278
|
+
command,
|
|
279
|
+
argv,
|
|
280
|
+
inspectedTrackerWriteExecuted: false,
|
|
281
|
+
ghImplementation: "Bash argv-only printer",
|
|
282
|
+
},
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Repeated typed API fields must not hide an earlier unresolved prose file. */
|
|
2
|
+
export function hostNameFieldOccurrenceCases({ lisaCwd, lisa, relative }) {
|
|
3
|
+
const prefix = 'cd "$D" && gh',
|
|
4
|
+
endpoint = `repos/${lisa}/issues`,
|
|
5
|
+
clean = `${lisaCwd}/body.md`,
|
|
6
|
+
refusal = "BLOCKED: the working directory";
|
|
7
|
+
const unknown = (name, command) => [name, lisaCwd, command, 2, {}, refusal];
|
|
8
|
+
return [
|
|
9
|
+
unknown(
|
|
10
|
+
"expanded repeated field retains earlier relative prose file",
|
|
11
|
+
`${prefix} "$N" ${endpoint} --field body=@body.md --field title=clean`
|
|
12
|
+
),
|
|
13
|
+
unknown(
|
|
14
|
+
"literal API repeated field retains earlier relative prose file",
|
|
15
|
+
`${prefix} api ${endpoint} --field body=@body.md --field title=clean`
|
|
16
|
+
),
|
|
17
|
+
unknown(
|
|
18
|
+
"literal API repeated F before absolute clean field retains relative file",
|
|
19
|
+
`${prefix} api ${endpoint} -F body=@body.md -F title=@${clean}`
|
|
20
|
+
),
|
|
21
|
+
unknown(
|
|
22
|
+
"expanded repeated F union retains unresolved file control",
|
|
23
|
+
`${prefix} "$N" ${endpoint} -F body=@body.md -F title=@${clean}`
|
|
24
|
+
),
|
|
25
|
+
unknown(
|
|
26
|
+
"expanded repeated field body-last control",
|
|
27
|
+
`${prefix} "$N" ${endpoint} --field title=clean --field body=@body.md`
|
|
28
|
+
),
|
|
29
|
+
[
|
|
30
|
+
"literal API repeated fields known cwd reads original prose file",
|
|
31
|
+
lisaCwd,
|
|
32
|
+
`cd '${relative}' && gh api ${endpoint} --field body=@body.md --field title=clean`,
|
|
33
|
+
2,
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
"literal API repeated fields GET remains read-only",
|
|
37
|
+
lisaCwd,
|
|
38
|
+
`${prefix} api ${endpoint} -X GET --field body=@body.md --field title=clean -q "$FILTER"`,
|
|
39
|
+
0,
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
"nonadditive body-file last value remains authoritative",
|
|
43
|
+
lisaCwd,
|
|
44
|
+
`${prefix} issue create --repo ${lisa} --body-file missing.md --body-file ${clean}`,
|
|
45
|
+
0,
|
|
46
|
+
],
|
|
47
|
+
unknown(
|
|
48
|
+
"expanded mixed field aliases retain earlier relative file control",
|
|
49
|
+
`${prefix} "$N" ${endpoint} --field body=@body.md -F title=@${clean}`
|
|
50
|
+
),
|
|
51
|
+
unknown(
|
|
52
|
+
"expanded repeated equal field retains earlier relative file",
|
|
53
|
+
`${prefix} "$N" ${endpoint} --field=body=@body.md --field=title=clean`
|
|
54
|
+
),
|
|
55
|
+
unknown(
|
|
56
|
+
"literal API repeated attached F retains earlier relative file",
|
|
57
|
+
`${prefix} api ${endpoint} -Fbody=@body.md -Ftitle=@${clean}`
|
|
58
|
+
),
|
|
59
|
+
];
|
|
60
|
+
}
|
|
@@ -17,6 +17,11 @@ import path from "node:path";
|
|
|
17
17
|
import { boundedExecFileSync, boundedSpawnSync } from "./lib/bounded-spawn.mjs";
|
|
18
18
|
import { hostNameTargetCases } from "./lib/host-name-target-cases.mjs";
|
|
19
19
|
import { hostNameReviewCases } from "./lib/host-name-review-cases.mjs";
|
|
20
|
+
import {
|
|
21
|
+
hostNameExpandedCommandCases,
|
|
22
|
+
verifyExpandedCommandArgv,
|
|
23
|
+
} from "./lib/host-name-expanded-command-cases.mjs";
|
|
24
|
+
import { hostNameFieldOccurrenceCases } from "./lib/host-name-field-occurrence-cases.mjs";
|
|
20
25
|
|
|
21
26
|
const root = process.cwd();
|
|
22
27
|
const DETECTOR_RELATIVE = "dist/core/downstream-references.js";
|
|
@@ -118,6 +123,15 @@ try {
|
|
|
118
123
|
const identity = {
|
|
119
124
|
proverCheckoutHead: git(root, ["rev-parse", "HEAD"]),
|
|
120
125
|
proverSha256: digest(new URL(import.meta.url)),
|
|
126
|
+
caseModules: [
|
|
127
|
+
"host-name-target-cases.mjs",
|
|
128
|
+
"host-name-review-cases.mjs",
|
|
129
|
+
"host-name-expanded-command-cases.mjs",
|
|
130
|
+
"host-name-field-occurrence-cases.mjs",
|
|
131
|
+
].map(file => ({
|
|
132
|
+
file,
|
|
133
|
+
sha256: digest(new URL(`./lib/${file}`, import.meta.url)),
|
|
134
|
+
})),
|
|
121
135
|
payloadRoot,
|
|
122
136
|
payloadPackageVersion: JSON.parse(
|
|
123
137
|
readFileSync(path.join(payloadRoot, "package.json"), "utf8")
|
|
@@ -299,7 +313,10 @@ try {
|
|
|
299
313
|
const cases = [
|
|
300
314
|
...hostNameTargetCases(context),
|
|
301
315
|
...hostNameReviewCases(context),
|
|
316
|
+
...hostNameExpandedCommandCases(context),
|
|
317
|
+
...hostNameFieldOccurrenceCases(context),
|
|
302
318
|
];
|
|
319
|
+
verifyExpandedCommandArgv(context, fixtureEnv);
|
|
303
320
|
for (const [
|
|
304
321
|
name,
|
|
305
322
|
cwd,
|
|
@@ -330,7 +347,16 @@ try {
|
|
|
330
347
|
);
|
|
331
348
|
const passed =
|
|
332
349
|
run.status === expected && (expected !== 2 || output.includes(refusal));
|
|
333
|
-
records.push({
|
|
350
|
+
records.push({
|
|
351
|
+
name,
|
|
352
|
+
cwd,
|
|
353
|
+
command,
|
|
354
|
+
overrides,
|
|
355
|
+
expected,
|
|
356
|
+
actual: run.status,
|
|
357
|
+
passed,
|
|
358
|
+
output,
|
|
359
|
+
});
|
|
334
360
|
console.log(JSON.stringify(records.at(-1)));
|
|
335
361
|
}
|
|
336
362
|
const failed = records.filter(record => !record.passed);
|