gitbutler icon indicating copy to clipboard operation
gitbutler copied to clipboard

rebased commits are not re-signed

Open schacon opened this issue 11 months ago • 3 comments

When a branch is updated and commits are rebased and SSH signing is on, we do not properly re-sign the commits. We should be checking for the signing option and re-signing commits that are rebased.

schacon avatar Mar 14 '24 14:03 schacon

I'm able to reproduce the issue. I'll like to work on it. Hope to have a fix ready by Monday.

Pranav2612000 avatar Mar 15 '24 02:03 Pranav2612000

I'll create a more detailed PR soon. But I was able to figure out a fix.

The problem is rebase.commit does not have support for signing the commits. This is because libgit2 itself does not have support for this. Ref: https://libgit2.org/libgit2/#v0.23.2/group/rebase

I was able to make it work by figuring out a workaround by using the commit function ( which in turn uses the commit_signed function to create signed commits. ) https://github.com/gitbutlerapp/gitbutler/blob/229b9b9bc9661c8cbcc4aca8ea5a0f0774456876/gitbutler-app/src/project_repository/repository.rs#L329). In this approach, instead of calling rebase.commit we call the commit function in such a way that it mimics the way rebase.commit would have worked.

Here's a sample piece of code which achieves it ( it's still WIP. I wanted to share it earlier to get feedback )

                if let Some(_) = signing_key {
                    let commit_id = rebase_op.id();
                    let commit = project_repository.find_commit(commit_id.into()).unwrap();
                    let message = commit.message().unwrap();
                    let tree = commit.tree().unwrap();

                    let head = project_repository.get_head().unwrap();
                    let head_commit = head.peel_to_commit().unwrap();

                    if let Ok(commit_id) = project_repository.commit(user, message, &tree, &[&head_commit], signing_key) {
                        last_rebase_head = commit_id.into();
                    } else {
                        rebase_success = false;
                        break;
                    }
                } else {
                    if let Ok(commit_id) = rebase.commit(None, &committer.clone().into(), None) {
                        last_rebase_head = commit_id.into();
                    } else {
                        rebase_success = false;
                        break;
                    }
                }

Thoughts @schacon

Pranav2612000 avatar Mar 15 '24 14:03 Pranav2612000

There's also a parameter in the rebase options of libgit2 – git_commit_create_cb ( https://github.com/libgit2/libgit2/blob/2fe50e295d12fcfcb75bfe5fe08a4582d0aff527/include/git2/rebase.h#L87 ) which runs a commit creation callback which will allow us to sign commits. The official documentation of the function also lists this as a possible use case for git_commit_create_cb. Unfortunately, git2 at the moment does not support this option ( https://docs.rs/git2/latest/git2/struct.RebaseOptions.html ).

There is already an open issue about this https://github.com/rust-lang/git2-rs/issues/850 and I was thinking of contributing a fix upstream as well so that we'll be able to use it in our codebase.

Pranav2612000 avatar Mar 18 '24 03:03 Pranav2612000