Compare commits

...
2 changed files with 95 additions and 10 deletions
+16 -1
View File
@@ -5,8 +5,8 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -407,6 +407,21 @@ namespace GitHub.Runner.Listener
{ {
Trace.Info(nameof(RunAsync)); Trace.Info(nameof(RunAsync));
// Validate directory permissions.
string workDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
Trace.Info($"Validating directory permissions for: '{workDirectory}'");
try
{
Directory.CreateDirectory(workDirectory);
IOUtil.ValidateExecutePermission(workDirectory);
}
catch (Exception ex)
{
Trace.Error(ex);
_term.WriteError($"Fail to create and validate runner's work directory '{workDirectory}'.");
return Constants.Runner.ReturnCode.TerminatedError;
}
// First try using migrated settings if available // First try using migrated settings if available
var configManager = HostContext.GetService<IConfigurationManager>(); var configManager = HostContext.GetService<IConfigurationManager>();
RunnerSettings migratedSettings = null; RunnerSettings migratedSettings = null;
+70
View File
@@ -1076,5 +1076,75 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(hc.AllowAuthMigration); Assert.True(hc.AllowAuthMigration);
} }
} }
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task RunCommand_ShouldReturnTerminatedError_WhenWorkDirCreationFails()
{
using (var hostCtx = new TestHostContext(this))
{
// Setup: arrange mocks and runner instance
var runnerInstance = new Runner.Listener.Runner();
hostCtx.SetSingleton<IConfigurationManager>(_configurationManager.Object);
hostCtx.SetSingleton<IJobNotification>(_jobNotification.Object);
hostCtx.SetSingleton<IMessageListener>(_messageListener.Object);
hostCtx.SetSingleton<IPromptManager>(_promptManager.Object);
hostCtx.SetSingleton<IConfigurationStore>(_configStore.Object);
hostCtx.SetSingleton<IRunnerServer>(_runnerServer.Object);
hostCtx.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
runnerInstance.Initialize(hostCtx);
// Create a file at the work directory path to block directory creation
string workPath = hostCtx.GetDirectory(WellKnownDirectory.Work);
// Clean up any existing directory first
if (Directory.Exists(workPath))
{
Directory.Delete(workPath, recursive: true);
}
// Place a file where the work directory should be - this blocks Directory.CreateDirectory
string parentPath = Path.GetDirectoryName(workPath);
Assert.NotNull(parentPath);
Assert.NotEmpty(parentPath);
Directory.CreateDirectory(parentPath);
const string blockingFileContent = "test file blocking directory creation";
File.WriteAllText(workPath, blockingFileContent);
const int testPoolId = 12345;
const int testAgentId = 67890;
var runnerConfig = new RunnerSettings
{
PoolId = testPoolId,
AgentId = testAgentId
};
_configurationManager.Setup(m => m.LoadSettings()).Returns(runnerConfig);
_configurationManager.Setup(m => m.IsConfigured()).Returns(true);
_configStore.Setup(m => m.IsServiceConfigured()).Returns(false);
try
{
// Execute: run the command which should fail during work dir validation
var cmd = new CommandSettings(hostCtx, new string[] { "run" });
int exitCode = await runnerInstance.ExecuteCommand(cmd);
// Verify: should return TerminatedError code when dir creation fails
Assert.Equal(Constants.Runner.ReturnCode.TerminatedError, exitCode);
}
finally
{
// Cleanup: remove the blocking file
if (File.Exists(workPath))
{
File.Delete(workPath);
}
}
}
}
} }
} }