go-tuf icon indicating copy to clipboard operation
go-tuf copied to clipboard

Tests fail for client while using repo created with python implementation

Open Aagat opened this issue 7 years ago • 5 comments

Result of go test -v

go-tuf/client [master●] » go test -v
=== RUN   Test

----------------------------------------------------------------------
FAIL: <autogenerated>:1: InteropSuite.TestGoClientPythonGenerated

interop_test.go:54:
    c.Assert(client.Init([]*data.Key{key}, 1), IsNil)
... value client.ErrDecodeFailed = client.ErrDecodeFailed{File:"root.json", Err:(*errors.errorString)(0xc4200964d0)} ("tuf: failed to decode root.json: tuf: valid signatures did not meet threshold")


OOPS: 31 passed, 1 FAILED
--- FAIL: Test (6.58s)
FAIL
exit status 1
FAIL	github.com/flynn/go-tuf/client	6.589s

Environment

» go version
go version go1.10 linux/amd64
» uname -a
Linux primary.aagat.com 4.15.3-2-ARCH #1 SMP PREEMPT Thu Feb 15 00:13:49 UTC 2018 x86_64 GNU/Linux

I had to make a few changes in order to generate repo (breaking changes upstream?).

Modified files:

client/testdata/generate/Dockerfile

FROM ubuntu:trusty

RUN apt-get update
RUN apt-get install -y python python-dev python-pip libffi-dev tree libssl-dev

# Use the develop branch of tuf for the following fix:
# https://github.com/theupdateframework/tuf/commit/38005fe
RUN apt-get install -y git
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install --no-use-wheel git+https://github.com/theupdateframework/tuf.git@develop && pip install tuf[tools]

ADD generate.py generate.sh /
CMD /generate.sh

Modified file: client/testdata/generate/generate.py

#
# A script to generate TUF repository files.
#
# A modification of generate.py from the Python implementation:
# https://github.com/theupdateframework/tuf/blob/v0.9.9/tests/repository_data/generate.py

import shutil
import datetime
import optparse
import stat

from tuf.repository_tool import *
import os

parser = optparse.OptionParser()
parser.add_option("-c","--consistent-snapshot", action='store_true',  dest="consistent_snapshot",
    help="Generate consistent snapshot", default=False)
(options, args) = parser.parse_args()

repository = create_new_repository('repository')

root_key_file = 'keystore/root_key'
targets_key_file = 'keystore/targets_key'
snapshot_key_file = 'keystore/snapshot_key'
timestamp_key_file = 'keystore/timestamp_key'

generate_and_write_ed25519_keypair(root_key_file, password='password')
generate_and_write_ed25519_keypair(targets_key_file, password='password')
generate_and_write_ed25519_keypair(snapshot_key_file, password='password')
generate_and_write_ed25519_keypair(timestamp_key_file, password='password')

root_public = import_ed25519_publickey_from_file(root_key_file+'.pub')
targets_public = import_ed25519_publickey_from_file(targets_key_file+'.pub')
snapshot_public = import_ed25519_publickey_from_file(snapshot_key_file+'.pub')
timestamp_public = import_ed25519_publickey_from_file(timestamp_key_file+'.pub')

root_private = import_ed25519_privatekey_from_file(root_key_file, 'password')
targets_private = import_ed25519_privatekey_from_file(targets_key_file, 'password')
snapshot_private = import_ed25519_privatekey_from_file(snapshot_key_file, 'password')
timestamp_private = import_ed25519_privatekey_from_file(timestamp_key_file, 'password')

repository.root.add_verification_key(root_public)
repository.targets.add_verification_key(targets_public)
repository.snapshot.add_verification_key(snapshot_public)
repository.timestamp.add_verification_key(timestamp_public)

repository.root.load_signing_key(root_private)
repository.targets.load_signing_key(targets_private)
repository.snapshot.load_signing_key(snapshot_private)
repository.timestamp.load_signing_key(timestamp_private)

