@cardstack/boxel-cli 0.2.0-unstable.298 → 0.2.0-unstable.327

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.
@@ -0,0 +1,34 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+
4
+ /**
5
+ * Walk up from `__dirname` until we find the `@cardstack/boxel-cli`
6
+ * package.json. The single-file esbuild bundle places `__dirname` at
7
+ * `boxel-cli/dist`; the ts-node fallback places it inside `src/...`.
8
+ * Anchoring to the package.json keeps every downstream path stable
9
+ * regardless of which entry mode is active.
10
+ */
11
+ export function findBoxelCliRoot(startDir: string): string {
12
+ let dir = startDir;
13
+ for (;;) {
14
+ let candidate = join(dir, 'package.json');
15
+ if (existsSync(candidate)) {
16
+ try {
17
+ let parsed = JSON.parse(readFileSync(candidate, 'utf8'));
18
+ if (parsed?.name === '@cardstack/boxel-cli') {
19
+ return dir;
20
+ }
21
+ } catch {
22
+ // ignore unparseable package.json and keep walking
23
+ }
24
+ }
25
+ let parent = dirname(dir);
26
+ if (parent === dir) {
27
+ throw new Error(
28
+ 'Could not locate the @cardstack/boxel-cli package root walking up from ' +
29
+ startDir,
30
+ );
31
+ }
32
+ dir = parent;
33
+ }
34
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Validate that an agent- or user-supplied `path` is a safe
3
+ * realm-relative path. Returns an error message if rejected, or null
4
+ * if the path is acceptable.
5
+ *
6
+ * Rejects:
7
+ * - empty / whitespace-only paths
8
+ * - absolute URLs with a scheme (`http:`, `file:`, etc.)
9
+ * - paths starting with `/`
10
+ * - backslash characters (ambiguous across URL/path handling layers;
11
+ * e.g. `foo\..\bar` never splits on `/` so the `..` check below
12
+ * misses it)
13
+ * - percent-encoded traversal segments — decodes once and rejects any
14
+ * `..` segment after decoding, so `%2e%2e`, `%2E%2E`, `%2e.`, etc.
15
+ * all collapse to a `..` and fail
16
+ * - malformed percent-encoded escapes
17
+ *
18
+ * Mirrors `packages/software-factory/src/realm-relative-path.ts` so
19
+ * both the SDK orchestrator and the boxel-cli validators apply the
20
+ * same gate before a path reaches realm-server URL handling.
21
+ */
22
+ export function validateRealmRelativePath(path: string): string | null {
23
+ if (path.trim() === '') {
24
+ return `Path must be a non-empty realm-relative file path.`;
25
+ }
26
+ if (/^[a-z][a-z0-9+.-]*:/i.test(path)) {
27
+ return `Path "${path}" must be realm-relative — absolute URLs (with a scheme) are not accepted.`;
28
+ }
29
+ if (path.startsWith('/')) {
30
+ return `Path "${path}" must be realm-relative — paths starting with "/" are not accepted.`;
31
+ }
32
+ if (path.includes('\\')) {
33
+ return `Path "${path}" must not contain backslash characters.`;
34
+ }
35
+ let decoded: string;
36
+ try {
37
+ decoded = decodeURIComponent(path);
38
+ } catch {
39
+ return `Path "${path}" contains an invalid percent-encoded escape.`;
40
+ }
41
+ let segments = decoded.split('/');
42
+ if (segments.some((seg) => seg === '..')) {
43
+ return `Path "${path}" must not contain ".." segments — the path must stay inside the target realm.`;
44
+ }
45
+ return null;
46
+ }