diff --git a/README.md b/README.md index dd2c7379ea..52f406aa7e 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ Create an `appsettings.Production.json` file next to `appsettings.json`. This wi - `General:MinimumPasswordLength`: Minimum password length requirement for database users +- `General:GitHubAccessToken`: Specify a GitHub personal access token with no scopes here to highly mitigate the possiblity of 429 response codes from GitHub requests + - `Logging:LogLevel:Default`: Can be one of `Trace`, `Debug`, `Information`, `Warning`, `Error`, or `Critical`. Restricts what is put into the log files. Currently `Debug` is reccommended for help with error reporting. - `Kestrel:Endpoints:Http:Url`: The URL (i.e. interface and ports) your application should listen on. General use case should be `http://localhost:` for restricted local connections. See the Remote Access section for configuring public access to the World Wide Web. diff --git a/appveyor.yml b/appveyor.yml index 9bd18e311d..4874f5497a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ pull_requests: environment: TGS4_TEST_DATABASE_TYPE: SqlServer TGS4_TEST_CONNECTION_STRING: Server=(local)\SQL2017;Initial Catalog=TGS_Test;User ID=sa;Password=Password12! - repo_token: + TGS4_TEST_GITHUB_TOKEN: secure: lJNGAXwiB5HlWdthz3K4PetqpTG5IEAyRgKaiKxFMQ8HW8CcOjRtB97B05op7BsK branches: only: diff --git a/build/BuildDox.ps1 b/build/BuildDox.ps1 index 81e88b9666..9087e16101 100644 --- a/build/BuildDox.ps1 +++ b/build/BuildDox.ps1 @@ -30,6 +30,6 @@ if($publish_dox){ echo "" > .nojekyll git add --all git commit -m "Deploy code docs to GitHub Pages for Appveyor build $Env:APPVEYOR_BUILD_NUMBER" -m "Commit: $Env:APPVEYOR_REPO_COMMIT" - git push -f "https://$Env:repo_token@$github_url" 2>&1 | out-null + git push -f "https://$Env:TGS4_TEST_GITHUB_TOKEN@$github_url" 2>&1 | out-null cd "$bf" } diff --git a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs index 6b7884b399..0451038e48 100644 --- a/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/GeneralConfiguration.cs @@ -24,5 +24,10 @@ /// Minimum length of database user passwords /// public uint MinimumPasswordLength { get; set; } + + /// + /// A GitHub personal access token to use for bypassing rate limits on requests. Requires no scopes + /// + public string GitHubAccessToken { get; set; } } } diff --git a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs index a401011001..e3d8fb5e6a 100644 --- a/src/Tgstation.Server.Host/Controllers/AdministrationController.cs +++ b/src/Tgstation.Server.Host/Controllers/AdministrationController.cs @@ -31,9 +31,9 @@ namespace Tgstation.Server.Host.Controllers const string RestartNotSupportedException = "This deployment of tgstation-server is lacking the Tgstation.Server.Host.Watchdog component. Restarts and version changes cannot be completed!"; /// - /// The for the + /// The for the /// - readonly IGitHubClient gitHubClient; + readonly IGitHubClientFactory gitHubClientFactory; /// /// The for the @@ -55,24 +55,31 @@ namespace Tgstation.Server.Host.Controllers /// readonly UpdatesConfiguration updatesConfiguration; + /// + /// The for the + /// + readonly GeneralConfiguration generalConfiguration; + /// /// Construct an /// /// The for the /// The for the - /// The value of + /// The value of /// The value of /// The value of /// The value of /// The for the /// The containing value of - public AdministrationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClient gitHubClient, IServerControl serverUpdater, IApplication application, IIOManager ioManager, ILogger logger, IOptions updatesConfigurationOptions) : base(databaseContext, authenticationContextFactory, logger, false) + /// The containing value of + public AdministrationController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IGitHubClientFactory gitHubClientFactory, IServerControl serverUpdater, IApplication application, IIOManager ioManager, ILogger logger, IOptions updatesConfigurationOptions, IOptions generalConfigurationOptions) : base(databaseContext, authenticationContextFactory, logger, false) { - this.gitHubClient = gitHubClient ?? throw new ArgumentNullException(nameof(gitHubClient)); + this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); this.serverUpdater = serverUpdater ?? throw new ArgumentNullException(nameof(serverUpdater)); this.application = application ?? throw new ArgumentNullException(nameof(application)); this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); updatesConfiguration = updatesConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(updatesConfigurationOptions)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } StatusCodeResult RateLimit(RateLimitExceededException exception) @@ -83,6 +90,8 @@ namespace Tgstation.Server.Host.Controllers return StatusCode(429); } + IGitHubClient GetGitHubClient() => String.IsNullOrEmpty(generalConfiguration.GitHubAccessToken) ? gitHubClientFactory.CreateClient() : gitHubClientFactory.CreateClient(generalConfiguration.GitHubAccessToken); + /// [TgsAuthorize] public override async Task Read(CancellationToken cancellationToken) @@ -93,6 +102,7 @@ namespace Tgstation.Server.Host.Controllers Uri repoUrl = null; try { + var gitHubClient = GetGitHubClient(); var repositoryTask = gitHubClient.Repository.Get(updatesConfiguration.GitHubRepositoryId); var releases = (await gitHubClient.Repository.Release.GetAll(updatesConfiguration.GitHubRepositoryId).ConfigureAwait(false)).Where(x => x.TagName.StartsWith(updatesConfiguration.GitTagPrefix, StringComparison.InvariantCulture)); @@ -137,6 +147,7 @@ namespace Tgstation.Server.Host.Controllers IEnumerable releases; try { + var gitHubClient = GetGitHubClient(); releases = (await gitHubClient.Repository.Release.GetAll(updatesConfiguration.GitHubRepositoryId).ConfigureAwait(false)).Where(x => x.TagName.StartsWith(updatesConfiguration.GitTagPrefix, StringComparison.InvariantCulture)); } catch (RateLimitExceededException e) diff --git a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs index 1d1d26b4e8..02ccede7d0 100644 --- a/src/Tgstation.Server.Host/Controllers/RepositoryController.cs +++ b/src/Tgstation.Server.Host/Controllers/RepositoryController.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Globalization; @@ -15,6 +16,7 @@ using Tgstation.Server.Api; using Tgstation.Server.Api.Models; using Tgstation.Server.Api.Rights; using Tgstation.Server.Host.Components; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Core; using Tgstation.Server.Host.Models; using Tgstation.Server.Host.Security; @@ -42,6 +44,11 @@ namespace Tgstation.Server.Host.Controllers /// readonly IJobManager jobManager; + /// + /// The for the + /// + readonly GeneralConfiguration generalConfiguration; + /// /// Construct a /// @@ -51,11 +58,13 @@ namespace Tgstation.Server.Host.Controllers /// The value of /// The value of /// The for the - public RepositoryController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager, IGitHubClientFactory gitHubClientFactory, IJobManager jobManager, ILogger logger) : base(databaseContext, authenticationContextFactory, logger, true) + /// The containing value of + public RepositoryController(IDatabaseContext databaseContext, IAuthenticationContextFactory authenticationContextFactory, IInstanceManager instanceManager, IGitHubClientFactory gitHubClientFactory, IJobManager jobManager, ILogger logger, IOptions generalConfigurationOptions) : base(databaseContext, authenticationContextFactory, logger, true) { this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager)); this.gitHubClientFactory = gitHubClientFactory ?? throw new ArgumentNullException(nameof(gitHubClientFactory)); this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); + generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); } static async Task LoadRevisionInformation(Components.Repository.IRepository repository, IDatabaseContext databaseContext, Models.Instance instance, string lastOriginCommitSha, Action revInfoSink, CancellationToken cancellationToken) @@ -480,7 +489,7 @@ namespace Tgstation.Server.Host.Controllers foreach (var I in model.NewTestMerges.Where(x => String.IsNullOrWhiteSpace(x.PullRequestRevision))) I.PullRequestRevision = null; - var gitHubClient = currentModel.AccessToken != null ? gitHubClientFactory.CreateClient(currentModel.AccessToken) : gitHubClientFactory.CreateClient(); + var gitHubClient = String.IsNullOrEmpty(generalConfiguration.GitHubAccessToken) ? (currentModel.AccessToken != null ? gitHubClientFactory.CreateClient(currentModel.AccessToken) : gitHubClientFactory.CreateClient()) : gitHubClientFactory.CreateClient(generalConfiguration.GitHubAccessToken); var repoOwner = repo.GitHubOwner; var repoName = repo.GitHubRepoName; diff --git a/src/Tgstation.Server.Host/Core/Application.cs b/src/Tgstation.Server.Host/Core/Application.cs index ea72e0aba3..eaa3e40521 100644 --- a/src/Tgstation.Server.Host/Core/Application.cs +++ b/src/Tgstation.Server.Host/Core/Application.cs @@ -176,7 +176,6 @@ namespace Tgstation.Server.Host.Core services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(x => x.GetRequiredService().CreateClient()); if (isWindows) { diff --git a/src/Tgstation.Server.Host/appsettings.Docker.json b/src/Tgstation.Server.Host/appsettings.Docker.json index d90c93f5a5..f7d5860d86 100644 --- a/src/Tgstation.Server.Host/appsettings.Docker.json +++ b/src/Tgstation.Server.Host/appsettings.Docker.json @@ -1,6 +1,8 @@ { "General": { - "LogFileDirectory": "/tgs_logs" + "LogFileDirectory": "/tgs_logs", + "MinimumPasswordLength": 15, + "GitHubAccessToken": null }, "Database": { "DatabaseType": "SqlServer or MySQL or MariaDB", diff --git a/src/Tgstation.Server.Host/appsettings.json b/src/Tgstation.Server.Host/appsettings.json index 84f836f297..79fa36f60b 100644 --- a/src/Tgstation.Server.Host/appsettings.json +++ b/src/Tgstation.Server.Host/appsettings.json @@ -2,7 +2,8 @@ "General": { "LogFileDirectory": null, //use the default path "DisableFileLogging": false, - "MinimumPasswordLength": 15 + "MinimumPasswordLength": 15, + "GitHubAccessToken": null }, "Kestrel": { "EndPoints": { diff --git a/tests/Tgstation.Server.Tests/TestingServer.cs b/tests/Tgstation.Server.Tests/TestingServer.cs index e583fa5e93..50a2691860 100644 --- a/tests/Tgstation.Server.Tests/TestingServer.cs +++ b/tests/Tgstation.Server.Tests/TestingServer.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading; @@ -28,6 +29,7 @@ namespace Tgstation.Server.Tests //we have to rely on env vars var databaseType = Environment.GetEnvironmentVariable("TGS4_TEST_DATABASE_TYPE"); var connectionString = Environment.GetEnvironmentVariable("TGS4_TEST_CONNECTION_STRING"); + var gitHubAccessToken = Environment.GetEnvironmentVariable("TGS4_TEST_GITHUB_TOKEN"); if (String.IsNullOrEmpty(databaseType)) Assert.Fail("No database type configured in env var TGS4_TEST_DATABASE_TYPE!"); @@ -35,13 +37,18 @@ namespace Tgstation.Server.Tests if (String.IsNullOrEmpty(connectionString)) Assert.Fail("No connection string configured in env var TGS4_TEST_CONNECTION_STRING!"); - realServer = new ServerFactory().CreateServer(new string[] + var args = new List() { String.Format(CultureInfo.InvariantCulture, "Kestrel:EndPoints:Http:Url={0}", Url), String.Format(CultureInfo.InvariantCulture, "Database:DatabaseType={0}", databaseType), String.Format(CultureInfo.InvariantCulture, "Database:ConnectionString={0}", connectionString), "Database:DropDatabase=true" - }, null); + }; + + if (!String.IsNullOrEmpty(gitHubAccessToken)) + args.Add(String.Format(CultureInfo.InvariantCulture, "General:GitHubAccessToken={0}", gitHubAccessToken)); + + realServer = new ServerFactory().CreateServer(args.ToArray(), null); } public void Dispose()