Skip to content

Commit

Permalink
Merge pull request #150 from jku/static-tests
Browse files Browse the repository at this point in the history
Static tests
  • Loading branch information
jku authored Aug 15, 2024
2 parents 94bcfb2 + c399662 commit e380ad0
Show file tree
Hide file tree
Showing 16 changed files with 487 additions and 3 deletions.
8 changes: 6 additions & 2 deletions tuf_conformance/client_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
from tuf.api.metadata import Metadata

from tuf_conformance.metadata import MetadataTest
from tuf_conformance.simulator_server import ClientInitData, SimulatorServer
from tuf_conformance.simulator_server import (
ClientInitData,
SimulatorServer,
StaticServer,
)


class ClientRunner:
Expand All @@ -19,7 +23,7 @@ class ClientRunner:
ClientRunner manages client resources (like the cache paths etc)"""

def __init__(
self, client_cmd: str, server: SimulatorServer, test_name: str
self, client_cmd: str, server: SimulatorServer | StaticServer, test_name: str
) -> None:
self._server = server
self._cmd = client_cmd.split(" ")
Expand Down
28 changes: 27 additions & 1 deletion tuf_conformance/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pytest

from tuf_conformance.client_runner import ClientRunner
from tuf_conformance.simulator_server import SimulatorServer
from tuf_conformance.simulator_server import SimulatorServer, StaticServer


def pytest_addoption(parser: pytest.Parser) -> None:
Expand Down Expand Up @@ -43,6 +43,16 @@ def server(pytestconfig: pytest.Config) -> Iterator[SimulatorServer]:
server.server_close()


@pytest.fixture
def static_server(pytestconfig: pytest.Config) -> Iterator[StaticServer]:
"""
Server that serves static repositories
"""
server = StaticServer()
yield server
server.server_close()


@pytest.fixture
def client(
pytestconfig: pytest.Config, server: SimulatorServer, request: pytest.FixtureRequest
Expand All @@ -57,6 +67,22 @@ def client(
return ClientRunner(entrypoint, server, request.node.name)


@pytest.fixture
def static_client(
pytestconfig: pytest.Config,
static_server: StaticServer,
request: pytest.FixtureRequest,
) -> ClientRunner:
"""
Client for running static repository tests.
"""
entrypoint = pytestconfig.getoption("--entrypoint")
if not os.path.isabs(entrypoint):
entrypoint = os.path.join(pytestconfig.invocation_params.dir, entrypoint)

return ClientRunner(entrypoint, static_server, request.node.name)


@pytest.fixture(autouse=True)
def conformance_xfail(
pytestconfig: pytest.Config, request: pytest.FixtureRequest
Expand Down
45 changes: 45 additions & 0 deletions tuf_conformance/simulator_server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from dataclasses import dataclass
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from os import path
Expand Down Expand Up @@ -82,3 +83,47 @@ def new_test(self, name: str) -> tuple[ClientInitData, RepositorySimulator]:

def debug_dump(self, test_name: str) -> None:
self.repos[test_name].debug_dump()


class StaticServer(ThreadingHTTPServer):
"""Web server to serve static repositories"""

def __init__(self) -> None:
class _StaticReqHandler(BaseHTTPRequestHandler):
def do_GET(self) -> None: # noqa: N802
filepath = os.path.join("tuf_conformance", "static_data", self.path[1:])
try:
with open(filepath, "rb") as f:
data = f.read()
except OSError:
self.send_error(404, f" {self.path} not found")
return

self.send_response(200)
self.send_header("Content-length", str(len(data)))
self.end_headers()
self.wfile.write(data)

super().__init__(("127.0.0.1", 0), _StaticReqHandler)
self.timeout = 0

def new_test(self, static_dir: str) -> tuple[ClientInitData, str]:
sub_dir = os.path.join("tuf_conformance", "static_data", static_dir)
with open(os.path.join(sub_dir, "initial_root.json"), "rb") as f:
initial_root = f.read()

host, port = self.server_address[0], self.server_address[1]
assert isinstance(host, str)
client_data = ClientInitData(
f"http://{host}:{port}/{static_dir}/metadata/",
f"http://{host}:{port}/{static_dir}/targets/",
initial_root,
)

with open(os.path.join(sub_dir, "targetpath")) as f:
targetpath = f.readline().strip("\n")

return client_data, targetpath

def debug_dump(self, test_name: str) -> None:
pass # not implemented
13 changes: 13 additions & 0 deletions tuf_conformance/static_data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Static test data from actual repository implementations

Subdirectories should contain complete repositories produced by a specific repository
implementation. Each repository in a `<SUBDIR>` should
* demonstrate all of the TUF features that the implementation uses
* not expire for a very long time
* Store metadata in `<SUBDIR/metadata>` and artifacts in `<SUBDIR/targets>`
* be ready to be published with just `python -m http.server <SUBDIR>` (in other words filenames
should match the TUF http API)

Additionally there should be
* A version of root in `<SUBDIR>/initial_root.json`: This will be used to initialize the client
* `<SUBDIR>/targetpath` containing a targetpath of an artifact that exists in the repository
10 changes: 10 additions & 0 deletions tuf_conformance/static_data/tuf-on-ci-0.11/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This is a repository created with tuf-on-ci 0.11 in
https://github.com/jku/test-data-for-tuf-conformance.

Notes:
* Contains Yubikey and Google Cloud KMS keys (both in practice ecdsa keys)
* There's one delegated targets role with one artifact
* "Unsigned" keys have an empty signature string in signatures
* The metadata contains custom fields in keys and roles
* Should stay valid until 2044
* There are a few additional files in the metadata dir (index.html, index.md)
65 changes: 65 additions & 0 deletions tuf_conformance/static_data/tuf-on-ci-0.11/initial_root.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"signatures": [
{
"keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81",
"sig": "3045022100e691c6fa8f401a7f6cb6f2fbf5d2596bf50755acdc95d53bbac1bb7f5c2d6bfc02206a85c8ea8015a63d9903588b3bbc5bd563e043cf43fc1b9198a9112e15f2df53"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2044-08-10T10:05:04Z",
"keys": {
"a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu+ebm3VUg6U2b0IIeR6NFZU7uxkL\nR1sVLxV8SEW7G+AMXMasEQf5daxfwVMP1kuEkhGs3mBYLkYXlWDh9BNSxg==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "gcpkms:projects/python-tuf-kms/locations/global/keyRings/git-repo-demo/cryptoKeys/online/cryptoKeyVersions/1"
},
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEohqIdE+yTl4OxpX8ZxNUPrg3SL9H\nBDnhZuceKkxy2oMhUOxhWweZeG3bfM1T4ZLnJimC6CAYVU5+F5jZCoftRw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@jku"
}
},
"roles": {
"root": {
"keyids": [
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81"
],
"threshold": 1
},
"snapshot": {
"keyids": [
"a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 60
},
"targets": {
"keyids": [
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81"
],
"threshold": 1
},
"timestamp": {
"keyids": [
"a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 1
}
},
"spec_version": "1.0.31",
"version": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 60
}
}
65 changes: 65 additions & 0 deletions tuf_conformance/static_data/tuf-on-ci-0.11/metadata/1.root.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"signatures": [
{
"keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81",
"sig": "3045022100e691c6fa8f401a7f6cb6f2fbf5d2596bf50755acdc95d53bbac1bb7f5c2d6bfc02206a85c8ea8015a63d9903588b3bbc5bd563e043cf43fc1b9198a9112e15f2df53"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2044-08-10T10:05:04Z",
"keys": {
"a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEu+ebm3VUg6U2b0IIeR6NFZU7uxkL\nR1sVLxV8SEW7G+AMXMasEQf5daxfwVMP1kuEkhGs3mBYLkYXlWDh9BNSxg==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "gcpkms:projects/python-tuf-kms/locations/global/keyRings/git-repo-demo/cryptoKeys/online/cryptoKeyVersions/1"
},
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEohqIdE+yTl4OxpX8ZxNUPrg3SL9H\nBDnhZuceKkxy2oMhUOxhWweZeG3bfM1T4ZLnJimC6CAYVU5+F5jZCoftRw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@jku"
}
},
"roles": {
"root": {
"keyids": [
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81"
],
"threshold": 1
},
"snapshot": {
"keyids": [
"a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 60
},
"targets": {
"keyids": [
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81"
],
"threshold": 1
},
"timestamp": {
"keyids": [
"a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 1
}
},
"spec_version": "1.0.31",
"version": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 60
}
}
54 changes: 54 additions & 0 deletions tuf_conformance/static_data/tuf-on-ci-0.11/metadata/1.targets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"signatures": [
{
"keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81",
"sig": "3044022027258898a89d38218fce7212c24659ec771105a3532d38ea4ef0d2fb84d9e7ff02206e086d154e3cba72e9c55941d85c61f74eb425e2e90e308636bb1883287290c0"
}
],
"signed": {
"_type": "targets",
"delegations": {
"keys": {
"01104111d18f559cd1ca33a2dd91a2100f2812ffe02c9f70a0e5c4d915b453ac": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1wgTb0BVTvCiDlaPmnUfXOLubQMj\nUxjiafwKLMgiRD0fK+XLSKK6fJjrzNkZCIYG78AUmhbRskgJgOatWD+Z9w==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@-test-user-"
},
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEohqIdE+yTl4OxpX8ZxNUPrg3SL9H\nBDnhZuceKkxy2oMhUOxhWweZeG3bfM1T4ZLnJimC6CAYVU5+F5jZCoftRw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-keyowner": "@jku"
}
},
"roles": [
{
"keyids": [
"aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81",
"01104111d18f559cd1ca33a2dd91a2100f2812ffe02c9f70a0e5c4d915b453ac"
],
"name": "delegatedrole",
"paths": [
"delegatedrole/*",
"delegatedrole/*/*",
"delegatedrole/*/*/*",
"delegatedrole/*/*/*/*"
],
"terminating": true,
"threshold": 1
}
]
},
"expires": "2044-08-10T10:09:31Z",
"spec_version": "1.0.31",
"targets": {},
"version": 1,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 60
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"signatures": [
{
"keyid": "aa61e09f6af7662ac686cf0c6364079f63d3e7a86836684eeced93eace3acd81",
"sig": "30440220396123e307132efdc6910ab3a82a1106d98f8720be7bd4c86ac9481c622d531f02207467ef8d27c9f7bae24c09c7392dfde1b0ad818c96fac1f413f290327611a07d"
},
{
"keyid": "01104111d18f559cd1ca33a2dd91a2100f2812ffe02c9f70a0e5c4d915b453ac",
"sig": ""
}
],
"signed": {
"_type": "targets",
"expires": "2044-08-10T10:18:49Z",
"spec_version": "1.0.31",
"targets": {
"delegatedrole/artifact": {
"hashes": {
"sha256": "45f337ee451b4c098d121d09cc224bacc7794503ac58a47a78cfe7ebefb7fab3"
},
"length": 34
}
},
"version": 2,
"x-tuf-on-ci-expiry-period": 7300,
"x-tuf-on-ci-signing-period": 60
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"signatures": [
{
"keyid": "a54e905f3e03bb0cccdc954bd40d4d29b5c1a2a95c2777f10f9c63a503c7f777",
"sig": "304502202009fa4afd2f4fbad523ebafcc5d22deb3428753c384395147f88265d6ec6f900221009298a6361fcdc1f3226b2f7e8aa056eccd4697ad8077d633f1c17b09f724dd8a"
}
],
"signed": {
"_type": "snapshot",
"expires": "2044-08-10T10:21:51Z",
"meta": {
"delegatedrole.json": {
"version": 2
},
"targets.json": {
"version": 1
}
},
"spec_version": "1.0.31",
"version": 2
}
}
Loading

0 comments on commit e380ad0

Please sign in to comment.