Linux maintainer tooling and workflows
 help / color / mirror / Atom feed
From: Christian Brauner <brauner@kernel.org>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
	 "Christian Brauner (Amutable)" <brauner@kernel.org>,
	 "str = 'test"@example.com'
Subject: [PATCH b4 2/2] tests: guard the test-apply probes against gpg signing
Date: Thu, 23 Jul 2026 10:33:36 +0200	[thread overview]
Message-ID: <20260723-work-b4-testapply-nosign-v1-2-a7cb7105e06f@kernel.org> (raw)
In-Reply-To: <20260723-work-b4-testapply-nosign-v1-0-a7cb7105e06f@kernel.org>

Test gpg override as best as possible. The tests force
commit.gpgsign=true with gpg.program=/bin/false through appended
GIT_CONFIG_* environment entries so a probe that regresses into signing
fails the apply and the test.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 src/tests/test_tui_tracking.py | 113 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 109 insertions(+), 4 deletions(-)

diff --git a/src/tests/test_tui_tracking.py b/src/tests/test_tui_tracking.py
index c987022..a809037 100644
--- a/src/tests/test_tui_tracking.py
+++ b/src/tests/test_tui_tracking.py
@@ -36,12 +36,15 @@ from b4 import (
 from b4.review_tui._modals import (
     ActionItem,
     ActionScreen,
+    BaseSelectionScreen,
     CherryPickScreen,
     ConfirmScreen,
     HelpScreen,
     LimitScreen,
     LinkRevisionScreen,
+    RebaseScreen,
     SnoozeScreen,
+    TakeConfirmScreen,
     TargetBranchScreen,
 )
 from b4.review_tui._tracking_app import (
@@ -121,10 +124,13 @@ def _create_review_branch(
     subject: str = 'Test series',
     sender_name: str = 'Test Author',
     sender_email: str = 'test@example.com',
+    with_patch: bool = False,
 ) -> str:
     """Create a fake b4 review branch with a proper tracking commit.
 
-    Returns the branch name.
+    With ``with_patch``, a real patch commit modifying file1.txt sits
+    between the base and the tracking commit, and the tracking metadata
+    describes it.  Returns the branch name.
     """
     branch_name = f'b4/review/{change_id}'
     # Get current HEAD as base
@@ -134,6 +140,24 @@ def _create_review_branch(
     # Create the branch at HEAD
     ecode, _ = b4.git_run_command(gitdir, ['branch', branch_name, base_sha])
     assert ecode == 0
+    parent_sha = base_sha
+    patches: List[Dict[str, Any]] = []
+    if with_patch:
+        ecode, _ = b4.git_run_command(gitdir, ['checkout', branch_name])
+        assert ecode == 0
+        with open(os.path.join(gitdir, 'file1.txt'), 'a') as fh:
+            fh.write(f'{change_id} tweak\n')
+        b4.git_run_command(gitdir, ['add', 'file1.txt'])
+        ecode, _ = b4.git_run_command(
+            gitdir, ['commit', '-m', f'{change_id}: tweak file1']
+        )
+        assert ecode == 0
+        ecode, parent_sha = b4.git_run_command(gitdir, ['rev-parse', 'HEAD'])
+        assert ecode == 0
+        parent_sha = parent_sha.strip()
+        ecode, _ = b4.git_run_command(gitdir, ['checkout', 'master'])
+        assert ecode == 0
+        patches = [{'title': f'{change_id}: tweak file1', 'link': ''}]
     # Build tracking metadata
     trk = {
         'series': {
@@ -148,11 +172,11 @@ def _create_review_branch(
             'complete': True,
             'base-commit': base_sha,
             'prerequisite-commits': [],
-            'first-patch-commit': base_sha,
+            'first-patch-commit': parent_sha,
             'header-info': {},
         },
         'followups': [],
-        'patches': [],
+        'patches': patches,
     }
     commit_msg = f'{subject}\n\n{b4.review.make_review_magic_json(trk)}'
     # Create an empty tracking commit on the branch
@@ -161,7 +185,7 @@ def _create_review_branch(
     tree = tree.strip()
     ecode, new_sha = b4.git_run_command(
         gitdir,
-        ['commit-tree', tree, '-p', base_sha],
+        ['commit-tree', tree, '-p', parent_sha],
         stdin=commit_msg.encode(),
     )
     assert ecode == 0
@@ -4140,3 +4164,84 @@ class TestDoTakeMergeConflict:
         common_dir = b4.git_get_common_dir(gitdir)
         assert common_dir is not None
         assert not os.path.isdir(os.path.join(common_dir, 'b4-take-worktree'))
+
+
+def _poison_gpg_signing(monkeypatch: pytest.MonkeyPatch) -> None:
+    """Force commit.gpgsign=true with a signing backend that always fails.
+
+    The appended entries override conftest's gpgsign=false injection, so
+    any git command that tries to sign fails outright; only a command
+    that explicitly disables signing (git -c commit.gpgsign=false, which
+    outranks environment config) can create commits.
+
+    gpg.format is pinned because the suite does not isolate the global
+    git config: under gpg.format=ssh git signs through gpg.ssh.program
+    and never looks at gpg.program, so the probes would sign happily and
+    these tests would pass with the fix reverted.
+
+    Build fixtures before poisoning -- they commit normally.
+    """
+    entries = [
+        ('commit.gpgsign', 'true'),
+        ('gpg.format', 'openpgp'),
+        ('gpg.program', '/bin/false'),
+    ]
+    count = int(os.environ.get('GIT_CONFIG_COUNT', '0'))
+    monkeypatch.setenv('GIT_CONFIG_COUNT', str(count + len(entries)))
+    for idx, (key, value) in enumerate(entries, start=count):
+        monkeypatch.setenv(f'GIT_CONFIG_KEY_{idx}', key)
+        monkeypatch.setenv(f'GIT_CONFIG_VALUE_{idx}', value)
+
+
+def _one_patch_mbox(gitdir: str) -> bytes:
+    """Build mbox bytes for one patch that applies cleanly to master."""
+    ecode, _ = b4.git_run_command(gitdir, ['checkout', '-b', 'sign-tweak'])
+    assert ecode == 0
+    with open(os.path.join(gitdir, 'file1.txt'), 'a') as fh:
+        fh.write('sign-tweak\n')
+    b4.git_run_command(gitdir, ['add', 'file1.txt'])
+    ecode, _ = b4.git_run_command(gitdir, ['commit', '-m', 'sign-tweak file1'])
+    assert ecode == 0
+    ecode, mbox = b4.git_run_command(
+        gitdir, ['format-patch', '-1', '--stdout'], decode=False
+    )
+    assert ecode == 0
+    b4.git_run_command(gitdir, ['checkout', 'master'])
+    b4.git_run_command(gitdir, ['branch', '-D', 'sign-tweak'])
+    return mbox
+
+
+class TestTestApplyNoSigning:
+    """Throwaway test-applies must never gpg-sign their commits.
+
+    With commit.gpgsign=true and a card-backed key, a signing git-am in a
+    modal worker pops pinentry on the tty the live TUI owns -- the TUI
+    repaints over the prompt and swallows the PIN, hanging the apply.
+    With gpg poisoned to always fail, these pass only if the test-apply
+    disables signing.
+    """
+
+    @pytest.mark.parametrize(
+        'screen_cls',
+        [RebaseScreen, TargetBranchScreen, BaseSelectionScreen],
+        ids=lambda c: c.__name__,
+    )
+    def test_static_test_apply_does_not_sign(
+        self,
+        gitdir: str,
+        monkeypatch: pytest.MonkeyPatch,
+        screen_cls: Any,
+    ) -> None:
+        ambytes = _one_patch_mbox(gitdir)
+        _poison_gpg_signing(monkeypatch)
+        ok, detail = screen_cls._test_apply_at(ambytes, 'master')
+        assert ok, f'{screen_cls.__name__} test-apply tried to sign: {detail}'
+
+    def test_take_confirm_test_apply_does_not_sign(
+        self, gitdir: str, monkeypatch: pytest.MonkeyPatch
+    ) -> None:
+        branch = _create_review_branch(gitdir, 'sign-take', with_patch=True)
+        _poison_gpg_signing(monkeypatch)
+        screen = TakeConfirmScreen('linear', 'master', branch)
+        ok, detail = screen._test_take()
+        assert ok, f'take test-apply tried to sign: {detail}'

-- 
2.53.0


  parent reply	other threads:[~2026-07-23  8:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23  8:33 [PATCH b4 0/2] review-tui: don't gpg-sign throwaway test-apply commits Christian Brauner
2026-07-23  8:33 ` [PATCH b4 1/2] " Christian Brauner
2026-07-23  8:33 ` Christian Brauner [this message]
2026-07-23 15:33 ` [PATCH b4 0/2] " Nicolas Schier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260723-work-b4-testapply-nosign-v1-2-a7cb7105e06f@kernel.org \
    --to=brauner@kernel.org \
    --cc="str = 'test"@example.com' \
    --cc=konstantin@linuxfoundation.org \
    --cc=tools@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox