keys_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path"
  8. "testing"
  9. rpc "github.com/mikkeloscar/aur"
  10. gopkg "github.com/mikkeloscar/gopkgbuild"
  11. )
  12. func newPkg(basename string) *rpc.Pkg {
  13. return &rpc.Pkg{Name: basename, PackageBase: basename}
  14. }
  15. func newSplitPkg(basename, name string) *rpc.Pkg {
  16. return &rpc.Pkg{Name: name, PackageBase: basename}
  17. }
  18. func createSrcinfo(pkgbase, srcinfoData string) error {
  19. dir := path.Join(config.BuildDir, pkgbase)
  20. if err := os.Mkdir(dir, 0755); err != nil {
  21. return err
  22. }
  23. return ioutil.WriteFile(path.Join(dir, ".SRCINFO"), []byte(srcinfoData), 0666)
  24. }
  25. func createDummyPkg(pkgbase string, keys []string, split []string) string {
  26. var buffer bytes.Buffer
  27. buffer.WriteString(fmt.Sprintf("pkgbase = %s\n\tpkgver = 42\n\tarch = x86_64\n", pkgbase))
  28. // Keys.
  29. for _, k := range keys {
  30. buffer.WriteString(fmt.Sprintf("validpgpkeys = %s\n", k))
  31. }
  32. buffer.WriteString(fmt.Sprintf("\npkgname = %s\n", pkgbase))
  33. for _, s := range split {
  34. buffer.WriteString(fmt.Sprintf("\npkgname = %s%s\n", pkgbase, s))
  35. }
  36. return buffer.String()
  37. }
  38. func TestFormatKeysToImport(t *testing.T) {
  39. casetests := []struct {
  40. keySet pgpKeySet
  41. bases map[string][]*rpc.Pkg
  42. expected string
  43. alternate string
  44. wantError bool
  45. }{
  46. // Single key, required by single package.
  47. {
  48. keySet: pgpKeySet{"KEY-1": []*rpc.Pkg{newPkg("PKG-foo")}},
  49. expected: fmt.Sprintf("GPG keys need importing:\n\tKEY-1, required by: PKG-foo\n%s Import?", arrow),
  50. wantError: false,
  51. },
  52. // Single key, required by two packages.
  53. {
  54. keySet: pgpKeySet{"KEY-1": []*rpc.Pkg{newPkg("PKG-foo"), newPkg("PKG-bar")}},
  55. expected: fmt.Sprintf("GPG keys need importing:\n\tKEY-1, required by: PKG-foo PKG-bar\n%s Import?", arrow),
  56. wantError: false,
  57. },
  58. // Two keys, each required by a single package. Since iterating the map
  59. // does not force any particular order, we cannot really predict the
  60. // order in which the elements will appear. As we have only two cases,
  61. // let's add the second possibility to the alternate variable, to check
  62. // if there are any errors.
  63. {
  64. keySet: pgpKeySet{"KEY-1": []*rpc.Pkg{newPkg("PKG-foo")}, "KEY-2": []*rpc.Pkg{newPkg("PKG-bar")}},
  65. expected: fmt.Sprintf("GPG keys need importing:\n\tKEY-1, required by: PKG-foo\n\tKEY-2, required by: PKG-bar\n%s Import?", arrow),
  66. alternate: fmt.Sprintf("GPG keys need importing:\n\tKEY-2, required by: PKG-bar\n\tKEY-1, required by: PKG-foo\n%s Import?", arrow),
  67. wantError: false,
  68. },
  69. // Two keys required by single package.
  70. {
  71. keySet: pgpKeySet{"KEY-1": []*rpc.Pkg{newPkg("PKG-foo")}, "KEY-2": []*rpc.Pkg{newPkg("PKG-foo")}},
  72. expected: fmt.Sprintf("GPG keys need importing:\n\tKEY-1, required by: PKG-foo\n\tKEY-2, required by: PKG-foo\n%s Import?", arrow),
  73. alternate: fmt.Sprintf("GPG keys need importing:\n\tKEY-2, required by: PKG-foo\n\tKEY-1, required by: PKG-foo\n%s Import?", arrow),
  74. wantError: false,
  75. },
  76. // Two keys, one of them required by two packages.
  77. {
  78. keySet: pgpKeySet{"KEY-1": []*rpc.Pkg{newPkg("PKG-foo"), newPkg("PKG-bar")}, "KEY-2": []*rpc.Pkg{newPkg("PKG-bar")}},
  79. expected: fmt.Sprintf("GPG keys need importing:\n\tKEY-1, required by: PKG-foo PKG-bar\n\tKEY-2, required by: PKG-bar\n%s Import?", arrow),
  80. alternate: fmt.Sprintf("GPG keys need importing:\n\tKEY-2, required by: PKG-bar\n\tKEY-1, required by: PKG-foo PKG-bar\n%s Import?", arrow),
  81. wantError: false,
  82. },
  83. // Two keys, split package (linux-ck/linux-ck-headers).
  84. {
  85. keySet: pgpKeySet{"ABAF11C65A2970B130ABE3C479BE3E4300411886": []*rpc.Pkg{newPkg("linux-ck")}, "647F28654894E3BD457199BE38DBBDC86092693E": []*rpc.Pkg{newPkg("linux-ck")}},
  86. bases: map[string][]*rpc.Pkg{"linux-ck": {newSplitPkg("linux-ck", "linux-ck-headers"), newPkg("linux-ck")}},
  87. expected: fmt.Sprintf("GPG keys need importing:\n\tABAF11C65A2970B130ABE3C479BE3E4300411886, required by: linux-ck (linux-ck-headers linux-ck)\n\t647F28654894E3BD457199BE38DBBDC86092693E, required by: linux-ck (linux-ck-headers linux-ck)\n%s Import?", arrow),
  88. alternate: fmt.Sprintf("GPG keys need importing:\n\t647F28654894E3BD457199BE38DBBDC86092693E, required by: linux-ck (linux-ck-headers linux-ck)\n\tABAF11C65A2970B130ABE3C479BE3E4300411886, required by: linux-ck (linux-ck-headers linux-ck)\n%s Import?", arrow),
  89. wantError: false,
  90. },
  91. // One key, three split packages.
  92. {
  93. keySet: pgpKeySet{"KEY-1": []*rpc.Pkg{newPkg("PKG-foo")}},
  94. bases: map[string][]*rpc.Pkg{"PKG-foo": {newPkg("PKG-foo"), newSplitPkg("PKG-foo", "PKG-foo-1"), newSplitPkg("PKG-foo", "PKG-foo-2")}},
  95. expected: fmt.Sprintf("GPG keys need importing:\n\tKEY-1, required by: PKG-foo (PKG-foo PKG-foo-1 PKG-foo-2)\n%s Import?", arrow),
  96. wantError: false,
  97. },
  98. // No keys, should fail.
  99. {
  100. keySet: pgpKeySet{},
  101. expected: "",
  102. wantError: true,
  103. },
  104. }
  105. for _, tt := range casetests {
  106. question, err := formatKeysToImport(tt.keySet, tt.bases)
  107. if !tt.wantError {
  108. if err != nil {
  109. t.Fatalf("Got error %q, want no error", err)
  110. }
  111. if question != tt.expected && question != tt.alternate {
  112. t.Fatalf("Got %q\n, expected: %q", question, tt.expected)
  113. }
  114. continue
  115. }
  116. // Here, we want to see the error.
  117. if err == nil {
  118. t.Fatalf("Got no error; want error")
  119. }
  120. }
  121. }
  122. func TestImportKeys(t *testing.T) {
  123. keyringDir, err := ioutil.TempDir("/tmp", "yay-test-keyring")
  124. if err != nil {
  125. t.Fatalf("Unable to init test keyring %q: %v\n", keyringDir, err)
  126. }
  127. // Removing the leftovers.
  128. defer os.RemoveAll(keyringDir)
  129. config.GpgBin = "gpg"
  130. keyringArgs := []string{"--homedir", keyringDir}
  131. casetests := []struct {
  132. keys []string
  133. wantError bool
  134. }{
  135. // Single key, should succeed.
  136. // C52048C0C0748FEE227D47A2702353E0F7E48EDB: Thomas Dickey.
  137. {
  138. keys: []string{"C52048C0C0748FEE227D47A2702353E0F7E48EDB"},
  139. wantError: false,
  140. },
  141. // Two keys, should succeed as well.
  142. // 11E521D646982372EB577A1F8F0871F202119294: Tom Stellard.
  143. // B6C8F98282B944E3B0D5C2530FC3042E345AD05D: Hans Wennborg.
  144. {
  145. keys: []string{"11E521D646982372EB577A1F8F0871F202119294",
  146. "B6C8F98282B944E3B0D5C2530FC3042E345AD05D"},
  147. wantError: false,
  148. },
  149. // Single invalid key, should fail.
  150. {
  151. keys: []string{"THIS-SHOULD-FAIL"},
  152. wantError: true,
  153. },
  154. // Two invalid keys, should fail.
  155. {
  156. keys: []string{"THIS-SHOULD-FAIL", "THIS-ONE-SHOULD-FAIL-TOO"},
  157. wantError: true,
  158. },
  159. // Invalid + valid key. Should fail as well.
  160. // 647F28654894E3BD457199BE38DBBDC86092693E: Greg Kroah-Hartman.
  161. {
  162. keys: []string{"THIS-SHOULD-FAIL",
  163. "647F28654894E3BD457199BE38DBBDC86092693E"},
  164. wantError: true,
  165. },
  166. }
  167. for _, tt := range casetests {
  168. err := importKeys(keyringArgs, tt.keys)
  169. if !tt.wantError {
  170. if err != nil {
  171. t.Fatalf("Got error %q, want no error", err)
  172. }
  173. continue
  174. }
  175. // Here, we want to see the error.
  176. if err == nil {
  177. t.Fatalf("Got no error; want error")
  178. }
  179. }
  180. }
  181. func TestCheckPgpKeys(t *testing.T) {
  182. keyringDir, err := ioutil.TempDir("/tmp", "yay-test-keyring")
  183. if err != nil {
  184. t.Fatalf("Unable to init test keyring: %v\n", err)
  185. }
  186. defer os.RemoveAll(keyringDir)
  187. buildDir, err := ioutil.TempDir("/tmp", "yay-test-build-dir")
  188. if err != nil {
  189. t.Fatalf("Unable to init temp build dir: %v\n", err)
  190. }
  191. defer os.RemoveAll(buildDir)
  192. config.BuildDir = buildDir
  193. config.GpgBin = "gpg"
  194. keyringArgs := []string{"--homedir", keyringDir}
  195. // Creating the dummy package data used in the tests.
  196. dummyData := map[string]string{
  197. "cower": createDummyPkg("cower", []string{"487EACC08557AD082088DABA1EB2638FF56C0C53"}, nil),
  198. "libc++": createDummyPkg("libc++", []string{"11E521D646982372EB577A1F8F0871F202119294", "B6C8F98282B944E3B0D5C2530FC3042E345AD05D"}, []string{"abi", "experimental"}),
  199. "dummy-1": createDummyPkg("dummy-1", []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}, nil),
  200. "dummy-2": createDummyPkg("dummy-2", []string{"ABAF11C65A2970B130ABE3C479BE3E4300411886"}, nil),
  201. "dummy-3": createDummyPkg("dummy-3", []string{"11E521D646982372EB577A1F8F0871F202119294", "C52048C0C0748FEE227D47A2702353E0F7E48EDB"}, nil),
  202. "dummy-4": createDummyPkg("dummy-4", []string{"11E521D646982372EB577A1F8F0871F202119294"}, nil),
  203. "dummy-5": createDummyPkg("dummy-5", []string{"C52048C0C0748FEE227D47A2702353E0F7E48EDB"}, nil),
  204. "dummy-6": createDummyPkg("dummy-6", []string{"THIS-SHOULD-FAIL"}, nil),
  205. "dummy-7": createDummyPkg("dummy-7", []string{"A314827C4E4250A204CE6E13284FC34C8E4B1A25", "THIS-SHOULD-FAIL"}, nil),
  206. }
  207. for pkgbase, srcinfoData := range dummyData {
  208. if err = createSrcinfo(pkgbase, srcinfoData); err != nil {
  209. t.Fatalf("Unable to create dummy data for package %q: %v\n", pkgbase, err)
  210. }
  211. }
  212. casetests := []struct {
  213. pkgs []*rpc.Pkg
  214. srcinfos map[string]*gopkg.PKGBUILD
  215. bases map[string][]*rpc.Pkg
  216. wantError bool
  217. }{
  218. // cower: single package, one valid key not yet in the keyring.
  219. // 487EACC08557AD082088DABA1EB2638FF56C0C53: Dave Reisner.
  220. {
  221. pkgs: []*rpc.Pkg{newPkg("cower")},
  222. bases: map[string][]*rpc.Pkg{"cower": {newPkg("cower")}},
  223. wantError: false,
  224. },
  225. // libc++: single package, two valid keys not yet in the keyring.
  226. // 11E521D646982372EB577A1F8F0871F202119294: Tom Stellard.
  227. // B6C8F98282B944E3B0D5C2530FC3042E345AD05D: Hans Wennborg.
  228. {
  229. pkgs: []*rpc.Pkg{newPkg("libc++")},
  230. bases: map[string][]*rpc.Pkg{"libc++": {newPkg("libc++")}},
  231. wantError: false,
  232. },
  233. // Two dummy packages requiring the same key.
  234. // ABAF11C65A2970B130ABE3C479BE3E4300411886: Linus Torvalds.
  235. {
  236. pkgs: []*rpc.Pkg{newPkg("dummy-1"), newPkg("dummy-2")},
  237. bases: map[string][]*rpc.Pkg{"dummy-1": {newPkg("dummy-1")}, "dummy-2": {newPkg("dummy-2")}},
  238. wantError: false,
  239. },
  240. // dummy package: single package, two valid keys, one of them already
  241. // in the keyring.
  242. // 11E521D646982372EB577A1F8F0871F202119294: Tom Stellard.
  243. // C52048C0C0748FEE227D47A2702353E0F7E48EDB: Thomas Dickey.
  244. {
  245. pkgs: []*rpc.Pkg{newPkg("dummy-3")},
  246. bases: map[string][]*rpc.Pkg{"dummy-3": {newPkg("dummy-3")}},
  247. wantError: false,
  248. },
  249. // Two dummy packages with existing keys.
  250. {
  251. pkgs: []*rpc.Pkg{newPkg("dummy-4"), newPkg("dummy-5")},
  252. bases: map[string][]*rpc.Pkg{"dummy-4": {newPkg("dummy-4")}, "dummy-5": {newPkg("dummy-5")}},
  253. wantError: false,
  254. },
  255. // Dummy package with invalid key, should fail.
  256. {
  257. pkgs: []*rpc.Pkg{newPkg("dummy-6")},
  258. bases: map[string][]*rpc.Pkg{"dummy-6": {newPkg("dummy-6")}},
  259. wantError: true,
  260. },
  261. // Dummy package with both an invalid an another valid key, should fail.
  262. // A314827C4E4250A204CE6E13284FC34C8E4B1A25: Thomas Bächler.
  263. {
  264. pkgs: []*rpc.Pkg{newPkg("dummy-7")},
  265. bases: map[string][]*rpc.Pkg{"dummy-7": {newPkg("dummy-7")}},
  266. wantError: true,
  267. },
  268. }
  269. for _, tt := range casetests {
  270. err := checkPgpKeys(tt.pkgs, tt.bases, keyringArgs)
  271. if !tt.wantError {
  272. if err != nil {
  273. t.Fatalf("Got error %q, want no error", err)
  274. }
  275. continue
  276. }
  277. // Here, we want to see the error.
  278. if err == nil {
  279. t.Fatalf("Got no error; want error")
  280. }
  281. }
  282. }