Skip to content

Commit

Permalink
feat:checking that the client is allowed to run against staging (#124)
Browse files Browse the repository at this point in the history
* feat: checking that the client is allowd to run against staging

Signed-off-by: javanlacerda <[email protected]>

* Update docs/cli_protocol.md

Signed-off-by: William Woodruff <[email protected]>

---------

Signed-off-by: javanlacerda <[email protected]>
Signed-off-by: William Woodruff <[email protected]>
Co-authored-by: William Woodruff <[email protected]>
  • Loading branch information
javanlacerda and woodruffw authored Feb 20, 2024
1 parent 7375951 commit 4d4933e
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 23 deletions.
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

0 comments on commit 4d4933e

Please sign in to comment.