Example #1
0
        public void BreakawayProcessCanReportAugmentedAccesses()
        {
            var fam = new FileAccessManifest(
                Context.PathTable,
                childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName })
            {
                FailUnexpectedFileAccesses   = false,
                ReportUnexpectedFileAccesses = true,
                ReportFileAccesses           = true
            };

            var srcFile = CreateSourceFile();
            var output  = CreateOutputFileArtifact();

            fam.AddScope(srcFile, FileAccessPolicy.MaskNothing, FileAccessPolicy.ReportAccess);
            fam.AddScope(output, FileAccessPolicy.MaskNothing, FileAccessPolicy.ReportAccess);

            var info = ToProcessInfo(
                ToProcess(
                    Operation.AugmentedRead(srcFile),
                    Operation.AugmentedWrite(output)),
                fileAccessManifest: fam);

            var result = RunProcess(info).GetAwaiter().GetResult();

            XAssert.AreEqual(0, result.ExitCode);

            var observedAccesses = result.FileAccesses.Select(fa => fa.ManifestPath);

            XAssert.Contains(observedAccesses, srcFile.Path, output.Path);
        }
        public void ValidateCompleteness()
        {
            // TODO: Dig into whether ipcSend should be allowed in config
            HashSet <string> ignoredMethods = new HashSet <string>()
            {
                "ScheduleProcessPip",
                "WriteDataCore",
                "GetBuildXLBinDirectoryToBeDeprecated",
                "GetNewIpcMoniker",
                "GetBuildEngineDirectoryToBeDeprecated",
            };

            // Extract string parameter for each InlineDataAttribute for each method.
            string[] inlineDataContent = this.GetType().GetMethods()
                                         .SelectMany(mi => mi.GetCustomAttributes <InlineDataAttribute>().Select(attr => (string)attr?.GetData(null)?.FirstOrDefault()[0]))
                                         .Select(s => s.Substring(0, s.IndexOf("(")))
                                         .ToArray();

            XAssert.All(GetAmbientMethods(AmbientContext.ContextName, typeof(AmbientContext))
                        .Concat(GetAmbientMethods(AmbientTransformerOriginal.Name, typeof(AmbientTransformerOriginal)))
                        .Concat(GetAmbientMethods(AmbientContract.ContractName, typeof(AmbientContract)))
                        .Concat(GetAmbientMethods(AmbientFile.FileName, typeof(AmbientFile)))
                        .ToArray(),
                        funcName => XAssert.Contains(inlineDataContent, funcName));

            IEnumerable <string> GetAmbientMethods(string name, System.Type type)
            {
                return(type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly)
                       .Where(mi => mi.ReturnType == typeof(EvaluationResult) && !ignoredMethods.Contains(mi.Name))
                       .Select(mi => $"{name}.{char.ToLowerInvariant(mi.Name[0])}{mi.Name.Substring(1)}"));
            }
        }
Example #3
0
        public async Task TestDynamicallyLoadedLibrariesReportedOnLinux()
        {
            if (!OperatingSystemHelper.IsLinuxOS)
            {
                return;
            }

            var proc = ToProcess(Operation.Echo("hi"));
            var info = ToProcessInfo(proc, nameof(TestDynamicallyLoadedLibrariesReportedOnLinux));

            info.FileAccessManifest.ReportFileAccesses         = true;
            info.FileAccessManifest.FailUnexpectedFileAccesses = false;
            using ISandboxedProcess process = await StartProcessAsync(info);

            var result = await process.GetResultAsync();

            XAssert.AreEqual(0, result.ExitCode);
            var accesses = result.FileAccesses
                           .Select(fa => fa.GetPath(Context.PathTable))
                           .Where(p => p.EndsWith(".so"))
                           .Select(p => Path.GetFileName(p))
                           .Select(n => n.Contains('-') ? n.Substring(0, n.IndexOf('-')) + ".so" : n)
                           .Distinct()
                           .ToHashSet();

            XAssert.Contains(accesses, new[]
            {
                "ld.so", "libc.so", "libdl.so", "libm.so", "libpthread.so", "librt.so",
                "libclrjit.so", "libcoreclr.so", "libcoreclrtraceptprovider.so",
                "libhostfxr.so", "libhostpolicy.so", "libmscordaccore.so", "libmscordbi.so",
            });

            XAssert.ContainsNot(accesses, new[] { "libDetours.so" });
        }
        public async Task TestShimChildProcessWithPluginAndNonEmptyMatchesAsync(bool shimAllProcesses, bool shouldBeShimmed, bool shouldFindMatch)
        {
            var stdOutSb = new StringBuilder(128);
            var stdErrSb = new StringBuilder();

            SandboxedProcessResult result = await RunWithPluginAsync(
                shimAllProcesses : shimAllProcesses,
                shouldBeShimmed : shouldBeShimmed,
                shouldFindMatch : shouldFindMatch,
                processMatches : shouldFindMatch?new[] { "cmd.exe" } : new[] { "foo.exe" },
                stdOutSb : stdOutSb,
                stdErrSb : stdErrSb);

            string stdOut = stdOutSb.ToString();
            string stdErr = stdErrSb.ToString();

            m_output.WriteLine($"stdout: {stdOut}");
            m_output.WriteLine($"stderr: {stdErr}");

            AssertSuccess(result, stdErr);

            if (shimAllProcesses)
            {
                AssertShimmedIf(stdOut, !shouldFindMatch || !shouldBeShimmed);
            }
            else
            {
                AssertShimmedIf(stdOut, shouldFindMatch && shouldBeShimmed);
            }

            XAssert.Contains(stdOut, GetChildOutputForPluginTest(shouldBeShimmed));
        }
        public async Task TestShimChildProcessWithPluginWithModifiedArgumentAsync()
        {
            var stdOutSb = new StringBuilder(128);
            var stdErrSb = new StringBuilder();

            SandboxedProcessResult result = await RunWithPluginAsync(
                shimAllProcesses : false,
                shouldBeShimmed : true,
                shouldFindMatch : false,
                processMatches : new string[0],
                stdOutSb : stdOutSb,
                stdErrSb : stdErrSb,
                shimmedText : "@responseFile");

            string stdOut = stdOutSb.ToString();
            string stdErr = stdErrSb.ToString();

            m_output.WriteLine($"stdout: {stdOut}");
            m_output.WriteLine($"stderr: {stdErr}");

            AssertSuccess(result, stdErr);
            AssertShimmed(stdOut);

            // Since shimmedText has '@', it will be replaced by "Content".
            // CODESYNC: Public\Src\Engine\UnitTests\Processes.TestPrograms\SubstituteProcessExecutionPlugin\dllmain.cpp
            XAssert.Contains(stdOut, GetChildOutputForPluginTest(true, "Content"));
        }
        public void RunSingleProcessWithSharedOpaqueOutputLogging()
        {
            var sharedOpaqueDir               = Path.Combine(ObjectRoot, "partialDir");
            var sharedOpaqueDirPath           = AbsolutePath.Create(Context.PathTable, sharedOpaqueDir);
            var sharedOpaqueDirectoryArtifact = DirectoryArtifact.CreateWithZeroPartialSealId(sharedOpaqueDirPath);
            var outputInSharedOpaque          = CreateOutputFileArtifact(sharedOpaqueDir);
            var source = CreateSourceFile();

            var builder = CreatePipBuilder(new[]
            {
                Operation.WriteFile(outputInSharedOpaque, content: "sod-out", doNotInfer: true)
            });

            builder.AddOutputDirectory(sharedOpaqueDirectoryArtifact, SealDirectoryKind.SharedOpaque);
            builder.Options |= Process.Options.RequiresAdmin;

            var pip = SchedulePipBuilder(builder);

            // run once and assert success
            var result = RunScheduler().AssertSuccess();

            // check that shared opaque outputs have been logged in the sideband file
            var writesInSidebandFile = GetJournaledWritesForProcess(result, pip.Process);

            XAssert.Contains(writesInSidebandFile, outputInSharedOpaque);
            XAssert.ContainsNot(writesInSidebandFile, pip.ProcessOutputs.GetOutputFiles().Select(f => f.Path).ToArray());

            // run again and assert cache hit
            RunScheduler().AssertCacheHit(pip.Process.PipId);

            // assert sideband files were used for scrubbing
            AssertInformationalEventLogged(EventId.DeletingOutputsFromSharedOpaqueSidebandFilesStarted, count: 1);
            AssertInformationalEventLogged(EventId.DeletingSharedOpaqueSidebandFilesStarted, count: 1);
        }
