Browse Source

Merge pull request #256 from qrwteyrutiyoup/keys

Updates on PGP keys
Morgana 7 years ago
parent
commit
aedbe04b04
9 changed files with 108 additions and 44 deletions
  1. 1 1
      bash-completion
  2. 7 2
      cmd.go
  3. 2 0
      config.go
  4. 1 1
      install.go
  5. 10 12
      keys.go
  6. 67 28
      keys_test.go
  7. 4 0
      parser.go
  8. 14 0
      yay.8
  9. 2 0
      zsh-completion

+ 1 - 1
bash-completion

@@ -68,7 +68,7 @@ _yay() {
   s u')
   common=('arch cachedir color config confirm dbpath debug gpgdir help hookdir logfile
            noconfirm noprogressbar noscriptlet quiet save mflags buildir editor
-           makepkg pacman tar git config requestsplitn sudoloop nosudoloop
+           makepkg pacman tar git gpg gpgflags config requestsplitn sudoloop nosudoloop
            redownload noredownload redownloadall root verbose' 'b d h q r v')
   core=('database files help query remove sync upgrade version' 'D F Q R S U V h')
 

+ 7 - 2
cmd.go

@@ -46,6 +46,7 @@ Permanent configuration options:
     --pacman   <file>    pacman command to use
     --tar      <file>    bsdtar command to use
     --git      <file>    git command to use
+    --gpg      <file>    gpg command to use
     --config   <file>    pacman.conf file to use
 
     --requestsplitn <n>  Max amount of packages to query per AUR request
@@ -63,9 +64,10 @@ Permanent configuration options:
     --noredownload       Skip pkgbuild download if in cache and up to date
     --rebuild            Always build target packages
     --rebuildall         Always build all AUR packages
-    --rebuildtree       Always build all AUR packages even if installed
+    --rebuildtree        Always build all AUR packages even if installed
     --norebuild          Skip package build if in cache and up to date
     --mflags <flags>     Pass arguments to makepkg
+    --gpgflags <flags>   Pass arguments to gpg
     --sudoloop           Loop sudo calls in the background to avoid timeout
     --nosudoloop         Do not loop sudo calls in the background
 
@@ -202,7 +204,6 @@ func initAlpm() (err error) {
 		alpmConf.IgnoreGroup = append(alpmConf.IgnoreGroup, strings.Split(value, ",")...)
 	}
 
-
 	//TODO
 	//current system does not allow duplicate arguments
 	//but pacman allows multiple cachdirs to be passed
@@ -411,6 +412,8 @@ func handleConfig(option, value string) bool {
 		config.ReBuild = "tree"
 	case "norebuild":
 		config.ReBuild = "no"
+	case "gpgflags":
+		config.GpgFlags = value
 	case "mflags":
 		config.MFlags = value
 	case "builddir":
@@ -425,6 +428,8 @@ func handleConfig(option, value string) bool {
 		config.TarBin = value
 	case "git":
 		config.GitBin = value
+	case "gpg":
+		config.GpgBin = value
 	case "requestsplitn":
 		n, err := strconv.Atoi(value)
 		if err == nil && n > 0 {

+ 2 - 0
config.go

@@ -35,6 +35,7 @@ type Configuration struct {
 	ReBuild       string `json:"rebuild"`
 	GitBin        string `json:"gitbin"`
 	GpgBin        string `json:"gpgbin"`
+	GpgFlags      string `json:"gpgflags"`
 	MFlags        string `json:"mflags"`
 	RequestSplitN int    `json:"requestsplitn"`
 	SearchMode    int    `json:"-"`
@@ -127,6 +128,7 @@ func defaultSettings(config *Configuration) {
 	config.NoConfirm = false
 	config.PacmanBin = "pacman"
 	config.PacmanConf = "/etc/pacman.conf"
+	config.GpgFlags = ""
 	config.MFlags = ""
 	config.SortMode = BottomUp
 	config.SudoLoop = false

+ 1 - 1
install.go

@@ -214,7 +214,7 @@ func install(parser *arguments) error {
 			return nil
 		}
 
-		err = checkPgpKeys(dc.Aur, dc.Bases, nil)
+		err = checkPgpKeys(dc.Aur, dc.Bases)
 		if err != nil {
 			return err
 		}

+ 10 - 12
keys.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
+	"path"
 	"strings"
 
 	rpc "github.com/mikkeloscar/aur"
@@ -40,19 +41,17 @@ func (set pgpKeySet) get(key string) bool {
 }
 
 // checkPgpKeys iterates through the keys listed in the PKGBUILDs and if needed,
-// asks the user whether yay should try to import them. gpgExtraArgs are extra
-// parameters to pass to gpg, in order to facilitate testing, such as using a
-// different keyring. It can be nil.
-func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, gpgExtraArgs []string) error {
+// asks the user whether yay should try to import them.
+func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg) error {
 	// Let's check the keys individually, and then we can offer to import
 	// the problematic ones.
 	problematic := make(pgpKeySet)
-	args := append(gpgExtraArgs, "--list-keys")
+	args := append(strings.Fields(config.GpgFlags), "--list-keys")
 
 	// Mapping all the keys.
 	for _, pkg := range pkgs {
-		dir := config.BuildDir + pkg.PackageBase + "/"
-		pkgbuild, err := gopkg.ParseSRCINFO(dir + ".SRCINFO")
+		srcinfo := path.Join(config.BuildDir, pkg.PackageBase, ".SRCINFO")
+		pkgbuild, err := gopkg.ParseSRCINFO(srcinfo)
 		if err != nil {
 			return fmt.Errorf("%s: %s", pkg.Name, err)
 		}
@@ -83,16 +82,15 @@ func checkPgpKeys(pkgs []*rpc.Pkg, bases map[string][]*rpc.Pkg, gpgExtraArgs []s
 		return err
 	}
 	if continueTask(question, "nN") {
-		return importKeys(gpgExtraArgs, problematic.toSlice())
+		return importKeys(problematic.toSlice())
 	}
 
 	return nil
 }
 
-// importKeys tries to import the list of keys specified in its argument. As
-// in checkGpgKeys, gpgExtraArgs are extra parameters to pass to gpg.
-func importKeys(gpgExtraArgs, keys []string) error {
-	args := append(gpgExtraArgs, "--recv-keys")
+// importKeys tries to import the list of keys specified in its argument.
+func importKeys(keys []string) error {
+	args := append(strings.Fields(config.GpgFlags), "--recv-keys")
 	cmd := exec.Command(config.GpgBin, append(args, keys...)...)
 	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
 

+ 67 - 28
keys_test.go

@@ -1,9 +1,11 @@
 package main
 
 import (
+	"bytes"
 	"fmt"
 	"io/ioutil"
 	"os"
+	"path"
 	"testing"
 
 	rpc "github.com/mikkeloscar/aur"
@@ -18,13 +20,29 @@ func newSplitPkg(basename, name string) *rpc.Pkg {
 	return &rpc.Pkg{Name: name, PackageBase: basename}
 }
 
-func initTestKeyring() (string, error) {
-	config.GpgBin = "gpg"
-	tmpdir, err := ioutil.TempDir("/tmp", "yay-test-keyring")
-	if err != nil {
-		return "", err
+func createSrcinfo(pkgbase, srcinfoData string) error {
+	dir := path.Join(config.BuildDir, pkgbase)
+	if err := os.Mkdir(dir, 0755); err != nil {
+		return err
 	}
-	return tmpdir, nil
+
+	return ioutil.WriteFile(path.Join(dir, ".SRCINFO"), []byte(srcinfoData), 0666)
+}
+
+func createDummyPkg(pkgbase string, keys []string, split []string) string {
+	var buffer bytes.Buffer
+	buffer.WriteString(fmt.Sprintf("pkgbase = %s\n\tpkgver = 42\n\tarch = x86_64\n", pkgbase))
+	// Keys.
+	for _, k := range keys {
+		buffer.WriteString(fmt.Sprintf("validpgpkeys = %s\n", k))
+	}
+
+	buffer.WriteString(fmt.Sprintf("\npkgname = %s\n", pkgbase))
+
+	for _, s := range split {
+		buffer.WriteString(fmt.Sprintf("\npkgname = %s%s\n", pkgbase, s))
+	}
+	return buffer.String()
 }
 
 func TestFormatKeysToImport(t *testing.T) {
@@ -116,14 +134,16 @@ func TestFormatKeysToImport(t *testing.T) {
 }
 
 func TestImportKeys(t *testing.T) {
-	keyring, err := initTestKeyring()
+	keyringDir, err := ioutil.TempDir("/tmp", "yay-test-keyring")
 	if err != nil {
-		t.Fatalf("Unable to init test keyring %q: %v\n", keyring, err)
+		t.Fatalf("Unable to init test keyring %q: %v\n", keyringDir, err)
 	}
 
 	// Removing the leftovers.
-	defer os.RemoveAll(keyring)
-	keyringArgs := []string{"--homedir", keyring}
+	defer os.RemoveAll(keyringDir)
+
+	config.GpgBin = "gpg"
+	config.GpgFlags = fmt.Sprintf("--homedir %s", keyringDir)
 
 	casetests := []struct {
 		keys      []string
@@ -163,7 +183,7 @@ func TestImportKeys(t *testing.T) {
 	}
 
 	for _, tt := range casetests {
-		err := importKeys(keyringArgs, tt.keys)
+		err := importKeys(tt.keys)
 		if !tt.wantError {
 			if err != nil {
 				t.Fatalf("Got error %q, want no error", err)
@@ -178,14 +198,40 @@ func TestImportKeys(t *testing.T) {
 }
 
 func TestCheckPgpKeys(t *testing.T) {
-	keyring, err := initTestKeyring()
+	keyringDir, err := ioutil.TempDir("/tmp", "yay-test-keyring")
 	if err != nil {
-		t.Fatalf("Unable to init test keyring %q: %v\n", keyring, err)
+		t.Fatalf("Unable to init test keyring: %v\n", err)
 	}
+	defer os.RemoveAll(keyringDir)
 
-	// Removing the leftovers.
-	defer os.RemoveAll(keyring)
-	keyringArgs := []string{"--homedir", keyring}
+	buildDir, err := ioutil.TempDir("/tmp", "yay-test-build-dir")
+	if err != nil {
+		t.Fatalf("Unable to init temp build dir: %v\n", err)
+	}
+	defer os.RemoveAll(buildDir)
+
+	config.BuildDir = buildDir
+	config.GpgBin = "gpg"
+	config.GpgFlags = fmt.Sprintf("--homedir %s", keyringDir)
+
+	// Creating the dummy package data used in the tests.
+	dummyData := map[string]string{
+		"cower":   createDummyPkg("cower", []string{"487EACC08557AD082088DABA1EB2638FF56C0C53"}, nil),
+		"libc++":  createDummyPkg("libc++", []string{"11E521D646982372EB577A1F8F0871F202119294", "B6C8F98282B944E3B0D5C2530FC3042E345AD05D"}, []string{"abi", "experimental"}),
+		"dummy-1": createDummyPkg("dummy-1", []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}, nil),
+		"dummy-2": createDummyPkg("dummy-2", []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}, nil),
+		"dummy-3": createDummyPkg("dummy-3", []string{"11E521D646982372EB577A1F8F0871F202119294", "C52048C0C0748FEE227D47A2702353E0F7E48EDB"}, nil),
+		"dummy-4": createDummyPkg("dummy-4", []string{"11E521D646982372EB577A1F8F0871F202119294"}, nil),
+		"dummy-5": createDummyPkg("dummy-5", []string{"C52048C0C0748FEE227D47A2702353E0F7E48EDB"}, nil),
+		"dummy-6": createDummyPkg("dummy-6", []string{"THIS-SHOULD-FAIL"}, nil),
+		"dummy-7": createDummyPkg("dummy-7", []string{"A314827C4E4250A204CE6E13284FC34C8E4B1A25", "THIS-SHOULD-FAIL"}, nil),
+	}
+
+	for pkgbase, srcinfoData := range dummyData {
+		if err = createSrcinfo(pkgbase, srcinfoData); err != nil {
+			t.Fatalf("Unable to create dummy data for package %q: %v\n", pkgbase, err)
+		}
+	}
 
 	casetests := []struct {
 		pkgs      []*rpc.Pkg
@@ -197,7 +243,6 @@ func TestCheckPgpKeys(t *testing.T) {
 		// 487EACC08557AD082088DABA1EB2638FF56C0C53: Dave Reisner.
 		{
 			pkgs:      []*rpc.Pkg{newPkg("cower")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"cower": &gopkg.PKGBUILD{Pkgbase: "cower", Validpgpkeys: []string{"487EACC08557AD082088DABA1EB2638FF56C0C53"}}},
 			bases:     map[string][]*rpc.Pkg{"cower": {newPkg("cower")}},
 			wantError: false,
 		},
@@ -206,7 +251,6 @@ func TestCheckPgpKeys(t *testing.T) {
 		// B6C8F98282B944E3B0D5C2530FC3042E345AD05D: Hans Wennborg.
 		{
 			pkgs:      []*rpc.Pkg{newPkg("libc++")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"libc++": &gopkg.PKGBUILD{Pkgbase: "libc++", Validpgpkeys: []string{"11E521D646982372EB577A1F8F0871F202119294", "B6C8F98282B944E3B0D5C2530FC3042E345AD05D"}}},
 			bases:     map[string][]*rpc.Pkg{"libc++": {newPkg("libc++")}},
 			wantError: false,
 		},
@@ -214,7 +258,6 @@ func TestCheckPgpKeys(t *testing.T) {
 		// ABAF11C65A2970B130ABE3C479BE3E4300411886: Linus Torvalds.
 		{
 			pkgs:      []*rpc.Pkg{newPkg("dummy-1"), newPkg("dummy-2")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"dummy-1": &gopkg.PKGBUILD{Pkgbase: "dummy-1", Validpgpkeys: []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}}, "dummy-2": &gopkg.PKGBUILD{Pkgbase: "dummy-2", Validpgpkeys: []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}}},
 			bases:     map[string][]*rpc.Pkg{"dummy-1": {newPkg("dummy-1")}, "dummy-2": {newPkg("dummy-2")}},
 			wantError: false,
 		},
@@ -224,36 +267,32 @@ func TestCheckPgpKeys(t *testing.T) {
 		// C52048C0C0748FEE227D47A2702353E0F7E48EDB: Thomas Dickey.
 		{
 			pkgs:      []*rpc.Pkg{newPkg("dummy-3")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"dummy-3": &gopkg.PKGBUILD{Pkgbase: "dummy-3", Validpgpkeys: []string{"11E521D646982372EB577A1F8F0871F202119294", "C52048C0C0748FEE227D47A2702353E0F7E48EDB"}}},
 			bases:     map[string][]*rpc.Pkg{"dummy-3": {newPkg("dummy-3")}},
 			wantError: false,
 		},
 		// Two dummy packages with existing keys.
 		{
 			pkgs:      []*rpc.Pkg{newPkg("dummy-4"), newPkg("dummy-5")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"dummy-4": &gopkg.PKGBUILD{Pkgbase: "dummy-4", Validpgpkeys: []string{"11E521D646982372EB577A1F8F0871F202119294"}}, "dummy-5": &gopkg.PKGBUILD{Pkgbase: "dummy-5", Validpgpkeys: []string{"C52048C0C0748FEE227D47A2702353E0F7E48EDB"}}},
 			bases:     map[string][]*rpc.Pkg{"dummy-4": {newPkg("dummy-4")}, "dummy-5": {newPkg("dummy-5")}},
 			wantError: false,
 		},
 		// Dummy package with invalid key, should fail.
 		{
-			pkgs:      []*rpc.Pkg{newPkg("dummy-7")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"dummy-7": &gopkg.PKGBUILD{Pkgbase: "dummy-7", Validpgpkeys: []string{"THIS-SHOULD-FAIL"}}},
-			bases:     map[string][]*rpc.Pkg{"dummy-7": {newPkg("dummy-7")}},
+			pkgs:      []*rpc.Pkg{newPkg("dummy-6")},
+			bases:     map[string][]*rpc.Pkg{"dummy-6": {newPkg("dummy-6")}},
 			wantError: true,
 		},
 		// Dummy package with both an invalid an another valid key, should fail.
 		// A314827C4E4250A204CE6E13284FC34C8E4B1A25: Thomas Bächler.
 		{
-			pkgs:      []*rpc.Pkg{newPkg("dummy-8")},
-			srcinfos:  map[string]*gopkg.PKGBUILD{"dummy-8": &gopkg.PKGBUILD{Pkgbase: "dummy-8", Validpgpkeys: []string{"A314827C4E4250A204CE6E13284FC34C8E4B1A25", "THIS-SHOULD-FAIL"}}},
-			bases:     map[string][]*rpc.Pkg{"dummy-8": {newPkg("dummy-8")}},
+			pkgs:      []*rpc.Pkg{newPkg("dummy-7")},
+			bases:     map[string][]*rpc.Pkg{"dummy-7": {newPkg("dummy-7")}},
 			wantError: true,
 		},
 	}
 
 	for _, tt := range casetests {
-		err := checkPgpKeys(tt.pkgs, tt.srcinfos, tt.bases, keyringArgs)
+		err := checkPgpKeys(tt.pkgs, tt.bases)
 		if !tt.wantError {
 			if err != nil {
 				t.Fatalf("Got error %q, want no error", err)

+ 4 - 0
parser.go

@@ -427,6 +427,8 @@ func hasParam(arg string) bool {
 	//yay params
 	case "mflags":
 		return true
+	case "gpgflags":
+		return true
 	case "builddir":
 		return true
 	case "editor":
@@ -439,6 +441,8 @@ func hasParam(arg string) bool {
 		return true
 	case "git":
 		return true
+	case "gpg":
+		return true
 	case "requestsplitn":
 		return true
 	default:

+ 14 - 0
yay.8

@@ -152,6 +152,12 @@ The command to use for \fBgit\fR calls. This can be a command in
 \fBPATH\fR or an absolute path to the file\&.
 .RE
 .PP
+\fB\-\-gpg <file>\fR
+.RS 4
+The command to use for \fBgpg\fR calls. This can be a command in
+\fBPATH\fR or an absolute path to the file\&.
+.RE
+.PP
 \fB\-\-config <file>\fR
 .RS 4
 The pacman config file to use\&.
@@ -257,6 +263,14 @@ passed to makepkg. Multiple arguments may be passed by supplying a space
 separated list that is quoted by the shell.
 .RE
 .PP
+\fB\-\-gpgflags <flags>\fR
+.RS 4
+Passes arguments to gpg\&. These flags get passed to every instance where
+gpg is called by Yay. Arguments are split on whitespace before being
+passed to gpg. Multiple arguments may be passed by supplying a space
+separated list that is quoted by the shell.
+.RE
+.PP
 \fB\-\-sudoloop\fR
 .RS 4
 Loop sudo calls in the background to prevent sudo from timing out during long

+ 2 - 0
zsh-completion

@@ -46,6 +46,7 @@ _pacman_opts_common=(
   '--pacman[pacman command to use]:pacman:_files'
   '--tar[bsdtar command to use]:tar:_files'
   '--git[git command to use]:git:_files'
+  '--gpg[gpg command to use]:gpg:_files'
 
   '--bottomup[Show AUR packages first]'
   '--topdown[Show repository packages first]'
@@ -59,6 +60,7 @@ _pacman_opts_common=(
   '--redownloadall[Always download pkgbuilds of all AUR packages]'
   '--noredownload[Skip pkgbuild download if in cache and up to date]'
   '--mflags[Pass arguments to makepkg]:mflags'
+  '--gpgflags[Pass arguments to gpg]:gpgflags'
   '--sudoloop[Loop sudo calls in the backgroud to avoid timeout]'
   '--nosudoloop[Do not loop sudo calls in the backgrount]'
 )