Warp is a service where you can share short-lived texts and media with your friends and colleagues and be sure the data will be removed whenever you expect. The solution based on Asp.Net Core service and backed with KeyDB as a storage for sensitive user data.
To run the service you have to pass the following environment variables:
| Variable | Type | Notes | Description |
|---|---|---|---|
| PNKL_VAULT_ADDR | String | An address of a Vault instance | |
| PNKL_VAULT_TOKEN | String | An access token of a Vault instance | |
| DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS | Boolean | Local env only | Dsiables the telemetry dashboard login |
Run the compose file inside the root directory. It sets up external dependencies like a database etc.
The compose stack now ships with a HashiCorp Vault dev server that mirrors the production contract (secrets/warp). Start the supporting containers before running the web app:
# Run the base compose and the e2e override so Vault containers are available for local e2e work
docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d keydb vault aspire-dashboard vault-initDuring boot the Vault container enables a KV v2 engine at secrets/ and seeds consul-address, consul-token, and s3-secret-access-key placeholders under secrets/warp. Override them at any time:
docker compose exec vault vault kv put secrets/warp consul-address=http://localhost:8500 consul-token=local-dev s3-secret-access-key=local-devConfigure the application to point at the local instance (PowerShell shown, use export on bash/zsh). Use the EndToEndTests ASP.NET Core environment to pick up the dedicated configuration while exercising the Vault-backed transit encryption path.
The bootstrap container also mints a scoped token with permissions for secrets/warp and the warp-end-to-end transit key. The token is saved to .vault/warp-e2e.token so you don't need to copy it from the container logs.
$env:PNKL_VAULT_ADDR = 'http://localhost:8200'
$env:PNKL_VAULT_TOKEN = (Get-Content -Path .vault/warp-e2e.token -Raw).Trim() # 'dev-root'
$env:ASPNETCORE_ENVIRONMENT = 'EndToEndTests'
$env:BASE_URL = 'https://localhost:8001'The End-to-End profile automatically reads
.vault/warp-e2e.token(viaPNKL_VAULT_TOKEN_FILE), so exportingPNKL_VAULT_TOKENis only necessary if you relocate or override the file.
You can inspect the seeded data with:
docker compose exec vault vault kv get secrets/warpNote: the dev server disables authentication and should never be exposed outside your workstation.
- Boot the supporting services (use the e2e override to start Vault):
# recommended - uses the e2e override so vault and vault-init only start when you include the file
docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d keydb vault aspire-dashboard vault-init
# Or use the convenience npm script from the repo root
npm run compose:e2e:up- Point the backend at the End-to-End configuration and local Vault instance (bash/zsh users can swap
$env:withexport):
$env:PNKL_VAULT_ADDR = 'http://localhost:8200'
$env:PNKL_VAULT_TOKEN = (Get-Content -Path .vault/warp-e2e.token -Raw).Trim()
$env:ASPNETCORE_ENVIRONMENT = 'EndToEndTests'
$env:BASE_URL = 'https://localhost:8001'You can skip
PNKL_VAULT_TOKENhere as well if you keep the generated token at.vault/warp-e2e.token.
- Run the web app on the port expected by the Playwright suite (and the warmup job):
dotnet run --project Warp.WebApp/Warp.WebApp.csproj --urls http://localhost:8080- With the server up, execute the SPA end-to-end tests by pointing Playwright at
http://localhost:8080(yarn playwright test --config e2e/playwright.config.ts).
The appsettings.EndToEndTests.json profile mirrors production defaults while substituting local dependencies (KeyDB, telemetry, and Vault transit key warp-end-to-end).
❗ You may use appSettings.Local.json for local runs.
Also you might need to override DB settings to run locally. Set up the Redis section of your appSettings.Local.json.
Warp includes a code generation system for managing logging events, domain errors, and messages. The generator creates consistent logging constants, enums, domain error factories, and helper methods based on a JSON configuration file.
The logging configuration is defined in Warp.WebApp/CodeGeneration/log-events.json. The configuration follows a hierarchical structure where logging events are organized by categories. Each logging event includes:
id- Unique numeric identifiername- Name of the logging eventdescription- Description template with optional parameters in format{ParameterName:Type}domainErrorDescription- Optional alternative description for domain error messageslogLevel- Severity level (Debug, Information, Warning, Error, Critical)generateLogMessage- Boolean flag to control whether a log method should be generatedobsolete- Boolean flag to mark deprecated log events that will be removed in future versionshttpCode- HTTP status code that generates a ProducesResponseType attribute
Example event:
{
"id": 12201,
"name": "ImageUploadError",
"description": "An error occurred while uploading the image. Details: '{ErrorMessage:string}'.",
"domainErrorDescription": "Failed to upload image: {ErrorMessage:string}",
"logLevel": "Error",
"generateLogMessage": true,
"obsolete": false,
"httpCode": 400
}The code generator produces:
LogEvents.cs- Enum definitions for all logging events with Description attributes and HTTP status code decorationsLogMessages.cs- Extension methods for ILogger with structured logging support using the [LoggerMessage] attribute patternDomainErrors.cs- Static methods to create strongly-typed DomainError instances with appropriate error codes and messages
When a log event is marked as obsolete: true, all related artifacts (enum value, log method, and domain error factory method) are decorated with the [Obsolete] attribute, generating compiler warnings when used.
When a log event includes an httpCode value, the enum will be decorated with [HttpStatusCode], which can be used for API documentation and response type specification.
The code generation system automatically extracts parameters from message templates using a regular expression pattern. Parameters are formatted as {ParameterName} or {ParameterName:Type} where:
ParameterNameis converted to camelCase for method parametersTypedefines the parameter type (defaults tostring?if not specified)
For example, a template like "User {UserId:Guid} uploaded {FileCount:int} files" generates parameters Guid userId, int fileCount.
Code generation runs automatically during the release build process through a target in the project file. You can also run it manually:
dotnet run --project Warp.CodeGen/Warp.CodeGen.csproj -- --json Warp.WebApp/CodeGeneration/log-events.json --constants Warp.WebApp/Constants/Logging/LogEvents.cs --messages Warp.WebApp/Telemetry/Logging/LogMessages.cs --domain-errors Warp.WebApp/Extensions/DomainErrors.csThe project uses a modern build process for its styles, leveraging both Sass and Tailwind CSS. All style assets are generated via a series of npm scripts defined in the package.json. Follow these steps to build the styles:
-
Install Node Modules
Make sure you have Node.js and Yarn installed. Then, from the root project folder, run:
yarn install
-
Build Styles
To compile all styles (both Sass and Tailwind), simply run:
yarn build
Warp uses AES-256 encryption for all data stored in KeyDB. The encryption key can be managed using the warp-keymanager tool.
Build and install the tool as a .NET global tool:
cd Warp.KeyManager
dotnet pack
dotnet tool install --global --add-source ./nupkg Warp.KeyManagerTo generate a new encryption key for local development:
# Generate and display a Base64 key
warp-keymanager generate --base64
# Generate and save a key to a file
warp-keymanager generate --base64 --output C:\ProgramData\Warp\encryption-key.txtUpdate your appsettings.json or appsettings.Local.json:
"EncryptionOptions": {
"KeyFilePath": "C:\\ProgramData\\Warp\\encryption-key.txt",
"TransitKeyName": "warp-key",
"Type": "AesEncryptionService"
}Alternatively, you can set an environment variable:
# Windows
set WARP_ENCRYPTION_KEY=your_base64_key_here
# Linux/macOS
export WARP_ENCRYPTION_KEY=your_base64_key_hereWarp offers a TransitEncryptionService which integrates with HashiCorp Vault's Transit secrets engine. To use it, set the following configuration:
"EncryptionOptions": {
"Type": "TransitEncryptionService",
"TransitKeyName": "warp-keydb"
}The EncryptionOptions:Type setting is mandatory and must be set to either AesEncryptionService or TransitEncryptionService to specify which encryption service implementation to use. The service implementation is selected at application startup based on this configuration value.
The project uses these icofont glyphs:
- align-left
- bin
- clock
- close
- copy
- exclamation-tringle
- eye
- hill-sunny
- link
- loop
- pencil-alt-2
- plus
- simple-left
- worried
Refer to docs/tracing.md for details on the end-to-end tracing pipeline, header propagation rules, and troubleshooting tips.