diff --git a/src/DMAPI/tgs/v4/api.dm b/src/DMAPI/tgs/v4/api.dm
index 4fb8afc385..bf1f506f0a 100644
--- a/src/DMAPI/tgs/v4/api.dm
+++ b/src/DMAPI/tgs/v4/api.dm
@@ -68,7 +68,7 @@
if(cached_json["apiValidateOnly"])
TGS_INFO_LOG("Validating API and exiting...")
- Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = minimum_required_security_level))
+ Export(TGS4_COMM_VALIDATE, list(TGS4_PARAMETER_DATA = "[minimum_required_security_level]"))
del(world)
chat_channels_json_path = cached_json["chatChannelsJson"]
diff --git a/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs b/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs
index 15c46067f8..e8dd38d401 100644
--- a/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs
+++ b/src/Tgstation.Server.Host/Components/Compiler/DreamMaker.cs
@@ -125,8 +125,8 @@ namespace Tgstation.Server.Host.Components.Compiler
/// The current
/// The port to use for API validation
/// The for the operation
- /// A resulting in if the DMAPI was successfully validated, otherwise
- async Task VerifyApi(uint timeout, DreamDaemonSecurity securityLevel, Models.CompileJob job, IByondExecutableLock byondLock, ushort portToUse, CancellationToken cancellationToken)
+ /// A representing the running operation
+ async Task VerifyApi(uint timeout, DreamDaemonSecurity securityLevel, Models.CompileJob job, IByondExecutableLock byondLock, ushort portToUse, CancellationToken cancellationToken)
{
logger.LogTrace("Verifying DMAPI...");
var launchParameters = new DreamDaemonLaunchParameters
@@ -156,13 +156,27 @@ namespace Tgstation.Server.Host.Components.Compiler
if (!controller.Lifetime.IsCompleted)
{
- logger.LogDebug("API validation timed out!");
- return false;
+ var validationStatus = controller.ApiValidationStatus;
+ logger.LogTrace("API validation status: {0}", validationStatus);
+ switch (validationStatus)
+ {
+ case ApiValidationStatus.Validated:
+ return;
+ case ApiValidationStatus.NeverValidated:
+ break;
+ case ApiValidationStatus.BadValidationRequest:
+ throw new JobException("Recieved an unrecognized API validation request from DreamDaemon!");
+ case ApiValidationStatus.RequiresSafe:
+ throw new JobException("This game must be run with at least the 'Safe' DreamDaemon security level!");
+ case ApiValidationStatus.RequiresTrusted:
+ throw new JobException("This game must be run with at least the 'Trusted' DreamDaemon security level!");
+ case ApiValidationStatus.UnaskedValidationRequest:
+ default:
+ throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Session controller returned unexpected ApiValidationStatus: {0}", validationStatus));
+ }
}
- var validated = controller.ApiValidated;
- logger.LogTrace("API valid: {0}", validated);
- return validated;
+ throw new JobException("DMAPI validation timed out!");
}
}
@@ -356,13 +370,18 @@ namespace Tgstation.Server.Host.Components.Compiler
var exitCode = await RunDreamMaker(byondLock.DreamMakerPath, job, cancellationToken).ConfigureAwait(false);
- var apiValidated = exitCode == 0 && await VerifyApi(apiValidateTimeout, securityLevel, job, byondLock, dreamMakerSettings.ApiValidationPort.Value, cancellationToken).ConfigureAwait(false);
+ try
+ {
+ if (exitCode != 0)
+ throw new JobException(String.Format(CultureInfo.InvariantCulture, "DM exited with a non-zero code: {0}{1}{2}", exitCode, Environment.NewLine, job.Output));
- if (!apiValidated)
+ await VerifyApi(apiValidateTimeout, securityLevel, job, byondLock, dreamMakerSettings.ApiValidationPort.Value, cancellationToken).ConfigureAwait(false);
+ }
+ catch (JobException)
{
//server never validated or compile failed
await eventConsumer.HandleEvent(EventType.CompileFailure, new List { resolvedGameDirectory, exitCode == 0 ? "1" : "0" }, cancellationToken).ConfigureAwait(false);
- throw new JobException(exitCode == 0 ? "Validation of the TGS api failed!" : String.Format(CultureInfo.InvariantCulture, "DM exited with a non-zero code: {0}{1}{2}", exitCode, Environment.NewLine, job.Output));
+ throw;
}
logger.LogTrace("Running post compile event...");
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/ApiValidationStatus.cs b/src/Tgstation.Server.Host/Components/Watchdog/ApiValidationStatus.cs
new file mode 100644
index 0000000000..cc179c5271
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Watchdog/ApiValidationStatus.cs
@@ -0,0 +1,33 @@
+namespace Tgstation.Server.Host.Components.Watchdog
+{
+ ///
+ /// Status of DMAPI validation
+ ///
+ enum ApiValidationStatus
+ {
+ ///
+ /// The DMAPI never contacted the server for validation
+ ///
+ NeverValidated,
+ ///
+ /// The server was contacted for validation but it was never requested
+ ///
+ UnaskedValidationRequest,
+ ///
+ /// The game must be run with a minimum security level of
+ ///
+ RequiresSafe,
+ ///
+ /// The game must be run with a security level of
+ ///
+ RequiresTrusted,
+ ///
+ /// The validation request was malformed
+ ///
+ BadValidationRequest,
+ ///
+ /// The DMAPI validated successfully
+ ///
+ Validated
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs
index 3f2e245eba..97e19b271d 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/ISessionController.cs
@@ -25,9 +25,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
bool TerminationWasRequested { get; }
///
- /// If the DMAPI was validated. This field may only be access once completes
+ /// The DMAPI
///
- bool ApiValidated { get; }
+ ApiValidationStatus ApiValidationStatus { get; }
///
/// The being used
diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
index 20b1115531..969aed7866 100644
--- a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
+++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs
@@ -29,13 +29,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
///
- public bool ApiValidated
+ public ApiValidationStatus ApiValidationStatus
{
get
{
if (!Lifetime.IsCompleted)
throw new InvalidOperationException("ApiValidated cannot be checked while Lifetime is incomplete!");
- return apiValidated;
+ return apiValidationStatus;
}
}
@@ -126,6 +126,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
///
readonly ILogger logger;
+ ///
+ /// The level the was launched with
+ ///
+ readonly DreamDaemonSecurity? launchSecurityLevel;
+
///
/// The waits on when DreamDaemon currently has it's ports closed
///
@@ -151,9 +156,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
bool disposed;
///
- /// If the DMAPI was validated
+ /// The for the
///
- bool apiValidated;
+ ApiValidationStatus apiValidationStatus;
///
/// If should be kept alive instead
@@ -171,8 +176,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// The value of
/// The value of
/// The value of
+ /// The value of
/// The optional time to wait before failing the
- public SessionController(ReattachInformation reattachInformation, IProcess process, IByondExecutableLock byondLock, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, ICommContext interopContext, IChat chat, ILogger logger, uint? startupTimeout)
+ public SessionController(ReattachInformation reattachInformation, IProcess process, IByondExecutableLock byondLock, IByondTopicSender byondTopicSender, IJsonTrackingContext chatJsonTrackingContext, ICommContext interopContext, IChat chat, ILogger logger, DreamDaemonSecurity? launchSecurityLevel, uint? startupTimeout)
{
this.chatJsonTrackingContext = chatJsonTrackingContext; //null valid
this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation));
@@ -183,11 +189,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
this.chat = chat ?? throw new ArgumentNullException(nameof(chat));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ this.launchSecurityLevel = launchSecurityLevel;
+
interopContext.RegisterHandler(this);
portClosedForReboot = false;
disposed = false;
- apiValidated = false;
+ apiValidationStatus = ApiValidationStatus.NeverValidated;
released = false;
rebootTcs = new TaskCompletionSource