target1_filepath = 'repository/targets/file1.txt'
if not os.path.exists('repository/targets/'):
    os.makedirs('repository/targets/')
target2_filepath = 'repository/targets/dir/file2.txt'
if not os.path.exists('repository/targets/dir/'):
    os.makedirs('repository/targets/dir/')

with open(target1_filepath, 'wt') as file_object:
  file_object.write('file1.txt')

with open(target2_filepath, 'wt') as file_object:
  file_object.write('file2.txt')

octal_file_permissions = oct(os.stat(target1_filepath).st_mode)[4:]
file_permissions = {'file_permissions': octal_file_permissions}
repository.targets.add_target(target1_filepath, file_permissions)
repository.targets.add_target(target2_filepath)

repository.root.expiration = datetime.datetime(2030, 1, 1, 0, 0)
repository.targets.expiration = datetime.datetime(2030, 1, 1, 0, 0)
repository.snapshot.expiration = datetime.datetime(2030, 1, 1, 0, 0)
repository.timestamp.expiration = datetime.datetime(2030, 1, 1, 0, 0)

repository.targets.compressions = ['gz']


if options.consistent_snapshot:
  repository.writeall(consistent_snapshot=True)

else:
  repository.writeall()

shutil.move('repository/metadata.staged', 'repository/metadata')

#!/usr/bin/env python
#
# A script to generate TUF repository files.
#
# A modification of generate.py from the Python implementation:
# https://github.com/theupdateframework/tuf/blob/v0.9.9/tests/repository_data/generate.py

import shutil
import datetime
import optparse
import stat

from tuf.repository_tool import *
import os

parser = optparse.OptionParser()
parser.add_option("-c","--consistent-snapshot", action='store_true',  dest="consistent_snapshot",
    help="Generate consistent snapshot", default=False)
(options, args) = parser.parse_args()

repository = create_new_repository('repository')

root_key_file = 'keystore/root_key'
targets_key_file = 'keystore/targets_key'
snapshot_key_file = 'keystore/snapshot_key'
timestamp_key_file = 'keystore/timestamp_key'

generate_and_write_ed25519_keypair(root_key_file, password='password')
generate_and_write_ed25519_keypair(targets_key_file, password='password')
generate_and_write_ed25519_keypair(snapshot_key_file, password='password')
generate_and_write_ed25519_keypair(timestamp_key_file, password='password')

root_public = import_ed25519_publickey_from_file(root_key_file+'.pub')
targets_public = import_ed25519_publickey_from_file(targets_key_file+'.pub')
snapshot_public = import_ed25519_publickey_from_file(snapshot_key_file+'.pub')
timestamp_public = import_ed25519_publickey_from_file(timestamp_key_file+'.pub')

root_private = import_ed25519_privatekey_from_file(root_key_file, 'password')
targets_private = import_ed25519_privatekey_from_file(targets_key_file, 'password')
snapshot_private = import_ed25519_privatekey_from_file(snapshot_key_file, 'password')
timestamp_private = import_ed25519_privatekey_from_file(timestamp_key_file, 'password')

repository.root.add_verification_key(root_public)
repository.targets.add_verification_key(targets_public)
repository.snapshot.add_verification_key(snapshot_public)
repository.timestamp.add_verification_key(timestamp_public)

repository.root.load_signing_key(root_private)
repository.targets.load_signing_key(targets_private)
repository.snapshot.load_signing_key(snapshot_private)
repository.timestamp.load_signing_key(timestamp_private)

target1_filepath = 'repository/targets/file1.txt'
if not os.path.exists('repository/targets/'):
    os.makedirs('repository/targets/')
target2_filepath = 'repository/targets/dir/file2.txt'
if not os.path.exists('repository/targets/dir/'):
    os.makedirs('repository/targets/dir/')

with open(target1_filepath, 'wt') as file_object:
  file_object.write('file1.txt')

