Skip to content

Commit fc1630e

Browse files
committed
feat: Expose ClientTrustConfig as a public class
Signed-off-by: SequeI <[email protected]>
1 parent 204e0f4 commit fc1630e

File tree

10 files changed

+144
-107
lines changed

10 files changed

+144
-107
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ All versions prior to 0.9.0 are untracked.
6565
* SigningConfig now has methods that return actual clients (like `RekorClient`) instead of
6666
just URLs. The returned clients are also filtered according to SigningConfig contents.
6767
[#1407](https://github.com/sigstore/sigstore-python/pull/1407)
68+
* The ClientTrustConfig class has been moved from the private _internal package to a new public
69+
module (sigstore.trust). This change formally adds the class to the project's public API,
70+
making it available for use in other projects.
6871
* `--trust-config` now requires a file with SigningConfig v0.2, and is able to fully
6972
configure the used Sigstore instance [#1358]/(https://github.com/sigstore/sigstore-python/pull/1358)
7073
* By default (when `--trust-config` is not used) the whole trust configuration now

docs/api/trust.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:::sigstore.trust
2+

sigstore/_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
from sigstore._internal.fulcio.client import ExpiredCertificate
3939
from sigstore._internal.rekor import _hashedrekord_from_parts
4040
from sigstore._internal.rekor.client import RekorClient
41-
from sigstore._internal.trust import ClientTrustConfig
4241
from sigstore._utils import sha256_digest
4342
from sigstore.dsse import StatementBuilder, Subject
4443
from sigstore.dsse._predicate import (
@@ -56,6 +55,7 @@
5655
detect_credential,
5756
)
5857
from sigstore.sign import Signer, SigningContext
58+
from sigstore.trust import ClientTrustConfig
5959
from sigstore.verify import (
6060
Verifier,
6161
policy,

sigstore/_internal/trust.py

Lines changed: 1 addition & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,13 @@
4343
from sigstore._internal.rekor.client import RekorClient
4444
from sigstore._internal.rekor.client_v2 import RekorV2Client
4545
from sigstore._internal.timestamp import TimestampAuthorityClient
46-
from sigstore._internal.tuf import DEFAULT_TUF_URL, STAGING_TUF_URL, TrustUpdater
4746
from sigstore._utils import (
4847
KeyID,
4948
PublicKey,
5049
key_id,
5150
load_der_public_key,
5251
)
53-
from sigstore.errors import Error, MetadataError, TUFError, VerificationError
52+
from sigstore.errors import Error, MetadataError, VerificationError
5453

5554
# Versions supported by this client
5655
REKOR_VERSIONS = [1, 2]
@@ -547,102 +546,3 @@ def get_timestamp_authorities(self) -> list[CertificateAuthority]:
547546
for cert_chain in self._inner.timestamp_authorities
548547
]
549548
return certificate_authorities
550-
551-
552-
class ClientTrustConfig:
553-
"""
554-
Represents a Sigstore client's trust configuration, including a root of trust.
555-
"""
556-
557-
class ClientTrustConfigType(str, Enum):
558-
"""
559-
Known Sigstore client trust config media types.
560-
"""
561-
562-
CONFIG_0_1 = "application/vnd.dev.sigstore.clienttrustconfig.v0.1+json"
563-
564-
def __str__(self) -> str:
565-
"""Returns the variant's string value."""
566-
return self.value
567-
568-
@classmethod
569-
def from_json(cls, raw: str) -> ClientTrustConfig:
570-
"""
571-
Deserialize the given client trust config.
572-
"""
573-
inner = trustroot_v1.ClientTrustConfig.from_json(raw)
574-
return cls(inner)
575-
576-
@classmethod
577-
def production(
578-
cls,
579-
offline: bool = False,
580-
) -> ClientTrustConfig:
581-
"""Create new trust config from Sigstore production TUF repository.
582-
583-
If `offline`, will use data in local TUF cache. Otherwise will
584-
update the data from remote TUF repository.
585-
"""
586-
return cls.from_tuf(DEFAULT_TUF_URL, offline)
587-
588-
@classmethod
589-
def staging(
590-
cls,
591-
offline: bool = False,
592-
) -> ClientTrustConfig:
593-
"""Create new trust config from Sigstore staging TUF repository.
594-
595-
If `offline`, will use data in local TUF cache. Otherwise will
596-
update the data from remote TUF repository.
597-
"""
598-
return cls.from_tuf(STAGING_TUF_URL, offline)
599-
600-
@classmethod
601-
def from_tuf(
602-
cls,
603-
url: str,
604-
offline: bool = False,
605-
) -> ClientTrustConfig:
606-
"""Create a new trust config from a TUF repository.
607-
608-
If `offline`, will use data in local TUF cache. Otherwise will
609-
update the trust config from remote TUF repository.
610-
"""
611-
updater = TrustUpdater(url, offline)
612-
613-
tr_path = updater.get_trusted_root_path()
614-
inner_tr = trustroot_v1.TrustedRoot.from_json(Path(tr_path).read_bytes())
615-
616-
try:
617-
sc_path = updater.get_signing_config_path()
618-
inner_sc = trustroot_v1.SigningConfig.from_json(Path(sc_path).read_bytes())
619-
except TUFError as e:
620-
raise e
621-
622-
return cls(
623-
trustroot_v1.ClientTrustConfig(
624-
media_type=ClientTrustConfig.ClientTrustConfigType.CONFIG_0_1.value,
625-
trusted_root=inner_tr,
626-
signing_config=inner_sc,
627-
)
628-
)
629-
630-
def __init__(self, inner: trustroot_v1.ClientTrustConfig) -> None:
631-
"""
632-
@api private
633-
"""
634-
self._inner = inner
635-
636-
@property
637-
def trusted_root(self) -> TrustedRoot:
638-
"""
639-
Return the interior root of trust, as a `TrustedRoot`.
640-
"""
641-
return TrustedRoot(self._inner.trusted_root)
642-
643-
@property
644-
def signing_config(self) -> SigningConfig:
645-
"""
646-
Return the interior root of trust, as a `SigningConfig`.
647-
"""
648-
return SigningConfig(self._inner.signing_config)

sigstore/sign.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,11 @@
5959
from sigstore._internal.rekor import EntryRequestBody, RekorLogSubmitter
6060
from sigstore._internal.sct import verify_sct
6161
from sigstore._internal.timestamp import TimestampAuthorityClient, TimestampError
62-
from sigstore._internal.trust import ClientTrustConfig, KeyringPurpose, TrustedRoot
62+
from sigstore._internal.trust import KeyringPurpose, TrustedRoot
6363
from sigstore._utils import sha256_digest
6464
from sigstore.models import Bundle
6565
from sigstore.oidc import ExpiredIdentity, IdentityToken
66+
from sigstore.trust import ClientTrustConfig
6667

6768
_logger = logging.getLogger(__name__)
6869

sigstore/trust.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Copyright 2023 The Sigstore Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
Client trust configuration for sigstore-python.
17+
"""
18+
19+
from __future__ import annotations
20+
21+
import logging
22+
from enum import Enum
23+
from pathlib import Path
24+
25+
from sigstore_models.trustroot import v1 as trustroot_v1
26+
27+
from sigstore._internal.trust import SigningConfig, TrustedRoot
28+
from sigstore._internal.tuf import DEFAULT_TUF_URL, STAGING_TUF_URL, TrustUpdater
29+
from sigstore.errors import TUFError
30+
31+
_logger = logging.getLogger(__name__)
32+
33+
34+
class ClientTrustConfig:
35+
"""
36+
Represents a Sigstore client's trust configuration, including a root of trust.
37+
"""
38+
39+
class ClientTrustConfigType(str, Enum):
40+
"""
41+
Known Sigstore client trust config media types.
42+
"""
43+
44+
CONFIG_0_1 = "application/vnd.dev.sigstore.clienttrustconfig.v0.1+json"
45+
46+
def __str__(self) -> str:
47+
"""Returns the variant's string value."""
48+
return self.value
49+
50+
@classmethod
51+
def from_json(cls, raw: str) -> ClientTrustConfig:
52+
"""
53+
Deserialize the given client trust config.
54+
"""
55+
inner = trustroot_v1.ClientTrustConfig.from_json(raw)
56+
return cls(inner)
57+
58+
@classmethod
59+
def production(
60+
cls,
61+
offline: bool = False,
62+
) -> ClientTrustConfig:
63+
"""Create new trust config from Sigstore production TUF repository.
64+
65+
If `offline`, will use data in local TUF cache. Otherwise will
66+
update the data from remote TUF repository.
67+
"""
68+
return cls.from_tuf(DEFAULT_TUF_URL, offline)
69+
70+
@classmethod
71+
def staging(
72+
cls,
73+
offline: bool = False,
74+
) -> ClientTrustConfig:
75+
"""Create new trust config from Sigstore staging TUF repository.
76+
77+
If `offline`, will use data in local TUF cache. Otherwise will
78+
update the data from remote TUF repository.
79+
"""
80+
return cls.from_tuf(STAGING_TUF_URL, offline)
81+
82+
@classmethod
83+
def from_tuf(
84+
cls,
85+
url: str,
86+
offline: bool = False,
87+
) -> ClientTrustConfig:
88+
"""Create a new trust config from a TUF repository.
89+
90+
If `offline`, will use data in local TUF cache. Otherwise will
91+
update the trust config from remote TUF repository.
92+
"""
93+
updater = TrustUpdater(url, offline)
94+
95+
tr_path = updater.get_trusted_root_path()
96+
inner_tr = trustroot_v1.TrustedRoot.from_json(Path(tr_path).read_bytes())
97+
98+
try:
99+
sc_path = updater.get_signing_config_path()
100+
inner_sc = trustroot_v1.SigningConfig.from_json(Path(sc_path).read_bytes())
101+
except TUFError as e:
102+
raise e
103+
104+
return cls(
105+
trustroot_v1.ClientTrustConfig(
106+
media_type=ClientTrustConfig.ClientTrustConfigType.CONFIG_0_1.value,
107+
trusted_root=inner_tr,
108+
signing_config=inner_sc,
109+
)
110+
)
111+
112+
def __init__(self, inner: trustroot_v1.ClientTrustConfig) -> None:
113+
"""
114+
@api private
115+
"""
116+
self._inner = inner
117+
118+
@property
119+
def trusted_root(self) -> TrustedRoot:
120+
"""
121+
Return the interior root of trust, as a `TrustedRoot`.
122+
"""
123+
return TrustedRoot(self._inner.trusted_root)
124+
125+
@property
126+
def signing_config(self) -> SigningConfig:
127+
"""
128+
Return the interior root of trust, as a `SigningConfig`.
129+
"""
130+
return SigningConfig(self._inner.signing_config)

sigstore/verify/verifier.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@
4949
verify_sct,
5050
)
5151
from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult
52-
from sigstore._internal.trust import ClientTrustConfig, KeyringPurpose, TrustedRoot
52+
from sigstore._internal.trust import KeyringPurpose, TrustedRoot
5353
from sigstore._utils import base64_encode_pem_cert, sha256_digest
5454
from sigstore.errors import VerificationError
5555
from sigstore.hashes import Hashed
5656
from sigstore.models import Bundle
57+
from sigstore.trust import ClientTrustConfig
5758
from sigstore.verify.policy import VerificationPolicy
5859

5960
_logger = logging.getLogger(__name__)

test/unit/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@
3838
from sigstore._internal import tuf
3939
from sigstore._internal.rekor import _hashedrekord_from_parts
4040
from sigstore._internal.rekor.client import RekorClient
41-
from sigstore._internal.trust import ClientTrustConfig
4241
from sigstore._utils import sha256_digest
4342
from sigstore.models import Bundle
4443
from sigstore.oidc import IdentityToken
4544
from sigstore.sign import SigningContext
45+
from sigstore.trust import ClientTrustConfig
4646
from sigstore.verify.verifier import Verifier
4747

4848
_TUF_ASSETS = (Path(__file__).parent.parent / "assets" / "staging-tuf").resolve()

test/unit/internal/test_trust.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@
3232
from sigstore._internal.timestamp import TimestampAuthorityClient
3333
from sigstore._internal.trust import (
3434
CertificateAuthority,
35-
ClientTrustConfig,
3635
KeyringPurpose,
3736
SigningConfig,
3837
TrustedRoot,
3938
_is_timerange_valid,
4039
)
4140
from sigstore._utils import load_pem_public_key
4241
from sigstore.errors import Error
42+
from sigstore.trust import ClientTrustConfig
4343

4444
# Test data for TestSigningcconfig
4545
_service_v1_op1 = Service(url="url1", major_api_version=1, operator="op1")

test/unit/test_sign.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121

2222
import sigstore.oidc
2323
from sigstore._internal.timestamp import TimestampAuthorityClient
24-
from sigstore._internal.trust import ClientTrustConfig
2524
from sigstore.dsse import StatementBuilder, Subject
2625
from sigstore.errors import VerificationError
2726
from sigstore.hashes import Hashed
2827
from sigstore.sign import SigningContext
28+
from sigstore.trust import ClientTrustConfig
2929
from sigstore.verify.policy import UnsafeNoOp
3030

3131

0 commit comments

Comments
 (0)