Skip to content

Commit 83aac7b

Browse files
committed
DockerBuild.ps1: transfer environment variables from key vault.
1 parent c559f33 commit 83aac7b

File tree

13 files changed

+140
-61
lines changed

13 files changed

+140
-61
lines changed

DockerBuild.ps1

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ param(
1111
[switch]$KeepEnv, # Does not override the env.g.json file.
1212
[string]$ImageName, # Image name (defaults to a name based on the directory).
1313
[string]$BuildAgentPath = 'C:\BuildAgent',
14+
[switch]$LoadEnvFromKeyVault, # Forces loading environment variables form the key vault.
1415
[Parameter(ValueFromRemainingArguments)]
1516
[string[]]$BuildArgs # Arguments passed to `Build.ps1` within the container.
1617
)
1718

18-
# This setting is replaced by the generate-scripts command.
19+
####
20+
# These settings are replaced by the generate-scripts command.
1921
$EngPath = 'eng'
20-
$EnvironmentVariables = 'AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AZ_IDENTITY_USERNAME,AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_DEVOPS_TOKEN,AZURE_DEVOPS_USER,AZURE_TENANT_ID,DOC_API_KEY,DOWNLOADS_API_KEY,ENG_USERNAME,GIT_USER_EMAIL,GIT_USER_NAME,GITHUB_AUTHOR_EMAIL,GITHUB_REVIEWER_TOKEN,GITHUB_TOKEN,IS_POSTSHARP_OWNED,IS_TEAMCITY_AGENT,NUGET_ORG_API_KEY,SIGNSERVER_SECRET,TEAMCITY_CLOUD_TOKEN,TYPESENSE_API_KEY,VS_MARKETPLACE_ACCESS_TOKEN,VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'
22+
$EnvironmentVariables = 'AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AZ_IDENTITY_USERNAME,AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_DEVOPS_TOKEN,AZURE_DEVOPS_USER,AZURE_TENANT_ID,DOC_API_KEY,DOWNLOADS_API_KEY,ENG_USERNAME,GIT_USER_EMAIL,GIT_USER_NAME,GITHUB_AUTHOR_EMAIL,GITHUB_REVIEWER_TOKEN,GITHUB_TOKEN,IS_POSTSHARP_OWNED,IS_TEAMCITY_AGENT,MetalamaLicense,NUGET_ORG_API_KEY,PostSharpLicense,SIGNSERVER_SECRET,TEAMCITY_CLOUD_TOKEN,TYPESENSE_API_KEY,VS_MARKETPLACE_ACCESS_TOKEN,VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'
23+
####
2124

25+
$ErrorActionPreference = "Stop"
2226
$dockerContextDirectory = "$EngPath/docker-context"
2327

2428
# Function to create secrets JSON file
@@ -42,6 +46,27 @@ function New-EnvJson
4246
}
4347
}
4448

49+
# Add secrets from the PostSharpBuildEnv key vault, on our development machines.
50+
# On CI agents, these environment variables are supposed to be set by the host.
51+
if ($LoadEnvFromKeyVault -or ($env:IS_POSTSHARP_OWNED -and -not $env:IS_TEAMCITY_AGENT))
52+
{
53+
$moduleName = "Az.KeyVault"
54+
55+
if (-not (Get-Module -ListAvailable -Name $moduleName)) {
56+
Write-Error "The required module '$moduleName' is not installed. Please install it with: Install-Module -Name $moduleName"
57+
exit 1
58+
}
59+
60+
Import-Module $moduleName
61+
foreach ($secret in Get-AzKeyVaultSecret -VaultName "PostSharpBuildEnv")
62+
{
63+
$secretWithValue = Get-AzKeyVaultSecret -VaultName "PostSharpBuildEnv" -Name $secret.Name
64+
$envName = $secretWithValue.Name -Replace "-", "_"
65+
$envValue = (ConvertFrom-SecureString $secretWithValue.SecretValue -AsPlainText)
66+
$secrets[$envName] = $envValue
67+
}
68+
}
69+
4570
# Convert to JSON and save
4671
$jsonPath = Join-Path $dockerContextDirectory "env.g.json"
4772

