Merge branch 'V6' into OpenDream

This commit is contained in:
Jordan Dominion
2023-11-10 23:26:31 -05:00
16 changed files with 76 additions and 43 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/co
### Development Environment
You need the .NET 8.0 SDK and npm>=v5.7 (in your PATH) to compile the server.
You need the .NET 8.0 SDK, node>=v20, and npm>=v5.7 (in your PATH) to compile the server.
The recommended IDE is Visual Studio 2022 or VSCode.
+3 -1
View File
@@ -117,6 +117,8 @@ sudo dpkg --add-architecture i386 \
&& sudo systemctl start tgstation-server
```
The service will execute as the newly created user: `tgstation-server`.
##### Debian
The `aspnetcore-runtime-8.0` package isn't yet available on mainline Debian and must be [installed from Microsoft](https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian) first. Use the following one-liner to add their packages repository.
@@ -143,7 +145,7 @@ The following dependencies are required.
[Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). Choose `ServerConsole`.
If you have SystemD installed, we recommend installing the service unit [here](./build/tgstation-server.service). It assumes TGS is installed into `/opt/tgstation-server` and you will be using the but feel free to adjust it to your needs. Note that the server will need to have it's configuration file setup before running with SystemD.
If you have SystemD installed, we recommend installing the service unit [here](./build/tgstation-server.service). It assumes TGS is installed into `/opt/tgstation-server`, it is executing as the user `tgstation-server`, and you will be using the console runner, but feel free to adjust it to your needs. Note that the server will need to have it's configuration file setup before running with SystemD.
Alternatively, to launch the server in the current shell, run `./tgs.sh` in the root of the installation directory. The process will run in a blocking fashion. SIGQUIT will close the server, terminating all live game instances.
+15 -5
View File
@@ -9,16 +9,27 @@ set -x
dpkg --add-architecture i386
apt-get update
# This package set needs cleanup probably, StackOverflow copypasta
apt-get install -y npm \
apt-get install -y \
build-essential \
binutils \
lintian \
debhelper \
dh-make \
devscripts \
ca-certificates \
curl \
gnupg \
xmlstarlet
# dotnet-sdk-8.0 # Disabled while in preview
# https://github.com/nodesource/distributions
mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
export NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
apt-get update
apt-get install nodejs -y
CURRENT_COMMIT=$(git rev-parse HEAD)
rm -rf packaging
@@ -56,14 +67,13 @@ set +e
if [[ -z "$PACKAGING_KEYGRIP" ]]; then
dpkg-buildpackage --no-sign
EXIT_CODE=$?
else
dpkg-buildpackage --sign-key=$PACKAGING_KEYGRIP --sign-command="$SIGN_COMMAND"
cat /tmp/tgs_wrap_gpg_output.log
EXIT_CODE=$?
fi
EXIT_CODE=$?
cat /tmp/tgs_wrap_gpg_output.log
cd ..
exit $EXIT_CODE
+1 -1
View File
@@ -5,7 +5,7 @@ Maintainer: Jordan Dominion <Cyberboss@users.noreply.github.com>
Rules-Requires-Root: no
Build-Depends:
debhelper-compat (= 13),
npm,
nodejs,
#dotnet-sdk-8.0, Disabled while in preview
Standards-Version: 4.6.2
Homepage: https://tgstation.github.io/tgstation-server
+6 -1
View File
@@ -1,9 +1,14 @@
#!/bin/sh -e
adduser --system tgstation-server
mkdir -m 754 -p /var/log/tgstation-server
chown -R tgstation-server /etc/tgstation-server
chown -R tgstation-server /opt/tgstation-server
chown -R tgstation-server /var/log/tgstation-server
#DEBHELPER#
if [ "$1" = "configure" ]; then
chmod 600 /etc/tgstation-server
deb-systemd-helper stop 'tgstation-server.service' >/dev/null || true
echo " _ _ _ _ "
+21 -11
View File
@@ -3,23 +3,23 @@
export DH_VERBOSE = 1
%:
dh $@
dh $@
override_dh_auto_clean:
rm -rf artifacts
dotnet clean -c ReleaseNoWindows
rm -rf artifacts
dotnet clean -c ReleaseNoWindows
override_dh_auto_build:
dotnet restore
cd src/Tgstation.Server.Host.Console && dotnet publish -c Release -o ../../artifacts
cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default
rm artifacts/lib/Default/appsettings.yml
build/RemoveUnsupportedRuntimes.sh artifacts/lib/Default
build/RemoveUnsupportedRuntimes.sh artifacts
dotnet restore
cd src/Tgstation.Server.Host.Console && dotnet publish -c Release -o ../../artifacts
cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default
rm artifacts/lib/Default/appsettings.yml
build/RemoveUnsupportedRuntimes.sh artifacts/lib/Default
build/RemoveUnsupportedRuntimes.sh artifacts
override_dh_auto_install:
cp build/package/deb/MakeInstall ./Makefile
dh_auto_install --
cp build/package/deb/MakeInstall ./Makefile
dh_auto_install --
override_dh_strip:
@@ -27,3 +27,13 @@ override_dh_shlibdeps:
override_dh_installsystemd:
dh_installsystemd -v --restart-after-upgrade
override_dh_fixperms:
dh_fixperms
find debian/tgstation-server/opt/tgstation-server -exec chmod 544 {} +
find debian/tgstation-server/opt/tgstation-server -type d -exec chmod 555 {} +
find debian/tgstation-server/opt/tgstation-server/lib -exec chmod 744 {} +
find debian/tgstation-server/opt/tgstation-server/lib -type d -exec chmod 755 {} +
find debian/tgstation-server/etc/tgstation-server -exec chmod 644 {} +
find debian/tgstation-server/etc/tgstation-server -type d -exec chmod 755 {} +
chmod 640 debian/tgstation-server/etc/tgstation-server/appsettings.Production.yml
+1 -3
View File
@@ -1,5 +1,3 @@
#!/bin/sh
cd /opt/tgstation-server
export General__SetupWizardMode=Only
exec /usr/bin/dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll /tmp/tgs_temp_should_not_be_used --appsettings-base-path=/etc/tgstation-server
exec su -s /bin/sh -c "cd /opt/tgstation-server && export General__SetupWizardMode=Only && exec /usr/bin/dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll /tmp/tgs_temp_should_not_be_used --appsettings-base-path=/etc/tgstation-server" tgstation-server
+1
View File
@@ -7,6 +7,7 @@ After=postgresql.service
After=mssql-server.service
[Service]
User=tgstation-server
Type=notify-reload
NotifyAccess=all
WorkingDirectory=/opt/tgstation-server
-1
View File
@@ -72,7 +72,6 @@ TGS will only every return the response codes listed here
- 410: Gone. Attempted to access/modify a resource that ideally should have been ready, but isn't or no longer is
- 422: Unprocessable Entity: Used specifically when an operation that requires a server restart is unable to be performed due to the @ref Tgstation.Server.Host.Watchdog not being present in the deployment. Should not happen with a proper server configuration. Response body contains an @ref Tgstation.Server.Api.Models.ErrorMessage
- 424: Failed Dependency: When a request that depends on an external API fails for a reason other than rate limiting. The response body will contain an @ref Tgstation.Server.Api.Models.ErrorMessage model detailing the error.
- 426: Upgrade required: Used when the client's API version is not compatible with the server's. Response body contains an @ref Tgstation.Server.Api.Models.ErrorMessage
- 429: Rate limited. Used with operations that rely on GitHub.com. If a rate limit is hit for an operation this will be returned. Response will contain a Retry-After header with the amount of seconds to wait.
- 500: Server error. Please report the request and response body to the code repository
- 501: Not implemented. Functionality not available in the current server version
+3 -2
View File
@@ -131,8 +131,6 @@ namespace Tgstation.Server.Client
#pragma warning restore IDE0066 // Convert switch statement to expression
#pragma warning restore IDE0010 // Add missing cases
{
case HttpStatusCode.UpgradeRequired:
throw new VersionMismatchException(errorMessage, response);
case HttpStatusCode.Unauthorized:
throw new UnauthorizedException(errorMessage, response);
case HttpStatusCode.InternalServerError:
@@ -154,6 +152,9 @@ namespace Tgstation.Server.Client
case (HttpStatusCode)429:
throw new RateLimitException(errorMessage, response);
default:
if (errorMessage?.ErrorCode == ErrorCode.ApiMismatch)
throw new VersionMismatchException(errorMessage, response);
throw new ApiConflictException(errorMessage, response);
}
}
@@ -7,6 +7,7 @@
<Description>Client library for tgstation-server.</Description>
<PackageTags>json web api tgstation-server tgstation ss13 byond client http</PackageTags>
<PackageReleaseNotes>$(TGS_NUGET_RELEASE_NOTES_CLIENT)</PackageReleaseNotes>
<NoWarn>NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
@@ -7,7 +7,6 @@ Some notable exceptions:
- [ApiController](./ApiController.cs) is the base class of nearly all API related controllers. It does the following:
- Contains code to deny the request if the instance is not present when it should be.
- Contains the `IDatabaseContext` and `ILogger` properties for child controllers.
- Returns 426 Upgrade Required if the API version in the headers are incompatible with the request.
- Returns 400 Bad Request if the headers or the PUT/POST'd model is invalid.
- Returns 401 If an `IAuthenticationContext` could not be created for a request.
- [BridgeController](./BridgeController.cs) is a special controller accessible only from localhost and is used to receive bridge request from DreamDaemon
@@ -132,11 +132,8 @@ namespace Tgstation.Server.Host.Extensions
var apiHeadersProvider = context.RequestServices.GetRequiredService<IApiHeadersProvider>();
if (apiHeadersProvider.ApiHeaders?.Compatible() == false)
{
await new JsonResult(
await new BadRequestObjectResult(
new ErrorMessageResponse(ErrorCode.ApiMismatch))
{
StatusCode = (int)HttpStatusCode.UpgradeRequired,
}
.ExecuteResultAsync(new ActionContext
{
HttpContext = context,
+2 -2
View File
@@ -16,7 +16,7 @@
## For the login request (`POST /`)
1. An attempt to parse the `ApiHeaders` is made. If they were valid, the API version check is performed. If it fails, HTTP 426 with an `ErrorMessageResponse` will be returned.
1. An attempt to parse the `ApiHeaders` is made. If they were valid, the API version check is performed. If it fails, HTTP 400 with an `ErrorMessageResponse` will be returned.
1. If, for some reason, the user attempts to use a JWT to authenticate this request, steps 2-4 of the non-login pipeline list below are performed.
1. The `ApiController` base class inspects the request.
- At this point, if the `ApiHeaders` (MINUS the `Authorization` header) cannot be properly parsed, HTTP 400 with an `ErrorMessageResponse` is returned.
@@ -51,7 +51,7 @@
## For all other authenticated requests
1. An attempt to parse the `ApiHeaders` is made. If they were valid. The API version check is performed. If it fails, HTTP 426 with an `ErrorMessageResponse` will be returned.
1. An attempt to parse the `ApiHeaders` is made. If they were valid. The API version check is performed. If it fails, HTTP 400 with an `ErrorMessageResponse` will be returned.
1. The JWT, if present, is validated. If it is, the scope's [AuthenticationContextFactory](./AuthenticationContextFactory.cs) has `SetTokenNbf` called. If not, HTTP 401 will be returned.
- Inside ASP.NET Core, this initializes the calling user's identity principal and sets the "sub" claim to the TGS user ID parsed out of the JWT.
- We know it's the user ID because we set it up like that in the [TokenFactory](./TokenFactory.cs)
@@ -158,19 +158,29 @@ namespace Tgstation.Server.Tests.Live.Instance
var seenThisJob = seenJobs.TryGetValue(job.Id.Value, out var hubJob);
if (seenThisJob)
{
Assert.AreEqual(job.StoppedAt, hubJob.StoppedAt);
if (hubJob.StoppedAt.HasValue)
{
Assert.AreEqual(job.StoppedAt, hubJob.StoppedAt);
Assert.AreEqual(job.ExceptionDetails, hubJob.ExceptionDetails);
Assert.AreEqual(job.Progress, hubJob.Progress);
Assert.AreEqual(job.Stage, hubJob.Stage);
Assert.AreEqual(job.ErrorCode, hubJob.ErrorCode);
Assert.AreEqual(job.CancelledBy?.Id, hubJob.CancelledBy?.Id);
Assert.AreEqual(job.Cancelled, hubJob.Cancelled);
}
static DateTimeOffset PerformDBTruncation(DateTimeOffset original)
=> new DateTimeOffset(
original.Ticks - (original.Ticks % TimeSpan.TicksPerSecond),
original.Offset);
Assert.AreEqual(job.InstanceId, hubJob.InstanceId);
Assert.AreEqual(job.ExceptionDetails, hubJob.ExceptionDetails);
Assert.AreEqual(job.Stage, hubJob.Stage);
Assert.AreEqual(job.CancelledBy?.Id, hubJob.CancelledBy?.Id);
Assert.AreEqual(job.Cancelled, hubJob.Cancelled);
Assert.AreEqual(job.StartedBy?.Id, hubJob.StartedBy?.Id);
Assert.AreEqual(job.CancelRight, hubJob.CancelRight);
Assert.AreEqual(job.CancelRightsType, hubJob.CancelRightsType);
Assert.AreEqual(job.Progress, hubJob.Progress);
Assert.AreEqual(job.Description, hubJob.Description);
Assert.AreEqual(job.ErrorCode, hubJob.ErrorCode);
Assert.AreEqual(job.StartedAt, hubJob.StartedAt);
Assert.AreEqual(PerformDBTruncation(job.StartedAt.Value), PerformDBTruncation(hubJob.StartedAt.Value)); // RHS may NOT be DB truncated, both sides because not all DBs do this
Assert.AreEqual(job.JobCode, hubJob.JobCode);
}
else
{
@@ -87,7 +87,7 @@ namespace Tgstation.Server.Tests.Live
request.Headers.Add(ApiHeaders.ApiVersionHeader, "Tgstation.Server.Api/6.0.0");
request.Headers.Authorization = new AuthenticationHeaderValue(ApiHeaders.BearerAuthenticationScheme, token);
using var response = await httpClient.SendAsync(request, cancellationToken);
Assert.AreEqual(HttpStatusCode.UpgradeRequired, response.StatusCode);
Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
var content = await response.Content.ReadAsStringAsync(cancellationToken);
var message = JsonConvert.DeserializeObject<ErrorMessageResponse>(content);
Assert.AreEqual(ErrorCode.ApiMismatch, message.ErrorCode);
@@ -101,7 +101,7 @@ namespace Tgstation.Server.Tests.Live
request.Headers.Add(ApiHeaders.ApiVersionHeader, "Tgstation.Server.Api/6.0.0");
request.Headers.Authorization = new AuthenticationHeaderValue(ApiHeaders.BearerAuthenticationScheme, token);
using var response = await httpClient.SendAsync(request, cancellationToken);
Assert.AreEqual(HttpStatusCode.UpgradeRequired, response.StatusCode);
Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
var content = await response.Content.ReadAsStringAsync(cancellationToken);
var message = JsonConvert.DeserializeObject<ErrorMessageResponse>(content);
Assert.AreEqual(ErrorCode.ApiMismatch, message.ErrorCode);