Skip to content
This repository was archived by the owner on Oct 2, 2023. It is now read-only.

Commit a057716

Browse files
committed
fix regex
1 parent 26788d0 commit a057716

32 files changed

+267
-1184
lines changed

GithubRunnerRegistration/.gitignore

100644100755
File mode changed.

GithubRunnerRegistration/GithubRunnerRegistration.Api/Controllers/RegisterController.cs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
using GithubRunnerRegistration.Models;
2+
using Microsoft.AspNetCore.Http;
23
using Microsoft.AspNetCore.Mvc;
34
using Microsoft.Extensions.Logging;
45
using System;
56
using System.Collections.Generic;
67
using System.Linq;
8+
using System.Text;
79
using System.Threading.Tasks;
810

911
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
1012

1113
namespace GithubRunnerRegistration.Api.Controllers
1214
{
15+
[Produces("application/json")]
1316
[Route("api/[controller]")]
1417
[ApiController]
1518
public class RegisterController : ControllerBase
@@ -20,21 +23,45 @@ public RegisterController(ILogger<RegisterController> logger)
2023
{
2124
this.logger = logger;
2225
}
26+
27+
28+
/// <summary>
29+
/// Registers runners against the provided repo and returns the data required to associate each runner with the repo.
30+
/// The data returned can be used as the data property of a secret which is then referenced by ScaledActionRunner.RunnerSecrets
31+
/// The secret will then be mnoounted by a pod and used to register with Github
32+
/// </summary>
33+
/// <param name="request"></param>
34+
/// <returns>A map of secret names to secret data</returns>
35+
/// <response code="201">Request passed validation and runner(s) have been registered</response>
36+
/// <response code="202">Request passed validation but no runners were created because dryRun was specified, dummy information has been returned</response>
37+
/// <response code="400">Supplied request is invalid</response>
2338
[HttpPost]
24-
public async Task<ActionResult> Post([FromBody] RegistrationRequest request)
39+
[ProducesResponseType(StatusCodes.Status201Created)]
40+
[ProducesResponseType(StatusCodes.Status202Accepted)]
41+
[ProducesResponseType(StatusCodes.Status400BadRequest)]
42+
public async Task<ActionResult<Dictionary<string,RunnerRegistrationSecretData>>> Post([FromBody] RegistrationRequest request)
2543
{
2644
try
2745
{
28-
var runners = new Dictionary<string, Dictionary<string, string>>();
46+
var runners = new Dictionary<string, RunnerRegistrationSecretData>();
2947
var register = new Register(request);
3048
await register.Setup();
49+
var identifier = new StringBuilder();
50+
identifier.AppendFormat ("runners://{0}/{1}", request.Owner, request.Repository);
3151
foreach (var name in request.RunnerNames)
3252
{
3353
this.logger.LogInformation("Adding runner {name} to {Owner}/{Repository}", name, request.Owner, request.Repository);
34-
var creds = await register.AddRunner(name);
54+
var creds = await register.AddRunner(name, request.DryRun);
3555
runners.Add(name, creds);
56+
identifier.AppendFormat("/{0}", creds.Id);
57+
}
58+
// This is essentially a registration request ID
59+
var idUri = new Uri(identifier.ToString());
60+
if (request.DryRun)
61+
{
62+
return this.Accepted(idUri, runners);
3663
}
37-
return this.Ok(runners);
64+
return this.Created(idUri,runners);
3865
}
3966
catch (InvalidOperationException ex)
4067
{
Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
<Project Sdk="Microsoft.NET.Sdk.Web">
22

3-
<PropertyGroup>
4-
<TargetFramework>netcoreapp3.1</TargetFramework>
5-
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
6-
</PropertyGroup>
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
6+
</PropertyGroup>
77

8-
<ItemGroup>
9-
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.9" />
10-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.2" />
11-
</ItemGroup>
12-
13-
<ItemGroup>
14-
<ProjectReference Include="..\GithubRunnerRegistration\GithubRunnerRegistration.csproj" />
15-
</ItemGroup>
8+
<ItemGroup>
9+
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.9" />
10+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.2" />
11+
</ItemGroup>
1612

13+
<ItemGroup>
14+
<ProjectReference Include="..\GithubRunnerRegistration\GithubRunnerRegistration.csproj" />
15+
</ItemGroup>
16+
<PropertyGroup>
17+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
18+
<NoWarn>$(NoWarn);1591</NoWarn>
19+
</PropertyGroup>
1720

1821
</Project>

GithubRunnerRegistration/GithubRunnerRegistration.Api/Startup.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
using Microsoft.Extensions.Logging;
88
using System;
99
using System.Collections.Generic;
10+
using System.IO;
1011
using System.Linq;
12+
using System.Reflection;
1113
using System.Threading.Tasks;
1214

1315
namespace GithubRunnerRegistration
@@ -25,7 +27,21 @@ public Startup(IConfiguration configuration)
2527
public void ConfigureServices(IServiceCollection services)
2628
{
2729
services.AddControllers();
28-
services.AddSwaggerGen();
30+
services.AddSwaggerGen(c =>
31+
{
32+
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
33+
{
34+
Title = "Github runner registration service",
35+
Version = "v1",
36+
Description = "Registers runners against a repo and returns the data required to associate each runner with the repo."
37+
});
38+
var apiXmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
39+
var xmlFile = $"{nameof(GithubRunnerRegistration)}.xml";
40+
41+
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, apiXmlFile));
42+
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFile));
43+
44+
});
2945
}
3046