@@ -98,6 +123,7 @@ if (-not $KeepEnv)
98123
$env:ENG_USERNAME = $env:USERNAME
99124
}
100125

126+
# Add git identity to environment
101127
$env:GIT_USER_EMAIL = git config --global user.email
102128
$env:GIT_USER_NAME = git config --global user.name
103129

src/PostSharp.Engineering.BuildTools/Build/Model/Product.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public BuildAgentRequirements ResolvedBuildAgentRequirements
135135
public static ImmutableArray<Publisher> DefaultPublicPublishers { get; }
136136
=
137137
[
138-
new NugetPublisher( Pattern.Create( "*.nupkg" ), "https://api.nuget.org/v3/index.json", "%NUGET_ORG_API_KEY%" ),
138+
new NugetPublisher( Pattern.Create( "*.nupkg" ), "https://api.nuget.org/v3/index.json", $"%{EnvironmentVariableNames.NuGetOrgApiKey}%" ),
139139
new VsixPublisher( Pattern.Create( "*.vsix" ) )
140140
];
141141

src/PostSharp.Engineering.BuildTools/Build/Publishing/DocumentationPublisher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ namespace PostSharp.Engineering.BuildTools.Build.Publishing;
99
public class DocumentationPublisher : InvalidatingS3Publisher
1010
{
1111
public DocumentationPublisher( IReadOnlyCollection<S3PublisherConfiguration> configurations, string documentationUrl )
12-
: base( configurations, $"{documentationUrl}_api/invalidate?%DOC_API_KEY%" ) { }
12+
: base( configurations, $"{documentationUrl}_api/invalidate?%{EnvironmentVariableNames.DocInvalidationKey}%" ) { }
1313
}

src/PostSharp.Engineering.BuildTools/Build/Publishing/Downloads/DownloadPublisher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ public class DownloadPublisher : InvalidatingS3Publisher
1010
{
1111
public DownloadPublisher( IReadOnlyCollection<S3PublisherConfiguration> configurations ) : base(
1212
configurations,
13-
"https://www.postsharp.net/download/Refresh.ashx?p=%DOWNLOADS_API_KEY%" ) { }
13+
$"https://www.postsharp.net/download/Refresh.ashx?p=%{EnvironmentVariableNames.DownloadsInvalidationKey}%" ) { }
1414
}

