From ce67fe4f40f0e890489d055e73ad6032cbd5107a Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Wed, 15 Jun 2022 22:53:19 +0530 Subject: [PATCH 01/40] Made the sample test repository Removed the folders "metadata.staged" and "metadata" and added all the metadata inside the "1.0.0" and "2.0.0" Signed-off-by: Abhisman Sarkar --- .../repository/{metadata.staged => 1.0.0}/1.root.json | 0 .../repository/{metadata.staged => 1.0.0}/role1.json | 0 .../repository/{metadata => 1.0.0}/role2.json | 0 .../repository/{metadata.staged => 1.0.0}/root.json | 0 .../repository/{metadata.staged => 1.0.0}/snapshot.json | 0 .../repository/{metadata.staged => 1.0.0}/targets.json | 0 .../repository/{metadata.staged => 1.0.0}/timestamp.json | 0 .../repository/{metadata => 2.0.0}/1.root.json | 0 .../repository/{metadata => 2.0.0}/role1.json | 0 .../repository/{metadata.staged => 2.0.0}/role2.json | 6 +----- .../repository/{metadata => 2.0.0}/root.json | 0 .../repository/{metadata => 2.0.0}/snapshot.json | 0 .../repository/{metadata => 2.0.0}/targets.json | 0 .../repository/{metadata => 2.0.0}/timestamp.json | 0 14 files changed, 1 insertion(+), 5 deletions(-) rename tests/repository_data/repository/{metadata.staged => 1.0.0}/1.root.json (100%) rename tests/repository_data/repository/{metadata.staged => 1.0.0}/role1.json (100%) rename tests/repository_data/repository/{metadata => 1.0.0}/role2.json (100%) rename tests/repository_data/repository/{metadata.staged => 1.0.0}/root.json (100%) rename tests/repository_data/repository/{metadata.staged => 1.0.0}/snapshot.json (100%) rename tests/repository_data/repository/{metadata.staged => 1.0.0}/targets.json (100%) rename tests/repository_data/repository/{metadata.staged => 1.0.0}/timestamp.json (100%) rename tests/repository_data/repository/{metadata => 2.0.0}/1.root.json (100%) rename tests/repository_data/repository/{metadata => 2.0.0}/role1.json (100%) rename tests/repository_data/repository/{metadata.staged => 2.0.0}/role2.json (55%) rename tests/repository_data/repository/{metadata => 2.0.0}/root.json (100%) rename tests/repository_data/repository/{metadata => 2.0.0}/snapshot.json (100%) rename tests/repository_data/repository/{metadata => 2.0.0}/targets.json (100%) rename tests/repository_data/repository/{metadata => 2.0.0}/timestamp.json (100%) diff --git a/tests/repository_data/repository/metadata.staged/1.root.json b/tests/repository_data/repository/1.0.0/1.root.json similarity index 100% rename from tests/repository_data/repository/metadata.staged/1.root.json rename to tests/repository_data/repository/1.0.0/1.root.json diff --git a/tests/repository_data/repository/metadata.staged/role1.json b/tests/repository_data/repository/1.0.0/role1.json similarity index 100% rename from tests/repository_data/repository/metadata.staged/role1.json rename to tests/repository_data/repository/1.0.0/role1.json diff --git a/tests/repository_data/repository/metadata/role2.json b/tests/repository_data/repository/1.0.0/role2.json similarity index 100% rename from tests/repository_data/repository/metadata/role2.json rename to tests/repository_data/repository/1.0.0/role2.json diff --git a/tests/repository_data/repository/metadata.staged/root.json b/tests/repository_data/repository/1.0.0/root.json similarity index 100% rename from tests/repository_data/repository/metadata.staged/root.json rename to tests/repository_data/repository/1.0.0/root.json diff --git a/tests/repository_data/repository/metadata.staged/snapshot.json b/tests/repository_data/repository/1.0.0/snapshot.json similarity index 100% rename from tests/repository_data/repository/metadata.staged/snapshot.json rename to tests/repository_data/repository/1.0.0/snapshot.json diff --git a/tests/repository_data/repository/metadata.staged/targets.json b/tests/repository_data/repository/1.0.0/targets.json similarity index 100% rename from tests/repository_data/repository/metadata.staged/targets.json rename to tests/repository_data/repository/1.0.0/targets.json diff --git a/tests/repository_data/repository/metadata.staged/timestamp.json b/tests/repository_data/repository/1.0.0/timestamp.json similarity index 100% rename from tests/repository_data/repository/metadata.staged/timestamp.json rename to tests/repository_data/repository/1.0.0/timestamp.json diff --git a/tests/repository_data/repository/metadata/1.root.json b/tests/repository_data/repository/2.0.0/1.root.json similarity index 100% rename from tests/repository_data/repository/metadata/1.root.json rename to tests/repository_data/repository/2.0.0/1.root.json diff --git a/tests/repository_data/repository/metadata/role1.json b/tests/repository_data/repository/2.0.0/role1.json similarity index 100% rename from tests/repository_data/repository/metadata/role1.json rename to tests/repository_data/repository/2.0.0/role1.json diff --git a/tests/repository_data/repository/metadata.staged/role2.json b/tests/repository_data/repository/2.0.0/role2.json similarity index 55% rename from tests/repository_data/repository/metadata.staged/role2.json rename to tests/repository_data/repository/2.0.0/role2.json index 93f378a758..9c49e16570 100644 --- a/tests/repository_data/repository/metadata.staged/role2.json +++ b/tests/repository_data/repository/2.0.0/role2.json @@ -2,15 +2,11 @@ "signatures": [ { "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "6c32f8cc2c642803a7b3b022ede0cf727e82964c1aa934571ef366bd5050ed02cfe3fdfe5477c08d0cbcc2dd17bb786d37ab1ce2b27e01ad79faf087594e0300" + "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" } ], "signed": { "_type": "targets", - "delegations": { - "keys": {}, - "roles": [] - }, "expires": "2030-01-01T00:00:00Z", "spec_version": "1.0.0", "targets": {}, diff --git a/tests/repository_data/repository/metadata/root.json b/tests/repository_data/repository/2.0.0/root.json similarity index 100% rename from tests/repository_data/repository/metadata/root.json rename to tests/repository_data/repository/2.0.0/root.json diff --git a/tests/repository_data/repository/metadata/snapshot.json b/tests/repository_data/repository/2.0.0/snapshot.json similarity index 100% rename from tests/repository_data/repository/metadata/snapshot.json rename to tests/repository_data/repository/2.0.0/snapshot.json diff --git a/tests/repository_data/repository/metadata/targets.json b/tests/repository_data/repository/2.0.0/targets.json similarity index 100% rename from tests/repository_data/repository/metadata/targets.json rename to tests/repository_data/repository/2.0.0/targets.json diff --git a/tests/repository_data/repository/metadata/timestamp.json b/tests/repository_data/repository/2.0.0/timestamp.json similarity index 100% rename from tests/repository_data/repository/metadata/timestamp.json rename to tests/repository_data/repository/2.0.0/timestamp.json From c8c3bb5bd73e82988bc17b2c30a7e6170eb7b85a Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Thu, 16 Jun 2022 00:20:32 +0530 Subject: [PATCH 02/40] Updated spec versions inside 2.0.0 Updated the spec version inside the metadata files inside the "2.0.0" folder Signed-off-by: Abhisman Sarkar --- tests/repository_data/repository/1.0.0/role1.json | 2 +- tests/repository_data/repository/1.0.0/role2.json | 2 +- tests/repository_data/repository/2.0.0/1.root.json | 2 +- tests/repository_data/repository/2.0.0/role1.json | 2 +- tests/repository_data/repository/2.0.0/root.json | 2 +- tests/repository_data/repository/2.0.0/snapshot.json | 2 +- tests/repository_data/repository/2.0.0/targets.json | 2 +- tests/repository_data/repository/2.0.0/timestamp.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/repository_data/repository/1.0.0/role1.json b/tests/repository_data/repository/1.0.0/role1.json index 0ac4687e77..66ec049d73 100644 --- a/tests/repository_data/repository/1.0.0/role1.json +++ b/tests/repository_data/repository/1.0.0/role1.json @@ -34,7 +34,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", + "spec_version": "2.0.0", "targets": { "file3.txt": { "hashes": { diff --git a/tests/repository_data/repository/1.0.0/role2.json b/tests/repository_data/repository/1.0.0/role2.json index 9c49e16570..252f2aa88d 100644 --- a/tests/repository_data/repository/1.0.0/role2.json +++ b/tests/repository_data/repository/1.0.0/role2.json @@ -8,7 +8,7 @@ "signed": { "_type": "targets", "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", + "spec_version": "2.0.0", "targets": {}, "version": 1 } diff --git a/tests/repository_data/repository/2.0.0/1.root.json b/tests/repository_data/repository/2.0.0/1.root.json index 214d8db01b..25595b3f38 100644 --- a/tests/repository_data/repository/2.0.0/1.root.json +++ b/tests/repository_data/repository/2.0.0/1.root.json @@ -81,7 +81,7 @@ "threshold": 1 } }, - "spec_version": "1.0.0", + "spec_version": "2.0.0", "version": 1 } } \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/role1.json b/tests/repository_data/repository/2.0.0/role1.json index 0ac4687e77..66ec049d73 100644 --- a/tests/repository_data/repository/2.0.0/role1.json +++ b/tests/repository_data/repository/2.0.0/role1.json @@ -34,7 +34,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", + "spec_version": "2.0.0", "targets": { "file3.txt": { "hashes": { diff --git a/tests/repository_data/repository/2.0.0/root.json b/tests/repository_data/repository/2.0.0/root.json index 214d8db01b..25595b3f38 100644 --- a/tests/repository_data/repository/2.0.0/root.json +++ b/tests/repository_data/repository/2.0.0/root.json @@ -81,7 +81,7 @@ "threshold": 1 } }, - "spec_version": "1.0.0", + "spec_version": "2.0.0", "version": 1 } } \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/snapshot.json b/tests/repository_data/repository/2.0.0/snapshot.json index 7c8c091a2e..51aa78a5a6 100644 --- a/tests/repository_data/repository/2.0.0/snapshot.json +++ b/tests/repository_data/repository/2.0.0/snapshot.json @@ -19,7 +19,7 @@ "version": 1 } }, - "spec_version": "1.0.0", + "spec_version": "2.0.0", "version": 1 } } \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/targets.json b/tests/repository_data/repository/2.0.0/targets.json index 8e21c269b4..9517c048d0 100644 --- a/tests/repository_data/repository/2.0.0/targets.json +++ b/tests/repository_data/repository/2.0.0/targets.json @@ -36,7 +36,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", + "spec_version": "2.0.0", "targets": { "file1.txt": { "custom": { diff --git a/tests/repository_data/repository/2.0.0/timestamp.json b/tests/repository_data/repository/2.0.0/timestamp.json index 9a0daf078b..9d38e7c7ed 100644 --- a/tests/repository_data/repository/2.0.0/timestamp.json +++ b/tests/repository_data/repository/2.0.0/timestamp.json @@ -17,7 +17,7 @@ "version": 1 } }, - "spec_version": "1.0.0", + "spec_version": "2.0.0", "version": 1 } } \ No newline at end of file From 2d830a09b73ecf10fecfc0a0367398b6d1db84c1 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Fri, 17 Jun 2022 17:19:56 +0530 Subject: [PATCH 03/40] Updated the directory structure Added the all the metadata files alongside the "1.0.0", "2.0.0" and "targets" folders Signed-off-by: Abhisman Sarkar --- tests/repository_data/repository/1.root.json | 87 +++++++++++++++++++ tests/repository_data/repository/role1.json | 49 +++++++++++ tests/repository_data/repository/role2.json | 15 ++++ tests/repository_data/repository/root.json | 87 +++++++++++++++++++ .../repository_data/repository/snapshot.json | 25 ++++++ tests/repository_data/repository/targets.json | 61 +++++++++++++ .../repository_data/repository/timestamp.json | 23 +++++ 7 files changed, 347 insertions(+) create mode 100644 tests/repository_data/repository/1.root.json create mode 100644 tests/repository_data/repository/role1.json create mode 100644 tests/repository_data/repository/role2.json create mode 100644 tests/repository_data/repository/root.json create mode 100644 tests/repository_data/repository/snapshot.json create mode 100644 tests/repository_data/repository/targets.json create mode 100644 tests/repository_data/repository/timestamp.json diff --git a/tests/repository_data/repository/1.root.json b/tests/repository_data/repository/1.root.json new file mode 100644 index 0000000000..214d8db01b --- /dev/null +++ b/tests/repository_data/repository/1.root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/role1.json b/tests/repository_data/repository/role1.json new file mode 100644 index 0000000000..66ec049d73 --- /dev/null +++ b/tests/repository_data/repository/role1.json @@ -0,0 +1,49 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role2", + "paths": [], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": { + "file3.txt": { + "hashes": { + "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", + "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" + }, + "length": 28 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/role2.json b/tests/repository_data/repository/role2.json new file mode 100644 index 0000000000..252f2aa88d --- /dev/null +++ b/tests/repository_data/repository/role2.json @@ -0,0 +1,15 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" + } + ], + "signed": { + "_type": "targets", + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/root.json b/tests/repository_data/repository/root.json new file mode 100644 index 0000000000..214d8db01b --- /dev/null +++ b/tests/repository_data/repository/root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/snapshot.json b/tests/repository_data/repository/snapshot.json new file mode 100644 index 0000000000..7c8c091a2e --- /dev/null +++ b/tests/repository_data/repository/snapshot.json @@ -0,0 +1,25 @@ +{ + "signatures": [ + { + "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", + "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "role1.json": { + "version": 1 + }, + "role2.json": { + "version": 1 + }, + "targets.json": { + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/targets.json b/tests/repository_data/repository/targets.json new file mode 100644 index 0000000000..8e21c269b4 --- /dev/null +++ b/tests/repository_data/repository/targets.json @@ -0,0 +1,61 @@ +{ + "signatures": [ + { + "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", + "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role1", + "paths": [ + "file3.txt" + ], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": { + "file1.txt": { + "custom": { + "file_permissions": "0644" + }, + "hashes": { + "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", + "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" + }, + "length": 31 + }, + "file2.txt": { + "hashes": { + "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", + "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" + }, + "length": 39 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/timestamp.json b/tests/repository_data/repository/timestamp.json new file mode 100644 index 0000000000..9a0daf078b --- /dev/null +++ b/tests/repository_data/repository/timestamp.json @@ -0,0 +1,23 @@ +{ + "signatures": [ + { + "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", + "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" + }, + "length": 515, + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file From 1c507c325f094a0d943654f67cdc779ab0076e05 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Thu, 23 Jun 2022 20:21:36 +0530 Subject: [PATCH 04/40] Reverted to 6e20c31 Reverted the directory structure to keep all metadata inside "metadata.staged" and "metadata" folders Signed-off-by: Abhisman Sarkar --- .../repository/1.0.0/role2.json | 15 ---- .../repository/2.0.0/1.root.json | 87 ------------------- .../repository/2.0.0/role1.json | 49 ----------- .../repository/2.0.0/root.json | 87 ------------------- .../repository/2.0.0/snapshot.json | 25 ------ .../repository/2.0.0/targets.json | 61 ------------- .../repository/2.0.0/timestamp.json | 23 ----- .../{1.0.0 => metadata.staged}/1.root.json | 0 .../{1.0.0 => metadata.staged}/role1.json | 2 +- .../repository/metadata.staged/role2.json | 19 ++++ .../{1.0.0 => metadata.staged}/root.json | 0 .../{1.0.0 => metadata.staged}/snapshot.json | 0 .../{1.0.0 => metadata.staged}/targets.json | 0 .../{1.0.0 => metadata.staged}/timestamp.json | 0 .../repository/{ => metadata}/1.root.json | 0 .../repository/{ => metadata}/role1.json | 2 +- .../repository/{2.0.0 => metadata}/role2.json | 0 .../repository/{ => metadata}/root.json | 0 .../repository/{ => metadata}/snapshot.json | 0 .../repository/{ => metadata}/targets.json | 0 .../repository/{ => metadata}/timestamp.json | 0 tests/repository_data/repository/role2.json | 15 ---- 22 files changed, 21 insertions(+), 364 deletions(-) delete mode 100644 tests/repository_data/repository/1.0.0/role2.json delete mode 100644 tests/repository_data/repository/2.0.0/1.root.json delete mode 100644 tests/repository_data/repository/2.0.0/role1.json delete mode 100644 tests/repository_data/repository/2.0.0/root.json delete mode 100644 tests/repository_data/repository/2.0.0/snapshot.json delete mode 100644 tests/repository_data/repository/2.0.0/targets.json delete mode 100644 tests/repository_data/repository/2.0.0/timestamp.json rename tests/repository_data/repository/{1.0.0 => metadata.staged}/1.root.json (100%) rename tests/repository_data/repository/{1.0.0 => metadata.staged}/role1.json (97%) create mode 100644 tests/repository_data/repository/metadata.staged/role2.json rename tests/repository_data/repository/{1.0.0 => metadata.staged}/root.json (100%) rename tests/repository_data/repository/{1.0.0 => metadata.staged}/snapshot.json (100%) rename tests/repository_data/repository/{1.0.0 => metadata.staged}/targets.json (100%) rename tests/repository_data/repository/{1.0.0 => metadata.staged}/timestamp.json (100%) rename tests/repository_data/repository/{ => metadata}/1.root.json (100%) rename tests/repository_data/repository/{ => metadata}/role1.json (97%) rename tests/repository_data/repository/{2.0.0 => metadata}/role2.json (100%) rename tests/repository_data/repository/{ => metadata}/root.json (100%) rename tests/repository_data/repository/{ => metadata}/snapshot.json (100%) rename tests/repository_data/repository/{ => metadata}/targets.json (100%) rename tests/repository_data/repository/{ => metadata}/timestamp.json (100%) delete mode 100644 tests/repository_data/repository/role2.json diff --git a/tests/repository_data/repository/1.0.0/role2.json b/tests/repository_data/repository/1.0.0/role2.json deleted file mode 100644 index 252f2aa88d..0000000000 --- a/tests/repository_data/repository/1.0.0/role2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" - } - ], - "signed": { - "_type": "targets", - "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", - "targets": {}, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/1.root.json b/tests/repository_data/repository/2.0.0/1.root.json deleted file mode 100644 index 25595b3f38..0000000000 --- a/tests/repository_data/repository/2.0.0/1.root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/role1.json b/tests/repository_data/repository/2.0.0/role1.json deleted file mode 100644 index 66ec049d73..0000000000 --- a/tests/repository_data/repository/2.0.0/role1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role2", - "paths": [], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", - "targets": { - "file3.txt": { - "hashes": { - "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", - "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" - }, - "length": 28 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/root.json b/tests/repository_data/repository/2.0.0/root.json deleted file mode 100644 index 25595b3f38..0000000000 --- a/tests/repository_data/repository/2.0.0/root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/snapshot.json b/tests/repository_data/repository/2.0.0/snapshot.json deleted file mode 100644 index 51aa78a5a6..0000000000 --- a/tests/repository_data/repository/2.0.0/snapshot.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "signatures": [ - { - "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", - "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" - } - ], - "signed": { - "_type": "snapshot", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "role1.json": { - "version": 1 - }, - "role2.json": { - "version": 1 - }, - "targets.json": { - "version": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/targets.json b/tests/repository_data/repository/2.0.0/targets.json deleted file mode 100644 index 9517c048d0..0000000000 --- a/tests/repository_data/repository/2.0.0/targets.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "signatures": [ - { - "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", - "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role1", - "paths": [ - "file3.txt" - ], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", - "targets": { - "file1.txt": { - "custom": { - "file_permissions": "0644" - }, - "hashes": { - "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", - "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" - }, - "length": 31 - }, - "file2.txt": { - "hashes": { - "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", - "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" - }, - "length": 39 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/2.0.0/timestamp.json b/tests/repository_data/repository/2.0.0/timestamp.json deleted file mode 100644 index 9d38e7c7ed..0000000000 --- a/tests/repository_data/repository/2.0.0/timestamp.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "signatures": [ - { - "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", - "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" - } - ], - "signed": { - "_type": "timestamp", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "snapshot.json": { - "hashes": { - "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" - }, - "length": 515, - "version": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/repository/1.0.0/1.root.json b/tests/repository_data/repository/metadata.staged/1.root.json similarity index 100% rename from tests/repository_data/repository/1.0.0/1.root.json rename to tests/repository_data/repository/metadata.staged/1.root.json diff --git a/tests/repository_data/repository/1.0.0/role1.json b/tests/repository_data/repository/metadata.staged/role1.json similarity index 97% rename from tests/repository_data/repository/1.0.0/role1.json rename to tests/repository_data/repository/metadata.staged/role1.json index 66ec049d73..0ac4687e77 100644 --- a/tests/repository_data/repository/1.0.0/role1.json +++ b/tests/repository_data/repository/metadata.staged/role1.json @@ -34,7 +34,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", + "spec_version": "1.0.0", "targets": { "file3.txt": { "hashes": { diff --git a/tests/repository_data/repository/metadata.staged/role2.json b/tests/repository_data/repository/metadata.staged/role2.json new file mode 100644 index 0000000000..93f378a758 --- /dev/null +++ b/tests/repository_data/repository/metadata.staged/role2.json @@ -0,0 +1,19 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "6c32f8cc2c642803a7b3b022ede0cf727e82964c1aa934571ef366bd5050ed02cfe3fdfe5477c08d0cbcc2dd17bb786d37ab1ce2b27e01ad79faf087594e0300" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": {}, + "roles": [] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/repository/1.0.0/root.json b/tests/repository_data/repository/metadata.staged/root.json similarity index 100% rename from tests/repository_data/repository/1.0.0/root.json rename to tests/repository_data/repository/metadata.staged/root.json diff --git a/tests/repository_data/repository/1.0.0/snapshot.json b/tests/repository_data/repository/metadata.staged/snapshot.json similarity index 100% rename from tests/repository_data/repository/1.0.0/snapshot.json rename to tests/repository_data/repository/metadata.staged/snapshot.json diff --git a/tests/repository_data/repository/1.0.0/targets.json b/tests/repository_data/repository/metadata.staged/targets.json similarity index 100% rename from tests/repository_data/repository/1.0.0/targets.json rename to tests/repository_data/repository/metadata.staged/targets.json diff --git a/tests/repository_data/repository/1.0.0/timestamp.json b/tests/repository_data/repository/metadata.staged/timestamp.json similarity index 100% rename from tests/repository_data/repository/1.0.0/timestamp.json rename to tests/repository_data/repository/metadata.staged/timestamp.json diff --git a/tests/repository_data/repository/1.root.json b/tests/repository_data/repository/metadata/1.root.json similarity index 100% rename from tests/repository_data/repository/1.root.json rename to tests/repository_data/repository/metadata/1.root.json diff --git a/tests/repository_data/repository/role1.json b/tests/repository_data/repository/metadata/role1.json similarity index 97% rename from tests/repository_data/repository/role1.json rename to tests/repository_data/repository/metadata/role1.json index 66ec049d73..0ac4687e77 100644 --- a/tests/repository_data/repository/role1.json +++ b/tests/repository_data/repository/metadata/role1.json @@ -34,7 +34,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", + "spec_version": "1.0.0", "targets": { "file3.txt": { "hashes": { diff --git a/tests/repository_data/repository/2.0.0/role2.json b/tests/repository_data/repository/metadata/role2.json similarity index 100% rename from tests/repository_data/repository/2.0.0/role2.json rename to tests/repository_data/repository/metadata/role2.json diff --git a/tests/repository_data/repository/root.json b/tests/repository_data/repository/metadata/root.json similarity index 100% rename from tests/repository_data/repository/root.json rename to tests/repository_data/repository/metadata/root.json diff --git a/tests/repository_data/repository/snapshot.json b/tests/repository_data/repository/metadata/snapshot.json similarity index 100% rename from tests/repository_data/repository/snapshot.json rename to tests/repository_data/repository/metadata/snapshot.json diff --git a/tests/repository_data/repository/targets.json b/tests/repository_data/repository/metadata/targets.json similarity index 100% rename from tests/repository_data/repository/targets.json rename to tests/repository_data/repository/metadata/targets.json diff --git a/tests/repository_data/repository/timestamp.json b/tests/repository_data/repository/metadata/timestamp.json similarity index 100% rename from tests/repository_data/repository/timestamp.json rename to tests/repository_data/repository/metadata/timestamp.json diff --git a/tests/repository_data/repository/role2.json b/tests/repository_data/repository/role2.json deleted file mode 100644 index 252f2aa88d..0000000000 --- a/tests/repository_data/repository/role2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" - } - ], - "signed": { - "_type": "targets", - "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", - "targets": {}, - "version": 1 - } -} \ No newline at end of file From ffbf4c4a317f612f564f4d99343e7ed7ef1e0a40 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Thu, 23 Jun 2022 20:23:23 +0530 Subject: [PATCH 05/40] Added the metadata under the newly created TAP 14 folder Created a new "TAP 14" folder wherein I added all the metadata inside the "1.0.0" and "2.0.0" folders and added the "targets" folder Signed-off-by: Abhisman Sarkar --- .../repository_data/TAP 14/1.0.0/1.root.json | 87 +++++++++++++++++++ tests/repository_data/TAP 14/1.0.0/role1.json | 49 +++++++++++ tests/repository_data/TAP 14/1.0.0/role2.json | 15 ++++ tests/repository_data/TAP 14/1.0.0/root.json | 87 +++++++++++++++++++ .../TAP 14/1.0.0/snapshot.json | 25 ++++++ .../repository_data/TAP 14/1.0.0/targets.json | 61 +++++++++++++ .../TAP 14/1.0.0/timestamp.json | 23 +++++ tests/repository_data/TAP 14/1.root.json | 87 +++++++++++++++++++ .../repository_data/TAP 14/2.0.0/1.root.json | 87 +++++++++++++++++++ tests/repository_data/TAP 14/2.0.0/role1.json | 49 +++++++++++ tests/repository_data/TAP 14/2.0.0/role2.json | 15 ++++ tests/repository_data/TAP 14/2.0.0/root.json | 87 +++++++++++++++++++ .../TAP 14/2.0.0/snapshot.json | 25 ++++++ .../repository_data/TAP 14/2.0.0/targets.json | 61 +++++++++++++ .../TAP 14/2.0.0/timestamp.json | 23 +++++ tests/repository_data/TAP 14/role1.json | 49 +++++++++++ tests/repository_data/TAP 14/role2.json | 15 ++++ tests/repository_data/TAP 14/root.json | 87 +++++++++++++++++++ tests/repository_data/TAP 14/snapshot.json | 25 ++++++ tests/repository_data/TAP 14/targets.json | 61 +++++++++++++ .../repository_data/TAP 14/targets/file1.txt | 1 + .../repository_data/TAP 14/targets/file2.txt | 1 + .../repository_data/TAP 14/targets/file3.txt | 1 + tests/repository_data/TAP 14/timestamp.json | 23 +++++ 24 files changed, 1044 insertions(+) create mode 100644 tests/repository_data/TAP 14/1.0.0/1.root.json create mode 100644 tests/repository_data/TAP 14/1.0.0/role1.json create mode 100644 tests/repository_data/TAP 14/1.0.0/role2.json create mode 100644 tests/repository_data/TAP 14/1.0.0/root.json create mode 100644 tests/repository_data/TAP 14/1.0.0/snapshot.json create mode 100644 tests/repository_data/TAP 14/1.0.0/targets.json create mode 100644 tests/repository_data/TAP 14/1.0.0/timestamp.json create mode 100644 tests/repository_data/TAP 14/1.root.json create mode 100644 tests/repository_data/TAP 14/2.0.0/1.root.json create mode 100644 tests/repository_data/TAP 14/2.0.0/role1.json create mode 100644 tests/repository_data/TAP 14/2.0.0/role2.json create mode 100644 tests/repository_data/TAP 14/2.0.0/root.json create mode 100644 tests/repository_data/TAP 14/2.0.0/snapshot.json create mode 100644 tests/repository_data/TAP 14/2.0.0/targets.json create mode 100644 tests/repository_data/TAP 14/2.0.0/timestamp.json create mode 100644 tests/repository_data/TAP 14/role1.json create mode 100644 tests/repository_data/TAP 14/role2.json create mode 100644 tests/repository_data/TAP 14/root.json create mode 100644 tests/repository_data/TAP 14/snapshot.json create mode 100644 tests/repository_data/TAP 14/targets.json create mode 100644 tests/repository_data/TAP 14/targets/file1.txt create mode 100644 tests/repository_data/TAP 14/targets/file2.txt create mode 100644 tests/repository_data/TAP 14/targets/file3.txt create mode 100644 tests/repository_data/TAP 14/timestamp.json diff --git a/tests/repository_data/TAP 14/1.0.0/1.root.json b/tests/repository_data/TAP 14/1.0.0/1.root.json new file mode 100644 index 0000000000..214d8db01b --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/1.root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.0.0/role1.json b/tests/repository_data/TAP 14/1.0.0/role1.json new file mode 100644 index 0000000000..66ec049d73 --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/role1.json @@ -0,0 +1,49 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role2", + "paths": [], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": { + "file3.txt": { + "hashes": { + "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", + "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" + }, + "length": 28 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.0.0/role2.json b/tests/repository_data/TAP 14/1.0.0/role2.json new file mode 100644 index 0000000000..252f2aa88d --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/role2.json @@ -0,0 +1,15 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" + } + ], + "signed": { + "_type": "targets", + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.0.0/root.json b/tests/repository_data/TAP 14/1.0.0/root.json new file mode 100644 index 0000000000..214d8db01b --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.0.0/snapshot.json b/tests/repository_data/TAP 14/1.0.0/snapshot.json new file mode 100644 index 0000000000..7c8c091a2e --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/snapshot.json @@ -0,0 +1,25 @@ +{ + "signatures": [ + { + "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", + "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "role1.json": { + "version": 1 + }, + "role2.json": { + "version": 1 + }, + "targets.json": { + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.0.0/targets.json b/tests/repository_data/TAP 14/1.0.0/targets.json new file mode 100644 index 0000000000..8e21c269b4 --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/targets.json @@ -0,0 +1,61 @@ +{ + "signatures": [ + { + "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", + "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role1", + "paths": [ + "file3.txt" + ], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": { + "file1.txt": { + "custom": { + "file_permissions": "0644" + }, + "hashes": { + "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", + "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" + }, + "length": 31 + }, + "file2.txt": { + "hashes": { + "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", + "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" + }, + "length": 39 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.0.0/timestamp.json b/tests/repository_data/TAP 14/1.0.0/timestamp.json new file mode 100644 index 0000000000..9a0daf078b --- /dev/null +++ b/tests/repository_data/TAP 14/1.0.0/timestamp.json @@ -0,0 +1,23 @@ +{ + "signatures": [ + { + "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", + "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" + }, + "length": 515, + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1.root.json b/tests/repository_data/TAP 14/1.root.json new file mode 100644 index 0000000000..214d8db01b --- /dev/null +++ b/tests/repository_data/TAP 14/1.root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/1.root.json b/tests/repository_data/TAP 14/2.0.0/1.root.json new file mode 100644 index 0000000000..25595b3f38 --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/1.root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "2.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/role1.json b/tests/repository_data/TAP 14/2.0.0/role1.json new file mode 100644 index 0000000000..66ec049d73 --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/role1.json @@ -0,0 +1,49 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role2", + "paths": [], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": { + "file3.txt": { + "hashes": { + "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", + "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" + }, + "length": 28 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/role2.json b/tests/repository_data/TAP 14/2.0.0/role2.json new file mode 100644 index 0000000000..9c49e16570 --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/role2.json @@ -0,0 +1,15 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" + } + ], + "signed": { + "_type": "targets", + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/root.json b/tests/repository_data/TAP 14/2.0.0/root.json new file mode 100644 index 0000000000..25595b3f38 --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "2.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/snapshot.json b/tests/repository_data/TAP 14/2.0.0/snapshot.json new file mode 100644 index 0000000000..51aa78a5a6 --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/snapshot.json @@ -0,0 +1,25 @@ +{ + "signatures": [ + { + "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", + "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "role1.json": { + "version": 1 + }, + "role2.json": { + "version": 1 + }, + "targets.json": { + "version": 1 + } + }, + "spec_version": "2.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/targets.json b/tests/repository_data/TAP 14/2.0.0/targets.json new file mode 100644 index 0000000000..9517c048d0 --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/targets.json @@ -0,0 +1,61 @@ +{ + "signatures": [ + { + "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", + "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role1", + "paths": [ + "file3.txt" + ], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": { + "file1.txt": { + "custom": { + "file_permissions": "0644" + }, + "hashes": { + "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", + "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" + }, + "length": 31 + }, + "file2.txt": { + "hashes": { + "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", + "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" + }, + "length": 39 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/timestamp.json b/tests/repository_data/TAP 14/2.0.0/timestamp.json new file mode 100644 index 0000000000..9d38e7c7ed --- /dev/null +++ b/tests/repository_data/TAP 14/2.0.0/timestamp.json @@ -0,0 +1,23 @@ +{ + "signatures": [ + { + "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", + "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" + }, + "length": 515, + "version": 1 + } + }, + "spec_version": "2.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/role1.json b/tests/repository_data/TAP 14/role1.json new file mode 100644 index 0000000000..66ec049d73 --- /dev/null +++ b/tests/repository_data/TAP 14/role1.json @@ -0,0 +1,49 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role2", + "paths": [], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": { + "file3.txt": { + "hashes": { + "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", + "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" + }, + "length": 28 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/role2.json b/tests/repository_data/TAP 14/role2.json new file mode 100644 index 0000000000..252f2aa88d --- /dev/null +++ b/tests/repository_data/TAP 14/role2.json @@ -0,0 +1,15 @@ +{ + "signatures": [ + { + "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", + "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" + } + ], + "signed": { + "_type": "targets", + "expires": "2030-01-01T00:00:00Z", + "spec_version": "2.0.0", + "targets": {}, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/root.json b/tests/repository_data/TAP 14/root.json new file mode 100644 index 0000000000..214d8db01b --- /dev/null +++ b/tests/repository_data/TAP 14/root.json @@ -0,0 +1,87 @@ +{ + "signatures": [ + { + "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", + "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" + } + ], + "signed": { + "_type": "root", + "consistent_snapshot": false, + "expires": "2030-01-01T00:00:00Z", + "keys": { + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "rsa", + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" + }, + "scheme": "rsassa-pss-sha256" + }, + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + }, + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" + }, + "scheme": "ed25519" + }, + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" + }, + "scheme": "ed25519" + } + }, + "roles": { + "root": { + "keyids": [ + "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" + ], + "threshold": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/snapshot.json b/tests/repository_data/TAP 14/snapshot.json new file mode 100644 index 0000000000..7c8c091a2e --- /dev/null +++ b/tests/repository_data/TAP 14/snapshot.json @@ -0,0 +1,25 @@ +{ + "signatures": [ + { + "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", + "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" + } + ], + "signed": { + "_type": "snapshot", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "role1.json": { + "version": 1 + }, + "role2.json": { + "version": 1 + }, + "targets.json": { + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets.json b/tests/repository_data/TAP 14/targets.json new file mode 100644 index 0000000000..8e21c269b4 --- /dev/null +++ b/tests/repository_data/TAP 14/targets.json @@ -0,0 +1,61 @@ +{ + "signatures": [ + { + "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", + "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" + } + ], + "signed": { + "_type": "targets", + "delegations": { + "keys": { + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], + "keytype": "ed25519", + "keyval": { + "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" + }, + "scheme": "ed25519" + } + }, + "roles": [ + { + "keyids": [ + "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" + ], + "name": "role1", + "paths": [ + "file3.txt" + ], + "terminating": false, + "threshold": 1 + } + ] + }, + "expires": "2030-01-01T00:00:00Z", + "spec_version": "1.0.0", + "targets": { + "file1.txt": { + "custom": { + "file_permissions": "0644" + }, + "hashes": { + "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", + "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" + }, + "length": 31 + }, + "file2.txt": { + "hashes": { + "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", + "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" + }, + "length": 39 + } + }, + "version": 1 + } +} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets/file1.txt b/tests/repository_data/TAP 14/targets/file1.txt new file mode 100644 index 0000000000..7bf3499f13 --- /dev/null +++ b/tests/repository_data/TAP 14/targets/file1.txt @@ -0,0 +1 @@ +This is an example target file. \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets/file2.txt b/tests/repository_data/TAP 14/targets/file2.txt new file mode 100644 index 0000000000..606f18efc8 --- /dev/null +++ b/tests/repository_data/TAP 14/targets/file2.txt @@ -0,0 +1 @@ +This is an another example target file. \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets/file3.txt b/tests/repository_data/TAP 14/targets/file3.txt new file mode 100644 index 0000000000..60464604aa --- /dev/null +++ b/tests/repository_data/TAP 14/targets/file3.txt @@ -0,0 +1 @@ +This is role1's target file. \ No newline at end of file diff --git a/tests/repository_data/TAP 14/timestamp.json b/tests/repository_data/TAP 14/timestamp.json new file mode 100644 index 0000000000..9a0daf078b --- /dev/null +++ b/tests/repository_data/TAP 14/timestamp.json @@ -0,0 +1,23 @@ +{ + "signatures": [ + { + "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", + "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" + } + ], + "signed": { + "_type": "timestamp", + "expires": "2030-01-01T00:00:00Z", + "meta": { + "snapshot.json": { + "hashes": { + "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" + }, + "length": 515, + "version": 1 + } + }, + "spec_version": "1.0.0", + "version": 1 + } +} \ No newline at end of file From 66b52f8680272ca5a8015a7be9feb2310579db5a Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Sun, 26 Jun 2022 22:24:36 +0530 Subject: [PATCH 06/40] Updated test_updater_ng.py file Added the test case which checks for the TAP 14 folder Signed-off-by: Abhisman Sarkar --- tests/test_updater_ng.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index c87a8fdc74..db37b6a88c 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -326,6 +326,16 @@ def test_non_existing_target_file(self) -> None: with self.assertRaises(exceptions.DownloadHTTPError): self.updater.download_target(info) + # test case to check for the TAP 14 folder + def test_check_folder_tap14(self) -> None: + # Creating the parent folder for the TAP 14 folder + original_repository_files = os.path.join( + utils.TESTS_DIR, "repository_data" + ) + #Adding the TAP 14 folder to the file path + tap_14 = os.path.join( + original_repository_files, "TAP 14") + self.assertTrue(os.path.isdir(tap_14)) if __name__ == "__main__": utils.configure_test_logging(sys.argv) From 99a454e58c5b2adf233747491d274ea9ad97371c Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Mon, 4 Jul 2022 11:37:28 +0530 Subject: [PATCH 07/40] Updated the test_updater_ng.py file Added a test function that check the contents inside the TAP 14 folder. Signed-off-by: Abhisman Sarkar --- tests/test_updater_ng.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index db37b6a88c..be085d676c 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -79,6 +79,8 @@ def setUp(self) -> None: "metadata", "current", ) + # Adding the TAP14 folder + original_tap14 = os.path.join(original_repository_files, "TAP 14") # Save references to the often-needed client repository directories. # Test cases need these references to access metadata and target files. @@ -87,12 +89,16 @@ def setUp(self) -> None: ) self.keystore_directory = os.path.join(self.tmp_test_dir, "keystore") self.client_directory = os.path.join(self.tmp_test_dir, "client") + # Adding the TAP14 folder + self.tap14_directory = os.path.join(self.tmp_test_dir, "TAP 14") # Copy the original 'repository', 'client', and 'keystore' directories # to the temporary repository the test cases can use. shutil.copytree(original_repository, self.repository_directory) shutil.copytree(original_client, self.client_directory) shutil.copytree(original_keystore, self.keystore_directory) + # Copying over the TAP 14 folder + shutil.copytree(original_tap14, self.tap14_directory) # 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'. repository_basepath = self.repository_directory[len(os.getcwd()) :] @@ -329,13 +335,18 @@ def test_non_existing_target_file(self) -> None: # test case to check for the TAP 14 folder def test_check_folder_tap14(self) -> None: # Creating the parent folder for the TAP 14 folder - original_repository_files = os.path.join( - utils.TESTS_DIR, "repository_data" - ) - #Adding the TAP 14 folder to the file path - tap_14 = os.path.join( - original_repository_files, "TAP 14") - self.assertTrue(os.path.isdir(tap_14)) + self.assertTrue(os.path.isdir(self.tap14_directory)) + + def test_check_tap14_contents(self) -> None: + # Checking specific files inside TAP 14 + filenames = ["targets.json","root.json"] + for file in filenames: + self.assertTrue(os.path.isfile(os.path.join(self.tap14_directory, file))) + + #Checking specific folders inside TAP 14 + foldernames = ["targets","1.0.0"] + for folder in foldernames: + self.assertTrue(os.path.isdir(os.path.join(self.tap14_directory, folder))) if __name__ == "__main__": utils.configure_test_logging(sys.argv) From 3b2e29b90e771cacfebca63b69d9c8886be80a1f Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Wed, 6 Jul 2022 11:22:22 +0530 Subject: [PATCH 08/40] Updated updater.py Added a function to select specification version folder to download metadata from Signed-off-by: Abhisman Sarkar --- tuf/ngclient/updater.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index e518118a80..640198fc7a 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -259,10 +259,10 @@ def download_target( def _download_metadata( self, rolename: str, length: int, version: Optional[int] = None - ) -> bytes: + ) -> bytes: # ADD ANOTHER VARIABLE FOR SPECIFICATION VERSION """Download a metadata file and return it as bytes""" - encoded_name = parse.quote(rolename, "") - if version is None: + encoded_name = parse.quote(rolename, "") + if version is None: # THIS IS SNAPSHOT VERSION !! url = f"{self._metadata_base_url}{encoded_name}.json" else: url = f"{self._metadata_base_url}{version}.{encoded_name}.json" @@ -471,6 +471,19 @@ def _preorder_depth_first_walk( # If this point is reached then target is not found, return None return None + def _tap14_implementation(self, folder:str) -> None: + # Downloading all metadata inside the specified folder + + path = f"{BASE_URL}/repository_data/TAP 14" # File path to download from + path = os.path.join(path,folder) # Add the folder to the path + + # I'll need to know exactly how the repository stores the metadata for me to know + # the file path I have to download from. + + files = next(os.walk(path))[2] # Get all the files inside the list + for file in files: + if file.endswith(".json"): + self._download_metadata(file) def _ensure_trailing_slash(url: str) -> str: """Return url guaranteed to end in a slash""" From f95fdb508d890c5379c10dbf7e9752f8623d32fd Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Sun, 7 Aug 2022 10:19:43 +0530 Subject: [PATCH 09/40] New client updation logic along with tests. Also some test file changes Added the logic for the new client update process inside tuf/ngclient/updater.py. Added test functions for the new process inside tests/test_updater_ng.py. Also made changes to some test files. Signed-off-by: Abhisman Sarkar --- tests/repository_data/TAP 14/1.0.0/role1.json | 2 +- tests/repository_data/TAP 14/1.0.0/role2.json | 2 +- tests/repository_data/TAP 14/role1.json | 2 +- tests/repository_data/TAP 14/role2.json | 2 +- tests/test_updater_ng.py | 25 +++++- tuf/ngclient/_internal/requests_fetcher.py | 14 +++ tuf/ngclient/fetcher.py | 5 ++ tuf/ngclient/updater.py | 85 ++++++++++++++++--- 8 files changed, 121 insertions(+), 16 deletions(-) diff --git a/tests/repository_data/TAP 14/1.0.0/role1.json b/tests/repository_data/TAP 14/1.0.0/role1.json index 66ec049d73..0ac4687e77 100644 --- a/tests/repository_data/TAP 14/1.0.0/role1.json +++ b/tests/repository_data/TAP 14/1.0.0/role1.json @@ -34,7 +34,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", + "spec_version": "1.0.0", "targets": { "file3.txt": { "hashes": { diff --git a/tests/repository_data/TAP 14/1.0.0/role2.json b/tests/repository_data/TAP 14/1.0.0/role2.json index 252f2aa88d..9c49e16570 100644 --- a/tests/repository_data/TAP 14/1.0.0/role2.json +++ b/tests/repository_data/TAP 14/1.0.0/role2.json @@ -8,7 +8,7 @@ "signed": { "_type": "targets", "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", + "spec_version": "1.0.0", "targets": {}, "version": 1 } diff --git a/tests/repository_data/TAP 14/role1.json b/tests/repository_data/TAP 14/role1.json index 66ec049d73..0ac4687e77 100644 --- a/tests/repository_data/TAP 14/role1.json +++ b/tests/repository_data/TAP 14/role1.json @@ -34,7 +34,7 @@ ] }, "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", + "spec_version": "1.0.0", "targets": { "file3.txt": { "hashes": { diff --git a/tests/repository_data/TAP 14/role2.json b/tests/repository_data/TAP 14/role2.json index 252f2aa88d..9c49e16570 100644 --- a/tests/repository_data/TAP 14/role2.json +++ b/tests/repository_data/TAP 14/role2.json @@ -8,7 +8,7 @@ "signed": { "_type": "targets", "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", + "spec_version": "1.0.0", "targets": {}, "version": 1 } diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index be085d676c..97d81af012 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -4,7 +4,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 """Test Updater class -""" +""" import logging import os @@ -348,6 +348,29 @@ def test_check_tap14_contents(self) -> None: for folder in foldernames: self.assertTrue(os.path.isdir(os.path.join(self.tap14_directory, folder))) + def test_get_spec_version1(self) -> None: + #This uses the default SUPPORTED_VERSIONS variable from updater.py + with self.assertRaises(exceptions.DownloadError): + self.updater._get_spec_version(["1","2","3"],"4",ngclient.updater.SUPPORTED_VERSIONS) + + self.assertEqual(self.updater._get_spec_version(["1","2","3"],"3",ngclient.updater.SUPPORTED_VERSIONS), "3") + + def test_get_spec_version2(self) -> None: + #Checks with different values + with self.assertRaises(exceptions.DownloadError): #Checks under point 2 + self.updater._get_spec_version(["3","5","6"],"7",["1","2","3","4"]) + + self.assertEqual(self.updater._get_spec_version(["3","5","6"],"3",["1","2","3","4"]), "3") + self.assertEqual(self.updater._get_spec_version(["1","2","3"],"3",["3","5","6"]), "3") + + with self.assertRaises(exceptions.DownloadError): #Checks under point 3 + self.updater._get_spec_version(["3","5","6"],"3",["1","2","4"]) + + # TODO Testing logging functionality. + #with self.assertLogs(ngclient.updater.__name__) as cm: + # logging.getLogger('foo').info('first message') + # self.updater._get_spec_version(["3","5","6"],"3",["1","2","3","4"]) + if __name__ == "__main__": utils.configure_test_logging(sys.argv) unittest.main() diff --git a/tuf/ngclient/_internal/requests_fetcher.py b/tuf/ngclient/_internal/requests_fetcher.py index 07562791f3..b485d85962 100644 --- a/tuf/ngclient/_internal/requests_fetcher.py +++ b/tuf/ngclient/_internal/requests_fetcher.py @@ -48,6 +48,20 @@ def __init__(self) -> None: # Default settings self.socket_timeout: int = 4 # seconds self.chunk_size: int = 400000 # bytes + + def _look(self, url: str) -> str: + """Function used for checking if a certain file exists""" + + response = requests.head(url) + + try: + response.raise_for_status() + except requests.HTTPError as e: + response.close() + status = e.response.status_code + raise exceptions.DownloadHTTPError(str(e), status) + + return response def _fetch(self, url: str) -> Iterator[bytes]: """Fetches the contents of HTTP/HTTPS url from a remote server diff --git a/tuf/ngclient/fetcher.py b/tuf/ngclient/fetcher.py index f13c893420..ed0db8194b 100644 --- a/tuf/ngclient/fetcher.py +++ b/tuf/ngclient/fetcher.py @@ -30,6 +30,11 @@ class FetcherInterface: __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def _look(self, url: str) -> str: + """Function used for checking if a certain file exists""" + raise NotImplementedError # pragma: no cover + @abc.abstractmethod def _fetch(self, url: str) -> Iterator[bytes]: """Fetches the contents of HTTP/HTTPS ``url`` from a remote server. diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 640198fc7a..ef7c3659c7 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -37,11 +37,12 @@ import os import shutil import tempfile -from typing import Optional, Set +from typing import Optional, Set, List from urllib import parse from tuf.api import exceptions from tuf.api.metadata import ( + SPECIFICATION_VERSION, Metadata, Root, Snapshot, @@ -54,7 +55,7 @@ from tuf.ngclient.fetcher import FetcherInterface logger = logging.getLogger(__name__) - +SUPPORTED_VERSIONS = ["1","2","3"] class Updater: """Creates a new ``Updater`` instance and loads trusted root metadata. @@ -76,15 +77,16 @@ class Updater: RepositoryError: Local root.json is invalid """ - def __init__( - self, - metadata_dir: str, + def __init__( + self, + metadata_dir: str, metadata_base_url: str, target_dir: Optional[str] = None, target_base_url: Optional[str] = None, fetcher: Optional[FetcherInterface] = None, config: Optional[UpdaterConfig] = None, ): + self.spec_version = None #spec_version is the last used version by the client to get metadata self._dir = metadata_dir self._metadata_base_url = _ensure_trailing_slash(metadata_base_url) self.target_dir = target_dir @@ -123,11 +125,71 @@ def refresh(self) -> None: DownloadError: Download of a metadata file failed in some way """ + repository_versions = self._get_repository_versions() + + #Updating self.spec_version + self.spec_version = self._get_spec_version(repository_versions, self.spec_version, SUPPORTED_VERSIONS) + self._load_root() self._load_timestamp() self._load_snapshot() self._load_targets(Targets.type, Root.type) + def _get_repository_versions(self) -> List[str]: + """Returns a list of all the repository versions.""" + + encoded_name = parse.quote("root", "") + url = f"{self._metadata_base_url}{self.spec_version}{encoded_name}.json" + repository_versions = [] + + # Here we manually enter the list of all possible versions that might exist on the + # repository side and then we check for each. Not an optimal solution. + for i in ["1", "2", "3"]: + try: + response = self._fetcher._look(url.replace(self.spec_version, i)) #Can I call _look()? + if response.status_code == 200: + repository_versions.append(i) + except Exception as e: + #logger.debug(f"Could not get root metadata from {url.replace(self.spec_version, i)}") + continue + + # Acc to the TAP, repository metadata is supposed to be kept under a folder strucutre + # but that isn't being used here. So, that might be a way to go + + #repository_versions = ["3.0.0","4.0.0","5.0.0"] + + #repository_versions = [i[0] for i in repository_versions] + + #return repository_versions + return ["1","2","3"] + + def _get_spec_version(self, repository_versions: List[str], spec_version: str, supported_versions: List[str]) -> str: + """Returns the specification version to be used.""" + + # point 1 + latestrep_ver = max(repository_versions) # To be used for a later warning + + # point 2 + if spec_version: + if latestrep_ver < spec_version: + raise exceptions.DownloadError("The repository version is lower than the last used spec version") + + # point 3 + try: + spec_version = max(set(supported_versions) & set(repository_versions)) + except ValueError: + raise exceptions.DownloadError(f"""No matching specification version found. Found {repository_versions} in + repository and {supported_versions} in client.""") + # Common error case for point 4 and point 3 + + # point 5 + # Warning for client + if latestrep_ver > spec_version: + logger.warning("Not using the latest specification version available on the repository") + + # TODO use logger.warning or store and return the warning message in a variable? + return spec_version + def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: raise ValueError("target_dir must be set if filepath is not given") @@ -259,13 +321,15 @@ def download_target( def _download_metadata( self, rolename: str, length: int, version: Optional[int] = None - ) -> bytes: # ADD ANOTHER VARIABLE FOR SPECIFICATION VERSION + ) -> bytes: """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") + + self.spec_version += ".0.0" if version is None: # THIS IS SNAPSHOT VERSION !! - url = f"{self._metadata_base_url}{encoded_name}.json" + url = f"{self._metadata_base_url}{self.spec_version}{encoded_name}.json" else: - url = f"{self._metadata_base_url}{version}.{encoded_name}.json" + url = f"{self._metadata_base_url}{self.spec_version}{version}.{encoded_name}.json" return self._fetcher.download_bytes(url, length) def _load_local_metadata(self, rolename: str) -> bytes: @@ -471,14 +535,13 @@ def _preorder_depth_first_walk( # If this point is reached then target is not found, return None return None - def _tap14_implementation(self, folder:str) -> None: + def _download_directory(self, folder:str) -> None: # Downloading all metadata inside the specified folder path = f"{BASE_URL}/repository_data/TAP 14" # File path to download from path = os.path.join(path,folder) # Add the folder to the path - # I'll need to know exactly how the repository stores the metadata for me to know - # the file path I have to download from. + # Repository might be storing data in different formats. files = next(os.walk(path))[2] # Get all the files inside the list for file in files: From 856716095bfb36e0bc81cd6b134892ec033855f1 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Thu, 25 Aug 2022 00:38:09 +0530 Subject: [PATCH 10/40] Updated test functionality and code structure Worked upon adding better tests in test_updater_ng.py and worked on the code structure for updater.py Signed-off-by: Abhisman Sarkar --- tests/test_updater_ng.py | 76 ++++++++++++++------- tuf/ngclient/updater.py | 142 ++++++++++++++++++++++++--------------- 2 files changed, 138 insertions(+), 80 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 97d81af012..f8096fce0b 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -4,7 +4,7 @@ # SPDX-License-Identifier: MIT OR Apache-2.0 """Test Updater class -""" +""" import logging import os @@ -29,6 +29,7 @@ Targets, Timestamp, ) +from tuf.ngclient.updater import _get_spec_version logger = logging.getLogger(__name__) @@ -332,45 +333,70 @@ def test_non_existing_target_file(self) -> None: with self.assertRaises(exceptions.DownloadHTTPError): self.updater.download_target(info) + # TAP 14 tests ~ REMOVE COMMENT BEFORE THE NEXT COMMIT!! + # test case to check for the TAP 14 folder def test_check_folder_tap14(self) -> None: - # Creating the parent folder for the TAP 14 folder + # Creating the parent folder for the TAP 14 folder self.assertTrue(os.path.isdir(self.tap14_directory)) - def test_check_tap14_contents(self) -> None: + def test_check_tap14_contents(self) -> None: # Checking specific files inside TAP 14 - filenames = ["targets.json","root.json"] + filenames = ["targets.json", "root.json"] for file in filenames: - self.assertTrue(os.path.isfile(os.path.join(self.tap14_directory, file))) + self.assertTrue( + os.path.isfile(os.path.join(self.tap14_directory, file)) + ) - #Checking specific folders inside TAP 14 - foldernames = ["targets","1.0.0"] + # Checking specific folders inside TAP 14 + foldernames = ["targets", "1.0.0"] for folder in foldernames: - self.assertTrue(os.path.isdir(os.path.join(self.tap14_directory, folder))) + self.assertTrue( + os.path.isdir(os.path.join(self.tap14_directory, folder)) + ) def test_get_spec_version1(self) -> None: - #This uses the default SUPPORTED_VERSIONS variable from updater.py + # This uses the default SUPPORTED_VERSIONS variable from updater.py with self.assertRaises(exceptions.DownloadError): - self.updater._get_spec_version(["1","2","3"],"4",ngclient.updater.SUPPORTED_VERSIONS) - - self.assertEqual(self.updater._get_spec_version(["1","2","3"],"3",ngclient.updater.SUPPORTED_VERSIONS), "3") - + _get_spec_version( + ["1", "2", "3"], "4", ngclient.updater.SUPPORTED_VERSIONS + ) + + self.assertEqual( + _get_spec_version( + ["1", "2", "3"], "3", ngclient.updater.SUPPORTED_VERSIONS + ), + ("3", None), + ) + def test_get_spec_version2(self) -> None: - #Checks with different values - with self.assertRaises(exceptions.DownloadError): #Checks under point 2 - self.updater._get_spec_version(["3","5","6"],"7",["1","2","3","4"]) - - self.assertEqual(self.updater._get_spec_version(["3","5","6"],"3",["1","2","3","4"]), "3") - self.assertEqual(self.updater._get_spec_version(["1","2","3"],"3",["3","5","6"]), "3") - - with self.assertRaises(exceptions.DownloadError): #Checks under point 3 - self.updater._get_spec_version(["3","5","6"],"3",["1","2","4"]) - - # TODO Testing logging functionality. - #with self.assertLogs(ngclient.updater.__name__) as cm: + warningchecker = "Not using the latest specification version available on the repository" + # Checks with different values + with self.assertRaises(exceptions.DownloadError): + _get_spec_version(["3", "5", "6"], "7", ["1", "2", "3", "4"]) + + self.assertEqual( + _get_spec_version(["3", "5", "6"], "3", ["1", "2", "3", "4"]), + ("3", warningchecker), + ) + self.assertEqual( + _get_spec_version(["1", "2", "3"], "3", ["3", "5", "6"]), + ("3", None), + ) + self.assertEqual( + _get_spec_version(["8", "11", "13"], "12", ["8", "11", "12"]), + ("11", warningchecker), + ) + + with self.assertRaises(exceptions.DownloadError): + _get_spec_version(["3", "5", "6"], "3", ["1", "2", "4"]) + + # TODO Testing logging functionality. + # with self.assertLogs(ngclient.updater.__name__) as cm: # logging.getLogger('foo').info('first message') # self.updater._get_spec_version(["3","5","6"],"3",["1","2","3","4"]) + if __name__ == "__main__": utils.configure_test_logging(sys.argv) unittest.main() diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index ef7c3659c7..36a6d921bf 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -55,7 +55,8 @@ from tuf.ngclient.fetcher import FetcherInterface logger = logging.getLogger(__name__) -SUPPORTED_VERSIONS = ["1","2","3"] +SUPPORTED_VERSIONS = ["1", "2", "3"] + class Updater: """Creates a new ``Updater`` instance and loads trusted root metadata. @@ -77,16 +78,16 @@ class Updater: RepositoryError: Local root.json is invalid """ - def __init__( - self, - metadata_dir: str, + def __init__( + self, + metadata_dir: str, metadata_base_url: str, target_dir: Optional[str] = None, target_base_url: Optional[str] = None, fetcher: Optional[FetcherInterface] = None, config: Optional[UpdaterConfig] = None, ): - self.spec_version = None #spec_version is the last used version by the client to get metadata + self.spec_version = None # spec_version is the last used version by the client to get metadata self._dir = metadata_dir self._metadata_base_url = _ensure_trailing_slash(metadata_base_url) self.target_dir = target_dir @@ -124,12 +125,20 @@ def refresh(self) -> None: RepositoryError: Metadata failed to verify in some way DownloadError: Download of a metadata file failed in some way """ - + # json.load() + # Load self.spec_version using self._load_local_metadata() here from disk + # Exception would be raised if spec_version is not found locally. Set to "1" in that case repository_versions = self._get_repository_versions() - - #Updating self.spec_version - self.spec_version = self._get_spec_version(repository_versions, self.spec_version, SUPPORTED_VERSIONS) + # Updating self.spec_version + specver_message = _get_spec_version( + repository_versions, self.spec_version, SUPPORTED_VERSIONS + ) + + if specver_message(1): + logger.warning(specver_message(1)) + self.spec_version = specver_message(0) + self._persist_metadata("spec_version", json.dumps(self.spec_version)) self._load_root() self._load_timestamp() self._load_snapshot() @@ -137,58 +146,33 @@ def refresh(self) -> None: def _get_repository_versions(self) -> List[str]: """Returns a list of all the repository versions.""" - + encoded_name = parse.quote("root", "") url = f"{self._metadata_base_url}{self.spec_version}{encoded_name}.json" repository_versions = [] - # Here we manually enter the list of all possible versions that might exist on the + # Here we manually enter the list of all possible versions that might exist on the # repository side and then we check for each. Not an optimal solution. for i in ["1", "2", "3"]: try: - response = self._fetcher._look(url.replace(self.spec_version, i)) #Can I call _look()? + response = self._fetcher._look( + url.replace(self.spec_version, i) + ) # Can I call _look()? if response.status_code == 200: repository_versions.append(i) except Exception as e: - #logger.debug(f"Could not get root metadata from {url.replace(self.spec_version, i)}") + # logger.debug(f"Could not get root metadata from {url.replace(self.spec_version, i)}") continue - + # Acc to the TAP, repository metadata is supposed to be kept under a folder strucutre # but that isn't being used here. So, that might be a way to go - #repository_versions = ["3.0.0","4.0.0","5.0.0"] - - #repository_versions = [i[0] for i in repository_versions] - - #return repository_versions - return ["1","2","3"] - - def _get_spec_version(self, repository_versions: List[str], spec_version: str, supported_versions: List[str]) -> str: - """Returns the specification version to be used.""" - - # point 1 - latestrep_ver = max(repository_versions) # To be used for a later warning - - # point 2 - if spec_version: - if latestrep_ver < spec_version: - raise exceptions.DownloadError("The repository version is lower than the last used spec version") - - # point 3 - try: - spec_version = max(set(supported_versions) & set(repository_versions)) - except ValueError: - raise exceptions.DownloadError(f"""No matching specification version found. Found {repository_versions} in - repository and {supported_versions} in client.""") - # Common error case for point 4 and point 3 - - # point 5 - # Warning for client - if latestrep_ver > spec_version: - logger.warning("Not using the latest specification version available on the repository") - - # TODO use logger.warning or store and return the warning message in a variable? - return spec_version + # repository_versions = ["3.0.0","4.0.0","5.0.0"] + + # repository_versions = [i[0] for i in repository_versions] + + # return repository_versions + return ["1", "2", "3"] def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: @@ -321,12 +305,12 @@ def download_target( def _download_metadata( self, rolename: str, length: int, version: Optional[int] = None - ) -> bytes: + ) -> bytes: """Download a metadata file and return it as bytes""" - encoded_name = parse.quote(rolename, "") + encoded_name = parse.quote(rolename, "") - self.spec_version += ".0.0" - if version is None: # THIS IS SNAPSHOT VERSION !! + self.spec_version += ".0.0" + if version is None: # THIS IS SNAPSHOT VERSION !! url = f"{self._metadata_base_url}{self.spec_version}{encoded_name}.json" else: url = f"{self._metadata_base_url}{self.spec_version}{version}.{encoded_name}.json" @@ -535,19 +519,67 @@ def _preorder_depth_first_walk( # If this point is reached then target is not found, return None return None - def _download_directory(self, folder:str) -> None: + def _download_directory(self, folder: str) -> None: # Downloading all metadata inside the specified folder - path = f"{BASE_URL}/repository_data/TAP 14" # File path to download from - path = os.path.join(path,folder) # Add the folder to the path + path = ( + f"{BASE_URL}/repository_data/TAP 14" # File path to download from + ) + path = os.path.join(path, folder) # Add the folder to the path # Repository might be storing data in different formats. - files = next(os.walk(path))[2] # Get all the files inside the list + files = next(os.walk(path))[2] # Get all the files inside the list for file in files: if file.endswith(".json"): self._download_metadata(file) + def _ensure_trailing_slash(url: str) -> str: """Return url guaranteed to end in a slash""" return url if url.endswith("/") else f"{url}/" + + +def _get_spec_version( + repository_versions: List[str], + spec_version: str, + supported_versions: List[str], +) -> str: + """Returns the specification version to be used.""" + + repository_versions = [int(i) for i in repository_versions] + supported_versions = [int(i) for i in supported_versions] + spec_version = int(spec_version) + + # The client determines the latest version available on the repository by looking + # for the directory with the largest version number. + latestrep_ver = max(repository_versions) + + # If the latest version on the repository is lower than the previous specification + # version the client used from this repository, the client should report an error + # and terminate the update. + if spec_version: + if latestrep_ver < spec_version: + raise exceptions.DownloadError( + "The repository version is lower than the last used spec version" + ) + + # If the latest version on the client is found on the repository or vice versa, the + # client will use this directory to download the metadata. + try: + spec_version = max(set(repository_versions) & set(supported_versions)) + except ValueError: + raise exceptions.DownloadError( + f"""No matching specification version found. Found {repository_versions} in + repository and {supported_versions} in client.""" + ) + # Checks for the highest matching version between the client and the repository + # and reports an error if no matching version is found. + + # If the latest version on the repository is higher than the client spec version, + # the client should report to the user that it is not using the most up to date version + warning = None + if latestrep_ver > spec_version: + warning = "Not using the latest specification version available on the repository" + + return (str(spec_version), warning) From a70cc4848c36e148943c52e22676e1acdb3cdf49 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Mon, 29 Aug 2022 22:54:40 +0530 Subject: [PATCH 11/40] Updated updater.py Made changes to _get_repository_versions() to read the supported-versions file and also removed _look() from fetcher.py and requests_fetcher.py Signed-off-by: Abhisman Sarkar --- tuf/ngclient/_internal/requests_fetcher.py | 14 ---------- tuf/ngclient/fetcher.py | 5 ---- tuf/ngclient/updater.py | 32 ++++++---------------- 3 files changed, 8 insertions(+), 43 deletions(-) diff --git a/tuf/ngclient/_internal/requests_fetcher.py b/tuf/ngclient/_internal/requests_fetcher.py index b485d85962..07562791f3 100644 --- a/tuf/ngclient/_internal/requests_fetcher.py +++ b/tuf/ngclient/_internal/requests_fetcher.py @@ -48,20 +48,6 @@ def __init__(self) -> None: # Default settings self.socket_timeout: int = 4 # seconds self.chunk_size: int = 400000 # bytes - - def _look(self, url: str) -> str: - """Function used for checking if a certain file exists""" - - response = requests.head(url) - - try: - response.raise_for_status() - except requests.HTTPError as e: - response.close() - status = e.response.status_code - raise exceptions.DownloadHTTPError(str(e), status) - - return response def _fetch(self, url: str) -> Iterator[bytes]: """Fetches the contents of HTTP/HTTPS url from a remote server diff --git a/tuf/ngclient/fetcher.py b/tuf/ngclient/fetcher.py index ed0db8194b..f13c893420 100644 --- a/tuf/ngclient/fetcher.py +++ b/tuf/ngclient/fetcher.py @@ -30,11 +30,6 @@ class FetcherInterface: __metaclass__ = abc.ABCMeta - @abc.abstractmethod - def _look(self, url: str) -> str: - """Function used for checking if a certain file exists""" - raise NotImplementedError # pragma: no cover - @abc.abstractmethod def _fetch(self, url: str) -> Iterator[bytes]: """Fetches the contents of HTTP/HTTPS ``url`` from a remote server. diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 36a6d921bf..e8f45f2151 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -37,6 +37,7 @@ import os import shutil import tempfile +import json from typing import Optional, Set, List from urllib import parse @@ -139,6 +140,7 @@ def refresh(self) -> None: logger.warning(specver_message(1)) self.spec_version = specver_message(0) self._persist_metadata("spec_version", json.dumps(self.spec_version)) + self._load_root() self._load_timestamp() self._load_snapshot() @@ -147,32 +149,14 @@ def refresh(self) -> None: def _get_repository_versions(self) -> List[str]: """Returns a list of all the repository versions.""" - encoded_name = parse.quote("root", "") - url = f"{self._metadata_base_url}{self.spec_version}{encoded_name}.json" - repository_versions = [] - - # Here we manually enter the list of all possible versions that might exist on the - # repository side and then we check for each. Not an optimal solution. - for i in ["1", "2", "3"]: - try: - response = self._fetcher._look( - url.replace(self.spec_version, i) - ) # Can I call _look()? - if response.status_code == 200: - repository_versions.append(i) - except Exception as e: - # logger.debug(f"Could not get root metadata from {url.replace(self.spec_version, i)}") - continue - - # Acc to the TAP, repository metadata is supposed to be kept under a folder strucutre - # but that isn't being used here. So, that might be a way to go - - # repository_versions = ["3.0.0","4.0.0","5.0.0"] + url = f"{self._metadata_base_url}supported-versions.json" - # repository_versions = [i[0] for i in repository_versions] + with self._fetcher.download_file( + url, "length placeholder" + ) as target_file: + repository_versions = json.loads(target_file) - # return repository_versions - return ["1", "2", "3"] + return repository_versions["supported_versions"] def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: From 04231c17faf82487c62b228c138425bfdddf9f9d Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Fri, 2 Sep 2022 22:32:02 +0530 Subject: [PATCH 12/40] Worked on reviews Made changes to updater.py and config.py Signed-off-by: Abhisman Sarkar --- tuf/ngclient/config.py | 1 + tuf/ngclient/updater.py | 76 +++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 41 deletions(-) diff --git a/tuf/ngclient/config.py b/tuf/ngclient/config.py index e6213d0bed..9da831b5dd 100644 --- a/tuf/ngclient/config.py +++ b/tuf/ngclient/config.py @@ -28,6 +28,7 @@ class UpdaterConfig: max_root_rotations: int = 32 max_delegations: int = 32 + supported_versions_max_length: int = 1000 # bytes root_max_length: int = 512000 # bytes timestamp_max_length: int = 16384 # bytes snapshot_max_length: int = 2000000 # bytes diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index e8f45f2151..84f08320da 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -38,7 +38,7 @@ import shutil import tempfile import json -from typing import Optional, Set, List +from typing import Optional, Set, List, Tuple from urllib import parse from tuf.api import exceptions @@ -56,7 +56,7 @@ from tuf.ngclient.fetcher import FetcherInterface logger = logging.getLogger(__name__) -SUPPORTED_VERSIONS = ["1", "2", "3"] +SUPPORTED_VERSIONS = [SPECIFICATION_VERSION] class Updater: @@ -88,7 +88,7 @@ def __init__( fetcher: Optional[FetcherInterface] = None, config: Optional[UpdaterConfig] = None, ): - self.spec_version = None # spec_version is the last used version by the client to get metadata + self._spec_version = None # spec_version is the last used version by the client to get metadata self._dir = metadata_dir self._metadata_base_url = _ensure_trailing_slash(metadata_base_url) self.target_dir = target_dir @@ -132,14 +132,14 @@ def refresh(self) -> None: repository_versions = self._get_repository_versions() # Updating self.spec_version - specver_message = _get_spec_version( - repository_versions, self.spec_version, SUPPORTED_VERSIONS + spec_version, message = _get_spec_version( + repository_versions, self._spec_version, SUPPORTED_VERSIONS ) - if specver_message(1): - logger.warning(specver_message(1)) - self.spec_version = specver_message(0) - self._persist_metadata("spec_version", json.dumps(self.spec_version)) + if message: + logger.warning(message) + self.spec_version = f"{spec_version}/" if spec_version is not None else "" + self._persist_metadata("spec_version", json.dumps(self._spec_version)) self._load_root() self._load_timestamp() @@ -151,8 +151,8 @@ def _get_repository_versions(self) -> List[str]: url = f"{self._metadata_base_url}supported-versions.json" - with self._fetcher.download_file( - url, "length placeholder" + with self._fetcher.download_bytes( + url, self.config.supported_versions_max_length ) as target_file: repository_versions = json.loads(target_file) @@ -293,11 +293,10 @@ def _download_metadata( """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") - self.spec_version += ".0.0" if version is None: # THIS IS SNAPSHOT VERSION !! - url = f"{self._metadata_base_url}{self.spec_version}{encoded_name}.json" + url = f"{self._metadata_base_url}{self._spec_version}{encoded_name}.json" else: - url = f"{self._metadata_base_url}{self.spec_version}{version}.{encoded_name}.json" + url = f"{self._metadata_base_url}{self._spec_version}{version}.{encoded_name}.json" return self._fetcher.download_bytes(url, length) def _load_local_metadata(self, rolename: str) -> bytes: @@ -503,21 +502,6 @@ def _preorder_depth_first_walk( # If this point is reached then target is not found, return None return None - def _download_directory(self, folder: str) -> None: - # Downloading all metadata inside the specified folder - - path = ( - f"{BASE_URL}/repository_data/TAP 14" # File path to download from - ) - path = os.path.join(path, folder) # Add the folder to the path - - # Repository might be storing data in different formats. - - files = next(os.walk(path))[2] # Get all the files inside the list - for file in files: - if file.endswith(".json"): - self._download_metadata(file) - def _ensure_trailing_slash(url: str) -> str: """Return url guaranteed to end in a slash""" @@ -528,8 +512,17 @@ def _get_spec_version( repository_versions: List[str], spec_version: str, supported_versions: List[str], -) -> str: - """Returns the specification version to be used.""" +) -> Tuple[str, Optional[str]]: + """Returns the specification version to be used, following the rules of TAP-14 + and displays a warning if chosen spec_version is lower than the highest repository version. + + Raises: + ValueError: supported_versions, repository_version or spec_version contains an + invalid entry (not parseable as ``int()``) + RepositoryError: Latest repository version lower than the last used version from + this repository + RepositoryError: #TODO + """ repository_versions = [int(i) for i in repository_versions] supported_versions = [int(i) for i in supported_versions] @@ -537,33 +530,34 @@ def _get_spec_version( # The client determines the latest version available on the repository by looking # for the directory with the largest version number. - latestrep_ver = max(repository_versions) + latest_repo_version = max(repository_versions) # If the latest version on the repository is lower than the previous specification # version the client used from this repository, the client should report an error # and terminate the update. if spec_version: - if latestrep_ver < spec_version: - raise exceptions.DownloadError( - "The repository version is lower than the last used spec version" + if latest_repo_version < spec_version: + raise exceptions.RepositoryError( + f"The latest repository version ({latest_repo_version}) is lower than the last used spec version ({spec_version})." ) # If the latest version on the client is found on the repository or vice versa, the # client will use this directory to download the metadata. + # Checks for the highest matching version between the client and the repository + # and reports an error if no matching version is found. try: spec_version = max(set(repository_versions) & set(supported_versions)) except ValueError: - raise exceptions.DownloadError( - f"""No matching specification version found. Found {repository_versions} in - repository and {supported_versions} in client.""" + raise exceptions.RepositoryError( + f"No matching specification version found. Found {repository_versions} in" + f"repository and {supported_versions} in client." ) - # Checks for the highest matching version between the client and the repository - # and reports an error if no matching version is found. + # If the latest version on the repository is higher than the client spec version, # the client should report to the user that it is not using the most up to date version warning = None - if latestrep_ver > spec_version: + if latest_repo_version > spec_version: warning = "Not using the latest specification version available on the repository" return (str(spec_version), warning) From e3fda3d5c5f800fdd610928a96675fdffe6c4a02 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Fri, 2 Sep 2022 22:38:29 +0530 Subject: [PATCH 13/40] Used the black formatter on updater.py Signed-off-by: Abhisman Sarkar --- tuf/ngclient/updater.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 84f08320da..a77bb55909 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -138,7 +138,9 @@ def refresh(self) -> None: if message: logger.warning(message) - self.spec_version = f"{spec_version}/" if spec_version is not None else "" + self.spec_version = ( + f"{spec_version}/" if spec_version is not None else "" + ) self._persist_metadata("spec_version", json.dumps(self._spec_version)) self._load_root() @@ -513,15 +515,15 @@ def _get_spec_version( spec_version: str, supported_versions: List[str], ) -> Tuple[str, Optional[str]]: - """Returns the specification version to be used, following the rules of TAP-14 + """Returns the specification version to be used, following the rules of TAP-14 and displays a warning if chosen spec_version is lower than the highest repository version. - + Raises: - ValueError: supported_versions, repository_version or spec_version contains an + ValueError: supported_versions, repository_version or spec_version contains an invalid entry (not parseable as ``int()``) RepositoryError: Latest repository version lower than the last used version from this repository - RepositoryError: #TODO + RepositoryError: No matching version found between supported_versions and repository_versions """ repository_versions = [int(i) for i in repository_versions] @@ -553,7 +555,6 @@ def _get_spec_version( f"repository and {supported_versions} in client." ) - # If the latest version on the repository is higher than the client spec version, # the client should report to the user that it is not using the most up to date version warning = None From 5814a2c5422e7aa0cc129735109bca21b9613fb9 Mon Sep 17 00:00:00 2001 From: Abhisman Sarkar Date: Fri, 9 Sep 2022 09:52:53 +0530 Subject: [PATCH 14/40] Some more changes to updater.py and test_updater_ng.py Added some more changes adhering to the reviews. Also worked on cleaning the code in the test file. This is the last pull request as part of GSoC'22 Signed-off-by: Abhisman Sarkar --- tests/test_updater_ng.py | 84 +++++++++++++++++++++++++++++----------- tuf/ngclient/updater.py | 56 ++++++++++++++++++--------- 2 files changed, 99 insertions(+), 41 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index f8096fce0b..9e540dc412 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -355,9 +355,13 @@ def test_check_tap14_contents(self) -> None: os.path.isdir(os.path.join(self.tap14_directory, folder)) ) - def test_get_spec_version1(self) -> None: - # This uses the default SUPPORTED_VERSIONS variable from updater.py - with self.assertRaises(exceptions.DownloadError): + def test_get_spec_version_supported(self) -> None: + """This uses the default SUPPORTED_VERSIONS variable from updater.py""" + + with self.assertRaises( + exceptions.RepositoryError, + msg="Latest repository version less than 4", + ): _get_spec_version( ["1", "2", "3"], "4", ngclient.updater.SUPPORTED_VERSIONS ) @@ -367,29 +371,65 @@ def test_get_spec_version1(self) -> None: ["1", "2", "3"], "3", ngclient.updater.SUPPORTED_VERSIONS ), ("3", None), + "3 is selected as the spec version and no warning ensues", ) - def test_get_spec_version2(self) -> None: + def test_get_spec_version(self) -> None: warningchecker = "Not using the latest specification version available on the repository" # Checks with different values - with self.assertRaises(exceptions.DownloadError): - _get_spec_version(["3", "5", "6"], "7", ["1", "2", "3", "4"]) - - self.assertEqual( - _get_spec_version(["3", "5", "6"], "3", ["1", "2", "3", "4"]), - ("3", warningchecker), - ) - self.assertEqual( - _get_spec_version(["1", "2", "3"], "3", ["3", "5", "6"]), - ("3", None), - ) - self.assertEqual( - _get_spec_version(["8", "11", "13"], "12", ["8", "11", "12"]), - ("11", warningchecker), - ) - - with self.assertRaises(exceptions.DownloadError): - _get_spec_version(["3", "5", "6"], "3", ["1", "2", "4"]) + test_cases = [ + ( + ["3", "5", "6"], + "7", + ["1", "2", "3", "4"], + ), # Latest repository version less than 7 + ( + ["3", "5", "6"], + "3", + ["1", "2", "4"], + ), # No common specification version between repository and client + ] + for repo_versions, spec_version, supported_versions in test_cases: + with self.assertRaises(exceptions.RepositoryError): + _get_spec_version( + repo_versions, spec_version, supported_versions + ) + + test_cases = [ + ( + ["3", "5", "6"], + "3", + ["1", "2", "3", "4"], + "3", + True, + ), # 3 is selected as the spec version but a warning ensues + ( + ["1", "2", "3"], + "3", + ["3", "5", "6"], + "3", + False, + ), # 3 is selected as the spec version and no warning ensues + ( + ["8", "11", "13"], + "12", + ["8", "11", "12"], + "11", + True, + ), # 11 is selected as the spec version but a warning ensues + ] + for ( + repo_versions, + spec_version, + supported_versions, + expected_version, + should_have_warning, + ) in test_cases: + actual_version, warning = _get_spec_version( + repo_versions, spec_version, supported_versions + ) + self.assertEqual(actual_version, expected_version) + self.assertEqual(bool(warning), should_have_warning) # TODO Testing logging functionality. # with self.assertLogs(ngclient.updater.__name__) as cm: diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index a77bb55909..12165e84ab 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -38,7 +38,7 @@ import shutil import tempfile import json -from typing import Optional, Set, List, Tuple +from typing import Optional, Set, List, Tuple, NewType from urllib import parse from tuf.api import exceptions @@ -126,9 +126,11 @@ def refresh(self) -> None: RepositoryError: Metadata failed to verify in some way DownloadError: Download of a metadata file failed in some way """ - # json.load() - # Load self.spec_version using self._load_local_metadata() here from disk - # Exception would be raised if spec_version is not found locally. Set to "1" in that case + try: + self._spec_version = self._load_local_metadata("spec_version") + except OSError: + self._spec_version = "1" + repository_versions = self._get_repository_versions() # Updating self.spec_version @@ -138,10 +140,14 @@ def refresh(self) -> None: if message: logger.warning(message) - self.spec_version = ( - f"{spec_version}/" if spec_version is not None else "" + self._spec_version = ( + f"{spec_version}/" + if spec_version is not None or spec_version == "1" + else "" + ) + self._persist_metadata( + "spec_version", json.dumps(self._spec_version) ) - self._persist_metadata("spec_version", json.dumps(self._spec_version)) self._load_root() self._load_timestamp() @@ -151,14 +157,18 @@ def refresh(self) -> None: def _get_repository_versions(self) -> List[str]: """Returns a list of all the repository versions.""" - url = f"{self._metadata_base_url}supported-versions.json" + try: + url = f"{self._metadata_base_url}supported-versions.json" - with self._fetcher.download_bytes( - url, self.config.supported_versions_max_length - ) as target_file: - repository_versions = json.loads(target_file) + with self._fetcher.download_bytes( + url, self.config.supported_versions_max_length + ) as target_file: + repository_versions = json.loads(target_file) + return repository_versions["supported_versions"] - return repository_versions["supported_versions"] + # If supported-versions.json is not found, then look through the root directory to find supported versions + except exceptions.DownloadHTTPError as e: + return ["1"] def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: @@ -295,6 +305,7 @@ def _download_metadata( """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") + # TODO Seperate URL for when snapshot-version.json doesn't exist if version is None: # THIS IS SNAPSHOT VERSION !! url = f"{self._metadata_base_url}{self._spec_version}{encoded_name}.json" else: @@ -525,6 +536,8 @@ def _get_spec_version( this repository RepositoryError: No matching version found between supported_versions and repository_versions """ + SpecificationVersion = NewType("SpecificationVersion", str) + WarningMessage = NewType("WarningMessage", str) repository_versions = [int(i) for i in repository_versions] supported_versions = [int(i) for i in supported_versions] @@ -543,10 +556,17 @@ def _get_spec_version( f"The latest repository version ({latest_repo_version}) is lower than the last used spec version ({spec_version})." ) - # If the latest version on the client is found on the repository or vice versa, the - # client will use this directory to download the metadata. - # Checks for the highest matching version between the client and the repository - # and reports an error if no matching version is found. + # If the latest version on the repository is equal to that of the client, it will use this directory to download metadata. + + # If the latest version pre-dates the client specification version, it may call functions from a previous client version + # to download the metadata. The client may support as many or as few versions as desired for the application. If the + # previous version is not available, the client shall report that an update can not be performed due to an old + # specification version on the repository. + + # If the latest version on the repository is higher than the client spec version, the client should report + # to the user that it is not using the most up to date version, and then perform the update with the directory + # that corresponds with the latest client specification version, if available. If no such directory exists, + # the client terminates the update. try: spec_version = max(set(repository_versions) & set(supported_versions)) except ValueError: @@ -555,8 +575,6 @@ def _get_spec_version( f"repository and {supported_versions} in client." ) - # If the latest version on the repository is higher than the client spec version, - # the client should report to the user that it is not using the most up to date version warning = None if latest_repo_version > spec_version: warning = "Not using the latest specification version available on the repository" From cf3d41ceddc6904c12e82f217f001997c4fe3b66 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 13:43:56 -0400 Subject: [PATCH 15/40] Rename TAP 14 directory 1.0.0 -> 1 Signed-off-by: Marina Moore --- tests/repository_data/TAP 14/{1.0.0 => 1}/1.root.json | 0 tests/repository_data/TAP 14/{1.0.0 => 1}/role1.json | 0 tests/repository_data/TAP 14/{1.0.0 => 1}/role2.json | 0 tests/repository_data/TAP 14/{1.0.0 => 1}/root.json | 0 tests/repository_data/TAP 14/{1.0.0 => 1}/snapshot.json | 0 tests/repository_data/TAP 14/{1.0.0 => 1}/targets.json | 0 tests/repository_data/TAP 14/{1.0.0 => 1}/timestamp.json | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename tests/repository_data/TAP 14/{1.0.0 => 1}/1.root.json (100%) rename tests/repository_data/TAP 14/{1.0.0 => 1}/role1.json (100%) rename tests/repository_data/TAP 14/{1.0.0 => 1}/role2.json (100%) rename tests/repository_data/TAP 14/{1.0.0 => 1}/root.json (100%) rename tests/repository_data/TAP 14/{1.0.0 => 1}/snapshot.json (100%) rename tests/repository_data/TAP 14/{1.0.0 => 1}/targets.json (100%) rename tests/repository_data/TAP 14/{1.0.0 => 1}/timestamp.json (100%) diff --git a/tests/repository_data/TAP 14/1.0.0/1.root.json b/tests/repository_data/TAP 14/1/1.root.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/1.root.json rename to tests/repository_data/TAP 14/1/1.root.json diff --git a/tests/repository_data/TAP 14/1.0.0/role1.json b/tests/repository_data/TAP 14/1/role1.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/role1.json rename to tests/repository_data/TAP 14/1/role1.json diff --git a/tests/repository_data/TAP 14/1.0.0/role2.json b/tests/repository_data/TAP 14/1/role2.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/role2.json rename to tests/repository_data/TAP 14/1/role2.json diff --git a/tests/repository_data/TAP 14/1.0.0/root.json b/tests/repository_data/TAP 14/1/root.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/root.json rename to tests/repository_data/TAP 14/1/root.json diff --git a/tests/repository_data/TAP 14/1.0.0/snapshot.json b/tests/repository_data/TAP 14/1/snapshot.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/snapshot.json rename to tests/repository_data/TAP 14/1/snapshot.json diff --git a/tests/repository_data/TAP 14/1.0.0/targets.json b/tests/repository_data/TAP 14/1/targets.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/targets.json rename to tests/repository_data/TAP 14/1/targets.json diff --git a/tests/repository_data/TAP 14/1.0.0/timestamp.json b/tests/repository_data/TAP 14/1/timestamp.json similarity index 100% rename from tests/repository_data/TAP 14/1.0.0/timestamp.json rename to tests/repository_data/TAP 14/1/timestamp.json From e0ddd4a82185cc2b1e3b747ef6c17d69aa7292e0 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 13:46:37 -0400 Subject: [PATCH 16/40] TAP 14 fix tests Signed-off-by: Marina Moore --- tests/repository_simulator.py | 4 +++ tests/test_updater_consistent_snapshot.py | 2 ++ tests/test_updater_delegation_graphs.py | 18 +++++------ tests/test_updater_ng.py | 14 +++++---- tests/test_updater_top_level_update.py | 6 ++-- tuf/ngclient/updater.py | 38 ++++++++++++++--------- 6 files changed, 51 insertions(+), 31 deletions(-) diff --git a/tests/repository_simulator.py b/tests/repository_simulator.py index abb7f37141..ebdcd2bc06 100644 --- a/tests/repository_simulator.py +++ b/tests/repository_simulator.py @@ -205,10 +205,14 @@ def _fetch(self, url: str) -> Iterator[bytes]: if path.startswith("/metadata/") and path.endswith(".json"): # figure out rolename and version ver_and_name = path[len("/metadata/") :][: -len(".json")] + # inside a version folder + if "/" in ver_and_name: + ver_and_name = ver_and_name.split("/")[1] version_str, _, role = ver_and_name.partition(".") # root is always version-prefixed while timestamp is always NOT if role == Root.type or ( self.root.consistent_snapshot and ver_and_name != Timestamp.type + and ver_and_name != "supported-versions" ): version: Optional[int] = int(version_str) else: diff --git a/tests/test_updater_consistent_snapshot.py b/tests/test_updater_consistent_snapshot.py index e4bab8a8c7..0a3880e4d5 100644 --- a/tests/test_updater_consistent_snapshot.py +++ b/tests/test_updater_consistent_snapshot.py @@ -104,6 +104,7 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: "consistent_snaphot disabled": { "consistent_snapshot": False, "calls": [ + ('supported-versions', None), ("root", 3), ("timestamp", None), ("snapshot", None), @@ -113,6 +114,7 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: "consistent_snaphot enabled": { "consistent_snapshot": True, "calls": [ + ('supported-versions', None), ("root", 3), ("timestamp", None), ("snapshot", 1), diff --git a/tests/test_updater_delegation_graphs.py b/tests/test_updater_delegation_graphs.py index ca04621da0..062c8c6313 100644 --- a/tests/test_updater_delegation_graphs.py +++ b/tests/test_updater_delegation_graphs.py @@ -134,7 +134,7 @@ def _assert_files_exist(self, roles: Iterable[str]) -> None: """Assert that local metadata files exist for 'roles'""" expected_files = sorted([f"{role}.json" for role in roles]) local_metadata_files = sorted(os.listdir(self.metadata_dir)) - self.assertListEqual(local_metadata_files, expected_files) + self.assertEqual(expected_files, local_metadata_files) class TestDelegationsGraphs(TestDelegations): @@ -263,7 +263,7 @@ def test_graph_traversal(self, test_data: DelegationsTestCase) -> None: in the delegator's metadata, using pre-order depth-first search""" try: - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order] + exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order, "spec_version"] exp_calls = [(role, 1) for role in test_data.visited_order] self._init_repo(test_data) @@ -276,7 +276,7 @@ def test_graph_traversal(self, test_data: DelegationsTestCase) -> None: updater.refresh() self.sim.fetch_tracker.metadata.clear() # Check that metadata dir contains only top-level roles - self._assert_files_exist(TOP_LEVEL_ROLE_NAMES) + self._assert_files_exist([*TOP_LEVEL_ROLE_NAMES, "spec_version"]) # Looking for a non-existing targetpath forces updater # to visit all possible delegated roles @@ -311,7 +311,7 @@ def test_invalid_metadata(self, test_data: DelegationsTestCase) -> None: self.setup_subtest() # The invalid role metadata must not be persisted - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order[:-1]] + exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order[:-1], "spec_version"] exp_calls = [(role, 1) for role in test_data.visited_order] updater = self._init_updater() @@ -397,7 +397,7 @@ def test_hash_bins_graph_traversal( they correctly reffer to the corresponding hash bin prefixes""" try: - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order] + exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order, "spec_version"] exp_calls = [(role, 1) for role in test_data.visited_order] self._init_repo(test_data) @@ -408,7 +408,7 @@ def test_hash_bins_graph_traversal( updater.refresh() self.sim.fetch_tracker.metadata.clear() # Check that metadata dir contains only top-level roles - self._assert_files_exist(TOP_LEVEL_ROLE_NAMES) + self._assert_files_exist([*TOP_LEVEL_ROLE_NAMES, "spec_version"]) # Looking for a non-existing targetpath forces updater # to visit a correspondning delegated role @@ -481,7 +481,7 @@ def test_succinct_roles_graph_traversal( # bin should exist locally and only one bin must be downloaded. try: - exp_files = [*TOP_LEVEL_ROLE_NAMES, test_data.expected_target_bin] + exp_files = [*TOP_LEVEL_ROLE_NAMES, test_data.expected_target_bin, "spec_version"] exp_calls = [(test_data.expected_target_bin, 1)] self.sim = RepositorySimulator() @@ -495,7 +495,7 @@ def test_succinct_roles_graph_traversal( updater.refresh() self.sim.fetch_tracker.metadata.clear() # Check that metadata dir contains only top-level roles - self._assert_files_exist(TOP_LEVEL_ROLE_NAMES) + self._assert_files_exist([*TOP_LEVEL_ROLE_NAMES, "spec_version"]) # Looking for a non-existing targetpath forces updater # to visit a corresponding delegated role. @@ -564,7 +564,7 @@ def setUp(self) -> None: def test_targetfile_search(self, test_data: TargetTestCase) -> None: try: self.setup_subtest() - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order] + exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order, "spec_version"] exp_calls = [(role, 1) for role in test_data.visited_order] exp_target = self.sim.target_files[test_data.targetpath].target_file diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 9e540dc412..475dfa9cad 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -174,14 +174,14 @@ def test_refresh_and_download(self) -> None: # top-level metadata is in local directory already self.updater.refresh() self._assert_files( - [Root.type, Snapshot.type, Targets.type, Timestamp.type] + [Root.type, Snapshot.type, "spec_version", Targets.type, Timestamp.type] ) # Get targetinfos, assert that cache does not contain files info1 = self.updater.get_targetinfo("file1.txt") assert isinstance(info1, TargetFile) self._assert_files( - [Root.type, Snapshot.type, Targets.type, Timestamp.type] + [Root.type, Snapshot.type, "spec_version", Targets.type, Timestamp.type] ) # Get targetinfo for 'file3.txt' listed in the delegated role1 @@ -191,6 +191,7 @@ def test_refresh_and_download(self) -> None: "role1", Root.type, Snapshot.type, + "spec_version", Targets.type, Timestamp.type, ] @@ -221,7 +222,7 @@ def test_refresh_with_only_local_root(self) -> None: self.updater.refresh() self._assert_files( - [Root.type, Snapshot.type, Targets.type, Timestamp.type] + [Root.type, Snapshot.type, "spec_version", Targets.type, Timestamp.type] ) # Get targetinfo for 'file3.txt' listed in the delegated role1 @@ -230,6 +231,7 @@ def test_refresh_with_only_local_root(self) -> None: "role1", Root.type, Snapshot.type, + "spec_version", Targets.type, Timestamp.type, ] @@ -246,7 +248,7 @@ def test_implicit_refresh_with_only_local_root(self) -> None: # Get targetinfo for 'file3.txt' listed in the delegated role1 self.updater.get_targetinfo("file3.txt") - expected_files = ["role1", "root", "snapshot", "targets", "timestamp"] + expected_files = ["role1", "root", "snapshot", "spec_version", "targets", "timestamp"] self._assert_files(expected_files) def test_both_target_urls_not_set(self) -> None: @@ -349,7 +351,7 @@ def test_check_tap14_contents(self) -> None: ) # Checking specific folders inside TAP 14 - foldernames = ["targets", "1.0.0"] + foldernames = ["targets", "1"] for folder in foldernames: self.assertTrue( os.path.isdir(os.path.join(self.tap14_directory, folder)) @@ -368,7 +370,7 @@ def test_get_spec_version_supported(self) -> None: self.assertEqual( _get_spec_version( - ["1", "2", "3"], "3", ngclient.updater.SUPPORTED_VERSIONS + ["1", "2", "3"], "3", [3] ), ("3", None), "3 is selected as the spec version and no warning ensues", diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index be6ce09d27..303884cac2 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -103,7 +103,8 @@ def _assert_files_exist(self, roles: Iterable[str]) -> None: """Assert that local metadata files exist for 'roles'""" expected_files = sorted([f"{role}.json" for role in roles]) local_metadata_files = sorted(os.listdir(self.metadata_dir)) - self.assertListEqual(local_metadata_files, expected_files) + for e in expected_files: + self.assertTrue(e in local_metadata_files) def _assert_content_equals( self, role: str, version: Optional[int] = None @@ -730,6 +731,7 @@ def test_load_metadata_from_cache(self, wrapped_open: MagicMock) -> None: wrapped_open.assert_has_calls( [ call(os.path.join(self.metadata_dir, "root.json"), "rb"), + call(os.path.join(self.metadata_dir, "spec_version.json"), "rb"), call(os.path.join(self.metadata_dir, "timestamp.json"), "rb"), call(os.path.join(self.metadata_dir, "snapshot.json"), "rb"), call(os.path.join(self.metadata_dir, "targets.json"), "rb"), @@ -737,7 +739,7 @@ def test_load_metadata_from_cache(self, wrapped_open: MagicMock) -> None: ] ) - expected_calls = [("root", 2), ("timestamp", None)] + expected_calls = [("supported-versions", None), ("root", 2), ("timestamp", None)] self.assertListEqual(self.sim.fetch_tracker.metadata, expected_calls) @patch.object(datetime, "datetime", wraps=datetime.datetime) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 12165e84ab..0379853709 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -33,6 +33,7 @@ `_. """ +import errno import logging import os import shutil @@ -56,7 +57,8 @@ from tuf.ngclient.fetcher import FetcherInterface logger = logging.getLogger(__name__) -SUPPORTED_VERSIONS = [SPECIFICATION_VERSION] +# only include the major version +SUPPORTED_VERSIONS = [SPECIFICATION_VERSION[0]] class Updater: @@ -127,8 +129,12 @@ def refresh(self) -> None: DownloadError: Download of a metadata file failed in some way """ try: - self._spec_version = self._load_local_metadata("spec_version") - except OSError: + version_bytes = self._load_local_metadata("spec_version") + self._spec_version = json.loads(version_bytes.decode('utf-8'))["version"] + + except OSError as e: + if e.errno != errno.ENOENT: + raise self._spec_version = "1" repository_versions = self._get_repository_versions() @@ -140,13 +146,10 @@ def refresh(self) -> None: if message: logger.warning(message) - self._spec_version = ( - f"{spec_version}/" - if spec_version is not None or spec_version == "1" - else "" - ) + self._spec_version = spec_version + self._persist_metadata( - "spec_version", json.dumps(self._spec_version) + "spec_version", json.dumps({"version": self._spec_version}).encode('utf-8') ) self._load_root() @@ -166,9 +169,12 @@ def _get_repository_versions(self) -> List[str]: repository_versions = json.loads(target_file) return repository_versions["supported_versions"] - # If supported-versions.json is not found, then look through the root directory to find supported versions + # If supported-versions.json is not found, then default to version 1 except exceptions.DownloadHTTPError as e: - return ["1"] + if e.status_code == 404: + return ["1"] + else: + raise def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: @@ -305,11 +311,15 @@ def _download_metadata( """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") - # TODO Seperate URL for when snapshot-version.json doesn't exist + if self._spec_version is None or self._spec_version == "1": + spec_folder = "" + else: + spec_folder = f"{self._spec_version}/" + if version is None: # THIS IS SNAPSHOT VERSION !! - url = f"{self._metadata_base_url}{self._spec_version}{encoded_name}.json" + url = f"{self._metadata_base_url}{spec_folder}{encoded_name}.json" else: - url = f"{self._metadata_base_url}{self._spec_version}{version}.{encoded_name}.json" + url = f"{self._metadata_base_url}{spec_folder}{version}.{encoded_name}.json" return self._fetcher.download_bytes(url, length) def _load_local_metadata(self, rolename: str) -> bytes: From 3c7be68c9b00fd200978d0345f59a3435ead8925 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 14:05:12 -0400 Subject: [PATCH 17/40] fix lint Signed-off-by: Marina Moore --- tests/repository_simulator.py | 3 +- tests/test_updater_consistent_snapshot.py | 4 +-- tests/test_updater_delegation_graphs.py | 30 +++++++++++++++--- tests/test_updater_ng.py | 37 ++++++++++++++++++----- tests/test_updater_top_level_update.py | 10 ++++-- tuf/ngclient/updater.py | 7 +++-- 6 files changed, 72 insertions(+), 19 deletions(-) diff --git a/tests/repository_simulator.py b/tests/repository_simulator.py index ebdcd2bc06..3f8d6f5643 100644 --- a/tests/repository_simulator.py +++ b/tests/repository_simulator.py @@ -211,7 +211,8 @@ def _fetch(self, url: str) -> Iterator[bytes]: version_str, _, role = ver_and_name.partition(".") # root is always version-prefixed while timestamp is always NOT if role == Root.type or ( - self.root.consistent_snapshot and ver_and_name != Timestamp.type + self.root.consistent_snapshot + and ver_and_name != Timestamp.type and ver_and_name != "supported-versions" ): version: Optional[int] = int(version_str) diff --git a/tests/test_updater_consistent_snapshot.py b/tests/test_updater_consistent_snapshot.py index 0a3880e4d5..49d099cd80 100644 --- a/tests/test_updater_consistent_snapshot.py +++ b/tests/test_updater_consistent_snapshot.py @@ -104,7 +104,7 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: "consistent_snaphot disabled": { "consistent_snapshot": False, "calls": [ - ('supported-versions', None), + ("supported-versions", None), ("root", 3), ("timestamp", None), ("snapshot", None), @@ -114,7 +114,7 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: "consistent_snaphot enabled": { "consistent_snapshot": True, "calls": [ - ('supported-versions', None), + ("supported-versions", None), ("root", 3), ("timestamp", None), ("snapshot", 1), diff --git a/tests/test_updater_delegation_graphs.py b/tests/test_updater_delegation_graphs.py index 062c8c6313..664a726ec6 100644 --- a/tests/test_updater_delegation_graphs.py +++ b/tests/test_updater_delegation_graphs.py @@ -263,7 +263,11 @@ def test_graph_traversal(self, test_data: DelegationsTestCase) -> None: in the delegator's metadata, using pre-order depth-first search""" try: - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order, "spec_version"] + exp_files = [ + *TOP_LEVEL_ROLE_NAMES, + *test_data.visited_order, + "spec_version", + ] exp_calls = [(role, 1) for role in test_data.visited_order] self._init_repo(test_data) @@ -311,7 +315,11 @@ def test_invalid_metadata(self, test_data: DelegationsTestCase) -> None: self.setup_subtest() # The invalid role metadata must not be persisted - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order[:-1], "spec_version"] + exp_files = [ + *TOP_LEVEL_ROLE_NAMES, + *test_data.visited_order[:-1], + "spec_version", + ] exp_calls = [(role, 1) for role in test_data.visited_order] updater = self._init_updater() @@ -397,7 +405,11 @@ def test_hash_bins_graph_traversal( they correctly reffer to the corresponding hash bin prefixes""" try: - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order, "spec_version"] + exp_files = [ + *TOP_LEVEL_ROLE_NAMES, + *test_data.visited_order, + "spec_version", + ] exp_calls = [(role, 1) for role in test_data.visited_order] self._init_repo(test_data) @@ -481,7 +493,11 @@ def test_succinct_roles_graph_traversal( # bin should exist locally and only one bin must be downloaded. try: - exp_files = [*TOP_LEVEL_ROLE_NAMES, test_data.expected_target_bin, "spec_version"] + exp_files = [ + *TOP_LEVEL_ROLE_NAMES, + test_data.expected_target_bin, + "spec_version", + ] exp_calls = [(test_data.expected_target_bin, 1)] self.sim = RepositorySimulator() @@ -564,7 +580,11 @@ def setUp(self) -> None: def test_targetfile_search(self, test_data: TargetTestCase) -> None: try: self.setup_subtest() - exp_files = [*TOP_LEVEL_ROLE_NAMES, *test_data.visited_order, "spec_version"] + exp_files = [ + *TOP_LEVEL_ROLE_NAMES, + *test_data.visited_order, + "spec_version", + ] exp_calls = [(role, 1) for role in test_data.visited_order] exp_target = self.sim.target_files[test_data.targetpath].target_file diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 475dfa9cad..fb4f9d8a33 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -174,14 +174,26 @@ def test_refresh_and_download(self) -> None: # top-level metadata is in local directory already self.updater.refresh() self._assert_files( - [Root.type, Snapshot.type, "spec_version", Targets.type, Timestamp.type] + [ + Root.type, + Snapshot.type, + "spec_version", + Targets.type, + Timestamp.type, + ] ) # Get targetinfos, assert that cache does not contain files info1 = self.updater.get_targetinfo("file1.txt") assert isinstance(info1, TargetFile) self._assert_files( - [Root.type, Snapshot.type, "spec_version", Targets.type, Timestamp.type] + [ + Root.type, + Snapshot.type, + "spec_version", + Targets.type, + Timestamp.type, + ] ) # Get targetinfo for 'file3.txt' listed in the delegated role1 @@ -222,7 +234,13 @@ def test_refresh_with_only_local_root(self) -> None: self.updater.refresh() self._assert_files( - [Root.type, Snapshot.type, "spec_version", Targets.type, Timestamp.type] + [ + Root.type, + Snapshot.type, + "spec_version", + Targets.type, + Timestamp.type, + ] ) # Get targetinfo for 'file3.txt' listed in the delegated role1 @@ -248,7 +266,14 @@ def test_implicit_refresh_with_only_local_root(self) -> None: # Get targetinfo for 'file3.txt' listed in the delegated role1 self.updater.get_targetinfo("file3.txt") - expected_files = ["role1", "root", "snapshot", "spec_version", "targets", "timestamp"] + expected_files = [ + "role1", + "root", + "snapshot", + "spec_version", + "targets", + "timestamp", + ] self._assert_files(expected_files) def test_both_target_urls_not_set(self) -> None: @@ -369,9 +394,7 @@ def test_get_spec_version_supported(self) -> None: ) self.assertEqual( - _get_spec_version( - ["1", "2", "3"], "3", [3] - ), + _get_spec_version(["1", "2", "3"], "3", [3]), ("3", None), "3 is selected as the spec version and no warning ensues", ) diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index 303884cac2..b572fa8cae 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -731,7 +731,9 @@ def test_load_metadata_from_cache(self, wrapped_open: MagicMock) -> None: wrapped_open.assert_has_calls( [ call(os.path.join(self.metadata_dir, "root.json"), "rb"), - call(os.path.join(self.metadata_dir, "spec_version.json"), "rb"), + call( + os.path.join(self.metadata_dir, "spec_version.json"), "rb" + ), call(os.path.join(self.metadata_dir, "timestamp.json"), "rb"), call(os.path.join(self.metadata_dir, "snapshot.json"), "rb"), call(os.path.join(self.metadata_dir, "targets.json"), "rb"), @@ -739,7 +741,11 @@ def test_load_metadata_from_cache(self, wrapped_open: MagicMock) -> None: ] ) - expected_calls = [("supported-versions", None), ("root", 2), ("timestamp", None)] + expected_calls = [ + ("supported-versions", None), + ("root", 2), + ("timestamp", None), + ] self.assertListEqual(self.sim.fetch_tracker.metadata, expected_calls) @patch.object(datetime, "datetime", wraps=datetime.datetime) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 0379853709..6e967931cd 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -130,7 +130,9 @@ def refresh(self) -> None: """ try: version_bytes = self._load_local_metadata("spec_version") - self._spec_version = json.loads(version_bytes.decode('utf-8'))["version"] + self._spec_version = json.loads(version_bytes.decode("utf-8"))[ + "version" + ] except OSError as e: if e.errno != errno.ENOENT: @@ -149,7 +151,8 @@ def refresh(self) -> None: self._spec_version = spec_version self._persist_metadata( - "spec_version", json.dumps({"version": self._spec_version}).encode('utf-8') + "spec_version", + json.dumps({"version": self._spec_version}).encode("utf-8"), ) self._load_root() From 78f5bfcce676141ea8fa14be64aeea775a5ba5ea Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 14:07:08 -0400 Subject: [PATCH 18/40] fix isort Signed-off-by: Marina Moore --- tuf/ngclient/updater.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 6e967931cd..bc31b2711d 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -34,12 +34,12 @@ """ import errno +import json import logging import os import shutil import tempfile -import json -from typing import Optional, Set, List, Tuple, NewType +from typing import List, NewType, Optional, Set, Tuple from urllib import parse from tuf.api import exceptions From d3b14938be98639e6239effb13553f4d9ee75771 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 14:12:31 -0400 Subject: [PATCH 19/40] fix style issues Signed-off-by: Marina Moore --- tuf/ngclient/updater.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index bc31b2711d..b6db8cc475 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -176,8 +176,7 @@ def _get_repository_versions(self) -> List[str]: except exceptions.DownloadHTTPError as e: if e.status_code == 404: return ["1"] - else: - raise + raise def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: @@ -549,9 +548,6 @@ def _get_spec_version( this repository RepositoryError: No matching version found between supported_versions and repository_versions """ - SpecificationVersion = NewType("SpecificationVersion", str) - WarningMessage = NewType("WarningMessage", str) - repository_versions = [int(i) for i in repository_versions] supported_versions = [int(i) for i in supported_versions] spec_version = int(spec_version) From d65640b9012e9779d654eb1c64b3c740f7235ff2 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 14:22:05 -0400 Subject: [PATCH 20/40] fix lint warnings Signed-off-by: Marina Moore --- tuf/ngclient/config.py | 1 + tuf/ngclient/updater.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tuf/ngclient/config.py b/tuf/ngclient/config.py index 9da831b5dd..c308ac71d5 100644 --- a/tuf/ngclient/config.py +++ b/tuf/ngclient/config.py @@ -8,6 +8,7 @@ @dataclass +# pylint: disable=too-many-instance-attributes class UpdaterConfig: """Used to store ``Updater`` configuration. diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index b6db8cc475..91798dc2a0 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -39,7 +39,7 @@ import os import shutil import tempfile -from typing import List, NewType, Optional, Set, Tuple +from typing import List, Optional, Set, Tuple from urllib import parse from tuf.api import exceptions @@ -81,6 +81,7 @@ class Updater: RepositoryError: Local root.json is invalid """ + # pylint: disable=too-many-instance-attributes def __init__( self, metadata_dir: str, From 250740d28c426b90f01180d117b2bf01bfc06218 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 15:58:34 -0400 Subject: [PATCH 21/40] Add TAP 14 integration tests Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 85 ++++++++++++++++++++++++++++++++++++++++ tuf/ngclient/updater.py | 11 +++--- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index fb4f9d8a33..a7ea70b6fe 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -6,6 +6,7 @@ """Test Updater class """ +import json import logging import os import shutil @@ -17,6 +18,8 @@ from securesystemslib.interface import import_rsa_privatekey_from_file from securesystemslib.signer import SSlibSigner +from securesystemslib.storage import FilesystemBackend +from securesystemslib.util import persist_temp_file from tests import utils from tuf import ngclient @@ -461,6 +464,88 @@ def test_get_spec_version(self) -> None: # logging.getLogger('foo').info('first message') # self.updater._get_spec_version(["3","5","6"],"3",["1","2","3","4"]) + def test_spec_version_increase(self) -> None: + # switch repository supported versions + repo_version_path = os.path.join( + self.repository_directory, "metadata", "supported-versions.json" + ) + repo_version_json = json.dumps({"supported_versions": [2]}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(repo_version_json.encode('utf-8')) + persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + + # switch client supported versions + self.updater._supported_versions = ["2"] + + # copy the current metadata to 2/ + shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + + self.updater.refresh() + self.assertEqual(self.updater._spec_version, "2") + + def test_spec_version_overlap(self) -> None: + # repository supports version 2 and 3 + repo_version_path = os.path.join( + self.repository_directory, "metadata", "supported-versions.json" + ) + repo_version_json = json.dumps({"supported_versions": [2, 3]}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(repo_version_json.encode('utf-8')) + persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + + # client supports version 1 and 2 + self.updater._supported_versions = ["1", "2"] + + # copy the current metadata to 2/ + shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + + self.updater.refresh() + self.assertEqual(self.updater._spec_version, "2") + # TODO assert that higher repo version available warning was logged + + + def test_tap14_backwards_compat(self) -> None: + # copy the current metadata to 2/ + shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + + # add supported-versions.json + repo_version_path = os.path.join( + self.repository_directory, "metadata", "supported-versions.json" + ) + repo_version_json = json.dumps({"supported_versions": [1]}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(repo_version_json.encode('utf-8')) + persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + + self.updater.refresh() + + def test_spec_version_rollback(self) -> None: + # set _spec_version to 2 + client_spec_version_path = os.path.join(self.client_directory, "spec_version.json") + client_spec_version_json = json.dumps({"version": 2}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(client_spec_version_json.encode('utf-8')) + persist_temp_file(temp_file, client_spec_version_path, FilesystemBackend()) + + # but supported-versions only contains 1 + # add supported-versions.json + repo_version_path = os.path.join( + self.repository_directory, "metadata", "supported-versions.json" + ) + repo_version_json = json.dumps({"supported_versions": [1]}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(repo_version_json.encode('utf-8')) + persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + + self.assertEqual(self.updater._supported_versions, ["1"]) + + with self.assertRaises(exceptions.RepositoryError): + self.updater.refresh() + + + + + if __name__ == "__main__": utils.configure_test_logging(sys.argv) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 91798dc2a0..1f595150bb 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -105,6 +105,7 @@ def __init__( self._trusted_set = trusted_metadata_set.TrustedMetadataSet(data) self._fetcher = fetcher or requests_fetcher.RequestsFetcher() self.config = config or UpdaterConfig() + self._supported_versions = SUPPORTED_VERSIONS def refresh(self) -> None: """Refreshes top-level metadata. @@ -144,7 +145,7 @@ def refresh(self) -> None: # Updating self.spec_version spec_version, message = _get_spec_version( - repository_versions, self._spec_version, SUPPORTED_VERSIONS + repository_versions, self._spec_version, self._supported_versions ) if message: @@ -167,11 +168,9 @@ def _get_repository_versions(self) -> List[str]: try: url = f"{self._metadata_base_url}supported-versions.json" - with self._fetcher.download_bytes( - url, self.config.supported_versions_max_length - ) as target_file: - repository_versions = json.loads(target_file) - return repository_versions["supported_versions"] + target_bytes = self._fetcher.download_bytes(url, self.config.supported_versions_max_length) + repository_versions = json.loads(target_bytes) + return repository_versions["supported_versions"] # If supported-versions.json is not found, then default to version 1 except exceptions.DownloadHTTPError as e: From 1e7da4c89e4028715ea2eeef799369b0026ffd76 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 16:30:21 -0400 Subject: [PATCH 22/40] Update supported-versions.json to match TAP Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 8 ++++---- tuf/ngclient/updater.py | 21 +++++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index a7ea70b6fe..b536da8227 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -469,7 +469,7 @@ def test_spec_version_increase(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [2]}) + repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}]}) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode('utf-8')) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) @@ -488,7 +488,7 @@ def test_spec_version_overlap(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [2, 3]}) + repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}, {"version": 3, "path": "3"}]}) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode('utf-8')) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) @@ -512,7 +512,7 @@ def test_tap14_backwards_compat(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [1]}) + repo_version_json = json.dumps({"supported_versions": [{"version": 1, "path": ""}]}) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode('utf-8')) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) @@ -532,7 +532,7 @@ def test_spec_version_rollback(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [1]}) + repo_version_json = json.dumps({"supported_versions": [{"version": 1, "path": ""}]}) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode('utf-8')) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 1f595150bb..72a78870bc 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -92,6 +92,7 @@ def __init__( config: Optional[UpdaterConfig] = None, ): self._spec_version = None # spec_version is the last used version by the client to get metadata + self._spec_version_dir = "" self._dir = metadata_dir self._metadata_base_url = _ensure_trailing_slash(metadata_base_url) self.target_dir = target_dir @@ -141,7 +142,10 @@ def refresh(self) -> None: raise self._spec_version = "1" - repository_versions = self._get_repository_versions() + repository_versions_and_paths = self._get_repository_versions() + + print(repository_versions_and_paths) + repository_versions = [i["version"] for i in repository_versions_and_paths] # Updating self.spec_version spec_version, message = _get_spec_version( @@ -152,9 +156,14 @@ def refresh(self) -> None: logger.warning(message) self._spec_version = spec_version + for i in repository_versions_and_paths: + if i["version"] == spec_version: + self._spec_version_dir = i["path"] + + # persist the version number self._persist_metadata( "spec_version", - json.dumps({"version": self._spec_version}).encode("utf-8"), + json.dumps({"version": spec_version}).encode("utf-8"), ) self._load_root() @@ -163,7 +172,7 @@ def refresh(self) -> None: self._load_targets(Targets.type, Root.type) def _get_repository_versions(self) -> List[str]: - """Returns a list of all the repository versions.""" + """Returns a list of all the repository versions and paths.""" try: url = f"{self._metadata_base_url}supported-versions.json" @@ -175,7 +184,7 @@ def _get_repository_versions(self) -> List[str]: # If supported-versions.json is not found, then default to version 1 except exceptions.DownloadHTTPError as e: if e.status_code == 404: - return ["1"] + return [{"version":1, "path": ""}] raise def _generate_target_file_path(self, targetinfo: TargetFile) -> str: @@ -313,10 +322,10 @@ def _download_metadata( """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") - if self._spec_version is None or self._spec_version == "1": + if self._spec_version_dir is "": spec_folder = "" else: - spec_folder = f"{self._spec_version}/" + spec_folder = f"{self._spec_version_dir}/" if version is None: # THIS IS SNAPSHOT VERSION !! url = f"{self._metadata_base_url}{spec_folder}{encoded_name}.json" From 2842d059fc8d94ac791da7623520cd7d4671fde3 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 17:20:08 -0400 Subject: [PATCH 23/40] add tap 14 root update order Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 43 +++++++++++++++++++++++++++++++++ tuf/ngclient/updater.py | 51 ++++++++++++++++++++++++++-------------- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index b536da8227..e42cecb294 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -543,7 +543,50 @@ def test_spec_version_rollback(self) -> None: self.updater.refresh() + def test_spec_version_root_update_order(self) -> None: + # copy the current metadata to 2/ + shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + # update root not in 2/ + self._modify_repository_root(lambda root: None, bump_version=True) + + # switch repository supported versions + repo_version_path = os.path.join( + self.repository_directory, "metadata", "supported-versions.json" + ) + repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}]}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(repo_version_json.encode('utf-8')) + persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + + # switch client supported versions + self.updater._supported_versions = ["2"] + + self.updater.refresh() + # it should not find version 2 of root as it is missing from 2/ + self.assertEqual(self.updater._trusted_set.root.signed.version, 1) + + def test_spec_version_root_update(self) -> None: + # update root + self._modify_repository_root(lambda root: None, bump_version=True) + + # copy the current metadata to 2/ + shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + + # switch repository supported versions + repo_version_path = os.path.join( + self.repository_directory, "metadata", "supported-versions.json" + ) + repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}]}) + with tempfile.TemporaryFile() as temp_file: + temp_file.write(repo_version_json.encode('utf-8')) + persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + + # switch client supported versions + self.updater._supported_versions = ["2"] + + self.updater.refresh() + self.assertEqual(self.updater._trusted_set.root.signed.version, 2) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 72a78870bc..c36ce1e4c2 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -144,7 +144,6 @@ def refresh(self) -> None: repository_versions_and_paths = self._get_repository_versions() - print(repository_versions_and_paths) repository_versions = [i["version"] for i in repository_versions_and_paths] # Updating self.spec_version @@ -156,6 +155,12 @@ def refresh(self) -> None: logger.warning(message) self._spec_version = spec_version + ordered_version_paths = [] + for version in sorted(repository_versions): + path = list(filter(lambda a: a["version"] == version and version <= int(spec_version), repository_versions_and_paths)) + if len(path) > 0: + ordered_version_paths.append(path[0]["path"]) + for i in repository_versions_and_paths: if i["version"] == spec_version: self._spec_version_dir = i["path"] @@ -166,7 +171,7 @@ def refresh(self) -> None: json.dumps({"version": spec_version}).encode("utf-8"), ) - self._load_root() + self._load_root(ordered_version_paths) self._load_timestamp() self._load_snapshot() self._load_targets(Targets.type, Root.type) @@ -361,7 +366,7 @@ def _persist_metadata(self, rolename: str, data: bytes) -> None: pass raise e - def _load_root(self) -> None: + def _load_root(self, supported_version_repos) -> None: """Load remote root metadata. Sequentially load and persist on local disk every newer root metadata @@ -372,21 +377,33 @@ def _load_root(self) -> None: lower_bound = self._trusted_set.root.signed.version + 1 upper_bound = lower_bound + self.config.max_root_rotations + save_repo_version_dir = self._spec_version_dir + for next_version in range(lower_bound, upper_bound): - try: - data = self._download_metadata( - Root.type, - self.config.root_max_length, - next_version, - ) - self._trusted_set.update_root(data) - self._persist_metadata(Root.type, data) - - except exceptions.DownloadHTTPError as exception: - if exception.status_code not in {403, 404}: - raise - # 404/403 means current root is newest available - break + for version_repo in supported_version_repos: + to_break = True + self._spec_version_dir = version_repo + try: + data = self._download_metadata( + Root.type, + self.config.root_max_length, + next_version, + ) + self._trusted_set.update_root(data) + self._persist_metadata(Root.type, data) + # if found, don't check older supported versions + to_break = False + break + + except exceptions.DownloadHTTPError as exception: + if exception.status_code not in {403, 404}: + raise + # 404/403 means current root is newest available + if to_break: + self._spec_version_dir = save_repo_version_dir + return + + self._spec_version_dir = save_repo_version_dir def _load_timestamp(self) -> None: """Load local and remote timestamp metadata""" From 08b0c2364f41525a9025f5433a9b186ad498b0a2 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 17:22:13 -0400 Subject: [PATCH 24/40] fix lint Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 81 ++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index e42cecb294..d905e54e22 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -469,16 +469,21 @@ def test_spec_version_increase(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}]}) + repo_version_json = json.dumps( + {"supported_versions": [{"version": 2, "path": "2"}]} + ) with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode('utf-8')) + temp_file.write(repo_version_json.encode("utf-8")) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) # switch client supported versions self.updater._supported_versions = ["2"] # copy the current metadata to 2/ - shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "2"), + ) self.updater.refresh() self.assertEqual(self.updater._spec_version, "2") @@ -488,64 +493,86 @@ def test_spec_version_overlap(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}, {"version": 3, "path": "3"}]}) + repo_version_json = json.dumps( + { + "supported_versions": [ + {"version": 2, "path": "2"}, + {"version": 3, "path": "3"}, + ] + } + ) with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode('utf-8')) + temp_file.write(repo_version_json.encode("utf-8")) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) # client supports version 1 and 2 self.updater._supported_versions = ["1", "2"] # copy the current metadata to 2/ - shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "2"), + ) self.updater.refresh() self.assertEqual(self.updater._spec_version, "2") # TODO assert that higher repo version available warning was logged - def test_tap14_backwards_compat(self) -> None: # copy the current metadata to 2/ - shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "2"), + ) # add supported-versions.json repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [{"version": 1, "path": ""}]}) + repo_version_json = json.dumps( + {"supported_versions": [{"version": 1, "path": ""}]} + ) with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode('utf-8')) + temp_file.write(repo_version_json.encode("utf-8")) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) self.updater.refresh() def test_spec_version_rollback(self) -> None: # set _spec_version to 2 - client_spec_version_path = os.path.join(self.client_directory, "spec_version.json") + client_spec_version_path = os.path.join( + self.client_directory, "spec_version.json" + ) client_spec_version_json = json.dumps({"version": 2}) with tempfile.TemporaryFile() as temp_file: - temp_file.write(client_spec_version_json.encode('utf-8')) - persist_temp_file(temp_file, client_spec_version_path, FilesystemBackend()) + temp_file.write(client_spec_version_json.encode("utf-8")) + persist_temp_file( + temp_file, client_spec_version_path, FilesystemBackend() + ) # but supported-versions only contains 1 # add supported-versions.json repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [{"version": 1, "path": ""}]}) + repo_version_json = json.dumps( + {"supported_versions": [{"version": 1, "path": ""}]} + ) with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode('utf-8')) + temp_file.write(repo_version_json.encode("utf-8")) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) self.assertEqual(self.updater._supported_versions, ["1"]) with self.assertRaises(exceptions.RepositoryError): - self.updater.refresh() - + self.updater.refresh() def test_spec_version_root_update_order(self) -> None: # copy the current metadata to 2/ - shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "2"), + ) # update root not in 2/ self._modify_repository_root(lambda root: None, bump_version=True) @@ -554,9 +581,11 @@ def test_spec_version_root_update_order(self) -> None: repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}]}) + repo_version_json = json.dumps( + {"supported_versions": [{"version": 2, "path": "2"}]} + ) with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode('utf-8')) + temp_file.write(repo_version_json.encode("utf-8")) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) # switch client supported versions @@ -571,15 +600,20 @@ def test_spec_version_root_update(self) -> None: self._modify_repository_root(lambda root: None, bump_version=True) # copy the current metadata to 2/ - shutil.copytree(os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2")) + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "2"), + ) # switch repository supported versions repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) - repo_version_json = json.dumps({"supported_versions": [{"version": 2, "path": "2"}]}) + repo_version_json = json.dumps( + {"supported_versions": [{"version": 2, "path": "2"}]} + ) with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode('utf-8')) + temp_file.write(repo_version_json.encode("utf-8")) persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) # switch client supported versions @@ -589,7 +623,6 @@ def test_spec_version_root_update(self) -> None: self.assertEqual(self.updater._trusted_set.root.signed.version, 2) - if __name__ == "__main__": utils.configure_test_logging(sys.argv) unittest.main() From fa75d78f7f9ec537ffe1013f7d812c7def56e0a1 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 17:23:34 -0400 Subject: [PATCH 25/40] fix lint Signed-off-by: Marina Moore --- tuf/ngclient/updater.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index c36ce1e4c2..322729e3db 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -144,7 +144,9 @@ def refresh(self) -> None: repository_versions_and_paths = self._get_repository_versions() - repository_versions = [i["version"] for i in repository_versions_and_paths] + repository_versions = [ + i["version"] for i in repository_versions_and_paths + ] # Updating self.spec_version spec_version, message = _get_spec_version( @@ -157,7 +159,13 @@ def refresh(self) -> None: ordered_version_paths = [] for version in sorted(repository_versions): - path = list(filter(lambda a: a["version"] == version and version <= int(spec_version), repository_versions_and_paths)) + path = list( + filter( + lambda a: a["version"] == version + and version <= int(spec_version), + repository_versions_and_paths, + ) + ) if len(path) > 0: ordered_version_paths.append(path[0]["path"]) @@ -182,14 +190,16 @@ def _get_repository_versions(self) -> List[str]: try: url = f"{self._metadata_base_url}supported-versions.json" - target_bytes = self._fetcher.download_bytes(url, self.config.supported_versions_max_length) + target_bytes = self._fetcher.download_bytes( + url, self.config.supported_versions_max_length + ) repository_versions = json.loads(target_bytes) return repository_versions["supported_versions"] # If supported-versions.json is not found, then default to version 1 except exceptions.DownloadHTTPError as e: if e.status_code == 404: - return [{"version":1, "path": ""}] + return [{"version": 1, "path": ""}] raise def _generate_target_file_path(self, targetinfo: TargetFile) -> str: From fd3d4d7115b095f2de9a40c696da2636eed5f724 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 17:34:55 -0400 Subject: [PATCH 26/40] fix pylint errors Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 4 ++-- tuf/ngclient/updater.py | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index d905e54e22..97b9266590 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -36,7 +36,7 @@ logger = logging.getLogger(__name__) - +# pylint: disable=too-many-public-methods class TestUpdater(unittest.TestCase): """Test the Updater class from 'tuf/ngclient/updater.py'.""" @@ -403,7 +403,7 @@ def test_get_spec_version_supported(self) -> None: ) def test_get_spec_version(self) -> None: - warningchecker = "Not using the latest specification version available on the repository" + # warningchecker = "Not using the latest specification version available on the repository" # Checks with different values test_cases = [ ( diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 322729e3db..e55652ab83 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -158,11 +158,13 @@ def refresh(self) -> None: self._spec_version = spec_version ordered_version_paths = [] + filter_fn = lambda a: a["version"] == version and version <= int( + spec_version + ) for version in sorted(repository_versions): path = list( filter( - lambda a: a["version"] == version - and version <= int(spec_version), + filter_fn, repository_versions_and_paths, ) ) @@ -337,7 +339,7 @@ def _download_metadata( """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") - if self._spec_version_dir is "": + if self._spec_version_dir == "": spec_folder = "" else: spec_folder = f"{self._spec_version_dir}/" @@ -614,11 +616,11 @@ def _get_spec_version( # the client terminates the update. try: spec_version = max(set(repository_versions) & set(supported_versions)) - except ValueError: + except ValueError as e: raise exceptions.RepositoryError( f"No matching specification version found. Found {repository_versions} in" f"repository and {supported_versions} in client." - ) + ) from e warning = None if latest_repo_version > spec_version: From 2d6847cb9dbea0ea5b2c72ff4bab2ae1ac202030 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Thu, 22 Sep 2022 17:38:11 -0400 Subject: [PATCH 27/40] lint Signed-off-by: Marina Moore --- tuf/ngclient/updater.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index e55652ab83..162dfe7579 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -158,9 +158,10 @@ def refresh(self) -> None: self._spec_version = spec_version ordered_version_paths = [] - filter_fn = lambda a: a["version"] == version and version <= int( - spec_version - ) + + def filter_fn(a): + return a["version"] == version and version <= int(spec_version) + for version in sorted(repository_versions): path = list( filter( From 851b2d65b4d25460ca63308bc1dfd7458213d6be Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Fri, 23 Sep 2022 13:36:40 -0400 Subject: [PATCH 28/40] clean up tests Signed-off-by: Marina Moore --- tests/repository_data/TAP 14/1.root.json | 87 ------------------- tests/repository_data/TAP 14/1/1.root.json | 87 ------------------- tests/repository_data/TAP 14/1/role1.json | 49 ----------- tests/repository_data/TAP 14/1/role2.json | 15 ---- tests/repository_data/TAP 14/1/root.json | 87 ------------------- tests/repository_data/TAP 14/1/snapshot.json | 25 ------ tests/repository_data/TAP 14/1/targets.json | 61 ------------- tests/repository_data/TAP 14/1/timestamp.json | 23 ----- .../repository_data/TAP 14/2.0.0/1.root.json | 87 ------------------- tests/repository_data/TAP 14/2.0.0/role1.json | 49 ----------- tests/repository_data/TAP 14/2.0.0/role2.json | 15 ---- tests/repository_data/TAP 14/2.0.0/root.json | 87 ------------------- .../TAP 14/2.0.0/snapshot.json | 25 ------ .../repository_data/TAP 14/2.0.0/targets.json | 61 ------------- .../TAP 14/2.0.0/timestamp.json | 23 ----- tests/repository_data/TAP 14/role1.json | 49 ----------- tests/repository_data/TAP 14/role2.json | 15 ---- tests/repository_data/TAP 14/root.json | 87 ------------------- tests/repository_data/TAP 14/snapshot.json | 25 ------ tests/repository_data/TAP 14/targets.json | 61 ------------- .../repository_data/TAP 14/targets/file1.txt | 1 - .../repository_data/TAP 14/targets/file2.txt | 1 - .../repository_data/TAP 14/targets/file3.txt | 1 - tests/repository_data/TAP 14/timestamp.json | 23 ----- tests/test_updater_ng.py | 28 ------ 25 files changed, 1072 deletions(-) delete mode 100644 tests/repository_data/TAP 14/1.root.json delete mode 100644 tests/repository_data/TAP 14/1/1.root.json delete mode 100644 tests/repository_data/TAP 14/1/role1.json delete mode 100644 tests/repository_data/TAP 14/1/role2.json delete mode 100644 tests/repository_data/TAP 14/1/root.json delete mode 100644 tests/repository_data/TAP 14/1/snapshot.json delete mode 100644 tests/repository_data/TAP 14/1/targets.json delete mode 100644 tests/repository_data/TAP 14/1/timestamp.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/1.root.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/role1.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/role2.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/root.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/snapshot.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/targets.json delete mode 100644 tests/repository_data/TAP 14/2.0.0/timestamp.json delete mode 100644 tests/repository_data/TAP 14/role1.json delete mode 100644 tests/repository_data/TAP 14/role2.json delete mode 100644 tests/repository_data/TAP 14/root.json delete mode 100644 tests/repository_data/TAP 14/snapshot.json delete mode 100644 tests/repository_data/TAP 14/targets.json delete mode 100644 tests/repository_data/TAP 14/targets/file1.txt delete mode 100644 tests/repository_data/TAP 14/targets/file2.txt delete mode 100644 tests/repository_data/TAP 14/targets/file3.txt delete mode 100644 tests/repository_data/TAP 14/timestamp.json diff --git a/tests/repository_data/TAP 14/1.root.json b/tests/repository_data/TAP 14/1.root.json deleted file mode 100644 index 214d8db01b..0000000000 --- a/tests/repository_data/TAP 14/1.root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/1.root.json b/tests/repository_data/TAP 14/1/1.root.json deleted file mode 100644 index 214d8db01b..0000000000 --- a/tests/repository_data/TAP 14/1/1.root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/role1.json b/tests/repository_data/TAP 14/1/role1.json deleted file mode 100644 index 0ac4687e77..0000000000 --- a/tests/repository_data/TAP 14/1/role1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role2", - "paths": [], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": { - "file3.txt": { - "hashes": { - "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", - "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" - }, - "length": 28 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/role2.json b/tests/repository_data/TAP 14/1/role2.json deleted file mode 100644 index 9c49e16570..0000000000 --- a/tests/repository_data/TAP 14/1/role2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" - } - ], - "signed": { - "_type": "targets", - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": {}, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/root.json b/tests/repository_data/TAP 14/1/root.json deleted file mode 100644 index 214d8db01b..0000000000 --- a/tests/repository_data/TAP 14/1/root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/snapshot.json b/tests/repository_data/TAP 14/1/snapshot.json deleted file mode 100644 index 7c8c091a2e..0000000000 --- a/tests/repository_data/TAP 14/1/snapshot.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "signatures": [ - { - "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", - "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" - } - ], - "signed": { - "_type": "snapshot", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "role1.json": { - "version": 1 - }, - "role2.json": { - "version": 1 - }, - "targets.json": { - "version": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/targets.json b/tests/repository_data/TAP 14/1/targets.json deleted file mode 100644 index 8e21c269b4..0000000000 --- a/tests/repository_data/TAP 14/1/targets.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "signatures": [ - { - "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", - "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role1", - "paths": [ - "file3.txt" - ], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": { - "file1.txt": { - "custom": { - "file_permissions": "0644" - }, - "hashes": { - "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", - "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" - }, - "length": 31 - }, - "file2.txt": { - "hashes": { - "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", - "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" - }, - "length": 39 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/1/timestamp.json b/tests/repository_data/TAP 14/1/timestamp.json deleted file mode 100644 index 9a0daf078b..0000000000 --- a/tests/repository_data/TAP 14/1/timestamp.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "signatures": [ - { - "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", - "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" - } - ], - "signed": { - "_type": "timestamp", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "snapshot.json": { - "hashes": { - "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" - }, - "length": 515, - "version": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/1.root.json b/tests/repository_data/TAP 14/2.0.0/1.root.json deleted file mode 100644 index 25595b3f38..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/1.root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/role1.json b/tests/repository_data/TAP 14/2.0.0/role1.json deleted file mode 100644 index 66ec049d73..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/role1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role2", - "paths": [], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", - "targets": { - "file3.txt": { - "hashes": { - "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", - "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" - }, - "length": 28 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/role2.json b/tests/repository_data/TAP 14/2.0.0/role2.json deleted file mode 100644 index 9c49e16570..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/role2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" - } - ], - "signed": { - "_type": "targets", - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": {}, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/root.json b/tests/repository_data/TAP 14/2.0.0/root.json deleted file mode 100644 index 25595b3f38..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/snapshot.json b/tests/repository_data/TAP 14/2.0.0/snapshot.json deleted file mode 100644 index 51aa78a5a6..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/snapshot.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "signatures": [ - { - "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", - "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" - } - ], - "signed": { - "_type": "snapshot", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "role1.json": { - "version": 1 - }, - "role2.json": { - "version": 1 - }, - "targets.json": { - "version": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/targets.json b/tests/repository_data/TAP 14/2.0.0/targets.json deleted file mode 100644 index 9517c048d0..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/targets.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "signatures": [ - { - "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", - "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role1", - "paths": [ - "file3.txt" - ], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "2.0.0", - "targets": { - "file1.txt": { - "custom": { - "file_permissions": "0644" - }, - "hashes": { - "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", - "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" - }, - "length": 31 - }, - "file2.txt": { - "hashes": { - "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", - "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" - }, - "length": 39 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/2.0.0/timestamp.json b/tests/repository_data/TAP 14/2.0.0/timestamp.json deleted file mode 100644 index 9d38e7c7ed..0000000000 --- a/tests/repository_data/TAP 14/2.0.0/timestamp.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "signatures": [ - { - "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", - "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" - } - ], - "signed": { - "_type": "timestamp", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "snapshot.json": { - "hashes": { - "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" - }, - "length": 515, - "version": 1 - } - }, - "spec_version": "2.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/role1.json b/tests/repository_data/TAP 14/role1.json deleted file mode 100644 index 0ac4687e77..0000000000 --- a/tests/repository_data/TAP 14/role1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "9408b46569e622a46f1d35d9fa3c10e17a9285631ced4f2c9c2bba2c2842413fcb796db4e81d6f988fc056c21c407fdc3c10441592cf1e837e088f2e2dfd5403" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role2", - "paths": [], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": { - "file3.txt": { - "hashes": { - "sha256": "141f740f53781d1ca54b8a50af22cbf74e44c21a998fa2a8a05aaac2c002886b", - "sha512": "ef5beafa16041bcdd2937140afebd485296cd54f7348ecd5a4d035c09759608de467a7ac0eb58753d0242df873c305e8bffad2454aa48f44480f15efae1cacd0" - }, - "length": 28 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/role2.json b/tests/repository_data/TAP 14/role2.json deleted file mode 100644 index 9c49e16570..0000000000 --- a/tests/repository_data/TAP 14/role2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "signatures": [ - { - "keyid": "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a", - "sig": "75b196a224fd200e46e738b1216b3316c5384f61083872f8d14b8b0a378b2344e64b1a6f1a89a711206a66a0b199d65ac0e30fe15ddbc4de89fa8ff645f99403" - } - ], - "signed": { - "_type": "targets", - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": {}, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/root.json b/tests/repository_data/TAP 14/root.json deleted file mode 100644 index 214d8db01b..0000000000 --- a/tests/repository_data/TAP 14/root.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "signatures": [ - { - "keyid": "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb", - "sig": "a337d6375fedd2eabfcd6c2ef6c8a9c3bb85dc5a857715f6a6bd41123e7670c4972d8548bcd7248154f3d864bf25f1823af59d74c459f41ea09a02db057ca1245612ebbdb97e782c501dc3e094f7fa8aa1402b03c6ed0635f565e2a26f9f543a89237e15a2faf0c267e2b34c3c38f2a43a28ddcdaf8308a12ead8c6dc47d1b762de313e9ddda8cc5bc25aea1b69d0e5b9199ca02f5dda48c3bff615fd12a7136d00634b9abc6e75c3256106c4d6f12e6c43f6195071355b2857bbe377ce028619b58837696b805040ce144b393d50a472531f430fadfb68d3081b6a8b5e49337e328c9a0a3f11e80b0bc8eb2dc6e78d1451dd857e6e6e6363c3fd14c590aa95e083c9bfc77724d78af86eb7a7ef635eeddaa353030c79f66b3ba9ea11fab456cfe896a826fdfb50a43cd444f762821aada9bcd7b022c0ee85b8768f960343d5a1d3d76374cc0ac9e12a500de0bf5d48569e5398cadadadab045931c398e3bcb6cec88af2437ba91959f956079cbed159fed3938016e6c3b5e446131f81cc5981" - } - ], - "signed": { - "_type": "root", - "consistent_snapshot": false, - "expires": "2030-01-01T00:00:00Z", - "keys": { - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "rsa", - "keyval": { - "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0GjPoVrjS9eCqzoQ8VRe\nPkC0cI6ktiEgqPfHESFzyxyjC490Cuy19nuxPcJuZfN64MC48oOkR+W2mq4pM51i\nxmdG5xjvNOBRkJ5wUCc8fDCltMUTBlqt9y5eLsf/4/EoBU+zC4SW1iPU++mCsity\nfQQ7U6LOn3EYCyrkH51hZ/dvKC4o9TPYMVxNecJ3CL1q02Q145JlyjBTuM3Xdqsa\nndTHoXSRPmmzgB/1dL/c4QjMnCowrKW06mFLq9RAYGIaJWfM/0CbrOJpVDkATmEc\nMdpGJYDfW/sRQvRdlHNPo24ZW7vkQUCqdRxvnTWkK5U81y7RtjLt1yskbWXBIbOV\nz94GXsgyzANyCT9qRjHXDDz2mkLq+9I2iKtEqaEePcWRu3H6RLahpM/TxFzw684Y\nR47weXdDecPNxWyiWiyMGStRFP4Cg9trcwAGnEm1w8R2ggmWphznCd5dXGhPNjfA\na82yNFY8ubnOUVJOf0nXGg3Edw9iY3xyjJb2+nrsk5f3AgMBAAE=\n-----END PUBLIC KEY-----" - }, - "scheme": "rsassa-pss-sha256" - }, - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" - }, - "scheme": "ed25519" - }, - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "89f28bd4ede5ec3786ab923fd154f39588d20881903e69c7b08fb504c6750815" - }, - "scheme": "ed25519" - }, - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "82ccf6ac47298ff43bfa0cd639868894e305a99c723ff0515ae2e9856eb5bbf4" - }, - "scheme": "ed25519" - } - }, - "roles": { - "root": { - "keyids": [ - "4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb" - ], - "threshold": 1 - }, - "snapshot": { - "keyids": [ - "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d" - ], - "threshold": 1 - }, - "targets": { - "keyids": [ - "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093" - ], - "threshold": 1 - }, - "timestamp": { - "keyids": [ - "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758" - ], - "threshold": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/snapshot.json b/tests/repository_data/TAP 14/snapshot.json deleted file mode 100644 index 7c8c091a2e..0000000000 --- a/tests/repository_data/TAP 14/snapshot.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "signatures": [ - { - "keyid": "59a4df8af818e9ed7abe0764c0b47b4240952aa0d179b5b78346c470ac30278d", - "sig": "085672c70dffe26610e58542ee552843633cfed973abdad94c56138dbf0cd991644f2d3f27e4dda3098e08ab676e7f52627b587947ae69db1012d59a6da18e0c" - } - ], - "signed": { - "_type": "snapshot", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "role1.json": { - "version": 1 - }, - "role2.json": { - "version": 1 - }, - "targets.json": { - "version": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets.json b/tests/repository_data/TAP 14/targets.json deleted file mode 100644 index 8e21c269b4..0000000000 --- a/tests/repository_data/TAP 14/targets.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "signatures": [ - { - "keyid": "65171251a9aff5a8b3143a813481cb07f6e0de4eb197c767837fe4491b739093", - "sig": "d65f8db0c1a8f0976552b9742bbb393f24a5fa5eaf145c37aee047236c79dd0b83cfbb8b49fa7803689dfe0031dcf22c4d006b593acac07d69093b9b81722c08" - } - ], - "signed": { - "_type": "targets", - "delegations": { - "keys": { - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": { - "keyid_hash_algorithms": [ - "sha256", - "sha512" - ], - "keytype": "ed25519", - "keyval": { - "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9" - }, - "scheme": "ed25519" - } - }, - "roles": [ - { - "keyids": [ - "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a" - ], - "name": "role1", - "paths": [ - "file3.txt" - ], - "terminating": false, - "threshold": 1 - } - ] - }, - "expires": "2030-01-01T00:00:00Z", - "spec_version": "1.0.0", - "targets": { - "file1.txt": { - "custom": { - "file_permissions": "0644" - }, - "hashes": { - "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da", - "sha512": "467430a68afae8e9f9c0771ea5d78bf0b3a0d79a2d3d3b40c69fde4dd42c461448aef76fcef4f5284931a1ffd0ac096d138ba3a0d6ca83fa8d7285a47a296f77" - }, - "length": 31 - }, - "file2.txt": { - "hashes": { - "sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99", - "sha512": "052b49a21e03606b28942db69aa597530fe52d47ee3d748ba65afcd14b857738e36bc1714c4f4adde46c3e683548552fe5c96722e0e0da3acd9050c2524902d8" - }, - "length": 39 - } - }, - "version": 1 - } -} \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets/file1.txt b/tests/repository_data/TAP 14/targets/file1.txt deleted file mode 100644 index 7bf3499f13..0000000000 --- a/tests/repository_data/TAP 14/targets/file1.txt +++ /dev/null @@ -1 +0,0 @@ -This is an example target file. \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets/file2.txt b/tests/repository_data/TAP 14/targets/file2.txt deleted file mode 100644 index 606f18efc8..0000000000 --- a/tests/repository_data/TAP 14/targets/file2.txt +++ /dev/null @@ -1 +0,0 @@ -This is an another example target file. \ No newline at end of file diff --git a/tests/repository_data/TAP 14/targets/file3.txt b/tests/repository_data/TAP 14/targets/file3.txt deleted file mode 100644 index 60464604aa..0000000000 --- a/tests/repository_data/TAP 14/targets/file3.txt +++ /dev/null @@ -1 +0,0 @@ -This is role1's target file. \ No newline at end of file diff --git a/tests/repository_data/TAP 14/timestamp.json b/tests/repository_data/TAP 14/timestamp.json deleted file mode 100644 index 9a0daf078b..0000000000 --- a/tests/repository_data/TAP 14/timestamp.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "signatures": [ - { - "keyid": "8a1c4a3ac2d515dec982ba9910c5fd79b91ae57f625b9cff25d06bf0a61c1758", - "sig": "de0e16920f87bf5500cc65736488ac17e09788cce808f6a4e85eb9e4e478a312b4c1a2d7723af56f7bfb1df533c67d8c93b6f49d39eabe7fae391a08e1f72f01" - } - ], - "signed": { - "_type": "timestamp", - "expires": "2030-01-01T00:00:00Z", - "meta": { - "snapshot.json": { - "hashes": { - "sha256": "8f88e2ba48b412c3843e9bb26e1b6f8fc9e98aceb0fbaa97ba37b4c98717d7ab" - }, - "length": 515, - "version": 1 - } - }, - "spec_version": "1.0.0", - "version": 1 - } -} \ No newline at end of file diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 97b9266590..b9a5f93d7b 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -83,8 +83,6 @@ def setUp(self) -> None: "metadata", "current", ) - # Adding the TAP14 folder - original_tap14 = os.path.join(original_repository_files, "TAP 14") # Save references to the often-needed client repository directories. # Test cases need these references to access metadata and target files. @@ -93,16 +91,12 @@ def setUp(self) -> None: ) self.keystore_directory = os.path.join(self.tmp_test_dir, "keystore") self.client_directory = os.path.join(self.tmp_test_dir, "client") - # Adding the TAP14 folder - self.tap14_directory = os.path.join(self.tmp_test_dir, "TAP 14") # Copy the original 'repository', 'client', and 'keystore' directories # to the temporary repository the test cases can use. shutil.copytree(original_repository, self.repository_directory) shutil.copytree(original_client, self.client_directory) shutil.copytree(original_keystore, self.keystore_directory) - # Copying over the TAP 14 folder - shutil.copytree(original_tap14, self.tap14_directory) # 'path/to/tmp/repository' -> 'localhost:8001/tmp/repository'. repository_basepath = self.repository_directory[len(os.getcwd()) :] @@ -363,28 +357,6 @@ def test_non_existing_target_file(self) -> None: with self.assertRaises(exceptions.DownloadHTTPError): self.updater.download_target(info) - # TAP 14 tests ~ REMOVE COMMENT BEFORE THE NEXT COMMIT!! - - # test case to check for the TAP 14 folder - def test_check_folder_tap14(self) -> None: - # Creating the parent folder for the TAP 14 folder - self.assertTrue(os.path.isdir(self.tap14_directory)) - - def test_check_tap14_contents(self) -> None: - # Checking specific files inside TAP 14 - filenames = ["targets.json", "root.json"] - for file in filenames: - self.assertTrue( - os.path.isfile(os.path.join(self.tap14_directory, file)) - ) - - # Checking specific folders inside TAP 14 - foldernames = ["targets", "1"] - for folder in foldernames: - self.assertTrue( - os.path.isdir(os.path.join(self.tap14_directory, folder)) - ) - def test_get_spec_version_supported(self) -> None: """This uses the default SUPPORTED_VERSIONS variable from updater.py""" From 76567c66fd540e097786a5e50b4c2884a1b9ca61 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Tue, 27 Sep 2022 14:57:43 -0400 Subject: [PATCH 29/40] simplify and refactor spec version checks Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 13 ++++++++----- tuf/ngclient/updater.py | 38 ++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index b9a5f93d7b..73c3817638 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -442,7 +442,7 @@ def test_spec_version_increase(self) -> None: self.repository_directory, "metadata", "supported-versions.json" ) repo_version_json = json.dumps( - {"supported_versions": [{"version": 2, "path": "2"}]} + {"supported_versions": [{"version": 2, "path": "2/"}]} ) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode("utf-8")) @@ -468,8 +468,8 @@ def test_spec_version_overlap(self) -> None: repo_version_json = json.dumps( { "supported_versions": [ - {"version": 2, "path": "2"}, - {"version": 3, "path": "3"}, + {"version": 2, "path": "2/"}, + {"version": 3, "path": "3/"}, ] } ) @@ -554,7 +554,7 @@ def test_spec_version_root_update_order(self) -> None: self.repository_directory, "metadata", "supported-versions.json" ) repo_version_json = json.dumps( - {"supported_versions": [{"version": 2, "path": "2"}]} + {"supported_versions": [{"version": 2, "path": "2/"}]} ) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode("utf-8")) @@ -577,12 +577,15 @@ def test_spec_version_root_update(self) -> None: os.path.join(self.repository_directory, "metadata", "2"), ) + # update root outside of 2/ **this should be ignored** + self._modify_repository_root(lambda root: None, bump_version=True) + # switch repository supported versions repo_version_path = os.path.join( self.repository_directory, "metadata", "supported-versions.json" ) repo_version_json = json.dumps( - {"supported_versions": [{"version": 2, "path": "2"}]} + {"supported_versions": [{"version": 2, "path": "2/"}]} ) with tempfile.TemporaryFile() as temp_file: temp_file.write(repo_version_json.encode("utf-8")) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 162dfe7579..7df1fe13f9 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -131,6 +131,14 @@ def refresh(self) -> None: RepositoryError: Metadata failed to verify in some way DownloadError: Download of a metadata file failed in some way """ + ordered_version_paths = self._set_spec_version() + + self._load_root(ordered_version_paths) + self._load_timestamp() + self._load_snapshot() + self._load_targets(Targets.type, Root.type) + + def _set_spec_version(self) -> List[str]: try: version_bytes = self._load_local_metadata("spec_version") self._spec_version = json.loads(version_bytes.decode("utf-8"))[ @@ -159,18 +167,12 @@ def refresh(self) -> None: ordered_version_paths = [] - def filter_fn(a): - return a["version"] == version and version <= int(spec_version) - for version in sorted(repository_versions): - path = list( - filter( - filter_fn, - repository_versions_and_paths, - ) - ) + path = [i["path"] for i in repository_versions_and_paths if version <= int(spec_version) and i["version"] == version] + + # found this version if len(path) > 0: - ordered_version_paths.append(path[0]["path"]) + ordered_version_paths.append(path[0]) for i in repository_versions_and_paths: if i["version"] == spec_version: @@ -182,12 +184,10 @@ def filter_fn(a): json.dumps({"version": spec_version}).encode("utf-8"), ) - self._load_root(ordered_version_paths) - self._load_timestamp() - self._load_snapshot() - self._load_targets(Targets.type, Root.type) + return ordered_version_paths - def _get_repository_versions(self) -> List[str]: + + def _get_repository_versions(self) -> List[object]: """Returns a list of all the repository versions and paths.""" try: @@ -340,10 +340,7 @@ def _download_metadata( """Download a metadata file and return it as bytes""" encoded_name = parse.quote(rolename, "") - if self._spec_version_dir == "": - spec_folder = "" - else: - spec_folder = f"{self._spec_version_dir}/" + spec_folder = f"{self._spec_version_dir}" if version is None: # THIS IS SNAPSHOT VERSION !! url = f"{self._metadata_base_url}{spec_folder}{encoded_name}.json" @@ -393,7 +390,7 @@ def _load_root(self, supported_version_repos) -> None: save_repo_version_dir = self._spec_version_dir for next_version in range(lower_bound, upper_bound): - for version_repo in supported_version_repos: + for i, version_repo in enumerate(supported_version_repos): to_break = True self._spec_version_dir = version_repo try: @@ -405,6 +402,7 @@ def _load_root(self, supported_version_repos) -> None: self._trusted_set.update_root(data) self._persist_metadata(Root.type, data) # if found, don't check older supported versions + supported_version_repos = supported_version_repos[:i+1] to_break = False break From 515b4f2284c211e6b41b498c7d61b6b30e0d2fb7 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 3 Oct 2022 11:46:09 -0400 Subject: [PATCH 30/40] Move repository supported-versions to root Signed-off-by: Marina Moore --- tests/test_updater_consistent_snapshot.py | 2 - tests/test_updater_ng.py | 136 ++++++++++------------ tests/test_updater_top_level_update.py | 1 - tuf/api/metadata.py | 21 +++- tuf/ngclient/updater.py | 93 ++++++++------- 5 files changed, 130 insertions(+), 123 deletions(-) diff --git a/tests/test_updater_consistent_snapshot.py b/tests/test_updater_consistent_snapshot.py index 49d099cd80..e4bab8a8c7 100644 --- a/tests/test_updater_consistent_snapshot.py +++ b/tests/test_updater_consistent_snapshot.py @@ -104,7 +104,6 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: "consistent_snaphot disabled": { "consistent_snapshot": False, "calls": [ - ("supported-versions", None), ("root", 3), ("timestamp", None), ("snapshot", None), @@ -114,7 +113,6 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None: "consistent_snaphot enabled": { "consistent_snapshot": True, "calls": [ - ("supported-versions", None), ("root", 3), ("timestamp", None), ("snapshot", 1), diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 73c3817638..676a82cf37 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -370,7 +370,7 @@ def test_get_spec_version_supported(self) -> None: self.assertEqual( _get_spec_version(["1", "2", "3"], "3", [3]), - ("3", None), + ("3"), "3 is selected as the spec version and no warning ensues", ) @@ -425,11 +425,12 @@ def test_get_spec_version(self) -> None: expected_version, should_have_warning, ) in test_cases: - actual_version, warning = _get_spec_version( + actual_version = _get_spec_version( repo_versions, spec_version, supported_versions ) self.assertEqual(actual_version, expected_version) - self.assertEqual(bool(warning), should_have_warning) + # TODO ensure warning was logged + # self.assertEqual(bool(warning), should_have_warning) # TODO Testing logging functionality. # with self.assertLogs(ngclient.updater.__name__) as cm: @@ -438,18 +439,15 @@ def test_get_spec_version(self) -> None: def test_spec_version_increase(self) -> None: # switch repository supported versions - repo_version_path = os.path.join( - self.repository_directory, "metadata", "supported-versions.json" - ) - repo_version_json = json.dumps( - {"supported_versions": [{"version": 2, "path": "2/"}]} - ) - with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode("utf-8")) - persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + def _set_supported_version(root) -> Root: + repo_version = [{"version": 2, "path": "2/"}] + root.signed.supported_versions = repo_version + return root + + self._modify_repository_root(_set_supported_version, bump_version=True) # switch client supported versions - self.updater._supported_versions = ["2"] + self.updater._supported_versions = ["1", "2"] # copy the current metadata to 2/ shutil.copytree( @@ -462,20 +460,15 @@ def test_spec_version_increase(self) -> None: def test_spec_version_overlap(self) -> None: # repository supports version 2 and 3 - repo_version_path = os.path.join( - self.repository_directory, "metadata", "supported-versions.json" - ) - repo_version_json = json.dumps( - { - "supported_versions": [ - {"version": 2, "path": "2/"}, - {"version": 3, "path": "3/"}, - ] - } - ) - with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode("utf-8")) - persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + def _set_supported_version(root) -> Root: + repo_version = [ + {"version": 2, "path": "2/"}, + {"version": 3, "path": "3/"}, + ] + root.signed.supported_versions = repo_version + return root + + self._modify_repository_root(_set_supported_version, bump_version=True) # client supports version 1 and 2 self.updater._supported_versions = ["1", "2"] @@ -497,16 +490,13 @@ def test_tap14_backwards_compat(self) -> None: os.path.join(self.repository_directory, "metadata", "2"), ) - # add supported-versions.json - repo_version_path = os.path.join( - self.repository_directory, "metadata", "supported-versions.json" - ) - repo_version_json = json.dumps( - {"supported_versions": [{"version": 1, "path": ""}]} - ) - with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode("utf-8")) - persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + # add supported-versions to root + def _set_supported_version(root) -> Root: + repo_version = [{"version": 1, "path": ""}] + root.signed.supported_versions = repo_version + return root + + self._modify_repository_root(_set_supported_version, bump_version=True) self.updater.refresh() @@ -523,16 +513,13 @@ def test_spec_version_rollback(self) -> None: ) # but supported-versions only contains 1 - # add supported-versions.json - repo_version_path = os.path.join( - self.repository_directory, "metadata", "supported-versions.json" - ) - repo_version_json = json.dumps( - {"supported_versions": [{"version": 1, "path": ""}]} - ) - with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode("utf-8")) - persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + # add supported-versions to root + def _set_supported_version(root) -> Root: + repo_version = [{"version": 1, "path": ""}] + root.signed.supported_versions = repo_version + return root + + self._modify_repository_root(_set_supported_version, bump_version=True) self.assertEqual(self.updater._supported_versions, ["1"]) @@ -540,6 +527,17 @@ def test_spec_version_rollback(self) -> None: self.updater.refresh() def test_spec_version_root_update_order(self) -> None: + # set supported versions in root + def _set_supported_version(root) -> Root: + repo_version = [ + {"version": 1, "path": ""}, + {"version": 2, "path": ""}, + ] + root.signed.supported_versions = repo_version + return root + + self._modify_repository_root(_set_supported_version, bump_version=True) + # copy the current metadata to 2/ shutil.copytree( os.path.join(self.repository_directory, "metadata"), @@ -549,23 +547,13 @@ def test_spec_version_root_update_order(self) -> None: # update root not in 2/ self._modify_repository_root(lambda root: None, bump_version=True) - # switch repository supported versions - repo_version_path = os.path.join( - self.repository_directory, "metadata", "supported-versions.json" - ) - repo_version_json = json.dumps( - {"supported_versions": [{"version": 2, "path": "2/"}]} - ) - with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode("utf-8")) - persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) - # switch client supported versions - self.updater._supported_versions = ["2"] + self.updater._supported_versions = ["1", "2"] self.updater.refresh() - # it should not find version 2 of root as it is missing from 2/ - self.assertEqual(self.updater._trusted_set.root.signed.version, 1) + # version 2 is missing the most recent root + self.assertEqual(self.updater._trusted_set.root.signed.version, 3) + self.assertEqual(self.updater._spec_version, "2") def test_spec_version_root_update(self) -> None: # update root @@ -577,25 +565,23 @@ def test_spec_version_root_update(self) -> None: os.path.join(self.repository_directory, "metadata", "2"), ) - # update root outside of 2/ **this should be ignored** - self._modify_repository_root(lambda root: None, bump_version=True) - # switch repository supported versions - repo_version_path = os.path.join( - self.repository_directory, "metadata", "supported-versions.json" - ) - repo_version_json = json.dumps( - {"supported_versions": [{"version": 2, "path": "2/"}]} - ) - with tempfile.TemporaryFile() as temp_file: - temp_file.write(repo_version_json.encode("utf-8")) - persist_temp_file(temp_file, repo_version_path, FilesystemBackend()) + def _set_supported_version(root) -> Root: + repo_version = [ + {"version": 1, "path": ""}, + {"version": 2, "path": ""}, + ] + root.signed.supported_versions = repo_version + return root + + self._modify_repository_root(_set_supported_version, bump_version=True) # switch client supported versions - self.updater._supported_versions = ["2"] + self.updater._supported_versions = ["1", "2"] self.updater.refresh() - self.assertEqual(self.updater._trusted_set.root.signed.version, 2) + self.assertEqual(self.updater._trusted_set.root.signed.version, 3) + self.assertEqual(self.updater._spec_version, "2") if __name__ == "__main__": diff --git a/tests/test_updater_top_level_update.py b/tests/test_updater_top_level_update.py index b572fa8cae..c2b1b0beac 100644 --- a/tests/test_updater_top_level_update.py +++ b/tests/test_updater_top_level_update.py @@ -742,7 +742,6 @@ def test_load_metadata_from_cache(self, wrapped_open: MagicMock) -> None: ) expected_calls = [ - ("supported-versions", None), ("root", 2), ("timestamp", None), ] diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index d05f12fcf8..ed3f348bf7 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -866,6 +866,8 @@ class Root(Signed): a dictionary of top level roles without keys and threshold of 1. consistent_snapshot: ``True`` if repository supports consistent snapshots. Default is True. + supported_versions: List of supported versions and their associated + directory unrecognized_fields: Dictionary of all attributes that are not managed by TUF Metadata API @@ -884,11 +886,13 @@ def __init__( keys: Optional[Dict[str, Key]] = None, roles: Optional[Mapping[str, Role]] = None, consistent_snapshot: Optional[bool] = True, + supported_versions: Optional[list[Dict]] = [], unrecognized_fields: Optional[Dict[str, Any]] = None, ): super().__init__(version, spec_version, expires, unrecognized_fields) self.consistent_snapshot = consistent_snapshot self.keys = keys if keys is not None else {} + self.supported_versions = supported_versions if roles is None: roles = {r: Role([], 1) for r in TOP_LEVEL_ROLE_NAMES} @@ -905,6 +909,7 @@ def __eq__(self, other: Any) -> bool: and self.keys == other.keys and self.roles == other.roles and self.consistent_snapshot == other.consistent_snapshot + and self.supported_versions == other.supported_versions ) @classmethod @@ -915,6 +920,7 @@ def from_dict(cls, signed_dict: Dict[str, Any]) -> "Root": ValueError, KeyError, TypeError: Invalid arguments. """ common_args = cls._common_fields_from_dict(signed_dict) + supported_versions = signed_dict.pop("supported_versions", []) consistent_snapshot = signed_dict.pop("consistent_snapshot", None) keys = signed_dict.pop("keys") roles = signed_dict.pop("roles") @@ -925,7 +931,14 @@ def from_dict(cls, signed_dict: Dict[str, Any]) -> "Root": roles[role_name] = Role.from_dict(role_dict) # All fields left in the signed_dict are unrecognized. - return cls(*common_args, keys, roles, consistent_snapshot, signed_dict) + return cls( + *common_args, + keys, + roles, + consistent_snapshot, + supported_versions, + signed_dict, + ) def to_dict(self) -> Dict[str, Any]: """Returns the dict representation of self.""" @@ -936,6 +949,12 @@ def to_dict(self) -> Dict[str, Any]: roles[role_name] = role.to_dict() if self.consistent_snapshot is not None: root_dict["consistent_snapshot"] = self.consistent_snapshot + if len(self.supported_versions) > 0: + supported_versions = [ + {field: value for (field, value) in v.items()} + for v in self.supported_versions + ] + root_dict["supported_versions"] = supported_versions root_dict.update( { diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 7df1fe13f9..a292d18f58 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -131,14 +131,15 @@ def refresh(self) -> None: RepositoryError: Metadata failed to verify in some way DownloadError: Download of a metadata file failed in some way """ - ordered_version_paths = self._set_spec_version() + self._set_spec_version() - self._load_root(ordered_version_paths) + self._load_root() self._load_timestamp() self._load_snapshot() self._load_targets(Targets.type, Root.type) - def _set_spec_version(self) -> List[str]: + def _set_spec_version(self) -> None: + # get previous spec version try: version_bytes = self._load_local_metadata("spec_version") self._spec_version = json.loads(version_bytes.decode("utf-8"))[ @@ -150,25 +151,31 @@ def _set_spec_version(self) -> List[str]: raise self._spec_version = "1" - repository_versions_and_paths = self._get_repository_versions() - + def _find_matching_spec_version( + self, repository_versions_and_paths + ) -> List[str]: repository_versions = [ i["version"] for i in repository_versions_and_paths ] # Updating self.spec_version - spec_version, message = _get_spec_version( + spec_version = _get_spec_version( repository_versions, self._spec_version, self._supported_versions ) - if message: - logger.warning(message) self._spec_version = spec_version ordered_version_paths = [] - for version in sorted(repository_versions): - path = [i["path"] for i in repository_versions_and_paths if version <= int(spec_version) and i["version"] == version] + repository_versions = sorted(repository_versions) + repository_versions.reverse() + + for version in repository_versions: + path = [ + i["path"] + for i in repository_versions_and_paths + if version >= int(spec_version) and i["version"] == version + ] # found this version if len(path) > 0: @@ -186,24 +193,14 @@ def _set_spec_version(self) -> List[str]: return ordered_version_paths - def _get_repository_versions(self) -> List[object]: """Returns a list of all the repository versions and paths.""" - try: - url = f"{self._metadata_base_url}supported-versions.json" - - target_bytes = self._fetcher.download_bytes( - url, self.config.supported_versions_max_length - ) - repository_versions = json.loads(target_bytes) - return repository_versions["supported_versions"] - - # If supported-versions.json is not found, then default to version 1 - except exceptions.DownloadHTTPError as e: - if e.status_code == 404: - return [{"version": 1, "path": ""}] - raise + # If supported-versions is not found, then default to version 1 + if len(self._trusted_set.root.signed.supported_versions) > 0: + return self._trusted_set.root.signed.supported_versions + else: + return [{"version": 1, "path": ""}] def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: @@ -376,23 +373,27 @@ def _persist_metadata(self, rolename: str, data: bytes) -> None: pass raise e - def _load_root(self, supported_version_repos) -> None: + def _load_root(self) -> None: """Load remote root metadata. Sequentially load and persist on local disk every newer root metadata version available on the remote. """ + # find the current highest compatible spec version and get the + # list of versions to look for root metadata + repository_versions_and_paths = self._get_repository_versions() + supported_version_repos = self._find_matching_spec_version( + repository_versions_and_paths + ) + # Update the root role lower_bound = self._trusted_set.root.signed.version + 1 upper_bound = lower_bound + self.config.max_root_rotations - save_repo_version_dir = self._spec_version_dir - - for next_version in range(lower_bound, upper_bound): - for i, version_repo in enumerate(supported_version_repos): - to_break = True - self._spec_version_dir = version_repo + for version_repo in supported_version_repos: + self._spec_version_dir = version_repo + for next_version in range(lower_bound, upper_bound): try: data = self._download_metadata( Root.type, @@ -401,20 +402,23 @@ def _load_root(self, supported_version_repos) -> None: ) self._trusted_set.update_root(data) self._persist_metadata(Root.type, data) - # if found, don't check older supported versions - supported_version_repos = supported_version_repos[:i+1] - to_break = False - break + # check if supported_versions was updated in this root + repository_versions_and_paths = ( + self._get_repository_versions() + ) + supported_version_repos = self._find_matching_spec_version( + repository_versions_and_paths + ) + # if found, don't check older versions + lower_bound = self._trusted_set.root.signed.version + 1 except exceptions.DownloadHTTPError as exception: if exception.status_code not in {403, 404}: raise # 404/403 means current root is newest available - if to_break: - self._spec_version_dir = save_repo_version_dir - return + break - self._spec_version_dir = save_repo_version_dir + # self._spec_version_dir = save_repo_version_dir def _load_timestamp(self) -> None: """Load local and remote timestamp metadata""" @@ -574,7 +578,7 @@ def _get_spec_version( repository_versions: List[str], spec_version: str, supported_versions: List[str], -) -> Tuple[str, Optional[str]]: +) -> str: """Returns the specification version to be used, following the rules of TAP-14 and displays a warning if chosen spec_version is lower than the highest repository version. @@ -621,8 +625,9 @@ def _get_spec_version( f"repository and {supported_versions} in client." ) from e - warning = None if latest_repo_version > spec_version: - warning = "Not using the latest specification version available on the repository" + logger.warning( + "Not using the latest specification version available on the repository" + ) - return (str(spec_version), warning) + return str(spec_version) From df2ecd40848c0035a1ec10a3dbd1ef7aef5d3d8b Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 3 Oct 2022 12:26:00 -0400 Subject: [PATCH 31/40] Fix typs Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 42 ++++++++++++++++++++-------------------- tuf/api/metadata.py | 5 ++++- tuf/ngclient/updater.py | 36 ++++++++++++++++++---------------- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 676a82cf37..add158759b 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -369,7 +369,7 @@ def test_get_spec_version_supported(self) -> None: ) self.assertEqual( - _get_spec_version(["1", "2", "3"], "3", [3]), + _get_spec_version(["1", "2", "3"], "3", ["3"]), ("3"), "3 is selected as the spec version and no warning ensues", ) @@ -418,19 +418,19 @@ def test_get_spec_version(self) -> None: True, ), # 11 is selected as the spec version but a warning ensues ] - for ( - repo_versions, - spec_version, - supported_versions, - expected_version, - should_have_warning, - ) in test_cases: + for t in test_cases: + ( + repo_versions, + spec_version, + supported_versions, + expected_version, + should_have_warning, + ) = t actual_version = _get_spec_version( repo_versions, spec_version, supported_versions ) self.assertEqual(actual_version, expected_version) # TODO ensure warning was logged - # self.assertEqual(bool(warning), should_have_warning) # TODO Testing logging functionality. # with self.assertLogs(ngclient.updater.__name__) as cm: @@ -439,10 +439,10 @@ def test_get_spec_version(self) -> None: def test_spec_version_increase(self) -> None: # switch repository supported versions - def _set_supported_version(root) -> Root: + def _set_supported_version(root: Metadata) -> None: repo_version = [{"version": 2, "path": "2/"}] root.signed.supported_versions = repo_version - return root + return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -460,13 +460,13 @@ def _set_supported_version(root) -> Root: def test_spec_version_overlap(self) -> None: # repository supports version 2 and 3 - def _set_supported_version(root) -> Root: + def _set_supported_version(root: Metadata) -> None: repo_version = [ {"version": 2, "path": "2/"}, {"version": 3, "path": "3/"}, ] root.signed.supported_versions = repo_version - return root + return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -491,10 +491,10 @@ def test_tap14_backwards_compat(self) -> None: ) # add supported-versions to root - def _set_supported_version(root) -> Root: + def _set_supported_version(root: Metadata) -> None: repo_version = [{"version": 1, "path": ""}] root.signed.supported_versions = repo_version - return root + return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -514,10 +514,10 @@ def test_spec_version_rollback(self) -> None: # but supported-versions only contains 1 # add supported-versions to root - def _set_supported_version(root) -> Root: + def _set_supported_version(root: Metadata) -> None: repo_version = [{"version": 1, "path": ""}] root.signed.supported_versions = repo_version - return root + return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -528,13 +528,13 @@ def _set_supported_version(root) -> Root: def test_spec_version_root_update_order(self) -> None: # set supported versions in root - def _set_supported_version(root) -> Root: + def _set_supported_version(root: Metadata) -> None: repo_version = [ {"version": 1, "path": ""}, {"version": 2, "path": ""}, ] root.signed.supported_versions = repo_version - return root + return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -566,13 +566,13 @@ def test_spec_version_root_update(self) -> None: ) # switch repository supported versions - def _set_supported_version(root) -> Root: + def _set_supported_version(root: Metadata) -> None: repo_version = [ {"version": 1, "path": ""}, {"version": 2, "path": ""}, ] root.signed.supported_versions = repo_version - return root + return None self._modify_repository_root(_set_supported_version, bump_version=True) diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index ed3f348bf7..8255767d3f 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -949,7 +949,10 @@ def to_dict(self) -> Dict[str, Any]: roles[role_name] = role.to_dict() if self.consistent_snapshot is not None: root_dict["consistent_snapshot"] = self.consistent_snapshot - if len(self.supported_versions) > 0: + if ( + self.supported_versions is not None + and len(self.supported_versions) > 0 + ): supported_versions = [ {field: value for (field, value) in v.items()} for v in self.supported_versions diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index a292d18f58..bbe0a540fe 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -91,7 +91,7 @@ def __init__( fetcher: Optional[FetcherInterface] = None, config: Optional[UpdaterConfig] = None, ): - self._spec_version = None # spec_version is the last used version by the client to get metadata + self._spec_version: str = "1" # spec_version is the last used version by the client to get metadata self._spec_version_dir = "" self._dir = metadata_dir self._metadata_base_url = _ensure_trailing_slash(metadata_base_url) @@ -152,7 +152,7 @@ def _set_spec_version(self) -> None: self._spec_version = "1" def _find_matching_spec_version( - self, repository_versions_and_paths + self, repository_versions_and_paths: List[dict] ) -> List[str]: repository_versions = [ i["version"] for i in repository_versions_and_paths @@ -193,12 +193,13 @@ def _find_matching_spec_version( return ordered_version_paths - def _get_repository_versions(self) -> List[object]: + def _get_repository_versions(self) -> List[dict]: """Returns a list of all the repository versions and paths.""" # If supported-versions is not found, then default to version 1 - if len(self._trusted_set.root.signed.supported_versions) > 0: - return self._trusted_set.root.signed.supported_versions + supported = self._trusted_set.root.signed.supported_versions + if supported is not None and len(supported) > 0: + return supported else: return [{"version": 1, "path": ""}] @@ -589,22 +590,21 @@ def _get_spec_version( this repository RepositoryError: No matching version found between supported_versions and repository_versions """ - repository_versions = [int(i) for i in repository_versions] - supported_versions = [int(i) for i in supported_versions] - spec_version = int(spec_version) + repository_versions_int = [int(i) for i in repository_versions] + supported_versions_int = [int(i) for i in supported_versions] + spec_version_int = int(spec_version) # The client determines the latest version available on the repository by looking # for the directory with the largest version number. - latest_repo_version = max(repository_versions) + latest_repo_version = max(repository_versions_int) # If the latest version on the repository is lower than the previous specification # version the client used from this repository, the client should report an error # and terminate the update. - if spec_version: - if latest_repo_version < spec_version: - raise exceptions.RepositoryError( - f"The latest repository version ({latest_repo_version}) is lower than the last used spec version ({spec_version})." - ) + if latest_repo_version < spec_version_int: + raise exceptions.RepositoryError( + f"The latest repository version ({latest_repo_version}) is lower than the last used spec version ({spec_version})." + ) # If the latest version on the repository is equal to that of the client, it will use this directory to download metadata. @@ -618,16 +618,18 @@ def _get_spec_version( # that corresponds with the latest client specification version, if available. If no such directory exists, # the client terminates the update. try: - spec_version = max(set(repository_versions) & set(supported_versions)) + spec_version_int = max( + set(repository_versions_int) & set(supported_versions_int) + ) except ValueError as e: raise exceptions.RepositoryError( f"No matching specification version found. Found {repository_versions} in" f"repository and {supported_versions} in client." ) from e - if latest_repo_version > spec_version: + if latest_repo_version > spec_version_int: logger.warning( "Not using the latest specification version available on the repository" ) - return str(spec_version) + return str(spec_version_int) From 6b7cf5d7944e31fa9c9edd201e1c38c00590eff1 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 3 Oct 2022 13:01:51 -0400 Subject: [PATCH 32/40] list -> List for python < 3.9 Signed-off-by: Marina Moore --- tuf/api/metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index 8255767d3f..4afdae573b 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -886,7 +886,7 @@ def __init__( keys: Optional[Dict[str, Key]] = None, roles: Optional[Mapping[str, Role]] = None, consistent_snapshot: Optional[bool] = True, - supported_versions: Optional[list[Dict]] = [], + supported_versions: Optional[List[Dict]] = [], unrecognized_fields: Optional[Dict[str, Any]] = None, ): super().__init__(version, spec_version, expires, unrecognized_fields) From f57bac799aaad472a55f4affbc82b8ca43652d5a Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 3 Oct 2022 14:04:44 -0400 Subject: [PATCH 33/40] fix pylint errors Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 12 +----------- tuf/api/metadata.py | 14 ++++---------- tuf/ngclient/updater.py | 10 +++++++--- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index add158759b..6b128f1898 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -401,21 +401,18 @@ def test_get_spec_version(self) -> None: "3", ["1", "2", "3", "4"], "3", - True, ), # 3 is selected as the spec version but a warning ensues ( ["1", "2", "3"], "3", ["3", "5", "6"], "3", - False, ), # 3 is selected as the spec version and no warning ensues ( ["8", "11", "13"], "12", ["8", "11", "12"], "11", - True, ), # 11 is selected as the spec version but a warning ensues ] for t in test_cases: @@ -424,13 +421,12 @@ def test_get_spec_version(self) -> None: spec_version, supported_versions, expected_version, - should_have_warning, ) = t actual_version = _get_spec_version( repo_versions, spec_version, supported_versions ) self.assertEqual(actual_version, expected_version) - # TODO ensure warning was logged + # TODO ensure warning was logged for case 1 and 3 # TODO Testing logging functionality. # with self.assertLogs(ngclient.updater.__name__) as cm: @@ -442,7 +438,6 @@ def test_spec_version_increase(self) -> None: def _set_supported_version(root: Metadata) -> None: repo_version = [{"version": 2, "path": "2/"}] root.signed.supported_versions = repo_version - return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -466,7 +461,6 @@ def _set_supported_version(root: Metadata) -> None: {"version": 3, "path": "3/"}, ] root.signed.supported_versions = repo_version - return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -494,7 +488,6 @@ def test_tap14_backwards_compat(self) -> None: def _set_supported_version(root: Metadata) -> None: repo_version = [{"version": 1, "path": ""}] root.signed.supported_versions = repo_version - return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -517,7 +510,6 @@ def test_spec_version_rollback(self) -> None: def _set_supported_version(root: Metadata) -> None: repo_version = [{"version": 1, "path": ""}] root.signed.supported_versions = repo_version - return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -534,7 +526,6 @@ def _set_supported_version(root: Metadata) -> None: {"version": 2, "path": ""}, ] root.signed.supported_versions = repo_version - return None self._modify_repository_root(_set_supported_version, bump_version=True) @@ -572,7 +563,6 @@ def _set_supported_version(root: Metadata) -> None: {"version": 2, "path": ""}, ] root.signed.supported_versions = repo_version - return None self._modify_repository_root(_set_supported_version, bump_version=True) diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index 4afdae573b..0d40f19e47 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -886,7 +886,7 @@ def __init__( keys: Optional[Dict[str, Key]] = None, roles: Optional[Mapping[str, Role]] = None, consistent_snapshot: Optional[bool] = True, - supported_versions: Optional[List[Dict]] = [], + supported_versions: Optional[List[Dict]] = None, unrecognized_fields: Optional[Dict[str, Any]] = None, ): super().__init__(version, spec_version, expires, unrecognized_fields) @@ -920,7 +920,7 @@ def from_dict(cls, signed_dict: Dict[str, Any]) -> "Root": ValueError, KeyError, TypeError: Invalid arguments. """ common_args = cls._common_fields_from_dict(signed_dict) - supported_versions = signed_dict.pop("supported_versions", []) + supported_versions = signed_dict.pop("supported_versions", None) consistent_snapshot = signed_dict.pop("consistent_snapshot", None) keys = signed_dict.pop("keys") roles = signed_dict.pop("roles") @@ -949,14 +949,8 @@ def to_dict(self) -> Dict[str, Any]: roles[role_name] = role.to_dict() if self.consistent_snapshot is not None: root_dict["consistent_snapshot"] = self.consistent_snapshot - if ( - self.supported_versions is not None - and len(self.supported_versions) > 0 - ): - supported_versions = [ - {field: value for (field, value) in v.items()} - for v in self.supported_versions - ] + if self.supported_versions is not None: + supported_versions = self.supported_versions root_dict["supported_versions"] = supported_versions root_dict.update( diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index bbe0a540fe..4058c80578 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -39,7 +39,7 @@ import os import shutil import tempfile -from typing import List, Optional, Set, Tuple +from typing import List, Optional, Set from urllib import parse from tuf.api import exceptions @@ -139,6 +139,7 @@ def refresh(self) -> None: self._load_targets(Targets.type, Root.type) def _set_spec_version(self) -> None: + """Load previous spec version from disk""" # get previous spec version try: version_bytes = self._load_local_metadata("spec_version") @@ -154,6 +155,10 @@ def _set_spec_version(self) -> None: def _find_matching_spec_version( self, repository_versions_and_paths: List[dict] ) -> List[str]: + """Find the set of spec versions that match between the client and repository. + Returns the paths for these spec versions in order + """ + repository_versions = [ i["version"] for i in repository_versions_and_paths ] @@ -200,8 +205,7 @@ def _get_repository_versions(self) -> List[dict]: supported = self._trusted_set.root.signed.supported_versions if supported is not None and len(supported) > 0: return supported - else: - return [{"version": 1, "path": ""}] + return [{"version": 1, "path": ""}] def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: From 4ffba951c1547705baf68cc3086e4014ca950350 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Fri, 21 Oct 2022 13:04:21 -0400 Subject: [PATCH 34/40] lint fix Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 6b128f1898..45f0214d76 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -13,7 +13,7 @@ import sys import tempfile import unittest -from typing import Callable, ClassVar, List +from typing import Callable, ClassVar, List, Tuple from unittest.mock import MagicMock, patch from securesystemslib.interface import import_rsa_privatekey_from_file @@ -377,7 +377,7 @@ def test_get_spec_version_supported(self) -> None: def test_get_spec_version(self) -> None: # warningchecker = "Not using the latest specification version available on the repository" # Checks with different values - test_cases = [ + test_cases: List[Tuple[List[str], str, List[str]]] = [ ( ["3", "5", "6"], "7", @@ -395,7 +395,7 @@ def test_get_spec_version(self) -> None: repo_versions, spec_version, supported_versions ) - test_cases = [ + test_cases_2: List[Tuple[List[str], str, List[str], str]] = [ ( ["3", "5", "6"], "3", @@ -415,7 +415,7 @@ def test_get_spec_version(self) -> None: "11", ), # 11 is selected as the spec version but a warning ensues ] - for t in test_cases: + for t in test_cases_2: ( repo_versions, spec_version, From 81c97184ddf888ce492fe2452c6be42a6b0b692b Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Fri, 21 Oct 2022 16:39:56 -0400 Subject: [PATCH 35/40] use supported_versions fields for root update Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 195 +++++++++++++++--- .../_internal/trusted_metadata_set.py | 13 ++ tuf/ngclient/updater.py | 152 ++++++++------ 3 files changed, 268 insertions(+), 92 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 45f0214d76..69df406c94 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -6,6 +6,7 @@ """Test Updater class """ +import base64 import json import logging import os @@ -20,6 +21,7 @@ from securesystemslib.signer import SSlibSigner from securesystemslib.storage import FilesystemBackend from securesystemslib.util import persist_temp_file +from securesystemslib import hash as sslib_hash from tests import utils from tuf import ngclient @@ -434,15 +436,21 @@ def test_get_spec_version(self) -> None: # self.updater._get_spec_version(["3","5","6"],"3",["1","2","3","4"]) def test_spec_version_increase(self) -> None: + # switch client supported versions + self.updater._supported_versions = ["1", "2"] + + # copy the current metadata to 1/ + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "1"), + ) + # switch repository supported versions - def _set_supported_version(root: Metadata) -> None: - repo_version = [{"version": 2, "path": "2/"}] + def _set_supported_version_v2(root: Metadata) -> None: + repo_version = [{"version": 2}] root.signed.supported_versions = repo_version - self._modify_repository_root(_set_supported_version, bump_version=True) - - # switch client supported versions - self.updater._supported_versions = ["1", "2"] + self._modify_repository_root(_set_supported_version_v2, bump_version=True) # copy the current metadata to 2/ shutil.copytree( @@ -450,29 +458,97 @@ def _set_supported_version(root: Metadata) -> None: os.path.join(self.repository_directory, "metadata", "2"), ) - self.updater.refresh() - self.assertEqual(self.updater._spec_version, "2") + # switch back to version 1 + shutil.copytree( + os.path.join(self.repository_directory, "metadata", "1"), + os.path.join(self.repository_directory, "metadata"), + dirs_exist_ok=True, + ) - def test_spec_version_overlap(self) -> None: - # repository supports version 2 and 3 + # get root digest + root_path = os.path.join( + self.repository_directory, "metadata", "2", "2.root.json" + ) + with open(root_path, "rb") as f: + hasher = sslib_hash.digest_fileobject(f, algorithm="sha256") + root_digest = base64.b64encode(hasher.digest()) + + # set supported versions in root def _set_supported_version(root: Metadata) -> None: repo_version = [ - {"version": 2, "path": "2/"}, - {"version": 3, "path": "3/"}, + {"version": 1}, + { + "version": 2, + "root-filename": "2.root.json", + "root-digest": root_digest.decode("utf-8"), + }, ] root.signed.supported_versions = repo_version self._modify_repository_root(_set_supported_version, bump_version=True) + self.updater.refresh() + self.assertEqual(self.updater._spec_version, "2") + + def test_spec_version_overlap(self) -> None: # client supports version 1 and 2 self.updater._supported_versions = ["1", "2"] + # copy the current metadata to 1/ + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "1"), + ) + + # repository supports version 2 and 3 + def _set_supported_version_v2(root: Metadata) -> None: + repo_version = [ + {"version": 2}, + { + "version": 3, + "root-filename": "wontuse", + "root-digest": "wontuse", + }, + ] + root.signed.supported_versions = repo_version + + self._modify_repository_root(_set_supported_version_v2, bump_version=True) + # copy the current metadata to 2/ shutil.copytree( os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2"), ) + # switch back to version 1 + shutil.copytree( + os.path.join(self.repository_directory, "metadata", "1"), + os.path.join(self.repository_directory, "metadata"), + dirs_exist_ok=True, + ) + + # get root digest + root_path = os.path.join( + self.repository_directory, "metadata", "2", "2.root.json" + ) + with open(root_path, "rb") as f: + hasher = sslib_hash.digest_fileobject(f, algorithm="sha256") + root_digest = base64.b64encode(hasher.digest()) + + # set supported versions in root + def _set_supported_version(root: Metadata) -> None: + repo_version = [ + {"version": 1}, + { + "version": 2, + "root-filename": "2.root.json", + "root-digest": root_digest.decode("utf-8"), + }, + ] + root.signed.supported_versions = repo_version + + self._modify_repository_root(_set_supported_version, bump_version=True) + self.updater.refresh() self.assertEqual(self.updater._spec_version, "2") # TODO assert that higher repo version available warning was logged @@ -486,7 +562,7 @@ def test_tap14_backwards_compat(self) -> None: # add supported-versions to root def _set_supported_version(root: Metadata) -> None: - repo_version = [{"version": 1, "path": ""}] + repo_version = [{"version": 1}] root.signed.supported_versions = repo_version self._modify_repository_root(_set_supported_version, bump_version=True) @@ -508,7 +584,7 @@ def test_spec_version_rollback(self) -> None: # but supported-versions only contains 1 # add supported-versions to root def _set_supported_version(root: Metadata) -> None: - repo_version = [{"version": 1, "path": ""}] + repo_version = [{"version": 1}] root.signed.supported_versions = repo_version self._modify_repository_root(_set_supported_version, bump_version=True) @@ -519,22 +595,57 @@ def _set_supported_version(root: Metadata) -> None: self.updater.refresh() def test_spec_version_root_update_order(self) -> None: - # set supported versions in root - def _set_supported_version(root: Metadata) -> None: + + # copy the current metadata to 1/ to save it + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "1"), + ) + + # make version 2 metadata + def _set_supported_version_v2(root: Metadata) -> None: repo_version = [ - {"version": 1, "path": ""}, - {"version": 2, "path": ""}, + {"version": 2}, ] root.signed.supported_versions = repo_version - self._modify_repository_root(_set_supported_version, bump_version=True) + self._modify_repository_root(_set_supported_version_v2, bump_version=True) - # copy the current metadata to 2/ + # move this metadata to 2/ shutil.copytree( os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2"), ) + # switch back to version 1 + shutil.copytree( + os.path.join(self.repository_directory, "metadata", "1"), + os.path.join(self.repository_directory, "metadata"), + dirs_exist_ok=True, + ) + + # get root digest + root_path = os.path.join( + self.repository_directory, "metadata", "2", "2.root.json" + ) + with open(root_path, "rb") as f: + hasher = sslib_hash.digest_fileobject(f, algorithm="sha256") + root_digest = base64.b64encode(hasher.digest()) + + # set supported versions in root + def _set_supported_version(root: Metadata) -> None: + repo_version = [ + {"version": 1}, + { + "version": 2, + "root-filename": "2.root.json", + "root-digest": root_digest.decode("utf-8"), + }, + ] + root.signed.supported_versions = repo_version + + self._modify_repository_root(_set_supported_version, bump_version=True) + # update root not in 2/ self._modify_repository_root(lambda root: None, bump_version=True) @@ -543,24 +654,60 @@ def _set_supported_version(root: Metadata) -> None: self.updater.refresh() # version 2 is missing the most recent root - self.assertEqual(self.updater._trusted_set.root.signed.version, 3) + self.assertEqual(self.updater._trusted_set.root.signed.version, 2) self.assertEqual(self.updater._spec_version, "2") def test_spec_version_root_update(self) -> None: # update root self._modify_repository_root(lambda root: None, bump_version=True) - # copy the current metadata to 2/ + # save the current metadata to 1/ + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "1"), + ) + + # make repository supported versions for version 2 + def _set_supported_version_v2(root: Metadata) -> None: + repo_version = [ + {"version": 2}, + ] + root.signed.supported_versions = repo_version + + self._modify_repository_root(_set_supported_version_v2, bump_version=True) + + # move this metadata to 2/ shutil.copytree( os.path.join(self.repository_directory, "metadata"), os.path.join(self.repository_directory, "metadata", "2"), ) + # switch back to version 1 + shutil.copytree( + os.path.join(self.repository_directory, "metadata", "1"), + os.path.join(self.repository_directory, "metadata"), + dirs_exist_ok=True, + ) + + # get root digest + root_path = os.path.join( + self.repository_directory, "metadata", "2", "3.root.json" + ) + with open(root_path, "rb") as f: + file_bytes = f.read() + hasher = sslib_hash.digest(algorithm="sha256") + hasher.update(file_bytes) + root_digest = base64.b64encode(hasher.digest()) + # switch repository supported versions def _set_supported_version(root: Metadata) -> None: repo_version = [ - {"version": 1, "path": ""}, - {"version": 2, "path": ""}, + {"version": 1}, + { + "version": 2, + "root-filename": "3.root.json", + "root-digest": root_digest.decode("utf-8"), + }, ] root.signed.supported_versions = repo_version diff --git a/tuf/ngclient/_internal/trusted_metadata_set.py b/tuf/ngclient/_internal/trusted_metadata_set.py index fa788d0a1f..abddd7a0d2 100644 --- a/tuf/ngclient/_internal/trusted_metadata_set.py +++ b/tuf/ngclient/_internal/trusted_metadata_set.py @@ -177,6 +177,19 @@ def update_root(self, data: bytes) -> Metadata[Root]: return new_root + def update_root_spec_rotation(self, data: bytes) -> Metadata[Root]: + """Loads ``data`` as new root metadata, skipping version and + signature checks. + """ + new_root = Metadata[Root].from_bytes(data) + self._trusted_set[Root.type] = new_root + logger.info( + "Updated root to new specification version root, new root version is v%d", + new_root.signed.version, + ) + + return new_root + def update_timestamp(self, data: bytes) -> Metadata[Timestamp]: """Verifies and loads ``data`` as new timestamp metadata. diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 4058c80578..b611ddf72a 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -33,15 +33,18 @@ `_. """ +import base64 import errno import json import logging import os import shutil import tempfile -from typing import List, Optional, Set +from typing import List, Optional, Set, Tuple from urllib import parse +from securesystemslib import hash as sslib_hash + from tuf.api import exceptions from tuf.api.metadata import ( SPECIFICATION_VERSION, @@ -151,52 +154,36 @@ def _set_spec_version(self) -> None: if e.errno != errno.ENOENT: raise self._spec_version = "1" + # persist the version number + self._persist_metadata( + "spec_version", + json.dumps({"version": "1"}).encode("utf-8"), + ) def _find_matching_spec_version( - self, repository_versions_and_paths: List[dict] - ) -> List[str]: + self, repository_versions_dicts: List[dict] + ) -> Tuple[str, str, str]: """Find the set of spec versions that match between the client and repository. - Returns the paths for these spec versions in order + Returns the largest matching version and information about + the new root """ - repository_versions = [ - i["version"] for i in repository_versions_and_paths - ] + repository_versions = [i["version"] for i in repository_versions_dicts] # Updating self.spec_version spec_version = _get_spec_version( repository_versions, self._spec_version, self._supported_versions ) - self._spec_version = spec_version - - ordered_version_paths = [] - - repository_versions = sorted(repository_versions) - repository_versions.reverse() - - for version in repository_versions: - path = [ - i["path"] - for i in repository_versions_and_paths - if version >= int(spec_version) and i["version"] == version - ] - - # found this version - if len(path) > 0: - ordered_version_paths.append(path[0]) - - for i in repository_versions_and_paths: - if i["version"] == spec_version: - self._spec_version_dir = i["path"] - - # persist the version number - self._persist_metadata( - "spec_version", - json.dumps({"version": spec_version}).encode("utf-8"), - ) + for i in repository_versions_dicts: + if i["version"] == int(spec_version): + if "root-filename" in i and "root-digest" in i: + return spec_version, i["root-filename"], i["root-digest"] + # root info will be empty if the version does not change + return spec_version, "", "" - return ordered_version_paths + # we shouldn't get here... + raise ValueError("current repository version not found") def _get_repository_versions(self) -> List[dict]: """Returns a list of all the repository versions and paths.""" @@ -205,7 +192,7 @@ def _get_repository_versions(self) -> List[dict]: supported = self._trusted_set.root.signed.supported_versions if supported is not None and len(supported) > 0: return supported - return [{"version": 1, "path": ""}] + return [{"version": 1}] def _generate_target_file_path(self, targetinfo: TargetFile) -> str: if self.target_dir is None: @@ -336,6 +323,11 @@ def download_target( logger.info("Downloaded target %s", targetinfo.path) return filepath + def _download_new_spec_root(self, rolename: str, length: int) -> bytes: + spec_folder = f"{self._spec_version_dir}" + url = f"{self._metadata_base_url}{spec_folder}{rolename}" + return self._fetcher.download_bytes(url, length) + def _download_metadata( self, rolename: str, length: int, version: Optional[int] = None ) -> bytes: @@ -387,43 +379,67 @@ def _load_root(self) -> None: # find the current highest compatible spec version and get the # list of versions to look for root metadata - repository_versions_and_paths = self._get_repository_versions() - supported_version_repos = self._find_matching_spec_version( - repository_versions_and_paths - ) + ( + supported_version, + new_root_filename, + new_root_bytes, + ) = self._find_matching_spec_version(self._get_repository_versions()) + + # if compatible version higher than current, jump to that root + # call _load_root in new version + if int(supported_version) > int(self._spec_version): + save_dir = self._spec_version_dir + self._spec_version_dir = supported_version + "/" + actual_bytes = self._download_new_spec_root( + new_root_filename, self.config.root_max_length + ) + hasher = sslib_hash.digest(algorithm="sha256") + hasher.update(actual_bytes) + if base64.b64decode(new_root_bytes) == hasher.digest(): + # set trustedroot + self._trusted_set.update_root_spec_rotation(actual_bytes) + + # try update again, checking for new supported versions first + self._spec_version = supported_version + + # persist the version number + self._persist_metadata( + "spec_version", + json.dumps({"version": self._spec_version}).encode("utf-8"), + ) + + self._load_root() + else: + # error loading new version, stay with this version + self._spec_version_dir = save_dir # Update the root role lower_bound = self._trusted_set.root.signed.version + 1 upper_bound = lower_bound + self.config.max_root_rotations - for version_repo in supported_version_repos: - self._spec_version_dir = version_repo - for next_version in range(lower_bound, upper_bound): - try: - data = self._download_metadata( - Root.type, - self.config.root_max_length, - next_version, - ) - self._trusted_set.update_root(data) - self._persist_metadata(Root.type, data) - # check if supported_versions was updated in this root - repository_versions_and_paths = ( - self._get_repository_versions() - ) - supported_version_repos = self._find_matching_spec_version( - repository_versions_and_paths - ) - # if found, don't check older versions - lower_bound = self._trusted_set.root.signed.version + 1 - - except exceptions.DownloadHTTPError as exception: - if exception.status_code not in {403, 404}: - raise - # 404/403 means current root is newest available - break - - # self._spec_version_dir = save_repo_version_dir + for next_version in range(lower_bound, upper_bound): + try: + data = self._download_metadata( + Root.type, + self.config.root_max_length, + next_version, + ) + self._trusted_set.update_root(data) + self._persist_metadata(Root.type, data) + # check if supported_versions was updated in this root + repository_versions = self._get_repository_versions() + new_supported_version, _, _ = self._find_matching_spec_version( + repository_versions + ) + # if found, recurse to try loading new spec version + if int(new_supported_version) > int(self._spec_version): + self._load_root() + + except exceptions.DownloadHTTPError as exception: + if exception.status_code not in {403, 404}: + raise + # 404/403 means current root is newest available + break def _load_timestamp(self) -> None: """Load local and remote timestamp metadata""" From db67863b1d63cfd867bf192395dad3c25b71ba5a Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Fri, 21 Oct 2022 16:45:20 -0400 Subject: [PATCH 36/40] format tests Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 69df406c94..94218259f4 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -450,7 +450,9 @@ def _set_supported_version_v2(root: Metadata) -> None: repo_version = [{"version": 2}] root.signed.supported_versions = repo_version - self._modify_repository_root(_set_supported_version_v2, bump_version=True) + self._modify_repository_root( + _set_supported_version_v2, bump_version=True + ) # copy the current metadata to 2/ shutil.copytree( @@ -512,7 +514,9 @@ def _set_supported_version_v2(root: Metadata) -> None: ] root.signed.supported_versions = repo_version - self._modify_repository_root(_set_supported_version_v2, bump_version=True) + self._modify_repository_root( + _set_supported_version_v2, bump_version=True + ) # copy the current metadata to 2/ shutil.copytree( @@ -609,7 +613,9 @@ def _set_supported_version_v2(root: Metadata) -> None: ] root.signed.supported_versions = repo_version - self._modify_repository_root(_set_supported_version_v2, bump_version=True) + self._modify_repository_root( + _set_supported_version_v2, bump_version=True + ) # move this metadata to 2/ shutil.copytree( @@ -674,7 +680,9 @@ def _set_supported_version_v2(root: Metadata) -> None: ] root.signed.supported_versions = repo_version - self._modify_repository_root(_set_supported_version_v2, bump_version=True) + self._modify_repository_root( + _set_supported_version_v2, bump_version=True + ) # move this metadata to 2/ shutil.copytree( From 4b5bf7eed32071a98378dce20f5c211b36193ca9 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 24 Oct 2022 09:32:45 -0400 Subject: [PATCH 37/40] remove flag not supported in python < 3.8 Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 94218259f4..ec92082bf3 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -17,11 +17,11 @@ from typing import Callable, ClassVar, List, Tuple from unittest.mock import MagicMock, patch +from securesystemslib import hash as sslib_hash from securesystemslib.interface import import_rsa_privatekey_from_file from securesystemslib.signer import SSlibSigner from securesystemslib.storage import FilesystemBackend from securesystemslib.util import persist_temp_file -from securesystemslib import hash as sslib_hash from tests import utils from tuf import ngclient @@ -461,10 +461,11 @@ def _set_supported_version_v2(root: Metadata) -> None: ) # switch back to version 1 - shutil.copytree( - os.path.join(self.repository_directory, "metadata", "1"), - os.path.join(self.repository_directory, "metadata"), - dirs_exist_ok=True, + shutil.copyfile( + os.path.join( + self.repository_directory, "metadata", "1", "1.root.json" + ), + os.path.join(self.repository_directory, "metadata", "1.root.json"), ) # get root digest @@ -525,10 +526,11 @@ def _set_supported_version_v2(root: Metadata) -> None: ) # switch back to version 1 - shutil.copytree( - os.path.join(self.repository_directory, "metadata", "1"), - os.path.join(self.repository_directory, "metadata"), - dirs_exist_ok=True, + shutil.copyfile( + os.path.join( + self.repository_directory, "metadata", "1", "1.root.json" + ), + os.path.join(self.repository_directory, "metadata", "1.root.json"), ) # get root digest @@ -624,10 +626,11 @@ def _set_supported_version_v2(root: Metadata) -> None: ) # switch back to version 1 - shutil.copytree( - os.path.join(self.repository_directory, "metadata", "1"), - os.path.join(self.repository_directory, "metadata"), - dirs_exist_ok=True, + shutil.copyfile( + os.path.join( + self.repository_directory, "metadata", "1", "1.root.json" + ), + os.path.join(self.repository_directory, "metadata", "1.root.json"), ) # get root digest @@ -691,10 +694,11 @@ def _set_supported_version_v2(root: Metadata) -> None: ) # switch back to version 1 - shutil.copytree( - os.path.join(self.repository_directory, "metadata", "1"), - os.path.join(self.repository_directory, "metadata"), - dirs_exist_ok=True, + shutil.copyfile( + os.path.join( + self.repository_directory, "metadata", "1", "1.root.json" + ), + os.path.join(self.repository_directory, "metadata", "1.root.json"), ) # get root digest From a2e58e20624ce6fafbc84323b8fffca4be4b87c3 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 24 Oct 2022 09:43:07 -0400 Subject: [PATCH 38/40] clarify partition Signed-off-by: Marina Moore --- tests/repository_simulator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/repository_simulator.py b/tests/repository_simulator.py index 3f8d6f5643..528a235f9b 100644 --- a/tests/repository_simulator.py +++ b/tests/repository_simulator.py @@ -207,13 +207,13 @@ def _fetch(self, url: str) -> Iterator[bytes]: ver_and_name = path[len("/metadata/") :][: -len(".json")] # inside a version folder if "/" in ver_and_name: - ver_and_name = ver_and_name.split("/")[1] + ver_and_name_split = ver_and_name.partition("/") + assert len(ver_and_name_split) == 3 + ver_and_name = ver_and_name_split[2] version_str, _, role = ver_and_name.partition(".") # root is always version-prefixed while timestamp is always NOT if role == Root.type or ( - self.root.consistent_snapshot - and ver_and_name != Timestamp.type - and ver_and_name != "supported-versions" + self.root.consistent_snapshot and ver_and_name != Timestamp.type ): version: Optional[int] = int(version_str) else: From e77f033880244e50caed22674f163aac7f4ae32c Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 31 Oct 2022 11:26:58 -0400 Subject: [PATCH 39/40] Add feature to supported versions Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 122 ++++++++++++++++++++++++--- tuf/ngclient/updater.py | 173 +++++++++++++++++++++++---------------- 2 files changed, 213 insertions(+), 82 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index ec92082bf3..85101233c7 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -34,7 +34,6 @@ Targets, Timestamp, ) -from tuf.ngclient.updater import _get_spec_version logger = logging.getLogger(__name__) @@ -366,52 +365,67 @@ def test_get_spec_version_supported(self) -> None: exceptions.RepositoryError, msg="Latest repository version less than 4", ): - _get_spec_version( - ["1", "2", "3"], "4", ngclient.updater.SUPPORTED_VERSIONS + self.updater._get_spec_version( + ["1", "2", "3"], [""], "4", ngclient.updater.SUPPORTED_VERSIONS ) self.assertEqual( - _get_spec_version(["1", "2", "3"], "3", ["3"]), - ("3"), + self.updater._get_spec_version( + ["1", "2", "3"], ["", "", ""], "3", ["3"] + ), + ("3", ""), "3 is selected as the spec version and no warning ensues", ) def test_get_spec_version(self) -> None: # warningchecker = "Not using the latest specification version available on the repository" # Checks with different values - test_cases: List[Tuple[List[str], str, List[str]]] = [ + test_cases: List[Tuple[List[str], List[str], str, List[str]]] = [ ( ["3", "5", "6"], + ["", "", ""], "7", ["1", "2", "3", "4"], ), # Latest repository version less than 7 ( ["3", "5", "6"], + ["", "", ""], "3", ["1", "2", "4"], ), # No common specification version between repository and client ] - for repo_versions, spec_version, supported_versions in test_cases: + for ( + repo_versions, + repo_features, + spec_version, + supported_versions, + ) in test_cases: with self.assertRaises(exceptions.RepositoryError): - _get_spec_version( - repo_versions, spec_version, supported_versions + self.updater._get_spec_version( + repo_versions, + repo_features, + spec_version, + supported_versions, ) - test_cases_2: List[Tuple[List[str], str, List[str], str]] = [ + test_cases_2: List[Tuple[List[str], List[str], str, List[str], str]] = [ ( ["3", "5", "6"], + ["", "", ""], "3", ["1", "2", "3", "4"], "3", ), # 3 is selected as the spec version but a warning ensues ( ["1", "2", "3"], + ["", "", ""], "3", ["3", "5", "6"], "3", ), # 3 is selected as the spec version and no warning ensues ( ["8", "11", "13"], + ["", "", ""], "12", ["8", "11", "12"], "11", @@ -420,12 +434,13 @@ def test_get_spec_version(self) -> None: for t in test_cases_2: ( repo_versions, + repo_features, spec_version, supported_versions, expected_version, ) = t - actual_version = _get_spec_version( - repo_versions, spec_version, supported_versions + actual_version, _ = self.updater._get_spec_version( + repo_versions, repo_features, spec_version, supported_versions ) self.assertEqual(actual_version, expected_version) # TODO ensure warning was logged for case 1 and 3 @@ -482,6 +497,8 @@ def _set_supported_version(root: Metadata) -> None: {"version": 1}, { "version": 2, + "path": "2/", + "features": "", "root-filename": "2.root.json", "root-digest": root_digest.decode("utf-8"), }, @@ -509,6 +526,8 @@ def _set_supported_version_v2(root: Metadata) -> None: {"version": 2}, { "version": 3, + "path": "3/", + "features": "", "root-filename": "wontuse", "root-digest": "wontuse", }, @@ -547,6 +566,8 @@ def _set_supported_version(root: Metadata) -> None: {"version": 1}, { "version": 2, + "path": "2/", + "features": "", "root-filename": "2.root.json", "root-digest": root_digest.decode("utf-8"), }, @@ -647,6 +668,8 @@ def _set_supported_version(root: Metadata) -> None: {"version": 1}, { "version": 2, + "path": "2/", + "features": "", "root-filename": "2.root.json", "root-digest": root_digest.decode("utf-8"), }, @@ -717,6 +740,8 @@ def _set_supported_version(root: Metadata) -> None: {"version": 1}, { "version": 2, + "path": "2/", + "features": "", "root-filename": "3.root.json", "root-digest": root_digest.decode("utf-8"), }, @@ -732,6 +757,79 @@ def _set_supported_version(root: Metadata) -> None: self.assertEqual(self.updater._trusted_set.root.signed.version, 3) self.assertEqual(self.updater._spec_version, "2") + def test_feature_change(self) -> None: + # switch client supported versions + self.updater._supported_versions = ["1"] + self.updater._supported_features = ["new_features"] + + # copy the current metadata to 1/ + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "1"), + ) + + # self._modify_repository_root( + # lambda root: None, bump_version=True + # ) + + # switch repository supported versions + def _set_supported_version_v2(root: Metadata) -> None: + repo_version = [ + {"version": 1, "path": "feature/", "features": "new_features"} + ] + root.signed.supported_versions = repo_version + + self._modify_repository_root( + _set_supported_version_v2, bump_version=False + ) + + # copy the current metadata to feature/ + shutil.copytree( + os.path.join(self.repository_directory, "metadata"), + os.path.join(self.repository_directory, "metadata", "feature"), + ) + + # switch back to version 1 + shutil.copytree( + os.path.join(self.repository_directory, "metadata", "1"), + os.path.join(self.repository_directory, "metadata"), + dirs_exist_ok=True, + ) + # shutil.copyfile( + # os.path.join( + # self.repository_directory, "metadata", "1", "1.root.json" + # ), + # os.path.join(self.repository_directory, "metadata", "1.root.json"), + # ) + + # get root digest + root_path = os.path.join( + self.repository_directory, "metadata", "feature", "1.root.json" + ) + with open(root_path, "rb") as f: + hasher = sslib_hash.digest_fileobject(f, algorithm="sha256") + root_digest = base64.b64encode(hasher.digest()) + + # set supported versions in root + def _set_supported_version(root: Metadata) -> None: + repo_version = [ + { + "version": 1, + "path": "feature/", + "features": "new_features", + "root-filename": "1.root.json", + "root-digest": root_digest.decode("utf-8"), + }, + {"version": 1}, + ] + root.signed.supported_versions = repo_version + + self._modify_repository_root(_set_supported_version, bump_version=True) + + self.updater.refresh() + self.assertEqual(self.updater._spec_version, "1") + self.assertEqual(self.updater._spec_version_dir, "feature/") + if __name__ == "__main__": utils.configure_test_logging(sys.argv) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index b611ddf72a..36498d32b9 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -62,6 +62,7 @@ logger = logging.getLogger(__name__) # only include the major version SUPPORTED_VERSIONS = [SPECIFICATION_VERSION[0]] +SUPPORTED_FEATURES = [""] class Updater: @@ -110,6 +111,7 @@ def __init__( self._fetcher = fetcher or requests_fetcher.RequestsFetcher() self.config = config or UpdaterConfig() self._supported_versions = SUPPORTED_VERSIONS + self._supported_features = SUPPORTED_FEATURES def refresh(self) -> None: """Refreshes top-level metadata. @@ -162,25 +164,42 @@ def _set_spec_version(self) -> None: def _find_matching_spec_version( self, repository_versions_dicts: List[dict] - ) -> Tuple[str, str, str]: + ) -> Tuple[str, str, str, str]: """Find the set of spec versions that match between the client and repository. Returns the largest matching version and information about - the new root + the new root and its path """ repository_versions = [i["version"] for i in repository_versions_dicts] + repository_features = [ + i["features"] if "features" in i else "" + for i in repository_versions_dicts + ] # Updating self.spec_version - spec_version = _get_spec_version( - repository_versions, self._spec_version, self._supported_versions + spec_version, features = self._get_spec_version( + repository_versions, + repository_features, + self._spec_version, + self._supported_versions, ) for i in repository_versions_dicts: - if i["version"] == int(spec_version): + if i["version"] == int(spec_version) and ( + "features" not in i or i["features"] == features + ): + new_path = self._spec_version_dir + if "path" in i: + new_path = i["path"] if "root-filename" in i and "root-digest" in i: - return spec_version, i["root-filename"], i["root-digest"] + return ( + spec_version, + i["root-filename"], + i["root-digest"], + new_path, + ) # root info will be empty if the version does not change - return spec_version, "", "" + return spec_version, "", "", new_path # we shouldn't get here... raise ValueError("current repository version not found") @@ -383,13 +402,14 @@ def _load_root(self) -> None: supported_version, new_root_filename, new_root_bytes, + new_spec_version_path, ) = self._find_matching_spec_version(self._get_repository_versions()) # if compatible version higher than current, jump to that root # call _load_root in new version - if int(supported_version) > int(self._spec_version): + if new_spec_version_path != self._spec_version_dir: save_dir = self._spec_version_dir - self._spec_version_dir = supported_version + "/" + self._spec_version_dir = new_spec_version_path actual_bytes = self._download_new_spec_root( new_root_filename, self.config.root_max_length ) @@ -409,6 +429,7 @@ def _load_root(self) -> None: ) self._load_root() + return else: # error loading new version, stay with this version self._spec_version_dir = save_dir @@ -428,12 +449,16 @@ def _load_root(self) -> None: self._persist_metadata(Root.type, data) # check if supported_versions was updated in this root repository_versions = self._get_repository_versions() - new_supported_version, _, _ = self._find_matching_spec_version( - repository_versions - ) - # if found, recurse to try loading new spec version - if int(new_supported_version) > int(self._spec_version): + ( + new_supported_version, + _, + _, + new_path, + ) = self._find_matching_spec_version(repository_versions) + # if path changed, recurse to try loading new spec version + if self._spec_version_dir != new_path: self._load_root() + return except exceptions.DownloadHTTPError as exception: if exception.status_code not in {403, 404}: @@ -589,67 +614,75 @@ def _preorder_depth_first_walk( # If this point is reached then target is not found, return None return None + def _get_spec_version( + self, + repository_versions: List[str], + repository_features: List[str], + spec_version: str, + supported_versions: List[str], + ) -> Tuple[str, str]: + """Returns the specification version and features to be used, following the rules of TAP-14 + and displays a warning if chosen spec_version is lower than the highest repository version. -def _ensure_trailing_slash(url: str) -> str: - """Return url guaranteed to end in a slash""" - return url if url.endswith("/") else f"{url}/" + Raises: + ValueError: supported_versions, repository_version or spec_version contains an + invalid entry (not parseable as ``int()``) + RepositoryError: Latest repository version lower than the last used version from + this repository + RepositoryError: No matching version found between supported_versions and repository_versions + """ + repository_versions_int = [int(i) for i in repository_versions] + supported_versions_int = [int(i) for i in supported_versions] + spec_version_int = int(spec_version) + + # The client determines the latest version available on the repository by looking + # for the directory with the largest version number. + latest_repo_version = max(repository_versions_int) + + # If the latest version on the repository is lower than the previous specification + # version the client used from this repository, the client should report an error + # and terminate the update. + if latest_repo_version < spec_version_int: + raise exceptions.RepositoryError( + f"The latest repository version ({latest_repo_version}) is lower than the last used spec version ({spec_version})." + ) + # If the latest version on the repository is equal to that of the client, it will use this directory to download metadata. -def _get_spec_version( - repository_versions: List[str], - spec_version: str, - supported_versions: List[str], -) -> str: - """Returns the specification version to be used, following the rules of TAP-14 - and displays a warning if chosen spec_version is lower than the highest repository version. + # If the latest version pre-dates the client specification version, it may call functions from a previous client version + # to download the metadata. The client may support as many or as few versions as desired for the application. If the + # previous version is not available, the client shall report that an update can not be performed due to an old + # specification version on the repository. - Raises: - ValueError: supported_versions, repository_version or spec_version contains an - invalid entry (not parseable as ``int()``) - RepositoryError: Latest repository version lower than the last used version from - this repository - RepositoryError: No matching version found between supported_versions and repository_versions - """ - repository_versions_int = [int(i) for i in repository_versions] - supported_versions_int = [int(i) for i in supported_versions] - spec_version_int = int(spec_version) - - # The client determines the latest version available on the repository by looking - # for the directory with the largest version number. - latest_repo_version = max(repository_versions_int) - - # If the latest version on the repository is lower than the previous specification - # version the client used from this repository, the client should report an error - # and terminate the update. - if latest_repo_version < spec_version_int: - raise exceptions.RepositoryError( - f"The latest repository version ({latest_repo_version}) is lower than the last used spec version ({spec_version})." - ) + # If the latest version on the repository is higher than the client spec version, the client should report + # to the user that it is not using the most up to date version, and then perform the update with the directory + # that corresponds with the latest client specification version, if available. If no such directory exists, + # the client terminates the update. + try: + spec_version_int = max( + set(repository_versions_int) & set(supported_versions_int) + ) + except ValueError as e: + raise exceptions.RepositoryError( + f"No matching specification version found. Found {repository_versions} in" + f"repository and {supported_versions} in client." + ) from e + + if latest_repo_version > spec_version_int: + logger.warning( + "Not using the latest specification version available on the repository" + ) - # If the latest version on the repository is equal to that of the client, it will use this directory to download metadata. + features = "" + for i in range(len(repository_versions_int)): + if repository_versions_int[i] == spec_version_int: + # current version, check for valid features + if repository_features[i] in self._supported_features: + features = repository_features[i] - # If the latest version pre-dates the client specification version, it may call functions from a previous client version - # to download the metadata. The client may support as many or as few versions as desired for the application. If the - # previous version is not available, the client shall report that an update can not be performed due to an old - # specification version on the repository. + return str(spec_version_int), features - # If the latest version on the repository is higher than the client spec version, the client should report - # to the user that it is not using the most up to date version, and then perform the update with the directory - # that corresponds with the latest client specification version, if available. If no such directory exists, - # the client terminates the update. - try: - spec_version_int = max( - set(repository_versions_int) & set(supported_versions_int) - ) - except ValueError as e: - raise exceptions.RepositoryError( - f"No matching specification version found. Found {repository_versions} in" - f"repository and {supported_versions} in client." - ) from e - - if latest_repo_version > spec_version_int: - logger.warning( - "Not using the latest specification version available on the repository" - ) - return str(spec_version_int) +def _ensure_trailing_slash(url: str) -> str: + """Return url guaranteed to end in a slash""" + return url if url.endswith("/") else f"{url}/" From d491d46c727a91b5caed605a05a4e3bdcb50a959 Mon Sep 17 00:00:00 2001 From: Marina Moore Date: Mon, 31 Oct 2022 11:43:24 -0400 Subject: [PATCH 40/40] fix lint Signed-off-by: Marina Moore --- tests/test_updater_ng.py | 15 +++++---------- tuf/ngclient/updater.py | 15 +++++++-------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/tests/test_updater_ng.py b/tests/test_updater_ng.py index 85101233c7..60b7a4d4f8 100644 --- a/tests/test_updater_ng.py +++ b/tests/test_updater_ng.py @@ -790,17 +790,12 @@ def _set_supported_version_v2(root: Metadata) -> None: ) # switch back to version 1 - shutil.copytree( - os.path.join(self.repository_directory, "metadata", "1"), - os.path.join(self.repository_directory, "metadata"), - dirs_exist_ok=True, + shutil.copyfile( + os.path.join( + self.repository_directory, "metadata", "1", "1.root.json" + ), + os.path.join(self.repository_directory, "metadata", "1.root.json"), ) - # shutil.copyfile( - # os.path.join( - # self.repository_directory, "metadata", "1", "1.root.json" - # ), - # os.path.join(self.repository_directory, "metadata", "1.root.json"), - # ) # get root digest root_path = os.path.join( diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 36498d32b9..6223b29c1f 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -430,9 +430,8 @@ def _load_root(self) -> None: self._load_root() return - else: - # error loading new version, stay with this version - self._spec_version_dir = save_dir + # error loading new version, stay with this version + self._spec_version_dir = save_dir # Update the root role lower_bound = self._trusted_set.root.signed.version + 1 @@ -450,13 +449,13 @@ def _load_root(self) -> None: # check if supported_versions was updated in this root repository_versions = self._get_repository_versions() ( - new_supported_version, _, _, - new_path, + _, + new_spec_version_path, ) = self._find_matching_spec_version(repository_versions) # if path changed, recurse to try loading new spec version - if self._spec_version_dir != new_path: + if self._spec_version_dir != new_spec_version_path: self._load_root() return @@ -674,8 +673,8 @@ def _get_spec_version( ) features = "" - for i in range(len(repository_versions_int)): - if repository_versions_int[i] == spec_version_int: + for i, v in enumerate(repository_versions_int): + if v == spec_version_int: # current version, check for valid features if repository_features[i] in self._supported_features: features = repository_features[i]