3147
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -49,6 +65,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
4965
{
5066
endpoints.MapControllers();
5167
});
68+
5269
}
5370
}
5471
}

GithubRunnerRegistration/GithubRunnerRegistration.Tests/GetCredentialsTest.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace GithubRunnerRegistration.Tests
1010
public class GetCredentialsTest
1111
{
1212
const string runner = "runner content";
13-
const string credentials = "credentials content";
13+
const string credentials = "{\"data\":{\"clientId\":\"213aa528-e449-4fc8-8b51-2f4bcd76d560\"}}";
1414
// This is just a random RSA params object and is not sensitive
1515
const string credentialsRsaParams = "{\"RSAParameters\":{},\"d\":\"hXdVeIRBXrT8GgOF9N5rB0PGhEgH0x9Nm0bzhCbL3YvWxuium+q2Sc8wy9xwBflknLCGD9j5uCyOiD9uxfh3q5Im6sESV/VgetRuGqjNGhSaAnobX6KBVEwYtWnWzV14u0os1F6P0Nkij5cnAOHe1y7LuibdvVkcmqsGudZcUYUlmNitqknWAoEoxtNpu5BjvbC/8MuOZ488NJJBDuZSg75yJsY6KSk/wMXWVWthQ+IiJQqZhi15iJefrlpW5aCmqtbkY2KGKBij+CjvSdMPFrfiKCDZv8PxlzcIIaD9T9pM0p89Ti78p4jBlMsN3dpWjXIQvE3QMnegUeILrxx+RQ==\",\"dp\":\"B3D+bJdztNWoIAfCw8Q/UlsANmCkP7E6XhGydpAtOKN9UhJeK4E9NRRIs6p0glaRR6nsGN4KkM3Yl61ROr8Kn89IsUCZXyXbLnXOmi4BcMrSqssguDQfVlE3NLXOtTYDDv6pDdY2ZMSpThl4edMUydlF7F6bmDaFjMZoEk1SpL0=\",\"dq\":\"AbhSl9H9SVjYzTwg6fLqzB3GCdeC1KTtIM2Uokj/VxjWXIbAxFRG4uSCx3ddoCyRex6WV8nqYSpvsyCoX76+jzomYPdns5SL9kgB2BgIYPKRszUoY8PcNDpPHAPj1PlmzZFpNzsE++kmon54kyavwb47Nuo1A2KnSkw359T+pDU=\",\"exponent\":\"AQAB\",\"inverseQ\":\"kBH3mldmzKxoEdNsMHSPCXenFQySm1hyv3DimLwlDTGX835qp6+FPdFVZK8o2d86kN9xwe/iX+mDe0yK2vCHskgscJlMcGvP0+IgTDDW4ctkmHlD/X2lcJKUif96pmr10bpMm9ayN6Hc4BJFo9YTHtqfZ+Xfc950qPp9GfMtLYs=\",\"modulus\":\"omMMkenoxhTbvMvPsjrYsvWE+VDPMPi8mKgpOr+ngf9AKMGD1fldxsakuxtq1g4qZM768yFMsGPf/XsfHNIwEXXVhn6RSuUu22n0Y8fmHxSraceYXPOCi0mBC64HHZr6jWeCB5KiL2g8iGiNDti6Tsv3xeDU8ACA6LmCz37CB68VUsxXaQQLbGXo8+3qcQ53D5FwLafGSk4yl7gucF5SThvIDxOMsoE65TOxyhEMqiAnGTCU50XJURPj1GBXCzW17CjDmsQ64QKOlNm9EJzmMFo6ttPoOxZRb8usJps0nzPcq2IVhihCnX+udlAttkmo0fdFHKhEKzFbgSvX0vVMWQ==\",\"p\":\"yVtPBKM6ljwjRR1Bsa3h1YsohbE3NaOgX/r7lpTMt5EDVgFLPkyZt9xAQkoBxmce42CVHghlWQqBiPmK5MI0ujrSLxD6Q/zdJzZw4kHqT4M4MM+J+HqPlYPcRC0tWKabsYrkXBdHIe9OuDUfACoh6+yHC0KV91hWmQu3WtYIQDs=\",\"q\":\"znRs1/NkBqBr4I2qs/b4+5Q71ZdKJ0VJBBVNxMAPDEYTZNwI8mxoouHWuq0N2aTg6Ja46K2PCrKTBNsx43Rr01JV21PFYpPyUoF3I5Nx7MCJvdLM24u1Bd3uVc1KfFvLAQm+qObILCLzpJ76MkqBm6hNbmF9du9wCSWav7gEUHs=\"}";
1616

@@ -26,12 +26,12 @@ public async Task ShouldParseCredentials()
2626
File.WriteAllText(Path.Combine(tmp, ".credentials_rsaparams"), credentialsRsaParams);
2727
var getCreds = new GetCredentials();
2828
var creds = await getCreds.GetCredentialsFromPath(tmp);
29-
Assert.Equal(5, creds.Count);
30-
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(credentialsRsaParams)), creds[".credentials_rsaparams"]);
31-
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(runner)), creds[".runner"]);
32-
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials)), creds[".credentials"]);
33-
Assert.NotNull(creds["private.pem"]);
34-
Assert.NotNull(creds["public.pem"]);
29+
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(credentialsRsaParams)), creds.CredentialsRsaParams);
30+
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(runner)), creds.Runner);
31+
Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials)), creds.Credentials);
32+
Assert.Equal("213aa528-e449-4fc8-8b51-2f4bcd76d560", creds.Id.ToString());
33+
Assert.NotNull(creds.PrivatePem);
34+
Assert.NotNull(creds.PublicPem);
3535
}
3636
finally
3737
{

GithubRunnerRegistration/GithubRunnerRegistration.Tests/RegisterTest.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class RegisterTest
2020

2121

2222
[Fact]
23-
public async Task ShouldErrorIfRequestLabelsContainsInvalidChars()
23+
public void ShouldErrorIfRequestLabelsContainsInvalidChars()
2424
{
2525
Assert.Throws<InvalidOperationException>(() => new Register(new RegistrationRequest { AdminPat = Pat, Labels = new string[] { "foo\"" }, Owner = Owner, Repository = Repo }, "a"));
2626
}
@@ -30,7 +30,7 @@ public async Task ShouldErrorIfRequestLabelsContainsInvalidChars()
3030
public async Task ShouldErrorIfNameContainsInvalidChars()
3131
{
3232
var register = new Register(new RegistrationRequest { AdminPat = Pat, Labels = new string[] { }, Owner = Owner, Repository = Repo }, "a");
33-
await Assert.ThrowsAsync<InvalidOperationException>(async () => await register.AddRunner("foo\""));
33+
await Assert.ThrowsAsync<InvalidOperationException>(async () => await register.AddRunner("foo\"", false));
3434
}
3535

3636
[Fact]
@@ -82,13 +82,13 @@ public async Task ShouldCopyAndExecuteBinary()
8282
var binary = Path.Combine(tmp, binaryName);
8383
File.WriteAllText(binary, "this isn't actually executable");
8484

85-
var request = new RegistrationRequest { AdminPat = Pat, Labels = new string[] {"foo" }, Owner = Owner, Repository = Repo };
85+
var request = new RegistrationRequest { AdminPat = Pat, Labels = new string[] { "foo" }, Owner = Owner, Repository = Repo };
8686
var register = new Register(request, binary);
8787
register.RunnerRegistrationToken = "RunnerRegistrationToken";
8888
var secretGenerator = new Mock<IGetCredentials>();
8989
string credsDir = Path.Combine(Path.GetTempPath(), name);
90-
string runnerWd = Path.Combine(credsDir, "runner");
91-
secretGenerator.Setup(g => g.GetCredentialsFromPath(credsDir)).Returns(Task.FromResult(new Dictionary<string, string>{ { "foo", "bar" } })).Verifiable();
90+
string runnerWd = Path.Combine(credsDir, "runner");
91+
secretGenerator.Setup(g => g.GetCredentialsFromPath(credsDir)).Returns(Task.FromResult(new RunnerRegistrationSecretData { Credentials = "foo" })).Verifiable();
9292
void mockRun(ProcessStartInfo startInfo)
9393
{
9494
Assert.Equal("dotnet", startInfo.FileName);
@@ -97,12 +97,36 @@ void mockRun(ProcessStartInfo startInfo)
9797
Assert.True(File.Exists(Path.Combine(runnerWd, binaryName)));
9898
Assert.Equal($"{binaryName} configure --name \"{name}\" --token {register.RunnerRegistrationToken} --url \"https://github.com/{Owner}/{Repo}\" --labels \"foo\" --replace --unattended", startInfo.Arguments);
9999
}
100-
var creds = await register.RegisterRunner(name, secretGenerator.Object, mockRun);
101-
Assert.Equal("bar", creds["foo"]);
100+
var creds = await register.RegisterRunner(name, secretGenerator.Object, false, mockRun);
101+
Assert.Equal("foo", creds.Credentials);
102102
Assert.False(Directory.Exists(runnerWd));
103103
secretGenerator.Verify();
104104
Directory.Delete(tmp, true);
105105
}
106106

