Skip to content

auth.m2m: Support configurable route path suffixes for OAuth2 endpoints#303

Merged
intel352 merged 4 commits intomainfrom
copilot/support-configurable-route-path-suffixes
Mar 12, 2026
Merged

auth.m2m: Support configurable route path suffixes for OAuth2 endpoints#303
intel352 merged 4 commits intomainfrom
copilot/support-configurable-route-path-suffixes

Conversation

Copy link
Contributor

Copilot AI commented Mar 12, 2026

auth.m2m hardcodes strings.HasSuffix checks against /oauth/token, /oauth/revoke, /oauth/introspect, and /oauth/jwks, breaking compatibility with Fosite/Auth0/Okta-style servers that expose revocation and introspection as sub-paths of the token endpoint.

Changes

  • module/auth_m2m.go: Added M2MEndpointPaths struct and DefaultM2MEndpointPaths(). Added endpointPaths field to M2MAuthModule, initialized to defaults in NewM2MAuthModule. Added SetEndpoints(M2MEndpointPaths) — merges only non-empty fields, so partial overrides preserve remaining defaults. Updated Handle() to route against configured paths.

  • plugins/auth/plugin.go: auth.m2m factory reads an endpoints map from YAML config and calls SetEndpoints. ModuleSchemas() documents the new field.

Usage

- name: m2m-auth
  type: auth.m2m
  config:
    endpoints:
      revoke: /oauth/token/revoke       # Fosite/Auth0-style
      introspect: /oauth/token/introspect
    # token and jwks remain at defaults (/oauth/token, /oauth/jwks)

Programmatic override:

m.SetEndpoints(module.M2MEndpointPaths{
    Revoke:     "/oauth/token/revoke",
    Introspect: "/oauth/token/introspect",
})
Original prompt

This section details on the original issue you should resolve

<issue_title>auth.m2m: Support configurable route path suffixes for OAuth2 endpoints</issue_title>
<issue_description>## Problem

The auth.m2m module's Handle() method routes requests using strings.HasSuffix() with hardcoded suffixes:

case r.Method == http.MethodPost && strings.HasSuffix(path, "/oauth/token"):
case r.Method == http.MethodPost && strings.HasSuffix(path, "/oauth/revoke"):
case r.Method == http.MethodPost && strings.HasSuffix(path, "/oauth/introspect"):
case r.Method == http.MethodGet && strings.HasSuffix(path, "/oauth/jwks"):

This creates a mismatch when integrating with systems that expect different OAuth endpoint paths. For example, RFC 7662 § 2 defines the introspection endpoint as a standalone path, but many real-world OAuth servers (ORY Fosite, Auth0, Okta) expose it as a sub-path of the token endpoint:

  • auth.m2m expects: POST /oauth/introspect
  • Many implementations expect: POST /oauth/token/introspect

Similarly for revocation:

  • auth.m2m expects: POST /oauth/revoke
  • Many implementations expect: POST /oauth/token/revoke

Current Workaround

Consumers must add custom Go code to intercept requests at the legacy paths, rewrite r.URL.Path, and delegate to the M2MAuthModule.Handle() method. This requires:

  1. Finding the M2MAuthModule instance in the service registry
  2. Finding the StandardHTTPRouter to register additional routes
  3. Implementing a path-rewriting wrapper

This is boilerplate that every consumer migrating from a Fosite/Auth0-style OAuth server needs.

Proposed Solution

Add a configuration option to auth.m2m that allows customizing the endpoint path suffixes, or support path aliases:

Option A: Configurable suffixes

- name: m2m-auth
  type: auth.m2m
  config:
    endpoints:
      token: /oauth/token
      introspect: /oauth/token/introspect  # custom path
      revoke: /oauth/token/revoke           # custom path
      jwks: /oauth/jwks

Option B: Path aliases

- name: m2m-auth
  type: auth.m2m
  config:
    path_aliases:
      introspect: ["/oauth/introspect", "/oauth/token/introspect"]
      revoke: ["/oauth/revoke", "/oauth/token/revoke"]

Option C: Support additional route registration in YAML

Allow the workflows.http.routes section to register multiple paths for the same handler, and have the Handle() method be more flexible about path matching (e.g., matching on the last path segment rather than a full suffix).

Impact

