Skip to content

fix: Stop swagger-ui redirect loop, split main()#899

Merged
gtema merged 1 commit into
mainfrom
binary-optimize
Jul 2, 2026
Merged

fix: Stop swagger-ui redirect loop, split main()#899
gtema merged 1 commit into
mainfrom
binary-optimize

Conversation

@gtema

@gtema gtema commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

NormalizePathLayer wrapped SwaggerUi along with the API router, so
trimming the trailing slash raced SwaggerUi's own "/swagger-ui" ->
"/swagger-ui/" redirect into an infinite loop (utoipa#1467). SwaggerUi
is now mounted via fallback_service outside the normalized service.

  • extract main() into init_tracing, init_audit, subscribe_event_hooks,
    build_router, start_raft, spawn_opa_subprocess, and per-interface
    listener functions
  • wrap the audit KEK in SecretBox so it zeroizes on drop
  • return Result from spawn_internal_listener instead of logging and
    continuing on a non-SPIFFE internal-interface misconfiguration
  • replace axum::serve(...).unwrap() on the public listener with the
    same log-and-cancel pattern used by the other listeners
  • fix extract_provider_name's &Box clippy lint, allow
    get_domain's currently-unused-but-tested dead code
  • add regression tests for the swagger-ui fix, trailing-slash
    normalization, and audit KEK generate/reuse/reject-bad-length

Signed-off-by: Artem Goncharov artem.goncharov@gmail.com

@gtema gtema force-pushed the binary-optimize branch from e89f969 to 4e9d811 Compare July 2, 2026 09:00
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

🦢 Load Test Results

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 26-07-02 09:44:00 26-07-02 09:44:11 00:00:11 0 → 20
Maintaining 26-07-02 09:44:11 26-07-02 09:44:41 00:00:30 20
Decreasing 26-07-02 09:44:41 26-07-02 09:45:20 00:00:39 0 ← 20

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
DELETE DELETE /v3/auth/tokens 602 0 59.22 9 78 20.07 0.00
DELETE DELETE /v3/projects/:id (teardown) 2 0 27.50 18 37 0.07 0.00
DELETE DELETE /v3/users/:id (teardown) 3 0 29.67 23 35 0.10 0.00
GET 5394 0 55.30 37 111 179.80 0.00
GET GET /v3/auth/tokens (validate new) 602 2 258.43 29 60001 20.07 0.07
GET GET /v3/projects/:id 1311 0 45.41 38 68 43.70 0.00
GET GET /v3/users/:id 1829 0 48.86 40 74 60.97 0.00
POST POST /v3/auth/tokens 599 0 44.63 38 59 19.97 0.00
Aggregated 10342 2 64.33 9 60001 344.73 0.07

Response Time Metrics

Method Name 50%ile (ms) 60%ile (ms) 70%ile (ms) 80%ile (ms) 90%ile (ms) 95%ile (ms) 99%ile (ms) 100%ile (ms)
DELETE DELETE /v3/auth/tokens 59 60 61 63 65 66 72 78
DELETE DELETE /v3/projects/:id (teardown) 18 18 18 37 37 37 37 37
DELETE DELETE /v3/users/:id (teardown) 31 31 31 31 35 35 35 35
GET 49 52 55 62 85 88 94 110
GET GET /v3/auth/tokens (validate new) 59 60 61 62 64 67 71 60,000
GET GET /v3/projects/:id 45 46 47 48 49 51 56 68
GET GET /v3/users/:id 49 49 50 51 53 55 59 74
POST POST /v3/auth/tokens 44 45 46 47 48 49 54 59
Aggregated 48 51 54 58 77 85 92 60,000

Status Code Metrics

Method Name Status Codes
DELETE DELETE /v3/auth/tokens 602 [204]
DELETE DELETE /v3/projects/:id (teardown) 2 [204]
DELETE DELETE /v3/users/:id (teardown) 3 [204]
GET 5,394 [200]
GET GET /v3/auth/tokens (validate new) 600 [200], 2 [0]
GET GET /v3/projects/:id 1,311 [200]
GET GET /v3/users/:id 1,829 [200]
POST POST /v3/auth/tokens 599 [200]
Aggregated 2 [0], 9,733 [200], 607 [204]

Transaction Metrics

Transaction # Times Run # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
ReadHeavy
0.0 1 0 26.00 26 26 0.03 0.00
0.1 1449 0 53.91 46 72 48.30 0.00
0.2 1449 0 45.13 38 65 48.30 0.00
0.3 1449 0 44.97 37 64 48.30 0.00
TokenLifecycle
1.0 0 0 0.00 0 0 0.00 0.00
1.1 602 0 363.41 85 60057 20.07 0.00
ValidateToken
2.0 0 0 0.00 0 0 0.00 0.00
2.1 1047 0 85.82 75 111 34.90 0.00
UserCRUD
3.0 0 0 0.00 0 0 0.00 0.00
3.1 0 0 0.00 0 0 0.00 0.00
3.2 1829 0 48.92 40 74 60.97 0.00
3.3 3 0 29.67 23 35 0.10 0.00
ProjectCRUD
4.0 0 0 0.00 0 0 0.00 0.00
4.1 0 0 0.00 0 0 0.00 0.00
4.2 1311 0 45.47 38 68 43.70 0.00
4.3 2 0 27.50 18 37 0.07 0.00
Aggregated 9142 0 72.77 18 60057 304.73 0.00

Scenario Metrics

Transaction # Users # Times Run Average (ms) Min (ms) Max (ms) Scenarios/s Iterations
ReadHeavy 7 1445 145.03 130 181 48.17 206.43
TokenLifecycle 4 597 164.71 147 197 19.90 149.25
ValidateToken 3 1044 85.83 75 111 34.80 348.00
UserCRUD 3 1826 48.92 40 74 60.87 608.67
ProjectCRUD 2 1309 45.48 38 68 43.63 654.50
Aggregated 19 6221 87.83 38 197 207.37 1966.85

Error Metrics

Method Name # Error
GET GET /v3/auth/tokens (validate new) 2 error sending request GET /v3/auth/tokens (validate new): operation timed out

View full report

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

🐰 Bencher Report

Branchbinary-optimize
Testbedubuntu-latest

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
Raft_1Node_Latency/read/1nodeLatency
microseconds (µs)
📈 plot
🚷 threshold
🚨 alert (🔔)
45.38 µs
(+473.59%)Baseline: 7.91 µs
45.07 µs
(100.67%)

Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
Command_Serde/apply/remove📈 view plot
🚷 view threshold
152,220.00 ns
(-46.16%)Baseline: 282,750.36 ns
1,686,273.19 ns
(9.03%)
Command_Serde/apply/set📈 view plot
🚷 view threshold
168,490.00 ns
(-27.81%)Baseline: 233,398.47 ns
983,564.80 ns
(17.13%)
Command_Serde/pack/delete📈 view plot
🚷 view threshold
121.44 ns
(+0.97%)Baseline: 120.27 ns
141.84 ns
(85.61%)
Command_Serde/pack/delete_index📈 view plot
🚷 view threshold
110.14 ns
(+0.40%)Baseline: 109.70 ns
129.32 ns
(85.17%)
Command_Serde/pack/set📈 view plot
🚷 view threshold
192.09 ns
(-0.38%)Baseline: 192.82 ns
230.80 ns
(83.23%)
Command_Serde/pack/set_index📈 view plot
🚷 view threshold
112.00 ns
(+2.27%)Baseline: 109.51 ns
128.70 ns
(87.02%)
Command_Serde/unpack/delete📈 view plot
🚷 view threshold
201.90 ns
(+4.68%)Baseline: 192.87 ns
233.96 ns
(86.30%)
Command_Serde/unpack/delete_index📈 view plot
🚷 view threshold
160.39 ns
(-0.09%)Baseline: 160.54 ns
195.75 ns
(81.94%)
Command_Serde/unpack/set📈 view plot
🚷 view threshold
275.09 ns
(+5.36%)Baseline: 261.10 ns
322.80 ns
(85.22%)
Command_Serde/unpack/set_index📈 view plot
🚷 view threshold
154.44 ns
(-3.09%)Baseline: 159.37 ns
193.88 ns
(79.66%)
Payload_encryption/pack/remove_cmd📈 view plot
🚷 view threshold
121.67 ns
(+4.49%)Baseline: 116.45 ns
138.79 ns
(87.66%)
Payload_encryption/pack/set_cmd📈 view plot
🚷 view threshold
197.46 ns
(-3.81%)Baseline: 205.28 ns
271.75 ns
(72.66%)
Payload_encryption/unpack/remove_cmd📈 view plot
🚷 view threshold
206.79 ns
(+0.97%)Baseline: 204.80 ns
247.03 ns
(83.71%)
Payload_encryption/unpack/set_cmd📈 view plot
🚷 view threshold
291.44 ns
(+6.51%)Baseline: 273.63 ns
338.80 ns
(86.02%)
Raft_1Node_Latency/prefix/1node📈 view plot
🚷 view threshold
2,536,900.00 ns
(-9.76%)Baseline: 2,811,277.66 ns
5,725,442.99 ns
(44.31%)
Raft_1Node_Latency/read/1node📈 view plot
🚷 view threshold
🚨 view alert (🔔)
45,375.00 ns
(+473.59%)Baseline: 7,910.76 ns
45,071.94 ns
(100.67%)

Raft_1Node_Latency/remove/1node📈 view plot
🚷 view threshold
385,320.00 ns
(-29.48%)Baseline: 546,409.69 ns
2,294,915.48 ns
(16.79%)
Raft_1Node_Latency/write/1node📈 view plot
🚷 view threshold
460,610.00 ns
(-18.64%)Baseline: 566,146.09 ns
2,127,959.36 ns
(21.65%)
build_snapshot/default📈 view plot
🚷 view threshold
108,380.00 ns
(+3.18%)Baseline: 105,036.77 ns
161,656.81 ns
(67.04%)
fernet token/project📈 view plot
🚷 view threshold
1,457.60 ns
(+5.23%)Baseline: 1,385.20 ns
1,623.34 ns
(89.79%)
get_data_keyspace📈 view plot
🚷 view threshold
0.33 ns
(+4.65%)Baseline: 0.32 ns
0.37 ns
(89.48%)
get_db📈 view plot
🚷 view threshold
0.33 ns
(+5.10%)Baseline: 0.32 ns
0.37 ns
(89.98%)
get_fernet_token_timestamp/project📈 view plot
🚷 view threshold
145.27 ns
(+0.34%)Baseline: 144.77 ns
180.36 ns
(80.55%)
get_keyspace📈 view plot
🚷 view threshold
4.45 ns
(-5.45%)Baseline: 4.71 ns
8.75 ns
(50.90%)
🐰 View full continuous benchmarking report in Bencher

NormalizePathLayer wrapped SwaggerUi along with the API router, so
trimming the trailing slash raced SwaggerUi's own "/swagger-ui" ->
"/swagger-ui/" redirect into an infinite loop (utoipa#1467). SwaggerUi
is now mounted via fallback_service outside the normalized service.

- extract main() into init_tracing, init_audit, subscribe_event_hooks,
  build_router, start_raft, spawn_opa_subprocess, and per-interface
  listener functions
- wrap the audit KEK in SecretBox so it zeroizes on drop
- return Result from spawn_internal_listener instead of logging and
  continuing on a non-SPIFFE internal-interface misconfiguration
- replace axum::serve(...).unwrap() on the public listener with the
  same log-and-cancel pattern used by the other listeners
- fix extract_provider_name's &Box<dyn Error> clippy lint, allow
  get_domain's currently-unused-but-tested dead code
- add regression tests for the swagger-ui fix, trailing-slash
  normalization, and audit KEK generate/reuse/reject-bad-length

Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
@gtema gtema force-pushed the binary-optimize branch from 4e9d811 to 6615ff8 Compare July 2, 2026 09:31
@gtema gtema merged commit fa0ed39 into main Jul 2, 2026
31 checks passed
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.

1 participant