107+
108+
[Fact]
109+
public async Task ShouldNotExecuteBinaryOnDryRun()
110+
{
111+
const string binaryName = "binary";
112+
const string name = "foobar";
113+
var tmp = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
114+
Directory.CreateDirectory(tmp);
115+
var binary = Path.Combine(tmp, binaryName);
116+
File.WriteAllText(binary, "this isn't actually executable");
117+
118+
var request = new RegistrationRequest { AdminPat = Pat, Labels = new string[] { "foo" }, Owner = Owner, Repository = Repo };
119+
var register = new Register(request, binary);
120+
register.RunnerRegistrationToken = "RunnerRegistrationToken";
121+
var secretGenerator = new Mock<IGetCredentials>();
122+
string credsDir = Path.Combine(Path.GetTempPath(), name);
123+
string runnerWd = Path.Combine(credsDir, "runner");
124+
var creds = await register.RegisterRunner(name, secretGenerator.Object, true, _=>throw new Exception("boom"));
125+
Assert.False(Directory.Exists(runnerWd));
126+
secretGenerator.Verify(sg => sg.GetCredentialsFromPath(It.IsAny<string>()), Times.Never);
127+
Assert.NotEqual(default, creds.Id);
128+
Directory.Delete(tmp, true);
129+
}
130+
107131
}
108132
}

GithubRunnerRegistration/GithubRunnerRegistration/.dockerignore

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)