This affects any consumer migrating to the workflow engine from an existing OAuth2 server implementation that used different endpoint paths. The migration forces either:

  • Custom Go code for path rewriting (defeats the zero-code YAML philosophy)
  • Updating all OAuth clients to use new paths (often not feasible for third-party integrations)</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…ints()

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for configurable route path suffixes in auth.m2m auth.m2m: Support configurable route path suffixes for OAuth2 endpoints Mar 12, 2026
@intel352 intel352 marked this pull request as ready for review March 12, 2026 04:43
Copilot AI review requested due to automatic review settings March 12, 2026 04:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds configurable OAuth2 endpoint path suffixes to the auth.m2m module so deployments can expose token/revoke/introspect/JWKS under non-default paths (while still supporting mounting behind a router prefix via suffix matching).

Changes:

  • Add M2MEndpointPaths + SetEndpoints() and route Handle() via configurable suffixes.
  • Wire new endpoints config into the auth plugin factory + schema, and add unit tests covering overrides.
  • Apply gofmt-style formatting cleanups in a few module test/files.

Reviewed changes

Copilot reviewed 4 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
module/auth_m2m.go Introduces endpoint path configuration and uses it for request routing.
plugins/auth/plugin.go Adds endpoints config plumbing and exposes it in the module schema.
plugins/auth/plugin_test.go Tests auth.m2m factory behavior with custom endpoint paths.
module/auth_m2m_test.go Adds unit tests verifying defaults and override behavior for endpoint paths.
module/scan_provider_test.go Formatting-only adjustments.
module/platform_do_database.go Formatting-only adjustments to struct field comments.
module/platform_do_database_test.go Formatting-only alignment changes in test config map.

Comment on lines +242 to +246
// SetEndpoints overrides the URL path suffixes used by Handle() to route incoming
// requests to the token, revocation, introspection, and JWKS sub-handlers.
// Any empty field in paths is left at its current value (defaulting to the standard
// paths set by NewM2MAuthModule).
//
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetEndpoints accepts arbitrary strings which are later used with strings.HasSuffix for routing, but there’s no validation to catch common misconfigurations (e.g., missing leading '/', duplicate paths between Token/Revoke/Introspect/JWKS, or values that are too generic like "/token" causing unintended matches). Consider validating the resulting endpoint paths (non-empty, distinct, and maybe must start with '/') and surfacing a clear init error when invalid so the module doesn’t start with unreachable/ambiguous endpoints.

Copilot uses AI. Check for mistakes.
@intel352
Copy link
Contributor

@copilot apply changes based on the comments in this thread

Ensure all linters, tests, config validation are passing.

@github-actions
Copy link

github-actions bot commented Mar 12, 2026

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:244: parsing iteration count: invalid syntax
baseline-bench.txt:364916: parsing iteration count: invalid syntax
baseline-bench.txt:745380: parsing iteration count: invalid syntax
baseline-bench.txt:1085071: parsing iteration count: invalid syntax
baseline-bench.txt:1464089: parsing iteration count: invalid syntax
baseline-bench.txt:1788525: parsing iteration count: invalid syntax
benchmark-results.txt:244: parsing iteration count: invalid syntax
benchmark-results.txt:308753: parsing iteration count: invalid syntax
benchmark-results.txt:609636: parsing iteration count: invalid syntax
benchmark-results.txt:904975: parsing iteration count: invalid syntax
benchmark-results.txt:1205165: parsing iteration count: invalid syntax
benchmark-results.txt:1510059: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                  6.665m ± 57%
ComponentLoad-4                        3.436m ±  1%
ComponentExecute-4                     2.007µ ±  2%
PoolContention/workers-1-4             1.083µ ±  4%
PoolContention/workers-2-4             1.083µ ±  1%
PoolContention/workers-4-4             1.082µ ±  1%
PoolContention/workers-8-4             1.087µ ±  1%
PoolContention/workers-16-4            1.096µ ±  1%
ComponentLifecycle-4                   3.507m ±  0%
SourceValidation-4                     2.325µ ±  2%
RegistryConcurrent-4                   764.3n ±  3%
LoaderLoadFromString-4                 3.591m ±  2%
geomean                                18.45µ

                            │ benchmark-results.txt │
                            │         B/op          │
InterpreterCreation-4                  1.944Mi ± 0%
ComponentLoad-4                        2.097Mi ± 0%
ComponentExecute-4                     1.203Ki ± 0%
PoolContention/workers-1-4             1.203Ki ± 0%
PoolContention/workers-2-4             1.203Ki ± 0%
PoolContention/workers-4-4             1.203Ki ± 0%
PoolContention/workers-8-4             1.203Ki ± 0%
PoolContention/workers-16-4            1.203Ki ± 0%
ComponentLifecycle-4                   2.099Mi ± 0%
SourceValidation-4                     1.984Ki ± 0%
RegistryConcurrent-4                   1.133Ki ± 0%
LoaderLoadFromString-4                 2.099Mi ± 0%
geomean                                15.05Ki

                            │ benchmark-results.txt │
                            │       allocs/op       │
InterpreterCreation-4                   15.09k ± 0%
ComponentLoad-4                         17.43k ± 0%
ComponentExecute-4                       25.00 ± 0%
PoolContention/workers-1-4               25.00 ± 0%
PoolContention/workers-2-4               25.00 ± 0%
PoolContention/workers-4-4               25.00 ± 0%
PoolContention/workers-8-4               25.00 ± 0%
PoolContention/workers-16-4              25.00 ± 0%
ComponentLifecycle-4                    17.48k ± 0%
SourceValidation-4                       32.00 ± 0%
RegistryConcurrent-4                     2.000 ± 0%
LoaderLoadFromString-4                  17.47k ± 0%
geomean                                  181.2

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4               6.671m ± 57%
ComponentLoad-4                     3.311m ±  1%
ComponentExecute-4                  1.949µ ±  2%
PoolContention/workers-1-4          1.198µ ±  1%
PoolContention/workers-2-4          1.203µ ±  1%
PoolContention/workers-4-4          1.217µ ±  2%
PoolContention/workers-8-4          1.203µ ±  4%
PoolContention/workers-16-4         1.204µ ±  1%
ComponentLifecycle-4                3.381m ±  0%
SourceValidation-4                  2.299µ ±  0%
RegistryConcurrent-4                907.2n ±  2%
LoaderLoadFromString-4              3.419m ±  4%
geomean                             19.28µ

                            │ baseline-bench.txt │
                            │        B/op        │
InterpreterCreation-4               1.944Mi ± 0%
ComponentLoad-4                     2.097Mi ± 0%
ComponentExecute-4                  1.203Ki ± 0%
PoolContention/workers-1-4          1.203Ki ± 0%
PoolContention/workers-2-4          1.203Ki ± 0%
PoolContention/workers-4-4          1.203Ki ± 0%
PoolContention/workers-8-4          1.203Ki ± 0%
PoolContention/workers-16-4         1.203Ki ± 0%
ComponentLifecycle-4                2.099Mi ± 0%
SourceValidation-4                  1.984Ki ± 0%
RegistryConcurrent-4                1.133Ki ± 0%
LoaderLoadFromString-4              2.099Mi ± 0%
geomean                             15.05Ki

                            │ baseline-bench.txt │
                            │     allocs/op      │
InterpreterCreation-4                15.09k ± 0%
ComponentLoad-4                      17.43k ± 0%
ComponentExecute-4                    25.00 ± 0%
PoolContention/workers-1-4            25.00 ± 0%
PoolContention/workers-2-4            25.00 ± 0%
PoolContention/workers-4-4            25.00 ± 0%
PoolContention/workers-8-4            25.00 ± 0%
PoolContention/workers-16-4           25.00 ± 0%
ComponentLifecycle-4                 17.48k ± 0%
SourceValidation-4                    32.00 ± 0%
RegistryConcurrent-4                  2.000 ± 0%
LoaderLoadFromString-4               17.47k ± 0%
geomean                               181.2

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                    291.4n ± 12%
CircuitBreakerExecution_Success-4            22.49n ±  0%
CircuitBreakerExecution_Failure-4            65.66n ±  1%
geomean                                      75.50n

                                  │ benchmark-results.txt │
                                  │         B/op          │
CircuitBreakerDetection-4                    144.0 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

                                  │ benchmark-results.txt │
                                  │       allocs/op       │
CircuitBreakerDetection-4                    1.000 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  462.7n ± 4%
CircuitBreakerExecution_Success-4          59.77n ± 0%
CircuitBreakerExecution_Failure-4          64.67n ± 0%
geomean                                    121.4n

                                  │ baseline-bench.txt │
                                  │        B/op        │
CircuitBreakerDetection-4                 144.0 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │
                                  │     allocs/op      │
