Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
124 commits
Select commit Hold shift + click to select a range
96bff10
Updated for the net10 support
albert-kunushevci Nov 16, 2025
e4b0215
update to release version
albert-kunushevci Nov 16, 2025
62c3ffa
added release for net9
albert-kunushevci Nov 16, 2025
e5037dd
added pattern to skip commits using comments on commit for cherry pic…
albert-kunushevci Nov 16, 2025
ade2439
remove unecessary build command
albert-kunushevci Nov 16, 2025
ae2a674
fixed the sync
albert-kunushevci Nov 16, 2025
03bd174
updated cherry detections
albert-kunushevci Nov 16, 2025
cf21cac
try merge based on commit
albert-kunushevci Nov 16, 2025
15acdce
Fixed the json options to be isolated (#375)
albert-kunushevci Nov 17, 2025
f7b961a
Fix/schedulerbackground (#376)
albert-kunushevci Nov 17, 2025
0af984b
beta version 17 release (#382)
albert-kunushevci Nov 17, 2025
15dee40
Feature/improvements (#386)
albert-kunushevci Nov 19, 2025
9d82d89
Update README.md
albert-kunushevci Nov 19, 2025
7ce13e5
Update README.md
albert-kunushevci Nov 19, 2025
5ae6cc7
updated beta version
albert-kunushevci Nov 20, 2025
2ea014a
Feature/new improvements (#397)
albert-kunushevci Nov 23, 2025
c7eb219
releas of stable version
albert-kunushevci Nov 23, 2025
593c553
Update README.md
albert-kunushevci Nov 23, 2025
7d50613
Release of stable version.
albert-kunushevci Nov 23, 2025
e4c1801
Fix schema assignment logic and add SetSchema method (#415)
SpaceOgre Nov 27, 2025
5251bd4
Add support for enabling/disabling background services (#413)
SpaceOgre Nov 27, 2025
6f6a580
Update Directory.Build.props
albert-kunushevci Nov 27, 2025
2e06180
Added logo locally
albert-kunushevci Nov 27, 2025
5c8216b
Fix retry logic and add unit tests for ExecuteTaskAsync (#429)
SpaceOgre Nov 29, 2025
4f888cb
fix: namespace conflicts for ModuleInitializer attribute in TickerQIn…
HulinCedric Dec 1, 2025
ebb26bf
Update Directory.Build.props
albert-kunushevci Dec 10, 2025
d7716b9
Update Directory.Build.props
albert-kunushevci Dec 10, 2025
298ca68
fix update ExecutionTime for CronTickerOccurrence (#461)
AlexeyKhlebnikov Dec 26, 2025
baed026
feat: add configurable policy name for Host auth (#482)
jods4 Jan 12, 2026
f47b7fd
fix: Host auth. should not depend on Authorization header (#481)
jods4 Jan 12, 2026
42d42c6
[Feature] Remove ASP.NET Core dependency from TickerQ.Utilities to su…
EarlJester Jan 12, 2026
52039f1
Fix missing await to AuthenticateHostAsync call (#494)
jods4 Jan 13, 2026
d24022f
Fix #497 (#503)
jods4 Jan 18, 2026
79fbbb2
Fix stackoverflow in JsonExampleGenerator (#519)
stevewoj Feb 4, 2026
da2d6d3
Feature/tickerq hub (#508)
albert-kunushevci Feb 4, 2026
ea1da0d
pre-release
albert-kunushevci Feb 4, 2026
e591557
fix references
albert-kunushevci Feb 4, 2026
af1cfda
Add missing ASP.NET Core package references to TickerQ.SDK (#537)
albert-kunushevci Feb 5, 2026
0e26c20
Claude/fix aspnetcore namespace xuvot (#540)
albert-kunushevci Feb 5, 2026
b427a77
Remove invalid ASP.NET Core package references (#541)
albert-kunushevci Feb 5, 2026
6e233eb
Claude/remove invalid aspnetcore packages xuvot (#542)
albert-kunushevci Feb 5, 2026
b4c0fe1
Claude/remove invalid aspnetcore packages xuvot (#543)
albert-kunushevci Feb 5, 2026
8c7d16d
Enable NuGet package generation for Web SDK projects (#546)
albert-kunushevci Feb 5, 2026
c686a9d
Fix #511 and #517: null reference and orphaned cron ticker bugs (#549)
albert-kunushevci Feb 9, 2026
fd743f1
Fix thread-safety bugs, resource leaks, and scheduling issues (#550)
desty2k Feb 9, 2026
7d576b0
added extension method for WebApplication
albert-kunushevci Feb 9, 2026
ff0d780
pre-release
albert-kunushevci Feb 9, 2026
ab9165a
fix and pre-release
albert-kunushevci Feb 9, 2026
abc83f1
removed the not-needed reference from the Tickerq.
albert-kunushevci Feb 9, 2026
831cd76
fixed based on the tickerq architecture.
albert-kunushevci Feb 9, 2026
a0221d3
update version
albert-kunushevci Feb 9, 2026
75cf665
fix and pre-release...
albert-kunushevci Feb 9, 2026
f3814bb
release a stable version
albert-kunushevci Feb 9, 2026
f862640
release a stable version along with the new libs for the hub.
albert-kunushevci Feb 9, 2026
39b9b90
Fix .NET 9+ EF Core query failures caused by ReadOnlySpan array.Conta…
albert-kunushevci Feb 10, 2026
b2684f4
fix the dashboard...
albert-kunushevci Feb 10, 2026
61c72a8
Add comprehensive unit tests for core TickerQ components (#582)
albert-kunushevci Feb 11, 2026
cbbd680
added rickerq hub to readme file.
albert-kunushevci Feb 11, 2026
898f713
Fix authorize against HostAuthorizationPolicy when set (#591)
stevewoj Feb 12, 2026
6fe6bff
Added dashboard group name for the openapi (#585)
albert-kunushevci Feb 13, 2026
5776656
fixed unit testing and issue of (#586)
albert-kunushevci Feb 13, 2026
646a75a
added the sample for worker service
albert-kunushevci Feb 16, 2026
d79bf98
fix issue 522 (#587)
albert-kunushevci Feb 25, 2026
d664833
Add JSON-serializable tracking fields to TimeTickerEntity (#609)
stevewoj Mar 6, 2026
4ddd580
Fix UseApplicationDbContext implementation #498 (#590)
Kedireng Mar 6, 2026
094dff7
added unit tests for more edge cases coverage. (#623)
albert-kunushevci Mar 13, 2026
257e222
Improve branch sync workflow, migrate to slnx, and clean up repo (#628)
albert-kunushevci Mar 13, 2026
0a48b8e
Fix EF Core type mapping error for MySQL providers in MigrateDefinedC…
albert-kunushevci Mar 14, 2026
b9507cc
Add IsEnabled property to CronTickerEntity with full-stack support (#…
albert-kunushevci Mar 14, 2026
55cb507
Fix TickerModelCustomizer not applying configured schema (#635)
albert-kunushevci Mar 14, 2026
2656d5a
Replace reflection-based JSON serialization in Dashboard with source …
albert-kunushevci Mar 14, 2026
544edf1
Fix Dashboard failing with old Startup.cs pattern (IHost not implemen…
albert-kunushevci Mar 14, 2026
ed1cd1c
Relax abstractions version constraints and fix sync workflow version …
albert-kunushevci Mar 14, 2026
88202f9
Relax abstractions version constraints and fix sync workflow version …
albert-kunushevci Mar 14, 2026
0ffa7b0
Eliminate inline scripts from Dashboard for CSP script-src 'self' sup…
albert-kunushevci Mar 14, 2026
757d148
Fix Dashboard BasePath not working with UsePathBase (#332) (#651)
albert-kunushevci Mar 14, 2026
0370af5
Fix design-time DbContext failure when TickerQEfCoreOptionBuilder is …
albert-kunushevci Mar 14, 2026
1a11f10
Fix source generator namespace sanitization for assemblies with inval…
albert-kunushevci Mar 14, 2026
f193634
Fix empty request deserialization throwing JsonException (#463) (#658)
albert-kunushevci Mar 14, 2026
b639ed1
Fix dashboard date format to use browser locale (#581) (#663)
albert-kunushevci Mar 14, 2026
e6f328b
Fix dashboard date format to use locale-independent YYYY-MM-DD (#666)
albert-kunushevci Mar 14, 2026
252c472
Add per-function concurrency control via maxConcurrency parameter (#670)
albert-kunushevci Mar 14, 2026
d8d2255
Centralize test project versions for cross-branch compatibility (#673)
albert-kunushevci Mar 14, 2026
d45691f
Fix AddStackExchangeRedis overriding EF Core persistence provider (#676)
albert-kunushevci Mar 15, 2026
ea1268e
Fix Redis registration test and remove redundant Hosting.Abstractions…
albert-kunushevci Mar 15, 2026
53ef0e5
Fix dashboard date formatting by timezone region and cron ticker togg…
albert-kunushevci Mar 15, 2026
cb6fd30
new release 10.2.0
albert-kunushevci Mar 15, 2026
f281df8
Simplify EF Core DbContext session pattern (#688)
albert-kunushevci Mar 16, 2026
23b8e53
Add unit tests for DbContextLease resolution across DI configurations…
albert-kunushevci Mar 16, 2026
816fbdc
release for fix/ef-core-dbcontext-session-cleanup
albert-kunushevci Mar 16, 2026
c3e6a32
Add head-to-head BenchmarkDotNet comparisons vs Hangfire & Quartz (#697)
albert-kunushevci Mar 16, 2026
aa6c831
Register scoped DbContext from factory for direct injection (#700) (#…
albert-kunushevci Mar 16, 2026
0e54aa3
Restructure hub projects: move RemoteExecutor and SDKs into hub/ fold…
albert-kunushevci Mar 18, 2026
b0e7b1d
Add CLA workflow, CLA document, and contributing guidelines (#722)
albert-kunushevci Mar 21, 2026
29d3e62
Scope CLA workflow to main branch only
albert-kunushevci Mar 21, 2026
6d47f9c
Update README.md (#726)
albert-miden Mar 21, 2026
5a79497
Rewrite README: cleaner structure, feature highlights, contributors s…
albert-kunushevci Mar 21, 2026
90f0f6e
Fix Discord badge to use static badge instead of invalid server ID
albert-kunushevci Mar 21, 2026
157b270
Update README tagline and subtitle
albert-kunushevci Mar 21, 2026
c1da63e
Update copyright to Arcenox LLC, add Authors/Copyright to NuGet metadata
albert-kunushevci Mar 21, 2026
97e4f63
Add SECURITY.md with vulnerability reporting policy
albert-kunushevci Mar 21, 2026
d9fdb93
Rewrite branch sync from cherry-pick to merge-based approach (#744)
albert-kunushevci Mar 21, 2026
4598a48
Fix sync-overrides loading from target branch instead of main
albert-kunushevci Mar 21, 2026
f667d43
Fix sync workflow: load exclude/overrides from main, escape sed regex
albert-kunushevci Mar 21, 2026
539ef27
Fix version-range sed regex error by using awk for replacements
albert-kunushevci Mar 21, 2026
0cc8981
Fix sync builds: use $(DotNetVersion) for packages, detect .NET versi…
albert-kunushevci Mar 21, 2026
d7e38e5
Centralize version props in src/Directory.Build.props
albert-kunushevci Mar 21, 2026
32e6e96
Add CustomizerServiceDescriptor.cs to .sync-exclude
albert-kunushevci Mar 21, 2026
4aee441
Add retry for PR comment in sync workflow
albert-kunushevci Mar 21, 2026
4e56cfb
Fix dashboard WebSocket 405 when host uses MapStaticAssets (#456) (#723)
albert-kunushevci Mar 21, 2026
cfe67fe
Fix Oracle-incompatible boolean default in CronTicker migration (#716…
albert-kunushevci Mar 21, 2026
aef8825
Switch build and sync workflows to trigger on release
albert-kunushevci Mar 21, 2026
415f8c0
Add test step to release build workflow
albert-kunushevci Mar 21, 2026
287321d
Add Source Link and symbol package support (#743)
albert-kunushevci Mar 21, 2026
061d1ec
Fix dashboard date/time display for Windows timezone IDs (#717) (#719)
albert-kunushevci Mar 21, 2026
01f4e24
Skip TickerQ initialization in design-time tools (#712) (#763)
albert-kunushevci Mar 21, 2026
493e77d
Fix TickerFunctionProvider Build() race condition and add startup val…
albert-kunushevci Mar 21, 2026
eb6d8a3
Bump version to 10.2.3
albert-kunushevci Mar 21, 2026
c12c8ae
Fix build pipeline: restore only build targets, not samples
albert-kunushevci Mar 21, 2026
53f9d2b
Switch Sample.WorkerService from PackageReference to ProjectReference
albert-kunushevci Mar 21, 2026
b44ddd7
Add UseAuthorization() to dashboard branch pipeline for Host auth (#4…
albert-kunushevci Mar 21, 2026
f40b712
Bump version to 10.2.4
albert-kunushevci Mar 21, 2026
93b81e2
Merge main into net9
github-actions[bot] Mar 21, 2026
a0f7364
Apply version-specific overrides for net9
github-actions[bot] Mar 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Version>9.2.3</Version>
<Version>9.2.4</Version>
<DotNetVersion>[9.0.0,10.0.0)</DotNetVersion>
<DotNetAbstractionsVersion>[10.0.0,11.0.0)</DotNetAbstractionsVersion>
<RepositoryUrl>https://github.com/arcenox-co/TickerQ</RepositoryUrl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ internal static void UseDashboardWithEndpoints<TTimeTicker, TCronTicker>(this IA
dashboardApp.UseRouting();
dashboardApp.UseCors("TickerQ_Dashboard_CORS");

// Add ASP.NET Core authorization middleware when auth is enabled.
// This is required because Host-mode endpoints use RequireAuthorization(),
// and ASP.NET Core's EndpointMiddleware throws InvalidOperationException
// if no AuthorizationMiddleware exists between UseRouting() and UseEndpoints().
// The host app's UseAuthorization() does not propagate into Map() branches.
if (config.Auth.IsEnabled)
{
dashboardApp.UseAuthorization();
}

// Add authentication middleware (only protects API endpoints)
if (config.Auth.IsEnabled)
{
Expand Down
229 changes: 229 additions & 0 deletions tests/TickerQ.Tests/DashboardAuthorizationPipelineTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
using System.Net;
using System.Reflection;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using TickerQ.Dashboard.DependencyInjection;

namespace TickerQ.Tests;

/// <summary>
/// Integration tests for the dashboard authorization middleware pipeline.
/// Covers issue #408: InvalidOperationException when using Host authentication because
/// UseAuthorization() was missing in the dashboard's Map() branch pipeline.
///
/// These tests reproduce the exact pattern used by the dashboard pipeline:
/// a Map() branch with UseRouting() + UseEndpoints() containing endpoints with
/// RequireAuthorization() metadata. Without UseAuthorization() in the branch,
/// ASP.NET Core's EndpointMiddleware throws InvalidOperationException.
/// </summary>
public class DashboardAuthorizationPipelineTests
{
private static readonly MethodInfo MapPathBaseAwareMethod =
typeof(ServiceCollectionExtensions).GetMethod(
"MapPathBaseAware",
BindingFlags.NonPublic | BindingFlags.Static)!;

/// <summary>
/// Reproduces issue #408: a Map() branch pipeline with UseRouting() + UseEndpoints()
/// where endpoints have RequireAuthorization() metadata but UseAuthorization() is
/// present in the branch. Should NOT throw InvalidOperationException.
/// </summary>
[Fact]
public async Task BranchPipeline_WithUseAuthorization_AndRequireAuthorization_DoesNotThrow()
{
using var host = await CreateTestHost(includeUseAuthorization: true);
var client = host.GetTestClient();

var response = await client.GetAsync("/dashboard/api/test");

// Should get 401 (unauthenticated) but NOT throw InvalidOperationException
Assert.True(
response.StatusCode == HttpStatusCode.Unauthorized ||
response.StatusCode == HttpStatusCode.OK,
$"Expected 401 or 200, got {(int)response.StatusCode}");
}

/// <summary>
/// Verifies the bug condition: without UseAuthorization() in the branch pipeline,
/// endpoints with RequireAuthorization() cause InvalidOperationException.
/// This test documents the exact failure that issue #408 reports.
/// </summary>
[Fact]
public async Task BranchPipeline_WithoutUseAuthorization_AndRequireAuthorization_Throws()
{
using var host = await CreateTestHost(includeUseAuthorization: false);
var client = host.GetTestClient();

// Without UseAuthorization(), ASP.NET Core's EndpointMiddleware throws
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => client.GetAsync("/dashboard/api/test"));

Assert.Contains("authorization", ex.Message, StringComparison.OrdinalIgnoreCase);
}

/// <summary>
/// Endpoints marked with AllowAnonymous should work even with UseAuthorization()
/// and no authenticated user, matching the dashboard's /api/auth/info behavior.
/// </summary>
[Fact]
public async Task BranchPipeline_AllowAnonymousEndpoint_Returns200()
{
using var host = await CreateTestHost(includeUseAuthorization: true);
var client = host.GetTestClient();

var response = await client.GetAsync("/dashboard/api/anonymous");

Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal("anonymous-ok", body);
}

/// <summary>
/// When auth is not configured (no RequireAuthorization on endpoints),
/// UseAuthorization() is not needed and endpoints work without it.
/// This covers the non-auth dashboard configuration path.
/// </summary>
[Fact]
public async Task BranchPipeline_NoAuthEndpoints_WorksWithout_UseAuthorization()
{
using var host = await CreateTestHostNoAuth();
var client = host.GetTestClient();

var response = await client.GetAsync("/dashboard/api/test");

Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal("no-auth-ok", body);
}

/// <summary>
/// Creates a test host that mirrors the dashboard's Map() branch pipeline pattern:
/// UseRouting() → UseCors() → [optional UseAuthorization()] → UseEndpoints() with
/// endpoints that have RequireAuthorization() metadata.
/// </summary>
private static async Task<IHost> CreateTestHost(bool includeUseAuthorization)
{
var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseTestServer();
webBuilder.ConfigureServices(services =>
{
services.AddRouting();
services.AddAuthorization();
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>("Test", _ => { });
services.AddCors(options =>
{
options.AddPolicy("TestCORS", b => b.AllowAnyOrigin());
});
});
webBuilder.Configure(app =>
{
// Use MapPathBaseAware to mirror the dashboard's exact pipeline
MapPathBaseAwareMethod.Invoke(null, new object[]
{
app, "/dashboard", new Action<IApplicationBuilder>(branch =>
{
branch.UseRouting();
branch.UseCors("TestCORS");

if (includeUseAuthorization)
{
branch.UseAuthorization();
}

branch.UseEndpoints(endpoints =>
{
endpoints.MapGet("/api/test", () => "ok")
.RequireAuthorization()
.RequireCors("TestCORS");

endpoints.MapGet("/api/anonymous", () => "anonymous-ok")
.AllowAnonymous()
.RequireCors("TestCORS");
});
})
});

app.Run(async context =>
{
await context.Response.WriteAsync("fallthrough");
});
});
})
.StartAsync();

return host;
}

/// <summary>
/// Creates a test host with no authorization on endpoints (mirrors no-auth dashboard config).
/// </summary>
private static async Task<IHost> CreateTestHostNoAuth()
{
var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder.UseTestServer();
webBuilder.ConfigureServices(services =>
{
services.AddRouting();
services.AddCors(options =>
{
options.AddPolicy("TestCORS", b => b.AllowAnyOrigin());
});
});
webBuilder.Configure(app =>
{
MapPathBaseAwareMethod.Invoke(null, new object[]
{
app, "/dashboard", new Action<IApplicationBuilder>(branch =>
{
branch.UseRouting();
branch.UseCors("TestCORS");

branch.UseEndpoints(endpoints =>
{
endpoints.MapGet("/api/test", () => "no-auth-ok")
.RequireCors("TestCORS");
});
})
});

app.Run(async context =>
{
await context.Response.WriteAsync("fallthrough");
});
});
})
.StartAsync();

return host;
}

/// <summary>
/// Minimal test authentication handler that always returns no-result (unauthenticated).
/// </summary>
private class TestAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public TestAuthHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
System.Text.Encodings.Web.UrlEncoder encoder)
: base(options, logger, encoder) { }

protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
return Task.FromResult(AuthenticateResult.NoResult());
}
}
}
Loading