Skip to content

feat(jira): add flyteplugins-jira - #1517

Merged
cosmicBboy merged 2 commits into
nielsb/webhooks-clickupfrom
nielsb/webhooks-jira
Sep 2, 2026
Merged

feat(jira): add flyteplugins-jira#1517
cosmicBboy merged 2 commits into
nielsb/webhooks-clickupfrom
nielsb/webhooks-jira

Conversation

@cosmicBboy

Copy link
Copy Markdown
Collaborator

Part of the webhook plugin stack. Requires #1512 (flyteplugins-webhooks-core), which is this PR's base — the diff here is just this package.

Receive Jira webhooks in Flyte.

What it implements

The Provider contract from core: which environment variable holds the secret, how to verify a delivery, how to parse one into a WebhookEvent, plus typed constants for every event Jira sends.

Verification: none — Jira Cloud does not sign its webhooks.

Because there is no signature, this plugin authenticates with a shared token in X-Webhook-Token, which something in front of the app has to inject since Jira cannot send custom headers. PROVIDER.signed is False, so the dashboard says the product does not sign rather than implying a guarantee that is absent.

This is the plugin that made the conformance harness better: it caught that a shared token, unlike an HMAC, is not bound to the request body, so a tampered payload still verifies. That is inherent to an unsigned webhook rather than a bug here, and signed=False now opts out of that one check explicitly instead of the harness quietly passing.

Conformance

Runs the shared assert_provider_conforms, which replays this plugin's SAMPLE_DELIVERY — a real Jira payload — through verify and parse rather than trusting them to agree with each other. It also asserts the verifier returns False rather than raising on a hostile header, that event constants render as wire values rather than enum names, and that the sample parses to something the constants actually spell.

6 tests. make fmt, make mypy, make ty, ruff, and codespell pass.

What it does not do

Call the Jira API. Use the jira package directly from your tasks — the recipes are in the examples PR at the end of this stack. This plugin owns only the part that is Flyte's: authenticating an inbound delivery and turning it into a run.

@cosmicBboy
cosmicBboy force-pushed the nielsb/webhooks-clickup branch from 410aa4a to d1b3007 Compare September 1, 2026 17:36
@cosmicBboy
cosmicBboy marked this pull request as ready for review September 1, 2026 17:54
@cosmicBboy
cosmicBboy force-pushed the nielsb/webhooks-clickup branch from d1b3007 to 69f870c Compare September 1, 2026 18:29
@cosmicBboy
cosmicBboy force-pushed the nielsb/webhooks-clickup branch from 69f870c to 7e85ea9 Compare September 1, 2026 18:54
@cosmicBboy
cosmicBboy force-pushed the nielsb/webhooks-clickup branch from 7e85ea9 to 8e7e70f Compare September 2, 2026 00:56
@cosmicBboy cosmicBboy changed the title feat(webhooks): flyteplugins-webhooks-jira feat(jira): add flyteplugins-jira Sep 2, 2026
@cosmicBboy
cosmicBboy force-pushed the nielsb/webhooks-clickup branch from 8e7e70f to 3ad4f51 Compare September 2, 2026 01:03
Receive Jira webhooks in Flyte. Exports JiraProvider, a Provider subclass with its
defaults pre-wired, so wiring it up reads:

    WebhookAppEnvironment(providers=[JiraProvider()])

The receiver itself ships with flyte, at flyte.extras.webhooks; this package
contributes only what is specific to Jira -- which environment variable holds
the secret, how to verify a delivery, how to parse one into a WebhookEvent, and
typed constants for every event Jira sends.

examples/jira_webhooks.py runs with no Jira account at all: --local replays
this plugin's own SAMPLE_DELIVERY through the app. The shared conformance check
exercises that same sample.

The package is named for the product rather than for webhooks, so client
methods can land here later when they earn their place -- as review_pr does in
flyteplugins-github, where flyte.new_condition is the part no vendor SDK can
provide. Plain API passthrough belongs in the vendor's own SDK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKZrTNjjWVzTZUxDFbn4Nk
Signed-off-by: Niels Bantilan <niels.bantilan@gmail.com>
@cosmicBboy
cosmicBboy force-pushed the nielsb/webhooks-clickup branch from 3ad4f51 to 42db125 Compare September 2, 2026 01:32
…1518)

Last of the webhook plugin stack (#1512#1517), based on #1517 so every
import resolves.

Worked recipes for driving GitHub, Slack, Linear, ClickUp, and Jira from
Flyte, plus one app receiving webhooks from all five.

## The argument these examples make

There is deliberately **no Flyte client plugin** for these products.
Each vendor already ships (or the community maintains) a Python client
tested against the live API by people who get deprecation notices first,
and a task is just a function — so calling `PyGithub` or `slack_sdk`
from a task needs nothing in between. A wrapper would only add a surface
to keep in sync with someone else's release calendar.

What Flyte contributes, and what these use:

- `flyteplugins-webhooks-*` — authenticate an inbound delivery and
normalize it
- `idempotent_run` — launch a run once per event key
- `flyte.new_condition` — park a run on a human decision with a typed
payload back

| File | Shows | Client |
| --- | --- | --- |
| `webhook_receiver.py` | One app receiving from all five products |
`flyteplugins-webhooks-*` |
| `github_pr_review_gate.py` | Human-gated merge: a condition carrying
JSON, parsed into a typed decision | `PyGithub` |
| `github_triage_pr.py` | Label, comment, report a check run |
`PyGithub` |
| `slack_notify.py` | Post, thread, react, answer a mention |
`slack_sdk` |
| `linear_triage_issue.py` | Query a backlog and comment, over GraphQL |
`gql` |
| `clickup_manage_ticket.py` | Open and close tickets, with a status
pre-check | `httpx` |
| `jira_manage_ticket.py` | Open, transition, and search issues | `jira`
|

Linear and ClickUp ship no official Python SDK — Linear's API is a
single GraphQL endpoint so `gql` is the maintained client, and ClickUp's
is a handful of REST calls where `httpx` directly beats a thin
third-party wrapper.

The review gate is here rather than in a plugin because
`flyte.new_condition` is the only part of it that needed inventing; the
rest is PyGithub calls.

## One thing I fixed while writing them

Task names are **environment-qualified** — `triage_pr` in
`github_triage_pr.py` deploys as `github-triage.triage_pr`, which is
what the receiver looks up. Bare names never resolve, and both the
Linear and Jira recipes define a `triage_issue`, so the qualifier is
also what keeps them apart. There is a check that every name the
receiver launches is actually defined; the original per-product examples
this replaces had bare names throughout and would have failed at the
first real event.

## Verification

Verified mechanically rather than by eye: every referenced example path
resolves, every `flyte create secret` name matches the actual provider
`secret_env`, every `flyte deploy <file> <env>` names a real
`TaskEnvironment`, every `flyte run` task is defined, and every example
file executes (the receiver registers all five handlers).

`make fmt`, `make mypy`, `make ty`, ruff, and codespell pass.

Signed-off-by: Niels Bantilan <niels.bantilan@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cosmicBboy
cosmicBboy merged commit d1e6896 into nielsb/webhooks-clickup Sep 2, 2026
62 checks passed
@cosmicBboy
cosmicBboy deleted the nielsb/webhooks-jira branch September 2, 2026 02:04
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