CircuitBreakerDetection-4                 1.000 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        919.6n ± 30%
JQTransform_ObjectConstruction-4            1.467µ ±  2%
JQTransform_ArraySelect-4                   3.452µ ±  3%
JQTransform_Complex-4                       39.41µ ±  1%
JQTransform_Throughput-4                    1.824µ ±  1%
SSEPublishDelivery-4                        66.77n ±  4%
geomean                                     1.678µ

                                 │ benchmark-results.txt │
                                 │         B/op          │
JQTransform_Simple-4                      1.273Ki ± 0%
JQTransform_ObjectConstruction-4          1.773Ki ± 0%
JQTransform_ArraySelect-4                 2.625Ki ± 0%
JQTransform_Complex-4                     16.22Ki ± 0%
JQTransform_Throughput-4                  1.984Ki ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                 │ benchmark-results.txt │
                                 │       allocs/op       │
JQTransform_Simple-4                        10.00 ± 0%
JQTransform_ObjectConstruction-4            15.00 ± 0%
JQTransform_ArraySelect-4                   30.00 ± 0%
JQTransform_Complex-4                       324.0 ± 0%
JQTransform_Throughput-4                    17.00 ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     990.4n ± 17%
JQTransform_ObjectConstruction-4         1.474µ ±  0%
JQTransform_ArraySelect-4                3.244µ ±  0%
JQTransform_Complex-4                    35.93µ ±  0%
JQTransform_Throughput-4                 1.805µ ±  0%
SSEPublishDelivery-4                     72.60n ±  3%
geomean                                  1.678µ

                                 │ baseline-bench.txt │
                                 │        B/op        │
JQTransform_Simple-4                   1.273Ki ± 0%
JQTransform_ObjectConstruction-4       1.773Ki ± 0%
JQTransform_ArraySelect-4              2.625Ki ± 0%
JQTransform_Complex-4                  16.22Ki ± 0%
JQTransform_Throughput-4               1.984Ki ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │
                                 │     allocs/op      │
JQTransform_Simple-4                     10.00 ± 0%
JQTransform_ObjectConstruction-4         15.00 ± 0%
JQTransform_ArraySelect-4                30.00 ± 0%
JQTransform_Complex-4                    324.0 ± 0%
JQTransform_Throughput-4                 17.00 ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                       1.128µ ± 3%
SchemaValidation_AllFields-4                    1.693µ ± 9%
SchemaValidation_FormatValidation-4             1.595µ ± 2%
SchemaValidation_ManySchemas-4                  1.849µ ± 1%
geomean                                         1.541µ

                                    │ benchmark-results.txt │
                                    │         B/op          │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

                                    │ benchmark-results.txt │
                                    │       allocs/op       │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                    1.009µ ± 5%
SchemaValidation_AllFields-4                 1.541µ ± 7%
SchemaValidation_FormatValidation-4          1.487µ ± 0%
SchemaValidation_ManySchemas-4               1.508µ ± 2%
geomean                                      1.366µ

                                    │ baseline-bench.txt │
                                    │        B/op        │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │
                                    │     allocs/op      │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   1.186µ ± 11%
EventStoreAppend_SQLite-4                     2.226m ± 16%
GetTimeline_InMemory/events-10-4              14.33µ ±  5%
GetTimeline_InMemory/events-50-4              77.92µ ± 20%
GetTimeline_InMemory/events-100-4             124.7µ ±  1%
GetTimeline_InMemory/events-500-4             637.0µ ±  1%
GetTimeline_InMemory/events-1000-4            1.313m ±  0%
GetTimeline_SQLite/events-10-4                107.8µ ±  1%
GetTimeline_SQLite/events-50-4                249.0µ ±  1%
GetTimeline_SQLite/events-100-4               422.4µ ±  0%
GetTimeline_SQLite/events-500-4               1.812m ±  2%
GetTimeline_SQLite/events-1000-4              3.584m ±  1%
geomean                                       230.6µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                    765.5 ± 12%
EventStoreAppend_SQLite-4                    1.985Ki ±  2%
GetTimeline_InMemory/events-10-4             7.953Ki ±  0%
GetTimeline_InMemory/events-50-4             46.62Ki ±  0%
GetTimeline_InMemory/events-100-4            94.48Ki ±  0%
GetTimeline_InMemory/events-500-4            472.8Ki ±  0%
GetTimeline_InMemory/events-1000-4           944.3Ki ±  0%
GetTimeline_SQLite/events-10-4               16.74Ki ±  0%
GetTimeline_SQLite/events-50-4               87.14Ki ±  0%
GetTimeline_SQLite/events-100-4              175.4Ki ±  0%
GetTimeline_SQLite/events-500-4              846.1Ki ±  0%
GetTimeline_SQLite/events-1000-4             1.639Mi ±  0%
geomean                                      67.17Ki

                                   │ benchmark-results.txt │
                                   │       allocs/op       │
