feat(pipeline): Add OrganizationPipelineEndpoint for API-driven pipelines#111539
Conversation
| except NotRegistered: | ||
| return Response({"detail": f"Unknown provider: {provider_id}"}, status=404) | ||
| except IntegrationPipelineError as e: | ||
| return Response({"detail": str(e)}, status=404 if e.not_found else 400) |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
In general, to fix this problem we should avoid returning raw exception messages to the client. Instead, we should: (1) log the exception (with stack trace) on the server for debugging; and (2) send a generic, non-sensitive error message in the HTTP response. If we still need to differentiate between “not found” and “bad request”, we can keep using e.not_found for the status code while hiding the detailed message.
In this specific file, the minimal and safest change is to modify the except IntegrationPipelineError as e: block in _initialize_pipeline. We should import logger is already defined (logging.getLogger(__name__)), so we can use that to log the error. Then change the response JSON so that it no longer includes str(e); instead, use a generic message such as "Failed to initialize integration pipeline." while preserving the existing status code decision. No other logic needs to change, and no new external dependencies are required.
Concretely:
- In
src/sentry/api/endpoints/organization_pipeline.py, at theexcept IntegrationPipelineError as e:clause (around lines 116–117), insert a call likelogger.exception("Failed to initialize integration pipeline for provider %s", provider_id)to log the full exception and stack trace. - Replace
{"detail": str(e)}with a fixed string, e.g.{"detail": "Failed to initialize integration pipeline."}. - Keep using
status=404 if e.not_found else 400to preserve the existing behavior regarding HTTP status codes.
| @@ -114,7 +114,13 @@ | ||
| except NotRegistered: | ||
| return Response({"detail": f"Unknown provider: {provider_id}"}, status=404) | ||
| except IntegrationPipelineError as e: | ||
| return Response({"detail": str(e)}, status=404 if e.not_found else 400) | ||
| logger.exception( | ||
| "Failed to initialize integration pipeline for provider %s", provider_id | ||
| ) | ||
| return Response( | ||
| {"detail": "Failed to initialize integration pipeline."}, | ||
| status=404 if e.not_found else 400, | ||
| ) | ||
|
|
||
| if not pipeline.is_api_ready(): | ||
| return Response({"detail": "Pipeline does not support API mode."}, status=400) |
7d65b9f to
0493c31
Compare
| except StopIteration: | ||
| return Response({"detail": "Invalid pipeline type"}, status=404) | ||
|
|
||
| pipeline = pipeline_cls.get_for_request(request._request) |
There was a problem hiding this comment.
If I understand right, we have only one state for integration pipelines and one state for auth pipelines. So if a user stats an integration pipeline (say github), then part way through abandons it and starts another (say gitlab), is there any way that cause this to have problems?
There was a problem hiding this comment.
I think that would be a problem even today actually.
There was a problem hiding this comment.
I think this would only happen if they did the slack setup pipeline, then later the identity slack pipeline though
| return [DummyStep()] | ||
|
|
||
|
|
||
| class NonApiPipeline(Pipeline[Never, PipelineSessionStore]): |
There was a problem hiding this comment.
I don't totally understand what Never represents here
There was a problem hiding this comment.
The first parameter is the Model associated to the pipeline. This one doesn't have a model so it's Never.
0493c31 to
ab46a65
Compare
|
🚨 Warning: This pull request contains Frontend and Backend changes! It's discouraged to make changes to Sentry's Frontend and Backend in a single pull request. The Frontend and Backend are not atomically deployed. If the changes are interdependent of each other, they must be separated into two pull requests and be made forward or backwards compatible, such that the Backend or Frontend can be safely deployed independently. Have questions? Please ask in the |
e61ed52 to
b13b88d
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 4 total unresolved issues (including 2 from previous reviews).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
4b7b022 to
7be2894
Compare
8cbf377 to
7be2894
Compare
6595ded to
5e884b8
Compare
…ines Add a new REST endpoint that allows driving integration pipelines via JSON API requests instead of the legacy redirect-based flow. The endpoint supports initializing a pipeline (POST with action=initialize), retrieving the current step info (GET), and advancing through steps (POST with step-specific data). Uses ControlSiloOrganizationEndpoint as the base class since integration models live in the control silo, requiring the RPC service layer to resolve organizations from slugs. The endpoint rejects pipelines that don't support API mode with a 400, and returns structured errors for invalid providers, missing sessions, and unsupported pipeline names. Refs VDY-36
8415c30 to
95f784e
Compare

Add a new REST endpoint that allows driving integration pipelines via
JSON API requests instead of the legacy redirect-based flow. The
endpoint supports initializing a pipeline (POST with action=initialize),
retrieving the current step info (GET), and advancing through steps
(POST with step-specific data).
Uses ControlSiloOrganizationEndpoint as the base class since integration
models live in the control silo, requiring the RPC service layer to
resolve organizations from slugs.
The endpoint rejects pipelines that don't support API mode with a 400,
and returns structured errors for invalid providers, missing sessions,
and unsupported pipeline names.
Refs VDY-36
Requires #111454