@f5-sales-demo/xcsh 19.102.4 → 19.102.6
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "19.102.
|
|
4
|
+
"version": "19.102.6",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
59
59
|
"@mozilla/readability": "^0.6",
|
|
60
|
-
"@f5-sales-demo/xcsh-stats": "19.102.
|
|
61
|
-
"@f5-sales-demo/pi-agent-core": "19.102.
|
|
62
|
-
"@f5-sales-demo/pi-ai": "19.102.
|
|
63
|
-
"@f5-sales-demo/pi-natives": "19.102.
|
|
64
|
-
"@f5-sales-demo/pi-resource-management": "19.102.
|
|
65
|
-
"@f5-sales-demo/pi-tui": "19.102.
|
|
66
|
-
"@f5-sales-demo/pi-utils": "19.102.
|
|
60
|
+
"@f5-sales-demo/xcsh-stats": "19.102.6",
|
|
61
|
+
"@f5-sales-demo/pi-agent-core": "19.102.6",
|
|
62
|
+
"@f5-sales-demo/pi-ai": "19.102.6",
|
|
63
|
+
"@f5-sales-demo/pi-natives": "19.102.6",
|
|
64
|
+
"@f5-sales-demo/pi-resource-management": "19.102.6",
|
|
65
|
+
"@f5-sales-demo/pi-tui": "19.102.6",
|
|
66
|
+
"@f5-sales-demo/pi-utils": "19.102.6",
|
|
67
67
|
"@sinclair/typebox": "^0.34",
|
|
68
68
|
"@xterm/headless": "^6.0",
|
|
69
69
|
"ajv": "^8.20",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.102.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.102.6",
|
|
21
|
+
"commit": "983ca4f8d682745db27c890d634cb459fc7e3e32",
|
|
22
|
+
"shortCommit": "983ca4f",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.102.
|
|
25
|
-
"commitDate": "2026-07-
|
|
26
|
-
"buildDate": "2026-07-
|
|
24
|
+
"tag": "v19.102.6",
|
|
25
|
+
"commitDate": "2026-07-31T01:44:23Z",
|
|
26
|
+
"buildDate": "2026-07-31T02:07:47.614Z",
|
|
27
27
|
"dirty": true,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5-sales-demo/xcsh",
|
|
30
30
|
"repoSlug": "f5-sales-demo/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.102.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/983ca4f8d682745db27c890d634cb459fc7e3e32",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.102.6"
|
|
33
33
|
};
|
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
<workspace-boundary>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
- Subdirectories may themselves be separate customers. Reachable does not mean in scope: work in
|
|
9
|
-
the one the task names, state the crossing when the task genuinely spans more than one, and
|
|
10
|
-
**MUST NOT** merge two customers' material into one artifact.
|
|
11
|
-
- A sandbox confines this session's file access, but its boundary is the working directory, not the
|
|
12
|
-
customer subdirectory: nothing refuses a sibling, so the rule above is yours to keep. When the
|
|
13
|
-
sandbox is active a path outside the working directory is refused — that is the boundary working,
|
|
14
|
-
not a tool failure. Say what you needed and why, and **MUST NOT** reach the same path another way.
|
|
2
|
+
Separate tenants may sit side by side — as subdirectories of the working directory, and anywhere
|
|
3
|
+
else you can reach when filesystem isolation is off. Reaching something is not the same as it being
|
|
4
|
+
in scope; keeping tenants apart is your judgment.
|
|
5
|
+
- Work in the one the task names, and say so when the task genuinely spans more than one.
|
|
6
|
+
- You **MUST NOT** open another tenant's material for context, examples, or precedent when the task
|
|
7
|
+
did not ask for it, and **MUST NOT** merge two tenants' material into one artifact.
|
|
15
8
|
</workspace-boundary>
|
|
@@ -203,6 +203,12 @@ const COMMAND_BEARING_CONFIG = [
|
|
|
203
203
|
// was measured working with its config.yml read-only.
|
|
204
204
|
path.join(".config", "glab-cli", "aliases.yml"),
|
|
205
205
|
path.join("Library", "Application Support", "glab-cli", "aliases.yml"),
|
|
206
|
+
// Build configuration that redirects a later build. Protected by *omission* while home was denied —
|
|
207
|
+
// the cache carve-outs grant `.cargo/registry` rather than `.cargo` — so #2637 had to name them. A
|
|
208
|
+
// write here is persistence, not theft: the operator's next build runs what it says. Reads are fine.
|
|
209
|
+
path.join(".cargo", "config.toml"),
|
|
210
|
+
path.join(".gradle", "init.gradle"),
|
|
211
|
+
path.join(".gradle", "init.d"),
|
|
206
212
|
];
|
|
207
213
|
|
|
208
214
|
/** Read-only inside home: configuration a tool needs to behave correctly, but must not rewrite. */
|
|
@@ -268,9 +274,10 @@ const AGENT_PROFILE_FILES = ["user-profile.json", "computer-profile.json", "sett
|
|
|
268
274
|
* unforeseen — `/data`, `/scratch`, a bespoke mount.
|
|
269
275
|
*/
|
|
270
276
|
const DATA_ROOTS = [
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
277
|
+
// `/Users` and `/home` are deliberately absent: denying the home container denies this operator's own
|
|
278
|
+
// home with it, which is the whole of #2637. Other accounts are 0700, so the filesystem already refuses
|
|
279
|
+
// them; the fence is not here to re-implement file permissions.
|
|
280
|
+
"/root", // Linux superuser home: not this operator's account
|
|
274
281
|
"/Volumes", // macOS mounts. Per-container, not per-child: /Volumes/Macintosh HD resolves to /,
|
|
275
282
|
"/mnt", // which `tooBroadToDeny` then rejects, and the kernel resolves such a path before any
|
|
276
283
|
"/media", // rule matches it — so denying the container cannot deny the boot volume.
|
|
@@ -528,8 +535,22 @@ export function buildContainmentFence(options: ContainmentOptions): ContainmentF
|
|
|
528
535
|
// rejects, so `/`, `/usr`, `/tmp` and `$TMPDIR` are never denied and operational paths stay
|
|
529
536
|
// reachable. And it costs nothing below: the workspace is allowed at greater depth, and
|
|
530
537
|
// `fenceVerdict` takes the deepest match.
|
|
531
|
-
|
|
538
|
+
// Home is never denied, and the walk stops there (#2637).
|
|
539
|
+
//
|
|
540
|
+
// This is a professional courtesy, not a prison: an effort to stop *inadvertent* filesystem wandering
|
|
541
|
+
// between customers, for an operator with senior technical skills and the same rights on this machine
|
|
542
|
+
// as the agent acting for them. Denying home outright refused `~/git/STYLE_GUIDE.md` and then needed
|
|
543
|
+
// ~30 carve-outs to make ordinary tooling work again — every one of them evidence the posture was wrong.
|
|
544
|
+
//
|
|
545
|
+
// What the walk still covers is the part that matters: every level between the workspace and home. With
|
|
546
|
+
// the workspace at `~/MEDDPICC/CUSTOMER-A`, `~/MEDDPICC` is denied so the `CUSTOMER-B` sibling is unreachable,
|
|
547
|
+
// and with `<container>/<tenant>/repo` every level up to home is denied, so the v19.100.1 cross-tenant
|
|
548
|
+
// regression does not return.
|
|
549
|
+
//
|
|
550
|
+
// A session whose folder IS home, or a direct child of it, therefore fences nothing above itself. That
|
|
551
|
+
// is deliberate: if the operator chooses to work in home, that is their filesystem to lay out.
|
|
532
552
|
for (let ancestor = path.dirname(workspace); ; ancestor = path.dirname(ancestor)) {
|
|
553
|
+
if (ancestor === home) break; // the operator's own account is theirs
|
|
533
554
|
if (tooBroadToDeny(ancestor, fsRoot)) break;
|
|
534
555
|
deny.add(ancestor);
|
|
535
556
|
const next = path.dirname(ancestor);
|
|
@@ -599,7 +620,7 @@ export function buildContainmentFence(options: ContainmentOptions): ContainmentF
|
|
|
599
620
|
}
|
|
600
621
|
|
|
601
622
|
// Top-level directories that hold somebody's files. Without these the fence covered only home and
|
|
602
|
-
// the workspace's ancestors, so with the workspace at `~/MEDDPICC/
|
|
623
|
+
// the workspace's ancestors, so with the workspace at `~/MEDDPICC/CUSTOMER-A` another operator's
|
|
603
624
|
// account, an external volume and `/data/globex` were all readable AND writable — measured. The
|
|
604
625
|
// command-text scan was refusing them on the way in, which is exactly why that scan could not
|
|
605
626
|
// simply be stood down (#2624).
|
|
@@ -629,6 +650,11 @@ export function buildContainmentFence(options: ContainmentOptions): ContainmentF
|
|
|
629
650
|
// e.g. /Volumes/Macintosh HD -> /. Skipped for the whole-root list, per the note above.
|
|
630
651
|
if (!rootScoped.has(resolved) && tooBroadToDeny(resolved, fsRoot)) continue;
|
|
631
652
|
if (resolved === fsRoot) continue; // never the root the workspace lives on
|
|
653
|
+
// Never a directory that CONTAINS home, because denying it denies home (#2637). Removing `/Users`
|
|
654
|
+
// and `/home` from the static list was not enough: the root enumeration re-adds them, since
|
|
655
|
+
// `Users` is not an operational name. That is what still refused `~/git/STYLE_GUIDE.md` at the
|
|
656
|
+
// kernel while `fenceVerdict` said allow — the unit tests use synthetic roots and could not see it.
|
|
657
|
+
if (home !== undefined && pathIsWithin(resolved, home)) continue;
|
|
632
658
|
// A deny beats an allow at EQUAL depth, so denying a root that IS the workspace or IS something
|
|
633
659
|
// the operator granted would not be redundant — it would silently revoke the grant. Deeper is
|
|
634
660
|
// fine and intended: an ancestor deny with the workspace allowed inside it is the normal shape.
|