with open(target2_filepath, 'wt') as file_object:
  file_object.write('file2.txt')

octal_file_permissions = oct(os.stat(target1_filepath).st_mode)[4:]
file_permissions = {'file_permissions': octal_file_permissions}
repository.targets.add_target(target1_filepath, file_permissions)
repository.targets.add_target(target2_filepath)

repository.root.expiration = datetime.datetime(2030, 1, 1, 0, 0)
repository.targets.expiration = datetime.datetime(2030, 1, 1, 0, 0)
repository.snapshot.expiration = datetime.datetime(2030, 1, 1, 0, 0)
repository.timestamp.expiration = datetime.datetime(2030, 1, 1, 0, 0)

repository.targets.compressions = ['gz']


if options.consistent_snapshot:
  repository.writeall(consistent_snapshot=True)

else:
  repository.writeall()

shutil.move('repository/metadata.staged', 'repository/metadata')

Result of make to generate repo.

client/testdata [master●] » make
docker build -t tuf-gen ./generate
Sending build context to Docker daemon   7.68kB
Step 1/9 : FROM ubuntu:trusty
 ---> dc4491992653
Step 2/9 : RUN apt-get update
 ---> Using cache
 ---> 4448229afdc9
Step 3/9 : RUN apt-get install -y python python-dev python-pip libffi-dev tree libssl-dev
 ---> Using cache
 ---> e76d647ae1d1
Step 4/9 : RUN apt-get install -y git
 ---> Using cache
 ---> 388e3c4d12f6
Step 5/9 : RUN pip install --upgrade pip
 ---> Using cache
 ---> bbc9ef4a7f4e
Step 6/9 : RUN pip install --upgrade setuptools
 ---> Using cache
 ---> 9b60f68e0734
Step 7/9 : RUN pip install --no-use-wheel git+https://github.com/theupdateframework/tuf.git@develop && pip install tuf[tools]
 ---> Using cache
 ---> 9ab38c82fee8
Step 8/9 : ADD generate.py generate.sh /
 ---> Using cache
 ---> 037b9501c3fd
Step 9/9 : CMD /generate.sh
 ---> Using cache
 ---> 0341e646ab74