EventStoreAppend_InMemory-4                     7.000 ± 0%
EventStoreAppend_SQLite-4                       53.00 ± 2%
GetTimeline_InMemory/events-10-4                125.0 ± 0%
GetTimeline_InMemory/events-50-4                653.0 ± 0%
GetTimeline_InMemory/events-100-4              1.306k ± 0%
GetTimeline_InMemory/events-500-4              6.514k ± 0%
GetTimeline_InMemory/events-1000-4             13.02k ± 0%
GetTimeline_SQLite/events-10-4                  382.0 ± 0%
GetTimeline_SQLite/events-50-4                 1.852k ± 0%
GetTimeline_SQLite/events-100-4                3.681k ± 0%
GetTimeline_SQLite/events-500-4                18.54k ± 0%
GetTimeline_SQLite/events-1000-4               37.29k ± 0%
geomean                                        1.162k

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.126µ ± 28%
EventStoreAppend_SQLite-4                  1.265m ±  7%
GetTimeline_InMemory/events-10-4           13.67µ ±  4%
GetTimeline_InMemory/events-50-4           77.66µ ±  4%
GetTimeline_InMemory/events-100-4          149.8µ ± 19%
GetTimeline_InMemory/events-500-4          622.1µ ±  1%
GetTimeline_InMemory/events-1000-4         1.259m ±  1%
GetTimeline_SQLite/events-10-4             83.67µ ±  2%
GetTimeline_SQLite/events-50-4             238.4µ ±  2%
GetTimeline_SQLite/events-100-4            423.1µ ±  1%
GetTimeline_SQLite/events-500-4            1.908m ±  1%
GetTimeline_SQLite/events-1000-4           3.763m ±  1%
geomean                                    216.7µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  826.0 ± 4%
EventStoreAppend_SQLite-4                  1.985Ki ± 2%
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%
geomean                                    67.60Ki

                                   │ baseline-bench.txt │
                                   │     allocs/op      │
EventStoreAppend_InMemory-4                  7.000 ± 0%
EventStoreAppend_SQLite-4                    53.00 ± 0%
GetTimeline_InMemory/events-10-4             125.0 ± 0%
GetTimeline_InMemory/events-50-4             653.0 ± 0%
GetTimeline_InMemory/events-100-4           1.306k ± 0%
GetTimeline_InMemory/events-500-4           6.514k ± 0%
GetTimeline_InMemory/events-1000-4          13.02k ± 0%
GetTimeline_SQLite/events-10-4               382.0 ± 0%
GetTimeline_SQLite/events-50-4              1.852k ± 0%
GetTimeline_SQLite/events-100-4             3.681k ± 0%
GetTimeline_SQLite/events-500-4             18.54k ± 0%
GetTimeline_SQLite/events-1000-4            37.29k ± 0%
geomean                                     1.162k

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

…ription

Co-authored-by: intel352 <77607+intel352@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 12, 2026

@copilot apply changes based on the comments in this thread

Ensure all linters, tests, config vali...

Done in b197df5. Three changes applied:

  1. Validation (SetEndpoints now returns error): paths must start with / and all four paths must be distinct. Init() also runs the same validation as defense-in-depth. The factory propagates SetEndpoints errors via SetInitErr. New tests cover missing leading slash, duplicate paths, and that an invalid call leaves state unchanged.

  2. Data race fix: SetEndpoints acquires m.mu.Lock() before mutating endpointPaths; Handle() copies endpointPaths under m.mu.RLock() before the routing switch. Confirmed clean with go test -race.

  3. Schema description: updated to clarify that values are matched via strings.HasSuffix (so a router mount prefix is allowed) and that paths must start with / and be distinct.

@intel352 intel352 merged commit 88fe2ed into main Mar 12, 2026
11 checks passed
@intel352 intel352 deleted the copilot/support-configurable-route-path-suffixes branch March 12, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

auth.m2m: Support configurable route path suffixes for OAuth2 endpoints

3 participants