Upgrade the pinned Flask-AppBuilder (FAB) dependency in the Apache Airflow FAB provider (`providers/fab/`). Bumps the exact `flask-appbuilder==` pin and its mirror constant, regenerates `uv.lock`, drives the `test_fab_alignment.py` drift tripwire, reviews the vendored security-manager `override.py` against the new upstream FAB, and conditionally re-vendors static assets / DB migrations. Use when asked to "upgrade FAB", "bump flask-appbuilder", or move the FAB provider to a newer Flask-AppBuilder release.
72
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Airflow's FAB provider is tightly coupled to a specific Flask-AppBuilder release because it vendors-in and subclasses large parts of FAB's security manager. A version bump is therefore never "just change the pin" — it must be reconciled against the vendored code, and that reconciliation is enforced by a pytest alignment test, not a prek hook.
The canonical reference for a real bump is PR #66841 ("Bump flask-appbuilder
to 5.2.1 and mirror new auth event hooks") — commit c72b6613fd. Read its diff
first when in doubt: git show c72b6613fd.
providers/fab/pyproject.toml:75-80 explains it: Airflow vendored FAB's
security-manager code into
providers/fab/src/airflow/providers/fab/auth_manager/security_manager/override.py
(~2700 lines) as FabAirflowSecurityManagerOverride. Every bump must review
that class against upstream FAB for new / changed / removed methods.test_fab_alignment.py mechanically detects drift between the installed
FAB package and the vendored override, and fails CI until the developer
reconciles it.https://pypi.org/pypi/flask-appbuilder/json → info.version).
Confirm the target with the user if it is a major or minor bump (higher
reconciliation risk); a patch bump can proceed.Always:
providers/fab/pyproject.toml — line ~80, the flask-appbuilder==X.Y.Z pin
(the only real dependency pin in the repo).providers/fab/tests/unit/fab/auth_manager/security_manager/test_fab_alignment.py
— EXPECTED_FAB_VERSION = "X.Y.Z" (line ~43). Must move in lockstep with the pin.providers/fab/docs/index.rst — the dependency table row
``flask-appbuilder`` ``==X.Y.Z`` (line ~114).providers/fab/README.rst — the Requirements table row (line ~60). Do
not hand-edit — it is auto-generated. Regenerate it from the bumped
pyproject.toml with the sync-provider-readme prek hook (Step 8); the hook
re-renders the table whenever pyproject.toml changes. (Pre-existing bumps
that predate this hook left it to release-time regeneration; today the hook is
per-commit, so CI flags the drift — run it.)uv.lock — regenerated (see Step 4 for the pinned-uv caveat).Conditionally:
providers/fab/src/airflow/providers/fab/auth_manager/security_manager/override.py
— transplant any relevant upstream FAB changes (new auth hooks, changed
signatures, ported fixes). The reference bump added +37 lines here. Note:
a green alignment test does not prove the transplant is unnecessary — a
security fix may live inside a method Airflow vendors (see the 5.2.2 worked
example below).providers/fab/src/airflow/providers/fab/www/** + providers/fab/www-hash.txt
— only if the new FAB ships changed static assets / templates that are
re-vendored (see Step 6).providers/fab/src/airflow/providers/fab/migrations/versions/** — only if the
new FAB version ships DB migrations (see Step 7).Never: no newsfragment, and do not hand-edit providers/fab/docs/changelog.rst
— providers are released from main and the release manager regenerates the
changelog from git log (per providers/AGENTS.md). The commit subject is the
changelog entry.
grep flask-appbuilder== providers/fab/pyproject.toml.https://github.com/dpgaspar/Flask-AppBuilder/releases) for
security-manager / model / template changes before editing.Edit in lockstep:
providers/fab/pyproject.toml — the flask-appbuilder==X.Y.Z line (keep the
trailing # Whenever updating the version, run test_fab_alignment.py to verify.
comment).test_fab_alignment.py — EXPECTED_FAB_VERSION = "X.Y.Z". It is the tripwire;
editing it now is fine — you will keep re-running the test until it and the
other three tests pass.providers/fab/docs/index.rst — the dependency-table ==X.Y.Z row.uv --project providers/fab sync installs the new pin. Confirm the installed
version:
uv run --project providers/fab python -c \
"import importlib.metadata as m; print(m.version('flask-appbuilder'))"The lock must be regenerated with the repo's pinned uv version, or it drifts hundreds of unrelated marker lines:
AIRFLOW_UV_VERSION=$(grep -oE 'AIRFLOW_UV_VERSION=[0-9.]+' Dockerfile.ci | head -1 | cut -d= -f2)
uvx --from uv==$AIRFLOW_UV_VERSION uv lockIf a conflict is irrecoverable, delete uv.lock and re-run uv lock with the
pinned version. Confirm the diff is limited to the FAB bump, not a wholesale
marker rewrite.
uv run --project providers/fab pytest \
providers/fab/tests/unit/fab/auth_manager/security_manager/test_fab_alignment.py -xvsUnder the host sandbox the test needs a writable AIRFLOW_HOME and the
rerun-failures socket disabled — if it errors on a socket bind or on
~/airflow, run it as:
AIRFLOW_HOME="$TMPDIR/fab_home" uv run --project providers/fab pytest \
providers/fab/tests/.../test_fab_alignment.py -q -p no:rerunfailuresThe four tests and how to fix each:
test_fab_version_matches_expected — trips on the version mismatch. It
passes once EXPECTED_FAB_VERSION == installed version, but only after you
have done the review below.test_no_unaudited_fab_methods — a new FAB public method exists that is
neither implemented in override.py nor listed in AUDITED_EXCLUSIONS.
Fix: either implement/override it in override.py, or add it to
AUDITED_EXCLUSIONS with a justification comment.test_no_stale_exclusions — AUDITED_EXCLUSIONS lists a method the new
FAB no longer has. Fix: remove that entry.test_shared_method_signatures_compatible — FAB changed a method
signature (new required param). Fix: update the override.py signature, or
add to KNOWN_SIGNATURE_DEVIATIONS if the divergence is intentional.The manual review that the test cannot fully automate: diff the vendored
override.py against the new FAB's flask_appbuilder/security/sqla/manager.py
and BaseSecurityManager and transplant behavioural changes (bug fixes, new
auth event hooks), not just signatures — the test only checks method presence
and required params. Locate the installed source:
uv run --project providers/fab python -c \
"import flask_appbuilder.security.sqla.manager as m; print(m.__file__)"If the new FAB changed frontend assets that Airflow vendors under
providers/fab/src/airflow/providers/fab/www/ (templates in
templates/appbuilder/, static JS/CSS), re-vendor them, then regenerate the
fingerprint:
prek run compile-fab-assets --all-filesThis runs scripts/ci/prek/compile_provider_assets.py fab (pnpm build over
www/) and rewrites providers/fab/www-hash.txt. A patch bump usually does
not touch assets — skip this step unless FAB's templates/static changed.
Commit the regenerated www-hash.txt if it changed.
If the new FAB adds/changes security-model tables, add the corresponding
migration under providers/fab/src/airflow/providers/fab/migrations/versions/
and run:
prek run update-migration-references-fab check-revision-heads-map-fab --all-filesPatch bumps normally have no migrations — skip unless the release notes mention schema changes.
prek run --from-ref main --stage pre-commit
uv run --project providers/fab pytest providers/fab/tests/unit/fab/auth_manager -xvsThe pre-commit stage runs sync-provider-readme (regenerating README.rst) and
other FAB hooks. Re-run the alignment test until all four tests pass. The full
provider suite is breeze testing providers-tests --test-type "Providers[fab]".
git diff main...HEAD — verify only the intended files changed, and uv.lock
is a clean FAB-scoped diff.Bump flask-appbuilder to X.Y.Z in FAB provider. Body explains
why (what upstream changes were mirrored), not what.providers/fab/CONTRIBUTING.rst so the
FAB-upgrade record stays current.origin and open the PR per the repo's PR conventions.EXPECTED_FAB_VERSION is a second pin. Forgetting it makes
test_fab_alignment.py fail even when everything else is correct.uv.lock marker drift. Always use the pinned uv (Step 4) — a bare
uv lock rewrites hundreds of environment-marker lines and buries the real diff.SecurityManager
(to avoid SQLAlchemy model-registry collisions with Airflow's vendored models).
A green test proves structural alignment; it does not prove behavioural
parity — Step 5's manual transplant review is still required.docs/index.rst dependency table may look auto-generated but the reference
PR edited it by hand; if a docs-regen prek hook rewrites it, let the hook win.README.rst is generated, but the sync hook is per-commit. Don't hand-edit
it; run prek run sync-provider-readme (or the full pre-commit stage) after
bumping pyproject.toml — CI fails on the drift otherwise.providers/fab/docs/upgrading.rst — that is end-user guidance
for upgrading the provider package in a deployment, not the developer bump
workflow.A patch bump that needed no override.py change, but only after a real
behavioural review — the green alignment test alone was not sufficient evidence:
email + "$"), and API-login provider
validation._search_ldap, auth_user_ldap,
auth_user_oauth) — so the alignment test passing did not mean "nothing to
do". Each had to be checked by hand:
_search_ldap already escapes via
ldap.filter.escape_filter_chars (and adds filter-parenthesis validation); it
was ahead of FAB. No transplant.AuthOAuthView
(views.py), and Airflow's CustomAuthOAuthView.oauth_authorized delegates
via super().oauth_authorized(), so the fix is inherited from the installed
FAB 5.2.2. No transplant.pyproject.toml, test_fab_alignment.py, docs/index.rst,
README.rst (via hook), uv.lock. Commit: Bump flask-appbuilder to 5.2.2 in FAB provider.The lesson the skill encodes: for every security/behavioural fix in the FAB release notes, locate the method and check whether Airflow vendors it — the alignment test guards structure, you guard behaviour.
1f529f3
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.