@robinmordasiewicz/f5xc-xcsh 1.0.91-2601032334 → 1.0.91-2601040203

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.
Files changed (2) hide show
  1. package/dist/index.js +550 -111
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -47052,8 +47052,8 @@ function getLogoModeFromEnv(envPrefix) {
47052
47052
  var CLI_NAME = "xcsh";
47053
47053
  var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
47054
47054
  function getVersion() {
47055
- if ("v1.0.91-2601032334") {
47056
- return "v1.0.91-2601032334";
47055
+ if ("v1.0.91-2601040203") {
47056
+ return "v1.0.91-2601040203";
47057
47057
  }
47058
47058
  if (process.env.XCSH_VERSION) {
47059
47059
  return process.env.XCSH_VERSION;
@@ -143334,10 +143334,30 @@ var DomainRegistry = class {
143334
143334
  const cmdArgs = restArgs.slice(1);
143335
143335
  const cmd2 = subgroup.commands.get(cmdName);
143336
143336
  if (cmd2) {
143337
+ const commandPath = `${domainName} ${firstArg} ${cmdName}`;
143338
+ const validationError = this.validateCommandArgs(
143339
+ cmd2,
143340
+ cmdArgs,
143341
+ subgroup.commands,
143342
+ commandPath
143343
+ );
143344
+ if (validationError) {
143345
+ return validationError;
143346
+ }
143337
143347
  return cmd2.execute(cmdArgs, session);
143338
143348
  }
143339
143349
  for (const [, command] of subgroup.commands) {
143340
143350
  if (command.aliases?.includes(cmdName)) {
143351
+ const commandPath = `${domainName} ${firstArg} ${command.name}`;
143352
+ const validationError = this.validateCommandArgs(
143353
+ command,
143354
+ cmdArgs,
143355
+ subgroup.commands,
143356
+ commandPath
143357
+ );
143358
+ if (validationError) {
143359
+ return validationError;
143360
+ }
143341
143361
  return command.execute(cmdArgs, session);
143342
143362
  }
143343
143363
  }
@@ -143355,10 +143375,30 @@ var DomainRegistry = class {
143355
143375
  }
143356
143376
  const cmd = domain.commands.get(firstArg);
143357
143377
  if (cmd) {
143378
+ const commandPath = `${domainName} ${firstArg}`;
143379
+ const validationError = this.validateCommandArgs(
143380
+ cmd,
143381
+ restArgs,
143382
+ domain.commands,
143383
+ commandPath
143384
+ );
143385
+ if (validationError) {
143386
+ return validationError;
143387
+ }
143358
143388
  return cmd.execute(restArgs, session);
143359
143389
  }
143360
143390
  for (const [, command] of domain.commands) {
143361
143391
  if (command.aliases?.includes(firstArg)) {
143392
+ const commandPath = `${domainName} ${command.name}`;
143393
+ const validationError = this.validateCommandArgs(
143394
+ command,
143395
+ restArgs,
143396
+ domain.commands,
143397
+ commandPath
143398
+ );
143399
+ if (validationError) {
143400
+ return validationError;
143401
+ }
143362
143402
  return command.execute(restArgs, session);
143363
143403
  }
143364
143404
  }
@@ -143460,6 +143500,67 @@ var DomainRegistry = class {
143460
143500
  contextChanged: false
143461
143501
  };
143462
143502
  }
143503
+ /**
143504
+ * Validate command arguments and check for conflicts with sibling commands.
143505
+ * Returns an error result if validation fails, undefined if OK to proceed.
143506
+ */
143507
+ validateCommandArgs(cmd, cmdArgs, siblingCommands, commandPath) {
143508
+ if (cmdArgs.length === 0) {
143509
+ return void 0;
143510
+ }
143511
+ if (cmd.usage && cmd.usage.trim().length > 0) {
143512
+ return void 0;
143513
+ }
143514
+ const firstExtraArg = cmdArgs[0]?.toLowerCase() ?? "";
143515
+ const siblingCmd = siblingCommands.get(firstExtraArg);
143516
+ if (siblingCmd) {
143517
+ const pathParts = commandPath.split(" ");
143518
+ pathParts.pop();
143519
+ const suggestedPath = [...pathParts, ...cmdArgs].join(" ");
143520
+ return {
143521
+ output: [
143522
+ `Error: Cannot combine '${cmd.name}' with '${firstExtraArg}'.`,
143523
+ ``,
143524
+ `Did you mean: ${suggestedPath}`
143525
+ ],
143526
+ shouldExit: false,
143527
+ shouldClear: false,
143528
+ contextChanged: false,
143529
+ error: `Conflicting subcommands: '${cmd.name}' and '${firstExtraArg}'`
143530
+ };
143531
+ }
143532
+ for (const [siblingName, sibling] of siblingCommands) {
143533
+ if (sibling.aliases?.includes(firstExtraArg)) {
143534
+ const pathParts = commandPath.split(" ");
143535
+ pathParts.pop();
143536
+ const suggestedPath = [...pathParts, ...cmdArgs].join(" ");
143537
+ return {
143538
+ output: [
143539
+ `Error: Cannot combine '${cmd.name}' with '${firstExtraArg}' (alias for '${siblingName}').`,
143540
+ ``,
143541
+ `Did you mean: ${suggestedPath}`
143542
+ ],
143543
+ shouldExit: false,
143544
+ shouldClear: false,
143545
+ contextChanged: false,
143546
+ error: `Conflicting subcommands: '${cmd.name}' and '${firstExtraArg}'`
143547
+ };
143548
+ }
143549
+ }
143550
+ return {
143551
+ output: [
143552
+ `Error: Unexpected arguments for '${cmd.name}': ${cmdArgs.join(" ")}`,
143553
+ ``,
143554
+ `Usage: ${commandPath}`,
143555
+ ``,
143556
+ `The '${cmd.name}' command does not accept additional arguments.`
143557
+ ],
143558
+ shouldExit: false,
143559
+ shouldClear: false,
143560
+ contextChanged: false,
143561
+ error: `Unexpected arguments: ${cmdArgs.join(" ")}`
143562
+ };
143563
+ }
143463
143564
  };
143464
143565
  var customDomains = new DomainRegistry();
143465
143566
  function successResult(output, contextChanged = false) {
@@ -145484,6 +145585,387 @@ function buildConnectionInfo(profileName, apiUrl, hasToken, namespace, isConnect
145484
145585
  return info;
145485
145586
  }
145486
145587
 
145588
+ // src/validation/namespace.ts
145589
+ function validateNamespaceScope(domain, action, currentNamespace, resourceType) {
145590
+ const opInfo = getOperationDescription(domain, action, resourceType);
145591
+ if (!opInfo?.namespaceScope) {
145592
+ return { valid: true };
145593
+ }
145594
+ const scope = opInfo.namespaceScope;
145595
+ const normalizedNamespace = currentNamespace.toLowerCase();
145596
+ switch (scope) {
145597
+ case "system":
145598
+ if (normalizedNamespace !== "system") {
145599
+ return {
145600
+ valid: false,
145601
+ scope,
145602
+ message: `${action} on ${resourceType || domain} requires the 'system' namespace`,
145603
+ suggestion: "system"
145604
+ };
145605
+ }
145606
+ return { valid: true, scope };
145607
+ case "shared":
145608
+ if (normalizedNamespace !== "shared") {
145609
+ return {
145610
+ valid: false,
145611
+ scope,
145612
+ message: `${action} on ${resourceType || domain} requires the 'shared' namespace`,
145613
+ suggestion: "shared"
145614
+ };
145615
+ }
145616
+ return { valid: true, scope };
145617
+ case "any":
145618
+ default:
145619
+ return { valid: true, scope };
145620
+ }
145621
+ }
145622
+
145623
+ // src/validation/safety.ts
145624
+ function checkOperationSafety(domain, action, resourceType) {
145625
+ const opInfo = getOperationDescription(domain, action, resourceType);
145626
+ const dangerLevel = opInfo?.dangerLevel || "low";
145627
+ const requiresConfirmation2 = opInfo?.confirmationRequired ?? dangerLevel === "high";
145628
+ const sideEffects = opInfo?.sideEffects;
145629
+ const result = {
145630
+ proceed: dangerLevel !== "high",
145631
+ // High danger requires explicit confirmation
145632
+ dangerLevel,
145633
+ requiresConfirmation: requiresConfirmation2
145634
+ };
145635
+ if (dangerLevel === "high") {
145636
+ result.warning = formatHighDangerWarning(domain, action, sideEffects);
145637
+ } else if (dangerLevel === "medium") {
145638
+ result.warning = formatMediumDangerWarning(domain, action, sideEffects);
145639
+ }
145640
+ if (sideEffects) {
145641
+ result.sideEffects = sideEffects;
145642
+ }
145643
+ return result;
145644
+ }
145645
+ function formatHighDangerWarning(_domain, _action, sideEffects) {
145646
+ const lines = [
145647
+ colorRed("\u26A0\uFE0F WARNING: This is a HIGH DANGER operation"),
145648
+ ""
145649
+ ];
145650
+ if (sideEffects) {
145651
+ if (sideEffects.deletes && sideEffects.deletes.length > 0) {
145652
+ lines.push(
145653
+ colorRed(` Will DELETE: ${sideEffects.deletes.join(", ")}`)
145654
+ );
145655
+ }
145656
+ if (sideEffects.updates && sideEffects.updates.length > 0) {
145657
+ lines.push(` Will UPDATE: ${sideEffects.updates.join(", ")}`);
145658
+ }
145659
+ if (sideEffects.creates && sideEffects.creates.length > 0) {
145660
+ lines.push(
145661
+ colorDim(` Will CREATE: ${sideEffects.creates.join(", ")}`)
145662
+ );
145663
+ }
145664
+ lines.push("");
145665
+ }
145666
+ lines.push(
145667
+ colorRed("This action may be destructive and cannot be undone.")
145668
+ );
145669
+ return lines.join("\n");
145670
+ }
145671
+ function formatMediumDangerWarning(_domain, _action, sideEffects) {
145672
+ const lines = [
145673
+ colorYellow("\u26A0\uFE0F CAUTION: This operation may have significant effects"),
145674
+ ""
145675
+ ];
145676
+ if (sideEffects) {
145677
+ const effects = [];
145678
+ if (sideEffects.creates && sideEffects.creates.length > 0) {
145679
+ effects.push(`creates: ${sideEffects.creates.join(", ")}`);
145680
+ }
145681
+ if (sideEffects.updates && sideEffects.updates.length > 0) {
145682
+ effects.push(`updates: ${sideEffects.updates.join(", ")}`);
145683
+ }
145684
+ if (sideEffects.deletes && sideEffects.deletes.length > 0) {
145685
+ effects.push(`deletes: ${sideEffects.deletes.join(", ")}`);
145686
+ }
145687
+ if (effects.length > 0) {
145688
+ lines.push(` Side effects: ${effects.join("; ")}`);
145689
+ lines.push("");
145690
+ }
145691
+ }
145692
+ return lines.join("\n");
145693
+ }
145694
+
145695
+ // src/validation/reserved-words.ts
145696
+ var RESERVED_ACTIONS = /* @__PURE__ */ new Set([
145697
+ // CRUD operations
145698
+ "create",
145699
+ "delete",
145700
+ "list",
145701
+ "get",
145702
+ "update",
145703
+ "apply",
145704
+ "patch",
145705
+ // Info operations
145706
+ "describe",
145707
+ "show",
145708
+ "status",
145709
+ "logs",
145710
+ "events",
145711
+ // Modification
145712
+ "edit",
145713
+ "replace",
145714
+ "set",
145715
+ "unset",
145716
+ // Lifecycle
145717
+ "start",
145718
+ "stop",
145719
+ "restart",
145720
+ "rollout",
145721
+ "scale",
145722
+ // Connection
145723
+ "attach",
145724
+ "detach",
145725
+ "connect",
145726
+ "disconnect",
145727
+ // Registration
145728
+ "register",
145729
+ "deregister",
145730
+ "associate",
145731
+ "disassociate",
145732
+ // AWS-specific
145733
+ "put",
145734
+ "modify",
145735
+ // Built-in xcsh commands
145736
+ "help",
145737
+ "quit",
145738
+ "exit",
145739
+ "clear",
145740
+ "history",
145741
+ "refresh",
145742
+ "context",
145743
+ "banner",
145744
+ "profile",
145745
+ "completion",
145746
+ // Common CLI patterns
145747
+ "run",
145748
+ "exec",
145749
+ "wait",
145750
+ "open",
145751
+ "close",
145752
+ "inspect",
145753
+ "validate",
145754
+ "diff",
145755
+ "plan",
145756
+ "import",
145757
+ "export"
145758
+ ]);
145759
+ var SHELL_METACHARACTERS = /[;&|`$()<>\\#!{}[\]*?~\n\r]/;
145760
+ var DANGEROUS_PATTERNS = [
145761
+ {
145762
+ pattern: /^-/,
145763
+ message: "Name cannot start with a hyphen (would be interpreted as a flag)"
145764
+ },
145765
+ {
145766
+ pattern: /^--/,
145767
+ message: "Name cannot start with double-hyphen (would be interpreted as a long flag)"
145768
+ },
145769
+ {
145770
+ pattern: /\.\./,
145771
+ message: "Name cannot contain '..' (path traversal risk)"
145772
+ },
145773
+ {
145774
+ pattern: /^\./,
145775
+ message: "Name cannot start with '.' (hidden file pattern)"
145776
+ },
145777
+ {
145778
+ pattern: /\//,
145779
+ message: "Name cannot contain '/' (path separator)"
145780
+ },
145781
+ {
145782
+ pattern: /\\$/,
145783
+ message: "Name cannot end with backslash (escape sequence risk)"
145784
+ },
145785
+ {
145786
+ pattern: /\s/,
145787
+ message: "Name cannot contain whitespace"
145788
+ },
145789
+ {
145790
+ pattern: /^_/,
145791
+ message: "Name cannot start with underscore (reserved for internal use)"
145792
+ }
145793
+ ];
145794
+ var DANGEROUS_COMMANDS = /* @__PURE__ */ new Set([
145795
+ // File destruction
145796
+ "rm",
145797
+ "rm-rf",
145798
+ "rmdir",
145799
+ "del",
145800
+ "unlink",
145801
+ "shred",
145802
+ // Privilege escalation
145803
+ "sudo",
145804
+ "su",
145805
+ "chmod",
145806
+ "chown",
145807
+ "chattr",
145808
+ "setfacl",
145809
+ // Network tools (payload download)
145810
+ "wget",
145811
+ "curl",
145812
+ "nc",
145813
+ "netcat",
145814
+ "socat",
145815
+ "telnet",
145816
+ "ssh",
145817
+ "scp",
145818
+ "rsync",
145819
+ // Shell execution
145820
+ "bash",
145821
+ "sh",
145822
+ "zsh",
145823
+ "csh",
145824
+ "ksh",
145825
+ "fish",
145826
+ "pwsh",
145827
+ "powershell",
145828
+ // Process execution
145829
+ "exec",
145830
+ "eval",
145831
+ "source",
145832
+ "nohup",
145833
+ "xargs",
145834
+ // Process termination
145835
+ "kill",
145836
+ "pkill",
145837
+ "killall",
145838
+ "killall5",
145839
+ // Disk operations
145840
+ "dd",
145841
+ "mkfs",
145842
+ "fdisk",
145843
+ "parted",
145844
+ "format",
145845
+ // System control
145846
+ "reboot",
145847
+ "shutdown",
145848
+ "halt",
145849
+ "poweroff",
145850
+ "init",
145851
+ "systemctl",
145852
+ // Container escape
145853
+ "docker",
145854
+ "kubectl",
145855
+ "nsenter",
145856
+ "chroot"
145857
+ ]);
145858
+ var CONTROL_CHARS = /[\x00-\x1f\x7f]/;
145859
+ var RFC1035_PATTERN = /^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
145860
+
145861
+ // src/validation/resource-name.ts
145862
+ var DEFAULT_OPTIONS = {
145863
+ maxLength: 63,
145864
+ allowUppercase: false,
145865
+ skipFormatValidation: false
145866
+ };
145867
+ function validateResourceName(name, options = {}) {
145868
+ const opts = { ...DEFAULT_OPTIONS, ...options };
145869
+ const nameLower = name.toLowerCase();
145870
+ if (!name || name.trim().length === 0) {
145871
+ return {
145872
+ valid: false,
145873
+ category: "invalid",
145874
+ message: "Resource name cannot be empty"
145875
+ };
145876
+ }
145877
+ if (name.length > opts.maxLength) {
145878
+ return {
145879
+ valid: false,
145880
+ category: "invalid",
145881
+ message: `Name exceeds maximum length of ${opts.maxLength} characters (got ${name.length})`,
145882
+ suggestion: sanitizeName(name.slice(0, opts.maxLength))
145883
+ };
145884
+ }
145885
+ if (CONTROL_CHARS.test(name)) {
145886
+ return {
145887
+ valid: false,
145888
+ category: "security",
145889
+ message: "Name contains control characters which are not allowed"
145890
+ };
145891
+ }
145892
+ if (SHELL_METACHARACTERS.test(name)) {
145893
+ const match = name.match(SHELL_METACHARACTERS);
145894
+ const char = match?.[0] ?? "unknown";
145895
+ const charDesc = getCharacterDescription(char);
145896
+ return {
145897
+ valid: false,
145898
+ category: "security",
145899
+ message: `Name contains shell metacharacter '${charDesc}' which could enable command injection`
145900
+ };
145901
+ }
145902
+ if (RESERVED_ACTIONS.has(nameLower)) {
145903
+ return {
145904
+ valid: false,
145905
+ category: "reserved",
145906
+ message: `'${name}' is a reserved CLI action word and cannot be used as a resource name`,
145907
+ suggestion: `my-${name}`
145908
+ };
145909
+ }
145910
+ if (DANGEROUS_COMMANDS.has(nameLower)) {
145911
+ return {
145912
+ valid: false,
145913
+ category: "dangerous",
145914
+ message: `'${name}' matches a dangerous system command and cannot be used as a resource name`
145915
+ };
145916
+ }
145917
+ for (const { pattern, message } of DANGEROUS_PATTERNS) {
145918
+ if (pattern.test(name)) {
145919
+ return {
145920
+ valid: false,
145921
+ category: "dangerous",
145922
+ message
145923
+ };
145924
+ }
145925
+ }
145926
+ if (!opts.skipFormatValidation) {
145927
+ const nameToCheck = opts.allowUppercase ? nameLower : name;
145928
+ if (!RFC1035_PATTERN.test(nameToCheck.toLowerCase())) {
145929
+ return {
145930
+ valid: false,
145931
+ category: "invalid",
145932
+ message: "Name must start with a letter, end with alphanumeric, and contain only lowercase letters, numbers, and hyphens",
145933
+ suggestion: sanitizeName(name)
145934
+ };
145935
+ }
145936
+ }
145937
+ return { valid: true };
145938
+ }
145939
+ function getCharacterDescription(char) {
145940
+ const descriptions = {
145941
+ ";": "; (command separator)",
145942
+ "&": "& (background execution)",
145943
+ "|": "| (pipe)",
145944
+ "`": "` (command substitution)",
145945
+ $: "$ (variable/command expansion)",
145946
+ "(": "( (subshell)",
145947
+ ")": ") (subshell)",
145948
+ "<": "< (input redirection)",
145949
+ ">": "> (output redirection)",
145950
+ "\\": "\\ (escape)",
145951
+ "#": "# (comment)",
145952
+ "!": "! (history expansion)",
145953
+ "{": "{ (brace expansion)",
145954
+ "}": "} (brace expansion)",
145955
+ "[": "[ (bracket expansion)",
145956
+ "]": "] (bracket expansion)",
145957
+ "*": "* (glob pattern)",
145958
+ "?": "? (glob pattern)",
145959
+ "~": "~ (home directory)",
145960
+ "\n": "newline",
145961
+ "\r": "carriage return"
145962
+ };
145963
+ return descriptions[char] ?? char;
145964
+ }
145965
+ function sanitizeName(name) {
145966
+ return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^[^a-z]+/, "").replace(/-+$/, "").replace(/-{2,}/g, "-").slice(0, 63) || "resource";
145967
+ }
145968
+
145487
145969
  // src/domains/login/profile/create.ts
145488
145970
  var createCommand2 = {
145489
145971
  name: "create",
@@ -145510,6 +145992,18 @@ var createCommand2 = {
145510
145992
  ].join("\n")
145511
145993
  );
145512
145994
  }
145995
+ const nameValidation = validateResourceName(name, {
145996
+ maxLength: 128,
145997
+ // Profiles can have longer names than API resources
145998
+ resourceType: "profile"
145999
+ });
146000
+ if (!nameValidation.valid) {
146001
+ const lines = [`Invalid profile name: ${nameValidation.message}`];
146002
+ if (nameValidation.suggestion) {
146003
+ lines.push("", `Suggested: ${nameValidation.suggestion}`);
146004
+ }
146005
+ return errorResult(lines.join("\n"));
146006
+ }
145513
146007
  const existing = await manager.get(name);
145514
146008
  if (existing) {
145515
146009
  return errorResult(
@@ -150409,13 +150903,13 @@ var RESERVED_API_ACTIONS = /* @__PURE__ */ new Set([
150409
150903
  "add-labels",
150410
150904
  "remove-labels"
150411
150905
  ]);
150412
- function isReservedAction(name) {
150906
+ function isReservedAction2(name) {
150413
150907
  return RESERVED_API_ACTIONS.has(name.toLowerCase());
150414
150908
  }
150415
150909
  function validateExtension(extension) {
150416
150910
  const conflicts = [];
150417
150911
  for (const [name] of extension.commands) {
150418
- if (isReservedAction(name)) {
150912
+ if (isReservedAction2(name)) {
150419
150913
  conflicts.push(name);
150420
150914
  }
150421
150915
  }
@@ -151760,114 +152254,15 @@ function useGitStatus(options = {}) {
151760
152254
  return { gitInfo, refresh, lastRefresh };
151761
152255
  }
151762
152256
 
151763
- // src/validation/namespace.ts
151764
- function validateNamespaceScope(domain, action, currentNamespace, resourceType) {
151765
- const opInfo = getOperationDescription(domain, action, resourceType);
151766
- if (!opInfo?.namespaceScope) {
151767
- return { valid: true };
151768
- }
151769
- const scope = opInfo.namespaceScope;
151770
- const normalizedNamespace = currentNamespace.toLowerCase();
151771
- switch (scope) {
151772
- case "system":
151773
- if (normalizedNamespace !== "system") {
151774
- return {
151775
- valid: false,
151776
- scope,
151777
- message: `${action} on ${resourceType || domain} requires the 'system' namespace`,
151778
- suggestion: "system"
151779
- };
151780
- }
151781
- return { valid: true, scope };
151782
- case "shared":
151783
- if (normalizedNamespace !== "shared") {
151784
- return {
151785
- valid: false,
151786
- scope,
151787
- message: `${action} on ${resourceType || domain} requires the 'shared' namespace`,
151788
- suggestion: "shared"
151789
- };
151790
- }
151791
- return { valid: true, scope };
151792
- case "any":
151793
- default:
151794
- return { valid: true, scope };
151795
- }
151796
- }
151797
-
151798
- // src/validation/safety.ts
151799
- function checkOperationSafety(domain, action, resourceType) {
151800
- const opInfo = getOperationDescription(domain, action, resourceType);
151801
- const dangerLevel = opInfo?.dangerLevel || "low";
151802
- const requiresConfirmation2 = opInfo?.confirmationRequired ?? dangerLevel === "high";
151803
- const sideEffects = opInfo?.sideEffects;
151804
- const result = {
151805
- proceed: dangerLevel !== "high",
151806
- // High danger requires explicit confirmation
151807
- dangerLevel,
151808
- requiresConfirmation: requiresConfirmation2
151809
- };
151810
- if (dangerLevel === "high") {
151811
- result.warning = formatHighDangerWarning(domain, action, sideEffects);
151812
- } else if (dangerLevel === "medium") {
151813
- result.warning = formatMediumDangerWarning(domain, action, sideEffects);
151814
- }
151815
- if (sideEffects) {
151816
- result.sideEffects = sideEffects;
151817
- }
151818
- return result;
151819
- }
151820
- function formatHighDangerWarning(_domain, _action, sideEffects) {
151821
- const lines = [
151822
- colorRed("\u26A0\uFE0F WARNING: This is a HIGH DANGER operation"),
151823
- ""
151824
- ];
151825
- if (sideEffects) {
151826
- if (sideEffects.deletes && sideEffects.deletes.length > 0) {
151827
- lines.push(
151828
- colorRed(` Will DELETE: ${sideEffects.deletes.join(", ")}`)
151829
- );
151830
- }
151831
- if (sideEffects.updates && sideEffects.updates.length > 0) {
151832
- lines.push(` Will UPDATE: ${sideEffects.updates.join(", ")}`);
151833
- }
151834
- if (sideEffects.creates && sideEffects.creates.length > 0) {
151835
- lines.push(
151836
- colorDim(` Will CREATE: ${sideEffects.creates.join(", ")}`)
151837
- );
151838
- }
151839
- lines.push("");
151840
- }
151841
- lines.push(
151842
- colorRed("This action may be destructive and cannot be undone.")
151843
- );
151844
- return lines.join("\n");
151845
- }
151846
- function formatMediumDangerWarning(_domain, _action, sideEffects) {
151847
- const lines = [
151848
- colorYellow("\u26A0\uFE0F CAUTION: This operation may have significant effects"),
151849
- ""
151850
- ];
151851
- if (sideEffects) {
151852
- const effects = [];
151853
- if (sideEffects.creates && sideEffects.creates.length > 0) {
151854
- effects.push(`creates: ${sideEffects.creates.join(", ")}`);
151855
- }
151856
- if (sideEffects.updates && sideEffects.updates.length > 0) {
151857
- effects.push(`updates: ${sideEffects.updates.join(", ")}`);
151858
- }
151859
- if (sideEffects.deletes && sideEffects.deletes.length > 0) {
151860
- effects.push(`deletes: ${sideEffects.deletes.join(", ")}`);
151861
- }
151862
- if (effects.length > 0) {
151863
- lines.push(` Side effects: ${effects.join("; ")}`);
151864
- lines.push("");
151865
- }
151866
- }
151867
- return lines.join("\n");
151868
- }
151869
-
151870
152257
  // src/repl/executor.ts
152258
+ var WRITE_OPERATIONS = /* @__PURE__ */ new Set([
152259
+ "create",
152260
+ "replace",
152261
+ "apply",
152262
+ "patch",
152263
+ "add-labels",
152264
+ "remove-labels"
152265
+ ]);
151871
152266
  var BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
151872
152267
  "help",
151873
152268
  "--help",
@@ -152552,6 +152947,50 @@ async function executeAPICommand(session, ctx, cmd) {
152552
152947
  );
152553
152948
  const { resourceType, name, namespace, outputFormat, spec, noColor } = parseCommandArgs(args, domainResourceTypes);
152554
152949
  const effectiveNamespace = namespace ?? session.getNamespace();
152950
+ if (effectiveNamespace) {
152951
+ const nsNameValidation = validateResourceName(effectiveNamespace, {
152952
+ resourceType: "namespace"
152953
+ });
152954
+ if (!nsNameValidation.valid) {
152955
+ const lines = [
152956
+ `Error: Invalid namespace name '${effectiveNamespace}'`,
152957
+ "",
152958
+ nsNameValidation.message ?? "Invalid namespace name"
152959
+ ];
152960
+ if (nsNameValidation.suggestion) {
152961
+ lines.push("", `Suggested: ${nsNameValidation.suggestion}`);
152962
+ }
152963
+ return {
152964
+ output: lines,
152965
+ shouldExit: false,
152966
+ shouldClear: false,
152967
+ contextChanged: false,
152968
+ error: nsNameValidation.message ?? "Invalid namespace name"
152969
+ };
152970
+ }
152971
+ }
152972
+ if (WRITE_OPERATIONS.has(action) && name) {
152973
+ const nameValidation = validateResourceName(name, {
152974
+ resourceType: resourceType ?? canonicalDomain
152975
+ });
152976
+ if (!nameValidation.valid) {
152977
+ const lines = [
152978
+ `Error: Invalid resource name '${name}'`,
152979
+ "",
152980
+ nameValidation.message ?? "Invalid resource name"
152981
+ ];
152982
+ if (nameValidation.suggestion) {
152983
+ lines.push("", `Suggested: ${nameValidation.suggestion}`);
152984
+ }
152985
+ return {
152986
+ output: lines,
152987
+ shouldExit: false,
152988
+ shouldClear: false,
152989
+ contextChanged: false,
152990
+ error: nameValidation.message ?? "Invalid resource name"
152991
+ };
152992
+ }
152993
+ }
152555
152994
  const effectiveResource = resourceType ?? canonicalDomain;
152556
152995
  const nsValidation = validateNamespaceScope(
152557
152996
  canonicalDomain,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinmordasiewicz/f5xc-xcsh",
3
- "version": "1.0.91-2601032334",
3
+ "version": "1.0.91-2601040203",
4
4
  "description": "F5 Distributed Cloud Shell - Interactive CLI for F5 XC",
5
5
  "type": "module",
6
6
  "bin": {