Skip to content

Commit fbaf7cf

Browse files
committed
chore: prepare new release(s)
1 parent 9aafb7e commit fbaf7cf

28 files changed

Lines changed: 1576 additions & 407 deletions

Cargo.lock

Lines changed: 222 additions & 117 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@
3131
oauth2-test-server = '=0.1.3'
3232
once_cell = '1.17.0'
3333
openapiv3 = '2.0'
34-
opentelemetry = '0.30.0'
35-
opentelemetry-http = '0.30.0'
36-
opentelemetry_sdk = '0.30.0'
34+
opentelemetry = '0.31'
35+
opentelemetry-http = '0.31'
36+
opentelemetry_sdk = '0.31'
3737
optipy = '0.1.0'
38-
pbjson = '0.7.0'
39-
pbjson-build = '0.7.0'
40-
pbjson-types = '0.7.0'
38+
pbjson = '0.9.0'
39+
pbjson-build = '0.9.0'
40+
pbjson-types = '0.9.0'
4141
prettyplease = '0.2'
42-
prost = '0.13.3'
43-
prost-build = '0.13.3'
44-
prost-types = '0.13.3'
42+
prost = '0.14.1'
43+
prost-build = '0.14.1'
44+
prost-types = '0.14.1'
4545
pyo3-build-config = '0.27.2'
4646
pyo3-stub-gen = '0.17.2'
4747
rigetti-pyo3 = '0.5.4'
@@ -58,11 +58,13 @@
5858
tempfile = '3.3.0'
5959
thiserror = '2.0'
6060
toml_edit = '0.23.7'
61-
tonic-build = '0.13.1'
62-
tonic-health = '0.13.1'
63-
tonic-web = '0.13.1'
61+
tonic-build = '0.14.2'
62+
tonic-health = '0.14.2'
63+
tonic-prost = '0.14.2'
64+
tonic-prost-build = '0.14.2'
65+
tonic-web = '0.14.2'
6466
tracing = '0.1.41'
65-
tracing-opentelemetry = '0.31.0'
67+
tracing-opentelemetry = '0.32.0'
6668
tracing-subscriber = '0.3.18'
6769
urlpattern = '0.4.0'
6870
walkdir = '2.5'
@@ -106,38 +108,38 @@
106108

107109
[workspace.dependencies.qcs-api-client-common]
108110
path = 'qcs-api-client-common'
109-
version = '0.17.6'
111+
version = '0.18.0'
110112

111113
[workspace.dependencies.qcs-api-client-grpc]
112114
path = 'qcs-api-client-grpc'
113-
version = '0.17.6'
115+
version = '0.18.0'
114116

115117
[workspace.dependencies.qcs-api-client-grpc-internal]
116118
path = 'qcs-api-client-grpc-internal'
117119
registry = 'rigetti-cargo'
118-
version = '0.18.6'
120+
version = '0.19.0'
119121

120122
[workspace.dependencies.qcs-api-client-openapi]
121123
path = 'qcs-api-client-openapi/public'
122-
version = '0.18.6'
124+
version = '0.19.0'
123125

124126
[workspace.dependencies.qcs-api-client-openapi-internal]
125127
path = 'qcs-api-client-openapi/internal'
126128
registry = 'rigetti-cargo'
127-
version = '0.18.6'
129+
version = '0.19.0'
128130

129131
[workspace.dependencies.reqwest]
130132
default-features = false
131-
features = ['json', 'rustls-tls-native-roots']
132-
version = '0.12.5'
133+
features = ['form', 'json', 'query', 'rustls', 'system-proxy']
134+
version = '0.13'
133135

134136
[workspace.dependencies.reqwest-middleware]
135-
features = ['json']
136-
version = '>0.3.0,<0.5'
137+
features = ['json', 'query']
138+
version = '0.5'
137139

138140
[workspace.dependencies.reqwest-tracing]
139-
features = ['opentelemetry_0_30']
140-
version = '0.5.8'
141+
features = ['opentelemetry_0_31']
142+
version = '0.7'
141143

142144
[workspace.dependencies.rigetti-hyper-proxy]
143145
default-features = false
@@ -176,7 +178,7 @@
176178

177179
[workspace.dependencies.tonic]
178180
features = ['tls-native-roots', 'gzip']
179-
version = '0.13.1'
181+
version = '0.14.2'
180182

181183
[workspace.dependencies.tower]
182184
features = ['retry', 'util']

