Skip to content

Conversation

@Dev-iL
Copy link
Collaborator

@Dev-iL Dev-iL commented Jan 8, 2026

- This PR was created with the help of AI

Depends on: #60270

Specific issues addressed:

  1. Repository file permissions: Cloned repositories inherit default umask permissions, which may not allow group access for impersonated users
  2. Git "dubious ownership" error: Git 2.35.2+ refuses to operate on repositories owned by different users without explicit safe.directory configuration

Changes

  1. _apply_permissions_recursively(path)
    New helper function that walks a directory tree and applies the configured dag_bundle_new_folder_permissions and dag_bundle_new_file_permissions to all directories and files.

  2. _configure_git_safe_directory(path)
    New helper function that adds the repository path to git's global safe.directory configuration, allowing git operations by users who don't own the repository.


^ Add meaningful description above
Read the Pull Request Guidelines for more information.
In case of fundamental code changes, an Airflow Improvement Proposal (AIP) is needed.
In case of a new dependency, check compliance with the ASF 3rd Party License Policy.
In case of backwards incompatible changes please leave a note in a newsfragment file, named {pr_number}.significant.rst or {issue_number}.significant.rst, in airflow-core/newsfragments.

("dag_processor", "dag_bundle_new_folder_permissions"): "0o775",
("dag_processor", "dag_bundle_new_file_permissions"): "0o664",
}
):
Copy link
Contributor

Choose a reason for hiding this comment

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

You should have included the other PR and mark this as dependent on that one

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I figured it would be easier to review in isolation.

Is there any specific way to mark a dependency? I did note it at the top of the PR description.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I rewrote the changes to be standalone via common.compat.

Git 2.35.2+ refuses to operate on repositories owned by different users
without explicit safe directory configuration. This is needed when using
user impersonation (run_as_user) where the repository is created by one
user but accessed by another.
Copy link
Contributor

Choose a reason for hiding this comment

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

What if the run_as_user is configured in only one task?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is perhaps slightly more permissive than strictly necessary. However, even if only one task uses run_as_user, the repository still needs to be accessible during DAG parsing, and having consistent permissions simplifies the security model.

How about I add the following docstring explaining this design decision?

def _apply_permissions_recursively(path: Path) -> None:
    """
    Apply configured bundle permissions to a directory tree.
    
    This ensures that when user impersonation is used, the impersonated user
    can access the cloned repository files.  Permissions are applied at clone
    time regardless of whether all or only some tasks use run_as_user, because: 
    1. DAG parsing needs access before task execution
    2. Bundles may serve multiple DAGs with different impersonation settings
    3. Applying permissions upfront provides a consistent security model
    
    :param path: The root path to apply permissions to recursively
    """


try:
subprocess.run(
["git", "config", "--global", "--add", "safe.directory", str(path)],
Copy link
Member

Choose a reason for hiding this comment

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

I’m not sure if this is a good idea… I’d not expect my global Git config to be silently changed. Can this be repo-local instead?

Copy link
Member

Choose a reason for hiding this comment

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

Also, why does this need to use a subprocess instead of the GitPython API?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  • Why global: I believe repository-local config is ignored for security reasons (otherwise malicious repos could whitelist themselves). Airflow typically runs in controlled environments (containers/VMs), modifying the global git config for the airflow user should be acceptable.
  • Why not GitPython:
    1. We need to configure safe.directory before creating the Repo object (L234), because GitPython internally runs git commands during Repo initialization. If the ownership check fails at that point, we get an exception before we can configure anything.
    2. While GitPython has GitConfigParser that can write to any config file, using it for ~/.gitconfig would essentially reimplement git config --global with more code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Another approach to consider:

If cloning a bare repository or a repository intended for multiple users (using git clone --shared), Git can be told to ignore the umask and use a specific scheme via the core.sharedRepository setting:

  • group (or true): Makes the repository group-writable (ignores umask for the group bits).
  • all (or world): Makes the repository readable by everyone.
  • 0xxx: An explicit octal mode (e.g., 0660).

@Dev-iL Dev-iL force-pushed the 2601/git_permissions branch 2 times, most recently from bf76aed to 41b5007 Compare January 13, 2026 08:24
@Dev-iL Dev-iL force-pushed the 2601/git_permissions branch from 41b5007 to a22d5cc Compare January 13, 2026 09:00
@Dev-iL
Copy link
Collaborator Author

Dev-iL commented Jan 14, 2026

Closing because a broader solution is preferred. See also: #60270 (comment)

@Dev-iL Dev-iL closed this Jan 14, 2026
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