Successfully built 0341e646ab74
Successfully tagged tuf-gen:latest
docker run tuf-gen | tar x
Creating '/tmp/tmp.CmokAtVEyB/with-consistent-snapshot/repository'
Creating u'/tmp/tmp.CmokAtVEyB/with-consistent-snapshot/repository/metadata.staged'
Creating u'/tmp/tmp.CmokAtVEyB/with-consistent-snapshot/repository/targets'
Creating '/tmp/tmp.CmokAtVEyB/without-consistent-snapshot/repository'
Creating u'/tmp/tmp.CmokAtVEyB/without-consistent-snapshot/repository/metadata.staged'
Creating u'/tmp/tmp.CmokAtVEyB/without-consistent-snapshot/repository/targets'
Files generated:
.
|-- with-consistent-snapshot
|   |-- keystore
|   |   |-- root_key
|   |   |-- root_key.pub
|   |   |-- snapshot_key
|   |   |-- snapshot_key.pub
|   |   |-- targets_key
|   |   |-- targets_key.pub
|   |   |-- timestamp_key
|   |   `-- timestamp_key.pub
|   |-- repository
|   |   |-- metadata
|   |   |   |-- 1.root.json
|   |   |   |-- 1.snapshot.json
|   |   |   |-- 1.targets.json
|   |   |   |-- 1.timestamp.json
|   |   |   |-- root.json
|   |   |   |-- snapshot.json
|   |   |   |-- targets.json
|   |   |   `-- timestamp.json
|   |   `-- targets
|   |       |-- 055dc805570eecebad4270774054ee4375ef9a7248d981cfa8155dc884817df31e8497684dd26addd018a30565c3ccf87eeb70445f2e76587af84ed6ce1e0302.file1.txt
|   |       |-- 55ae75d991c770d8f3ef07cbfde124ffce9c420da5db6203afab700b27e10cf9.file1.txt
|   |       |-- dir
|   |       |   |-- 04e2f59431a9d219321baf7d21b8cc797d7615dc3e9515c782c49d2075658701.file2.txt
|   |       |   |-- 2b85daf030ebc94d302822da4fd50216dc56f90c9bb60a95b272aa5b11fe81cd9b192b1a860896d6a8241d1a42cc97b6015d42100c9b46432a32db4b13a11c58.file2.txt
|   |       |   `-- file2.txt
|   |       `-- file1.txt
|   `-- tuf.log
`-- without-consistent-snapshot
    |-- keystore
    |   |-- root_key
    |   |-- root_key.pub
    |   |-- snapshot_key
    |   |-- snapshot_key.pub
    |   |-- targets_key
    |   |-- targets_key.pub
    |   |-- timestamp_key
    |   `-- timestamp_key.pub
    |-- repository
    |   |-- metadata
    |   |   |-- 1.root.json
    |   |   |-- root.json
    |   |   |-- snapshot.json
    |   |   |-- targets.json
    |   |   `-- timestamp.json
    |   `-- targets
    |       |-- dir
    |       |   `-- file2.txt
    |       `-- file1.txt
    `-- tuf.log

12 directories, 39 files

Aagat avatar Feb 22 '18 17:02 Aagat

@Aagat I'm not sure what the issue is here, the tests seem to pass just fine for me:

$ git rev-parse HEAD
a98aea1463c972506e302344ebbfa30f85b74f2f

$ go test ./...
ok      github.com/flynn/go-tuf 1.247s
ok      github.com/flynn/go-tuf/client  6.834s
?       github.com/flynn/go-tuf/cmd/tuf [no test files]
?       github.com/flynn/go-tuf/cmd/tuf-client  [no test files]
ok      github.com/flynn/go-tuf/data    0.012s
ok      github.com/flynn/go-tuf/encrypted       1.024s
?       github.com/flynn/go-tuf/sign    [no test files]
ok      github.com/flynn/go-tuf/util    0.011s
ok      github.com/flynn/go-tuf/verify  0.051s

lmars avatar Feb 23 '18 00:02 lmars

@lmars That'd odd. I can't even generate required testdata with current HEAD.

» git rev-parse HEAD
a98aea1463c972506e302344ebbfa30f85b74f2

» make clean
rm -rf with{,out}-consistent-snapshot

» make
docker build -t tuf-gen ./generate
Sending build context to Docker daemon   7.68kB
Step 1/7 : FROM ubuntu:trusty
 ---> dc4491992653
Step 2/7 : RUN apt-get update
 ---> Using cache
 ---> 4448229afdc9
Step 3/7 : RUN apt-get install -y python python-dev python-pip libffi-dev tree
 ---> Using cache
 ---> 8c8fa8f6160a
Step 4/7 : RUN apt-get install -y git
 ---> Using cache
 ---> 2a7b539941c6
Step 5/7 : RUN pip install --no-use-wheel git+https://github.com/theupdateframework/tuf.git@develop && pip install tuf[tools]
 ---> Running in b110d38070a2
Downloading/unpacking git+https://github.com/theupdateframework/tuf.git@develop
  Cloning https://github.com/theupdateframework/tuf.git (to develop) to /tmp/pip-CCCf76-build
  Running setup.py (path:/tmp/pip-CCCf76-build/setup.py) egg_info for package from git+https://github.com/theupdateframework/tuf.git@develop
    
    warning: no files found matching '*' under directory 'examples'
    warning: no files found matching '*.pem' under directory 'tests'
    warning: no files found matching '*.gz' under directory 'tests'
    warning: no files found matching '*.gitignore' under directory 'tuf'
    warning: no files found matching '*.rst' under directory 'tuf'
    warning: no files found matching '*.yml' under directory 'tuf'
Downloading/unpacking iso8601>=0.1.12 (from tuf==0.10.2)
  Downloading iso8601-0.1.12.tar.gz
  Running setup.py (path:/tmp/pip_build_root/iso8601/setup.py) egg_info for package iso8601
    
Downloading/unpacking six>=1.11.0 (from tuf==0.10.2)
  Downloading six-1.11.0.tar.gz
  Running setup.py (path:/tmp/pip_build_root/six/setup.py) egg_info for package six
    
    no previously-included directories found matching 'documentation/_build'
Downloading/unpacking securesystemslib>=0.10.10 (from tuf==0.10.2)
  Running setup.py (path:/tmp/pip_build_root/securesystemslib/setup.py) egg_info for package securesystemslib
    
Downloading/unpacking cryptography>=2.1.3 (from securesystemslib>=0.10.10->tuf==0.10.2)
  Running setup.py (path:/tmp/pip_build_root/cryptography/setup.py) egg_info for package cryptography
    error in cryptography setup command: Invalid environment marker: python_version < '3'
    Complete output from command python setup.py egg_info:
    error in cryptography setup command: Invalid environment marker: python_version < '3'

----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in /tmp/pip_build_root/cryptography
Storing debug log for failure in /root/.pip/pip.log
The command '/bin/sh -c pip install --no-use-wheel git+https://github.com/theupdateframework/tuf.git@develop && pip install tuf[tools]' returned a non-zero code: 1
make: *** [Makefile:2: all] Error 1

Tests then fails as expected because no test repo was generated.

» go test ./...
ok  	github.com/flynn/go-tuf	(cached)

----------------------------------------------------------------------
FAIL: <autogenerated>:1: InteropSuite.TestGoClientPythonGenerated

interop_test.go:48:
    c.Assert(err, IsNil)
... value *os.PathError = &os.PathError{Op:"open", Path:"testdata/with-consistent-snapshot/keystore/root_key.pub", Err:0x2} ("open testdata/with-consistent-snapshot/keystore/root_key.pub: no such file or directory")

OOPS: 31 passed, 1 FAILED
--- FAIL: Test (6.62s)
FAIL
FAIL	github.com/flynn/go-tuf/client	6.629s
?   	github.com/flynn/go-tuf/cmd/tuf	[no test files]
?   	github.com/flynn/go-tuf/cmd/tuf-client	[no test files]
ok  	github.com/flynn/go-tuf/data	(cached)
ok  	github.com/flynn/go-tuf/encrypted	(cached)
?   	github.com/flynn/go-tuf/sign	[no test files]
ok  	github.com/flynn/go-tuf/util	(cached)
ok  	github.com/flynn/go-tuf/verify	(cached)

I'm not sure if I am doing something horribly wrong or you have running it against previously generated tuf repo. Can you confirm if test data generator Docker image is working for you.

Aagat avatar Feb 23 '18 11:02 Aagat

@Aagat I was running them against the committed files yes. I tried the latest Python release and there are a few changes which the Go implementation is not compatible with (for example prefixing a version rather than hash to metadata files in a consistent snapshot).

I've pushed a branch python-compatibility with my fixes so far: https://github.com/flynn/go-tuf/compare/python-compatibility

The InteropSuite.TestGoClientPythonGenerated test is still failing, feel free to try and fix the incompatibilities.

lmars avatar Mar 06 '18 12:03 lmars

@lmars Thank you for taking time to look into the issue deeper. I will try to a look at these in coming week. For the moment I worked around the issue by using keys generated by go-tuf for testing but I think python interop is very important.

Aagat avatar Mar 06 '18 15:03 Aagat

cc @hosseinsia

mnm678 avatar Sep 10 '21 13:09 mnm678

Closing since the code base changed, but it's also not relevant anymore. The new code base is compliant against the python-tuf implementation.

Thanks for raising this! 👍

rdimitrov avatar Jan 31 '24 21:01 rdimitrov