Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
21 changes: 21 additions & 0 deletions src/SourceLink.Common.UnitTests/GenerateSourceLinkFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,26 @@ public void DoesNotRewriteContentIfFileContentIsSame()

Assert.Equal(beforeWriteTime, afterWriteTime);
}

[Fact]
public void WriteSourceLinkFileRejectsRelativeOutputFile()
{
var engine = new MockEngine();
var task = new GenerateSourceLinkFile()
{
BuildEngine = engine,
// OutputFile must be fully qualified: file access must not depend on the shared process
// current directory under the multithreaded task model, so a relative path is rejected.
OutputFile = "sourcelink.json",
SourceRoots = new[]
{
new MockItem(@"/_/", KVP("SourceLinkUrl", "https://raw.githubusercontent.com/repo/*"), KVP("SourceControl", "git")),
},
};

Assert.False(task.Execute());
Assert.Null(task.SourceLink);
Assert.Contains("ERROR", engine.Log);
}
}
}
9 changes: 9 additions & 0 deletions src/SourceLink.Common/GenerateSourceLinkFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Microsoft.SourceLink.Common
{
[MSBuildMultiThreadableTask]
public sealed class GenerateSourceLinkFile : Task
{
[Required, NotNull]
Expand Down Expand Up @@ -114,6 +115,14 @@ private void WriteSourceLinkFile(string? content)

try
{
// OutputFile is required to be a fully qualified path. It is set by the SourceLink targets from
// _SourceLinkFilePath, so file access must not (and does not need to) depend on the shared process
// current directory under the multithreaded task model. Reject a path that isn't fully qualified.
if (string.IsNullOrEmpty(OutputFile) || !PathUtilities.IsPathFullyQualified(OutputFile))
{
throw new ArgumentException($"The path '{OutputFile}' must be fully qualified.", nameof(OutputFile));
}

if (File.Exists(OutputFile))
{
if (content == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

<Target Name="_SetSourceLinkFilePath">
<PropertyGroup>
<_SourceLinkFilePath>$(IntermediateOutputPath)$(MSBuildProjectName).sourcelink.json</_SourceLinkFilePath>
<!--
All source link tasks require absolute paths so that file access does not depend on the process
current directory (which is not reliable under the multithreaded task model). IntermediateOutputPath
is typically relative to the project directory, so make _SourceLinkFilePath absolute here.
-->
<_SourceLinkFilePath>$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', '$(MSBuildProjectName).sourcelink.json'))</_SourceLinkFilePath>
</PropertyGroup>
</Target>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void FullValidation_Https()
ProjectSourceRoot,
$"https://tfs.{TestStrings.DomainName}.local:8080/tfs/DefaultCollection/project/_apis/git/repositories/{repoName}/items?api-version=1.0&versionType=commit&version={commitSha}&path=/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://tfs.{TestStrings.DomainName}.local:8080/tfs/DefaultCollection/project/_git/{repoName}",
$"https://tfs.{TestStrings.DomainName}.local:8080/tfs/DefaultCollection/project/_git/{repoName}",
});
Expand Down Expand Up @@ -114,7 +114,7 @@ public void FullValidation_Ssh()
ProjectSourceRoot,
$"https://tfs.{TestStrings.DomainName}.local/tfs/DefaultCollection/project/_apis/git/repositories/{repoName}/items?api-version=1.0&versionType=commit&version={commitSha}&path=/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://tfs.{TestStrings.DomainName}.local/tfs/DefaultCollection/project/_git/{repoName}",
$"https://tfs.{TestStrings.DomainName}.local/tfs/DefaultCollection/project/_git/{repoName}",
});
Expand Down
4 changes: 2 additions & 2 deletions src/SourceLink.Git.IntegrationTests/AzureReposTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void FullValidation_Https(string host)
ProjectSourceRoot,
$"https://test.{host}/test-org/_apis/git/repositories/{repoName}/items?api-version=1.0&versionType=commit&version={commitSha}&path=/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://test.{host}/test-org/_git/{repoName}",
$"https://test.{host}/test-org/_git/{repoName}",
});
Expand Down Expand Up @@ -113,7 +113,7 @@ public void FullValidation_Ssh(string host)
ProjectSourceRoot,
$"https://test.{host}/test-org/_apis/git/repositories/{repoName}/items?api-version=1.0&versionType=commit&version={commitSha}&path=/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://test.{host}/test-org/_git/{repoName}",
$"https://test.{host}/test-org/_git/{repoName}",
});
Expand Down
16 changes: 8 additions & 8 deletions src/SourceLink.Git.IntegrationTests/BitbucketGitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void FullValidation_CloudHttps()
ProjectSourceRoot,
$"https://api.bitbucket.org/2.0/repositories/test-org/{repoName}/src/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://bitbucket.org/test-org/{repoName}",
$"https://bitbucket.org/test-org/{repoName}"
});
Expand Down Expand Up @@ -111,7 +111,7 @@ public void FullValidation_EnterpriseNewHttps()
ProjectSourceRoot,
$"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://bitbucket.domain.com/scm/test-org/{repoName}",
$"https://bitbucket.domain.com/scm/test-org/{repoName}"
});
Expand Down Expand Up @@ -170,7 +170,7 @@ public void FullValidation_EnterpriseNewHttps_UrlWithPersonalToken()
ProjectSourceRoot,
$"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://bitbucket.domain.com/scm/test-org/{repoName}.git",
$"https://bitbucket.domain.com/scm/test-org/{repoName}.git"
});
Expand Down Expand Up @@ -229,7 +229,7 @@ public void FullValidation_EnterpriseNewHttpsWithDefaultFlags()
NuGetPackageFolders,
ProjectSourceRoot,
$"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://bitbucket.domain.com/scm/test-org/{repoName}",
$"https://bitbucket.domain.com/scm/test-org/{repoName}"
});
Expand Down Expand Up @@ -289,7 +289,7 @@ public void FullValidation_EnterpriseOldHttps()
ProjectSourceRoot,
$"https://bitbucket.domain.com/projects/test-org/repos/{repoName}/browse/*?at={commitSha}&raw",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://bitbucket.domain.com/scm/test-org/{repoName}",
$"https://bitbucket.domain.com/scm/test-org/{repoName}"
});
Expand Down Expand Up @@ -349,7 +349,7 @@ public void FullValidation_CloudSsh()
ProjectSourceRoot,
$"https://api.{TestStrings.DomainName}.com/2.0/repositories/test-org/{repoName}/src/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down Expand Up @@ -409,7 +409,7 @@ public void FullValidation_EnterpriseOldSsh()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/projects/test-org/repos/{repoName}/browse/*?at={commitSha}&raw",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down Expand Up @@ -469,7 +469,7 @@ public void FullValidation_EnterpriseNewSsh()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/projects/test-org/repos/{repoName}/raw/*?at={commitSha}",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,10 @@ public void CustomTranslation()
ProjectSourceRoot,
$"https://raw.githubusercontent.com/test-org/{repoName}/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://github.com/test-org/{repoName}",
$"https://github.com/test-org/{repoName}",
s_relativeSourceLinkJsonPath
SourceLinkFilePath
});

AssertEx.AreEqual(
Expand Down Expand Up @@ -361,7 +361,7 @@ public void Host_VisualStudio(string host)
ProjectSourceRoot,
$"https://test.{host}/test-org/_apis/git/repositories/{repoName}/items?api-version=1.0&versionType=commit&version={commitSha}&path=/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://test.{host}/test-org/_git/{repoName}",
$"https://test.{host}/test-org/_git/{repoName}",
});
Expand Down Expand Up @@ -405,7 +405,7 @@ public void Host_DevAzureCom(string host)
ProjectSourceRoot,
$"https://{host}/test/test-org/_apis/git/repositories/{repoName}/items?api-version=1.0&versionType=commit&version={commitSha}&path=/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{host}/test/test-org/_git/{repoName}",
$"https://{host}/test/test-org/_git/{repoName}",
});
Expand Down
6 changes: 3 additions & 3 deletions src/SourceLink.Git.IntegrationTests/GitHubTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void MutlipleProjects()
SourceRoot,
$"https://raw.githubusercontent.com/test-org/test-repo2/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"http://github.com/test-org/test-repo2",
},
// the second project should reuse the repository info cached by the first project:
Expand Down Expand Up @@ -216,7 +216,7 @@ public void FullValidation_Https()
ProjectSourceRoot,
$"https://raw.githubusercontent.com/test-org/{repoName}/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"http://github.com/test-org/{repoName}",
$"http://github.com/test-org/{repoName}"
});
Expand Down Expand Up @@ -274,7 +274,7 @@ public void FullValidation_Ssh()
ProjectSourceRoot,
$"https://raw.githubusercontent.com/test-org/{repoName}/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://github.com/test-org/{repoName}",
$"https://github.com/test-org/{repoName}"
});
Expand Down
4 changes: 2 additions & 2 deletions src/SourceLink.Git.IntegrationTests/GitLabTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void FullValidation_Https()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}/-/raw/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down Expand Up @@ -114,7 +114,7 @@ public void FullValidation_Ssh()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}/-/raw/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down
2 changes: 1 addition & 1 deletion src/SourceLink.Git.IntegrationTests/GitWebTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public void FullValidation_Ssh()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/gitweb/?p={repoName};a=blob_plain;hb={commitSha};f=*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"ssh://git@{TestStrings.DomainName}.com/{repoNameFullyEscaped}",
$"ssh://git@{TestStrings.DomainName}.com/{repoNameFullyEscaped}"
});
Expand Down
4 changes: 2 additions & 2 deletions src/SourceLink.Git.IntegrationTests/GiteaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void FullValidation_Https()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}/raw/commit/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down Expand Up @@ -114,7 +114,7 @@ public void FullValidation_Ssh()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}/raw/commit/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down
4 changes: 2 additions & 2 deletions src/SourceLink.Git.IntegrationTests/GiteeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public void FullValidation_Https()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}/raw/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down Expand Up @@ -114,7 +114,7 @@ public void FullValidation_Ssh()
ProjectSourceRoot,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}/raw/{commitSha}/*",
"refs/heads/main",
s_relativeSourceLinkJsonPath,
SourceLinkFilePath,
$"https://{TestStrings.DomainName}.com/test-org/{repoName}",
$"https://{TestStrings.DomainName}.com/test-org/{repoName}"
});
Expand Down
6 changes: 6 additions & 0 deletions src/TestUtilities/DotNetSdk/DotNetSdkTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ private static string GetLocalNuGetConfigContent(string packagesDir) =>
protected readonly string DotNetPath;
protected readonly Dictionary<string, string> EnvironmentVariables;

// Absolute path of the generated source link file. The source link targets pass an absolute OutputFile
// to the GenerateSourceLinkFile task, so $(SourceLink) (and the corresponding FileWrites item) is absolute.
protected readonly string SourceLinkFilePath;

protected static readonly string s_relativeSourceLinkJsonPath = Path.Combine("obj", "Debug", "netstandard2.0", "test.sourcelink.json");
protected static readonly string s_relativeOutputFilePath = Path.Combine("obj", "Debug", "netstandard2.0", "test.dll");
protected static readonly string s_relativePackagePath = Path.Combine("bin", "Debug", "test.1.0.0.nupkg");
Expand Down Expand Up @@ -213,6 +217,8 @@ public DotNetSdkTestBase(params string[] packages)

Project = ProjectDir.CreateFile(ProjectFileName).WriteAllText(s_projectSource);
ProjectDir.CreateFile("TestClass.cs").WriteAllText(s_classSource);

SourceLinkFilePath = Path.Combine(ProjectDir.Path, s_relativeSourceLinkJsonPath);
}

public static string EnsureTrailingDirectorySeparator(string path)
Expand Down