Skip to content

gRPC (AIO) missing None check for when RPC method not implemented #3108

Closed
@ordinary-jamie

Description

@ordinary-jamie

How do you use Sentry?

Sentry Saas (sentry.io)

Version

master

Steps to Reproduce

Call an unimplemented RPC for an gRPC.AIO server using Sentry SDK

Reproducer:

  1. pip install sentry-sdk grpcio grpcio-tools
  2. Get sample Protobuf stubs (grpc/grpc HelloWorld)
# Get a sample protobuf, helloworld proto
curl https://raw.githubusercontent.com/grpc/grpc/v1.62.0/examples/protos/helloworld.proto > helloworld.proto

# Generate stubs
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. --pyi_out=. *.proto

Run test script:

"""Missing None check replication for gRPC AIO."""

import asyncio
import contextlib
import logging

import grpc.aio as grpc
import helloworld_pb2
import helloworld_pb2_grpc
import sentry_sdk
from sentry_sdk.integrations.grpc import GRPCIntegration


@contextlib.asynccontextmanager
async def test_server(port: int = 50051):
    server = grpc.server()
    server.add_insecure_port(f"[::]:{port}")

    try:
        await server.start()
        yield
    finally:
        await server.stop(grace=None)


async def client(port: int = 50051):
    async with grpc.insecure_channel(f"[::]:{port}") as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        try:
            return await stub.SayHello(helloworld_pb2.HelloRequest(name="Jamie"))
        except grpc.AioRpcError as exc:
            print(exc.details())


async def test():
    port = 50051

    async with test_server(port=port):
        await client(port=port)


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    sentry_sdk.init(integrations=[GRPCIntegration()])
    asyncio.run(test())

Expected Result

Expected RPC error "Method not found!"

Note, grpc.aio.ServerInterceptors should return None if they have not serviced the RPC:

https://grpc.github.io/grpc/python/grpc_asyncio.html#grpc.aio.ServerInterceptor

Returns: An RpcMethodHandler with which the RPC may be serviced if the interceptor chooses to service this RPC, or None otherwise.

Actual Result

ERROR:grpc._cython.cygrpc:Unexpected [AttributeError] raised by servicer method [/helloworld.Greeter/SayHello]
Traceback (most recent call last):
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 689, in grpc._cython.cygrpc._handle_exceptions
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 789, in _handle_rpc
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 383, in _find_method_handler
  File "src/python/grpcio/grpc/_cython/_cygrpc/aio/server.pyx.pxi", line 360, in _run_interceptor
  File ".direnv/python-3.12/lib/python3.12/site-packages/sentry_sdk/integrations/grpc/aio/server.py", line 33, in intercept_service
    if not handler.request_streaming and not handler.response_streaming:
           ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'request_streaming'
Unexpected <class 'AttributeError'>: 'NoneType' object has no attribute 'request_streaming'

Metadata

Metadata

Assignees

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions