Skip to content

Commit

Permalink
Merge pull request #340 from microsoft/dev
Browse files Browse the repository at this point in the history
support for github environments
  • Loading branch information
markusheiliger committed May 23, 2022
2 parents cfab301 + 2b546ca commit 2c9924f
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 182 deletions.
3 changes: 2 additions & 1 deletion src/TeamCloud.Adapters.AzureDevOps/AzureDevOpsAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public sealed class AzureDevOpsAdapter : AdapterWithIdentity, IAdapterAuthorize
// however; it is used to managed singleton function execution within the functions fx !!!

public AzureDevOpsAdapter(
IAdapterProvider adapterProvider,
IAuthorizationSessionClient sessionClient,
IAuthorizationTokenClient tokenClient,
IDistributedLockManager distributedLockManager,
Expand All @@ -94,7 +95,7 @@ public AzureDevOpsAdapter(
IGraphService graphService,
IFunctionsHost functionsHost = null,
ILoggerFactory loggerFactory = null)
: base(sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
: base(adapterProvider, sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
{
this.httpClientFactory = httpClientFactory ?? new DefaultHttpClientFactory();
this.userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

namespace TeamCloud.Adapters.AzureResourceManager;

public sealed class AzureResourceManagerAdapter : Adapter
public sealed class AzureResourceManagerAdapter : AdapterWithIdentity
{
private readonly IAzureService azure;
private readonly IAzureResourceService azureResourceService;
Expand All @@ -40,7 +40,9 @@ public sealed class AzureResourceManagerAdapter : Adapter
// IDistributedLockManager is marked as obsolete, because it's not ready for "prime time"
// however; it is used to managed singleton function execution within the functions fx !!!

public AzureResourceManagerAdapter(IAuthorizationSessionClient sessionClient,
public AzureResourceManagerAdapter(
IAdapterProvider adapterProvider,
IAuthorizationSessionClient sessionClient,
IAuthorizationTokenClient tokenClient,
IDistributedLockManager distributedLockManager,
IAzureService azure,
Expand All @@ -52,7 +54,7 @@ public AzureResourceManagerAdapter(IAuthorizationSessionClient sessionClient,
IProjectRepository projectRepository,
IComponentRepository componentRepository,
IComponentTemplateRepository componentTemplateRepository)
: base(sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
: base(adapterProvider, sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
{
this.azure = azure ?? throw new ArgumentNullException(nameof(azure));
this.azureResourceService = azureResourceService ?? throw new ArgumentNullException(nameof(azureResourceService));
Expand Down Expand Up @@ -197,6 +199,16 @@ async Task UpdateComponentRoleAssignmentsAsync()
.Add(identity.PrincipalId, Enumerable.Repeat(AzureRoleDefinition.Contributor, 1));
}

if (this is IAdapterIdentity adapterIdentity)
{
var componentDeploymentScopeServiceIdentity = await adapterIdentity
.GetServiceIdentityAsync(componentDeploymentScope)
.ConfigureAwait(false);

roleAssignmentMap
.Add(componentDeploymentScopeServiceIdentity.Id.ToString(), Enumerable.Repeat(AzureRoleDefinition.Contributor, 1));
}

if (string.IsNullOrEmpty(componentResourceId.ResourceGroup))
{
var subscription = await azureResourceService
Expand Down
420 changes: 275 additions & 145 deletions src/TeamCloud.Adapters.GitHub/GitHubAdapter.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/TeamCloud.Adapters.GitHub/GitHubAdapter_Register.html
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ <h1>GitHub Provider Setup</h1>
"default_permissions": {
"actions": "write",
"administration": "write",
"environments": "write",
"checks": "write",
"contents": "write",
"issues": "write",
Expand Down
2 changes: 1 addition & 1 deletion src/TeamCloud.Adapters.GitHub/GitHubData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public sealed class GitHubData
[TeamCloudFormDescription("GitHub organization's name or base URL.")]
public string Organization
{
get => string.IsNullOrWhiteSpace(organization) ? null : GitHubToken.FormatOrganizationUrl(organization);
get => string.IsNullOrWhiteSpace(organization) ? null : GitHubToken.SanitizeOrganizationUrl(organization);
set => organization = value;
}

Expand Down
9 changes: 3 additions & 6 deletions src/TeamCloud.Adapters.GitHub/GitHubToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using TeamCloud.Adapters.Authorization;
using TeamCloud.Model.Data;
using User = Octokit.User;
Expand All @@ -13,7 +14,7 @@ namespace TeamCloud.Adapters.GitHub;

public sealed class GitHubToken : AuthorizationToken
{
internal static string FormatOrganizationUrl(string organization)
internal static string SanitizeOrganizationUrl(string organization)
{
if (string.IsNullOrWhiteSpace(organization))
return null;
Expand All @@ -39,27 +40,23 @@ public GitHubToken(DeploymentScope deployementScope) : base(GetEntityId(deployem
public bool Enabled
=> !Suspended && long.TryParse(ApplicationId, out _) && long.TryParse(InstallationId, out _);

[DataMember(Name = "id")]
public string ApplicationId { get; set; }

public string InstallationId { get; set; }

[DataMember(Name = "client_id")]
public string ClientId { get; set; }

[DataMember(Name = "client_secret")]
public string ClientSecret { get; set; }

public string AccessToken { get; set; }

// [IgnoreDataMember]
public DateTime? AccessTokenExpires { get; set; }

[IgnoreDataMember]
[JsonIgnore]
public bool AccessTokenExpired
=> !AccessTokenExpires.HasValue || AccessTokenExpires < DateTime.UtcNow;

[DataMember(Name = "webhook_secret")]
public string WebhookSecret { get; set; }

public string Pem { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<PackageReference Include="FluentValidation" Version="9.2.2" />
<PackageReference Include="Flurl.Http" Version="3.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Octokit" Version="0.50.0" />
<PackageReference Include="Octokit" Version="0.51.0" />
<PackageReference Include="Sodium.Core" Version="1.2.3" />
</ItemGroup>

Expand Down
5 changes: 3 additions & 2 deletions src/TeamCloud.Adapters.Kubernetes/KubernetesAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public sealed class KubernetesAdapter : Adapter
// IDistributedLockManager is marked as obsolete, because it's not ready for "prime time"
// however; it is used to managed singleton function execution within the functions fx !!!

public KubernetesAdapter(IAuthorizationSessionClient sessionClient,
public KubernetesAdapter(IAdapterProvider adapterProvider,
IAuthorizationSessionClient sessionClient,
IAuthorizationTokenClient tokenClient,
IDistributedLockManager distributedLockManager,
IAzureService azure,
Expand All @@ -48,7 +49,7 @@ public KubernetesAdapter(IAuthorizationSessionClient sessionClient,
IDeploymentScopeRepository deploymentScopeRepository,
IProjectRepository projectRepository,
IUserRepository userRepository)
: base(sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
: base(adapterProvider, sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
{
this.azureResourceService = azureResourceService ?? throw new ArgumentNullException(nameof(azureResourceService));
}
Expand Down
5 changes: 4 additions & 1 deletion src/TeamCloud.Adapters/Adapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public abstract class Adapter : IAdapter
{
private static readonly JSchema dataSchemaEmpty = new() { Type = JSchemaType.Object };
private static readonly JObject formSchemaEmpty = new();
private readonly IAdapterProvider adapterProvider;

#pragma warning disable CS0618 // Type or member is obsolete

Expand All @@ -43,7 +44,8 @@ public abstract class Adapter : IAdapter
private readonly IProjectRepository projectRepository;
private readonly IUserRepository userRepository;

protected Adapter(IAuthorizationSessionClient sessionClient,
protected Adapter(IAdapterProvider adapterProvider,
IAuthorizationSessionClient sessionClient,
IAuthorizationTokenClient tokenClient,
IDistributedLockManager distributedLockManager,
IAzureService azure,
Expand All @@ -53,6 +55,7 @@ protected Adapter(IAuthorizationSessionClient sessionClient,
IProjectRepository projectRepository,
IUserRepository userRepository)
{
this.adapterProvider = adapterProvider ?? throw new ArgumentNullException(nameof(adapterProvider));
this.sessionClient = sessionClient ?? throw new ArgumentNullException(nameof(sessionClient));
this.tokenClient = tokenClient ?? throw new ArgumentNullException(nameof(tokenClient));
this.distributedLockManager = distributedLockManager ?? throw new ArgumentNullException(nameof(distributedLockManager));
Expand Down
51 changes: 32 additions & 19 deletions src/TeamCloud.Adapters/AdapterWithIdentity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,37 @@ namespace TeamCloud.Adapters;

public abstract class AdapterWithIdentity : Adapter, IAdapterIdentity
{
private readonly IAzureService azure;
private readonly IAzureService azureService;
private readonly IGraphService graphService;
private readonly IOrganizationRepository organizationRepository;
private readonly IProjectRepository projectRepository;

#pragma warning disable CS0618 // Type or member is obsolete

protected AdapterWithIdentity(IAuthorizationSessionClient sessionClient,
IAuthorizationTokenClient tokenClient,
IDistributedLockManager distributedLockManager,
IAzureService azure,
IGraphService graphService,
IOrganizationRepository organizationRepository,
IDeploymentScopeRepository deploymentScopeRepository,
IProjectRepository projectRepository,
IUserRepository userRepository) : base(sessionClient, tokenClient, distributedLockManager, azure, graphService, organizationRepository, deploymentScopeRepository, projectRepository, userRepository)
protected AdapterWithIdentity(
IAdapterProvider adapterProvider,
IAuthorizationSessionClient sessionClient,
IAuthorizationTokenClient tokenClient,
IDistributedLockManager distributedLockManager,
IAzureService azureService,
IGraphService graphService,
IOrganizationRepository organizationRepository,
IDeploymentScopeRepository deploymentScopeRepository,
IProjectRepository projectRepository,
IUserRepository userRepository)
: base(
adapterProvider,
sessionClient,
tokenClient,
distributedLockManager,
azureService,
graphService,
organizationRepository,
deploymentScopeRepository,
projectRepository,
userRepository)
{
this.azure = azure ?? throw new ArgumentNullException(nameof(azure));
this.azureService = azureService ?? throw new ArgumentNullException(nameof(azureService));
this.graphService = graphService ?? throw new ArgumentNullException(nameof(graphService));
this.organizationRepository = organizationRepository ?? throw new ArgumentNullException(nameof(organizationRepository));
this.projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
Expand Down Expand Up @@ -65,7 +78,7 @@ public virtual async Task<AzureServicePrincipal> GetServiceIdentityAsync(Compone
.CreateServicePrincipalAsync(servicePrincipalName)
.ConfigureAwait(false);
}
else if (servicePrincipal.ExpiresOn.GetValueOrDefault(DateTime.MinValue) < DateTime.UtcNow)
else if (servicePrincipal.ExpiresOn.GetValueOrDefault(DateTime.MinValue.ToUniversalTime()) < DateTime.UtcNow)
{
// a service principal exists, but its secret is expired. lets refresh
// the service principal (create a new secret) so we can move on
Expand All @@ -82,7 +95,7 @@ public virtual async Task<AzureServicePrincipal> GetServiceIdentityAsync(Compone
.GetAsync(component.Organization, component.ProjectId)
.ConfigureAwait(false);

var secretClient = await azure.KeyVaults
var secretClient = await azureService.KeyVaults
.GetSecretClientAsync(project.SecretsVaultId, ensureIdentityAccess: true)
.ConfigureAwait(false);

Expand All @@ -96,7 +109,7 @@ public virtual async Task<AzureServicePrincipal> GetServiceIdentityAsync(Compone
.GetAsync(component.Organization, component.ProjectId)
.ConfigureAwait(false);

var secretClient = await azure.KeyVaults
var secretClient = await azureService.KeyVaults
.GetSecretClientAsync(project.SecretsVaultId, ensureIdentityAccess: true)
.ConfigureAwait(false);

Expand Down Expand Up @@ -134,7 +147,7 @@ public virtual async Task<AzureServicePrincipal> GetServiceIdentityAsync(Deploym
.CreateServicePrincipalAsync(servicePrincipalName)
.ConfigureAwait(false);
}
else if (servicePrincipal.ExpiresOn.GetValueOrDefault(DateTime.MinValue) < DateTime.UtcNow)
else if (servicePrincipal.ExpiresOn.GetValueOrDefault(DateTime.MinValue.ToUniversalTime()) < DateTime.UtcNow)
{
// a service principal exists, but its secret is expired. lets refresh
// the service principal (create a new secret) so we can move on
Expand All @@ -147,15 +160,15 @@ public virtual async Task<AzureServicePrincipal> GetServiceIdentityAsync(Deploym

if (!string.IsNullOrEmpty(servicePrincipal.Password))
{
var tenantId = await azure
var tenantId = await azureService
.GetTenantIdAsync()
.ConfigureAwait(false);

var organization = await organizationRepository
.GetAsync(tenantId, deploymentScope.Organization)
.ConfigureAwait(false);

var secretClient = await azure.KeyVaults
var secretClient = await azureService.KeyVaults
.GetSecretClientAsync(organization.SecretsVaultId, ensureIdentityAccess: true)
.ConfigureAwait(false);

Expand All @@ -165,15 +178,15 @@ public virtual async Task<AzureServicePrincipal> GetServiceIdentityAsync(Deploym
}
else if (withPassword)
{
var tenantId = await azure
var tenantId = await azureService
.GetTenantIdAsync()
.ConfigureAwait(false);

var organization = await organizationRepository
.GetAsync(tenantId, deploymentScope.Organization)
.ConfigureAwait(false);

var secretClient = await azure.KeyVaults
var secretClient = await azureService.KeyVaults
.GetSecretClientAsync(organization.SecretsVaultId, ensureIdentityAccess: true)
.ConfigureAwait(false);

Expand Down
2 changes: 1 addition & 1 deletion src/TeamCloud.Git/TeamCloud.Git.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.20.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.0" />
<PackageReference Include="Octokit" Version="0.50.0" />
<PackageReference Include="Octokit" Version="0.51.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="YamlDotNet" Version="8.1.2" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
Expand Down
1 change: 0 additions & 1 deletion src/TeamCloud.Orchestrator/Command/CommandOrchestration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ public CommandOrchestration(ICommandHandler[] commandHandlers)
this.commandHandlers = commandHandlers;
}

// [Deterministic]
[FunctionName(nameof(CommandOrchestration))]
public async Task Execute(
[OrchestrationTrigger] IDurableOrchestrationContext orchestratorContext,
Expand Down
2 changes: 1 addition & 1 deletion src/TeamCloud.Orchestrator/TeamCloud.Orchestrator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Cosmos" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="4.5.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.0.1" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="Microsoft.Azure.SignalR" Version="1.15.0" />
<PackageReference Include="Microsoft.Azure.SignalR.Management" Version="1.15.0" />
Expand Down

0 comments on commit 2c9924f

Please sign in to comment.