Conversation
Bumps caddy from `efb93f7` to `b6424b4`. --- updated-dependencies: - dependency-name: caddy dependency-version: '2' dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 5.0.1 to 5.1.0. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](actions/setup-dotnet@2016bd2...baa11fb) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-version: 5.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix Apple Music link parser to properly handle query parameters
…the queuing system for requests.
…umentation for Redis migration (#242)
…encies, and credential validation (#253)
- Run formatter, fix line endings and encodings
… and comprehensive tests (#254)
In-Progress merge to reduce the number of PRs see the fan out of PRs for more context. - Add initial ATProto user OAuth configuration - Add genre caching functionality - Overhaul ATProto process to add a unified session manager to vastly reduce the number of refreshSession and getSession calls we're making - Update package lock files for CI with linux-x64 runtime (#256) - Implement Initial ATProto OAuth token exchange with DPoP and fix base branch issues - Add genre caching for playlist organization (#258) - Fix additional bugs
…#259) * - Add initial ATProto user OAuth configuration - Add genre caching functionality * Overhaul ATProto process to add a unified session manager to vastly reduce the number of refreshSession and getSession calls we're making * Update package lock files for CI with linux-x64 runtime (#256) * Initial plan * Address non-resolved review comments: OAuth methods and Dockerfile improvements Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Move ATProtoOAuthResult to its own file in Records directory Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Implement full OAuth token exchange with DPoP support Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Improve redirect URI handling with constants and validation Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Address code review feedback: sealed modifier, error handling, and redirect URI fix Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Refactor: narrow try-catch scope and simplify JWT return Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Address review feedback: validation, error handling, and DPoP improvements Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Refine error handling and nbf timing for clock skew tolerance Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Clarify error messages for token response parsing Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Add comprehensive unit tests for ATProto OAuth service and DPoP JWT creation Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Fix HttpClient anti-pattern: use IHttpClientFactory instead of storing HttpClient Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Run formatter * Enhance error handling and JWK validation, reorganize utility methods Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * refactor: standardize logging with Serilog and consolidate cache layer - Migrate all workers to Serilog via ServiceDefaults - Remove MediaLinkCacheRepository, consolidate into RedisMediaLinkCache - Enhance SagaCoordinator with comprehensive logging and retry logic - Add integration tests for cache layer - Update documentation and deployment scripts * Add resilience configuration, documentation, and TODOs for OAuth improvements Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * 1. Increase maintainability index scores by a. Breaking out shared logic into the BridgeBeats.Worker.Common project b. reducing top-level namespaces and breaking code up into methods and classes. * Implement ATProto OAuth token exchange with DPoP and fix base branch issues (#257) * Move dependabot file back out of workflows. * [WIP] Add genre caching for playlist organization (#258) * Initial plan * Fix Dockerfile ARG, encrypt DPoP key storage, add OAuth cleanup service Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Replace silent OAuth session failure with explicit NotImplementedException Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Remove old unencrypted DPoP key property and add migration Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Run initial OAuth cleanup on startup and simplify exception message Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Fix Data Protection config and scoped service dependency in cleanup service Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Fix Data Protection wiring and update comments to reflect actual behavior Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Document plain text storage reality and security risks honestly Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Fix ASP0015 issues * - Resolve CA1041 issues - Fix tests - Run formatter - Prefer string.Empty to "" * - Resolve CA1822 issues * - Resolve CA1848 and add event Ids. - Resolve IDE0305 too because I forgot to hit commit before updating these. * Additional IDE recommended improvements. * Adjustments to address MSTEST0049 * Queues seem functional * Regenerate package lock files for linux-x64 runtime Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> --------- Co-authored-by: Taylor Marvin <taylor@marvin.email> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com>
…est forgery token validation Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…est forgery token validation Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…ry test helper, break up TestUtilities file into individual class files.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…Beats into refactor-develop
- services start up and stay running
…Beats into refactor-develop
wip oauth public -> confidential client update
…Beats into refactor-develop
…285) * Initial plan * Address review comments: fix path comment, secure Redis password, require persistent internal service key Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Improve Redis password handling: add error checking and prevent command injection Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Use head -n 1 to ensure only first line of password file is used Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Improve error handling and use safer awk print instead of printf Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Fix Redis config generation, healthcheck auth, signal handling, and secret newlines Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Add --no-auth-warning flag and clarify secret handling comment Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> * Use head -n 1 in healthcheck for consistency and security Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tsmarvin <57049894+tsmarvin@users.noreply.github.com> Co-authored-by: Taylor Marvin <Taylor@Marvin.Email>
There was a problem hiding this comment.
Pull request overview
Continues the refactor work from PR#274 by updating deployment/docs for the new worker/Redis-based architecture, modernizing container startup/build tooling, and expanding automated tests for newly introduced components.
Changes:
- Updated deployment/configuration docs for installation scripts, Redis, ATProto lexicons, and the Discord worker architecture.
- Refactored container build + entrypoint flow to publish multiple projects, run the AppHost, and add Redis to docker-compose.
- Added substantial unit/integration test coverage and new test infrastructure (shared Redis Testcontainer, antiforgery helpers, controller/service tests).
Reviewed changes
Copilot reviewed 75 out of 397 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/DISCORD_BOT.md | Documents Discord worker architecture separation/scaling concept. |
| docs/DEPLOYMENT.md | Adds install-script quick start and updates sharding/deployment guidance. |
| docs/CONFIGURATION.md | Documents Redis + Discord worker settings and updates appsettings examples. |
| docs/ATPROTO_LEXICON.md | Expands lexicon docs to include playlist lexicon and updated paths. |
| containers/setup-secrets.sh | Removes old secrets setup script in favor of new installation approach. |
| containers/entrypoint.sh | Refactors startup to generate appsettings, configure Aspire dashboard, Redis, and run AppHost. |
| containers/docker-compose.yml | Adds Redis service, new secret mounts, DP key persistence, and dependency wiring. |
| containers/Test-LockFileChanges.ps1 | New lock-file diff validator intended for cross-platform restore/publish consistency. |
| containers/Dockerfile.caddy | Updates pinned Caddy base image digests. |
| containers/Dockerfile | Reworks container build to publish all projects and include Aspire tools/dashboard. |
| containers/Caddyfile | Proxies Aspire Dashboard to in-container dashboard port rather than separate container. |
| containers/Build-Publish.ps1 | New publish orchestrator script to standardize output layout and lock regeneration. |
| containers/.env.example | Updates env example to remove SQLite cache config and document required secrets. |
| Tests/Unit/WellKnownControllerTests.cs | Adds unit tests for ATProto OAuth well-known endpoints. |
| Tests/Unit/StatisticsControllerTests.cs | Adds controller unit tests for stats rendering/refresh behavior. |
| Tests/Unit/SpotifyArtistGenreServiceTests.cs | Adds constructor validation tests for Spotify genre service. |
| Tests/Unit/RetryAfterExceededExceptionTests.cs | Adds tests for rate-limit exception behavior and provider detection. |
| Tests/Unit/RecordKeyGeneratorTests.cs | Updates tests to new namespaces and MSTest assertions, adds XML docs. |
| Tests/Unit/QrCodeServiceTests.cs | Adds unit tests for QR code data URI generation. |
| Tests/Unit/OpenGraphExtensionsTests.cs | Updates namespace and test naming for theme-color expectations. |
| Tests/Unit/OpenGraphCardServiceTests.cs | Updates namespace and expands card service constructor checks. |
| Tests/Unit/LookupStatisticsTests.cs | Adds DTO default/initializer behavior tests. |
| Tests/Unit/LoggingConfigurationTests.cs | Updates logging config tests to LogDirPath and adds documentation. |
| Tests/Unit/HashUtilityTests.cs | Adds tests for hashing utilities and URL normalization. |
| Tests/Unit/DataProtectionLookupProtectorTests.cs | Adds tests for DP-based lookup protection roundtrips and failure modes. |
| Tests/Unit/DataProtectionKeyRingTests.cs | Adds tests for DP key ring behavior. |
| Tests/Unit/ConnectionStringCompatibilityTests.cs | Removes tests tied to the removed SQLite link-cache connection string. |
| Tests/Unit/ConfigurationValidationTests.cs | Updates tests to reflect removed link-cache connection string usage. |
| Tests/Unit/CacheBootstrapBackgroundServiceTests.cs | Adds background service tests for ATProto→cache bootstrap logic. |
| Tests/Unit/AppleMusicLinkParserTests.cs | Adds coverage for Apple Music URL parsing edge cases. |
| Tests/Unit/AppleJwtHandlerTests.cs | Updates namespace and adds more documentation around JWT generation tests. |
| Tests/Unit/AppSettingsTests.cs | Updates binding tests for renamed logging setting and removed settings. |
| Tests/Unit/ATProtoSigningKeyProviderTests.cs | Adds extensive JWKS/JWK key provider tests. |
| Tests/TestUtilities.cs | Removes old custom factory utilities replaced by new infra. |
| Tests/TestConfiguration.cs | Adds shared config loader and helper for Aspire parameter args. |
| Tests/SharedTestInfrastructure.cs | Adds shared Redis Testcontainer lifecycle for integration tests. |
| Tests/RateLimitTestHelper.cs | Adds helper to mark tests inconclusive when rate limited. |
| Tests/Integration/RedisRequestDeduplicatorTests.cs | Adds Redis integration tests for request de-dup + pub/sub completion. |
| Tests/Integration/RedisRateLimitTrackerTests.cs | Adds Redis integration tests for rate limit state/TTL behavior. |
| Tests/Integration/QueueMetricsIntegrationTests.cs | Adds integration tests validating observable gauge metrics from Redis streams. |
| Tests/Integration/HealthEndpointAuthorizationTests.cs | Re-enables health endpoint checks and updates config overrides. |
| Tests/Integration/DashboardAuthorizationTests.cs | Re-enables dashboard auth tests with a test auth scheme/factory. |
| Tests/EndToEnd/OpenGraphCardControllerTests.cs | Updates E2E tests to direct-provider mode + improved rate-limit handling. |
| Tests/EndToEnd/MusicLookupControllerTests.cs | Uses antiforgery helper and adjusts multi-URL test expectations. |
| Tests/EndToEnd/HomeControllerTests.cs | Adds antiforgery handling for POST endpoints and expands docs. |
| Tests/CustomWebApplicationFactory.cs | New factory wiring Redis + direct-mode overrides for WebApplicationFactory tests. |
| Tests/BridgeBeats.Tests.csproj | Adds Testcontainers/Aspire testing deps, removes FluentAssertions, tightens build settings. |
| Tests/AntiforgeryTestHelper.cs | Adds helper for antiforgery token acquisition and POST wrapper. |
| .github/workflows/tests.yml | Switches restore workflow to RID-specific restore + lock validation script. |
| .github/workflows/publish-caddy-cloudflare.yml | Updates pinned docker/login-action version SHA. |
| .github/workflows/docs.yml | Updates setup-dotnet action SHA. |
| .github/workflows/docker-publish.yml | Updates pinned docker/login-action version SHA. |
| .editorconfig | Tightens analyzer severities and adds additional analyzer config. |
| RUN chown -R $APP_UID:$APP_UID /src && \ | ||
| chown -R $APP_UID:$APP_UID /app/ && \ | ||
| chown $APP_UID:$APP_UID /entrypoint.sh && \ | ||
| chmod +x /entrypoint.sh && \ | ||
| chmod +x /app/tools/dcp/dcp | ||
|
|
||
| USER $APP_UID |
There was a problem hiding this comment.
The Dockerfile uses $APP_UID for chown and USER selection, but this diff removed the earlier USER $APP_UID and does not define ARG/ENV APP_UID in the shown stages. If APP_UID is unset at build time, these lines can fail (or run as an empty user). Define APP_UID explicitly (e.g., ARG with a default + matching user creation) or switch to a known existing user.
| // Can calculate when to retry | ||
| DateTimeOffset now = DateTimeOffset.UtcNow; | ||
| DateTimeOffset suggestedRetryTime = now.Add(exception.RetryAfterValue); | ||
| Assert.IsGreaterThan(now, suggestedRetryTime); |
There was a problem hiding this comment.
The assertion is reversed: suggestedRetryTime should be later than now when retryAfterValue is positive. This test will fail as written; assert that suggestedRetryTime is greater than now.
| Assert.IsGreaterThan(now, suggestedRetryTime); | |
| Assert.IsGreaterThan(suggestedRetryTime, now); |
|
|
||
| # Logging configuration | ||
| LOG_FILE_PATH="${LOG_FILE_PATH:-/app/data/logs/bridgebeats-.log}" | ||
| LOG_DIR_PATH="${LOG_DIR_PATH:-/app/data/logs}" |
There was a problem hiding this comment.
The script defines LOG_DIR_PATH but always creates /app/data/logs instead of "$LOG_DIR_PATH". If LOG_DIR_PATH is overridden, the target directory may not exist and file logging can fail. Create the directory using the configured LOG_DIR_PATH.
| LOG_DIR_PATH="${LOG_DIR_PATH:-/app/data/logs}" | |
| LOG_DIR_PATH="${LOG_DIR_PATH:-/app/data/logs}" | |
| mkdir -p "$LOG_DIR_PATH" |
| @@ -151,17 +197,27 @@ BridgeBeats is stateless (except for the optional SQLite cache) and can be horiz | |||
|
|
|||
| ### Discord Bot Sharding | |||
|
|
|||
| For large Discord deployments, use the `NODE_NUMBER` environment variable: | |||
| The Discord integration runs as a separate worker service (`BridgeBeats.Worker.Discord`). For large Discord deployments, run multiple instances with different node numbers: | |||
There was a problem hiding this comment.
This section mixes BridgeBeats__NodeNumber (used in the example) with NODE_NUMBER (called out as the uniqueness requirement). Pick one configuration name and use it consistently throughout the sharding docs (including the unique-shard warning) to avoid misconfiguration.
| -e BridgeBeats__DiscordToken=your_token \ | ||
| -e BridgeBeats__NodeNumber=0 \ | ||
| -e BridgeBeats__BaseUrl=https://bridgebeats.link \ |
There was a problem hiding this comment.
This section mixes BridgeBeats__NodeNumber (used in the example) with NODE_NUMBER (called out as the uniqueness requirement). Pick one configuration name and use it consistently throughout the sharding docs (including the unique-shard warning) to avoid misconfiguration.
| ``` | ||
|
|
||
| Note: If you do not increment this integer you could have multiple instances replying to the same events. | ||
| **Important**: Each shard must have a unique `NODE_NUMBER`. Running multiple instances with the same node number will cause duplicate responses to the same messages. |
There was a problem hiding this comment.
This section mixes BridgeBeats__NodeNumber (used in the example) with NODE_NUMBER (called out as the uniqueness requirement). Pick one configuration name and use it consistently throughout the sharding docs (including the unique-shard warning) to avoid misconfiguration.
| **Important**: Each shard must have a unique `NODE_NUMBER`. Running multiple instances with the same node number will cause duplicate responses to the same messages. | |
| **Important**: Each shard must have a unique `BridgeBeats__NodeNumber`. Running multiple instances with the same node number will cause duplicate responses to the same messages. |
| $backup = Get-Content $BackupPath -Raw | ConvertFrom-Json -AsHashtable | ||
| $current = Get-Content $CurrentPath -Raw | ConvertFrom-Json -AsHashtable |
There was a problem hiding this comment.
Comparing ConvertTo-Json output from hashtables can be unstable because hashtable key enumeration order isn’t guaranteed, which can cause false positives when the underlying data is the same. A more robust approach is to compare specific fields (e.g., resolved/type/contentHash) or parse into ordered objects (avoid -AsHashtable) and canonicalize/sort keys before comparison.
| $backupJson = $backupDeps[$package] | ConvertTo-Json -Compress | ||
| $currentJson = $currentDeps[$package] | ConvertTo-Json -Compress | ||
|
|
||
| if ($backupJson -ne $currentJson) { |
There was a problem hiding this comment.
Comparing ConvertTo-Json output from hashtables can be unstable because hashtable key enumeration order isn’t guaranteed, which can cause false positives when the underlying data is the same. A more robust approach is to compare specific fields (e.g., resolved/type/contentHash) or parse into ordered objects (avoid -AsHashtable) and canonicalize/sort keys before comparison.
| RUN DOTNET_RID="linux-x64"; \ | ||
| if [ "$TARGETARCH" = "arm64" ]; then DOTNET_RID="linux-arm64"; fi; \ | ||
| pwsh /build/containers/Build-Publish.ps1 -Runtime $DOTNET_RID |
There was a problem hiding this comment.
The mcr.microsoft.com/dotnet/sdk base image typically doesn't include PowerShell (pwsh). This RUN pwsh ... step will fail during Docker build unless PowerShell is explicitly installed. Consider either installing PowerShell in the build stage (apt-get) or rewriting the publish pipeline in bash/dotnet so it runs without pwsh.
|
|
||
| // Assert | ||
| Assert.StartsWith( "data:image/png;base64,", result ); | ||
| Assert.IsGreaterThan( 100, result.Length, "Base64 PNG should be substantial" ); |
There was a problem hiding this comment.
These Assert.IsGreaterThan(...) calls have the expected/actual arguments reversed, which will make the tests fail (e.g., you want result.Length > 100, largeResult.Length > smallResult.Length, and bytes.Length > 8). Swap the argument order (or use a boolean assertion) so the comparisons reflect the intended expectations.
|
|
||
| // Assert | ||
| // Larger pixels per module should produce a larger base64 string (larger image) | ||
| Assert.IsGreaterThan( smallResult.Length, largeResult.Length, "Larger pixelsPerModule should produce larger image" ); |
There was a problem hiding this comment.
These Assert.IsGreaterThan(...) calls have the expected/actual arguments reversed, which will make the tests fail (e.g., you want result.Length > 100, largeResult.Length > smallResult.Length, and bytes.Length > 8). Swap the argument order (or use a boolean assertion) so the comparisons reflect the intended expectations.
| byte[] bytes = Convert.FromBase64String( base64Part ); | ||
|
|
||
| // PNG files start with specific magic bytes: 137 80 78 71 13 10 26 10 | ||
| Assert.IsGreaterThan( 8, bytes.Length, "PNG file should have more than 8 bytes" ); |
There was a problem hiding this comment.
These Assert.IsGreaterThan(...) calls have the expected/actual arguments reversed, which will make the tests fail (e.g., you want result.Length > 100, largeResult.Length > smallResult.Length, and bytes.Length > 8). Swap the argument order (or use a boolean assertion) so the comparisons reflect the intended expectations.
| Assert.IsGreaterThan( 8, bytes.Length, "PNG file should have more than 8 bytes" ); | |
| Assert.IsGreaterThan( bytes.Length, 8, "PNG file should have more than 8 bytes" ); |
| # Instance 1 - shard 0 | ||
| docker run -p 10001:10000 \ | ||
| -e BridgeBeats__DiscordToken=your_token \ | ||
| -e BridgeBeats__NodeNumber=0 \ | ||
| -e BridgeBeats__BaseUrl=https://bridgebeats.link \ | ||
| tsmarvin/bridgebeats-discord:latest |
There was a problem hiding this comment.
This section mixes BridgeBeats__NodeNumber (in the examples) with NODE_NUMBER (in the Important note). Align on a single variable name (and match docs/CONFIGURATION.md) so operators don’t configure the wrong setting.
| - internal | ||
| environment: | ||
| - BASEURL=${BASEURL:-bridgebeats.link} | ||
| - NODE_NUMBER=${NODE_NUMBER:-100} |
There was a problem hiding this comment.
The compose default NODE_NUMBER is 100, while the documentation/config references indicate a default of 0. If NODE_NUMBER is still meaningful (e.g., sharding), consider making the compose default consistent with the documented default or add a brief note explaining why 100 is chosen here.
| - NODE_NUMBER=${NODE_NUMBER:-100} | |
| - NODE_NUMBER=${NODE_NUMBER:-0} |
| .Where( kv => kv.Value is not null ) | ||
| .Where( kv => !kv.Key.EndsWith( "ConnectionString", StringComparison.OrdinalIgnoreCase ) ) | ||
| .ToDictionary( kv => kv.Key, kv => kv.Value ); | ||
| .ToDictionary( ); |
There was a problem hiding this comment.
Using .ToDictionary() without selectors is unusual and may not compile unless you’re relying on a very specific framework/library overload. For clarity and compatibility, prefer an explicit form like .ToDictionary(kv => kv.Key, kv => kv.Value) (this pattern appears in multiple test files in the PR).
| .ToDictionary( ); | |
| .ToDictionary( kv => kv.Key, kv => kv.Value ); |
| for lockfile in $(find . -name "packages.lock.json" ! -name "*.backup"); do | ||
| backup="${lockfile}.backup" | ||
| if [ -f "$backup" ]; then | ||
| pwsh containers/Test-LockFileChanges.ps1 -BackupPath "$backup" -CurrentPath "$lockfile" -ToPlatform "linux-x64" |
There was a problem hiding this comment.
The lock validation script is being called without -FromPlatform, so it assumes the backup lock file was also linux-x64. If a checked-in lock file uses a different RID, this can produce false failures. Consider detecting the original RID per lock file (similar to Build-Publish.ps1) and passing it as -FromPlatform in the workflow.
| pwsh containers/Test-LockFileChanges.ps1 -BackupPath "$backup" -CurrentPath "$lockfile" -ToPlatform "linux-x64" | |
| fromRid=$(grep -m1 '"runtimeIdentifier"' "$backup" | sed -E 's/.*"runtimeIdentifier"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/') | |
| if [ -z "$fromRid" ]; then | |
| fromRid="linux-x64" | |
| fi | |
| pwsh containers/Test-LockFileChanges.ps1 -BackupPath "$backup" -CurrentPath "$lockfile" -FromPlatform "$fromRid" -ToPlatform "linux-x64" |
| # Logging configuration | ||
| LOG_FILE_PATH="${LOG_FILE_PATH:-/app/data/logs/bridgebeats-.log}" | ||
| LOG_DIR_PATH="${LOG_DIR_PATH:-/app/data/logs}" | ||
|
|
There was a problem hiding this comment.
LOG_DIR_PATH is configurable, but directory creation is hardcoded to /app/data/logs. Create the directory using $LOG_DIR_PATH (and optionally also create /app/data/logs for backward compatibility) so non-default log paths work reliably.
| # Ensure the configured log directory exists (and keep /app/data/logs for backward compatibility) | |
| if [ ! -d "$LOG_DIR_PATH" ]; then | |
| mkdir -p "$LOG_DIR_PATH" | |
| fi | |
| if [ "$LOG_DIR_PATH" != "/app/data/logs" ]; then | |
| mkdir -p "/app/data/logs" | |
| fi |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 75 out of 397 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (1)
Tests/Unit/HashUtilityTests.cs:1
- This likely asserts the opposite of what the message says (it reads as “8 is greater than bytes.Length”). To match “PNG file should have more than 8 bytes”, the assertion should validate
bytes.Length > 8.
using BridgeBeats.Core.Infrastructure.Utilities;
| escape_bs() { printf '%s' "$1" | sed 's/\\/\\\\/g'; } | ||
|
|
||
| # 0) Create logs directory if it doesn't exist | ||
| # 0) Create required directories |
There was a problem hiding this comment.
LOG_DIR_PATH is configurable, but the script always creates /app/data/logs instead of creating the directory specified by $LOG_DIR_PATH. If LOG_DIR_PATH is set to a different path, log writing can fail. Create "$LOG_DIR_PATH" (and consider also keeping /app/data/logs only if it’s still required elsewhere).
| # 0) Create required directories | |
| # 0) Create required directories | |
| mkdir -p "$LOG_DIR_PATH" |
| | `ALLOWED_HOSTS` | Allowed hosts for the web server | `*` | | ||
| | `DEFAULT_LOGLEVEL` | Default logging level | `Information` | | ||
| | `HOSTING_DEFAULT_LOGLEVEL` | ASP.NET hosting logging level | `Information` | | ||
| | `OTLP_ENDPOINT` | OpenTelemetry OTLP endpoint for Aspire Dashboard | `http://aspire-dashboard:4317` | | ||
| | `LOG_FILE_PATH` | File path for log files | `/app/data/logs/bridgebeats-.log` | | ||
| | `CACHE_DAYS` | Number of days to cache ATProto PDS lookup results | `7` | | ||
| | `BridgeBeats__LinkCacheConnectionString` | SQLite connection string for cache database | `Data Source=bridgebeats.db` | | ||
| | `REDIS_CONNECTION_STRING` | Redis connection string for caching and queuing | `localhost:6379` (provided by Aspire) | |
There was a problem hiding this comment.
The docs instruct users to set REDIS_CONNECTION_STRING, but the container configuration/entrypoint wiring in this PR uses REDIS_HOST/REDIS_PORT (+ a Redis password secret) to construct ConnectionStrings:redis. Either document the REDIS_HOST/REDIS_PORT setup (and secret) here, or update the container entrypoint/compose to accept REDIS_CONNECTION_STRING directly so docs and deployment match.
| | `REDIS_CONNECTION_STRING` | Redis connection string for caching and queuing | `localhost:6379` (provided by Aspire) | | |
| | `REDIS_HOST` | Redis host for caching and queuing | `redis` (provided by Aspire/container) | | |
| | `REDIS_PORT` | Redis port for caching and queuing | `6379` | | |
| | `REDIS_PASSWORD` | Redis password for caching and queuing (if required) | *(empty – no auth by default)* | |
| Redis is used for distributed caching, request queuing, and rate limit tracking. In development, Aspire provides and configures Redis automatically. In production: | ||
|
|
||
| 1. Deploy a Redis instance (standalone or cluster) | ||
| 2. Set `REDIS_CONNECTION_STRING` to your Redis endpoint | ||
| 3. Recommended: Use Redis with persistence (RDB or AOF) for queue durability | ||
| 4. Recommended: Enable TLS and authentication for production deployments |
There was a problem hiding this comment.
The docs instruct users to set REDIS_CONNECTION_STRING, but the container configuration/entrypoint wiring in this PR uses REDIS_HOST/REDIS_PORT (+ a Redis password secret) to construct ConnectionStrings:redis. Either document the REDIS_HOST/REDIS_PORT setup (and secret) here, or update the container entrypoint/compose to accept REDIS_CONNECTION_STRING directly so docs and deployment match.
| Redis is used for distributed caching, request queuing, and rate limit tracking. In development, Aspire provides and configures Redis automatically. In production: | |
| 1. Deploy a Redis instance (standalone or cluster) | |
| 2. Set `REDIS_CONNECTION_STRING` to your Redis endpoint | |
| 3. Recommended: Use Redis with persistence (RDB or AOF) for queue durability | |
| 4. Recommended: Enable TLS and authentication for production deployments | |
| Redis is used for distributed caching, request queuing, and rate limit tracking. In development, Aspire provides and configures Redis automatically. In production (containerized deployment): | |
| 1. Deploy a Redis instance (standalone or cluster). | |
| 2. Configure the BridgeBeats container with: | |
| - `REDIS_HOST` – the hostname or service name of your Redis instance | |
| - `REDIS_PORT` – the TCP port for Redis (usually `6379`) | |
| - A Redis password provided via environment variable or secret (for example, `REDIS_PASSWORD`), which the container entrypoint uses together with `REDIS_HOST`/`REDIS_PORT` to build `ConnectionStrings:redis` | |
| 3. Recommended: Use Redis with persistence (RDB or AOF) for queue durability. | |
| 4. Recommended: Enable TLS and authentication for production deployments. |
| 2. Set `REDIS_CONNECTION_STRING` to your Redis endpoint | ||
| 3. Recommended: Use Redis with persistence (RDB or AOF) for queue durability | ||
| 4. Recommended: Enable TLS and authentication for production deployments |
There was a problem hiding this comment.
The docs instruct users to set REDIS_CONNECTION_STRING, but the container configuration/entrypoint wiring in this PR uses REDIS_HOST/REDIS_PORT (+ a Redis password secret) to construct ConnectionStrings:redis. Either document the REDIS_HOST/REDIS_PORT setup (and secret) here, or update the container entrypoint/compose to accept REDIS_CONNECTION_STRING directly so docs and deployment match.
| 2. Set `REDIS_CONNECTION_STRING` to your Redis endpoint | |
| 3. Recommended: Use Redis with persistence (RDB or AOF) for queue durability | |
| 4. Recommended: Enable TLS and authentication for production deployments | |
| 2. When running in containers (e.g., via Aspire or Docker), configure Redis using `REDIS_HOST` and `REDIS_PORT` (and the associated Redis password secret defined in your deployment). The container entrypoint combines these into `ConnectionStrings:redis` for the application. | |
| 3. When running outside of containers, you may instead set `REDIS_CONNECTION_STRING` directly to a full Redis connection string if your hosting model prefers a single connection string value. | |
| 4. Recommended: Use Redis with persistence (RDB or AOF) for queue durability | |
| 5. Recommended: Enable TLS and authentication for production deployments |
| The fastest way to deploy BridgeBeats is with the installation script. No need to clone the repository. | ||
|
|
||
| ### Linux / macOS | ||
|
|
There was a problem hiding this comment.
The deployment guide promotes curl | bash, which is risky because it executes remote code without an integrity check. Consider documenting a safer flow (download to a file, review, optionally verify a checksum/signature, then execute), or at minimum call out the trust/security tradeoff explicitly.
| .AsEnumerable() | ||
| .Where( kv => kv.Value is not null ) | ||
| .Where( kv => !kv.Key.EndsWith( "ConnectionString", StringComparison.OrdinalIgnoreCase ) ) | ||
| .ToDictionary( kv => kv.Key, kv => kv.Value ); | ||
| .ToDictionary( ); |
There was a problem hiding this comment.
Enumerable.ToDictionary() does not have a parameterless overload in common LINQ APIs; this is likely a compile error. Use an explicit key/value selector (e.g., ToDictionary(kv => kv.Key, kv => kv.Value)) or construct a Dictionary<string, string?> from the enumeration. The same pattern appears in other updated test files in this PR (e.g., DashboardAuthorizationTests, OpenGraphCardControllerTests, MusicLookupControllerTests, HomeControllerTests) and should be corrected consistently.
| string smallResult = _service.GenerateQrCodeDataUri( url, pixelsPerModule: 5 ); | ||
| string largeResult = _service.GenerateQrCodeDataUri( url, pixelsPerModule: 20 ); |
There was a problem hiding this comment.
The comparison assertions appear to have their operands reversed relative to the intent expressed in the messages. For example, “should be substantial” implies result.Length > 100, and “larger image” implies largeResult.Length > smallResult.Length. Fix the operand ordering (or use explicit boolean assertions) so the tests validate the intended behavior.
Description
Continued refactor of the in progress updates to PR#274