feat: pure grpcAuth adapter — translate .http-auth.json profiles into gRPC channel + metadata credentials (#24)#37
Merged
Conversation
… credentials (#24) Introduces src/core/grpcAuth.ts + 15 vitest cases. The adapter takes a ParsedGrpcRequest plus the ResolvedAuth already produced by applyAuth and returns a plain-object GrpcCallCredentials bundle the (upcoming) @grpc/grpc-js wire-up can hand straight to Metadata + ChannelCredentials: - metadata: lowercased, HPACK-safe map of headers to send with the call - tls: TlsMaterial (reuses .http-auth.json clientCert profiles for mTLS) - channelSecurity: plaintext | tls | mtls verdict for picking channel creds - warnings / errors: structured translation notes for the response panel Rules enforced: - Reserved gRPC / http/2 transport headers (te, content-type, grpc-timeout, :authority, Host, hop-by-hop, ...) are stripped with a warning whether they come from the request block or an auth profile. - Metadata keys are validated against the HPACK charset (/^[a-z0-9._-]+$/); invalid keys are dropped with a warning. - apiKey in=query profiles produce a blocking error since gRPC has no URL query string — points users at 'apiKey in=header' instead. - clientCert + grpc:// plaintext is a blocking error (drops the cert to make the mismatch obvious) and the panel keeps rendering the rest of the report. - Auth-profile headers override request-block metadata but emit a warning when they shadow an explicit key so users notice the collision. Pure, VS Code-free, transport-free — lives in src/core/ per AGENTS.md. No new dependencies; @grpc/grpc-js is still deferred to the wire-up slice.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes part of #24.
Next slice on the gRPC track. Pure-core module + tests only — sets up the auth translation the (still-pending)
@grpc/grpc-jswire-up will need at send time.What lands
src/core/grpcAuth.ts—buildGrpcCredentials({ request, auth, authName })→{ metadata, tls?, channelSecurity, warnings, errors }.test/grpcAuth.test.ts— 15 vitest cases covering the rules listed below.Reuses:
ResolvedAuthfromsrc/core/auth.ts(whateverapplyAuthproduces for a profile —headers,query, optionaltls).ParsedGrpcRequestfromsrc/core/grpc.ts(already merged).No dependency changes. Still no
@grpc/grpc-jsin the tree — that ships with the transport slice.Why a dedicated adapter
applyAuthalready knows how to turn anAuthProfileinto HTTP-flavoured pieces, which is what undici wants. gRPC is close but different enough to justify one small translation layer instead of teachingapplyAuthabout gRPC:apiKey in=queryprofiles need to hard-error, not silently drop.te,content-type,:authority,grpc-timeout,Host, hop-by-hop, …). We strip them from both request-block metadata and auth-emitted headers with a warning so users don't spend an hour on a mysteryUNIMPLEMENTED.clientCertmaterial rides at the channel layer via TLS, not per-call metadata. We surface achannelSecurity: 'plaintext' | 'tls' | 'mtls'verdict so the extension layer knows whether to buildcreateInsecure(),createSsl(), orcreateSsl() + createFromSecureContext().grpc://(plaintext) with aclientCertprofile is a hard mismatch — the whole point of a client cert is TLS. We block the send with a clear error message instead of quietly dropping the cert.Rules (mirrored in tests)
te,content-type,:authority,:method,:path,:scheme,:status,grpc-encoding,grpc-accept-encoding,grpc-timeout,user-agent, HTTP/1.1 hop-by-hop headers, andhost./^[a-z0-9._-]+$/after lowering) dropped with a warning.apiKey in=query→ blocking error naming the offending keys.clientCert+grpcs://→channelSecurity: 'mtls'andtlspopulated (PEM or PFX with resolved passphrase).clientCert+grpc://(plaintext) → blocking error,tlscleared,channelSecurity: 'plaintext'for display so the panel can still render the mismatch.What's left on #24
@grpc/grpc-jsclient +ServerReflectionInfostreaming — decodes reflection bytes into theDescriptorIndexshape (whichgrpcPreflightalready consumes).buildGrpcCredentialsintosendGrpcRequest(extension layer) once the transport lands.Verification
npm run lint— cleannpm run typecheck— cleannpm run test:unit— 304 tests pass (23 files, +15 from this PR)