@foro-sh/foro 0.10.0 → 0.11.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/README.md +6 -4
- package/dist/_generated-manifest-cases.d.ts +338 -72
- package/dist/_generated-manifest-cases.d.ts.map +1 -1
- package/dist/_generated-manifest-cases.js +360 -72
- package/dist/manifest-cases.d.ts +5 -3
- package/dist/manifest-cases.d.ts.map +1 -1
- package/dist/manifest-cases.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,16 +4,18 @@ This package is the TypeScript SDK for Foro.
|
|
|
4
4
|
|
|
5
5
|
## `@foro-sh/foro/manifest-cases`
|
|
6
6
|
|
|
7
|
-
The shared
|
|
7
|
+
The shared project-config validation table, as typed data. Foro's Python
|
|
8
8
|
`_manifest.py` is a port of [foro-sh/platform]'s
|
|
9
9
|
`apps/api/src/services/manifest.ts`, so both implementations run this same
|
|
10
|
-
table to guarantee they never disagree about what a valid
|
|
11
|
-
they did, `foro check` would pass locally and the deploy
|
|
10
|
+
table to guarantee they never disagree about what a valid `pyproject.toml` or
|
|
11
|
+
`package.json` is — if they did, `foro check` would pass locally and the deploy
|
|
12
|
+
would fail.
|
|
12
13
|
|
|
13
14
|
```ts
|
|
14
15
|
import { manifestCases } from '@foro-sh/foro/manifest-cases'
|
|
15
16
|
|
|
16
|
-
for (const { name,
|
|
17
|
+
for (const { name, files, expect } of manifestCases) {
|
|
18
|
+
// write `files` into an empty directory, then validate it
|
|
17
19
|
// expect is { ok: true } or { ok: false, reason: ManifestRejectionReason }
|
|
18
20
|
}
|
|
19
21
|
```
|
|
@@ -1,221 +1,487 @@
|
|
|
1
1
|
export declare const rawManifestCases: readonly [{
|
|
2
|
-
readonly name: "minimal
|
|
3
|
-
readonly
|
|
2
|
+
readonly name: "python-minimal";
|
|
3
|
+
readonly files: {
|
|
4
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n";
|
|
5
|
+
readonly "server.py": "";
|
|
6
|
+
};
|
|
4
7
|
readonly expect: {
|
|
5
8
|
readonly ok: true;
|
|
6
9
|
};
|
|
7
10
|
}, {
|
|
8
|
-
readonly name: "
|
|
9
|
-
readonly
|
|
11
|
+
readonly name: "python-poetry-only-name";
|
|
12
|
+
readonly files: {
|
|
13
|
+
readonly "pyproject.toml": "[tool.poetry]\nname = \"my-server\"\n";
|
|
14
|
+
readonly "main.py": "";
|
|
15
|
+
};
|
|
10
16
|
readonly expect: {
|
|
11
17
|
readonly ok: true;
|
|
12
18
|
};
|
|
13
19
|
}, {
|
|
14
|
-
readonly name: "
|
|
15
|
-
readonly
|
|
20
|
+
readonly name: "python-explicit-entrypoint";
|
|
21
|
+
readonly files: {
|
|
22
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"src/server.py\"\n";
|
|
23
|
+
};
|
|
16
24
|
readonly expect: {
|
|
17
25
|
readonly ok: true;
|
|
18
26
|
};
|
|
19
27
|
}, {
|
|
20
|
-
readonly name: "
|
|
21
|
-
readonly
|
|
28
|
+
readonly name: "python-all-fields";
|
|
29
|
+
readonly files: {
|
|
30
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nbuild_path = \"app\"\nentrypoint = \"server.py\"\nruntime = \"python\"\nruntime_version = \"3.11\"\nport = 9000\ndependency_manager = \"poetry\"\n";
|
|
31
|
+
};
|
|
22
32
|
readonly expect: {
|
|
23
33
|
readonly ok: true;
|
|
24
34
|
};
|
|
25
35
|
}, {
|
|
26
|
-
readonly name: "
|
|
27
|
-
readonly
|
|
36
|
+
readonly name: "python-requires-python-range";
|
|
37
|
+
readonly files: {
|
|
38
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \">=3.11,<3.13\"\n";
|
|
39
|
+
readonly "server.py": "";
|
|
40
|
+
};
|
|
41
|
+
readonly expect: {
|
|
42
|
+
readonly ok: true;
|
|
43
|
+
};
|
|
44
|
+
}, {
|
|
45
|
+
readonly name: "python-requires-python-exclusion";
|
|
46
|
+
readonly files: {
|
|
47
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \">=3.11,!=3.13\"\n";
|
|
48
|
+
readonly "server.py": "";
|
|
49
|
+
};
|
|
50
|
+
readonly expect: {
|
|
51
|
+
readonly ok: true;
|
|
52
|
+
};
|
|
53
|
+
}, {
|
|
54
|
+
readonly name: "python-requires-python-excludes-every-supported-version-one-by-one";
|
|
55
|
+
readonly files: {
|
|
56
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \">=3.11,!=3.11,!=3.12,!=3.13\"\n";
|
|
57
|
+
readonly "server.py": "";
|
|
58
|
+
};
|
|
28
59
|
readonly expect: {
|
|
29
60
|
readonly ok: false;
|
|
30
|
-
readonly reason: "
|
|
61
|
+
readonly reason: "invalid_runtime_version";
|
|
62
|
+
};
|
|
63
|
+
}, {
|
|
64
|
+
readonly name: "python-hyphen-inside-a-path-segment-is-fine";
|
|
65
|
+
readonly files: {
|
|
66
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"my-tools/mcp-server.py\"\n";
|
|
67
|
+
};
|
|
68
|
+
readonly expect: {
|
|
69
|
+
readonly ok: true;
|
|
31
70
|
};
|
|
32
71
|
}, {
|
|
33
|
-
readonly name: "
|
|
34
|
-
readonly
|
|
72
|
+
readonly name: "python-scoped-unspellable-name-is-normalised";
|
|
73
|
+
readonly files: {
|
|
74
|
+
readonly "pyproject.toml": "[project]\nname = \"My_Server\"\n";
|
|
75
|
+
readonly "server.py": "";
|
|
76
|
+
};
|
|
77
|
+
readonly expect: {
|
|
78
|
+
readonly ok: true;
|
|
79
|
+
};
|
|
80
|
+
}, {
|
|
81
|
+
readonly name: "python-no-entry-file";
|
|
82
|
+
readonly files: {
|
|
83
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n";
|
|
84
|
+
};
|
|
35
85
|
readonly expect: {
|
|
36
86
|
readonly ok: false;
|
|
37
|
-
readonly reason: "
|
|
87
|
+
readonly reason: "invalid_entrypoint";
|
|
38
88
|
};
|
|
39
89
|
}, {
|
|
40
|
-
readonly name: "
|
|
41
|
-
readonly
|
|
90
|
+
readonly name: "python-entrypoint-traversal";
|
|
91
|
+
readonly files: {
|
|
92
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"../server.py\"\n";
|
|
93
|
+
};
|
|
42
94
|
readonly expect: {
|
|
43
95
|
readonly ok: false;
|
|
44
|
-
readonly reason: "
|
|
96
|
+
readonly reason: "invalid_entrypoint";
|
|
45
97
|
};
|
|
46
98
|
}, {
|
|
47
|
-
readonly name: "
|
|
48
|
-
readonly
|
|
99
|
+
readonly name: "python-entrypoint-absolute";
|
|
100
|
+
readonly files: {
|
|
101
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"/server.py\"\n";
|
|
102
|
+
};
|
|
49
103
|
readonly expect: {
|
|
50
104
|
readonly ok: false;
|
|
51
105
|
readonly reason: "invalid_entrypoint";
|
|
52
106
|
};
|
|
53
107
|
}, {
|
|
54
|
-
readonly name: "
|
|
55
|
-
readonly
|
|
108
|
+
readonly name: "python-entrypoint-shell-metachar";
|
|
109
|
+
readonly files: {
|
|
110
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py; rm -rf x\"\n";
|
|
111
|
+
};
|
|
56
112
|
readonly expect: {
|
|
57
113
|
readonly ok: false;
|
|
58
114
|
readonly reason: "invalid_entrypoint";
|
|
59
115
|
};
|
|
60
116
|
}, {
|
|
61
|
-
readonly name: "
|
|
62
|
-
readonly
|
|
117
|
+
readonly name: "python-entrypoint-leading-dash";
|
|
118
|
+
readonly files: {
|
|
119
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"--isolated\"\n";
|
|
120
|
+
};
|
|
63
121
|
readonly expect: {
|
|
64
122
|
readonly ok: false;
|
|
65
123
|
readonly reason: "invalid_entrypoint";
|
|
66
124
|
};
|
|
67
125
|
}, {
|
|
68
|
-
readonly name: "
|
|
69
|
-
readonly
|
|
126
|
+
readonly name: "python-entrypoint-leading-dash-nested";
|
|
127
|
+
readonly files: {
|
|
128
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"src/-rf.py\"\n";
|
|
129
|
+
};
|
|
70
130
|
readonly expect: {
|
|
71
131
|
readonly ok: false;
|
|
72
132
|
readonly reason: "invalid_entrypoint";
|
|
73
133
|
};
|
|
74
134
|
}, {
|
|
75
|
-
readonly name: "
|
|
76
|
-
readonly
|
|
135
|
+
readonly name: "python-build-path-traversal";
|
|
136
|
+
readonly files: {
|
|
137
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"../x\"\n";
|
|
138
|
+
};
|
|
77
139
|
readonly expect: {
|
|
78
140
|
readonly ok: false;
|
|
79
141
|
readonly reason: "invalid_build_path";
|
|
80
142
|
};
|
|
81
143
|
}, {
|
|
82
|
-
readonly name: "
|
|
83
|
-
readonly
|
|
144
|
+
readonly name: "python-build-path-shell-metachar";
|
|
145
|
+
readonly files: {
|
|
146
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \". && whoami\"\n";
|
|
147
|
+
};
|
|
84
148
|
readonly expect: {
|
|
85
149
|
readonly ok: false;
|
|
86
150
|
readonly reason: "invalid_build_path";
|
|
87
151
|
};
|
|
88
152
|
}, {
|
|
89
|
-
readonly name: "
|
|
90
|
-
readonly
|
|
153
|
+
readonly name: "python-build-path-space";
|
|
154
|
+
readonly files: {
|
|
155
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"my services\"\n";
|
|
156
|
+
};
|
|
91
157
|
readonly expect: {
|
|
92
158
|
readonly ok: false;
|
|
93
159
|
readonly reason: "invalid_build_path";
|
|
94
160
|
};
|
|
95
161
|
}, {
|
|
96
|
-
readonly name: "
|
|
97
|
-
readonly
|
|
162
|
+
readonly name: "python-build-path-newline";
|
|
163
|
+
readonly files: {
|
|
164
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"app\\nUSER root\"\n";
|
|
165
|
+
};
|
|
98
166
|
readonly expect: {
|
|
99
167
|
readonly ok: false;
|
|
100
168
|
readonly reason: "invalid_build_path";
|
|
101
169
|
};
|
|
102
170
|
}, {
|
|
103
|
-
readonly name: "
|
|
104
|
-
readonly
|
|
171
|
+
readonly name: "python-build-path-leading-dash";
|
|
172
|
+
readonly files: {
|
|
173
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"-rf\"\n";
|
|
174
|
+
};
|
|
175
|
+
readonly expect: {
|
|
176
|
+
readonly ok: false;
|
|
177
|
+
readonly reason: "invalid_build_path";
|
|
178
|
+
};
|
|
179
|
+
}, {
|
|
180
|
+
readonly name: "python-runtime-version-outside-allowlist";
|
|
181
|
+
readonly files: {
|
|
182
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime_version = \"3.9\"\n";
|
|
183
|
+
};
|
|
105
184
|
readonly expect: {
|
|
106
185
|
readonly ok: false;
|
|
107
186
|
readonly reason: "invalid_runtime_version";
|
|
108
187
|
};
|
|
109
188
|
}, {
|
|
110
|
-
readonly name: "
|
|
111
|
-
readonly
|
|
189
|
+
readonly name: "python-requires-python-excludes-every-supported-version";
|
|
190
|
+
readonly files: {
|
|
191
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \"==3.9\"\n";
|
|
192
|
+
readonly "server.py": "";
|
|
193
|
+
};
|
|
112
194
|
readonly expect: {
|
|
113
195
|
readonly ok: false;
|
|
114
|
-
readonly reason: "
|
|
196
|
+
readonly reason: "invalid_runtime_version";
|
|
115
197
|
};
|
|
116
198
|
}, {
|
|
117
|
-
readonly name: "runtime-version-from-another-runtime";
|
|
118
|
-
readonly
|
|
199
|
+
readonly name: "python-runtime-version-from-another-runtime";
|
|
200
|
+
readonly files: {
|
|
201
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime_version = \"22\"\n";
|
|
202
|
+
};
|
|
119
203
|
readonly expect: {
|
|
120
204
|
readonly ok: false;
|
|
121
205
|
readonly reason: "invalid_runtime_version";
|
|
122
206
|
};
|
|
207
|
+
}, {
|
|
208
|
+
readonly name: "runtime-outside-allowlist";
|
|
209
|
+
readonly files: {
|
|
210
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime = \"ruby\"\n";
|
|
211
|
+
};
|
|
212
|
+
readonly expect: {
|
|
213
|
+
readonly ok: false;
|
|
214
|
+
readonly reason: "invalid_runtime";
|
|
215
|
+
};
|
|
216
|
+
}, {
|
|
217
|
+
readonly name: "runtime-disagrees-with-the-file-it-was-read-from";
|
|
218
|
+
readonly files: {
|
|
219
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime = \"node\"\n";
|
|
220
|
+
};
|
|
221
|
+
readonly expect: {
|
|
222
|
+
readonly ok: false;
|
|
223
|
+
readonly reason: "invalid_runtime";
|
|
224
|
+
};
|
|
225
|
+
}, {
|
|
226
|
+
readonly name: "both-config-files-and-neither-claims-the-runtime";
|
|
227
|
+
readonly files: {
|
|
228
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n";
|
|
229
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\"}";
|
|
230
|
+
readonly "server.py": "";
|
|
231
|
+
};
|
|
232
|
+
readonly expect: {
|
|
233
|
+
readonly ok: false;
|
|
234
|
+
readonly reason: "invalid_runtime";
|
|
235
|
+
};
|
|
236
|
+
}, {
|
|
237
|
+
readonly name: "both-config-files-and-both-claim-the-runtime";
|
|
238
|
+
readonly files: {
|
|
239
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nruntime = \"python\"\n";
|
|
240
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"runtime\": \"node\"}}";
|
|
241
|
+
readonly "server.py": "";
|
|
242
|
+
};
|
|
243
|
+
readonly expect: {
|
|
244
|
+
readonly ok: false;
|
|
245
|
+
readonly reason: "invalid_runtime";
|
|
246
|
+
};
|
|
247
|
+
}, {
|
|
248
|
+
readonly name: "both-config-files-python-claims-the-runtime";
|
|
249
|
+
readonly files: {
|
|
250
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nruntime = \"python\"\n";
|
|
251
|
+
readonly "package.json": "{\"name\": \"tooling-only\"}";
|
|
252
|
+
readonly "server.py": "";
|
|
253
|
+
};
|
|
254
|
+
readonly expect: {
|
|
255
|
+
readonly ok: true;
|
|
256
|
+
};
|
|
257
|
+
}, {
|
|
258
|
+
readonly name: "both-config-files-node-claims-the-runtime";
|
|
259
|
+
readonly files: {
|
|
260
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n";
|
|
261
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"runtime\": \"node\"}}";
|
|
262
|
+
readonly "server.py": "";
|
|
263
|
+
};
|
|
264
|
+
readonly expect: {
|
|
265
|
+
readonly ok: true;
|
|
266
|
+
};
|
|
267
|
+
}, {
|
|
268
|
+
readonly name: "no-config-file-only-a-legacy-manifest";
|
|
269
|
+
readonly files: {
|
|
270
|
+
readonly "foro.yaml": "name: my-server\nentrypoint: server.py\n";
|
|
271
|
+
readonly "server.py": "";
|
|
272
|
+
};
|
|
273
|
+
readonly expect: {
|
|
274
|
+
readonly ok: false;
|
|
275
|
+
readonly reason: "missing_manifest";
|
|
276
|
+
};
|
|
123
277
|
}, {
|
|
124
278
|
readonly name: "unknown-field-stale-python-version";
|
|
125
|
-
readonly
|
|
279
|
+
readonly files: {
|
|
280
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\npython_version = \"3.13\"\n";
|
|
281
|
+
};
|
|
126
282
|
readonly expect: {
|
|
127
283
|
readonly ok: false;
|
|
128
284
|
readonly reason: "unknown_field";
|
|
129
285
|
};
|
|
130
286
|
}, {
|
|
131
287
|
readonly name: "unknown-field-typo";
|
|
132
|
-
readonly
|
|
288
|
+
readonly files: {
|
|
289
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nentrypoints = \"server.py\"\n";
|
|
290
|
+
};
|
|
133
291
|
readonly expect: {
|
|
134
292
|
readonly ok: false;
|
|
135
293
|
readonly reason: "unknown_field";
|
|
136
294
|
};
|
|
137
295
|
}, {
|
|
138
|
-
readonly name: "
|
|
139
|
-
readonly
|
|
296
|
+
readonly name: "unknown-field-name-belongs-to-the-package";
|
|
297
|
+
readonly files: {
|
|
298
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nname = \"other\"\n";
|
|
299
|
+
};
|
|
300
|
+
readonly expect: {
|
|
301
|
+
readonly ok: false;
|
|
302
|
+
readonly reason: "unknown_field";
|
|
303
|
+
};
|
|
304
|
+
}, {
|
|
305
|
+
readonly name: "port-too-low";
|
|
306
|
+
readonly files: {
|
|
307
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 80\n";
|
|
308
|
+
};
|
|
140
309
|
readonly expect: {
|
|
141
310
|
readonly ok: false;
|
|
142
311
|
readonly reason: "invalid_port";
|
|
143
312
|
};
|
|
144
313
|
}, {
|
|
145
|
-
readonly name: "
|
|
146
|
-
readonly
|
|
314
|
+
readonly name: "port-too-high";
|
|
315
|
+
readonly files: {
|
|
316
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 70000\n";
|
|
317
|
+
};
|
|
147
318
|
readonly expect: {
|
|
148
319
|
readonly ok: false;
|
|
149
320
|
readonly reason: "invalid_port";
|
|
150
321
|
};
|
|
151
322
|
}, {
|
|
152
|
-
readonly name: "
|
|
153
|
-
readonly
|
|
323
|
+
readonly name: "port-sidecar-reserved";
|
|
324
|
+
readonly files: {
|
|
325
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 8001\n";
|
|
326
|
+
};
|
|
154
327
|
readonly expect: {
|
|
155
328
|
readonly ok: false;
|
|
156
329
|
readonly reason: "invalid_port";
|
|
157
330
|
};
|
|
158
331
|
}, {
|
|
159
|
-
readonly name: "
|
|
160
|
-
readonly
|
|
332
|
+
readonly name: "port-gate-reserved";
|
|
333
|
+
readonly files: {
|
|
334
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 8002\n";
|
|
335
|
+
};
|
|
161
336
|
readonly expect: {
|
|
162
337
|
readonly ok: false;
|
|
163
338
|
readonly reason: "invalid_port";
|
|
164
339
|
};
|
|
165
340
|
}, {
|
|
166
|
-
readonly name: "
|
|
167
|
-
readonly
|
|
341
|
+
readonly name: "port-non-integer";
|
|
342
|
+
readonly files: {
|
|
343
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = \"abc\"\n";
|
|
344
|
+
};
|
|
168
345
|
readonly expect: {
|
|
169
346
|
readonly ok: false;
|
|
170
|
-
readonly reason: "
|
|
347
|
+
readonly reason: "invalid_port";
|
|
171
348
|
};
|
|
172
349
|
}, {
|
|
173
|
-
readonly name: "
|
|
174
|
-
readonly
|
|
350
|
+
readonly name: "dependency-manager-outside-allowlist";
|
|
351
|
+
readonly files: {
|
|
352
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\ndependency_manager = \"pipx\"\n";
|
|
353
|
+
};
|
|
175
354
|
readonly expect: {
|
|
176
355
|
readonly ok: false;
|
|
177
|
-
readonly reason: "
|
|
356
|
+
readonly reason: "invalid_dependency_manager";
|
|
178
357
|
};
|
|
179
358
|
}, {
|
|
180
|
-
readonly name: "
|
|
181
|
-
readonly
|
|
359
|
+
readonly name: "node-dependency-manager-on-python";
|
|
360
|
+
readonly files: {
|
|
361
|
+
readonly "pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\ndependency_manager = \"npm\"\n";
|
|
362
|
+
};
|
|
182
363
|
readonly expect: {
|
|
183
364
|
readonly ok: false;
|
|
184
|
-
readonly reason: "
|
|
365
|
+
readonly reason: "invalid_dependency_manager";
|
|
185
366
|
};
|
|
186
367
|
}, {
|
|
187
|
-
readonly name: "
|
|
188
|
-
readonly
|
|
368
|
+
readonly name: "unparseable-pyproject";
|
|
369
|
+
readonly files: {
|
|
370
|
+
readonly "pyproject.toml": "[project\nname = \"my-server\"\n";
|
|
371
|
+
};
|
|
189
372
|
readonly expect: {
|
|
190
373
|
readonly ok: false;
|
|
191
374
|
readonly reason: "invalid_shape";
|
|
192
375
|
};
|
|
193
376
|
}, {
|
|
194
|
-
readonly name: "
|
|
195
|
-
readonly
|
|
377
|
+
readonly name: "node-minimal";
|
|
378
|
+
readonly files: {
|
|
379
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"dist/index.js\"}";
|
|
380
|
+
};
|
|
381
|
+
readonly expect: {
|
|
382
|
+
readonly ok: true;
|
|
383
|
+
};
|
|
384
|
+
}, {
|
|
385
|
+
readonly name: "node-scoped-name";
|
|
386
|
+
readonly files: {
|
|
387
|
+
readonly "package.json": "{\"name\": \"@acme/my-server\", \"main\": \"dist/index.js\"}";
|
|
388
|
+
};
|
|
389
|
+
readonly expect: {
|
|
390
|
+
readonly ok: true;
|
|
391
|
+
};
|
|
392
|
+
}, {
|
|
393
|
+
readonly name: "node-bin-map";
|
|
394
|
+
readonly files: {
|
|
395
|
+
readonly "package.json": "{\"name\": \"my-server\", \"bin\": {\"my-server\": \"dist/cli.js\"}}";
|
|
396
|
+
};
|
|
397
|
+
readonly expect: {
|
|
398
|
+
readonly ok: true;
|
|
399
|
+
};
|
|
400
|
+
}, {
|
|
401
|
+
readonly name: "node-implicit-index";
|
|
402
|
+
readonly files: {
|
|
403
|
+
readonly "package.json": "{\"name\": \"my-server\"}";
|
|
404
|
+
readonly "index.js": "";
|
|
405
|
+
};
|
|
406
|
+
readonly expect: {
|
|
407
|
+
readonly ok: true;
|
|
408
|
+
};
|
|
409
|
+
}, {
|
|
410
|
+
readonly name: "node-engines-range";
|
|
411
|
+
readonly files: {
|
|
412
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \">=22\"}}";
|
|
413
|
+
};
|
|
414
|
+
readonly expect: {
|
|
415
|
+
readonly ok: true;
|
|
416
|
+
};
|
|
417
|
+
}, {
|
|
418
|
+
readonly name: "node-engines-union-of-every-supported-major";
|
|
419
|
+
readonly files: {
|
|
420
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \"^22 || ^24\"}}";
|
|
421
|
+
};
|
|
422
|
+
readonly expect: {
|
|
423
|
+
readonly ok: true;
|
|
424
|
+
};
|
|
425
|
+
}, {
|
|
426
|
+
readonly name: "node-engines-union-with-one-unsupported-branch";
|
|
427
|
+
readonly files: {
|
|
428
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \"^20 || ^22\"}}";
|
|
429
|
+
};
|
|
430
|
+
readonly expect: {
|
|
431
|
+
readonly ok: true;
|
|
432
|
+
};
|
|
433
|
+
}, {
|
|
434
|
+
readonly name: "node-all-fields";
|
|
435
|
+
readonly files: {
|
|
436
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"dist/index.js\", \"foro\": {\"runtime\": \"node\", \"runtime_version\": \"22\", \"port\": 9000, \"dependency_manager\": \"pnpm\"}}";
|
|
437
|
+
};
|
|
438
|
+
readonly expect: {
|
|
439
|
+
readonly ok: true;
|
|
440
|
+
};
|
|
441
|
+
}, {
|
|
442
|
+
readonly name: "node-no-entry-file";
|
|
443
|
+
readonly files: {
|
|
444
|
+
readonly "package.json": "{\"name\": \"my-server\"}";
|
|
445
|
+
};
|
|
196
446
|
readonly expect: {
|
|
197
447
|
readonly ok: false;
|
|
198
448
|
readonly reason: "invalid_entrypoint";
|
|
199
449
|
};
|
|
200
450
|
}, {
|
|
201
|
-
readonly name: "
|
|
202
|
-
readonly
|
|
451
|
+
readonly name: "node-engines-excludes-every-supported-version";
|
|
452
|
+
readonly files: {
|
|
453
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \"^20\"}}";
|
|
454
|
+
};
|
|
203
455
|
readonly expect: {
|
|
204
456
|
readonly ok: false;
|
|
205
|
-
readonly reason: "
|
|
457
|
+
readonly reason: "invalid_runtime_version";
|
|
206
458
|
};
|
|
207
459
|
}, {
|
|
208
|
-
readonly name: "
|
|
209
|
-
readonly
|
|
460
|
+
readonly name: "node-runtime-version-from-another-runtime";
|
|
461
|
+
readonly files: {
|
|
462
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"runtime_version\": \"3.12\"}}";
|
|
463
|
+
};
|
|
210
464
|
readonly expect: {
|
|
211
465
|
readonly ok: false;
|
|
212
|
-
readonly reason: "
|
|
466
|
+
readonly reason: "invalid_runtime_version";
|
|
213
467
|
};
|
|
214
468
|
}, {
|
|
215
|
-
readonly name: "
|
|
216
|
-
readonly
|
|
469
|
+
readonly name: "python-dependency-manager-on-node";
|
|
470
|
+
readonly files: {
|
|
471
|
+
readonly "package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"dependency_manager\": \"uv\"}}";
|
|
472
|
+
};
|
|
217
473
|
readonly expect: {
|
|
218
|
-
readonly ok:
|
|
474
|
+
readonly ok: false;
|
|
475
|
+
readonly reason: "invalid_dependency_manager";
|
|
476
|
+
};
|
|
477
|
+
}, {
|
|
478
|
+
readonly name: "unparseable-package-json";
|
|
479
|
+
readonly files: {
|
|
480
|
+
readonly "package.json": "{\"name\": ";
|
|
481
|
+
};
|
|
482
|
+
readonly expect: {
|
|
483
|
+
readonly ok: false;
|
|
484
|
+
readonly reason: "invalid_shape";
|
|
219
485
|
};
|
|
220
486
|
}];
|
|
221
487
|
//# sourceMappingURL=_generated-manifest-cases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_generated-manifest-cases.d.ts","sourceRoot":"","sources":["../src/_generated-manifest-cases.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"_generated-manifest-cases.d.ts","sourceRoot":"","sources":["../src/_generated-manifest-cases.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4hBnB,CAAA"}
|
|
@@ -2,148 +2,316 @@
|
|
|
2
2
|
// manifest-cases.json. Do not edit - edit the JSON and rebuild.
|
|
3
3
|
export const rawManifestCases = [
|
|
4
4
|
{
|
|
5
|
-
"name": "minimal
|
|
6
|
-
"
|
|
5
|
+
"name": "python-minimal",
|
|
6
|
+
"files": {
|
|
7
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n",
|
|
8
|
+
"server.py": ""
|
|
9
|
+
},
|
|
7
10
|
"expect": {
|
|
8
11
|
"ok": true
|
|
9
12
|
}
|
|
10
13
|
},
|
|
11
14
|
{
|
|
12
|
-
"name": "
|
|
13
|
-
"
|
|
15
|
+
"name": "python-poetry-only-name",
|
|
16
|
+
"files": {
|
|
17
|
+
"pyproject.toml": "[tool.poetry]\nname = \"my-server\"\n",
|
|
18
|
+
"main.py": ""
|
|
19
|
+
},
|
|
14
20
|
"expect": {
|
|
15
21
|
"ok": true
|
|
16
22
|
}
|
|
17
23
|
},
|
|
18
24
|
{
|
|
19
|
-
"name": "
|
|
20
|
-
"
|
|
25
|
+
"name": "python-explicit-entrypoint",
|
|
26
|
+
"files": {
|
|
27
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"src/server.py\"\n"
|
|
28
|
+
},
|
|
21
29
|
"expect": {
|
|
22
30
|
"ok": true
|
|
23
31
|
}
|
|
24
32
|
},
|
|
25
33
|
{
|
|
26
|
-
"name": "
|
|
27
|
-
"
|
|
34
|
+
"name": "python-all-fields",
|
|
35
|
+
"files": {
|
|
36
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nbuild_path = \"app\"\nentrypoint = \"server.py\"\nruntime = \"python\"\nruntime_version = \"3.11\"\nport = 9000\ndependency_manager = \"poetry\"\n"
|
|
37
|
+
},
|
|
28
38
|
"expect": {
|
|
29
39
|
"ok": true
|
|
30
40
|
}
|
|
31
41
|
},
|
|
32
42
|
{
|
|
33
|
-
"name": "
|
|
34
|
-
"
|
|
43
|
+
"name": "python-requires-python-range",
|
|
44
|
+
"files": {
|
|
45
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \">=3.11,<3.13\"\n",
|
|
46
|
+
"server.py": ""
|
|
47
|
+
},
|
|
48
|
+
"expect": {
|
|
49
|
+
"ok": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "python-requires-python-exclusion",
|
|
54
|
+
"files": {
|
|
55
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \">=3.11,!=3.13\"\n",
|
|
56
|
+
"server.py": ""
|
|
57
|
+
},
|
|
58
|
+
"expect": {
|
|
59
|
+
"ok": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "python-requires-python-excludes-every-supported-version-one-by-one",
|
|
64
|
+
"files": {
|
|
65
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \">=3.11,!=3.11,!=3.12,!=3.13\"\n",
|
|
66
|
+
"server.py": ""
|
|
67
|
+
},
|
|
35
68
|
"expect": {
|
|
36
69
|
"ok": false,
|
|
37
|
-
"reason": "
|
|
70
|
+
"reason": "invalid_runtime_version"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "python-hyphen-inside-a-path-segment-is-fine",
|
|
75
|
+
"files": {
|
|
76
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"my-tools/mcp-server.py\"\n"
|
|
77
|
+
},
|
|
78
|
+
"expect": {
|
|
79
|
+
"ok": true
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "python-scoped-unspellable-name-is-normalised",
|
|
84
|
+
"files": {
|
|
85
|
+
"pyproject.toml": "[project]\nname = \"My_Server\"\n",
|
|
86
|
+
"server.py": ""
|
|
87
|
+
},
|
|
88
|
+
"expect": {
|
|
89
|
+
"ok": true
|
|
38
90
|
}
|
|
39
91
|
},
|
|
40
92
|
{
|
|
41
|
-
"name": "
|
|
42
|
-
"
|
|
93
|
+
"name": "python-no-entry-file",
|
|
94
|
+
"files": {
|
|
95
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n"
|
|
96
|
+
},
|
|
43
97
|
"expect": {
|
|
44
98
|
"ok": false,
|
|
45
|
-
"reason": "
|
|
99
|
+
"reason": "invalid_entrypoint"
|
|
46
100
|
}
|
|
47
101
|
},
|
|
48
102
|
{
|
|
49
|
-
"name": "
|
|
50
|
-
"
|
|
103
|
+
"name": "python-entrypoint-traversal",
|
|
104
|
+
"files": {
|
|
105
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"../server.py\"\n"
|
|
106
|
+
},
|
|
51
107
|
"expect": {
|
|
52
108
|
"ok": false,
|
|
53
|
-
"reason": "
|
|
109
|
+
"reason": "invalid_entrypoint"
|
|
54
110
|
}
|
|
55
111
|
},
|
|
56
112
|
{
|
|
57
|
-
"name": "
|
|
58
|
-
"
|
|
113
|
+
"name": "python-entrypoint-absolute",
|
|
114
|
+
"files": {
|
|
115
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"/server.py\"\n"
|
|
116
|
+
},
|
|
59
117
|
"expect": {
|
|
60
118
|
"ok": false,
|
|
61
119
|
"reason": "invalid_entrypoint"
|
|
62
120
|
}
|
|
63
121
|
},
|
|
64
122
|
{
|
|
65
|
-
"name": "
|
|
66
|
-
"
|
|
123
|
+
"name": "python-entrypoint-shell-metachar",
|
|
124
|
+
"files": {
|
|
125
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py; rm -rf x\"\n"
|
|
126
|
+
},
|
|
67
127
|
"expect": {
|
|
68
128
|
"ok": false,
|
|
69
129
|
"reason": "invalid_entrypoint"
|
|
70
130
|
}
|
|
71
131
|
},
|
|
72
132
|
{
|
|
73
|
-
"name": "
|
|
74
|
-
"
|
|
133
|
+
"name": "python-entrypoint-leading-dash",
|
|
134
|
+
"files": {
|
|
135
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"--isolated\"\n"
|
|
136
|
+
},
|
|
75
137
|
"expect": {
|
|
76
138
|
"ok": false,
|
|
77
139
|
"reason": "invalid_entrypoint"
|
|
78
140
|
}
|
|
79
141
|
},
|
|
80
142
|
{
|
|
81
|
-
"name": "
|
|
82
|
-
"
|
|
143
|
+
"name": "python-entrypoint-leading-dash-nested",
|
|
144
|
+
"files": {
|
|
145
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"src/-rf.py\"\n"
|
|
146
|
+
},
|
|
83
147
|
"expect": {
|
|
84
148
|
"ok": false,
|
|
85
149
|
"reason": "invalid_entrypoint"
|
|
86
150
|
}
|
|
87
151
|
},
|
|
88
152
|
{
|
|
89
|
-
"name": "
|
|
90
|
-
"
|
|
153
|
+
"name": "python-build-path-traversal",
|
|
154
|
+
"files": {
|
|
155
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"../x\"\n"
|
|
156
|
+
},
|
|
91
157
|
"expect": {
|
|
92
158
|
"ok": false,
|
|
93
159
|
"reason": "invalid_build_path"
|
|
94
160
|
}
|
|
95
161
|
},
|
|
96
162
|
{
|
|
97
|
-
"name": "
|
|
98
|
-
"
|
|
163
|
+
"name": "python-build-path-shell-metachar",
|
|
164
|
+
"files": {
|
|
165
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \". && whoami\"\n"
|
|
166
|
+
},
|
|
99
167
|
"expect": {
|
|
100
168
|
"ok": false,
|
|
101
169
|
"reason": "invalid_build_path"
|
|
102
170
|
}
|
|
103
171
|
},
|
|
104
172
|
{
|
|
105
|
-
"name": "
|
|
106
|
-
"
|
|
173
|
+
"name": "python-build-path-space",
|
|
174
|
+
"files": {
|
|
175
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"my services\"\n"
|
|
176
|
+
},
|
|
107
177
|
"expect": {
|
|
108
178
|
"ok": false,
|
|
109
179
|
"reason": "invalid_build_path"
|
|
110
180
|
}
|
|
111
181
|
},
|
|
112
182
|
{
|
|
113
|
-
"name": "
|
|
114
|
-
"
|
|
183
|
+
"name": "python-build-path-newline",
|
|
184
|
+
"files": {
|
|
185
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"app\\nUSER root\"\n"
|
|
186
|
+
},
|
|
115
187
|
"expect": {
|
|
116
188
|
"ok": false,
|
|
117
189
|
"reason": "invalid_build_path"
|
|
118
190
|
}
|
|
119
191
|
},
|
|
120
192
|
{
|
|
121
|
-
"name": "
|
|
122
|
-
"
|
|
193
|
+
"name": "python-build-path-leading-dash",
|
|
194
|
+
"files": {
|
|
195
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nbuild_path = \"-rf\"\n"
|
|
196
|
+
},
|
|
197
|
+
"expect": {
|
|
198
|
+
"ok": false,
|
|
199
|
+
"reason": "invalid_build_path"
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"name": "python-runtime-version-outside-allowlist",
|
|
204
|
+
"files": {
|
|
205
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime_version = \"3.9\"\n"
|
|
206
|
+
},
|
|
123
207
|
"expect": {
|
|
124
208
|
"ok": false,
|
|
125
209
|
"reason": "invalid_runtime_version"
|
|
126
210
|
}
|
|
127
211
|
},
|
|
128
212
|
{
|
|
129
|
-
"name": "
|
|
130
|
-
"
|
|
213
|
+
"name": "python-requires-python-excludes-every-supported-version",
|
|
214
|
+
"files": {
|
|
215
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\nrequires-python = \"==3.9\"\n",
|
|
216
|
+
"server.py": ""
|
|
217
|
+
},
|
|
131
218
|
"expect": {
|
|
132
219
|
"ok": false,
|
|
133
|
-
"reason": "
|
|
220
|
+
"reason": "invalid_runtime_version"
|
|
134
221
|
}
|
|
135
222
|
},
|
|
136
223
|
{
|
|
137
|
-
"name": "runtime-version-from-another-runtime",
|
|
138
|
-
"
|
|
224
|
+
"name": "python-runtime-version-from-another-runtime",
|
|
225
|
+
"files": {
|
|
226
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime_version = \"22\"\n"
|
|
227
|
+
},
|
|
139
228
|
"expect": {
|
|
140
229
|
"ok": false,
|
|
141
230
|
"reason": "invalid_runtime_version"
|
|
142
231
|
}
|
|
143
232
|
},
|
|
233
|
+
{
|
|
234
|
+
"name": "runtime-outside-allowlist",
|
|
235
|
+
"files": {
|
|
236
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime = \"ruby\"\n"
|
|
237
|
+
},
|
|
238
|
+
"expect": {
|
|
239
|
+
"ok": false,
|
|
240
|
+
"reason": "invalid_runtime"
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"name": "runtime-disagrees-with-the-file-it-was-read-from",
|
|
245
|
+
"files": {
|
|
246
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nruntime = \"node\"\n"
|
|
247
|
+
},
|
|
248
|
+
"expect": {
|
|
249
|
+
"ok": false,
|
|
250
|
+
"reason": "invalid_runtime"
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"name": "both-config-files-and-neither-claims-the-runtime",
|
|
255
|
+
"files": {
|
|
256
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n",
|
|
257
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\"}",
|
|
258
|
+
"server.py": ""
|
|
259
|
+
},
|
|
260
|
+
"expect": {
|
|
261
|
+
"ok": false,
|
|
262
|
+
"reason": "invalid_runtime"
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "both-config-files-and-both-claim-the-runtime",
|
|
267
|
+
"files": {
|
|
268
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nruntime = \"python\"\n",
|
|
269
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"runtime\": \"node\"}}",
|
|
270
|
+
"server.py": ""
|
|
271
|
+
},
|
|
272
|
+
"expect": {
|
|
273
|
+
"ok": false,
|
|
274
|
+
"reason": "invalid_runtime"
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"name": "both-config-files-python-claims-the-runtime",
|
|
279
|
+
"files": {
|
|
280
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nruntime = \"python\"\n",
|
|
281
|
+
"package.json": "{\"name\": \"tooling-only\"}",
|
|
282
|
+
"server.py": ""
|
|
283
|
+
},
|
|
284
|
+
"expect": {
|
|
285
|
+
"ok": true
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"name": "both-config-files-node-claims-the-runtime",
|
|
290
|
+
"files": {
|
|
291
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n",
|
|
292
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"runtime\": \"node\"}}",
|
|
293
|
+
"server.py": ""
|
|
294
|
+
},
|
|
295
|
+
"expect": {
|
|
296
|
+
"ok": true
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"name": "no-config-file-only-a-legacy-manifest",
|
|
301
|
+
"files": {
|
|
302
|
+
"foro.yaml": "name: my-server\nentrypoint: server.py\n",
|
|
303
|
+
"server.py": ""
|
|
304
|
+
},
|
|
305
|
+
"expect": {
|
|
306
|
+
"ok": false,
|
|
307
|
+
"reason": "missing_manifest"
|
|
308
|
+
}
|
|
309
|
+
},
|
|
144
310
|
{
|
|
145
311
|
"name": "unknown-field-stale-python-version",
|
|
146
|
-
"
|
|
312
|
+
"files": {
|
|
313
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\npython_version = \"3.13\"\n"
|
|
314
|
+
},
|
|
147
315
|
"expect": {
|
|
148
316
|
"ok": false,
|
|
149
317
|
"reason": "unknown_field"
|
|
@@ -151,105 +319,225 @@ export const rawManifestCases = [
|
|
|
151
319
|
},
|
|
152
320
|
{
|
|
153
321
|
"name": "unknown-field-typo",
|
|
154
|
-
"
|
|
322
|
+
"files": {
|
|
323
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nentrypoints = \"server.py\"\n"
|
|
324
|
+
},
|
|
325
|
+
"expect": {
|
|
326
|
+
"ok": false,
|
|
327
|
+
"reason": "unknown_field"
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
"name": "unknown-field-name-belongs-to-the-package",
|
|
332
|
+
"files": {
|
|
333
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nname = \"other\"\n"
|
|
334
|
+
},
|
|
155
335
|
"expect": {
|
|
156
336
|
"ok": false,
|
|
157
337
|
"reason": "unknown_field"
|
|
158
338
|
}
|
|
159
339
|
},
|
|
160
340
|
{
|
|
161
|
-
"name": "
|
|
162
|
-
"
|
|
341
|
+
"name": "port-too-low",
|
|
342
|
+
"files": {
|
|
343
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 80\n"
|
|
344
|
+
},
|
|
163
345
|
"expect": {
|
|
164
346
|
"ok": false,
|
|
165
347
|
"reason": "invalid_port"
|
|
166
348
|
}
|
|
167
349
|
},
|
|
168
350
|
{
|
|
169
|
-
"name": "
|
|
170
|
-
"
|
|
351
|
+
"name": "port-too-high",
|
|
352
|
+
"files": {
|
|
353
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 70000\n"
|
|
354
|
+
},
|
|
171
355
|
"expect": {
|
|
172
356
|
"ok": false,
|
|
173
357
|
"reason": "invalid_port"
|
|
174
358
|
}
|
|
175
359
|
},
|
|
176
360
|
{
|
|
177
|
-
"name": "
|
|
178
|
-
"
|
|
361
|
+
"name": "port-sidecar-reserved",
|
|
362
|
+
"files": {
|
|
363
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 8001\n"
|
|
364
|
+
},
|
|
179
365
|
"expect": {
|
|
180
366
|
"ok": false,
|
|
181
367
|
"reason": "invalid_port"
|
|
182
368
|
}
|
|
183
369
|
},
|
|
184
370
|
{
|
|
185
|
-
"name": "
|
|
186
|
-
"
|
|
371
|
+
"name": "port-gate-reserved",
|
|
372
|
+
"files": {
|
|
373
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = 8002\n"
|
|
374
|
+
},
|
|
187
375
|
"expect": {
|
|
188
376
|
"ok": false,
|
|
189
377
|
"reason": "invalid_port"
|
|
190
378
|
}
|
|
191
379
|
},
|
|
192
380
|
{
|
|
193
|
-
"name": "
|
|
194
|
-
"
|
|
381
|
+
"name": "port-non-integer",
|
|
382
|
+
"files": {
|
|
383
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\nport = \"abc\"\n"
|
|
384
|
+
},
|
|
195
385
|
"expect": {
|
|
196
386
|
"ok": false,
|
|
197
|
-
"reason": "
|
|
387
|
+
"reason": "invalid_port"
|
|
198
388
|
}
|
|
199
389
|
},
|
|
200
390
|
{
|
|
201
|
-
"name": "
|
|
202
|
-
"
|
|
391
|
+
"name": "dependency-manager-outside-allowlist",
|
|
392
|
+
"files": {
|
|
393
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\ndependency_manager = \"pipx\"\n"
|
|
394
|
+
},
|
|
203
395
|
"expect": {
|
|
204
396
|
"ok": false,
|
|
205
|
-
"reason": "
|
|
397
|
+
"reason": "invalid_dependency_manager"
|
|
206
398
|
}
|
|
207
399
|
},
|
|
208
400
|
{
|
|
209
|
-
"name": "
|
|
210
|
-
"
|
|
401
|
+
"name": "node-dependency-manager-on-python",
|
|
402
|
+
"files": {
|
|
403
|
+
"pyproject.toml": "[project]\nname = \"my-server\"\n\n[tool.foro]\nentrypoint = \"server.py\"\ndependency_manager = \"npm\"\n"
|
|
404
|
+
},
|
|
211
405
|
"expect": {
|
|
212
406
|
"ok": false,
|
|
213
|
-
"reason": "
|
|
407
|
+
"reason": "invalid_dependency_manager"
|
|
214
408
|
}
|
|
215
409
|
},
|
|
216
410
|
{
|
|
217
|
-
"name": "
|
|
218
|
-
"
|
|
411
|
+
"name": "unparseable-pyproject",
|
|
412
|
+
"files": {
|
|
413
|
+
"pyproject.toml": "[project\nname = \"my-server\"\n"
|
|
414
|
+
},
|
|
219
415
|
"expect": {
|
|
220
416
|
"ok": false,
|
|
221
417
|
"reason": "invalid_shape"
|
|
222
418
|
}
|
|
223
419
|
},
|
|
224
420
|
{
|
|
225
|
-
"name": "
|
|
226
|
-
"
|
|
421
|
+
"name": "node-minimal",
|
|
422
|
+
"files": {
|
|
423
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"dist/index.js\"}"
|
|
424
|
+
},
|
|
425
|
+
"expect": {
|
|
426
|
+
"ok": true
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"name": "node-scoped-name",
|
|
431
|
+
"files": {
|
|
432
|
+
"package.json": "{\"name\": \"@acme/my-server\", \"main\": \"dist/index.js\"}"
|
|
433
|
+
},
|
|
434
|
+
"expect": {
|
|
435
|
+
"ok": true
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"name": "node-bin-map",
|
|
440
|
+
"files": {
|
|
441
|
+
"package.json": "{\"name\": \"my-server\", \"bin\": {\"my-server\": \"dist/cli.js\"}}"
|
|
442
|
+
},
|
|
443
|
+
"expect": {
|
|
444
|
+
"ok": true
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
"name": "node-implicit-index",
|
|
449
|
+
"files": {
|
|
450
|
+
"package.json": "{\"name\": \"my-server\"}",
|
|
451
|
+
"index.js": ""
|
|
452
|
+
},
|
|
453
|
+
"expect": {
|
|
454
|
+
"ok": true
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"name": "node-engines-range",
|
|
459
|
+
"files": {
|
|
460
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \">=22\"}}"
|
|
461
|
+
},
|
|
462
|
+
"expect": {
|
|
463
|
+
"ok": true
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"name": "node-engines-union-of-every-supported-major",
|
|
468
|
+
"files": {
|
|
469
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \"^22 || ^24\"}}"
|
|
470
|
+
},
|
|
471
|
+
"expect": {
|
|
472
|
+
"ok": true
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"name": "node-engines-union-with-one-unsupported-branch",
|
|
477
|
+
"files": {
|
|
478
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \"^20 || ^22\"}}"
|
|
479
|
+
},
|
|
480
|
+
"expect": {
|
|
481
|
+
"ok": true
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"name": "node-all-fields",
|
|
486
|
+
"files": {
|
|
487
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"dist/index.js\", \"foro\": {\"runtime\": \"node\", \"runtime_version\": \"22\", \"port\": 9000, \"dependency_manager\": \"pnpm\"}}"
|
|
488
|
+
},
|
|
489
|
+
"expect": {
|
|
490
|
+
"ok": true
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"name": "node-no-entry-file",
|
|
495
|
+
"files": {
|
|
496
|
+
"package.json": "{\"name\": \"my-server\"}"
|
|
497
|
+
},
|
|
227
498
|
"expect": {
|
|
228
499
|
"ok": false,
|
|
229
500
|
"reason": "invalid_entrypoint"
|
|
230
501
|
}
|
|
231
502
|
},
|
|
232
503
|
{
|
|
233
|
-
"name": "
|
|
234
|
-
"
|
|
504
|
+
"name": "node-engines-excludes-every-supported-version",
|
|
505
|
+
"files": {
|
|
506
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"engines\": {\"node\": \"^20\"}}"
|
|
507
|
+
},
|
|
235
508
|
"expect": {
|
|
236
509
|
"ok": false,
|
|
237
|
-
"reason": "
|
|
510
|
+
"reason": "invalid_runtime_version"
|
|
238
511
|
}
|
|
239
512
|
},
|
|
240
513
|
{
|
|
241
|
-
"name": "
|
|
242
|
-
"
|
|
514
|
+
"name": "node-runtime-version-from-another-runtime",
|
|
515
|
+
"files": {
|
|
516
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"runtime_version\": \"3.12\"}}"
|
|
517
|
+
},
|
|
243
518
|
"expect": {
|
|
244
519
|
"ok": false,
|
|
245
|
-
"reason": "
|
|
520
|
+
"reason": "invalid_runtime_version"
|
|
246
521
|
}
|
|
247
522
|
},
|
|
248
523
|
{
|
|
249
|
-
"name": "
|
|
250
|
-
"
|
|
524
|
+
"name": "python-dependency-manager-on-node",
|
|
525
|
+
"files": {
|
|
526
|
+
"package.json": "{\"name\": \"my-server\", \"main\": \"index.js\", \"foro\": {\"dependency_manager\": \"uv\"}}"
|
|
527
|
+
},
|
|
251
528
|
"expect": {
|
|
252
|
-
"ok":
|
|
529
|
+
"ok": false,
|
|
530
|
+
"reason": "invalid_dependency_manager"
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
"name": "unparseable-package-json",
|
|
535
|
+
"files": {
|
|
536
|
+
"package.json": "{\"name\": "
|
|
537
|
+
},
|
|
538
|
+
"expect": {
|
|
539
|
+
"ok": false,
|
|
540
|
+
"reason": "invalid_shape"
|
|
253
541
|
}
|
|
254
542
|
}
|
|
255
543
|
];
|
package/dist/manifest-cases.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The shared
|
|
2
|
+
* The shared project-config validation table.
|
|
3
3
|
*
|
|
4
4
|
* foro's `_manifest.py` is a port of foro-sh/platform's
|
|
5
5
|
* `apps/api/src/services/manifest.ts`, and the two can never be allowed to
|
|
@@ -19,8 +19,10 @@ export type ManifestRejectionReason = 'missing_manifest' | 'unsupported_language
|
|
|
19
19
|
export interface ManifestCase {
|
|
20
20
|
/** Stable identifier, unique across the table - use it as the test name. */
|
|
21
21
|
readonly name: string;
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/** Files to write into an empty directory before validating it, keyed by
|
|
23
|
+
* repo-relative path. Always the config file under test, plus whatever the
|
|
24
|
+
* entry-file inference has to find on disk. */
|
|
25
|
+
readonly files: Readonly<Record<string, string>>;
|
|
24
26
|
readonly expect: {
|
|
25
27
|
readonly ok: true;
|
|
26
28
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-cases.d.ts","sourceRoot":"","sources":["../src/manifest-cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;kCAEkC;AAClC,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,sBAAsB,GACtB,cAAc,GACd,eAAe,GACf,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,iBAAiB,GACjB,yBAAyB,GACzB,cAAc,GACd,4BAA4B,GAC5B,qBAAqB,GACrB,eAAe,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB
|
|
1
|
+
{"version":3,"file":"manifest-cases.d.ts","sourceRoot":"","sources":["../src/manifest-cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;kCAEkC;AAClC,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,sBAAsB,GACtB,cAAc,GACd,eAAe,GACf,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,iBAAiB,GACjB,yBAAyB,GACzB,cAAc,GACd,4BAA4B,GAC5B,qBAAqB,GACrB,eAAe,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;oDAEgD;IAChD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChD,QAAQ,CAAC,MAAM,EACX;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,GACrB;QAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAA;KAAE,CAAA;CACrE;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,YAAY,EAAqB,CAAA"}
|
package/dist/manifest-cases.js
CHANGED