@robinmordasiewicz/f5xc-xcsh 1.0.91-2601040044 → 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 +449 -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;
|
|
@@ -145585,6 +145585,387 @@ function buildConnectionInfo(profileName, apiUrl, hasToken, namespace, isConnect
|
|
|
145585
145585
|
return info;
|
|
145586
145586
|
}
|
|
145587
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
|
+
|
|
145588
145969
|
// src/domains/login/profile/create.ts
|
|
145589
145970
|
var createCommand2 = {
|
|
145590
145971
|
name: "create",
|
|
@@ -145611,6 +145992,18 @@ var createCommand2 = {
|
|
|
145611
145992
|
].join("\n")
|
|
145612
145993
|
);
|
|
145613
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
|
+
}
|
|
145614
146007
|
const existing = await manager.get(name);
|
|
145615
146008
|
if (existing) {
|
|
145616
146009
|
return errorResult(
|
|
@@ -150510,13 +150903,13 @@ var RESERVED_API_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
150510
150903
|
"add-labels",
|
|
150511
150904
|
"remove-labels"
|
|
150512
150905
|
]);
|
|
150513
|
-
function
|
|
150906
|
+
function isReservedAction2(name) {
|
|
150514
150907
|
return RESERVED_API_ACTIONS.has(name.toLowerCase());
|
|
150515
150908
|
}
|
|
150516
150909
|
function validateExtension(extension) {
|
|
150517
150910
|
const conflicts = [];
|
|
150518
150911
|
for (const [name] of extension.commands) {
|
|
150519
|
-
if (
|
|
150912
|
+
if (isReservedAction2(name)) {
|
|
150520
150913
|
conflicts.push(name);
|
|
150521
150914
|
}
|
|
150522
150915
|
}
|
|
@@ -151861,114 +152254,15 @@ function useGitStatus(options = {}) {
|
|
|
151861
152254
|
return { gitInfo, refresh, lastRefresh };
|
|
151862
152255
|
}
|
|
151863
152256
|
|
|
151864
|
-
// src/validation/namespace.ts
|
|
151865
|
-
function validateNamespaceScope(domain, action, currentNamespace, resourceType) {
|
|
151866
|
-
const opInfo = getOperationDescription(domain, action, resourceType);
|
|
151867
|
-
if (!opInfo?.namespaceScope) {
|
|
151868
|
-
return { valid: true };
|
|
151869
|
-
}
|
|
151870
|
-
const scope = opInfo.namespaceScope;
|
|
151871
|
-
const normalizedNamespace = currentNamespace.toLowerCase();
|
|
151872
|
-
switch (scope) {
|
|
151873
|
-
case "system":
|
|
151874
|
-
if (normalizedNamespace !== "system") {
|
|
151875
|
-
return {
|
|
151876
|
-
valid: false,
|
|
151877
|
-
scope,
|
|
151878
|
-
message: `${action} on ${resourceType || domain} requires the 'system' namespace`,
|
|
151879
|
-
suggestion: "system"
|
|
151880
|
-
};
|
|
151881
|
-
}
|
|
151882
|
-
return { valid: true, scope };
|
|
151883
|
-
case "shared":
|
|
151884
|
-
if (normalizedNamespace !== "shared") {
|
|
151885
|
-
return {
|
|
151886
|
-
valid: false,
|
|
151887
|
-
scope,
|
|
151888
|
-
message: `${action} on ${resourceType || domain} requires the 'shared' namespace`,
|
|
151889
|
-
suggestion: "shared"
|
|
151890
|
-
};
|
|
151891
|
-
}
|
|
151892
|
-
return { valid: true, scope };
|
|
151893
|
-
case "any":
|
|
151894
|
-
default:
|
|
151895
|
-
return { valid: true, scope };
|
|
151896
|
-
}
|
|
151897
|
-
}
|
|
151898
|
-
|
|
151899
|
-
// src/validation/safety.ts
|
|
151900
|
-
function checkOperationSafety(domain, action, resourceType) {
|
|
151901
|
-
const opInfo = getOperationDescription(domain, action, resourceType);
|
|
151902
|
-
const dangerLevel = opInfo?.dangerLevel || "low";
|
|
151903
|
-
const requiresConfirmation2 = opInfo?.confirmationRequired ?? dangerLevel === "high";
|
|
151904
|
-
const sideEffects = opInfo?.sideEffects;
|
|
151905
|
-
const result = {
|
|
151906
|
-
proceed: dangerLevel !== "high",
|
|
151907
|
-
// High danger requires explicit confirmation
|
|
151908
|
-
dangerLevel,
|
|
151909
|
-
requiresConfirmation: requiresConfirmation2
|
|
151910
|
-
};
|
|
151911
|
-
if (dangerLevel === "high") {
|
|
151912
|
-
result.warning = formatHighDangerWarning(domain, action, sideEffects);
|
|
151913
|
-
} else if (dangerLevel === "medium") {
|
|
151914
|
-
result.warning = formatMediumDangerWarning(domain, action, sideEffects);
|
|
151915
|
-
}
|
|
151916
|
-
if (sideEffects) {
|
|
151917
|
-
result.sideEffects = sideEffects;
|
|
151918
|
-
}
|
|
151919
|
-
return result;
|
|
151920
|
-
}
|
|
151921
|
-
function formatHighDangerWarning(_domain, _action, sideEffects) {
|
|
151922
|
-
const lines = [
|
|
151923
|
-
colorRed("\u26A0\uFE0F WARNING: This is a HIGH DANGER operation"),
|
|
151924
|
-
""
|
|
151925
|
-
];
|
|
151926
|
-
if (sideEffects) {
|
|
151927
|
-
if (sideEffects.deletes && sideEffects.deletes.length > 0) {
|
|
151928
|
-
lines.push(
|
|
151929
|
-
colorRed(` Will DELETE: ${sideEffects.deletes.join(", ")}`)
|
|
151930
|
-
);
|
|
151931
|
-
}
|
|
151932
|
-
if (sideEffects.updates && sideEffects.updates.length > 0) {
|
|
151933
|
-
lines.push(` Will UPDATE: ${sideEffects.updates.join(", ")}`);
|
|
151934
|
-
}
|
|
151935
|
-
if (sideEffects.creates && sideEffects.creates.length > 0) {
|
|
151936
|
-
lines.push(
|
|
151937
|
-
colorDim(` Will CREATE: ${sideEffects.creates.join(", ")}`)
|
|
151938
|
-
);
|
|
151939
|
-
}
|
|
151940
|
-
lines.push("");
|
|
151941
|
-
}
|
|
151942
|
-
lines.push(
|
|
151943
|
-
colorRed("This action may be destructive and cannot be undone.")
|
|
151944
|
-
);
|
|
151945
|
-
return lines.join("\n");
|
|
151946
|
-
}
|
|
151947
|
-
function formatMediumDangerWarning(_domain, _action, sideEffects) {
|
|
151948
|
-
const lines = [
|
|
151949
|
-
colorYellow("\u26A0\uFE0F CAUTION: This operation may have significant effects"),
|
|
151950
|
-
""
|
|
151951
|
-
];
|
|
151952
|
-
if (sideEffects) {
|
|
151953
|
-
const effects = [];
|
|
151954
|
-
if (sideEffects.creates && sideEffects.creates.length > 0) {
|
|
151955
|
-
effects.push(`creates: ${sideEffects.creates.join(", ")}`);
|
|
151956
|
-
}
|
|
151957
|
-
if (sideEffects.updates && sideEffects.updates.length > 0) {
|
|
151958
|
-
effects.push(`updates: ${sideEffects.updates.join(", ")}`);
|
|
151959
|
-
}
|
|
151960
|
-
if (sideEffects.deletes && sideEffects.deletes.length > 0) {
|
|
151961
|
-
effects.push(`deletes: ${sideEffects.deletes.join(", ")}`);
|
|
151962
|
-
}
|
|
151963
|
-
if (effects.length > 0) {
|
|
151964
|
-
lines.push(` Side effects: ${effects.join("; ")}`);
|
|
151965
|
-
lines.push("");
|
|
151966
|
-
}
|
|
151967
|
-
}
|
|
151968
|
-
return lines.join("\n");
|
|
151969
|
-
}
|
|
151970
|
-
|
|
151971
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
|
+
]);
|
|
151972
152266
|
var BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
|
|
151973
152267
|
"help",
|
|
151974
152268
|
"--help",
|
|
@@ -152653,6 +152947,50 @@ async function executeAPICommand(session, ctx, cmd) {
|
|
|
152653
152947
|
);
|
|
152654
152948
|
const { resourceType, name, namespace, outputFormat, spec, noColor } = parseCommandArgs(args, domainResourceTypes);
|
|
152655
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
|
+
}
|
|
152656
152994
|
const effectiveResource = resourceType ?? canonicalDomain;
|
|
152657
152995
|
const nsValidation = validateNamespaceScope(
|
|
152658
152996
|
canonicalDomain,
|