Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat:checking that the client is allowed to run against staging #124

Merged
merged 2 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ Or if you are only checking verification use cases,
(env) $ pytest test --skip-signing --entrypoint=SIGSTORE_CLIENT
```

You can also run the tests against staging by adding `--staging` on the command,

```sh
(env) $ pytest test --staging --entrypoint=SIGSTORE_CLIENT
```

Using the [`gh` CLI](https://cli.github.com/) and noting SIGSTORE_CLIENT is the absolute path to a client implementing the [CLI specification](https://github.com/sigstore/sigstore-conformance/blob/main/docs/cli_protocol.md).

## Licensing
Expand Down
8 changes: 7 additions & 1 deletion docs/cli_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ client's native CLI accepts.
This is the set of subcommands that the test CLI must support. Each subcommand
has a provided syntax and list of descriptions for each argument.

To simplify argument parsing, all arguments are required and will **always** be
To simplify argument parsing, all arguments are required, except `--staging`, and will **always** be
supplied by the conformance suite in the order that they are specified in the
templates below.

All commands below are allowed to run against staging by appending the `--staging` in the command, for example:

```console
${ENTRYPOINT} sign --identity-token TOKEN --signature FILE --certificate FILE FILE --staging
```

### Sign

#### Signature and certificate flow
Expand Down
32 changes: 17 additions & 15 deletions test/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class SigstoreClient:
methods should not be called directly.
"""

def __init__(self, entrypoint: str, identity_token: str) -> None:
def __init__(self, entrypoint: str, identity_token: str, staging: bool) -> None:
"""
Create a new `SigstoreClient`.

Expand All @@ -120,15 +120,20 @@ def __init__(self, entrypoint: str, identity_token: str) -> None:
self.entrypoint = entrypoint
self.identity_token = identity_token
self.completed_process: subprocess.CompletedProcess | None = None
self.staging = staging

def run(self, *args) -> None:
"""
Execute a command against the Sigstore client.
"""
self.completed_process = None
full_command = [self.entrypoint, *args]
if self.staging:
full_command.append("--staging")

try:
self.completed_process = subprocess.run(
[self.entrypoint, *args],
full_command,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
Expand Down Expand Up @@ -182,8 +187,7 @@ def _sign_for_sigcrt(
This is an overload of `sign` for the signature/certificate flow and should not
be called directly.
"""

self.run(
args = [
"sign",
"--identity-token",
self.identity_token,
Expand All @@ -192,7 +196,9 @@ def _sign_for_sigcrt(
"--certificate",
materials.certificate,
artifact,
)
]

self.run(*args)

@sign.register
def _sign_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) -> None:
Expand All @@ -202,21 +208,19 @@ def _sign_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) ->
This is an overload of `sign` for the bundle flow and should not be called directly.
"""

self.run(
args = [
"sign-bundle",
"--identity-token",
self.identity_token,
"--bundle",
materials.bundle,
artifact,
)
]

self.run(*args)

@singledispatchmethod
def verify(
self,
materials: VerificationMaterials,
artifact: os.PathLike,
) -> None:
def verify(self, materials: VerificationMaterials, artifact: os.PathLike) -> None:
"""
Verify an artifact with the Sigstore client. Dispatches to `_verify_for_sigcrt`
when given `SignatureCertificateMaterials`, or `_verify_for_bundle` when given
Expand All @@ -230,9 +234,7 @@ def verify(

@verify.register
def _verify_for_sigcrt(
self,
materials: SignatureCertificateMaterials,
artifact: os.PathLike,
self, materials: SignatureCertificateMaterials, artifact: os.PathLike
) -> None:
"""
Verify an artifact given a signature and certificate with the Sigstore client.
Expand Down
8 changes: 7 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ def pytest_addoption(parser) -> None:
action="store_true",
help="skip tests that require signing functionality",
)
parser.addoption(
"--staging",
action="store_true",
help="run tests against staging",
)


def pytest_runtest_setup(item):
Expand Down Expand Up @@ -162,7 +167,8 @@ def client(pytestconfig, identity_token):
Parametrize each test with the client under test.
"""
entrypoint = pytestconfig.getoption("--entrypoint")
return SigstoreClient(entrypoint, identity_token)
staging = pytestconfig.getoption("--staging")
return SigstoreClient(entrypoint, identity_token, staging)


@pytest.fixture
Expand Down
25 changes: 19 additions & 6 deletions test/test_bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ def test_verify(client: SigstoreClient, make_materials_by_type: _MakeMaterialsBy
client.verify(materials, input_path)


def test_verify_dsse_bundle_with_trust_root(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None:
def test_verify_dsse_bundle_with_trust_root(
client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType
) -> None:
"""
Test the happy path of verification for DSSE bundle w/ custom trust root
"""
Expand Down Expand Up @@ -170,7 +172,9 @@ def test_verify_rejects_different_materials(
client.verify(materials, input_path)


def test_verify_rejects_expired_certificate(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None:
def test_verify_rejects_expired_certificate(
client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType
) -> None:
"""
Check that the client rejects a bundle if the certificate was issued
outside the validity window of the trusted root
Expand All @@ -184,7 +188,9 @@ def test_verify_rejects_expired_certificate(client: SigstoreClient, make_materia
client.verify(materials, input_path)


def test_verify_rejects_missing_inclusion_proof(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None:
def test_verify_rejects_missing_inclusion_proof(
client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType
) -> None:
"""
Check that the client rejects a v0.2 bundle if the TLog entry does NOT
contain an inclusion proof
Expand All @@ -198,7 +204,9 @@ def test_verify_rejects_missing_inclusion_proof(client: SigstoreClient, make_mat
client.verify(materials, input_path)


def test_verify_rejects_bad_tlog_timestamp(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None:
def test_verify_rejects_bad_tlog_timestamp(
client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType
) -> None:
"""
Check that the client rejects a bundle if the TLog entry contains a
timestamp that falls outside the validity window of the signing
Expand All @@ -213,7 +221,9 @@ def test_verify_rejects_bad_tlog_timestamp(client: SigstoreClient, make_material
client.verify(materials, input_path)


def test_verify_rejects_bad_tlog_entry(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None:
def test_verify_rejects_bad_tlog_entry(
client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType
) -> None:
"""
Check that the client rejects a bundle if the body of the TLog entry does
not match the signed artifact.
Expand All @@ -226,7 +236,10 @@ def test_verify_rejects_bad_tlog_entry(client: SigstoreClient, make_materials_by
with client.raises():
client.verify(materials, input_path)

def test_verify_rejects_bad_tsa_timestamp(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None:

def test_verify_rejects_bad_tsa_timestamp(
client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType
) -> None:
"""
Check that the client rejects a bundle if the TSA timestamp falls outside
the validity window of the signing certificate.
Expand Down
Loading