Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
Add source-checksum option #619
Conversation
tsimonq2
added some commits
Jun 29, 2016
snappy-m-o
commented
Jun 30, 2016
|
Can one of the admins verify this patch? |
snappy-m-o
commented
Jun 30, 2016
|
Can one of the admins verify this patch? |
sergiusens
reviewed
Jun 30, 2016
| from snapcraft.internal import common | ||
| - | ||
| -logging.getLogger('urllib3').setLevel(logging.CRITICAL) | ||
| +logging.getLogger('urllib').setLevel(logging.CRITICAL) |
sergiusens
reviewed
Jun 30, 2016
| # TODO add unit tests. | ||
| tarball = os.path.join(self.source_dir, os.path.basename(self.source)) | ||
| + self.pre_check_checksum(self, source_checksum, tarball) |
sergiusens
reviewed
Jun 30, 2016
| + raise IncompatibleOptionsError( | ||
| + 'can\'t specify source-checksum for a zip source right now') | ||
| + | ||
| + def pre_check_checksum(self, source_checksum, zip): |
sergiusens
Jun 30, 2016
Collaborator
this looks like duplicate code, please consider adding it to FileBase (which also needs its init updated)
|
Please merge with master or rebase |
|
you also need to update https://github.com/snapcore/snapcraft/pull/619/files#diff-e6205a80af76b4faec1d9241dc3b3b7cR455 |
tsimonq2
added some commits
Jun 30, 2016
|
@sergiusens Thanks for taking the time to look at this. I updated my code with your suggestions. Let me know what you think. @elopio Can you please take a look? |
|
From a quick look at the test failures it seems you still need to update all constructors for the sources used in the unit tests. |
tsimonq2
added some commits
Jul 1, 2016
|
So right now, the Travis build has passed. My goal now is to do some more local testing and to get an integration test ready. I'll change the description accordingly. |
tsimonq2
added some commits
Jul 5, 2016
snappy-m-o
commented
Jul 6, 2016
|
Can one of the admins verify this patch? |
snappy-m-o
commented
Jul 6, 2016
|
Can one of the admins verify this patch? |
snappy-m-o
commented
Jul 7, 2016
|
Can one of the admins verify this patch? |
snappy-m-o
commented
Jul 7, 2016
|
Can one of the admins verify this patch? |
tsimonq2
added some commits
Jul 7, 2016
snappy-m-o
commented
Jul 8, 2016
|
Can one of the admins verify this patch? |
tsimonq2
added some commits
Jul 8, 2016
snappy-m-o
commented
Jul 8, 2016
|
Can one of the admins verify this patch? |
tsimonq2
added some commits
Jul 8, 2016
|
I believe that all the intended testing and code is in place for this PR. Could this be evaluated please? |
tsimonq2
changed the title from
Add source-checksum option for tar and zip sources (bug 1585913)
to
Add source-checksum option
Jul 8, 2016
|
I also added sort of a specification to refer to in my initial comment. |
|
Bump |
sergiusens
reviewed
Jul 12, 2016
| + source_checksum, "checksum.tar") | ||
| + | ||
| + # From remote file | ||
| + source_checksum = 'http://tsimonq2.net/misc/snapcraft-checksum-tar' |
sergiusens
Jul 12, 2016
Collaborator
this should use a fakeserver, check snapcraft/tests/fake_servers.py
tsimonq2
Jul 15, 2016
Contributor
@sergiusens I'm a little confused as to the usage of this, where can I find an example of a test case that uses it?
sergiusens
reviewed
Jul 12, 2016
| + | ||
| +def check_checksum_determine_type_and_read_file(source_checksum, checkfile): | ||
| + if len(source_checksum) == 32: | ||
| + chksum = hashlib.md5() |
|
Hi, looks good One general comment is to use |
sergiusens
reviewed
Jul 12, 2016
| @@ -68,6 +71,89 @@ def test_pull_tarball_must_download_to_sourcedir(self, mock_prov): | ||
| with open(os.path.join(dest_dir, tar_file_name), 'r') as tar_file: | ||
| self.assertEqual('Test fake compressed file', tar_file.read()) | ||
| + def test_checksum(self): |
sergiusens
Jul 12, 2016
Collaborator
what are you testing here, or in other words, what are your assertions to know it all worked as expected?
sergiusens
Jul 12, 2016
Collaborator
maybe I am confused by check_checksum_determine_format and a better method name is needed here.
tsimonq2
Jul 15, 2016
•
Contributor
@sergiusens this function uses the various supported checksum formats and checks the checksum with them. This ensures that the checksum can be successfully checked with the raw checksums.
I know this works because if it doesn't, the built-in errors will catch it. That's why I'm not doing a try/fail here.
The only reason why I had to split it into separate functions was because the static tests were complaining about check_checksum being too complex. This is now corrected to be in one function.
sergiusens
reviewed
Jul 12, 2016
| @@ -114,6 +200,89 @@ def test_extract_and_keep_zipfile(self, mock_zip): | ||
| with open(zip_download, 'r') as zip_file: | ||
| self.assertEqual('Test fake compressed file', zip_file.read()) | ||
| + def test_checksum_of_zip(self): |
sergiusens
reviewed
Jul 12, 2016
| + check_checksum_determine_type_and_read_file(source_checksum, checkfile) | ||
| + | ||
| + | ||
| +def check_checksum_determine_type_and_read_file(source_checksum, checkfile): |
sergiusens
Jul 12, 2016
Collaborator
if this is only used by check_checksum_determine_format then prefix the method name with _
sergiusens
reviewed
Jul 12, 2016
| + elif len(source_checksum) == 128: | ||
| + chksum = hashlib.sha512() | ||
| + else: | ||
| + raise IncompatibleOptionsError("Invalid checksum format") |
sergiusens
Jul 12, 2016
•
Collaborator
This could be a dictionary instead
_HASH_FUNCTIONS = {
32: hashlib.md5,
40: hashlib.sha1,
...
...
}
try:
checksumer = _HASH_FUNCTIONS[len(source_checksum)]()
except KeyError:
raise IncompatibleOptionsError("Invalid checksum format")|
Another general comment, you should name the method the sources classes With that returned value, if you use the dict, just do the check there and finally check if they are a match or raise the exception. This IMHO would read much simpler. |
tsimonq2
added some commits
Jul 13, 2016
|
@sergiusens I made some changes that addresses your comments, let me know if you have more. |
sergiusens
reviewed
Jul 30, 2016
| + data = response.read() | ||
| + source_checksum = data.decode('utf-8') | ||
| + if (" " in source_checksum): | ||
| + source_checksum = source_checksum.split(" ", 1)[0] |
sergiusens
reviewed
Jul 30, 2016
| + if (" " in source_checksum): | ||
| + source_checksum = source_checksum.split(" ", 1)[0] | ||
| + else: | ||
| + print('No file name detected in the checksum file, perhaps an ' |
tsimonq2
Jul 31, 2016
Contributor
@sergiusens do you think it's always the case that the checksum file has a filename? If so, I'll correct it.
sergiusens
reviewed
Jul 30, 2016
| @@ -310,6 +346,10 @@ def __init__(self, source, source_dir, source_tag=None, | ||
| def provision(self, dst, clean_target=True, keep_zip=False): | ||
| zip = os.path.join(self.source_dir, os.path.basename(self.source)) | ||
| + if self.source_checksum: | ||
| + verify_checksum( | ||
| + self.source_checksum, zip) |
sergiusens
reviewed
Jul 30, 2016
| @@ -310,6 +346,10 @@ def __init__(self, source, source_dir, source_tag=None, | ||
| def provision(self, dst, clean_target=True, keep_zip=False): | ||
| zip = os.path.join(self.source_dir, os.path.basename(self.source)) |
sergiusens
Jul 30, 2016
Collaborator
please use a different name than zip, zip is a python keyword and it might get confusing.
tsimonq2
Jul 31, 2016
Contributor
@sergiusens This is applicable to the original source as well and should be dealt with in a separate PR, I'm just using what has already been given to me for variable names.
sergiusens
reviewed
Jul 30, 2016
| + filework = open(filename, 'r') | ||
| + source_checksum = filework.read() | ||
| + if (" " in source_checksum): | ||
| + source_checksum = source_checksum.split(" ", 1)[0] |
sergiusens
reviewed
Jul 30, 2016
| + if (" " in source_checksum): | ||
| + source_checksum = source_checksum.split(" ", 1)[0] | ||
| + else: | ||
| + print('No file name detected in the checksum file, perhaps an ' |
sergiusens
reviewed
Jul 30, 2016
| + | ||
| + if checksum != source_checksum: | ||
| + raise ChecksumDoesNotMatch( | ||
| + "the checksum ( "+source_checksum+" ) doesn't match the file" |
sergiusens
Aug 2, 2016
Collaborator
Should be something like
raise ChecksumDoesNotMatch(
'the checksum {!r} doesn't match the file'.format(source_checksum)
sergiusens
reviewed
Jul 30, 2016
| + try: | ||
| + checksum = _HASH_FUNCTIONS[len(source_checksum)] | ||
| + except KeyError: | ||
| + raise IncompatibleOptionsError("Invalid checksum format") |
sergiusens
reviewed
Jul 30, 2016
| + # md5 | ||
| + source_checksum = '1276481102f218c981e0324180bafd9f' | ||
| + sources.verify_checksum( | ||
| + source_checksum, "checksum.tar") |
tsimonq2
Jul 31, 2016
Contributor
Pushing a fix to a bunch of lines that can be fixed by this, thanks for pointing this out.
tsimonq2
added some commits
Jul 31, 2016
|
OK, one final checkup, in the bug sabdfl mentions we should support sha-3-384; how do we differentiate sha-2 and sha-3 with the autodetection? |
tsimonq2
added some commits
Aug 3, 2016
|
@tsimonq2 did you see @sergiusens's question? |
|
Closing due to inactivity |
tsimonq2 commentedJun 30, 2016
•
Edited 1 time
-
tsimonq2
Jul 5, 2016
This adds an optional
source-checksumtag to ensure download integrity by checking the checksum.Features
source-types:source-type: tarsource-type: zipmd5sha1sha224sha256sha384sha512source-checksum: HASH- raw hashsource-checksum: checksum.txt- local filesource-checksum: http(s)://example.com/checksum- remote URLFailsafes
It has the following failsafes to ensure the code always works as intended:
Testing coverage
I have the following testing in place:
snapcraft.yamlfiles forsimple-tarandsimple-zipDiscrepancies between this specification and the source
If you find any difference between the code in this PR and the specification above, please comment, as that wasn't intended.