Skip to content

Sync v3-4-stable with v3-4-test to release 3.4.0rc1 - #75755

Merged
vatsrahul1001 merged 103 commits into
v3-4-stablefrom
changes-3.4.0rc1
Oct 28, 2026
Merged

vatsrahul1001 merged 103 commits into
v3-4-stablefrom
changes-3.4.0rc1

Conversation

@vatsrahul1001

@vatsrahul1001 vatsrahul1001 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Time for 3.4.0rc1

Release Notes

  • Read the Pull Request Guidelines for more information. Note: commit author/co-author name and email in commits become permanently public when merged.
  • For fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
  • When adding dependency, check compliance with the ASF 3rd Party License Policy.
  • For significant user-facing changes create newsfragment: {pr_number}.significant.rst, in airflow-core/newsfragments. You can add this file in a follow-up commit after the PR is created so you know the PR number.

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

jason810496 and others added 30 commits October 23, 2026 21:37
This reverts commit eda782f.

Since it merged, the K8S Lang-SDK test has hung in about 40% of CI runs:
a Java task stops right after its first request to the supervisor and
stays running until the test times out. Every run before the merge
passed. Reverting keeps CI usable while the hang is investigated on
#74690.

Generated-by: Claude Opus 5
(cherry picked from commit 40b5d36)