qcs-api-client-common/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 0.18.0 (2026-05-04)
2+
3+
### Breaking Changes
4+
5+
- upgrade tonic
6+
7+
### Fixes
8+
9+
- Return valid OAuthSession even if there is a WriteError
10+
111
## 0.17.6 (2026-04-21)
212

313
### Fixes

qcs-api-client-common/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171

7272
[dependencies.reqwest]
7373
default-features = false
74-
features = ['socks', 'rustls-tls-native-roots']
74+
features = ['socks']
7575
workspace = true
7676

7777
[dependencies.rigetti-pyo3]
@@ -220,7 +220,7 @@
220220
publish = true
221221
readme = 'README.md'
222222
repository = 'https://github.com/rigetti/qcs-api-client-rust'
223-
version = '0.17.6'
223+
version = '0.18.0'
224224

225225
[package.metadata]
226226
[package.metadata.docs]

qcs-api-client-common/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "qcs-api-client-common"
33
requires-python = ">=3.10,<4"
4-
version = "0.17.6"
4+
version = "0.18.0"
55
description = "Contains core QCS client functionality and middleware implementations."
66
readme = "README-py.md"
77
license = { text = "Apache-2.0" }

qcs-api-client-common/src/configuration/error.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,15 @@ pub enum TokenError {
9090
#[error("Failed to request an externally managed access token: {0}")]
9191
ExternallyManaged(String),
9292
/// Failure writing the new access token to the secrets file.
93-
#[error("Failed to write the new access token to the secrets file. Setting `{SECRETS_READ_ONLY_VAR}=true` in the environment will skip persistence of newly acquired tokens. Error details: {0}")]
94-
Write(#[from] WriteError),
93+
#[error("Failed to write the new access token to the secrets file. Setting `{SECRETS_READ_ONLY_VAR}=true` in the environment will skip persistence of newly acquired tokens. Error details: {error}")]
94+
Write {
95+
/// The underlying write error.
96+
error: WriteError,
97+
/// The successfully refreshed OAuth session that failed to persist. The token is valid and can be used despite the write failure.
98+
///
99+
/// Boxed to reduce the size of the `TokenError` enum and avoid `clippy::result_large_err` warnings.
100+
oauth_session: Box<super::OAuthSession>,
101+
},
95102
/// Failure fetching the OIDC discovery document.
96103
#[error("Failed to fetch the OIDC discovery document: {0}")]
97104
Discovery(#[from] DiscoveryError),

qcs-api-client-common/src/configuration/pkce.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub enum PkceLoginError {
4747
#[error(transparent)]
4848
RedirectListenerError(#[from] RedirectListenerError),
4949
#[error(transparent)]
50-
ReqwestClient(#[from] reqwest::Error),
50+
ReqwestClient(#[from] oauth2::reqwest::Error),
5151
#[error("Error joining redirect listener task: {0}")]
5252
JoinError(#[from] tokio::task::JoinError),
5353
#[error("The redirect response's verifier state doesn't match the expected values")]
@@ -56,7 +56,7 @@ pub enum PkceLoginError {
5656
RequestToken(
5757
#[from]
5858
RequestTokenError<
59-
HttpClientError<reqwest::Error>,
59+
HttpClientError<oauth2::reqwest::Error>,
6060
StandardErrorResponse<BasicErrorResponseType>,
6161
>,
6262
),
@@ -120,7 +120,7 @@ pub(crate) async fn pkce_login(
120120

121121
if cfg!(test) {
122122
// Tests are headless, and should use an oauth2 request that does not require entering credentials.
123-
let client = reqwest::Client::new();
123+
let client = oauth2::reqwest::Client::new();
124124
println!("Requesting auth URL: {auth_url}");
125125
client.get(auth_url).send().await?.error_for_status()?;
126126
} else {
@@ -140,9 +140,9 @@ pub(crate) async fn pkce_login(
140140
return Err(PkceLoginError::CodeChallengeMismatch);
141141
}
142142

143-
let http_client = reqwest::ClientBuilder::new()
143+
let http_client = oauth2::reqwest::ClientBuilder::new()
144144
// Following redirects opens the client up to SSRF vulnerabilities.
145-
.redirect(reqwest::redirect::Policy::none())
145+
.redirect(oauth2::reqwest::redirect::Policy::none())
146146
.build()?;
147147

148148
let token_result = client

qcs-api-client-common/src/configuration/tokens.rs

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -596,34 +596,50 @@ impl TokenDispatcher {
596596
let oauth_session = refresh_fn(self.lock.clone()).await?;
597597

598598
// If the config source is a file, write the new access token to the file
599-
if let ConfigSource::File {
599+
let write_result = if let ConfigSource::File {
600600
settings_path: _,
601601
secrets_path,
602602
} = source
603603
{
604-
if !Secrets::is_read_only(secrets_path).await? {
605-
// If the payload is a PkceFlow, write the fresh refresh token if available.
606-
let refresh_token = match &oauth_session.payload {
607-
OAuthGrant::PkceFlow(payload) => {
608-
payload.refresh_token.as_ref().map(|rt| &rt.refresh_token)
609-
}
610-
_ => None,
611-
};
612-
613-
let now = OffsetDateTime::now_utc();
614-
Secrets::write_tokens(
615-
secrets_path,
616-
profile,
617-
refresh_token,
618-
oauth_session.access_token()?,
619-
now,
620-
)
621-
.await?;
604+
match Secrets::is_read_only(secrets_path).await {
605+
Ok(true) => Ok(()),
606+
Ok(false) => {
607+
// If the payload is a PkceFlow, write the fresh refresh token if available.
608+
let refresh_token = match &oauth_session.payload {
609+
OAuthGrant::PkceFlow(payload) => {
610+
payload.refresh_token.as_ref().map(|rt| &rt.refresh_token)
611+
}
612+
_ => None,
613+
};
614+
615+
let now = OffsetDateTime::now_utc();
616+
Secrets::write_tokens(
617+
secrets_path,
618+
profile,
619+
refresh_token,
620+
oauth_session.access_token()?,
621+
now,
622+
)
623+
.await
624+
}
625+
Err(e) => Err(e),
622626
}
623-
}
627+
} else {
628+
Ok(())
629+
};
624630

631+
// Always clean up the refreshing lock, even if write failed
625632
*self.refreshing.lock().await = false;
626633
self.notify_refreshed.notify_waiters();
634+
635+
// If write failed, return error with the valid oauth_session
636+
if let Err(error) = write_result {
637+
return Err(TokenError::Write {
638+
error,
639+
oauth_session: Box::new(oauth_session),
640+
});
641+
}
642+
627643
Ok(oauth_session)
628644
}
629645

@@ -897,7 +913,22 @@ impl TokenRefresher for ClientConfiguration {
897913
}
898914

899915
async fn refresh_access_token(&self) -> Result<SecretAccessToken, Self::Error> {
900-
Ok(self.refresh().await?.access_token()?.clone())
916+
match self.refresh().await {
917+
Ok(session) => Ok(session.access_token()?.clone()),
918+
Err(TokenError::Write {
919+
error,
920+
oauth_session,
921+
}) => {
922+
// Token refresh succeeded but persistence failed. Extract and return the access token from the error.
923+
#[cfg(feature = "tracing")]
924+
tracing::warn!(
925+
"Token refresh succeeded but failed to persist: {}. Returning access token from error.",
926+
error
927+
);
928+
Ok(oauth_session.access_token()?.clone())
929+
}
930+
Err(e) => Err(e),
931+
}
901932
}
902933

903934
async fn get_access_token(&self) -> Result<Option<SecretAccessToken>, Self::Error> {

qcs-api-client-grpc/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 0.18.0 (2026-05-04)
2+
3+
### Breaking Changes
4+
5+
- upgrade tonic
6+
7+
### Fixes
8+
9+
- Return valid OAuthSession even if there is a WriteError
10+
111
## 0.17.6 (2026-04-21)
212

313
### Fixes

qcs-api-client-grpc/Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
[build-dependencies.tonic-build]
99
workspace = true
1010

11+
[build-dependencies.tonic-prost-build]
12+
workspace = true
13+
1114
[dependencies]
1215
[dependencies.backoff]
1316
features = ['tokio']
@@ -77,6 +80,9 @@
7780
[dependencies.tonic]
7881
workspace = true
7982

83+
[dependencies.tonic-prost]
84+
workspace = true
85+
8086
[dependencies.tonic-web]
8187
optional = true
8288
workspace = true
@@ -164,4 +170,4 @@
164170
publish = true
165171
readme = 'README.md'
166172
repository = 'https://github.com/rigetti/qcs-api-client-rust'
167-
version = '0.17.6'
173+
version = '0.18.0'

0 commit comments

Comments
 (0)