diff --git a/Directory.Packages.props b/Directory.Packages.props
index ea8ccb57..de14c2aa 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -12,6 +12,7 @@
+
@@ -21,6 +22,7 @@
+
diff --git a/docker-compose.yml b/docker-compose.yml
index bba4ad9c..c06c3a06 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,22 @@
version: '3.8'
services:
+ localstack:
+ image: localstack/localstack:4.8
+ container_name: adaptiveremote-localstack
+ ports:
+ - "4566:4566"
+ environment:
+ - SERVICES=lambda,dynamodb,sqs
+ - DEBUG=1
+ - LAMBDA_EXECUTOR=docker
+ - AWS_DEFAULT_REGION=us-east-1
+ volumes:
+ - localstack-data:/var/lib/localstack
+ - /var/run/docker.sock:/var/run/docker.sock
+ networks:
+ - backend
+
compiledlayoutservice:
build:
context: .
@@ -14,9 +30,15 @@ services:
# See _doc_Auth.md for Cognito dev user pool setup instructions.
- Cognito__Authority=${COGNITO_AUTHORITY:-}
- Cognito__Audience=${COGNITO_AUDIENCE:-}
+ - LocalStack__BaseUrl=http://localstack:4566
+ depends_on:
+ - localstack
networks:
- backend
networks:
backend:
driver: bridge
+
+volumes:
+ localstack-data:
diff --git a/docs/local-dev.md b/docs/local-dev.md
new file mode 100644
index 00000000..06622d97
--- /dev/null
+++ b/docs/local-dev.md
@@ -0,0 +1,98 @@
+# Local Backend Development
+
+This guide covers local backend dependencies for AdaptiveRemote backend services.
+
+> Current repository state: `AdaptiveRemote.Backend.CompiledLayoutService` is the only
+> backend API service currently implemented in `src/`. Apply the same startup and `/scalar`
+> checks to additional backend services as they are added.
+
+## Prerequisites
+
+1. Install Docker Desktop (or Docker Engine + Docker Compose plugin).
+2. Verify tools:
+ - `docker --version`
+ - `docker compose version`
+3. From the repository root, start local dependencies:
+
+ ```bash
+ docker compose up -d
+ ```
+
+## Confirm LocalStack health
+
+LocalStack health endpoint must be reachable:
+
+```bash
+curl http://localhost:4566/_localstack/health
+```
+
+Expected response contains LocalStack health JSON with either:
+
+```json
+{ "status": "running" }
+```
+
+or service entries showing required services as available/running, for example:
+
+```json
+{
+ "services": {
+ "dynamodb": "available",
+ "lambda": "available",
+ "sqs": "available"
+ }
+}
+```
+
+## Cognito development credentials
+
+Set Cognito values for backend services (for `docker-compose` these map to
+`COGNITO_AUTHORITY` and `COGNITO_AUDIENCE`):
+
+- `Cognito__Authority` / `COGNITO_AUTHORITY`
+- `Cognito__Audience` / `COGNITO_AUDIENCE` (optional)
+
+See `src/AdaptiveRemote.Backend.CompiledLayoutService/_doc_Auth.md`
+for full Cognito dev user pool setup.
+
+## Scalar API browser
+
+When running backend API services in development, Scalar is available at:
+
+- `http://localhost:/scalar`
+
+Scalar is development-only and is not mapped in non-development environments.
+
+## Lambda local debugging
+
+Install the Lambda test tool globally (latest .NET 10-compatible package):
+
+```bash
+dotnet tool install -g Amazon.Lambda.TestTool-10.0
+```
+
+Use a launch profile that starts the test tool for interactive invocation/debugging.
+
+## LocalStack Lambda invocation samples
+
+Use `--endpoint-url http://localhost:4566` for local invocation.
+
+### LayoutCompilerService
+
+```bash
+aws lambda invoke \
+ --endpoint-url http://localhost:4566 \
+ --function-name adaptiveremote-layout-compiler-dev \
+ --payload '{"id":"00000000-0000-0000-0000-000000000001","userId":"test-user","elements":[]}' \
+ response-layout-compiler.json
+```
+
+### LayoutValidationService
+
+```bash
+aws lambda invoke \
+ --endpoint-url http://localhost:4566 \
+ --function-name adaptiveremote-layout-validation-dev \
+ --payload '{"id":"00000000-0000-0000-0000-000000000001","userId":"test-user","elements":[],"cssDefinitions":[]}' \
+ response-layout-validation.json
+```
diff --git a/global.json b/global.json
index b24aad66..512142d2 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "10.0.100",
- "rollForward": "latestPatch"
+ "rollForward": "latestFeature"
}
}
diff --git a/src/AdaptiveRemote.Backend.CompiledLayoutService/AdaptiveRemote.Backend.CompiledLayoutService.csproj b/src/AdaptiveRemote.Backend.CompiledLayoutService/AdaptiveRemote.Backend.CompiledLayoutService.csproj
index a2b8d2e2..8199e544 100644
--- a/src/AdaptiveRemote.Backend.CompiledLayoutService/AdaptiveRemote.Backend.CompiledLayoutService.csproj
+++ b/src/AdaptiveRemote.Backend.CompiledLayoutService/AdaptiveRemote.Backend.CompiledLayoutService.csproj
@@ -5,10 +5,13 @@
enable
enable
AdaptiveRemote.Backend.CompiledLayoutService
+ 3b8e930e-a235-49e8-81b1-db01bf4f9540
+
+
diff --git a/src/AdaptiveRemote.Backend.CompiledLayoutService/Logging/MessageLogger.cs b/src/AdaptiveRemote.Backend.CompiledLayoutService/Logging/MessageLogger.cs
index 761f67ff..a1ff5f46 100644
--- a/src/AdaptiveRemote.Backend.CompiledLayoutService/Logging/MessageLogger.cs
+++ b/src/AdaptiveRemote.Backend.CompiledLayoutService/Logging/MessageLogger.cs
@@ -33,4 +33,10 @@ public static partial class MessageLogger
[LoggerMessage(EventId = 1107, Level = LogLevel.Error, Message = "Error processing health check request")]
public static partial void ErrorProcessingHealthCheck(this ILogger logger, Exception exception);
+
+ [LoggerMessage(
+ EventId = 1108,
+ Level = LogLevel.Error,
+ Message = "LocalStack dependency check failed at {HealthUrl}: {FailureReason}. LocalStack is required for local development. See docs/local-dev.md for setup instructions")]
+ public static partial void LocalStackDependencyUnavailable(this ILogger logger, string healthUrl, string failureReason, Exception? exception);
}
diff --git a/src/AdaptiveRemote.Backend.CompiledLayoutService/Program.cs b/src/AdaptiveRemote.Backend.CompiledLayoutService/Program.cs
index e03e5bb2..df0627e8 100644
--- a/src/AdaptiveRemote.Backend.CompiledLayoutService/Program.cs
+++ b/src/AdaptiveRemote.Backend.CompiledLayoutService/Program.cs
@@ -7,6 +7,9 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Scalar.AspNetCore;
+using System.Net.Http;
+using System.Text.Json;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
@@ -41,15 +44,28 @@
});
builder.Services.AddAuthorization();
+builder.Services.AddOpenApi();
WebApplication app = builder.Build();
ILogger logger = app.Services.GetRequiredService>();
logger.ServiceStarting();
+if (app.Environment.IsDevelopment())
+{
+ await EnsureLocalStackRunningAsync(app, logger).ConfigureAwait(false);
+}
+
app.UseAuthentication();
app.UseAuthorization();
+app.MapOpenApi();
+
+if (app.Environment.IsDevelopment())
+{
+ app.MapScalarApiReference();
+}
+
// Map endpoints
app.MapHealthEndpoints();
app.MapLayoutEndpoints();
@@ -63,5 +79,111 @@
app.Run();
+static async Task EnsureLocalStackRunningAsync(WebApplication app, ILogger logger)
+{
+ const int LocalStackHealthCheckTimeoutSeconds = 5;
+ const int LocalStackStartupWaitTimeoutSeconds = 30;
+ const int LocalStackRetryDelaySeconds = 2;
+ TimeSpan localStackStartupWaitTimeout = TimeSpan.FromSeconds(LocalStackStartupWaitTimeoutSeconds);
+ TimeSpan localStackRetryDelay = TimeSpan.FromSeconds(LocalStackRetryDelaySeconds);
+ string[] requiredServices = ["dynamodb", "lambda", "sqs"];
+
+ string baseUrl = app.Configuration["LocalStack:BaseUrl"] ?? "http://localhost:4566";
+
+ if (!Uri.TryCreate(baseUrl, UriKind.Absolute, out Uri? baseUri))
+ {
+ logger.LocalStackDependencyUnavailable(baseUrl, "configuration value is not a valid absolute URL", exception: null);
+ Environment.Exit(1);
+ }
+
+ Uri healthUri = new(baseUri, "/_localstack/health");
+
+ using HttpClient client = new() { Timeout = TimeSpan.FromSeconds(LocalStackHealthCheckTimeoutSeconds) };
+ Exception? lastException = null;
+ string? lastFailureReason = null;
+ DateTime deadlineUtc = DateTime.UtcNow.Add(localStackStartupWaitTimeout);
+
+ while (DateTime.UtcNow < deadlineUtc)
+ {
+ try
+ {
+ using HttpResponseMessage response = await client.GetAsync(healthUri).ConfigureAwait(false);
+ string body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ lastFailureReason = $"HTTP {(int)response.StatusCode}";
+ }
+ else
+ {
+ using JsonDocument json = JsonDocument.Parse(body);
+ if (IsLocalStackRunning(json.RootElement, requiredServices, out string failureReason))
+ {
+ return;
+ }
+
+ lastFailureReason = failureReason;
+ }
+
+ lastException = null;
+ }
+ catch (Exception ex)
+ {
+ lastException = ex;
+ lastFailureReason = ex.Message;
+ }
+
+ await Task.Delay(localStackRetryDelay).ConfigureAwait(false);
+ }
+
+ logger.LocalStackDependencyUnavailable(
+ healthUri.ToString(),
+ $"did not become healthy within {LocalStackStartupWaitTimeoutSeconds}s; last check result: {lastFailureReason ?? "unknown health check failure"}",
+ lastException);
+ Environment.Exit(1);
+}
+
+static bool IsLocalStackRunning(JsonElement root, IReadOnlyList requiredServices, out string failureReason)
+{
+ if (root.TryGetProperty("status", out JsonElement statusElement))
+ {
+ string status = statusElement.GetString() ?? string.Empty;
+ if (string.Equals(status, "running", StringComparison.OrdinalIgnoreCase))
+ {
+ failureReason = string.Empty;
+ return true;
+ }
+
+ failureReason = $"status='{status}'";
+ return false;
+ }
+
+ if (!root.TryGetProperty("services", out JsonElement servicesElement) || servicesElement.ValueKind != JsonValueKind.Object)
+ {
+ failureReason = "health response did not contain a running status or services object";
+ return false;
+ }
+
+ foreach (string service in requiredServices)
+ {
+ if (!servicesElement.TryGetProperty(service, out JsonElement serviceStatusElement))
+ {
+ failureReason = $"service '{service}' was missing from health response";
+ return false;
+ }
+
+ string serviceStatus = serviceStatusElement.GetString() ?? string.Empty;
+ if (!string.Equals(serviceStatus, "available", StringComparison.OrdinalIgnoreCase) &&
+ !string.Equals(serviceStatus, "running", StringComparison.OrdinalIgnoreCase))
+ {
+ failureReason = $"service '{service}' status was '{serviceStatus}'";
+ return false;
+ }
+ }
+
+ failureReason = string.Empty;
+ return true;
+}
+
// Make Program visible for testing
public partial class Program { }
diff --git a/src/AdaptiveRemote.Backend.CompiledLayoutService/Properties/launchSettings.json b/src/AdaptiveRemote.Backend.CompiledLayoutService/Properties/launchSettings.json
index 665343d2..6c3e8839 100644
--- a/src/AdaptiveRemote.Backend.CompiledLayoutService/Properties/launchSettings.json
+++ b/src/AdaptiveRemote.Backend.CompiledLayoutService/Properties/launchSettings.json
@@ -1,12 +1,23 @@
{
"profiles": {
+ "Development": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "scalar",
+ "outputCapture": "None",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:54433;http://localhost:54434"
+ },
"AdaptiveRemote.Backend.CompiledLayoutService": {
"commandName": "Project",
"launchBrowser": true,
+ "launchUrl": "scalar",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:54433;http://localhost:54434"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/AdaptiveRemote.Backend.CompiledLayoutService/_doc_Auth.md b/src/AdaptiveRemote.Backend.CompiledLayoutService/_doc_Auth.md
index 843ce8e5..ca4d63f2 100644
--- a/src/AdaptiveRemote.Backend.CompiledLayoutService/_doc_Auth.md
+++ b/src/AdaptiveRemote.Backend.CompiledLayoutService/_doc_Auth.md
@@ -22,7 +22,7 @@ The `sub` claim from the validated JWT is used as the `userId` throughout the se
- `adaptiveremote-editor` — enable Authorization Code flow; configure allowed callback URL.
3. Create a resource server (custom scope), e.g. `adaptiveremote/layouts.read`.
4. Note the user pool's **Issuer URL** (shown in the pool's details page):
- `https://cognito-idp.{region}.amazonaws.com/{userPoolId}`
+ `https://cognito-idp.us-east-2.amazonaws.com/us-east-2_65NKvrlha`
## Configuring the backend service
@@ -30,7 +30,7 @@ Set these environment variables (or values in `appsettings.Development.json` —
| Variable | Example |
|----------|---------|
-| `Cognito__Authority` | `https://cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC123` |
+| `Cognito__Authority` | `https://cognito-idp.us-east-2.amazonaws.com/us-east-2_65NKvrlha` |
| `Cognito__Audience` | `` (optional; leave empty to skip audience validation) |
For local development via `docker-compose`, set `COGNITO_AUTHORITY` and `COGNITO_AUDIENCE` in a
@@ -45,8 +45,8 @@ Set in `appsettings.Development.json` (non-secret values) and user secrets (secr
"backend": {
"baseUrl": "http://localhost:8080",
"cognito": {
- "authority": "https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
- "clientId": "YOUR_CLIENT_ID",
+ "authority": "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_65NKvrlha",
+ "clientId": "5g6eqq1v1o7lju703enelssl89",
"scope": "adaptiveremote/layouts.read"
}
}
@@ -82,6 +82,34 @@ with **Lambda Function URLs**. These URLs are not exposed via API Gateway and ar
only from within the ECS cluster (network isolation via VPC/security groups). No bearer token
validation is required or expected on internal Lambda endpoints.
+## Getting a test token (manual testing / Scalar)
+
+To test protected endpoints manually (e.g. via the Scalar UI), you need a bearer token from
+the `adaptiveremote-client` app client.
+
+**Option 1 — curl**
+```bash
+curl -X POST https://us-east-265nkvrlha.auth.us-east-2.amazoncognito.com/oauth2/token \
+ -H "Content-Type: application/x-www-form-urlencoded" \
+ -d "grant_type=client_credentials&client_id=44qanfe7hvaeumffnt5hsk0ojr&client_secret=YOUR_CLIENT_SECRET&scope=adaptiveremote/layouts.read"
+```
+
+**Option 2 — browser console (no install required)**
+```javascript
+const resp = await fetch("https://us-east-265nkvrlha.auth.us-east-2.amazoncognito.com/oauth2/token", {
+ method: "POST",
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
+ body: "grant_type=client_credentials&client_id=44qanfe7hvaeumffnt5hsk0ojr&client_secret=YOUR_CLIENT_SECRET&scope=adaptiveremote/layouts.read"
+});
+console.log(await resp.json());
+```
+
+Both return a JSON object containing `access_token`. Set it as `Authorization: Bearer `
+in the request headers.
+
+If you don't know the token endpoint URL, discover it from the OIDC metadata document:
+`https://cognito-idp.us-east-2.amazonaws.com/us-east-2_65NKvrlha/.well-known/openid-configuration` — look for the `token_endpoint` field.
+
## API integration tests
Tests use a `TestJwtAuthority` (`test/AdaptiveRemote.Backend.ApiTests/Support/TestJwtAuthority.cs`),
diff --git a/src/AdaptiveRemote.Backend.CompiledLayoutService/appsettings.Development.json b/src/AdaptiveRemote.Backend.CompiledLayoutService/appsettings.Development.json
index 3ae5de58..fc09110a 100644
--- a/src/AdaptiveRemote.Backend.CompiledLayoutService/appsettings.Development.json
+++ b/src/AdaptiveRemote.Backend.CompiledLayoutService/appsettings.Development.json
@@ -8,5 +8,8 @@
"Cognito": {
"Authority": "",
"Audience": ""
+ },
+ "LocalStack": {
+ "BaseUrl": "http://localhost:4566"
}
}
diff --git a/src/_doc_BackendDevelopment.md b/src/_doc_BackendDevelopment.md
index 867b0807..e3bb6090 100644
--- a/src/_doc_BackendDevelopment.md
+++ b/src/_doc_BackendDevelopment.md
@@ -1,18 +1,38 @@
# Backend Development Guide
-> **Status:** Stub — to be populated during Task 5 ([ADR-187](https://jodasoft.atlassian.net/browse/ADR-187))
->
-> See `src/_spec_LayoutCustomizationService.md` Task 5 for the full exit criteria.
+This document defines the standing development pattern for backend services introduced by
+Task 5 ([ADR-187](https://jodasoft.atlassian.net/browse/ADR-187)).
-## Agent Verification Step
+## ECS/Fargate-style API services
-After every change to a backend service, verify the development environment still works:
+All backend API services must follow this local development pattern:
-1. **With LocalStack running:** `dotnet run` (or F5 in VS) → confirm the service starts cleanly, log output appears in a console window, and `/scalar` is reachable in a browser
-2. **With LocalStack stopped:** `dotnet run` → confirm the process exits with a non-zero code and the console names LocalStack as the missing dependency with a reference to `docs/local-dev.md`
+1. Register OpenAPI and map Scalar UI only in development (`/scalar`).
+2. Include a `Development` launch profile with `"outputCapture": "None"` so F5 opens a
+ separate console window in Visual Studio.
+3. On startup (development), check `/_localstack/health` on the configured LocalStack base URL.
+ If unavailable or not `running`, log an error that names LocalStack and references
+ `docs/local-dev.md`, then exit non-zero immediately.
-For Lambda functions:
-1. Confirm F5 in VS opens the Lambda Test Tool UI
-2. Confirm `aws lambda invoke --endpoint-url http://localhost:4566` returns a valid response
+## Lambda services
-> This section will be expanded with full setup details and patterns once Task 5 is implemented.
+All backend Lambda projects must include:
+
+1. A launch profile that starts the Lambda Test Tool for interactive local debugging.
+2. LocalStack deployment support through `docker-compose`.
+3. Documented `aws lambda invoke --endpoint-url http://localhost:4566` sample commands.
+
+## Agent Verification Step (required after backend changes)
+
+After every backend service change:
+
+1. **With LocalStack running:** run the service and confirm clean startup plus `/scalar` availability.
+2. **With LocalStack stopped:** run the service and confirm non-zero exit with the LocalStack
+ dependency error message that includes `docs/local-dev.md`.
+
+For Lambda services:
+
+1. Confirm the Lambda Test Tool profile launches successfully.
+2. Confirm `aws lambda invoke --endpoint-url http://localhost:4566` returns a valid response.
+
+See `docs/local-dev.md` for setup and invocation details.
diff --git a/test/AdaptiveRemote.Backend.ApiTests/Support/ServiceFixture.cs b/test/AdaptiveRemote.Backend.ApiTests/Support/ServiceFixture.cs
index 25b9f59b..959e73e6 100644
--- a/test/AdaptiveRemote.Backend.ApiTests/Support/ServiceFixture.cs
+++ b/test/AdaptiveRemote.Backend.ApiTests/Support/ServiceFixture.cs
@@ -86,6 +86,8 @@ public async Task StartServiceAsync()
["ASPNETCORE_URLS"] = ServiceUrl,
// Point the service at the local test JWT authority.
["Cognito__Authority"] = _jwtAuthority.Authority,
+ // Use the same local test authority host for LocalStack health checks.
+ ["LocalStack__BaseUrl"] = _jwtAuthority.Authority,
}
};
@@ -148,7 +150,7 @@ public async Task StartServiceAsync()
{
lock (_logLock)
{
- _logOutput.AppendLine($"[HealthCheck attempt {i + 1}] Exception polling {ServiceUrl}/health: {ex.GetType().Name}: {ex.Message}");
+ _logOutput.AppendLine($"[HealthCheck attempt {i + 1}] Request failed polling {ServiceUrl}/health: {ex.Message}");
}
}
diff --git a/test/AdaptiveRemote.Backend.ApiTests/Support/TestJwtAuthority.cs b/test/AdaptiveRemote.Backend.ApiTests/Support/TestJwtAuthority.cs
index 226f948a..dcba9a7c 100644
--- a/test/AdaptiveRemote.Backend.ApiTests/Support/TestJwtAuthority.cs
+++ b/test/AdaptiveRemote.Backend.ApiTests/Support/TestJwtAuthority.cs
@@ -11,9 +11,10 @@ namespace AdaptiveRemote.Backend.ApiTests.Support;
/// A minimal local OIDC/JWKS authority used by API integration tests to issue and
/// validate JWTs without a real Cognito user pool.
///
-/// Exposes two endpoints on a dynamically-assigned localhost port:
+/// Exposes three endpoints on a dynamically-assigned localhost port:
/// GET /.well-known/openid-configuration — OIDC discovery document
/// GET /.well-known/jwks.json — RSA public key in JWK format
+/// GET /_localstack/health — LocalStack-compatible health response
///
/// The service under test is configured to use this authority via the
/// Cognito__Authority environment variable so that bearer token validation
@@ -118,6 +119,7 @@ private void HandleRequest(HttpListenerContext context)
{
"/.well-known/openid-configuration" => BuildDiscoveryDocument(),
"/.well-known/jwks.json" => BuildJwks(),
+ "/_localstack/health" => BuildLocalStackHealth(),
_ => BuildNotFound(context),
};
@@ -168,6 +170,15 @@ private static byte[] BuildNotFound(HttpListenerContext context)
return System.Text.Encoding.UTF8.GetBytes("{}");
}
+ private static byte[] BuildLocalStackHealth()
+ {
+ string json = JsonSerializer.Serialize(new
+ {
+ status = "running",
+ });
+ return System.Text.Encoding.UTF8.GetBytes(json);
+ }
+
private static int GetFreePort()
{
using System.Net.Sockets.TcpListener listener = new(IPAddress.Loopback, 0);
diff --git a/test/AdaptiveRemote.EndToEndTests.Host.Wpf/AdaptiveRemote.EndToEndTests.Host.Wpf.csproj b/test/AdaptiveRemote.EndToEndTests.Host.Wpf/AdaptiveRemote.EndToEndTests.Host.Wpf.csproj
index 808f3c5d..f80a6b55 100644
--- a/test/AdaptiveRemote.EndToEndTests.Host.Wpf/AdaptiveRemote.EndToEndTests.Host.Wpf.csproj
+++ b/test/AdaptiveRemote.EndToEndTests.Host.Wpf/AdaptiveRemote.EndToEndTests.Host.Wpf.csproj
@@ -6,6 +6,7 @@
enable
enable
Exe
+ true
diff --git a/test/AdaptiveRemote.EndtoEndTests.Host.Console/AdaptiveRemote.EndToEndTests.Host.Console.csproj b/test/AdaptiveRemote.EndtoEndTests.Host.Console/AdaptiveRemote.EndToEndTests.Host.Console.csproj
index b7ccd9b2..6e2f5b6e 100644
--- a/test/AdaptiveRemote.EndtoEndTests.Host.Console/AdaptiveRemote.EndToEndTests.Host.Console.csproj
+++ b/test/AdaptiveRemote.EndtoEndTests.Host.Console/AdaptiveRemote.EndToEndTests.Host.Console.csproj
@@ -6,6 +6,7 @@
enable
enable
Exe
+ true