One adaptation: #75439 rewrote the "Stopping when Airflow asks" section
of java.rst, so the section is removed in that rewritten form rather
than the one the original revert deletes. java.rst now matches main.

Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
Co-authored-by: Claude <noreply@anthropic.com>
…ocs sidebar (#75471) (#75475)

0.3.15 spaces sidebar entries so wrapped titles read as one entry, and
lists only pages in the left sidebar, leaving page headings to the
right-hand TOC (apache/airflow-site#1700).
(cherry picked from commit d977d20)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
…75443) (#75476)

* Go SDK: fail a task whose return-value XCom push fails, fix the Label doc

A failed return-value push was logged and the task was left successful, so the
downstream tasks that read it failed later with XComNotFound. Fail the task
instead, and stop pushing a result the task never produced when its function
already returned an error, as the branch path does.

The guide's labelled-edge example did not compile: Label takes only the text,
and On names the tasks its edges reach.

* Go SDK: address review on the return-value XCom push

Push the task instance from the runtime context as is, share its lookup
with startBranch, and cover the failed push on the branch path. Merge the
copied test helper into runTask.

* Go SDK: test that a task pushes no nil-pointer return value

Only the branch path covered this check, and a nil pointer that slipped
past it would be pushed as null now that a push can fail the task.

---------
(cherry picked from commit 1a50a18)

Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
…uage SDK (#74869)" (#75376) (#75469)

This reverts commit 8326025.

3.4.0 closes today and #75376 needs #75387 alongside it, which needs more
bandwidth than is left. On v3-4-test alone, the Python task runner arms
SIGALRM from task.execution_timeout while the supervisor arms its deadline
from TIRunContext.execution_timeout. When the server value is smaller, the
supervisor sends SIGTERM before the runner raises AirflowTaskTimeout, so
on_kill, the retry policy, callbacks and listeners are skipped. Reverting
avoids shipping that regression in 3.4.0.

#74869 stays on main. SetExecutionTimeout (#73806) is untouched, so Python
tasks keep the supervisor backstop they had before #75376.

Co-authored-by: Claude <noreply@anthropic.com>
… (#75441)

Anyone who can see values, the overwhelmingly common case, got an
Occurrences column that was 1 on every row: each such record stands for
exactly one change. Even redacted, only a path that hides a task, tag or
group behind "*" merges changes. Drop the column and show a "xN" badge
("xN+" for a truncated diff) after the path when a record stands for
more than one change, with a tooltip explaining the count.

The badge is outlined purple so it stands apart from the impact badges.
Remove the now-unused column label from all locales.
(cherry picked from commit 29bb140)

Co-authored-by: Jed Cunningham <66968678+jedcunningham@users.noreply.github.com>
…n the sidebar (#75478) (#75481)

Eight pages underlined a later section like the page title, so Sphinx
treated it as another top-level title and listed it in the sidebar as
its own page. Demote each extra title and its subsections one level.

metric_tables.rst is included under Metric Descriptions and shares its
heading levels, so the generator now writes its headings one level
deeper to stay nested.
(cherry picked from commit b7dfaf6)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
… (#75482)

* Add consolidated Language SDK compatibility matrix

Users comparing Language SDKs had to read each SDK's README, and the
per-SDK manifests lagged behind what the SDKs actually ship. One generated
matrix, split by authoring mode, shows what each SDK supports for a Dag
definition and for a Python Dag with stub TaskHandler.

* Add callbacks, listeners and provider operators to the SDK matrix

Users comparing Language SDKs could not see where callbacks, Airflow's
listener API and Python provider operators stand, because the matrix had
no dimension for any of them. Callbacks ask different things of an SDK per
authoring mode, so they are declared per mode like the other shared
capabilities.

* Address review on the Language SDK matrix generator

The umbrella capability and the authoring mode both read `dag-definition`,
which gives one name two meanings in the same manifest. A row's kind also
belongs in its entry key: state and capability names happen not to collide
today, so the lookup worked by accident rather than by design.

* Rename the dynamic-task-mapping dimension to mapped-tasks

The dimension is about whether a task can be a mapped task, which the
shorter name says directly and keeps the matrix row readable next to the
other task-level dimensions.

* Split callbacks into Dag-level and task-level dimensions

The callbacks of a Python Dag run whichever SDK executes its stub tasks, so
``dag-callbacks`` is a Dag-definition concern only, while ``task-callbacks``
stays declared per authoring mode. Drop ``provider-operators`` until ADR-0009
is accepted, and reuse the shared ``capabilities_doc`` fixture in the per-SDK
README tests.

* Fix the hook attribution in the matrix generation diagram

``index.rst`` is written by ``update-lang-sdk-central-matrix`` from every SDK
in ``LANG_SDKS``, not by the per-SDK README hook.

---------
(cherry picked from commit 719a685)

Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
…nner (#75485) (#75487)

custom.css still padded the docs layout by 163px and offset anchor
targets by 161px, sized for a 40px banner above a 121px navbar. The site
now has no banner, a 90px navbar (80px at 1280px and below), and the
theme already pads the body for the navbar, so docs content started
253px down instead of 130px.

Drop the padding override so the theme's 40px applies, and size the
anchor offset to the navbar plus the same 40px.
(cherry picked from commit a5160a9)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
… this page list (#75491) (#75495)

0.3.16 stops pinning the docs' right-hand contents 263px from the top
(apache/airflow-site#1701), so it lines up with the content and the
left sidebar.
(cherry picked from commit d41a7c8)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
…are (#75217) (#75454)

JWTRefreshMiddleware appends its own _token Set-Cookie after the
response headers. When the route itself sets _token, the browser
applies the middleware cookie last, so it overrides the route:

- A login route, e.g. an auth manager callback mounted under /auth,
  sets a fresh token while the request still carries an expired or
  invalid one. The middleware appends a deletion and the user is
  logged out right after logging in.
- /api/v2/auth/logout deletes the cookie, but if refresh_user returned
  a refreshed user for that request the middleware appends a newly
  minted, unrevoked token and the user stays logged in.

Skip the middleware token cookie when the response already sets
_token. Stale root-path cookies are still cleared.
(cherry picked from commit 99eff46)

Co-authored-by: Mathieu Monet <60776491+stegololz@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ands (#75483) (#75501)

sphinx-argparse makes every sub-command and its argument groups a
section, so the right-hand contents on the CLI reference pages listed
about 290 entries, mostly repeated Named Arguments, Positional Arguments
and Sub-commands. A :tocdepth: of 4 stops the contents at the top-level
commands; the full reference stays on the page.

The field goes above the license header, and an empty comment ends it,
because the indented license would otherwise be read as part of the
field's value.
(cherry picked from commit d613e99)

Co-authored-by: Kaxil Naik <kaxilnaik@gmail.com>
…) (#75494)

A task instance's log link ignored its loop iteration: the one Airflow
builds put the iteration where the UI expects a map index, pointing at a
page that doesn't exist, and the one the Task SDK builds couldn't tell the
iterations of a loop apart. Failure emails, notifiers and OpenLineage
events carried these links.
(cherry picked from commit a0be43d)

Co-authored-by: Kacper Muda <mudakacper@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
…5515)

(cherry picked from commit e144499)

Co-authored-by: Shivam Rastogi <6463385+shivaam@users.noreply.github.com>
…ry-package-updates group across 1 directory (#75506)

Bumps the 3-4-registry-package-updates group with 1 update in the /registry directory: [swagger-ui-dist](https://github.com/swagger-api/swagger-ui).


Updates `swagger-ui-dist` from 5.33.3 to 5.34.0
- [Release notes](https://github.com/swagger-api/swagger-ui/releases)
- [Commits](swagger-api/swagger-ui@v5.33.3...v5.34.0)

---
updated-dependencies:
- dependency-name: swagger-ui-dist
  dependency-version: 5.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: 3-4-registry-package-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the 3-4-auth-ui-package-updates group with 1 update in the /airflow-core/src/airflow/api_fastapi/auth/managers/simple/ui directory: [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query).


Updates `@tanstack/react-query` from 5.104.3 to 5.104.4
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.104.4/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.104.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: 3-4-auth-ui-package-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…es (#74874) (#75488)

Bumps the ts-sdk-package-updates group with 3 updates in the /ts-sdk directory: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [prettier](https://github.com/prettier/prettier) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@types/node` from 26.2.0 to 26.6.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `prettier` from 3.9.6 to 3.9.9
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](prettier/prettier@3.9.6...3.9.9)

Updates `vitest` from 5.0.1 to 5.0.3
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.3/packages/vitest)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.6.4
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: ts-sdk-package-updates
- dependency-name: prettier
  dependency-version: 3.9.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: ts-sdk-package-updates
- dependency-name: vitest
  dependency-version: 5.0.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: ts-sdk-package-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…75489)

Bumps the ts-sdk-package-updates group in /ts-sdk with 1 update: [eslint](https://github.com/eslint/eslint).


Updates `eslint` from 10.11.0 to 10.12.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](eslint/eslint@v10.11.0...v10.12.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.12.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: ts-sdk-package-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 01907e0)

Co-authored-by: Jeff(Wei-Hao) Lu <jeff563715@gmail.com>
…72063) (#75463)

RedactedIO exists so that output produced by user code is masked before it
reaches stdout, and its docstring says "Writes to stdout will be redacted".
write() applied redact(); writelines() forwarded straight to the target, so a
secret written that way was printed verbatim.

The one call site is task_test() in cli/commands/task_command.py, so this is
reachable from `airflow tasks test`, which deliberately routes task output up
to the console handler for local debugging.

Non-string elements now stringify rather than raising TypeError, matching what
write() already does.
(cherry picked from commit 3d5c533)

Co-authored-by: Mahathir Mohammad Shuvo <48558774+MahathirMohammadShuvo@users.noreply.github.com>
…ibility (#73680) (#75464)

(cherry picked from commit 8143b8d)

Co-authored-by: Aditya kumar singh <143548997+Adityakk9031@users.noreply.github.com>
Users currently have to infer how the CLI and REST API values correspond to the clearer labels shown in the UI. Making that relationship explicit prevents the same behavior from appearing to be three different settings.
(cherry picked from commit e7369d0)

Co-authored-by: Sasali <138128067+IcebreakerSA@users.noreply.github.com>
…75142) (#75550)

* Enable auto-merge, gated on a dedicated CI passed check

Committers wait on CI for every approved PR only to click merge. Auto-merge was tried in 2025 and turned off because a required check left no way to merge past CI that was red for unrelated reasons; rulesets now let committers bypass the required check, which restores that escape hatch. The existing Finalize tests job cannot be the required check: it is skipped when tests fail, and GitHub counts a skipped required check as passed, so a dedicated gate job reports a real result on every PR.

Generated-by: Claude Opus 5

* Do not report CI passed when project CI did not run

With the fork CI gate (AIP-120), a gated pull request skips build-info and every job after it, which the CI passed job would count as success and let the pull request merge on no CI. The job now reports under another name when build-info is skipped; the fork CI reconciler posts CI passed from the fork run instead.

Generated-by: Claude Opus 5

* Require CI passed on release branches too

allow_auto_merge is repository-wide, but only main required CI, so auto-merge on a pull request to a release branch would merge on approval alone, before CI finished or despite failures.

Generated-by: Claude Opus 5

* Address auto-merge review: clarify ARM gate and fork CI dependency

The README no longer asks for an immediate backport, and says that Tests (ARM) has the same CI passed job for its push and scheduled runs. The CI passed job comment notes that the project-CI-not-run name only appears once the AIP-120 gate adds a condition to build-info.

Generated-by: Claude Opus 5

* Add check-run-needed to the CI passed gate

Rebased onto main, which added the check-run-needed job in #75420. Without it in the gate's needs, a failure of that job would not stop auto-merge, and check-ci-gate-needs failed in Scripts tests.

Generated-by: Claude Opus 5

* Set PYTHONPYCACHEPREFIX for the CI passed gate hook

main now requires every prek hook to write bytecode outside the source tree (check-prek-hooks-pycache-prefix).

Generated-by: Claude Opus 5

* Let the Write role bypass the CI rulesets instead of the secret committers team

GitHub refuses secret teams as ruleset bypass actors, so airflow-committers cannot be one. The Write repository role is held only by committers on this repository, and the asfyaml convenience syntax only names teams, so both CI rulesets move to the raw payload syntax. That syntax cannot pin the required checks to the GitHub Actions app, because asfyaml sends integration_id to the API as a string.
(cherry picked from commit a5af91d)


Generated-by: Claude Opus 5

Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
…ckout (#75001) (#75537)

(cherry picked from commit 602e150)

Co-authored-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com>
Add jason810496 to the sender allowlist in publish-docs-to-s3.yml, so the
TypeScript SDK API reference can be refreshed from its release tag without
asking another committer to dispatch the workflow.
(cherry picked from commit e025c33)

Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
…#75000) (#75467)

* Run the Kerberos renewer without metadata database checks

Ticket initialization does not use the metadata database. Cover standard and one-time CLI dispatch when migration and log-template access are unavailable.

Generated-by: OpenAI Codex

* Use mock.patch decorators in the Kerberos no-database test

Generated-by: Claude Opus 5

---------
(cherry picked from commit fefb87a)

Co-authored-by: Himanshu Chawla <himanshuchawla0807@gmail.com>
Co-authored-by: Himanshu Chawla <241715894+himanshuchawla0807-gif@users.noreply.github.com>
Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
…k Instances to Browse (#75422) (#75517)

The Dags button opened a hover menu, so clicking it never reached the Dags page. Make it a plain link to /dags and list Dag Runs and Task Instances in the Browse menu, gated by the Dags permission.
(cherry picked from commit b9c657b)

Co-authored-by: Stephen Yang <stephenyang0215@gmail.com>
…#75448) (#75490)

The Tasks tab filters the task list client-side (operator, trigger rule,
retries, mapped, name search) but passed the API's total_entries to the
DataTable heading, so the heading kept reporting the unfiltered count
("12 Tasks") even when a search narrowed the list to a single task.
Pass the filtered list's length instead, as Configs.tsx already does for
its client-built list, and assert the count in the existing filter tests.
(cherry picked from commit 99bdeab)

Co-authored-by: 김난희 <nanhee.kim@ishopcare.co.kr>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… switched (#74853) (#75466)

git-sync publishes each revision by repointing the Dags folder symlink
to a new checkout. When that happens during file discovery, child
directories resolve into the new checkout and no longer find the ignore
rules inherited from their parent, so files under ignored directories
are picked up for that scan.
(cherry picked from commit 04e68bf)

Co-authored-by: Haram Lee <yoonsoi041909@gmail.com>
…75535)

The "About this comparison" icon on the Versions tab showed a hard to
follow caveat that added little to the page. Remove the icon, its test,
and the two now-unused translation keys from every locale.
(cherry picked from commit 4639f24)

Co-authored-by: Jed Cunningham <66968678+jedcunningham@users.noreply.github.com>
@ashb

This comment was marked as outdated.

The backport of #75414 (#75709) raised the SMTP provider version in its
pyproject.toml without refreshing uv.lock. The constraints jobs run
`uv sync`, which then tries to rewrite the lock file. The lock is
bind-mounted as a single file in the container, so the rename fails with
"Device or resource busy" and every "Generate constraints" job on
v3-4-test fails.
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The re-run of the jobs stopped by EC2 Spot interruptions finished: attempt 2 failed.

github-actions Bot and others added 20 commits October 27, 2026 11:39
The task runner always opens a "Post Execute" log group after execute()
returns, but for a plain task nothing is logged at INFO before it is
closed, so the UI showed a section header that expanded to nothing.

When parsing logs, drop a group header if the group closes with no
entries in it. A parent containing only empty groups is dropped too.
Unclosed groups are kept so a running task still shows its current
section.
(cherry picked from commit 8f7a8e4)

Co-authored-by: Jed Cunningham <66968678+jedcunningham@users.noreply.github.com>
…75674) (#75799)

(cherry picked from commit 91ca0ac)

Co-authored-by: Yuseok Jo <yuseok89@gmail.com>
… (#75798)

(cherry picked from commit d92a480)

Co-authored-by: Pushkal Gupta <161060351+Pushkal-Gupta@users.noreply.github.com>
Co-authored-by: Brent Bovenzi <brent@astronomer.io>
…o editor (#75684) (#75797)

closes: #75661
(cherry picked from commit aaba5c3)

Signed-off-by: Arnav Singh <arnavsingh08@outlook.com>
Co-authored-by: Arnav Singh <arnavsingh08@outlook.com>
…ne (#75723) (#75800)

* Fix UI crash from unresolvable Windows PT timezone

Validate the stored/system timezone before using it, falling back
to UTC when it cannot be resolved (e.g. Windows' new unified 'PT'
zone name). Prevents a TypeError crash across the UI.

Closes #75697

* Fix formatting: correct indentation and add missing newline

* Add Apache license header to new test file

* Remove extra blank line after license header
(cherry picked from commit df37268)

Co-authored-by: Basant_Jamwal <basantrajput570@gmail.com>
…5792)

Backport PRs opened by cherry_picker are authored by github-actions[bot],
so the blanket "bot PR means public runners" rule sent them to public
runners although a committer's merge or manual dispatch started them and
the code is already on main.

Route a PR to RunsOn when it is authored by github-actions[bot], its head
ref starts with backport- and its head repo is apache/airflow. Dependabot,
ci-upgrade-* PRs, other bots and fork PRs stay on public runners.
(cherry picked from commit 4ace0a1)

Co-authored-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com>
* Bootstrap constraints generation for a Python without a baseline file (#74596)

The generator always downloads the previous constraints file of the same Python from the constraints
branch to diff against it, and failed with a 404 for the first generation of a new Python. When the
branch carries the same constraints mode for other Pythons, a missing file means a first publication and
the generator diffs against an empty baseline instead. A 404 on a branch without any file of that mode,
and every other HTTP error, still fails.

(cherry picked from commit d267fbd)

* Check out constraints from apache/airflow when diffing them in CI (#75675)

The Update constraints job checked out the constraints branch from the
repository the run belongs to. Forks do not carry the constraints-*
branches, so the job failed on every canary push in a fork. Diff against
apache/airflow instead; the job only diffs now, so it needs neither
credentials nor history.

Generated-by: Claude Opus 5
(cherry picked from commit 3348602)

* Always approve workflow runs of PRs from trusted stakeholder repositories (#75677)

Amazon, Google and Astronomer maintain large parts of Airflow and open many
PRs from their own repositories. Their PRs often touch large providers or CI
and wait for a maintainer to approve every push, although only people those
stakeholders gave write access can push the commits of these PRs.

Generated-by: Claude Opus 5
(cherry picked from commit ffd9398)

* Retry GitHub calls that fail to connect in the fork CI monitor (#75701)

A monitor run failed to report job statuses for a PR because a POST to the statuses API ended in a TLS handshake timeout. Network failures are as transient as the server errors already retried, and one that happens before the request reaches GitHub cannot have taken effect, so it is safe to repeat even for calls such as creating a comment.

Generated-by: Claude Opus 5
(cherry picked from commit 2ae00f1)

* Stop breeze k8s commands from silently rewriting uv.lock (#75763)

A v3-4-test backport bumped a workspace member's version without updating
uv.lock, and the `update-uv-lock` static check still passed. The chart's
prek hooks run `breeze k8s setup-env`, which ran a plain `uv sync` in
kubernetes-tests. That project is a uv workspace member, so the sync
re-resolved and rewrote the root uv.lock before the root hook checked it.
Nested prek configs do not inherit the root UV_FROZEN=1, and prek does not
report files a nested-project hook modifies outside its own project, so
the rewrite went unnoticed and the stale lock was merged. It then broke
every "Generate constraints" job on the branch.

The `uv run pytest` calls of `breeze k8s tests` and the overlay tests had
the same effect on contributors' checkouts.

CI now also fails when the static checks leave tracked files modified, so
any other hook writing outside its project is caught.

(cherry picked from commit 7c7157b)

* Keep breeze verify working when dry-run is on (#75713)

With dry-run on, run_command skips every command and returns empty
output. breeze verify only reads git state to list the checks a change
needs, so skipping those queries made it crash with an IndexError
instead of answering.

(cherry picked from commit a5ff71d)

* Tell contributors when their fork CI workflow stops running (#75814)

The fork CI monitor read the fork's workflow state only until it first saw
the workflow enabled. When the workflow was disabled afterwards, by the
contributor or by GitHub after 60 days of fork inactivity, the pull request
kept waiting for a push that could never run CI, while its comment still
said the workflow was enabled. Contributors now get a new comment telling
them why it stopped and how to turn it back on, starting with syncing their
fork's main from apache/airflow.

breeze ci audit also stops suggesting committers disable the workflow: a
committer trying fork CI needs it, and following the hint is one way a pull
request ends up stuck like this.

Generated-by: Claude Opus 5
(cherry picked from commit 891e83d)

* Harden the fork CI reconciler and protect the fork CI gate (#74909)

* Retry the fork CI push-again nudge when posting it fails

The state comment is what the next reconciler run compares with. Recording
awaiting_push there before the nudge was posted meant a failed post was never
retried, and the contributor got no prompt before the inactivity closure.

Generated-by: Claude Opus 5

* Ignore fork-only workflows that skipped every job in the fork CI tampering check

A workflow or trigger the base branch does not have always counted as
project CI, so a pull request adding a fork-only workflow that its jobs
guard off in apache/airflow was closed for gate tampering although nothing
ran.

Generated-by: Claude Opus 5

* Keep fork CI pull requests sharing a head commit across bases for a maintainer

The green-trust decision is stored as a commit status, which every pull
request with that head commit shares. Pull requests with different bases
have different changed files, so a decision made for one could mark the
other ready without checking it.

Generated-by: Claude Opus 5

* Attribute fork CI runs to the right pull request in the tampering check

Runs from forks carry no pull request, so they were matched by fork branch
alone. Legitimate project CI against a base branch without the gate, made
before a retarget, or a run of another pull request from the same branch,
could close a gated pull request for gate tampering.

Generated-by: Claude Opus 5

* Close fork CI pull requests that change the fork CI gate

A pull request whose CI runs in the contributor's fork could change the gate
that sent it there: its code, its configuration, the gate job or the
monitor. Such a change decides where the pull request's own CI runs, so the
monitor now closes it and explains why. Contributors can still add, change
or remove their own pilot entry, which is how they join and leave the pilot.

Generated-by: Claude Opus 5

* Count only started jobs of fork-only workflows as project CI work

A fork-only workflow run cancelled before a runner took its jobs reports them
completed and cancelled, so it counted as project CI work. It now uses the
same started-job test as ci-amd.yml runs.

Generated-by: Claude Opus 5

* Name the cancelled-run CI passed job in the fork CI tampering docs

The tampering check now accepts the name a cancelled ci-amd.yml run gives
its CI passed job, so the docs list it with the other names of that job.

Generated-by: Claude Opus 5
(cherry picked from commit 8058c88)

---------

Co-authored-by: Dev-iL <6509619+Dev-iL@users.noreply.github.com>
Co-authored-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com>
…ts (#75213) (#75817)

* Scope asset expressions to the assets the caller may read

`next_run_assets` scopes the asset scheduling expression it serves to the
assets the caller may read (#72864), and the dependencies graph followed
(#73008). Four endpoints still served `DagModel.asset_expression` verbatim:
the public Dag details endpoint, the UI Dag list, and both partitioned Dag
run endpoints. A caller authorized on a Dag but not on its upstream assets
could read every name and uri out of them, and the public endpoint needs no
UI to reach. Asset names and uris commonly encode bucket, table or dataset
names, which is why the rest of the asset API already scopes them.

The sibling `assets` array of the pending partitioned Dag run response
carries the same names; scoping that is a separate change with its own UI
consumers.

* UI: Scope partitioned Dag run asset list to readable assets

The pending partitioned Dag run detail response carries two asset-bearing
fields. `asset_expression` is scoped to the assets the caller may read; the
sibling `assets` array was not, so one payload could blank an asset inside the
boolean tree while spelling its name and uri out one key over. That defeated
the redaction on this route, and the route's own asset dependency only checks
whether the caller may read assets at all -- there is no asset id in its path
for it to authorize against.

The counts and partition keys of a blanked asset are kept. They describe the
Dag's own schedule, which a caller who reached this endpoint can already read,
and dropping them would leave a stuck run with no explanation at all.

This endpoint is served only to the UI: the public v2 spec regenerates
byte-identical, and no airflow-ctl model references the response.
(cherry picked from commit a462d68)

Co-authored-by: Henry Chen <henrychen@apache.org>
…75806)

Grid bars show no run type icon for scheduled runs, but the run type
legend showed one next to "Scheduled", suggesting an icon that users
never see. Keep the label and drop its icon, with a spacer so the
labels stay aligned.
(cherry picked from commit d583ffe)

Co-authored-by: Jed Cunningham <66968678+jedcunningham@users.noreply.github.com>
…#75223) (#75354)

* UI: Warn in the trigger form when the logical date is outside the Dag's dates

* Show the logical date warning as field helper text instead of an alert

* Show the Dag start and end dates under the logical date to keep the form from shifting
(cherry picked from commit c81ca3c)

Co-authored-by: Yuseok Jo <yuseok89@gmail.com>
…PRs (#75761) (#75794)

The first stale step used the default budget of 30 operations. Every
run ran out after the newest ~800 of ~1900 open items, so PRs older
than about #71300 were never marked or closed.
(cherry picked from commit cb58200)

Co-authored-by: Andrew Chang <69671930+Andrushika@users.noreply.github.com>
…5795) (#75802)

* [v3-4-test] Load the serialized Dag in ti_run only for stub tasks (#75795)

Starting any task deserialized its whole Dag so the route could find out
whether the task was a stub and read its arg_bindings. Denormalize the
serialized is_stub flag onto task_instance, which ti_run already fetches
and locks, and load the Dag only when it is set.

* Mark a Go or Java TriggerDagRun task a stub, as TypeScript does

* Inline the table name in the is_stub migration

* Starve a Dag the scheduler cannot deserialize

test_find_executable_task_instances_skips_dag_that_cannot_be_deserialized
fails on v3-4-test independently of this backport. #75745 brought the guard
over from #75263 without the starved set that #75263 relies on, because that
set came with #70307, which is not on this branch. The guard then returns
False without narrowing the next query, so a cycle whose batch is filled by
the bad Dag ends with nothing queued.

---------
…ars (#75842) (#75844)

* Isolate otel config-priority test from ambient OTEL env vars

test_config_priorities asserts that the Airflow config host/port is used
when a case provides no OTEL endpoint env var. It applied only the case's
provided_env_vars on top of the ambient environment, so any OTEL_* var
already exported by the runner leaked in. RunsOn CI runners export
OTEL_EXPORTER_OTLP_ENDPOINT (resolving to 127.0.0.1:4318), which wins over
the Airflow config and failed the six config-priority cases on both main
and the release branches.

Clear all OTEL_* env vars before applying provided_env_vars so the test
only sees its own inputs regardless of the runner environment.

* Move OTEL_* clearing into a class-scoped autouse fixture

Per review: clear ambient OTEL_* vars for every test in TestOtelMetrics
rather than only test_config_priorities.
(cherry picked from commit 5df209d)

Co-authored-by: Rahul Vats <43964496+vatsrahul1001@users.noreply.github.com>
…pacity-optimized, size ranges (#75822) (#75825)

* Let RunsOn x64 runners use more instance families for Spot

Generated-by: Claude Opus 5

* Take RunsOn Spot runners from capacity-optimized pools

Generated-by: Claude Opus 5

* Let RunsOn runners take Spot from up to twice the requested size
(cherry picked from commit d17f121)


Generated-by: Claude Opus 5

Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
)

(cherry picked from commit 881f362)

Signed-off-by: PoAn Yang <payang@apache.org>
Co-authored-by: PoAn Yang <payang@apache.org>
… are derived (#75262) (#75837)

(cherry picked from commit e31f52e)

Signed-off-by: PoAn Yang <payang@apache.org>
Co-authored-by: PoAn Yang <payang@apache.org>
…proval (#75832) (#75840)

* Show why external contributors' workflow runs wait for approval

Contributors whose runs the auto-approve workflow leaves for a maintainer
only saw a label, with no reason, and a comment for each would notify
every subscriber. A pending "Workflow approval" commit status shows the
reason in the PR's checks without notifying anyone.

GitHub has no event for approving runs, but a waiting run never starts,
so a run that starts is the signal to clear the status and the label,
also for runs a maintainer approves by hand, without listing every
waiting run.

Generated-by: Claude Opus 5

* Keep the approval status in sync with runs approved during a tick

Generated-by: Claude Opus 5

* Re-check approved runs after the failure path writes the approval state
(cherry picked from commit ee62251)


Generated-by: Claude Opus 5

Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
…ed PRs (#75268) (#75845)

(cherry picked from commit 4151914)

Signed-off-by: PoAn Yang <payang@apache.org>
Co-authored-by: PoAn Yang <payang@apache.org>
…nts (#75765) (#75846)

* Avoid loading timetables for dags in Execution API endpoints

For a few reasons/places now in the Exec API we now need the serialized
dag, but we don't need the timetable (which could involve loading) plugins
or user code.

This should let the ExecAPI run without user code if a deployment admin
wishes to try that.

* Stop eagerly decoding custom weight_rules

`weight_rule` on SerializedDag is already a property that decodes/inflates
strings into the object

* Fix reviews

* fixup! Avoid loading timetables for dags in Execution API endpoints

---------
(cherry picked from commit 402ab11)

Co-authored-by: Ash Berlin-Taylor <ash@astronomer.io>
Co-authored-by: Jason(Zhe-You) Liu <68415893+jason810496@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

8 participants