Merge lp:~elopio/snappy/test-verify into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by Leo Arias
Status: Superseded
Proposed branch: lp:~elopio/snappy/test-verify
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Prerequisite: lp:~elopio/snappy/snappy_from_trunk
Diff against target: 485 lines (+319/-45)
10 files modified
_integration-tests/tests/latest/install_test.go (+9/-0)
cmd/snappy/cmd_verify.go (+43/-0)
helpers/helpers.go (+4/-0)
snappy/build.go (+3/-37)
snappy/build_test.go (+1/-3)
snappy/hashes.go (+85/-0)
snappy/hashes_test.go (+65/-0)
snappy/snapp.go (+26/-5)
snappy/verify.go (+48/-0)
snappy/verify_test.go (+35/-0)
To merge this branch: bzr merge lp:~elopio/snappy/test-verify
Reviewer Review Type Date Requested Status
Michael Vogt Pending
Review via email: mp+263311@code.launchpad.net
To post a comment you must log in.
lp:~elopio/snappy/test-verify updated
520. By Leo Arias

Added a todo comment.

Unmerged revisions

520. By Leo Arias

Added a todo comment.

519. By Leo Arias

Merged with the other verify branch.

518. By Leo Arias

Update the common calls.

517. By Leo Arias

Fixed the suite name.

516. By Leo Arias

Merged with prerequisite.

515. By Leo Arias

Added a verify test.

514. By Leo Arias

Merged with prerequisites.

513. By Michael Vogt

helpers/helpers.go: fix typo in comment (thanks Leo)

512. By Michael Vogt

cmd/snappy/cmd_verify.go: improve help message (thanks Leo!)

511. By Michael Vogt

