Skip to content

Enable repair of failed Databricks Workflow tasks from Airflow 3 UI - #69998

Open
PrakshiGoyal10 wants to merge 2 commits into
apache:mainfrom
PrakshiGoyal10:databricks-repair-from-airflow-3
Open

Enable repair of failed Databricks Workflow tasks from Airflow 3 UI#69998
PrakshiGoyal10 wants to merge 2 commits into
apache:mainfrom
PrakshiGoyal10:databricks-repair-from-airflow-3

Conversation

@PrakshiGoyal10

@PrakshiGoyal10 PrakshiGoyal10 commented Jul 17, 2026

Copy link
Copy Markdown

On Airflow 3 the "Repair a single task" and "Repair All Failed Tasks" links on DatabricksWorkflowTaskGroup tasks were gated off, so on-call users had to leave Airflow and repair failed runs in the Databricks UI.

This restores repair-from-Airflow on Airflow 3 (3.1+), served by a FastAPI sub-application on the API server since Flask-AppBuilder was dropped:

  • A GET renders a read-only confirmation page; only a same-site POST performs the repair and clears tasks. Because the API server's auth cookie is SameSite=Lax, it is not sent on a cross-site POST, so moving the mutation off GET is what protects the action from cross-site request forgery — matching how Airflow 3's own UI mutations are protected.
  • The repair link carries only Airflow identifiers (the run's launch task_id, and for a single-task repair the target task_id). The Databricks connection and run id are derived server-side from the launch task's trusted WorkflowRunMetadata XCom, never from the request, so a crafted link cannot point the repair at an arbitrary connection or Databricks run.
  • The set of failed tasks is resolved from the live Databricks run state (hook helper get_run_failed_task_keys), and repair_run is called with rerun_dependent_tasks so downstream tasks resume too.
  • The repaired task instances and their downstream instances are cleared — but only after a successful repair call — mapping Databricks task keys to Airflow task_ids via the same md5(dag_id__task_id) scheme the operators use, resolved from the serialized Dag.
  • Databricks failures surface as a generic 502 without reflecting the upstream exception text, and confirmation-page identifiers are HTML-escaped.
  • The repair backend and its links are gated to Airflow 3.1+, where the cookie-or-bearer authentication resolver it relies on is available; the redirect target is a same-site relative path, resolving the CodeQL open-redirect findings.

Verified end-to-end against a real Databricks workflow on serverless and job clusters: a failed task plus its upstream_failed downstream both return to success after confirming the repair. Unit tests cover the GET-does-not-mutate behaviour, confirmation-page escaping, server-side identifier resolution on the POST, and the generic 502.

related: #52280


Was generative AI tooling used to co-author this PR?
  • Yes — Claude Code (Opus 4.8)

Generated-by: Claude Code (Opus 4.8) following the guidelines


Important

🛠️ Maintainer triage note for @PrakshiGoyal10 · by @potiuk · 2026-07-28 16:20 UTC

Helpful heads-up from the maintainers — please address before this PR can be reviewed:

  • Pre-commit / static checks. See docs.
  • Provider tests. See docs.

The ball is in your court — you've been assigned to this PR. Fix the above, then mark it Ready for review.

See the Pull Request quality criteria for how to fix each item. There is no rush.

Note: your branch is 294 commits behind main — please rebase and push again to get up-to-date CI results.

Automated triage — may be imperfect; a maintainer takes the next look. We use this two-stage triage process so maintainers' limited time goes to the conversation with you.

@boring-cyborg

boring-cyborg Bot commented Jul 17, 2026

Copy link
Copy Markdown

Congratulations on your first Pull Request and welcome to the Apache Airflow community! If you have any issues or are unsure about any anything please check our Contributors' Guide
Here are some useful points:

  • Pay attention to the quality of your code (ruff, mypy and type annotations). Our prek-hooks will help you with that.
  • In case of a new feature add useful documentation (in docstrings or in docs/ directory). Adding a new operator? Check this short guide Consider adding an example Dag that shows how users should use it.
  • Consider using Breeze environment for testing locally, it's a heavy docker but it ships with a working Airflow and a lot of integrations.
  • Be patient and persistent. It might take some time to get a review or get the final approval from Committers.
  • Please follow ASF Code of Conduct for all communication including (but not limited to) comments on Pull Requests, Mailing list and Slack.
  • Be sure to read the Airflow Coding style.
  • Always keep your Pull Requests rebased, otherwise your build might fail due to changes not related to your commits.
    Apache Airflow is a community-driven project and together we are making it better 🚀.
    In case of doubts contact the developers at:
    Mailing List: dev@airflow.apache.org
    Slack: https://s.apache.org/airflow-slack


if not task_keys:
log.info("No failed Databricks tasks to repair for run %s", databricks_run_id)
return RedirectResponse(return_url, status_code=303)
raise HTTPException(status_code=502, detail=f"Databricks repair request failed: {e}") from e

_clear_repaired_and_downstream(dag_id, run_id, task_keys, log)
return RedirectResponse(return_url, status_code=303)
@Vamsi-klu

Vamsi-klu commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

I rechecked the current head and think the repair path needs a security/compatibility redesign before it is safe to validate against a real workspace:

  • GET should render a read-only confirmation page; only a CSRF-protected, Dag-authorized POST should repair or clear tasks.
  • The URL should carry only validated Dag/run/task identifiers. databricks_conn_id, the Databricks run ID, and Databricks task keys should be derived server-side from trusted WorkflowRunMetadata XCom instead of accepted from the request.
  • Redirect targets should be same-site relative paths built from validated identifiers, resolving the two open CodeQL redirect findings.
  • The FastAPI repair app should be registered only on Airflow 3.1+, since resolve_user_from_token is unavailable on 3.0.6. Provider config must come from airflow.providers.common.compat.sdk, not airflow.configuration, to clear the current static check.
  • Databricks failures should produce a generic 502 without reflecting raw upstream exception text, and task clearing should happen only after a successful repair call.
  • Confirmation-page values must be safely encoded so identifiers cannot become reflected HTML or JavaScript.

The PR body should also include related: #52280. I can prepare a patch branch with the route split, trusted identifier resolution, access checks, and focused DB/API tests if that collaboration route would be useful; I will not open a competing Apache PR while this one is active. Until the mutation-on-GET issue is fixed, I do not recommend clicking the current repair link against a live Databricks workspace.


Drafted-by: Codex (GPT-5)

@Vamsi-klu

Copy link
Copy Markdown
Contributor

@PrakshiGoyal10 , Some CI signals are failing. PTAL and fix those. Thanks!

On Airflow 3 the "Repair a single task" and "Repair All Failed Tasks"
links on DatabricksWorkflowTaskGroup tasks were gated off, so on-call
users had to leave Airflow and repair failed runs in the Databricks UI.

This restores repair-from-Airflow on Airflow 3:

- Register a FastAPI app on the API server that performs the repair,
  authorized with Dag-run edit access and authenticated via either the
  UI's bearer token (XHR) or its _token cookie (plain navigation), so a
  repair link clicked in the browser is authorized.
- Resolve the set of failed tasks from the live Databricks run state
  rather than Airflow's metadata DB (new hook helper
  get_run_failed_task_keys), and call repair_run with
  rerun_dependent_tasks so downstream tasks resume too.
