From 1f52d67300ea901b32bceab6f01b4fa15db31619 Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Tue, 24 Mar 2026 19:48:42 -0400 Subject: [PATCH 1/2] MEIER-354: Add Serilog with OpenTelemetry sink and harden WAF rules --- pulumi/src/cloudflare/waf.ts | 75 +++++++++-------- pulumi/src/config.ts | 6 ++ pulumi/src/k8s/deployment.ts | 3 +- sln/paket.dependencies | 4 + sln/paket.lock | 146 +++++++++++++++++++++++++++++++--- sln/src/Docs/Config.fs | 31 ++++++-- sln/src/Docs/Program.fs | 62 ++++++++++++--- sln/src/Docs/paket.references | 4 + 8 files changed, 269 insertions(+), 62 deletions(-) diff --git a/pulumi/src/cloudflare/waf.ts b/pulumi/src/cloudflare/waf.ts index 48d503c..9ad4fb9 100644 --- a/pulumi/src/cloudflare/waf.ts +++ b/pulumi/src/cloudflare/waf.ts @@ -3,48 +3,59 @@ import { provider } from './provider' import * as config from '../config' import { zone } from './zone' +// Use lower(url_decode()) to normalize both case and percent-encoding. +// Scanners use mixed case (e.g. /ReAcT/.EnV) and URL encoding (e.g. %2F) +// to bypass WAF rules. Cloudflare does NOT decode reserved chars like %2F +// during standard normalization, so url_decode() is required. +const p = 'lower(url_decode(http.request.uri.path))' + const expression = [ // Sensitive dotfiles and directories - '(http.request.uri.path contains "/.env")', - '(http.request.uri.path contains "/.git")', - '(http.request.uri.path contains "/.aws")', - '(http.request.uri.path contains "/.ssh")', - '(http.request.uri.path contains "/.terraform")', + `(${p} contains "/.env")`, + `(${p} contains "/.git")`, + `(${p} contains "/.aws")`, + `(${p} contains "/.ssh")`, + `(${p} contains "/.terraform")`, // CMS and framework probes - '(http.request.uri.path contains "/wp-")', - '(http.request.uri.path contains "/wordpress")', - '(http.request.uri.path contains "/xmlrpc")', - '(http.request.uri.path contains "/phpMyAdmin")', - '(http.request.uri.path contains "/phpmyadmin")', - '(http.request.uri.path contains "/pma")', + `(${p} contains "/wp-")`, + `(${p} contains "/wordpress")`, + `(${p} contains "/xmlrpc")`, + `(${p} contains "/phpmyadmin")`, + `(${p} contains "/pma")`, // Admin and server management - '(http.request.uri.path contains "/admin")', - '(http.request.uri.path contains "/cgi-bin")', - '(http.request.uri.path contains "/actuator")', - '(http.request.uri.path contains "/solr")', - '(http.request.uri.path contains "/telescope")', - '(http.request.uri.path contains "/vendor")', - '(http.request.uri.path contains "/invoker")', - '(http.request.uri.path contains "/balancer-manager")', + `(${p} contains "/admin")`, + `(${p} contains "/cgi-bin")`, + `(${p} contains "/actuator")`, + `(${p} contains "/solr")`, + `(${p} contains "/telescope")`, + `(${p} contains "/vendor")`, + `(${p} contains "/invoker")`, + `(${p} contains "/balancer-manager")`, + `(${p} contains "/login")`, // Credential and config probes - '(http.request.uri.path contains "/credentials")', - '(http.request.uri.path contains "/known_hosts")', - '(http.request.uri.path contains "sendgrid")', - '(http.request.uri.path contains "codecommit")', - '(http.request.uri.path contains "/env.cfg")', + `(${p} contains "/credentials")`, + `(${p} contains "/known_hosts")`, + `(${p} contains "sendgrid")`, + `(${p} contains "codecommit")`, + `(${p} contains "/env.cfg")`, + `(${p} contains "/api/config")`, + `(${p} contains "/careers_not_hosted")`, // Dangerous file extensions - '(http.request.uri.path contains ".php")', - '(http.request.uri.path contains ".asp")', - '(http.request.uri.path contains ".jsp")', - '(http.request.uri.path contains ".cgi")', - '(http.request.uri.path contains ".yml")', - '(http.request.uri.path contains ".xml")', - '(http.request.uri.path contains ".bak")', - '(http.request.uri.path contains ".rb")', + `(${p} contains ".php")`, + `(${p} contains ".asp")`, + `(${p} contains ".jsp")`, + `(${p} contains ".cgi")`, + `(${p} contains ".yml")`, + `(${p} contains ".xml")`, + `(${p} contains ".bak")`, + `(${p} contains ".rb")`, + + // Env file variants (with dots in name like .env.sample, .env.prod) + `(${p} contains ".env.")`, ].join(' or ') new cloudflare.Ruleset(`${config.identifier}-waf`, { diff --git a/pulumi/src/config.ts b/pulumi/src/config.ts index 918feb0..136bae0 100644 --- a/pulumi/src/config.ts +++ b/pulumi/src/config.ts @@ -26,3 +26,9 @@ const rawK8sConfig = new pulumi.Config('k8s') export const k8sConfig = { namespace: rawK8sConfig.require('namespace'), } + +const rawSeqConfig = new pulumi.Config('seq') + +export const seqConfig = { + endpoint: rawSeqConfig.require('endpoint'), +} diff --git a/pulumi/src/k8s/deployment.ts b/pulumi/src/k8s/deployment.ts index 3d90787..6765d9b 100644 --- a/pulumi/src/k8s/deployment.ts +++ b/pulumi/src/k8s/deployment.ts @@ -11,7 +11,8 @@ let appConfigMap = new k8s.core.v1.ConfigMap(config.identifier, { }, immutable: true, data: { - SERVER_URL: 'http://0.0.0.0:5000' + SERVER_URL: 'http://0.0.0.0:5000', + SEQ_ENDPOINT: config.seqConfig.endpoint, } }, { provider }) diff --git a/sln/paket.dependencies b/sln/paket.dependencies index 7fe6d97..7f39ae1 100644 --- a/sln/paket.dependencies +++ b/sln/paket.dependencies @@ -11,3 +11,7 @@ nuget FSharp.Core nuget Giraffe.ViewEngine nuget Feliz.ViewEngine nuget Oxpecker.ViewEngine +nuget Serilog +nuget Serilog.AspNetCore +nuget Serilog.Sinks.Console +nuget Serilog.Sinks.OpenTelemetry diff --git a/sln/paket.lock b/sln/paket.lock index d8bbd0e..03f63e7 100644 --- a/sln/paket.lock +++ b/sln/paket.lock @@ -81,12 +81,40 @@ NUGET System.Text.Json (>= 8.0.6) - restriction: >= net6.0 Giraffe.ViewEngine (1.4) FSharp.Core (>= 5.0) - restriction: >= netstandard2.0 + Google.Protobuf (3.34.1) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + System.Memory (>= 4.5.3) - restriction: || (>= net45) (&& (< net5.0) (>= netstandard2.0)) (&& (>= netstandard1.1) (< netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 4.5.2) - restriction: && (< net45) (< net5.0) (>= netstandard2.0) + Grpc.Core.Api (2.76) - restriction: || (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + System.Memory (>= 4.5.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Grpc.Net.Client (2.76) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Grpc.Net.Common (>= 2.76) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Logging.Abstractions (>= 8.0) - restriction: || (>= net462) (>= netstandard2.0) + System.Diagnostics.DiagnosticSource (>= 6.0.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Net.Http.WinHttpHandler (>= 8.0.3) - restriction: >= net462 + Grpc.Net.Common (2.76) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Grpc.Core.Api (>= 2.76) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 8.0) - restriction: && (>= netstandard2.0) (< netstandard2.1) Iced (1.21) - restriction: >= netstandard2.0 JetBrains.Annotations (2025.2.4) System.Runtime (>= 4.1) - restriction: && (< net20) (>= netstandard1.0) (< netstandard2.0) Markdig (0.44) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) - Microsoft.Bcl.AsyncInterfaces (10.0.2) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net6.0) (< net8.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.AspNetCore.Hosting.Abstractions (2.3.9) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.AspNetCore.Hosting.Server.Abstractions (>= 2.3) - restriction: >= netstandard2.0 + Microsoft.AspNetCore.Http.Abstractions (>= 2.3) - restriction: >= netstandard2.0 + Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1) - restriction: >= netstandard2.0 + Microsoft.AspNetCore.Hosting.Server.Abstractions (2.3.9) - restriction: || (&& (>= net462) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.AspNetCore.Http.Features (>= 2.3) - restriction: >= netstandard2.0 + Microsoft.Extensions.Configuration.Abstractions (>= 8.0) - restriction: >= netstandard2.0 + Microsoft.AspNetCore.Http.Abstractions (2.3.9) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.AspNetCore.Http.Features (>= 2.3) - restriction: >= netstandard2.0 + System.Text.Encodings.Web (>= 8.0) - restriction: >= netstandard2.0 + Microsoft.AspNetCore.Http.Features (5.0.17) - restriction: || (&& (>= net462) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.Primitives (>= 5.0.1) - restriction: || (>= net461) (>= netstandard2.0) + System.IO.Pipelines (>= 5.0.2) - restriction: || (>= net461) (>= netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (10.0.5) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net471) (&& (>= net6.0) (< net8.0)) (&& (>= net6.0) (< netstandard2.1)) (&& (< net8.0) (>= netstandard2.0)) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Bcl.HashCode (6.0) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (< netstandard2.0)) (>= net471) Microsoft.CodeAnalysis.Analyzers (3.11) - restriction: >= netstandard2.0 Microsoft.CodeAnalysis.Common (5.0) - restriction: >= netstandard2.0 Microsoft.CodeAnalysis.Analyzers (>= 3.11) - restriction: >= netstandard2.0 @@ -127,15 +155,64 @@ NUGET System.Text.Json (>= 9.0.8) - restriction: >= netstandard2.0 Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: >= netstandard2.0 System.Runtime.InteropServices.RuntimeInformation (>= 4.0) - restriction: || (>= net45) (&& (>= netstandard1.3) (< netstandard2.0)) - Microsoft.Extensions.DependencyInjection.Abstractions (10.0.2) - restriction: >= netstandard2.0 + Microsoft.Extensions.Configuration (10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Configuration.Abstractions (>= 10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Primitives (>= 10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Configuration.Abstractions (10.0.5) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (>= netstandard2.0) + Microsoft.Extensions.Primitives (>= 10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + System.ValueTuple (>= 4.6.1) - restriction: >= net462 + Microsoft.Extensions.Configuration.Binder (10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Configuration (>= 10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Configuration.Abstractions (>= 10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.DependencyInjection (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.DependencyInjection.Abstractions (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.DependencyModel (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Text.Encodings.Web (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Text.Json (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + Microsoft.Extensions.Diagnostics.Abstractions (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Options (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Diagnostics.DiagnosticSource (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + Microsoft.Extensions.FileProviders.Abstractions (10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Primitives (>= 10.0.5) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Hosting.Abstractions (10.0.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (>= netstandard2.0) Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.Configuration.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Diagnostics.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.FileProviders.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Logging.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) - Microsoft.Extensions.Logging.Abstractions (10.0.2) - restriction: >= netstandard2.0 + Microsoft.Extensions.Logging (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Extensions.DependencyInjection (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Logging.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Options (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + System.Diagnostics.DiagnosticSource (>= 10.0.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + System.ValueTuple (>= 4.6.1) - restriction: >= net462 + Microsoft.Extensions.Logging.Abstractions (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Diagnostics.DiagnosticSource (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) Microsoft.Extensions.ObjectPool (10.0.2) - restriction: >= net10.0 + Microsoft.Extensions.Options (10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Primitives (>= 10.0.2) - restriction: || (>= net462) (>= netstandard2.0) + System.ComponentModel.Annotations (>= 5.0) - restriction: || (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net8.0) (>= netstandard2.1)) + System.ValueTuple (>= 4.6.1) - restriction: >= net462 + Microsoft.Extensions.Primitives (10.0.5) - restriction: || (&& (>= net461) (>= netstandard2.1)) (>= net462) (&& (< net8.0) (>= netstandard2.1)) (>= netstandard2.0) + System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) Microsoft.IO.RecyclableMemoryStream (3.0.1) - restriction: >= net6.0 Microsoft.NETCore.Platforms (7.0.4) - restriction: || (&& (>= monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (>= monoandroid) (>= netcoreapp2.1) (< netstandard1.3)) (&& (< monoandroid) (< net20) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net20) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net20) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (< monotouch) (< net20) (>= netstandard1.5) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinios)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinmac)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarintvos)) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (>= xamarinwatchos)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (< netcoreapp2.0) (>= netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) (&& (>= netcoreapp2.1) (>= uap10.1)) Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (< net20) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net20) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net20) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net20) (>= netstandard1.5) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) @@ -150,24 +227,68 @@ NUGET Microsoft.Extensions.ObjectPool (>= 10.0) - restriction: >= net10.0 Perfolizer (0.3.17) - restriction: >= netstandard2.0 System.Memory (>= 4.5.5) - restriction: && (>= netstandard2.0) (< netstandard2.1) + Serilog (4.3.1) + System.Diagnostics.DiagnosticSource (>= 8.0.1) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (< net6.0) (>= netstandard2.0)) (>= net471) + System.Threading.Channels (>= 8.0) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (< net6.0) (>= netstandard2.0)) (>= net471) + System.ValueTuple (>= 4.5) - restriction: && (>= net462) (< netstandard2.0) + Serilog.AspNetCore (10.0) + Microsoft.AspNetCore.Hosting.Abstractions (>= 2.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + Microsoft.AspNetCore.Http.Abstractions (>= 2.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) + Serilog (>= 4.3) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Extensions.Hosting (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Formatting.Compact (>= 3.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Settings.Configuration (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Sinks.Console (>= 6.1.1) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Sinks.Debug (>= 3.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Sinks.File (>= 7.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Extensions.Hosting (10.0) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Hosting.Abstractions (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Logging.Abstractions (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog (>= 4.3) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Extensions.Logging (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Extensions.Logging (10.0) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Logging (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog (>= 4.2) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Formatting.Compact (3.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog (>= 4.0) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Serilog.Settings.Configuration (10.0) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.Configuration.Binder (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Microsoft.Extensions.DependencyModel (>= 10.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog (>= 4.3) - restriction: || (>= net462) (>= netstandard2.0) + Serilog.Sinks.Console (6.1.1) + Serilog (>= 4.0) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Serilog.Sinks.Debug (3.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog (>= 4.0) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Serilog.Sinks.File (7.0) - restriction: || (>= net462) (>= netstandard2.0) + Serilog (>= 4.2) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Serilog.Sinks.OpenTelemetry (4.2) + Google.Protobuf (>= 3.30.1) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Grpc.Net.Client (>= 2.70) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) + Serilog (>= 4.2) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0)) (>= net471) (>= net6.0) System.Buffers (4.6.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= net462) (&& (>= net6.0) (< net8.0)) (&& (< net6.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net6.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (< net8.0) (>= netstandard2.0)) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.CodeDom (10.0.2) - restriction: >= netstandard2.0 System.Collections.Immutable (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net8.0) (< net9.0)) (>= netstandard2.0) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) - System.Diagnostics.DiagnosticSource (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) + System.ComponentModel.Annotations (5.0) - restriction: || (&& (>= net462) (>= netstandard2.1)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (&& (< net8.0) (>= netstandard2.1)) + System.Diagnostics.DiagnosticSource (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net6.0) (< net8.0)) (&& (>= net6.0) (< netstandard2.1)) (&& (< net6.0) (>= netstandard2.0)) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) - System.IO.Pipelines (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= net6.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) + System.IO.Pipelines (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net461) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.1)) (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Management (10.0.2) - restriction: >= netstandard2.0 System.CodeDom (>= 10.0.2) - restriction: >= netstandard2.0 - System.Memory (4.6.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net462) (&& (>= net6.0) (< net8.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Memory (4.6.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net45) (>= net6.0)) (&& (>= net45) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net462) (&& (< net5.0) (>= net6.0)) (&& (< net5.0) (>= netstandard2.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net6.0) (< netstandard2.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) (&& (>= netstandard2.0) (>= uap10.1)) System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.Numerics.Vectors (>= 4.6.1) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + System.Net.Http.WinHttpHandler (10.0.5) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (< netstandard2.0)) (>= net471) + Microsoft.Bcl.HashCode (>= 6.0) - restriction: >= net462 + System.Buffers (>= 4.6.1) - restriction: >= net462 + System.Memory (>= 4.6.3) - restriction: >= net462 System.Numerics.Vectors (4.6.1) - restriction: || (>= net462) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) System.Reactive (6.1) - restriction: >= netstandard2.0 System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< net6.0) (>= netstandard2.0)) (>= uap10.1) @@ -182,7 +303,7 @@ NUGET System.Runtime (4.3.1) - restriction: && (< net20) (>= netstandard1.0) (< netstandard2.0) Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) - System.Runtime.CompilerServices.Unsafe (6.1.2) - restriction: || (>= net462) (&& (>= net6.0) (< net8.0)) (>= netstandard2.0) + System.Runtime.CompilerServices.Unsafe (6.1.2) - restriction: || (&& (< net45) (>= net471)) (>= net462) (&& (< net5.0) (>= net6.0)) (&& (>= net6.0) (< net8.0)) (>= netstandard2.0) System.Runtime.InteropServices.RuntimeInformation (4.3) - restriction: && (>= net45) (>= netstandard2.0) System.Security.AccessControl (6.0.1) - restriction: || (&& (>= monoandroid) (< netstandard1.3) (>= netstandard2.0)) (&& (< monoandroid) (< net6.0) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (&& (< net6.0) (>= netcoreapp2.1)) (&& (< net6.0) (>= netstandard2.0) (>= xamarintvos)) (&& (< net6.0) (>= netstandard2.0) (>= xamarinwatchos)) (&& (< net6.0) (>= xamarinios)) (&& (< net6.0) (>= xamarinmac)) (&& (>= netstandard2.0) (>= uap10.1)) System.Security.Principal.Windows (>= 5.0) - restriction: || (>= net461) (&& (< net6.0) (>= netstandard2.0)) @@ -192,11 +313,11 @@ NUGET System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.ValueTuple (>= 4.6.1) - restriction: >= net462 - System.Text.Encodings.Web (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (&& (>= net462) (>= net6.0)) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) + System.Text.Encodings.Web (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net6.0) (< net8.0)) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.1)) (&& (>= netstandard2.0) (< netstandard2.1)) System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Memory (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) - System.Text.Json (10.0.2) - restriction: >= netstandard2.0 + System.Text.Json (10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (>= netstandard2.0) Microsoft.Bcl.AsyncInterfaces (>= 10.0.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Buffers (>= 4.6.1) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.IO.Pipelines (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) @@ -204,6 +325,9 @@ NUGET System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) System.Text.Encodings.Web (>= 10.0.2) - restriction: || (&& (< net10.0) (>= net9.0)) (>= net462) (&& (>= net8.0) (< net9.0)) (&& (< net8.0) (>= netstandard2.0)) System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (< net8.0) (>= netstandard2.0)) - System.Threading.Tasks.Extensions (4.6.3) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (>= netstandard2.0)) (&& (>= net6.0) (< net8.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Threading.Channels (10.0.5) - restriction: || (&& (>= net462) (< netstandard2.0)) (&& (< net462) (< net6.0) (>= netstandard2.0)) (>= net471) + Microsoft.Bcl.AsyncInterfaces (>= 10.0.5) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Threading.Tasks.Extensions (>= 4.6.3) - restriction: || (>= net462) (&& (>= netstandard2.0) (< netstandard2.1)) + System.Threading.Tasks.Extensions (4.6.3) - restriction: || (&& (>= net462) (>= net6.0)) (&& (>= net462) (< netstandard2.0)) (&& (< net462) (>= netstandard2.0) (< netstandard2.1)) (>= net471) (&& (>= net6.0) (< net8.0)) (&& (< net6.0) (>= netstandard2.0)) (&& (< net8.0) (>= netstandard2.0)) System.Runtime.CompilerServices.Unsafe (>= 6.1.2) - restriction: || (>= net462) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) - System.ValueTuple (4.6.1) - restriction: && (>= net462) (>= netstandard2.0) + System.ValueTuple (4.6.1) - restriction: >= net462 diff --git a/sln/src/Docs/Config.fs b/sln/src/Docs/Config.fs index 828c661..d64009c 100644 --- a/sln/src/Docs/Config.fs +++ b/sln/src/Docs/Config.fs @@ -2,12 +2,33 @@ namespace Docs open System +module Env = + let variable (key: string) = + match Environment.GetEnvironmentVariable(key) with + | value when String.IsNullOrEmpty(value) -> failwith $"Environment variable '{key}' is required" + | value -> value + + let variableOrDefault (key: string) (defaultValue: string) = + match Environment.GetEnvironmentVariable(key) with + | value when String.IsNullOrEmpty(value) -> defaultValue + | value -> value + +type SeqConfig = + { endpoint: string } + +module SeqConfig = + let load () = + { endpoint = Env.variableOrDefault "SEQ_ENDPOINT" "http://localhost:5341" } + type Config = - { serverUrl: string } + { debug: bool + appName: string + serverUrl: string + seq: SeqConfig } module Config = let load () = - { serverUrl = - Environment.GetEnvironmentVariable("SERVER_URL") - |> Option.ofObj - |> Option.defaultValue "https://localhost:5000" } + { debug = Env.variableOrDefault "DEBUG" "false" |> Boolean.Parse + appName = "fsharp-viewengine-docs" + serverUrl = Env.variableOrDefault "SERVER_URL" "https://localhost:5000" + seq = SeqConfig.load () } diff --git a/sln/src/Docs/Program.fs b/sln/src/Docs/Program.fs index 6aaa010..a9469b4 100644 --- a/sln/src/Docs/Program.fs +++ b/sln/src/Docs/Program.fs @@ -2,6 +2,9 @@ open Microsoft.AspNetCore.Builder open Microsoft.Extensions.Hosting open Microsoft.Extensions.DependencyInjection open Giraffe +open Serilog +open Serilog.Events +open Serilog.Sinks.OpenTelemetry open Docs.Handlers let webApp = @@ -21,27 +24,60 @@ let webApp = ] ] +let configureLogger (config: Docs.Config) = + let initialLogLevel = + if config.debug then LogEventLevel.Debug + else LogEventLevel.Information + + let logger = + LoggerConfiguration() + .MinimumLevel.Is(initialLogLevel) + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning) + .WriteTo.Console() + .WriteTo.OpenTelemetry(fun opts -> + opts.Endpoint <- config.seq.endpoint + "/ingest/otlp/v1/logs" + opts.Protocol <- OtlpProtocol.HttpProtobuf + opts.ResourceAttributes <- dict [ "service.name", box config.appName ]) + .CreateLogger() + + Log.Logger <- logger + let configureApp (app : IApplicationBuilder) = - app.UseStaticFiles() |> ignore + app + .UseSerilogRequestLogging(fun opts -> + opts.GetLevel <- fun ctx _ _ -> + if ctx.Request.Path.Value = "/health" then LogEventLevel.Verbose + else LogEventLevel.Information) + .UseStaticFiles() |> ignore app.UseGiraffe(webApp) let configureServices (services : IServiceCollection) = - services.AddGiraffe() |> ignore + services + .AddSerilog() + .AddGiraffe() |> ignore [] -let main args = - let builder = WebApplication.CreateBuilder(args) - configureServices builder.Services - - let app = builder.Build() +let main _args = + let config = Docs.Config.load() + configureLogger config - if app.Environment.IsDevelopment() then - app.UseDeveloperExceptionPage() |> ignore + try + try + let builder = WebApplication.CreateBuilder() + configureServices builder.Services - configureApp app + let app = builder.Build() - let config = Docs.Config.load() - app.Run(config.serverUrl) + if app.Environment.IsDevelopment() then + app.UseDeveloperExceptionPage() |> ignore - 0 // Exit code + configureApp app + Log.Information("Starting {AppName}", config.appName) + app.Run(config.serverUrl) + 0 + with ex -> + Log.Fatal(ex, "Application start-up failed") + 1 + finally + Log.CloseAndFlush() diff --git a/sln/src/Docs/paket.references b/sln/src/Docs/paket.references index 94e7207..52d67b0 100644 --- a/sln/src/Docs/paket.references +++ b/sln/src/Docs/paket.references @@ -1,2 +1,6 @@ Giraffe Markdig +Serilog +Serilog.AspNetCore +Serilog.Sinks.Console +Serilog.Sinks.OpenTelemetry From 39abe00c20362a72432faf70598a452e398a7593 Mon Sep 17 00:00:00 2001 From: Andrew Meier Date: Wed, 25 Mar 2026 04:58:29 -0400 Subject: [PATCH 2/2] MEIER-354: Fix tunnel config to target port 5000 --- pulumi/src/cloudflare/tunnel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pulumi/src/cloudflare/tunnel.ts b/pulumi/src/cloudflare/tunnel.ts index f8c418b..9e905a2 100644 --- a/pulumi/src/cloudflare/tunnel.ts +++ b/pulumi/src/cloudflare/tunnel.ts @@ -16,7 +16,7 @@ new cloudflare.ZeroTrustTunnelCloudflaredConfig(config.identifier, { ingresses: [ { hostname: `${config.identifier}.${config.cloudflareConfig.zoneName}`, - service: 'http://localhost:80' + service: 'http://localhost:5000' }, { service: 'http_status:404'