@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.
- package/dist/index.js +550 -111
- 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-
|
|
47056
|
-
return "v1.0.91-
|
|
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
|
|
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 (
|
|
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,
|