- Clear the repaired task instances and their downstream instances,
  mapping Databricks task keys to Airflow task_ids via the same
  md5(dag_id__task_id) scheme used by the operators, which works on the
  serialized Dag.
- Remove the Airflow 3 gates on the plugin registration and the
  per-operator extra links so the repair buttons render again.

Verified end-to-end against a real Databricks workflow on serverless and
job clusters: a failed task plus its upstream_failed downstream both
return to success after clicking repair.
…irect

The repair action mutated state on a cookie-authenticated GET and trusted the
Databricks connection, run id, and task keys from the request, so a crafted
repair link could repair an arbitrary run and CodeQL flagged the redirect as an
open redirect. The endpoint also required an auth helper unavailable on 3.0.6.

A GET now renders a read-only confirmation page and only a same-site POST
repairs and clears tasks, which SameSite=Lax on the auth cookie protects from
cross-site forgery. The connection and Databricks run id are derived server-side
from the launch task's trusted WorkflowRunMetadata XCom, the redirect target is a
same-site relative path, Databricks failures return a generic 502, and the
backend is gated to Airflow 3.1+ where its authentication resolver exists.
@PrakshiGoyal10
PrakshiGoyal10 force-pushed the databricks-repair-from-airflow-3 branch from 5f287ab to 5e536ea Compare August 5, 2026 13:44

if not task_keys:
log.info("No failed Databricks tasks to repair for run %s", metadata.run_id)
return RedirectResponse(return_url, status_code=303)
_clear_repaired_and_downstream(dag, run_id, repaired_task_ids, session, log)
session.commit()

return RedirectResponse(return_url, status_code=303)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants