Package: git-buildpackage
Version: 0.8.9
Severity: normal
Tags: patch

I'm currently using git-buildpackage with a custom --builder command
(vectis, https://github.com/smcv/vectis) that among other things accepts
a command-line option of the form:

    --extra-repository='deb [trusted=yes] http://localhost/path suite component'

With git-buildpackage, I have to backslash-escape the spaces:

    --extra-repository='deb\ [trusted=yes]\ ...'

or it will treat "--extra-repository=deb", "[trusted=yes]", etc. as
separate command-line arguments for vectis. This is because
gbp.command_wrappers.Command(..., shell=True) just joins the command
to the arguments with " ".join() rather than doing proper shell quoting.
That's correct for the --builder as currently documented, but not for
its arguments.

It would be easy to run into this with debuild if you're using something
like gbp buildpackage --set-envvar=DEBFULLNAME="Simon McVittie"
(a debuild option) or gbp buildpackage --check-command="lintian -Ii"
(a dpkg-buildpackage option).

Doing proper shell quoting in Python 3 is trival (shlex.quote, which
I use a lot in vectis) but Python 2 doesn't have that function. However,
there is another way to get the --builder interpreted as a shell
one-liner and still pass it arguments: you can invoke

    ["sh", "-c", ('%s "$@"' % builder), "sh"] + arguments

with shell=False, and it will do the right thing. The first "sh" in
that monster is argv[0] for the subprocess, and the second is $0 for
the shell one-liner.

I attach a possible patch.

    S
>From a088aef91ffa9de60c6d7ac3278360ce0ee571e1 Mon Sep 17 00:00:00 2001
From: Simon McVittie <s...@debian.org>
Date: Tue, 10 Jan 2017 19:49:08 +0000
Subject: [PATCH] buildpackage: don't treat dpkg arguments as shell input

If one of gbp buildpackage's command-line arguments (after processing
by the calling shell if applicable) includes spaces or shell
metacharacters, it's unexpected to subject it to a layer of shell
interpretation. Conversely, the builder option is documented to be
a shell command and so must go through one layer of shell
interpretation.

This makes an invocation like

    gbp buildpackage --check-command="lintian -Ii"

work the way it was presumably intended.
---
 gbp/scripts/buildpackage.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/gbp/scripts/buildpackage.py b/gbp/scripts/buildpackage.py
index 6524f01..c7ad903 100755
--- a/gbp/scripts/buildpackage.py
+++ b/gbp/scripts/buildpackage.py
@@ -727,7 +727,11 @@ def main(argv):
                      )(dir=build_dir)
 
             # Finally build the package:
-            RunAtCommand(options.builder, dpkg_args, shell=True,
+            RunAtCommand('sh',
+                         ['-c', options.builder + ' "$@"',
+                          'sh'] +       # $0 for the shell one-liner
+                         dpkg_args,     # $@ for the shell one-liner
+                         shell=False,   # we start the shell explicitly
                          extra_env=Hook.md(build_env,
                                            {'GBP_BUILD_DIR': build_dir})
                          )(dir=build_dir)
-- 
2.11.0

Reply via email to