snappy/snapp.go: remove RemoteSnapPart.Verify, SystemImagePart.Verify

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '_integration-tests/tests/latest/install_test.go'
--- _integration-tests/tests/latest/install_test.go 2015-06-30 03:40:28 +0000
+++ _integration-tests/tests/latest/install_test.go 2015-06-30 03:40:28 +0000
@@ -92,3 +92,12 @@
92 expected := "(?ms).*^apps: hello-world\n"92 expected := "(?ms).*^apps: hello-world\n"
93 c.Assert(infoOutput, Matches, expected)93 c.Assert(infoOutput, Matches, expected)
94}94}
95
96func (s *installSuite) TestVerifyWithInstalledPackage(c *C) {
97 installSnap(c, "hello-world")
98
99 verifyOutput := ExecCommand(c, "snappy", "verify")
100
101 // TODO fill the right expected message.
102 c.Assert(verifyOutput, Equals, "Verified successfully")
103}
95104
=== added file 'cmd/snappy/cmd_verify.go'
--- cmd/snappy/cmd_verify.go 1970-01-01 00:00:00 +0000
+++ cmd/snappy/cmd_verify.go 2015-06-30 03:40:28 +0000
@@ -0,0 +1,43 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2014-2015 Canonical Ltd
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20package main
21
22import (
23 "launchpad.net/snappy/logger"
24 "launchpad.net/snappy/progress"
25 "launchpad.net/snappy/snappy"
26)
27
28type cmdVerify struct {
29}
30
31func init() {
32 _, err := parser.AddCommand("verify",
33 "Verify the integrity of all installed snap packages",
34 "Verify the integrity of all installed snap packages by comparing the permissions, sizes and file hashes of each file",
35 &cmdVerify{})
36 if err != nil {
37 logger.Panicf("Unable to verify: %v", err)
38 }
39}
40
41func (x *cmdVerify) Execute(args []string) (err error) {
42 return snappy.VerifyInstalled(progress.MakeProgressBar())
43}
044
=== modified file 'helpers/helpers.go'
--- helpers/helpers.go 2015-06-09 19:11:54 +0000
+++ helpers/helpers.go 2015-06-30 03:40:28 +0000
@@ -115,6 +115,10 @@
115115
116// UnpackTar unpacks the given tar file into the target directory116// UnpackTar unpacks the given tar file into the target directory
117func UnpackTar(r io.Reader, targetDir string, fn UnpackTarTransformFunc) error {117func UnpackTar(r io.Reader, targetDir string, fn UnpackTarTransformFunc) error {
118 // ensure we extract with the original permissions
119 oldUmask := syscall.Umask(0)
120 defer syscall.Umask(oldUmask)
121
118 return TarIterate(r, func(tr *tar.Reader, hdr *tar.Header) (err error) {122 return TarIterate(r, func(tr *tar.Reader, hdr *tar.Header) (err error) {
119 // run tar transform func123 // run tar transform func
120 name := hdr.Name124 name := hdr.Name
121125
=== modified file 'snappy/build.go'
--- snappy/build.go 2015-06-11 19:30:45 +0000
+++ snappy/build.go 2015-06-30 03:40:28 +0000
@@ -186,42 +186,6 @@
186 return strings.Fields(string(output))[0], nil186 return strings.Fields(string(output))[0], nil
187}187}
188188
189func hashForFile(buildDir, path string, info os.FileInfo) (h *fileHash, err error) {
190 sha512sum := ""
191 // pointer so that omitempty works (we don't want size for
192 // directories or symlinks)
193 var size *int64
194 if info.Mode().IsRegular() {
195 sha512sum, err = helpers.Sha512sum(path)
196 if err != nil {
197 return nil, err
198 }
199 fsize := info.Size()
200 size = &fsize
201 }
202
203 // major/minor handling
204 device := ""
205 major, minor, err := helpers.MajorMinor(info)
206 if err == nil {
207 device = fmt.Sprintf("%v,%v", major, minor)
208 }
209
210 if buildDir != "" {
211 path = path[len(buildDir)+1:]
212 }
213
214 return &fileHash{
215 Name: path,
216 Size: size,
217 Sha512: sha512sum,
218 Device: device,
219 // FIXME: not portable, this output is different on
220 // windows, macos
221 Mode: newYamlFileMode(info.Mode()),
222 }, nil
223}
224
225func writeHashes(buildDir, dataTar string) error {189func writeHashes(buildDir, dataTar string) error {
226190
227 debianDir := filepath.Join(buildDir, "DEBIAN")191 debianDir := filepath.Join(buildDir, "DEBIAN")
@@ -244,10 +208,12 @@
244 return nil208 return nil
245 }209 }
246210
247 hash, err := hashForFile(buildDir, path, info)211 hash, err := hashForFile(path)
248 if err != nil {212 if err != nil {
249 return err213 return err
250 }214 }
215 // adjust the name by removing the builddir
216 hash.Name = hash.Name[len(buildDir)+1:]
251 hashes.Files = append(hashes.Files, hash)217 hashes.Files = append(hashes.Files, hash)
252218
253 return nil219 return nil
254220
=== modified file 'snappy/build_test.go'
--- snappy/build_test.go 2015-06-08 16:26:25 +0000
+++ snappy/build_test.go 2015-06-30 03:40:28 +0000
@@ -432,9 +432,7 @@
432 c.Skip("no /dev/kmsg")432 c.Skip("no /dev/kmsg")
433 }433 }
434434
435 stat, err := os.Stat("/dev/kmsg")435 h, err := hashForFile("/dev/kmsg")
436 c.Assert(err, IsNil)
437 h, err := hashForFile("", "/dev/kmsg", stat)
438 c.Assert(err, IsNil)436 c.Assert(err, IsNil)
439 c.Assert(h.Name, Equals, "/dev/kmsg")437 c.Assert(h.Name, Equals, "/dev/kmsg")
440 c.Assert(h.Device, Equals, "1,11")438 c.Assert(h.Device, Equals, "1,11")
441439
=== modified file 'snappy/hashes.go'
--- snappy/hashes.go 2015-05-15 13:33:27 +0000
+++ snappy/hashes.go 2015-06-30 03:40:28 +0000
@@ -22,6 +22,8 @@
22import (22import (
23 "fmt"23 "fmt"
24 "os"24 "os"
25
26 "launchpad.net/snappy/helpers"
25)27)
2628
27type yamlFileMode struct {29type yamlFileMode struct {
@@ -111,6 +113,40 @@
111 XAttr map[string]string `yaml:"xattr,omitempty"`113 XAttr map[string]string `yaml:"xattr,omitempty"`
112}114}
113115
116func (fh *fileHash) Verify() error {
117 fh2, err := hashForFile(fh.Name)
118 if err != nil {
119 return err
120 }
121
122 // check permissions
123 if fh2.Mode.mode != fh.Mode.mode {
124 return fmt.Errorf("file mode mismatch for %v: 0%o != 0%o", fh.Name, fh.Mode.mode, fh2.Mode.mode)
125 }
126
127 // check size (only files have them)
128 if (fh2.Size == nil && fh.Size != nil) || (fh2.Size != nil && fh.Size == nil) {
129 return fmt.Errorf("size data mismatch for %v", fh.Name)
130 }
131 if fh2.Size != nil && fh.Size != nil {
132 if *fh2.Size != *fh.Size {
133 return fmt.Errorf("size mismatch for %v: %v != %v", fh.Name, *fh.Size, *fh2.Size)
134 }
135 }
136
137 // check hash
138 if fh2.Sha512 != fh.Sha512 {
139 return fmt.Errorf("hash mismatch for %v: %v != %v", fh.Name, fh.Sha512, fh2.Sha512)
140 }
141
142 // check device
143 if fh2.Device != fh.Device {
144 return fmt.Errorf("device info mismatch for %v: %v != %v", fh.Name, fh.Device, fh2.Device)
145 }
146
147 return nil
148}
149
114// the meta/hashes file150// the meta/hashes file
115type hashesYaml struct {151type hashesYaml struct {
116 // the archive hash152 // the archive hash
@@ -119,3 +155,52 @@
119 // the hashes for the files in the archive155 // the hashes for the files in the archive
120 Files []*fileHash156 Files []*fileHash
121}157}
158
159func (h *hashesYaml) Verify() error {
160 for _, fh := range h.Files {
161 if err := fh.Verify(); err != nil {
162 return err
163 }
164 }
165
166 return nil
167}
168
169// get the path for the given file
170func hashForFile(path string) (h *fileHash, err error) {
171 sha512sum := ""
172
173 info, err := os.Lstat(path)
174 if err != nil {
175 return nil, err
176 }
177
178 // pointer so that omitempty works (we don't want size for
179 // directories or symlinks)
180 var size *int64
181 if info.Mode().IsRegular() {
182 sha512sum, err = helpers.Sha512sum(path)
183 if err != nil {
184 return nil, err
185 }
186 fsize := info.Size()
187 size = &fsize
188 }
189
190 // major/minor handling
191 device := ""
192 major, minor, err := helpers.MajorMinor(info)
193 if err == nil {
194 device = fmt.Sprintf("%v,%v", major, minor)
195 }
196
197 return &fileHash{
198 Name: path,
199 Size: size,
200 Sha512: sha512sum,
201 Device: device,
202 // FIXME: not portable, this output is different on
203 // windows, macos
204 Mode: newYamlFileMode(info.Mode()),
205 }, nil
206}
122207
=== modified file 'snappy/hashes_test.go'
--- snappy/hashes_test.go 2015-06-02 20:46:07 +0000
+++ snappy/hashes_test.go 2015-06-30 03:40:28 +0000
@@ -152,3 +152,68 @@
152 mode: frw-r--r--152 mode: frw-r--r--
153`)153`)
154}154}
155
156func makeTestFileWithHash(c *C) (*fileHash, string) {
157 p := filepath.Join(c.MkDir(), "foo")
158 err := ioutil.WriteFile(p, []byte("bar\n"), 0644)
159 c.Assert(err, IsNil)
160 st, err := os.Stat(p)
161 c.Assert(err, IsNil)
162
163 size := int64(4)
164 mode := newYamlFileMode(st.Mode())
165 fh := fileHash{
166 Name: p,
167 Size: &size,
168 Sha512: "cc06808cbbee0510331aa97974132e8dc296aeb795be229d064bae784b0a87a5cf4281d82e8c99271b75db2148f08a026c1a60ed9cabdb8cac6d24242dac4063",
169 Mode: mode,
170 }
171 return &fh, p
172}
173
174func (s *SnapTestSuite) TestFileHashSimple(c *C) {
175 fh, _ := makeTestFileWithHash(c)
176 err := fh.Verify()
177 c.Assert(err, IsNil)
178}
179
180func (s *SnapTestSuite) TestFileHashWrongSize(c *C) {
181 fh, _ := makeTestFileWithHash(c)
182
183 fakeSize := int64(1)
184 fh.Size = &fakeSize
185
186 err := fh.Verify()
187 c.Assert(err, ErrorMatches, "size mismatch for .*/foo: 1 != 4")
188}
189
190func (s *SnapTestSuite) TestFileHashWrongMode(c *C) {
191 fh, _ := makeTestFileWithHash(c)
192 fh.Mode.mode = 0444
193
194 err := fh.Verify()
195 c.Assert(err, ErrorMatches, "file mode mismatch for .*/foo: 0444 != 0644")
196}
197
198func (s *SnapTestSuite) TestFileHashWrongHash(c *C) {
199 fh, _ := makeTestFileWithHash(c)
200 fh.Sha512 = "xx"
201
202 err := fh.Verify()
203 c.Assert(err, ErrorMatches, "hash mismatch for .*/foo: xx != cc06808cbbee0510331aa97974132e8dc296aeb795be229d064bae784b0a87a5cf4281d82e8c99271b75db2148f08a026c1a60ed9cabdb8cac6d24242dac4063")
204}
205
206func (s *SnapTestSuite) TestFileHashForDir(c *C) {
207 name := c.MkDir()
208 st, err := os.Stat(name)
209 c.Assert(err, IsNil)
210
211 mode := newYamlFileMode(st.Mode())
212 fh := fileHash{
213 Name: name,
214 Mode: mode,
215 }
216
217 err = fh.Verify()
218 c.Assert(err, IsNil)
219}
155220
=== modified file 'snappy/snapp.go'
--- snappy/snapp.go 2015-06-12 03:55:01 +0000
+++ snappy/snapp.go 2015-06-30 03:40:28 +0000
@@ -608,9 +608,18 @@
608 part.description = description608 part.description = description
609 }609 }
610610
611 // read hash, its ok if its not there, some older versions of611 // read hash
612 // snappy did not write this file612 h, err := part.hashesData()
613 hashesData, err := ioutil.ReadFile(filepath.Join(part.basedir, "meta", "hashes.yaml"))613 if err != nil {
614 return nil, err
615 }
616 part.hash = h.ArchiveSha512
617
618 return part, nil
619}
620
621func (s *SnapPart) hashesData() (*hashesYaml, error) {
622 hashesData, err := ioutil.ReadFile(filepath.Join(s.basedir, "meta", "hashes.yaml"))
614 if err != nil {623 if err != nil {
615 return nil, err624 return nil, err
616 }625 }
@@ -620,9 +629,8 @@
620 if err != nil {629 if err != nil {
621 return nil, &ErrInvalidYaml{file: "hashes.yaml", err: err, yaml: hashesData}630 return nil, &ErrInvalidYaml{file: "hashes.yaml", err: err, yaml: hashesData}
622 }631 }
623 part.hash = h.ArchiveSha512
624632
625 return part, nil633 return &h, nil
626}634}
627635
628// Type returns the type of the SnapPart (app, oem, ...)636// Type returns the type of the SnapPart (app, oem, ...)
@@ -1083,6 +1091,19 @@
1083 return s.m.Frameworks, nil1091 return s.m.Frameworks, nil
1084}1092}
10851093
1094// Verify checks the integrity
1095func (s *SnapPart) Verify(pb progress.Meter) error {
1096 hashesData, err := s.hashesData()
1097 if err != nil {
1098 return err
1099 }
1100
1101 helpers.ChDir(s.basedir, func() {
1102 err = hashesData.Verify()
1103 })
1104 return err
1105}
1106
1086// DependentNames returns a list of the names of apps installed that1107// DependentNames returns a list of the names of apps installed that
1087// depend on this one1108// depend on this one
1088//1109//
10891110
=== added file 'snappy/verify.go'
--- snappy/verify.go 1970-01-01 00:00:00 +0000
+++ snappy/verify.go 2015-06-30 03:40:28 +0000
@@ -0,0 +1,48 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2014-2015 Canonical Ltd
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20package snappy
21
22import (
23 "fmt"
24
25 "launchpad.net/snappy/progress"
26)
27
28// VerifyInstalled verifies all installed snaps
29func VerifyInstalled(pb progress.Meter) error {
30 m := NewMetaLocalRepository()
31 installed, err := m.Installed()
32 if err != nil {
33 return err
34 }
35
36 for _, part := range installed {
37 if _, ok := part.(*SnapPart); !ok {
38 continue
39 }
40 pb.Notify(fmt.Sprintf("Verifying %s", part.Name()))
41 if err := part.(*SnapPart).Verify(pb); err != nil {
42 return fmt.Errorf("verify for %v failed: %v", part.Name(), err)
43 }
44 }
45 pb.Notify(fmt.Sprintf("Verified %d successfully", len(installed)))
46
47 return nil
48}
049
=== added file 'snappy/verify_test.go'
--- snappy/verify_test.go 1970-01-01 00:00:00 +0000
+++ snappy/verify_test.go 2015-06-30 03:40:28 +0000
@@ -0,0 +1,35 @@
1// -*- Mode: Go; indent-tabs-mode: t -*-
2
3/*
4 * Copyright (C) 2014-2015 Canonical Ltd
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20package snappy
21
22import (
23 "path/filepath"
24
25 . "gopkg.in/check.v1"
26)
27
28func (s *SnapTestSuite) TestSnapVerifyWorksWithSystemImage(c *C) {
29 systemImageRoot = c.MkDir()
30
31 makeFakeSystemImageChannelConfig(c, filepath.Join(systemImageRoot, systemImageChannelConfig), "1")
32
33 err := VerifyInstalled(&MockProgressMeter{})
34 c.Assert(err, IsNil)
35}

Subscribers

People subscribed via source and target branches