Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.296.2 Release notes #2107

Merged
merged 4 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion releaseNote.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Bugs
- Fixed an issue where job and service container envs were corrupted (#2091)
- Fixed an issue where self hosted environments had their docker env's overwritten (#2107)
## Misc

## Windows x64
Expand Down
13 changes: 3 additions & 10 deletions src/Runner.Worker/Container/DockerCommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ public async Task<int> DockerBuild(IExecutionContext context, string workingDire
public async Task<string> DockerCreate(IExecutionContext context, ContainerInfo container)
{
IList<string> dockerOptions = new List<string>();
IDictionary<string, string> environment = new Dictionary<string, string>();
// OPTIONS
dockerOptions.Add($"--name {container.ContainerDisplayName}");
dockerOptions.Add($"--label {DockerInstanceLabel}");
Expand Down Expand Up @@ -136,8 +135,7 @@ public async Task<string> DockerCreate(IExecutionContext context, ContainerInfo
}
else
{
environment.Add(env.Key, env.Value);
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key));
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key, env.Value));
}
}

Expand Down Expand Up @@ -185,7 +183,7 @@ public async Task<string> DockerCreate(IExecutionContext context, ContainerInfo
dockerOptions.Add($"{container.ContainerEntryPointArgs}");

var optionsString = string.Join(" ", dockerOptions);
List<string> outputStrings = await ExecuteDockerCommandAsync(context, "create", optionsString, environment);
List<string> outputStrings = await ExecuteDockerCommandAsync(context, "create", optionsString);

return outputStrings.FirstOrDefault();
}
Expand Down Expand Up @@ -445,11 +443,6 @@ public Task<int> DockerLogin(IExecutionContext context, string configFileDirecto
}

private async Task<List<string>> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options)
{
return await ExecuteDockerCommandAsync(context, command, options, null);
}

private async Task<List<string>> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options, IDictionary<string, string> environment)
{
string arg = $"{command} {options}".Trim();
context.Command($"{DockerPath} {arg}");
Expand Down Expand Up @@ -477,7 +470,7 @@ await processInvoker.ExecuteAsync(
workingDirectory: context.GetGitHubContext("workspace"),
fileName: DockerPath,
arguments: arg,
environment: environment,
environment: null,
requireExitCodeZero: true,
outputEncoding: null,
cancellationToken: CancellationToken.None);
Expand Down
29 changes: 27 additions & 2 deletions src/Runner.Worker/Container/DockerUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,37 @@ public static string CreateEscapedOption(string flag, string key)
{
return "";
}
return $"{flag} \"{EscapeString(key)}\"";
return $"{flag} {EscapeString(key)}";
}

public static string CreateEscapedOption(string flag, string key, string value)
{
if (String.IsNullOrEmpty(key))
{
return "";
}
var escapedString = EscapeString($"{key}={value}");
return $"{flag} {escapedString}";
}

private static string EscapeString(string value)
{
return value.Replace("\\", "\\\\").Replace("\"", "\\\"");
if (String.IsNullOrEmpty(value))
{
return "";
}
// Dotnet escaping rules are weird here, we can only escape \ if it precedes a "
// If a double quotation mark follows two or an even number of backslashes, each proceeding backslash pair is replaced with one backslash and the double quotation mark is removed.
// If a double quotation mark follows an odd number of backslashes, including just one, each preceding pair is replaced with one backslash and the remaining backslash is removed; however, in this case the double quotation mark is not removed.
// https://docs.microsoft.com/en-us/dotnet/api/system.environment.getcommandlineargs?redirectedfrom=MSDN&view=net-6.0#remarks

// First, find any \ followed by a " and double the number of \ + 1.
value = Regex.Replace(value, @"(\\*)" + "\"", @"$1$1\" + "\"");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: formatting

// Next, what if it ends in `\`, it would escape the end quote. So, we need to detect that at the end of the string and perform the same escape
// Luckily, we can just use the $ character with detects the end of string in regex
value = Regex.Replace(value, @"(\\+)$", @"$1$1");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we compile these regexes?

// Finally, wrap it in quotes
return $"\"{value}\"";
}
}
}
36 changes: 29 additions & 7 deletions src/Test/L0/Container/DockerUtilL0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,12 @@ public void ParseRegistryHostnameFromImageName(string input, string expected)
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
[InlineData("", "")]
[InlineData("HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #")]
[InlineData("HOME \"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \"\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\\\\\"\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #")]
[InlineData("foo", "foo")]
[InlineData("foo \\ bar", "foo \\ bar")]
[InlineData("foo \\", "foo \\\\")]
[InlineData("foo \\\\", "foo \\\\\\\\")]
[InlineData("foo \\\" bar", "foo \\\\\\\" bar")]
[InlineData("foo \\\\\" bar", "foo \\\\\\\\\\\" bar")]
public void CreateEscapedOption_keyOnly(string input, string escaped)
{
var flag = "--example";
Expand All @@ -171,5 +170,28 @@ public void CreateEscapedOption_keyOnly(string input, string escaped)
}
Assert.Equal(expected, actual);
}

[Theory]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
[InlineData("foo", "bar", "foo=bar")]
[InlineData("foo\\", "bar", "foo\\=bar")]
[InlineData("foo\\", "bar\\", "foo\\=bar\\\\")]
[InlineData("foo \\","bar \\", "foo \\=bar \\\\")]
public void CreateEscapedOption_keyValue(string keyInput, string valueInput, string escapedString)
{
var flag = "--example";
var actual = DockerUtil.CreateEscapedOption(flag, keyInput, valueInput);
string expected;
if (String.IsNullOrEmpty(keyInput))
{
expected = "";
}
else
{
expected = $"{flag} \"{escapedString}\"";
}
Assert.Equal(expected, actual);
}
}
}
2 changes: 1 addition & 1 deletion src/runnerversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.296.1
2.296.2