Repository navigation
feat(#7821): let a listed trusted proxy vouch for the gRPC CreateApiToken transport - #8891
Conversation
…oken transport The gRPC interceptor now reads arcadedb.server.apiTokenTrustedProxies, the same list the HTTP mint uses, and believes the x-forwarded-proto metadata key only from a listed peer, requiring https for every value. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
This pull request does not currently match the merge queue conditions, so it cannot be queued from here. The box comes back if it matches again. |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 16 |
🟢 Coverage 100.00% diff coverage · -5.90% coverage variation
Metric Results Coverage variation ✅ -5.90% coverage variation Diff coverage ✅ 100.00% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (6c2a724) 206367 174647 84.63% Head commit (62c6b99) 238995 (+32628) 188168 (+13521) 78.73% (-5.90%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#8891) 50 50 100.00% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (2)
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe gRPC transport interceptor now accepts cleartext token-creation calls from configured trusted proxies when every ChangesTrusted proxy support for gRPC token creation
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Feature · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant GrpcServerPlugin
participant GrpcTransportSecurityInterceptor
participant ArcadeDbGrpcAdminService
GrpcServerPlugin->>GrpcTransportSecurityInterceptor: Install interceptor with server configuration
GrpcTransportSecurityInterceptor->>GrpcTransportSecurityInterceptor: Check peer address and x-forwarded-proto metadata
GrpcTransportSecurityInterceptor->>ArcadeDbGrpcAdminService: Publish transport-safety result in gRPC context
ArcadeDbGrpcAdminService->>ArcadeDbGrpcAdminService: Reject token creation if transport is unsafe
Merge Risk: ⚪ Minimal · up to No actionable merge-blocking issue is established. Trusted-proxy support preserves the existing TLS and loopback paths and requires trusted peers with HTTPS-only forwarded metadata; merge after normal checks pass. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change adds an explicit proxy trust path while preserving authentication, administrator authorization, and fail-closed transport checks. Its security depends on accurate proxy headers and a protected proxy-to-server network. No introduced authorization bypass was established, but deployment and concurrent revocation coverage remain incomplete. Retained concerns Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review of #8891Overall this is a clean, well-scoped change. The security shape is right: the metadata is read only when the direct peer is on the list, the default (empty list) leaves it unread, an unparseable list fails closed, every Suggestions (non-blocking)
Operational note (docs)The scheme relies on the proxy listed being the address ArcadeDB sees as the direct peer (not the client). Envoy overwrites Test coverageGood: 12 new unit tests covering the forgery case, CIDR, live setting change, throwing supplier and the LGTM modulo the nits above. |
… pin the gate, add mapped/padded tests Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review of #8891 (gRPC CreateApiToken behind a trusted proxy)Overall this is a clean, well-scoped change. The trust decision is the same as the HTTP gate from #7804, the shared helpers avoid a second CIDR/https parser, the default (empty list) leaves the metadata unread, and failure modes all fail closed (unparseable list, throwing supplier, null/unresolved peer, non-IP transport). I found no blocking issues. What I checked
Suggestions (non-blocking)
Style nits
Nice work on the mutation check and the live-setting tests. Fine to merge from my side once the description/wrapper mismatch in item 1 is settled. 🤖 Generated with Claude Code |
…on the setting, shorter plugin comment Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review of #8891 (gRPC
|
…nterceptor Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Review of #8891 (trusted proxy vouching for gRPC
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8891 +/- ##
=========================================
Coverage 76.37% 76.38%
- Complexity 3800 3802 +2
=========================================
Files 2104 2105 +1
Lines 206367 206401 +34
Branches 43491 43497 +6
=========================================
+ Hits 157620 157659 +39
+ Misses 31762 31760 -2
+ Partials 16985 16982 -3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Closes #7821
Summary
Decision on the issue's question: yes, the gRPC interceptor reads the same
arcadedb.server.apiTokenTrustedProxieslist. gRPC metadata travels as HTTP/2 headers, so a TLS-terminating L7 proxy reports the client scheme as thex-forwarded-protometadata key: Envoy adds it to gRPC requests on its own, and nginxgrpc_passadds it withgrpc_set_header X-Forwarded-Proto $scheme.GrpcTransportSecurityInterceptornow marks a cleartext call as safe for secrets when the direct peer is on the list AND everyx-forwarded-protovalue reportshttps, on exactly the terms of the HTTP gate from #7804. Parsing and the "every hop https" check are shared, not copied: they moved fromPostApiTokenHandlerinto the newcom.arcadedb.server.security.ApiTokenTrustedProxies(parse,forwardedProtoIsFullyEncrypted), which both the interceptor and the HTTP handler call (the handler keeps package-private one-line delegates its existing tests use). With the list empty (the default), the metadata is never read and the decision is the TLS-or-loopback test #7309 shipped.GrpcTransportSecurityInterceptor.forConfiguration(server.getConfiguration()), soSET SERVER SETTINGtakes effect on the next call (same as HTTP). The parsed list is cached keyed by the setting text, because the interceptor runs on every call, not only on mints.FAILED_PRECONDITIONrefusal now namesarcadedb.server.apiTokenTrustedProxiesand the metadata key.ServerControlPlane.createApiTokenandPostApiTokenHandlerjavadocs mention the gRPC side.Completeness
Invariant: the gRPC and HTTP mints accept the same transports - TLS, loopback, or a listed proxy reporting https on every hop.
GrpcServerPluginstandard + xDS builders (sharedinterceptpath)forConfigurationArcadeDbGrpcAdminService.createApiToken(only reader ofSECRET_SAFE_TRANSPORT_KEY)PostApiTokenHandlerApiTokenTrustedProxiesCreateApiTokenisrequireLeader, it is refused on a follower, not forwardedKnown gaps: None.
Test plan
ApiTokenTrustedProxiesTest(new, server): the shared contract pinned independent of both callersIssue7821GrpcTrustedProxyWiringTest: the plugin-registered interceptor honors the live server settingGrpcTransportSecurityInterceptorTest(21 tests, 14 new; incl. gate true/false/unset, IPv4-mapped peer, padded value): listed proxy + https, CIDR, unlisted peer forging the key, empty/null list, cleartext/empty/trailing-comma values, appended values (https,http), unparseable list, live setting change, TLS/loopback never narrowed, throwing supplier,forConfigurationfactory read live, refusal message names the settingfalsefails 5 of the new testsmvn verify -pl grpcwunit tests: 305 run, 0 failuresIssue7309GrpcSecurityControlPlaneIT: 18/18 (real server mint over loopback still works through the new factory)Issue7804*,Issue7372*,Issue8109*,*ApiToken*: 81/81Adversarial pass
The subagent tool was not available in this run, so the Phase 1.5 pass was done inline against the diff:
x-forwarded-protobehind an appending proxy: covered by requiring every value to be https (testeveryForwardedValueMustBeHttps).Review cycles
0418a3c- claude: LGTM with suggestions. Applied: helpers moved to neutralApiTokenTrustedProxies; gate pinned for true/false/unset; IPv4-mapped + padded-value tests; javadoc rewrap, comment placement, import grouping.57c13fa- claude: no blockers. Applied: PR description corrected (it still said the helpers were made public); directApiTokenTrustedProxiesTest; L4-balancer caveat added to the setting description; shorter plugin comment.cd9583a- claude: LGTM, optional suggestions. Applied:Issue7821GrpcTrustedProxyWiringTestpins thatGrpcServerPlugin.configureServerregisters the list-reading interceptor (mutation-checked: registeringnew GrpcTransportSecurityInterceptor()fails it); comment on why the server configuration, not theconfigargument, is used.62c6b99- claude: "No blocking issues ... good to merge". Not acted on (max cycles reached), see deferred items.Final state: max-cycles-reached (the last review had no blockers; one optional wording item remains).
Deferred / skipped items
String.equalsagainst the cached text; the reviewer agreed it is not worth restricting to the mint method.requireTransportSafeForSecretsvisibility" (cycle 2, Bump mongo-java-driver from 3.12.4 to 3.12.10 #4) - skipped: package-private static only reads the Context key; covered by the gate tests.forConfigurationfactory test.PostApiTokenHandler: point tests atApiTokenTrustedProxiesand delete them" (cycle 3, Bump slf4j-simple.version from 1.7.31 to 1.7.32 #3) - skipped: churn across the existing Decide when arcadedb.server.apiTokenRequireSecureTransport should default to true #7804 tests for no behavior change.PostApiTokenHandler?" (cycle 4, build support #1) - verified not real:LogManager,Level(line 184) andIPAddressBlocklist(lines 169, 192, 248) are all still used.use_remote_address: true, which overwrites the header). Envoy behind another hop, withuse_remote_address: false, preserves an inbound value ... a short 'and does not trust a client-supplied value' qualifier would keep that guidance consistent." Valid wording refinement of theapiTokenTrustedProxiesdescription; not pushed because the cycle budget was spent.providedserver dependency" (cycle 4, Bump slf4j-simple.version from 1.7.31 to 1.7.32 #3) - not real for this PR: grpcw already depends on manyarcadedb-serverclasses at the same version; the distribution always ships server.CreateApiTokenis accepted via a proxy" (cycle 4, Bump mongo-java-driver from 3.12.4 to 3.12.10 #4, optional) - follow-up material only if operators ask.🤖 Generated with Claude Code