src/PostSharp.Engineering.BuildTools/Build/Publishing/MsDeployPublisher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ private static bool QueryPublishProfile(
3434
var args =
3535
$"webapp deployment list-publishing-profiles --subscription {configuration.SubscriptionId} --resource-group {configuration.ResourceGroupName} --name {configuration.SiteName} --slot {configuration.SlotName}";
3636

37-
if ( !AzHelper.Query( context.Console, args, settings.Dry, out var profiles ) )
37+
if ( !AzHelper.Query( context, args, settings.Dry, out var profiles ) )
3838
{
3939
publishProfile = null;
4040

src/PostSharp.Engineering.BuildTools/Build/Publishing/VsixPublisher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public override SuccessCode PublishFile(
4949
var exe = $@"{vsSdkDir}\VisualStudioIntegration\Tools\Bin\VsixPublisher.exe";
5050

5151
var args =
52-
$" publish -payload \"{file}\" -publishManifest \"{file}.json\" -personalAccessToken \"%VS_MARKETPLACE_ACCESS_TOKEN%\"";
52+
$" publish -payload \"{file}\" -publishManifest \"{file}.json\" -personalAccessToken \"%{nameof(EnvironmentVariableNames.VsMarketplaceAccessToken)}%\"";
5353

5454
if ( settings.Dry )
5555
{

src/PostSharp.Engineering.BuildTools/Build/Swapping/AppServiceSwapper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected override SuccessCode ExecuteCore(
5757
return SuccessCode.Success;
5858
}
5959

60-
return AzHelper.Run( context.Console, args, settings.Dry ) ? SuccessCode.Success : SuccessCode.Error;
60+
return AzHelper.Run( context, args, settings.Dry ) ? SuccessCode.Success : SuccessCode.Error;
6161
}
6262
}
6363
}

src/PostSharp.Engineering.BuildTools/ContinuousIntegration/AzureDevOpsHelper.cs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
2121
{
2222
var user = Environment.GetEnvironmentVariable( EnvironmentVariableNames.AzureDevOpsUser ) ?? "[email protected]";
2323

24-
2524
var token = Environment.GetEnvironmentVariable( EnvironmentVariableNames.AzureDevOpsToken );
2625

2726
if ( string.IsNullOrEmpty( token ) )
@@ -79,7 +78,7 @@ private static bool TryConnect( ConsoleHelper console, string url, [NotNullWhen(
7978
var pullRequestWithAutoCompleteEnabled = new GitPullRequest
8079
{
8180
AutoCompleteSetBy = new IdentityRef { Id = createdPullRequest.CreatedBy.Id },
82-
CompletionOptions = new GitPullRequestCompletionOptions { DeleteSourceBranch = true, MergeCommitMessage = title },
81+
CompletionOptions = new GitPullRequestCompletionOptions { DeleteSourceBranch = true, MergeCommitMessage = title }
8382
};
8483

8584
console.WriteMessage( "Setting the new pull request to get completed automatically." );
@@ -117,10 +116,13 @@ public static async Task<bool> TrySetBranchPoliciesAsync(
117116
var project = azureDevOpsRepository.Project;
118117
var projectIdArgs = $"--org {org} --project {project}";
119118

120-
context.Console.WriteMessage( "Fetching repository ID." );
119+
var console = context.Console;
120+
var product = context.Product;
121+
122+
console.WriteMessage( "Fetching repository ID." );
121123

122124
if ( !AzHelper.Query(
123-
context.Console,
125+
context,
124126
$"repos show --repository {repository} {projectIdArgs}",
125127
dry,
126128
out var repositoryJson ) )
@@ -138,24 +140,24 @@ string GetCommonArgs( string branch )
138140
return $"{branchIdArgs} --blocking true --enabled true";
139141
}
140142

141-
var branch = context.Product.DependencyDefinition.Branch;
143+
var branch = product.DependencyDefinition.Branch;
142144
var commonArgs = GetCommonArgs( branch );
143145

144146
bool TryRequireApproversAndCommentResolution()
145147
{
146-
context.Console.WriteMessage( $"Requiring approvers for '{branch}' branch." );
148+
console.WriteMessage( $"Requiring approvers for '{branch}' branch." );
147149

148150
if ( !AzHelper.Run(
149-
context.Console,
151+
context,
150152
$"repos policy approver-count create {commonArgs} --allow-downvotes false --creator-vote-counts true --minimum-approver-count 1 --reset-on-source-push false",
151153
dry ) )
152154
{
153155
return false;
154156
}
155157

156-
context.Console.WriteMessage( $"Requiring comment resolution for '{branch}' branch." );
158+
console.WriteMessage( $"Requiring comment resolution for '{branch}' branch." );
157159

158-
if ( !AzHelper.Run( context.Console, $"repos policy comment-required create {commonArgs}", dry ) )
160+
if ( !AzHelper.Run( context, $"repos policy comment-required create {commonArgs}", dry ) )
159161
{
160162
return false;
161163
}
@@ -170,11 +172,11 @@ bool TryRequireApproversAndCommentResolution()
170172

171173
if ( buildStatusName == null )
172174
{
173-
context.Console.WriteMessage( $"Success status for '{branch}' branch is not required." );
175+
console.WriteMessage( $"Success status for '{branch}' branch is not required." );
174176
}
175177
else
176178
{
177-
context.Console.WriteMessage( $"Requiring success status for '{branch}' branch." );
179+
console.WriteMessage( $"Requiring success status for '{branch}' branch." );
178180

179181
// This is not covered by "az repos policy" command. https://github.com/Azure/azure-devops-cli-extension/issues/1040
180182
var statusCheckPayload = $@"{{
@@ -207,7 +209,7 @@ bool TryRequireApproversAndCommentResolution()
207209
{
208210
await File.WriteAllTextAsync( statusCheckPayloadFile, statusCheckPayload );
209211

210-
if ( !AzHelper.Run( context.Console, $"repos policy create {projectIdArgs} --config {statusCheckPayloadFile}", dry ) )
212+
if ( !AzHelper.Run( context, $"repos policy create {projectIdArgs} --config {statusCheckPayloadFile}", dry ) )
211213
{
212214
return false;
213215
}
@@ -218,26 +220,26 @@ bool TryRequireApproversAndCommentResolution()
218220
}
219221
}
220222

221-
if ( context.Product.DependencyDefinition.ReleaseBranch != null )
223+
if ( product.DependencyDefinition.ReleaseBranch != null )
222224
{
223225
var developBranch = branch;
224-
branch = context.Product.DependencyDefinition.ReleaseBranch;
226+
branch = product.DependencyDefinition.ReleaseBranch;
225227
commonArgs = GetCommonArgs( branch );
226228

227229
if ( !TryRequireApproversAndCommentResolution() )
228230
{
229231
return false;
230232
}
231233

232-
context.Console.WriteMessage( $"Requiring reviewers for '{branch}' branch." );
234+
console.WriteMessage( $"Requiring reviewers for '{branch}' branch." );
233235

234236
var message =
235237
$"\"TeamCity is a required reviewer because only automated merges during publishing are allowed to a release branch. For development, use '{developBranch}' branch as a target branch of your PR.\"";
236238

237239
var options = new ToolInvocationOptions( new Dictionary<string, string?> { { "ReviewerMessage", message } }.ToImmutableDictionary() );
238240

239241
if ( !AzHelper.Run(
240-
context.Console,
242+
context,
241243
$"repos policy required-reviewer create {commonArgs} --message %ReviewerMessage% --required-reviewer-ids [email protected]",
242244
dry,
243245
options ) )
@@ -248,9 +250,9 @@ bool TryRequireApproversAndCommentResolution()
248250

249251
return await Task.FromResult( true );
250252
}
251-
253+
252254
public static async Task<bool> TrySetDefaultBranchAsync(
253-
ConsoleHelper console,
255+
BuildContext context,
254256
AzureDevOpsRepository azureDevOpsRepository,
255257
string defaultBranch,
256258
bool dry )
@@ -261,10 +263,10 @@ public static async Task<bool> TrySetDefaultBranchAsync(
261263
var projectIdArgs = $"--org {org} --project {project}";
262264
var repositoryIdArgs = $"{projectIdArgs} --repository {repository}";
263265

264-
console.WriteMessage( $"Setting repository default branch to '{defaultBranch}'." );
266+
context.Console.WriteMessage( $"Setting repository default branch to '{defaultBranch}'." );
265267

266268
if ( !AzHelper.Run(
267-
console,
269+
context,
268270
$"repos update {repositoryIdArgs} --default-branch {defaultBranch}",
269271
dry ) )
270272
{

src/PostSharp.Engineering.BuildTools/EnvironmentVariableNames.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace PostSharp.Engineering.BuildTools;
44

5-
public static class EnvironmentVariableNames
5+
internal static class EnvironmentVariableNames
66
{
77
// Our infrastructure
88
public const string IsPostSharpOwned = "IS_POSTSHARP_OWNED";
@@ -11,6 +11,8 @@ public static class EnvironmentVariableNames
1111
public const string SignServerSecret = "SIGNSERVER_SECRET";
1212
public const string DocInvalidationKey = "DOC_API_KEY";
1313
public const string DownloadsInvalidationKey = "DOWNLOADS_API_KEY";
14+
private const string _metalamaLicense = "MetalamaLicense";
15+
private const string _postSharpLicense = "PostSharpLicense";
1416

1517
// AWS
1618
public const string AwsAccessKeyId = "AWS_ACCESS_KEY_ID";
@@ -21,10 +23,10 @@ public static class EnvironmentVariableNames
2123

2224
// NuGet.org
2325
public const string NuGetOrgApiKey = "NUGET_ORG_API_KEY";
24-
26+
2527
// Git - set by DockerBuild.ps1 from current git config.
26-
public const string GitUserName = "GIT_USER_NAME";
27-
public const string GitUserEmail = "GIT_USER_EMAIL";
28+
private const string _gitUserName = "GIT_USER_NAME";
29+
private const string _gitUserEmail = "GIT_USER_EMAIL";
2830

2931
// GitHub
3032
public const string GitHubToken = "GITHUB_TOKEN";
@@ -48,6 +50,7 @@ public static class EnvironmentVariableNames
4850
public const string AzureClientSecret = "AZURE_CLIENT_SECRET";
4951
public const string AzureTenantId = "AZURE_TENANT_ID";
5052

53+
// List of all environment variables, injected into DockerBuild.ps1 and passed to the container.
5154
public static readonly string[] All =
5255
[
5356
TeamCityToken,
@@ -62,8 +65,8 @@ public static class EnvironmentVariableNames
6265
AzureDevOpsToken,
6366
GitHubReviewerToken,
6467
GitHubAuthorEmail,
65-
GitUserEmail,
66-
GitUserName,
68+
_gitUserEmail,
69+
_gitUserName,
6770
NuGetOrgApiKey,
6871
AwsAccessKeyId,
6972
AwsAccessKeySecret,
@@ -73,6 +76,8 @@ public static class EnvironmentVariableNames
7376
AzureClientSecret,
7477
AzureTenantId,
7578
DocInvalidationKey,
76-
DownloadsInvalidationKey
79+
DownloadsInvalidationKey,
80+
_metalamaLicense,
81+
_postSharpLicense
7782
];
7883
}

src/PostSharp.Engineering.BuildTools/Resources/DockerBuild.ps1

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ param(
1111
[switch]$KeepEnv, # Does not override the env.g.json file.
1212
[string]$ImageName, # Image name (defaults to a name based on the directory).
1313
[string]$BuildAgentPath = 'C:\BuildAgent',
14+
[switch]$LoadEnvFromKeyVault, # Forces loading environment variables form the key vault.
1415
[Parameter(ValueFromRemainingArguments)]
1516
[string[]]$BuildArgs # Arguments passed to `Build.ps1` within the container.
1617
)
1718

18-
# This setting is replaced by the generate-scripts command.
19+
####
20+
# These settings are replaced by the generate-scripts command.
1921
$EngPath = '<ENG_PATH>'
2022
$EnvironmentVariables = '<ENVIRONMENT_VARIABLES>'
23+
####
2124

25+
$ErrorActionPreference = "Stop"
2226
$dockerContextDirectory = "$EngPath/docker-context"
2327

2428
# Function to create secrets JSON file
@@ -42,6 +46,27 @@ function New-EnvJson
4246
}
4347
}
4448

49+
# Add secrets from the PostSharpBuildEnv key vault, on our development machines.
50+
# On CI agents, these environment variables are supposed to be set by the host.
51+
if ($LoadEnvFromKeyVault -or ($env:IS_POSTSHARP_OWNED -and -not $env:IS_TEAMCITY_AGENT))
52+
{
53+
$moduleName = "Az.KeyVault"
54+
55+
if (-not (Get-Module -ListAvailable -Name $moduleName)) {
56+
Write-Error "The required module '$moduleName' is not installed. Please install it with: Install-Module -Name $moduleName"
57+
exit 1
58+
}
59+
60+
Import-Module $moduleName
61+
foreach ($secret in Get-AzKeyVaultSecret -VaultName "PostSharpBuildEnv")
62+
{
63+
$secretWithValue = Get-AzKeyVaultSecret -VaultName "PostSharpBuildEnv" -Name $secret.Name
64+
$envName = $secretWithValue.Name -Replace "-", "_"
65+
$envValue = (ConvertFrom-SecureString $secretWithValue.SecretValue -AsPlainText)
66+
$secrets[$envName] = $envValue
67+
}
68+
}
69+
4570
# Convert to JSON and save
4671
$jsonPath = Join-Path $dockerContextDirectory "env.g.json"
4772

@@ -98,6 +123,7 @@ if (-not $KeepEnv)
98123
$env:ENG_USERNAME = $env:USERNAME
99124
}
100125

126+
# Add git identity to environment
101127
$env:GIT_USER_EMAIL = git config --global user.email
102128
$env:GIT_USER_NAME = git config --global user.name
103129

0 commit comments

Comments
 (0)