Skip to content

Commit a2687bf

Browse files
SteveL-MSFTlzybkr
authored andcommitted
Allow profile directory creation failures for Service Account scenarios (#3244)
XDG profile directory creation can fail for accounts that do not have home directories. The module analysis was trying to persist it's cache in an XDG profile directory. The cache is less critical than it once was, so it's reasonable to not cache if there is no good place to do so. Fixes #3011
1 parent df0a390 commit a2687bf

3 files changed

Lines changed: 69 additions & 6 deletions

File tree

src/System.Management.Automation/CoreCLR/CorePsPlatform.cs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,14 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
261261
// create the xdg folder if needed
262262
if (!Directory.Exists(xdgDataHomeDefault))
263263
{
264-
Directory.CreateDirectory(xdgDataHomeDefault);
264+
try
265+
{
266+
Directory.CreateDirectory(xdgDataHomeDefault);
267+
}
268+
catch (UnauthorizedAccessException)
269+
{
270+
//service accounts won't have permission to create user folder
271+
}
265272
}
266273
return xdgDataHomeDefault;
267274
}
@@ -277,7 +284,14 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
277284
//xdg values have not been set
278285
if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist
279286
{
280-
Directory.CreateDirectory(xdgModuleDefault);
287+
try
288+
{
289+
Directory.CreateDirectory(xdgModuleDefault);
290+
}
291+
catch (UnauthorizedAccessException)
292+
{
293+
//service accounts won't have permission to create user folder
294+
}
281295
}
282296
return xdgModuleDefault;
283297
}
@@ -296,7 +310,14 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
296310
//xdg values have not been set
297311
if (!Directory.Exists(xdgCacheDefault)) //module folder not always guaranteed to exist
298312
{
299-
Directory.CreateDirectory(xdgCacheDefault);
313+
try
314+
{
315+
Directory.CreateDirectory(xdgCacheDefault);
316+
}
317+
catch (UnauthorizedAccessException)
318+
{
319+
//service accounts won't have permission to create user folder
320+
}
300321
}
301322

302323
return xdgCacheDefault;
@@ -306,7 +327,14 @@ public static string SelectProductNameForDirectory(Platform.XDG_Type dirpath)
306327
{
307328
if (!Directory.Exists(Path.Combine(xdgcachehome, "powershell")))
308329
{
309-
Directory.CreateDirectory(Path.Combine(xdgcachehome, "powershell"));
330+
try
331+
{
332+
Directory.CreateDirectory(Path.Combine(xdgcachehome, "powershell"));
333+
}
334+
catch (UnauthorizedAccessException)
335+
{
336+
//service accounts won't have permission to create user folder
337+
}
310338
}
311339

312340
return Path.Combine(xdgcachehome, "powershell");

src/System.Management.Automation/engine/Modules/AnalysisCache.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,14 +618,16 @@ private static byte[] GetHeader()
618618

619619
private int _saveCacheToDiskQueued;
620620

621+
private bool _saveCacheToDisk = true;
622+
621623
public void QueueSerialization()
622624
{
623625
// We expect many modules to rapidly call for serialization.
624626
// Instead of doing it right away, we'll queue a task that starts writing
625627
// after it seems like we've stopped adding stuff to write out. This is
626628
// avoids blocking the pipeline thread waiting for the write to finish.
627629
// We want to make sure we only queue one task.
628-
if (Interlocked.Increment(ref _saveCacheToDiskQueued) == 1)
630+
if (_saveCacheToDisk && Interlocked.Increment(ref _saveCacheToDiskQueued) == 1)
629631
{
630632
Task.Run(async delegate
631633
{
@@ -694,6 +696,8 @@ private static void Write(string val, byte[] bytes, FileStream stream)
694696
private void Serialize(string filename)
695697
{
696698
AnalysisCacheData fromOtherProcess = null;
699+
Diagnostics.Assert(_saveCacheToDisk != false, "Serialize should never be called without going through QueueSerialization which has a check");
700+
697701
try
698702
{
699703
if (Utils.NativeFileExists(filename))
@@ -710,7 +714,16 @@ private void Serialize(string filename)
710714
var folder = Path.GetDirectoryName(filename);
711715
if (!Directory.Exists(folder))
712716
{
713-
Directory.CreateDirectory(folder);
717+
try
718+
{
719+
Directory.CreateDirectory(folder);
720+
}
721+
catch (UnauthorizedAccessException)
722+
{
723+
// service accounts won't be able to create directory
724+
_saveCacheToDisk = false;
725+
return;
726+
}
714727
}
715728
}
716729
}

test/powershell/Host/ConsoleHost.Tests.ps1

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,28 @@ foo
381381
}
382382
}
383383
}
384+
385+
Context "Data, Config, and Cache locations" {
386+
BeforeEach {
387+
$XDG_CACHE_HOME = $env:XDG_CACHE_HOME
388+
$XDG_DATA_HOME = $env:XDG_DATA_HOME
389+
$XDG_CONFIG_HOME = $env:XDG_CONFIG_HOME
390+
}
391+
392+
AfterEach {
393+
$env:XDG_CACHE_HOME = $XDG_CACHE_HOME
394+
$env:XDG_DATA_HOME = $XDG_DATA_HOME
395+
$env:XDG_CONFIG_HOME = $XDG_CONFIG_HOME
396+
}
397+
398+
It "Should start if Data, Config, and Cache location is not accessible" -skip:($IsWindows) {
399+
$env:XDG_CACHE_HOME = "/dev/cpu"
400+
$env:XDG_DATA_HOME = "/dev/cpu"
401+
$env:XDG_CONFIG_HOME = "/dev/cpu"
402+
$output = & powershell -noprofile -Command { (get-command).count }
403+
[int]$output | Should BeGreaterThan 0
404+
}
405+
}
384406
}
385407

386408
Describe "Console host api tests" -Tag CI {

0 commit comments

Comments
 (0)