Compare commits

...

5 Commits

Author SHA1 Message Date
Thomas Boop
21c30edf1e Update releaseVersion 2022-09-08 13:38:20 -04:00
Thomas Boop
96f4f5e76e 2.296.2 Release notes (#2107)
* fix issue with env's overwriting environment

* add release notes

* handle value escaping

* compile regex for runtime perf improvements
2022-09-08 13:36:38 -04:00
Thomas Boop
219852abcb Update releaseVersion 2022-08-31 13:40:17 -04:00
Thomas Boop
8dc5ca2208 2.296.1 Release (#2092)
* docker: escape key-value pair as -e KEY and VALUE being environment var

* removed code duplication, removed unused method and test

* add release notes

Co-authored-by: Nikola Jokic <nikola-jokic@github.com>
2022-08-31 13:39:32 -04:00
Thomas Boop
0f4622653b Update releaseVersion 2022-08-23 10:52:30 -04:00
5 changed files with 37 additions and 26 deletions

View File

@@ -1,9 +1,6 @@
## Bugs ## Bugs
- Avoid key based command injection via Docker command arguments (#2062) - Fixed an issue where self hosted environments had their docker env's overwritten (#2107)
## Misc ## Misc
- Added step context name and start/finish time in step telemetry (#2069)
- Improved error logs when there is a missing 'using' token configuration in the metadata file (#2052)
- Added full job name and nested workflow details in log (#2049)
## Windows x64 ## Windows x64
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows. We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.

View File

@@ -1 +1 @@
<Update to ./src/runnerversion when creating release> 2.296.2

View File

@@ -6,6 +6,9 @@ namespace GitHub.Runner.Worker.Container
{ {
public class DockerUtil public class DockerUtil
{ {
private static readonly Regex QuoteEscape = new Regex(@"(\\*)" + "\"", RegexOptions.Compiled);
private static readonly Regex EndOfStringEscape = new Regex(@"(\\+)$", RegexOptions.Compiled);
public static List<PortMapping> ParseDockerPort(IList<string> portMappingLines) public static List<PortMapping> ParseDockerPort(IList<string> portMappingLines)
{ {
const string targetPort = "targetPort"; const string targetPort = "targetPort";
@@ -68,7 +71,7 @@ namespace GitHub.Runner.Worker.Container
{ {
return ""; return "";
} }
return $"{flag} \"{EscapeString(key)}\""; return $"{flag} {EscapeString(key)}";
} }
public static string CreateEscapedOption(string flag, string key, string value) public static string CreateEscapedOption(string flag, string key, string value)
@@ -77,12 +80,28 @@ namespace GitHub.Runner.Worker.Container
{ {
return ""; return "";
} }
return $"{flag} \"{EscapeString(key)}={EscapeString(value)}\""; var escapedString = EscapeString($"{key}={value}");
return $"{flag} {escapedString}";
} }
private static string EscapeString(string value) 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 = QuoteEscape.Replace(value, @"$1$1\" + "\"");
// 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 = EndOfStringEscape.Replace(value, @"$1$1");
// Finally, wrap it in quotes
return $"\"{value}\"";
} }
} }
} }

View File

@@ -149,13 +149,12 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Worker")] [Trait("Category", "Worker")]
[InlineData("", "")] [InlineData("", "")]
[InlineData("HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #")] [InlineData("foo", "foo")]
[InlineData("HOME \"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #")] [InlineData("foo \\ bar", "foo \\ bar")]
[InlineData("HOME \\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #")] [InlineData("foo \\", "foo \\\\")]
[InlineData("HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #")] [InlineData("foo \\\\", "foo \\\\\\\\")]
[InlineData("HOME \"\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #")] [InlineData("foo \\\" bar", "foo \\\\\\\" bar")]
[InlineData("HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\\\\\"\\\"alpine:3.8 sh -c id #")] [InlineData("foo \\\\\" bar", "foo \\\\\\\\\\\" bar")]
[InlineData("HOME \"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #")]
public void CreateEscapedOption_keyOnly(string input, string escaped) public void CreateEscapedOption_keyOnly(string input, string escaped)
{ {
var flag = "--example"; var flag = "--example";
@@ -175,15 +174,11 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
[Theory] [Theory]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Worker")] [Trait("Category", "Worker")]
[InlineData("HOME", "", "HOME", "")] [InlineData("foo", "bar", "foo=bar")]
[InlineData("HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #")] [InlineData("foo\\", "bar", "foo\\=bar")]
[InlineData("HOME \"alpine:3.8 sh -c id #", "HOME \"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #")] [InlineData("foo\\", "bar\\", "foo\\=bar\\\\")]
[InlineData("HOME \\\"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #")] [InlineData("foo \\","bar \\", "foo \\=bar \\\\")]
[InlineData("HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #")] public void CreateEscapedOption_keyValue(string keyInput, string valueInput, string escapedString)
[InlineData("HOME \"\"alpine:3.8 sh -c id #", "HOME \"\"alpine:3.8 sh -c id #", "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 #", "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 #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #")]
public void CreateEscapedOption_keyValue(string keyInput, string valueInput, string escapedKey, string escapedValue)
{ {
var flag = "--example"; var flag = "--example";
var actual = DockerUtil.CreateEscapedOption(flag, keyInput, valueInput); var actual = DockerUtil.CreateEscapedOption(flag, keyInput, valueInput);
@@ -194,7 +189,7 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
} }
else else
{ {
expected = $"{flag} \"{escapedKey}={escapedValue}\""; expected = $"{flag} \"{escapedString}\"";
} }
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }

View File

@@ -1 +1 @@
2.296.0 2.296.2