Skip to content

Commit 05c2959

Browse files
author
Jussi Kukkonen
authored
Merge pull request #1915 from MVrachev/test-statics-data-generation
Tests: provide a way to generate a simple metadata set
2 parents b272ac7 + 384772e commit 05c2959

8 files changed

Lines changed: 297 additions & 3 deletions

File tree

.gitattributes

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
# Files that will always have LF line endings on checkout.
2-
tests/repository_data/** text eol=lf
3-
1+
# All JSON files will always have LF line endings on checkout.
2+
# This prevents git replacing line endings with CRLF on Windows.
3+
*.json text eol=lf

tests/generated_data/__init__.py

Whitespace-only changes.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{
2+
"signatures": [
3+
{
4+
"keyid": "5822582e7072996c1eef1cec24b61115d364987faa486659fe3d3dce8dae2aba",
5+
"sig": "e2cfb42fe355843c5284ca0bd58acb742a232c2c7b93a87c34ed086cfe51c41a21f77bb8d4ed0c74f9fb3f76f48f7005488347450c28468d8bb288e5988ae201"
6+
}
7+
],
8+
"signed": {
9+
"_type": "root",
10+
"consistent_snapshot": true,
11+
"expires": "2050-01-01T00:00:00Z",
12+
"keys": {
13+
"09d440e3725cec247dcb8703b646a87dd2a4d75343e8095c036c32795eefe3b9": {
14+
"keytype": "ed25519",
15+
"keyval": {
16+
"public": "250f9ae3d1d3d5c419a73cfb4a470c01de1d5d3d61a3825416b5f5d6b88f4a30"
17+
},
18+
"scheme": "ed25519"
19+
},
20+
"2be5c21e3614f9f178fb49c4a34d0c18ffac30abd14ced917c60a52c8d8094b7": {
21+
"keytype": "ed25519",
22+
"keyval": {
23+
"public": "0e6738fc1ac6fb4de680b4be99ecbcd99b030f3963f291277eef67bb9bd123e9"
24+
},
25+
"scheme": "ed25519"
26+
},
27+
"3458204ed467519c19a5316eb278b5608472a1bbf15850ebfb462d5315e4f86d": {
28+
"keytype": "ed25519",
29+
"keyval": {
30+
"public": "82380623abb9666d4bf274b1a02577469445a972e5650d270101faa5107b19c8"
31+
},
32+
"scheme": "ed25519"
33+
},
34+
"5822582e7072996c1eef1cec24b61115d364987faa486659fe3d3dce8dae2aba": {
35+
"keytype": "ed25519",
36+
"keyval": {
37+
"public": "b11d2ff132c033a657318c74c39526476c56de7556c776f11070842dbc4ac14c"
38+
},
39+
"scheme": "ed25519"
40+
}
41+
},
42+
"roles": {
43+
"root": {
44+
"keyids": [
45+
"5822582e7072996c1eef1cec24b61115d364987faa486659fe3d3dce8dae2aba"
46+
],
47+
"threshold": 1
48+
},
49+
"snapshot": {
50+
"keyids": [
51+
"3458204ed467519c19a5316eb278b5608472a1bbf15850ebfb462d5315e4f86d"
52+
],
53+
"threshold": 1
54+
},
55+
"targets": {
56+
"keyids": [
57+
"2be5c21e3614f9f178fb49c4a34d0c18ffac30abd14ced917c60a52c8d8094b7"
58+
],
59+
"threshold": 1
60+
},
61+
"timestamp": {
62+
"keyids": [
63+
"09d440e3725cec247dcb8703b646a87dd2a4d75343e8095c036c32795eefe3b9"
64+
],
65+
"threshold": 1
66+
}
67+
},
68+
"spec_version": "1.0.28",
69+
"version": 1
70+
}
71+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"signatures": [
3+
{
4+
"keyid": "3458204ed467519c19a5316eb278b5608472a1bbf15850ebfb462d5315e4f86d",
5+
"sig": "40853c2711d5ea49066c6b27a078f9e65419e0a4a3e298b75204e83713fe1d8ae9db91eccda5a8bfc14a5d71b3862c3ab27339db630056948ca0548a3e0edf03"
6+
}
7+
],
8+
"signed": {
9+
"_type": "snapshot",
10+
"expires": "2050-01-01T00:00:00Z",
11+
"meta": {
12+
"targets.json": {
13+
"version": 1
14+
}
15+
},
16+
"spec_version": "1.0.28",
17+
"version": 1
18+
}
19+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"signatures": [
3+
{
4+
"keyid": "2be5c21e3614f9f178fb49c4a34d0c18ffac30abd14ced917c60a52c8d8094b7",
5+
"sig": "2954a14e207e8de2e5a2f9c88cfe99c56d357b7c9fa4c5f4ad9496279a6a7e253cf80bcd109467bb2ff8b9691d240fef18aaf55ee24a22e8d2432338f6bbc40b"
6+
}
7+
],
8+
"signed": {
9+
"_type": "targets",
10+
"expires": "2050-01-01T00:00:00Z",
11+
"spec_version": "1.0.28",
12+
"targets": {},
13+
"version": 1
14+
}
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"signatures": [
3+
{
4+
"keyid": "09d440e3725cec247dcb8703b646a87dd2a4d75343e8095c036c32795eefe3b9",
5+
"sig": "c9094d7b773277f7acf040949358b684bd09be53be1deaaa7e1c5513bb30ded125dca1dd9d0893c542d52d53f555c85dca960ab147852757c0f5f7399787a704"
6+
}
7+
],
8+
"signed": {
9+
"_type": "timestamp",
10+
"expires": "2050-01-01T00:00:00Z",
11+
"meta": {
12+
"snapshot.json": {
13+
"version": 1
14+
}
15+
},
16+
"spec_version": "1.0.28",
17+
"version": 1
18+
}
19+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
"""Script for generating new metadata files."""
2+
3+
# Copyright New York University and the TUF contributors
4+
# SPDX-License-Identifier: MIT OR Apache-2.0
5+
6+
import os
7+
import sys
8+
from datetime import datetime
9+
from typing import Dict, List, Optional
10+
11+
from securesystemslib.signer import SSlibSigner
12+
13+
from tests import utils
14+
from tuf.api.metadata import (
15+
SPECIFICATION_VERSION,
16+
TOP_LEVEL_ROLE_NAMES,
17+
Key,
18+
Metadata,
19+
MetaFile,
20+
Role,
21+
Root,
22+
Snapshot,
23+
Targets,
24+
Timestamp,
25+
)
26+
from tuf.api.serialization.json import JSONSerializer
27+
28+
# Hardcode keys and expiry time to achieve reproducibility.
29+
public_values: List[str] = [
30+
"b11d2ff132c033a657318c74c39526476c56de7556c776f11070842dbc4ac14c",
31+
"250f9ae3d1d3d5c419a73cfb4a470c01de1d5d3d61a3825416b5f5d6b88f4a30",
32+
"82380623abb9666d4bf274b1a02577469445a972e5650d270101faa5107b19c8",
33+
"0e6738fc1ac6fb4de680b4be99ecbcd99b030f3963f291277eef67bb9bd123e9",
34+
]
35+
private_values: List[str] = [
36+
"510e5e04d7a364af850533856eacdf65d30cc0f8803ecd5fdc0acc56ca2aa91c",
37+
"e6645b00312c8a257782e3e61e85bafda4317ad072c52251ef933d480c387abd",
38+
"cd13dd2180334b24c19b32aaf27f7e375a614d7ba0777220d5c2290bb2f9b868",
39+
"7e2e751145d1b22f6e40d4ba2aa47158207acfd3c003f1cbd5a08141dfc22a15",
40+
]
41+
keyids: List[str] = [
42+
"5822582e7072996c1eef1cec24b61115d364987faa486659fe3d3dce8dae2aba",
43+
"09d440e3725cec247dcb8703b646a87dd2a4d75343e8095c036c32795eefe3b9",
44+
"3458204ed467519c19a5316eb278b5608472a1bbf15850ebfb462d5315e4f86d",
45+
"2be5c21e3614f9f178fb49c4a34d0c18ffac30abd14ced917c60a52c8d8094b7",
46+
]
47+
48+
keys: Dict[str, Key] = {}
49+
for index in range(4):
50+
keys[f"ed25519_{index}"] = Key.from_securesystemslib_key(
51+
{
52+
"keytype": "ed25519",
53+
"scheme": "ed25519",
54+
"keyid": keyids[index],
55+
"keyval": {
56+
"public": public_values[index],
57+
"private": private_values[index],
58+
},
59+
}
60+
)
61+
62+
expires_str = "2050-01-01T00:00:00Z"
63+
EXPIRY = datetime.strptime(expires_str, "%Y-%m-%dT%H:%M:%SZ")
64+
SPEC_VERSION = ".".join(SPECIFICATION_VERSION)
65+
OUT_DIR = "generated_data/ed25519_metadata"
66+
if not os.path.exists(OUT_DIR):
67+
os.mkdir(OUT_DIR)
68+
69+
SERIALIZER = JSONSerializer()
70+
ROLES = {role_name: Role([], 1) for role_name in TOP_LEVEL_ROLE_NAMES}
71+
72+
73+
def verify_generation(md: Metadata, path: str) -> None:
74+
"""Verify that newly generated file equals the locally stored one.
75+
76+
Args:
77+
md: Newly generated metadata object.
78+
path: Path to the locally stored metadata file.
79+
"""
80+
with open(path, "rb") as f:
81+
static_md_bytes = f.read()
82+
md_bytes = md.to_bytes(SERIALIZER)
83+
if static_md_bytes != md_bytes:
84+
raise ValueError(
85+
f"Generated data != local data at {path}. Generate a new "
86+
+ "metadata with 'python generated_data/generate_md.py'"
87+
)
88+
89+
90+
def generate_all_files(
91+
dump: Optional[bool] = False, verify: Optional[bool] = False
92+
) -> None:
93+
"""Generate a new repository and optionally verify it.
94+
95+
Args:
96+
dump: Wheter to dump the newly generated files.
97+
verify: Whether to verify the newly generated files with the
98+
local staored.
99+
"""
100+
root = Root(1, SPEC_VERSION, EXPIRY, {}, ROLES, True)
101+
root.add_key("root", keys["ed25519_0"])
102+
root.add_key("timestamp", keys["ed25519_1"])
103+
root.add_key("snapshot", keys["ed25519_2"])
104+
root.add_key("targets", keys["ed25519_3"])
105+
106+
md_root: Metadata[Root] = Metadata(root, {})
107+
108+
timestamp = Timestamp(1, SPEC_VERSION, EXPIRY, MetaFile(1))
109+
md_timestamp: Metadata[Timestamp] = Metadata(timestamp, {})
110+
111+
meta: Dict[str, MetaFile] = {"targets.json": MetaFile(1)}
112+
snapshot = Snapshot(1, SPEC_VERSION, EXPIRY, meta)
113+
md_snapshot: Metadata[Snapshot] = Metadata(snapshot, {})
114+
115+
targets = Targets(1, SPEC_VERSION, EXPIRY, {})
116+
md_targets: Metadata[Targets] = Metadata(targets, {})
117+
118+
for i, md in enumerate([md_root, md_timestamp, md_snapshot, md_targets]):
119+
assert isinstance(md, Metadata)
120+
signer = SSlibSigner(
121+
{
122+
"keytype": "ed25519",
123+
"scheme": "ed25519",
124+
"keyid": keyids[i],
125+
"keyval": {
126+
"public": public_values[i],
127+
"private": private_values[i],
128+
},
129+
}
130+
)
131+
md.sign(signer)
132+
path = os.path.join(OUT_DIR, f"{md.signed.type}_with_ed25519.json")
133+
if verify:
134+
verify_generation(md, path)
135+
136+
if dump:
137+
md.to_file(path, SERIALIZER)
138+
139+
140+
if __name__ == "__main__":
141+
utils.configure_test_logging(sys.argv)
142+
# To generate a new set of metadata files this script is supposed to be run
143+
# from the "tests" folder.
144+
generate_all_files(dump=True)

tests/test_metadata_generation.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Unit tests for 'tests/generated_data/generate_md.py'."""
2+
3+
# Copyright New York University and the TUF contributors
4+
# SPDX-License-Identifier: MIT OR Apache-2.0
5+
6+
7+
import sys
8+
import unittest
9+
10+
from tests import utils
11+
from tests.generated_data.generate_md import generate_all_files
12+
13+
14+
class TestMetadataGeneration(unittest.TestCase):
15+
"""Test metadata files generation."""
16+
17+
@staticmethod
18+
def test_compare_static_md_to_generated() -> None:
19+
# md_generator = MetadataGenerator("generated_data/ed25519_metadata")
20+
generate_all_files(dump=False, verify=True)
21+
22+
23+
# Run unit test.
24+
if __name__ == "__main__":
25+
utils.configure_test_logging(sys.argv)
26+
unittest.main()

0 commit comments

Comments
 (0)