Skip to content

Close the ssh askpass helper before ssh executes it - #73427

Open
MichalJaroslawKrzywanski-TomTom wants to merge 5 commits into
apache:mainfrom
MichalJaroslawKrzywanski-TomTom:fix-git-askpass-etxtbsy
Open

MichalJaroslawKrzywanski-TomTom wants to merge 5 commits into
apache:mainfrom
MichalJaroslawKrzywanski-TomTom:fix-git-askpass-etxtbsy

Conversation

@MichalJaroslawKrzywanski-TomTom

@MichalJaroslawKrzywanski-TomTom MichalJaroslawKrzywanski-TomTom commented Sep 21, 2026 •

Copy link
Copy Markdown

GitHook writes the SSH_ASKPASS helper that unlocks a passphrase-protected private key with NamedTemporaryFile(delete=True) and keeps the handle open for writing while ssh runs. Linux refuses to exec a file that is still open for writing (ETXTBSY, "Text file busy"), so a clone or fetch with a passphrase-protected key fails with cannot exec '/tmp/tmpXXXX.sh': Text file busy and then falls back to prompting for the passphrase. macOS does not enforce this, which hid the bug.

The fix writes the helper through a small module-level context manager (_executable_script) that closes the file before yielding its path and unlinks it in finally.

Scope changed after a rebase on main

This PR originally fixed the same bug on both askpass paths. #64105 has since replaced GIT_ASKPASS with a credential helper that is written and closed before git runs, which fixes the token path upstream, so only SSH_ASKPASS is left to fix here. The test that exercised the old GitHub App askpass script is dropped with the mechanism it tested; #64105's own tests cover the credential helper.

That also means #73425, which reported the failure on the GitHub App path, is already fixed on main by #64105 rather than by this PR — hence related: instead of closes:.

Verification

Run in apache/airflow:3.2.2-python3.10 (Debian 12, git 2.39.5) against the rebased branch:

providers/git/tests/unit/git/hooks/test_git.py .......................................................
55 passed

With main's unpatched hook, the added test fails there:

E   OSError: [Errno 26] Text file busy: '/tmp/tmpyrbc4wtp.sh'

ruff check and ruff format --check are clean on both changed files.

related: #73425
related: #64105


Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code following the guidelines. The diagnosis, the fix, the tests and the rebase resolution were reviewed by hand; the ETXTBSY reproduction and the test runs above were executed by me.

@boring-cyborg

boring-cyborg Bot commented Sep 21, 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

GitHook writes the SSH_ASKPASS helper that unlocks a passphrase-protected
private key with NamedTemporaryFile(delete=True) and keeps the handle open for
writing while ssh runs. Linux refuses to exec a file that is still open for
writing (ETXTBSY, "Text file busy"), so a clone or fetch with a
passphrase-protected key fails with "cannot exec ...: Text file busy" and then
falls back to prompting for the passphrase. macOS does not enforce this, which
hid the bug.

Write the helper through a small module-level context manager that closes the
file before yielding its path and unlinks it in finally. The added test runs
the helper through configure_hook_env and asserts its output; on Linux it fails
without the fix with "OSError: [Errno 26] Text file busy".

The token path hit the same constraint. apache#64105 fixed it there by replacing
GIT_ASKPASS with a credential helper written and closed before git runs, which
is why this change is now limited to SSH_ASKPASS.

related: apache#73425
related: apache#64105

Co-Authored-By: krzywans <MichalJaroslaw.Krzywanski@tomtom.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@MichalJaroslawKrzywanski-TomTom MichalJaroslawKrzywanski-TomTom changed the title Close git askpass helpers before git and ssh execute them Close the ssh askpass helper before ssh executes it Sep 22, 2026

@shahar1 shahar1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@shahar1

shahar1 commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

@MichalJaroslawKrzywanski-TomTom Please do not merge from main so I could see that all checks are green and merge. Thank you!

This branch has not been deployed

No deployments
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