Skip to content

Commit 6895ec5

Browse files
Improve SSH key filename validation in interactive mode (#86)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d549725 commit 6895ec5

5 files changed

Lines changed: 35 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ _Pvt_Extensions
243243

244244
# Claude AI assistant
245245
CLAUDE.md
246-
**/.claude/settings.local.json
246+
**/.claude/**
247247

248248
# Portal sample credentials
249249
azure_cert.pem

Tracebit.Cli.Tests/Commands/UtilsTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,21 @@ public void GetCurrentVersion_ReturnsVersion()
9898
Assert.NotNull(version);
9999
Assert.True(version.Major >= 0);
100100
}
101+
102+
[Theory]
103+
[InlineData("tracebit-key.pem", true)]
104+
[InlineData("my_ssh_key", true)]
105+
[InlineData("key123", true)]
106+
[InlineData("id_rsa", true)]
107+
[InlineData("", false)]
108+
[InlineData("key with spaces.pem", false)]
109+
[InlineData("\tkey.pem", false)]
110+
[InlineData("path/to/key.pem", false)]
111+
[InlineData("path\\to\\key.pem", false)]
112+
public void IsValidSshKeyFileName_ValidatesFileName(string input, bool expected)
113+
{
114+
var result = Utils.IsValidSshKeyFileName(input);
115+
116+
Assert.Equal(expected, result);
117+
}
101118
}

Tracebit.Cli/Commands/Deploy.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,6 @@ private static Command DeployCanaryCredentialsCommand(string type, string descri
688688
defaultName = defaultNameExists ? $"{defaultName}-{Utils.GenerateRandomString(5)}" : defaultName;
689689
var name = await AnsiConsole.PromptAsync(TextPrompts.NamePrompt(defaultName), cancellationToken);
690690
var labels = _labelsParsing(await AnsiConsole.PromptAsync(TextPrompts.LabelsPrompt, cancellationToken));
691-
// NOTE: only does a whitespace check for now, not legal filename checks yet like how the option does AcceptLegalFileNamesOnly()
692691
var sshKeyFileName = await AnsiConsole.PromptAsync(TextPrompts.SshKeyFileNamePrompt(defaultSshKeyFileName), cancellationToken);
693692
AnsiConsole.WriteLine();
694693
return (name, labels, sshKeyFileName);

Tracebit.Cli/Commands/TextPrompts.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static TextPrompt<string> SshKeyFileNamePrompt(string defaultSshKeyFileNa
4848
.DefaultValue(defaultSshKeyFileName)
4949
.DefaultValueStyle(Style.Parse("silver"))
5050
.Validate(s =>
51-
s.Any(char.IsWhiteSpace)
52-
? ValidationResult.Error("Whitespace in name not supported")
53-
: ValidationResult.Success());
51+
Utils.IsValidSshKeyFileName(s)
52+
? ValidationResult.Success()
53+
: ValidationResult.Error("Invalid SSH key file name: provide a file name (not a path) with no spaces or special characters"));
5454
}

Tracebit.Cli/Commands/Utils.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,20 @@ public static bool IsLabelFormat(string input)
131131
return LabelFormat().IsMatch(input);
132132
}
133133

134+
public static bool IsValidSshKeyFileName(string fileName)
135+
{
136+
if (string.IsNullOrEmpty(fileName))
137+
return false;
138+
if (fileName.Any(char.IsWhiteSpace))
139+
return false;
140+
if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
141+
return false;
142+
// Ensure it's a file name and not a path (check both separators regardless of platform)
143+
if (fileName.Contains('/') || fileName.Contains('\\'))
144+
return false;
145+
return true;
146+
}
147+
134148
public static void PrintCanaryRemovalFailedUsingForce(string reason)
135149
{
136150
AnsiConsole.MarkupLineInterpolated(

0 commit comments

Comments
 (0)