Example #7
0
        public void QualifierBasedTagsAreSet()
        {
            // Writes a file using a process pip with user defined tags 'test1' and 'test2'
            string spec = @"
import {Cmd, Transformer} from 'Sdk.Transformers';

export declare const qualifier: {platform: 'x86' | 'x64'; configuration: 'debug' | 'release'};

const outDir = Context.getNewOutputDirectory('tags');

const result = Transformer.execute({
    tool: {" +
                          $"exe: f`{(OperatingSystemHelper.IsUnixOS ? "/bin/sh" : @"${Environment.getPathValue(""COMSPEC"")}")}`"
                          + @"},
    workingDirectory: d`.`,
    arguments: [ Cmd.rawArgument('" + $"{(OperatingSystemHelper.IsUnixOS ? "-c echo test > obj/a.txt" : @"/d /c echo test > obj\a.txt")}" + @"'),
    ],
    outputs: [
        p`${outDir}/obj/a.txt`,
    ],
    tags: ['test1', 'test2']
});
";

            using (var tempFiles = new TempFileStorage(canGetFileNames: true, rootPath: TestOutputDirectory))
            {
                var appDeployment = CreateAppDeployment(tempFiles);

                // Configure the initial qualifier to be configuration=debug, platform=x64
                var config = Build()
                             .Configuration(@"
config({
    qualifiers: {
        defaultQualifier: {
            configuration: 'debug',
            platform: 'x64'
        }
    }
});")
                             .AddSpec(spec)
                             .PersistSpecsAndGetConfiguration();

                // Scheduling is enough, we just want to inspect the tags
                ((CommandLineConfiguration)config).Engine.Phase = global::BuildXL.Utilities.Configuration.EnginePhases.Schedule;

                var engineResult = CreateAndRunEngine(
                    config,
                    appDeployment,
                    testRootDirectory: null,
                    rememberAllChangedTrackedInputs: false,
                    engine: out var engine);

                XAssert.IsTrue(engineResult.IsSuccess);

                // The corresponding process pip should have both the user defined tags and the current qualifier tags
                var process = (PipsOperations.Process)engineResult.EngineState.PipGraph.RetrievePipsOfType(PipsOperations.PipType.Process).Single();
                XAssert.Contains(process.Tags.Select(tag => tag.ToString(StringTable)), "test1", "test2", "platform=x64", "configuration=debug");
            }
        }
Example #8
0
        public void TestHandleExceptions(IpcResultStatus status)
        {
            var exceptionMessage = "invalid operation";
            var ipcResult        = Utils.HandleExceptions(status, () => throw new InvalidOperationException(exceptionMessage));

            XAssert.AreEqual(status, ipcResult.ExitCode);
            XAssert.Contains(ipcResult.Payload, exceptionMessage);
        }
Example #9
0
        public void TestDeserializationOfUnknownCommand()
        {
            var    cmd       = new UnknownCommand();
            string str       = Command.Serialize(cmd);
            var    exception = Assert.Throws <ArgumentException>(() => Command.Deserialize(str));

            XAssert.Contains(exception.Message, cmd.TypeName);
        }
        public void ChildProcessCanBreakawayWhenConfigured(bool letInfiniteWaiterSurvive)
        {
            // We use InfiniteWaiter (a process that waits forever) as a long-living process that we can actually check it can
            // escape the job object
            var fam = new FileAccessManifest(
                Context.PathTable,
                childProcessesToBreakawayFromSandbox: letInfiniteWaiterSurvive ? new[] { InfiniteWaiterToolName } : null)
            {
                FailUnexpectedFileAccesses = false
            };

            // We instruct the regular test process to spawn InfiniteWaiter as a child
            var info = ToProcessInfo(
                ToProcess(
                    Operation.SpawnExe(
                        Context.PathTable,
                        CreateFileArtifactWithName(InfiniteWaiterToolName, TestDeploymentDir))),
                fileAccessManifest: fam);

            // Let's shorten the default time to wait for nested processes, since we are spawning
            // a process that never ends and we don't want this test to wait for that long
            info.NestedProcessTerminationTimeout = TimeSpan.FromMilliseconds(10);

            var result = RunProcess(info).GetAwaiter().GetResult();

            XAssert.AreEqual(0, result.ExitCode);

            if (!letInfiniteWaiterSurvive)
            {
                // If we didn't let infinite waiter escape, we should have killed it when the job object was finalized
                XAssert.IsTrue(result.Killed);
                XAssert.Contains(
                    result.SurvivingChildProcesses.Select(p => p?.Path).Where(p => p != null).Select(p => System.IO.Path.GetFileName(p).ToUpperInvariant()),
                    InfiniteWaiterToolName.ToUpperInvariant());
            }
            else
            {
                // If we did let it escape, then nothing should have been killed (nor tried to survive and later killed, from the job object point of view)
                XAssert.IsFalse(result.Killed);
                if (result.SurvivingChildProcesses != null)
                {
                    var survivors = string.Join(
                        ", ",
                        result.SurvivingChildProcesses.Select(p => p?.Path != null ? System.IO.Path.GetFileName(p.Path) : "<unknown>"));
                    XAssert.Fail($"Unexpected {result.SurvivingChildProcesses.Count()} surviving child processes: {survivors}");
                }

                // Let's retrieve the child process and confirm it survived
                var infiniteWaiterInfo = RetrieveChildProcessesCreatedBySpawnExe(result).Single();
                // The fact that this does not throw confirms survival
                var dummyWaiter = Process.GetProcessById(infiniteWaiterInfo.pid);
                // Just being protective, let's make sure we are talking about the same process
                XAssert.AreEqual(infiniteWaiterInfo.processName, dummyWaiter.ProcessName);

                // Now let's kill the surviving process, since we don't want it to linger around unnecessarily
                dummyWaiter.Kill();
            }
        }
Example #11
0
        public void TestCatastrophicFailureRecovery()
        {
            // Run some valid module
            SetupTestData();
            RunEngine();

            // List the files in the engine cache after a valid run
            var engineCacheDirectory = Configuration.Layout.EngineCacheDirectory.ToString(Context.PathTable);
            var engineCacheFilesList = new List <string>();

            FileUtilities.EnumerateDirectoryEntries(engineCacheDirectory, (file, attributes) =>
            {
                if (!attributes.HasFlag(FileAttributes.Directory))
                {
                    engineCacheFilesList.Add(file);
                }
            });

            var recovery = FailureRecoveryFactory.Create(LoggingContext, Context.PathTable, Configuration);

            // This will trigger the recovery mechanism for unknown catastrophic errors, which is to log and remove the engine state (EngineCache folder)
            XAssert.IsTrue(recovery.TryMarkFailure(new BuildXLException("fake failure"), ExceptionRootCause.Unknown));

            // List the files in the logs directory for corrupt engine cache files
            var logsDirectory = Configuration.Logging.EngineCacheCorruptFilesLogDirectory.ToString(Context.PathTable);
            var logsFilesList = new HashSet <string>();

            FileUtilities.EnumerateDirectoryEntries(logsDirectory, (file, attributes) =>
            {
                logsFilesList.Add(file);
            });

            var childrenCount = Directory.GetFiles(engineCacheDirectory, "*", SearchOption.TopDirectoryOnly).Length;
            var expectedCount = -1;

            // File content table has a special exclusion from the removal policy for performance reasons, but it should still be copied to logs
            // (Unless the file content table doesn't exist in the engine cache, then it doesn't need to exist in the logs)
            var engineCacheFileContentTablePath = Configuration.Layout.FileContentTableFile.ToString(Context.PathTable);
            var fileContentTableFile            = Path.GetFileName(engineCacheFileContentTablePath);

            // Make sure file content table was copied to logs
            XAssert.Contains(logsFilesList, fileContentTableFile);
            expectedCount = 1;

            // Make sure file content table file exists in the engine cache directory after recovery
            XAssert.IsTrue(File.Exists(engineCacheFileContentTablePath));

            // Check to make sure the engine cache directory is empty except for maybe the file content table
            XAssert.AreEqual(expectedCount, childrenCount);

            // Check to make sure all the file from the engine cache directory ended up in the logs directory
            foreach (var file in engineCacheFilesList)
            {
                XAssert.Contains(logsFilesList, file);
            }
        }
Example #12
0
        public async Task TestConnectWithRetriesFailsAsync()
        {
            var errMessage      = "can't connect";
            var maybeConnection = await Utils.ConnectAsync <int>(
                maxRetry : 2,
                waitTimeBetweenAttempts : TimeSpan.FromMilliseconds(1),
                connectionFactory : () => throw new InvalidOperationException(errMessage));

            XAssert.IsFalse(maybeConnection.Succeeded);
            XAssert.Contains(maybeConnection.Failure.DescribeIncludingInnerFailures(), errMessage);
        }
Example #13
0
        public void IncorrectSwitchDoesNotFailLogger()
        {
            var result = RunMSBuild($"Win32ManifestFile='does/not/exist'", out string standardOutput);

            // The run should fail
            XAssert.AreNotEqual(0, result);

            // The reason should be because an unexpected task attribute (MSB4064), but not because of a logger failure
            XAssert.ContainsNot(standardOutput, "InvalidOperationException");
            XAssert.Contains(standardOutput, "MSB4064");
        }
Example #14
0
        public void TestIpcResultMerge(IpcResultStatus lhsStatus, IpcResultStatus rhsStatus, IpcResultStatus mergeStatus)
        {
            var lhs    = new IpcResult(lhsStatus, "lhs");
            var rhs    = new IpcResult(rhsStatus, "rhs");
            var merged = IpcResult.Merge(lhs, rhs);

            // contains both payloads
            XAssert.Contains(merged.Payload, lhs.Payload, rhs.Payload);
            // has correct status
            XAssert.AreEqual(merged.ExitCode, mergeStatus);
        }
Example #15
0
 private static void AssertShimmedIf(string output, bool shimmedCondition)
 {
     if (shimmedCondition)
     {
         XAssert.Contains(output, ShimOutput);
     }
     else
     {
         XAssert.ContainsNot(output, ShimOutput);
     }
 }
Example #16
0
        public void ValidateStringMatch()
        {
            var aBuild   = CreateJavaScriptProject("project-A", "build");
            var aTest    = CreateJavaScriptProject("project-A", "test");
            var bBuild   = CreateJavaScriptProject("project-B", "build");
            var selector = new JavaScriptProjectSelector(new[] { aBuild, aTest, bBuild });

            var result = selector.GetMatches("project-A");

            XAssert.Contains(result, aBuild, aTest);
            XAssert.ContainsNot(result, bBuild);
        }
Example #17
0
        public async Task TestClientWhenCommandThrowsAsync()
        {
            var exceptionMessage = "invalid operation";

            using var apiClient = CreateApiClient(ipcOperation =>
            {
                throw new InvalidOperationException(exceptionMessage);
            });
            var maybeResult = await apiClient.LogMessage("hi");

            XAssert.IsFalse(maybeResult.Succeeded);
            XAssert.Contains(maybeResult.Failure.DescribeIncludingInnerFailures(), exceptionMessage);
        }
Example #18
0
        public async Task TestClientWhenCommandReturnsBogusValueAsync()
        {
            var bogusPayload = "bogus payload";

            using var apiClient = CreateApiClient(ipcOperation =>
            {
                return(new IpcResult(IpcResultStatus.Success, bogusPayload));
            });
            var maybeResult = await apiClient.LogMessage("hi");

            XAssert.IsFalse(maybeResult.Succeeded);
            XAssert.Contains(maybeResult.Failure.DescribeIncludingInnerFailures(), bogusPayload, Client.ErrorCannotParseIpcResultMessage);
        }
Example #19
0
        public async Task TestClientWhenCommandFailsAsync()
        {
            var errorPayload = "operation failed";

            using var apiClient = CreateApiClient(ipcOperation =>
            {
                return(new IpcResult(IpcResultStatus.GenericError, errorPayload));
            });
            var maybeResult = await apiClient.LogMessage("hi");

            XAssert.IsFalse(maybeResult.Succeeded);
            XAssert.Contains(maybeResult.Failure.DescribeIncludingInnerFailures(), errorPayload);
        }
Example #20
0
        public void ScriptNameIsSetAsTag()
        {
            var project = CreateRushProject(scriptCommandName: "some-script");

            var processTags = Start()
                              .Add(project)
                              .ScheduleAll()
                              .RetrieveSuccessfulProcess(project)
                              .Tags;

            // The script name should be part of the process tags
            XAssert.Contains(processTags, StringId.Create(StringTable, "some-script"));
        }
Example #21
0
        public void MaskedReportAugmentedAccessIsNotReported(bool reportFileAccesses)
        {
            var fam = new FileAccessManifest(
                Context.PathTable,
                childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName })
            {
                FailUnexpectedFileAccesses   = false,
                ReportUnexpectedFileAccesses = true,
                ReportFileAccesses           = reportFileAccesses
            };

            var basePath = TestBinRootPath.Combine(Context.PathTable, "foo");

            var output1 = CreateOutputFileArtifact(basePath);
            var output2 = CreateOutputFileArtifact(basePath);

            // We mask reporting accesses for output1 and enable it for output2
            fam.AddScope(output1.Path, ~FileAccessPolicy.ReportAccess, FileAccessPolicy.AllowAll);
            fam.AddScope(output2.Path, FileAccessPolicy.MaskNothing, FileAccessPolicy.AllowAll | FileAccessPolicy.ReportAccess);

            var collector = new FileAccessCollector(Context.PathTable);

            var info = ToProcessInfo(
                ToProcess(
                    Operation.AugmentedWrite(output1),
                    Operation.AugmentedWrite(output2)),
                fileAccessManifest: fam,
                detoursListener: collector);

            var result = RunProcess(info).GetAwaiter().GetResult();

            XAssert.AreEqual(0, result.ExitCode);

            // We should get a single explicit access with output2, since output1 shouldn't be reported
            var accessPath = result.ExplicitlyReportedFileAccesses.Single(rfa => rfa.Method == FileAccessStatusMethod.TrustedTool).ManifestPath;

            XAssert.AreEqual(output2.Path, accessPath);

            // We should get both accesses as part of the (optional) FileAccess on request
            if (reportFileAccesses)
            {
                var allTrustedAcceses = result.FileAccesses.Where(rfa => rfa.Method == FileAccessStatusMethod.TrustedTool).Select(rfa => rfa.ManifestPath);
                XAssert.Contains(allTrustedAcceses, output1.Path, output2.Path);
            }
            else
            {
                // Make sure the access related to output1 is not actually reported, and the only one the listener got is output2
                XAssert.Contains(collector.FileAccessPaths, output2.Path);
                XAssert.ContainsNot(collector.FileAccessPaths, output1.Path);
            }
        }
Example #22
0
        public void ExtractFilesDiff()
        {
            var oldData = new[] { A("X", "Y", "a"), A("X", "Y", "b"), A("X", "Y", "c"), A("X", "Y", "d") };
            var newData = new[] { A("X", "Y", "a"), A("X", "Y", "b"), A("X", "Y", "f"), A("X", "Y", "g") };

            bool hasDiff = ExtractUnorderedListDiff(oldData, newData, out var added, out var removed);

            XAssert.IsTrue(hasDiff);
            XAssert.AreEqual(2, added.Count);
            XAssert.AreEqual(2, removed.Count);

            XAssert.Contains(added, A("X", "Y", "f"), A("X", "Y", "g"));
            XAssert.Contains(removed, A("X", "Y", "c"), A("X", "Y", "d"));
        }
Example #23
0
        public void BreakawayProcessIsHonored()
        {
            var project            = CreateRushProject();
            var breakawayTest      = PathAtom.Create(StringTable, "test.exe");
            var breakawayProcesses = Start(new RushResolverSettings {
                ChildProcessesToBreakawayFromSandbox = new[] { breakawayTest }
            })
                                     .Add(project)
                                     .ScheduleAll()
                                     .RetrieveSuccessfulProcess(project)
                                     .ChildProcessesToBreakawayFromSandbox;

            XAssert.Contains(breakawayProcesses, breakawayTest);
        }
        public void SuccessfulCodesAreHonored()
        {
            var project = CreateRushProject();

            var successfullCodes = Start(new RushResolverSettings {
                SuccessExitCodes = new[] { 42 }
            })
                                   .Add(project)
                                   .ScheduleAll()
                                   .RetrieveSuccessfulProcess(project)
                                   .SuccessExitCodes;

            XAssert.Contains(successfullCodes, 42);
        }
Example #25
0
        public async Task CmdWithTestShim_ShimNothingRunsChildProcessWithoutShimAsync(bool shimAllProcess, bool filterMatch)
        {
            var context         = BuildXLContext.CreateInstanceForTesting();
            var shimProgramPath = GetShimProgramPath(context);

            string executable   = CmdHelper.CmdX64;
            string processMatch = filterMatch ? null : "foo.exe"; // Filter should never match foo.exe.

            var fam = CreateCommonFileAccessManifest(context.PathTable);

            fam.SubstituteProcessExecutionInfo = new SubstituteProcessExecutionInfo(
                shimProgramPath,
                shimAllProcesses: shimAllProcess,
                processMatches: processMatch == null
                    ? new ShimProcessMatch[0]
                    : new[] { new ShimProcessMatch(PathAtom.Create(context.StringTable, processMatch), PathAtom.Invalid) });

            string predicate   = shimAllProcess ? string.Empty : "not ";
            string childOutput = $"Child cmd that should {predicate}be shimmed";
            string childArgs   = $"{executable} /D /C @echo {childOutput}";
            string args        = "/D /C echo Top-level cmd. Running child process && " + childArgs;

            var stdOutSb = new StringBuilder(128);
            var stdErrSb = new StringBuilder();

            SandboxedProcessInfo sandboxedProcessInfo = CreateCommonSandboxedProcessInfo(
                context,
                executable,
                args,
                fam,
                stdOutSb,
                stdErrSb);

            ISandboxedProcess sandboxedProcess =
                await SandboxedProcessFactory.StartAsync(sandboxedProcessInfo, forceSandboxing : true)
                .ConfigureAwait(false);

            SandboxedProcessResult result = await sandboxedProcess.GetResultAsync().ConfigureAwait(false);

            string stdOut = stdOutSb.ToString();
            string stdErr = stdErrSb.ToString();

            m_output.WriteLine($"stdout: {stdOut}");
            m_output.WriteLine($"stderr: {stdErr}");

            AssertSuccess(result, stdErr);
            AssertShimmedIf(stdOut, shimAllProcess);
            XAssert.Contains(stdOut, childOutput);
        }
        public void BreakawayProcessIsNotDetoured()
        {
            // TODO: doesn't currently work on Linux
            if (OperatingSystemHelper.IsLinuxOS)
            {
                return;
            }

            var fam = new FileAccessManifest(
                Context.PathTable,
                childProcessesToBreakawayFromSandbox: new[] { TestProcessToolName })
            {
                FailUnexpectedFileAccesses   = false,
                ReportUnexpectedFileAccesses = true,
                ReportFileAccesses           = true
            };

            var srcFile1 = CreateSourceFile();
            var srcFile2 = CreateSourceFile();

            var info = ToProcessInfo(
                ToProcess(
                    Operation.ReadFile(srcFile1),
                    Operation.Spawn(
                        Context.PathTable,
                        true,
                        Operation.ReadFile(srcFile2))),
                fileAccessManifest: fam);

            var result = RunProcess(info).GetAwaiter().GetResult();

            XAssert.AreEqual(0, result.ExitCode);

            var observedAccesses = result.FileAccesses
                                   .Select(reportedAccess => AbsolutePath.TryCreate(Context.PathTable, reportedAccess.GetPath(Context.PathTable), out AbsolutePath result) ? result : AbsolutePath.Invalid)
                                   .ToArray();

            // We should see the access that happens on the main test process
            XAssert.Contains(observedAccesses, srcFile1.Path);
            // We shouldn't see the access that happens on the spawned process
            XAssert.ContainsNot(observedAccesses, srcFile2.Path);

            // Only a single process should be reported: the parent one
            var testProcess = ExcludeInjectedOnes(result.Processes).Single();

            XAssert.AreEqual(TestProcessToolName.ToLowerInvariant(), Path.GetFileName(testProcess.Path).ToLowerInvariant());
        }
Example #27
0
        public void ExistingErrorFileGetsProperlyReported()
        {
            Configuration.Sandbox.OutputReportingMode = global::BuildXL.Utilities.Configuration.OutputReportingMode.TruncatedOutputOnError;
            var text = @"
* BEFORE *
* <error> *
* err1 *
* </error> *
* AFTER *
* <error>err2</error> * <error>err3</error> *
";

            var errRegex = "error";

            var ops = SplitLines(text)
                      .Select(l => Operation.Echo(l, true))
                      .Concat(new[]
            {
                Operation.WriteFile(CreateOutputFileArtifact()),
                Operation.Fail()
            });
            var pipBuilder = CreatePipBuilder(ops);

            pipBuilder.ErrorRegex = new RegexDescriptor(StringId.Create(Context.StringTable, errRegex), RegexOptions.None);
            pipBuilder.EnableMultiLineErrorScanning = false;

            Process pip = SchedulePipBuilder(pipBuilder).Process;

            // Let's make sure a pip process error gets reported
            RunScheduler().AssertFailure();
            AssertErrorEventLogged(LogEventId.PipProcessError);

            // Rerun the pip. Same type of error should occur
            RunScheduler().AssertFailure();
            AssertErrorEventLogged(LogEventId.PipProcessError);

            // Retrieve the error messages for the pip process error for both runs
            var pipProcessErrorMessages = EventListener.GetLogMessagesForEventId((int)LogEventId.PipProcessError);

            XAssert.AreEqual(2, pipProcessErrorMessages.Length);

            // On the first run, standard error should have been copied to a file named err.txt
            XAssert.Contains(pipProcessErrorMessages[0], "err.txt");
            // On the second run, the file existed already, so it should have been renamed
            XAssert.Contains(pipProcessErrorMessages[1], "err.1.txt");
        }
Example #28
0
        private static bool TryVerifySingleReport(PathTable pathTable, ReportedFileAccess actualReport, AccessType access, Dictionary <AbsolutePath, ExpectedReportEntry> pathsToExpectations, out AbsolutePath actualReportedPath)
        {
            string actualReportedPathString = actualReport.GetPath(pathTable);

            if (!AbsolutePath.TryCreate(pathTable, actualReportedPathString, out actualReportedPath))
            {
                return(false);
            }

            ExpectedReportEntry expected;

            if (!pathsToExpectations.TryGetValue(actualReportedPath, out expected))
            {
                return(false);
            }

            XAssert.AreEqual(expected.Exists, !actualReport.IsNonexistent, "Bad assumption on file existence of {0}; this can break ACL decisions", actualReportedPathString);
            XAssert.AreEqual(
                expected.Allowed ? FileAccessStatus.Allowed : FileAccessStatus.Denied,
                actualReport.Status,
                "Incorrect ACL decision for " + actualReportedPathString);

            // on MacOS we cannot distinguish Read vs. Probe for absent files so we always report Probe in those cases
            var expectedAccess = OperatingSystemHelper.IsUnixOS && actualReport.IsNonexistent
                ? RequestedAccess.Probe
                : access == AccessType.Read ? RequestedAccess.Read : RequestedAccess.Probe;

            XAssert.AreEqual(
                expectedAccess,
                actualReport.RequestedAccess,
                "Incorrect access type for path " + actualReportedPathString);

            if (expectedAccess == RequestedAccess.Read)
            {
                var allowedOperations = !OperatingSystemHelper.IsUnixOS
                    ? new[] { ReportedFileOperation.CreateFile }
                    : expected.Exists
                        ? new[] { ReportedFileOperation.KAuthVNodeRead, ReportedFileOperation.KAuthReadFile }
                        : new[] { ReportedFileOperation.MacLookup };

                XAssert.Contains(allowedOperations, actualReport.Operation);
            }

            return(true);
        }
Example #29
0
        public void DirectoryMembershipExistenceTest()
        {
            CacheMissData cacheMiss;

            DirectoryArtifact dir = DirectoryArtifact.CreateWithZeroPartialSealId(CreateUniqueDirectory(ReadonlyRoot));

            Directory.CreateDirectory(ArtifactToString(dir));

            Process pip = CreateAndSchedulePipBuilder(new Operation[]
            {
                Operation.EnumerateDir(dir),
                Operation.WriteFile(CreateOutputFileArtifact())
            }).Process;

            Configuration.Sandbox.UnsafeSandboxConfigurationMutable.IgnorePreloadedDlls = true;
            FileArtifact srcFile1 = CreateSourceFile(dir);

            File.WriteAllText(ArtifactToString(srcFile1), "member1");
            RunScheduler().AssertCacheMiss(pip.PipId);
            ScheduleRunResult buildA = RunScheduler().AssertCacheHit(pip.PipId);

            FileArtifact srcFile2 = CreateSourceFile(dir);

            File.WriteAllText(ArtifactToString(srcFile2), "member2");
            ScheduleRunResult buildB = RunScheduler(m_testHooks).AssertCacheMiss(pip.PipId);

            XAssert.IsTrue(m_testHooks.FingerprintStoreTestHooks.TryGetCacheMiss(pip.PipId, out cacheMiss));
            XAssert.Contains(cacheMiss.DetailAndResult.Detail.Info.ToString(), srcFile2.Path.GetName(Context.PathTable).ToString(Context.PathTable.StringTable));

            Configuration.Sandbox.UnsafeSandboxConfigurationMutable.IgnorePreloadedDlls = false;
            ScheduleRunResult buildC = RunScheduler(m_testHooks).AssertCacheMiss(pip.PipId);

            XAssert.IsTrue(m_testHooks.FingerprintStoreTestHooks.TryGetCacheMiss(pip.PipId, out cacheMiss));
            XAssert.Contains(cacheMiss.DetailAndResult.Detail.Info.ToString(), ObservedPathSet.Labels.UnsafeOptions);

            FileArtifact srcFile3 = CreateSourceFile(dir);

            File.WriteAllText(ArtifactToString(srcFile3), "member3");
            ScheduleRunResult buildD = RunScheduler(m_testHooks).AssertCacheMiss(pip.PipId);

            XAssert.IsTrue(m_testHooks.FingerprintStoreTestHooks.TryGetCacheMiss(pip.PipId, out cacheMiss));
            XAssert.Contains(cacheMiss.DetailAndResult.Detail.Info.ToString(), srcFile3.Path.GetName(Context.PathTable).ToString(Context.PathTable.StringTable));
            XAssert.ContainsNot(cacheMiss.DetailAndResult.Detail.Info.ToString(), RepeatedStrings.MissingDirectoryMembershipFingerprint);
        }
Example #30
0
        public void BreakawayProcessesAreUntracked()
        {
            var outerSourceFile = CreateSourceFileWithPrefix(SourceRoot, prefix: $"{nameof(BreakawayProcessesAreUntracked)}-outer-src");
            var innerSourceFile = CreateSourceFileWithPrefix(SourceRoot, prefix: $"{nameof(BreakawayProcessesAreUntracked)}-inner-src");

            var outerOutputFile = CreateOutputFileArtifact(ObjectRoot, prefix: $"{nameof(BreakawayProcessesAreUntracked)}-outer-out");
            var innerOutputFile = CreateOutputFileArtifact(ObjectRoot, prefix: $"{nameof(BreakawayProcessesAreUntracked)}-inner-out");

            var builder = CreatePipBuilder(new Operation[]
            {
                Operation.ReadFile(outerSourceFile),
                Operation.WriteFile(outerOutputFile),

                Operation.Spawn(Context.PathTable, waitToFinish: true,
                                Operation.WriteFile(innerOutputFile, doNotInfer: true),
                                Operation.ReadFile(innerSourceFile, doNotInfer: true))
            });

            // Configure the test process itself to escape the sandbox
            builder.ChildProcessesToBreakawayFromSandbox = ReadOnlyArray <PathAtom> .FromWithoutCopy(new[] { PathAtom.Create(Context.StringTable, TestProcessToolName) });

            var pip = SchedulePipBuilder(builder);

            // 1st run: success + cache miss
            var result = RunScheduler().AssertSuccess().AssertCacheMiss(pip.Process.PipId);

            // there should be a single "produced output" message and it should be for the outer output file
            var producedOutputLogMessage = EventListener.GetLogMessagesForEventId((int)LogEventId.PipOutputProduced).Single().ToCanonicalizedPath();

            XAssert.Contains(producedOutputLogMessage, ToString(outerOutputFile).ToCanonicalizedPath());
            XAssert.ContainsNot(producedOutputLogMessage, ToString(innerOutputFile).ToCanonicalizedPath());

            // 2nd run (no changes): success + up to date
            RunScheduler().AssertSuccess().AssertCacheHit(pip.Process.PipId);

            // 3nd run (change inner source file): success + cache hit (because inner source is untracked)
            File.WriteAllText(ToString(innerSourceFile), contents: Guid.NewGuid().ToString());
            RunScheduler().AssertSuccess().AssertCacheHit(pip.Process.PipId);

            // 4th run (change outer source file): success + cache miss
            File.WriteAllText(ToString(outerSourceFile), contents: Guid.NewGuid().ToString());
            RunScheduler().AssertSuccess().AssertCacheMiss(pip.Process.PipId);
        }