fix: require authenticated runtime bindings

This commit is contained in:
2026-09-06 03:28:19 +09:00
parent 7363dffb9d
commit 51c6d7f835
5 changed files with 255 additions and 178 deletions
@@ -438,14 +438,13 @@ CREATE TABLE workspace_runtime_bindings (
runtime_id TEXT NOT NULL,
display_name TEXT NOT NULL,
base_url TEXT NOT NULL,
public_key TEXT,
public_key_fingerprint TEXT,
public_key TEXT NOT NULL,
public_key_fingerprint TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
revoked_at TEXT,
PRIMARY KEY (workspace_id, runtime_id),
UNIQUE (workspace_id, public_key_fingerprint),
CHECK ((public_key IS NULL) = (public_key_fingerprint IS NULL)),
FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE RESTRICT
);
CREATE TABLE typed_ticket_artifacts (
+5 -5
View File
@@ -322,8 +322,8 @@ fn run_trust_runtime_command(args: Vec<String>) -> Result<(), Box<dyn std::error
runtime_id: runtime_id.clone(),
display_name: display_name.unwrap_or_else(|| runtime_id.clone()),
base_url,
public_key: Some(public_key),
public_key_fingerprint: None,
public_key,
public_key_fingerprint: String::new(),
created_at: now.clone(),
updated_at: now,
revoked_at: None,
@@ -384,7 +384,7 @@ fn run_trust_runtime_command(args: Vec<String>) -> Result<(), Box<dyn std::error
runtime.workspace_id,
runtime.runtime_id,
runtime.base_url,
runtime.public_key_fingerprint.as_deref().unwrap_or(""),
runtime.public_key_fingerprint,
runtime.revoked_at.unwrap_or_default()
);
}
@@ -857,8 +857,8 @@ mod tests {
runtime_id: "runtime-a".to_string(),
display_name: "Runtime A".to_string(),
base_url: "http://127.0.0.1:18080".to_string(),
public_key: Some(public_key),
public_key_fingerprint: None,
public_key,
public_key_fingerprint: String::new(),
created_at: "2026-07-26T00:00:00Z".to_string(),
updated_at: "2026-07-26T00:00:00Z".to_string(),
revoked_at: None,
+123 -97
View File
@@ -1572,8 +1572,8 @@ impl WorkspaceApi {
runtime_id: EMBEDDED_RUNTIME_ID.to_owned(),
display_name: "Embedded Runtime".to_owned(),
base_url: "in-process://embedded".to_owned(),
public_key: Some(embedded_identity.public_key.clone()),
public_key_fingerprint: None,
public_key: embedded_identity.public_key.clone(),
public_key_fingerprint: String::new(),
created_at: config.workspace_created_at.clone(),
updated_at: config.workspace_created_at.clone(),
revoked_at: None,
@@ -1605,7 +1605,26 @@ impl WorkspaceApi {
))
})?;
let runtime_binding_store = store.clone();
let runtime_binding_workspace_id = config.workspace_id.clone();
let configured_runtime_endpoints = config
.remote_runtime_sources
.iter()
.filter_map(|source| {
(source.workspace_id.as_deref() == Some(config.workspace_id.as_str()))
.then(|| (source.runtime_id.clone(), source.base_url.clone()))
})
.collect::<HashMap<_, _>>();
let expected_runtime_bindings = Arc::new(
store
.list_workspace_runtime_bindings(&config.workspace_id, false)
.await?
.into_iter()
.filter(|binding| binding.runtime_id != EMBEDDED_RUNTIME_ID)
.filter(|binding| {
configured_runtime_endpoints.get(&binding.runtime_id) == Some(&binding.base_url)
})
.map(|binding| (binding.runtime_id.clone(), binding))
.collect::<HashMap<_, _>>(),
);
let api = Self::new_with_execution_backend_and_broker(
config,
store,
@@ -1615,9 +1634,13 @@ impl WorkspaceApi {
)
.await?;
api.runtime.set_runtime_binding_gate(move |runtime_id| {
expected_runtime_bindings
.get(runtime_id)
.is_some_and(|expected| {
runtime_binding_store
.workspace_runtime_binding_is_active(&runtime_binding_workspace_id, runtime_id)
.workspace_runtime_binding_matches(expected)
.unwrap_or(false)
})
});
Ok(api)
}
@@ -12404,7 +12427,7 @@ async fn list_workers(
}
async fn create_remote_runtime(
State(api): State<WorkspaceApi>,
State(_api): State<WorkspaceApi>,
Json(request): Json<CreateRemoteRuntimeRequest>,
) -> ApiResult<(StatusCode, Json<WorkspaceRuntimeResource>)> {
validate_runtime_connection_request(&request)?;
@@ -12425,52 +12448,10 @@ async fn create_remote_runtime(
"remote Runtime token_ref persistence is not supported",
));
}
let now = Utc::now().to_rfc3339();
let binding = WorkspaceRuntimeBinding {
workspace_id: api.config.workspace_id.clone(),
runtime_id: id.clone(),
display_name: request
.display_name
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.unwrap_or(&id)
.to_owned(),
base_url: request.endpoint.trim().to_string(),
public_key: None,
public_key_fingerprint: None,
created_at: now.clone(),
updated_at: now,
revoked_at: None,
};
api.store
.upsert_workspace_runtime_binding_record(binding.clone(), false)
.await?;
let active_config = remote_runtime_config_from_binding(&binding).map_err(|diagnostic| {
ApiError::with_diagnostics(
Error::RuntimeOperationFailed {
runtime_id: binding.runtime_id.clone(),
code: diagnostic.code.clone(),
message: diagnostic.message.clone(),
},
vec![diagnostic],
)
})?;
let active_runtime = RemoteWorkerRuntime::new(
active_config,
api.config.workspace_id.clone(),
api.config
.backend_base_url
.clone()
.unwrap_or_else(|| "http://127.0.0.1:8787".to_string()),
)
.map(|host| host.with_resource_broker(api.resource_broker.clone()))
.map_err(|err| err.into_error())?;
api.runtime.register_or_replace(active_runtime);
let resource = workspace_runtime_resource_by_id(&api, &id)
.await?
.ok_or_else(|| Error::UnknownRuntime(id.clone()))?;
Ok((StatusCode::CREATED, Json(resource)))
Err(settings_bad_request(
"runtime_public_key_required",
"remote Runtime registration requires an authenticated public key; use `yoi-server trust-runtime add` until the Workspace Runtime key API is available",
))
}
async fn delete_remote_runtime(
@@ -14482,19 +14463,6 @@ async fn workspace_runtime_resources_response(
})
}
async fn workspace_runtime_resource_by_id(
api: &WorkspaceApi,
runtime_id: &str,
) -> ApiResult<Option<WorkspaceRuntimeResource>> {
Ok(
workspace_runtime_resources_response(api, &api.config.workspace_id)
.await?
.items
.into_iter()
.find(|resource| resource.runtime.runtime_id == runtime_id),
)
}
fn validate_runtime_connection_request(request: &CreateRemoteRuntimeRequest) -> ApiResult<()> {
validate_public_runtime_id(request.runtime_id.trim())?;
let endpoint = request.endpoint.trim();
@@ -14538,6 +14506,7 @@ fn validate_public_runtime_id(runtime_id: &str) -> ApiResult<()> {
Ok(())
}
#[cfg(test)]
fn remote_runtime_config_from_binding(
binding: &WorkspaceRuntimeBinding,
) -> std::result::Result<RemoteRuntimeConfig, RuntimeDiagnostic> {
@@ -16030,12 +15999,14 @@ fn worker_create_not_accepted_error(
}
fn settings_bad_request(code: &'static str, message: &'static str) -> ApiError {
Error::RuntimeOperationFailed {
runtime_id: "workspace-backend".to_string(),
code: code.to_string(),
message: message.to_string(),
}
.into()
ApiError::with_diagnostics(
Error::InvalidInput(format!("{code}: {message}")),
vec![settings_diagnostic(
code,
DiagnosticSeverity::Error,
message,
)],
)
}
fn settings_diagnostic(
@@ -16879,8 +16850,8 @@ mod tests {
runtime_id: runtime_id.to_owned(),
display_name: runtime_id.to_owned(),
base_url: "https://runtime.test".to_owned(),
public_key: Some(identity.public_key.clone()),
public_key_fingerprint: None,
public_key: identity.public_key.clone(),
public_key_fingerprint: String::new(),
created_at: "2026-01-01T00:00:00Z".to_owned(),
updated_at: "2026-01-01T00:00:00Z".to_owned(),
revoked_at: None,
@@ -22908,8 +22879,8 @@ mod tests {
runtime_id: "runtime-remote".to_string(),
display_name: "Remote Runtime".to_string(),
base_url: "https://runtime.invalid".to_string(),
public_key: Some(identity.public_key.clone()),
public_key_fingerprint: None,
public_key: identity.public_key.clone(),
public_key_fingerprint: String::new(),
created_at: "2026-08-11T00:00:00Z".to_string(),
updated_at: "2026-08-11T00:00:00Z".to_string(),
revoked_at: None,
@@ -25421,6 +25392,31 @@ mod tests {
let dir = tempfile::tempdir().unwrap();
let api = test_api(dir.path()).await;
let store = api.store.clone();
let identity = RuntimeIdentityMaterial::generate("team-runtime").unwrap();
let binding = WorkspaceRuntimeBinding {
workspace_id: TEST_WORKSPACE_ID.to_string(),
runtime_id: "team-runtime".to_string(),
display_name: "Team Runtime".to_string(),
base_url: "https://runtime.example.invalid".to_string(),
public_key: identity.public_key,
public_key_fingerprint: String::new(),
created_at: "1".to_string(),
updated_at: "1".to_string(),
revoked_at: None,
};
store
.upsert_workspace_runtime_binding_record(binding.clone(), false)
.await
.unwrap();
let remote = remote_runtime_config_from_binding(&binding).unwrap();
api.runtime.register_or_replace(
RemoteWorkerRuntime::new(
remote,
TEST_WORKSPACE_ID.to_string(),
"http://127.0.0.1:8787".to_string(),
)
.unwrap(),
);
let app = build_inner_router(api);
let runtimes_uri = format!("/api/w/{TEST_WORKSPACE_ID}/runtimes");
@@ -25450,19 +25446,31 @@ mod tests {
)
.await;
let added = request_json(
let rejected = request_json(
app.clone(),
"POST",
&runtimes_uri,
Some(serde_json::json!({
"runtime_id": "team-runtime",
"display_name": "Team Runtime",
"endpoint": "https://runtime.example.invalid"
"runtime_id": "keyless-runtime",
"display_name": "Keyless Runtime",
"endpoint": "https://keyless.runtime.invalid"
})),
StatusCode::CREATED,
StatusCode::BAD_REQUEST,
)
.await;
assert_eq!(added["runtime_id"], "team-runtime");
assert!(
rejected["message"]
.as_str()
.unwrap_or_default()
.contains("runtime_public_key_required")
);
let listed = get_json(app.clone(), &runtimes_uri).await;
let added = listed["items"]
.as_array()
.unwrap()
.iter()
.find(|runtime| runtime["runtime_id"] == "team-runtime")
.unwrap();
assert_eq!(added["management"]["config_managed"], true);
assert_eq!(added["management"]["endpoint_configured"], true);
let projected = serde_json::to_string(&added).unwrap();
@@ -25530,20 +25538,34 @@ mod tests {
});
let dir = tempfile::tempdir().unwrap();
let app = test_app(dir.path()).await;
let added = request_json(
app.clone(),
"POST",
&format!("/api/w/{TEST_WORKSPACE_ID}/runtimes"),
Some(serde_json::json!({
"runtime_id": "busy-runtime",
"display_name": "Busy Runtime",
"endpoint": format!("http://{runtime_addr}")
})),
StatusCode::CREATED,
let endpoint = format!("http://{runtime_addr}");
let api = test_api(dir.path()).await;
let binding = WorkspaceRuntimeBinding {
workspace_id: TEST_WORKSPACE_ID.to_string(),
runtime_id: "busy-runtime".to_string(),
display_name: "Busy Runtime".to_string(),
base_url: endpoint,
public_key: RuntimeIdentityMaterial::generate("busy-runtime")
.unwrap()
.public_key,
public_key_fingerprint: String::new(),
created_at: "1".to_string(),
updated_at: "1".to_string(),
revoked_at: None,
};
api.store
.upsert_workspace_runtime_binding_record(binding.clone(), false)
.await
.unwrap();
api.runtime.register_or_replace(
RemoteWorkerRuntime::new(
remote_runtime_config_from_binding(&binding).unwrap(),
TEST_WORKSPACE_ID.to_string(),
"http://127.0.0.1:8787".to_string(),
)
.await;
assert_eq!(added["runtime_id"], "busy-runtime");
.unwrap(),
);
let app = build_inner_router(api);
let workers = get_json(app.clone(), "/api/workers").await;
assert!(
workers["items"]
@@ -25602,8 +25624,10 @@ mod tests {
runtime_id: "probe-runtime".to_string(),
display_name: "Probe Runtime".to_string(),
base_url: endpoint.clone(),
public_key: None,
public_key_fingerprint: None,
public_key: RuntimeIdentityMaterial::generate("probe-runtime")
.unwrap()
.public_key,
public_key_fingerprint: String::new(),
created_at: "2026-01-01T00:00:00Z".to_string(),
updated_at: "2026-01-01T00:00:00Z".to_string(),
revoked_at: None,
@@ -25672,8 +25696,10 @@ mod tests {
runtime_id: "control-only-runtime".to_string(),
display_name: "Control-only Runtime".to_string(),
base_url: endpoint,
public_key: None,
public_key_fingerprint: None,
public_key: RuntimeIdentityMaterial::generate("control-only-runtime")
.unwrap()
.public_key,
public_key_fingerprint: String::new(),
created_at: "2026-01-01T00:00:00Z".to_string(),
updated_at: "2026-01-01T00:00:00Z".to_string(),
revoked_at: None,
+114 -56
View File
@@ -104,8 +104,8 @@ pub struct WorkspaceRuntimeBinding {
pub runtime_id: String,
pub display_name: String,
pub base_url: String,
pub public_key: Option<String>,
pub public_key_fingerprint: Option<String>,
pub public_key: String,
pub public_key_fingerprint: String,
pub created_at: String,
pub updated_at: String,
pub revoked_at: Option<String>,
@@ -544,11 +544,8 @@ pub trait ControlPlaneStore: Send + Sync {
&self,
record: &WorkspaceBootstrapRecord,
) -> Result<WorkspaceBootstrapResult>;
fn workspace_runtime_binding_is_active(
&self,
workspace_id: &str,
runtime_id: &str,
) -> Result<bool>;
fn workspace_runtime_binding_matches(&self, expected: &WorkspaceRuntimeBinding)
-> Result<bool>;
async fn get_workspace_runtime_binding(
&self,
workspace_id: &str,
@@ -1840,15 +1837,16 @@ impl ControlPlaneStore for SqliteWorkspaceStore {
})
}
fn workspace_runtime_binding_is_active(
fn workspace_runtime_binding_matches(
&self,
workspace_id: &str,
runtime_id: &str,
expected: &WorkspaceRuntimeBinding,
) -> Result<bool> {
Ok(
SqliteWorkspaceStore::get_workspace_runtime_binding(self, workspace_id, runtime_id)?
.is_some_and(|binding| binding.revoked_at.is_none()),
)
Ok(SqliteWorkspaceStore::get_workspace_runtime_binding(
self,
&expected.workspace_id,
&expected.runtime_id,
)?
.is_some_and(|binding| binding == *expected && binding.revoked_at.is_none()))
}
async fn get_workspace_runtime_binding(
@@ -5316,29 +5314,16 @@ pub fn normalize_runtime_public_key(public_key: &str) -> Result<(String, String)
}
fn normalize_workspace_runtime_binding_key(record: &mut WorkspaceRuntimeBinding) -> Result<()> {
match (&record.public_key, &record.public_key_fingerprint) {
(None, None) => Ok(()),
(Some(public_key), None) => {
let (canonical, fingerprint) = normalize_runtime_public_key(public_key)?;
record.public_key = Some(canonical);
record.public_key_fingerprint = Some(fingerprint);
Ok(())
}
(Some(public_key), Some(public_key_fingerprint)) => {
let (canonical, fingerprint) = normalize_runtime_public_key(public_key)?;
if public_key_fingerprint != &fingerprint {
let (canonical, fingerprint) = normalize_runtime_public_key(&record.public_key)?;
if !record.public_key_fingerprint.is_empty() && record.public_key_fingerprint != fingerprint {
return Err(Error::InvalidInput(
"Runtime public key fingerprint does not match the public key".into(),
));
}
record.public_key = Some(canonical);
record.public_key = canonical;
record.public_key_fingerprint = fingerprint;
Ok(())
}
(None, Some(_)) => Err(Error::InvalidInput(
"Runtime public key fingerprint requires a public key".into(),
)),
}
}
fn map_runtime_binding_write_error(err: rusqlite::Error) -> Error {
if matches!(
@@ -6034,6 +6019,19 @@ CREATE TABLE IF NOT EXISTS __yoi_schema_migrations (
}
fn migrate_workspace_runtime_bindings_v50_to_v51(conn: &Connection) -> Result<()> {
migrate_workspace_runtime_bindings_v50_to_v51_with_verifier(
conn,
verify_workspace_runtime_binding_schema,
)
}
fn migrate_workspace_runtime_bindings_v50_to_v51_with_verifier<F>(
conn: &Connection,
verify: F,
) -> Result<()>
where
F: FnOnce(&Connection) -> Result<()>,
{
let tx = rusqlite::Transaction::new_unchecked(conn, TransactionBehavior::Exclusive)?;
let legacy_columns = table_columns(&tx, "trusted_runtime_records")?
.into_iter()
@@ -6108,8 +6106,8 @@ fn migrate_workspace_runtime_bindings_v50_to_v51(conn: &Connection) -> Result<()
runtime_id,
display_name,
base_url,
public_key: Some(public_key),
public_key_fingerprint: Some(fingerprint),
public_key,
public_key_fingerprint: fingerprint,
created_at,
updated_at,
revoked_at,
@@ -6126,10 +6124,7 @@ fn migrate_workspace_runtime_bindings_v50_to_v51(conn: &Connection) -> Result<()
binding.workspace_id, binding.runtime_id
)));
}
let fingerprint = binding
.public_key_fingerprint
.clone()
.expect("normalized key");
let fingerprint = binding.public_key_fingerprint.clone();
if !trust_keys.insert((binding.workspace_id.clone(), fingerprint.clone())) {
return Err(Error::Store(format!(
"duplicate Runtime trust fingerprint `{fingerprint}` in Workspace `{}`",
@@ -6184,14 +6179,13 @@ fn migrate_workspace_runtime_bindings_v50_to_v51(conn: &Connection) -> Result<()
runtime_id TEXT NOT NULL,
display_name TEXT NOT NULL,
base_url TEXT NOT NULL,
public_key TEXT,
public_key_fingerprint TEXT,
public_key TEXT NOT NULL,
public_key_fingerprint TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
revoked_at TEXT,
PRIMARY KEY (workspace_id, runtime_id),
UNIQUE (workspace_id, public_key_fingerprint),
CHECK ((public_key IS NULL) = (public_key_fingerprint IS NULL)),
FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE RESTRICT
);
CREATE INDEX idx_workspace_runtime_bindings_workspace
@@ -6246,10 +6240,12 @@ fn migrate_workspace_runtime_bindings_v50_to_v51(conn: &Connection) -> Result<()
"schema-{LATEST_SCHEMA_VERSION} migration produced {foreign_key_failures} foreign-key violation(s)"
)));
}
verify(&tx)?;
tx.execute(
"INSERT INTO __yoi_schema_migrations (version, name) VALUES (?1, ?2)",
params![LATEST_SCHEMA_VERSION, RUNTIME_BINDINGS_MIGRATION_NAME],
)?;
verify_current_schema_history(&tx)?;
tx.commit()?;
Ok(())
}
@@ -6997,13 +6993,8 @@ mod tests {
.unwrap()
.unwrap();
assert_eq!(binding.revoked_at.as_deref(), Some("2"));
assert!(binding.public_key.is_some());
assert!(
binding
.public_key_fingerprint
.as_deref()
.is_some_and(|value| value.starts_with("sha256:"))
);
assert!(!binding.public_key.is_empty());
assert!(binding.public_key_fingerprint.starts_with("sha256:"));
store
.with_conn(|conn| {
let jti_workspace: String = conn.query_row(
@@ -7073,6 +7064,53 @@ mod tests {
);
}
#[test]
fn schema_v50_runtime_migration_rolls_back_when_final_verification_fails() {
let temp = tempfile::tempdir().unwrap();
let path = temp.path().join("server.db");
prepare_schema_v50(&path, Some("workspace-a"));
let conn = Connection::open(&path).unwrap();
configure_sqlite(&conn).unwrap();
let error = migrate_workspace_runtime_bindings_v50_to_v51_with_verifier(&conn, |_| {
Err(Error::Store(
"forced final verification failure".to_string(),
))
})
.unwrap_err();
assert!(
error
.to_string()
.contains("forced final verification failure")
);
let version: i64 = conn
.query_row(
"SELECT MAX(version) FROM __yoi_schema_migrations",
[],
|row| row.get(0),
)
.unwrap();
assert_eq!(version, PREVIOUS_SCHEMA_VERSION);
assert!(
!table_columns(&conn, "trusted_runtime_records")
.unwrap()
.is_empty()
);
assert!(
table_columns(&conn, "workspace_runtime_bindings")
.unwrap()
.is_empty()
);
let jti: String = conn
.query_row(
"SELECT jti FROM worker_mutation_source_proof_jtis WHERE runtime_id = 'shared'",
[],
|row| row.get(0),
)
.unwrap();
assert_eq!(jti, "jti-1");
}
#[test]
fn runtime_binding_identity_and_trust_uniqueness_are_workspace_scoped() {
let temp = tempfile::tempdir().unwrap();
@@ -7099,8 +7137,8 @@ mod tests {
runtime_id: runtime_id.to_string(),
display_name: runtime_id.to_string(),
base_url: format!("https://{workspace_id}.runtime.test"),
public_key: Some(identity.public_key.clone()),
public_key_fingerprint: None,
public_key: identity.public_key.clone(),
public_key_fingerprint: String::new(),
created_at: "1".to_string(),
updated_at: "1".to_string(),
revoked_at: None,
@@ -7141,9 +7179,32 @@ mod tests {
.len(),
1
);
let expected_workspace_a = store
.get_workspace_runtime_binding("workspace-a", "shared")
.unwrap()
.unwrap();
assert!(
store
.revoke_workspace_runtime_binding("workspace-a", "shared", "2")
.workspace_runtime_binding_matches(&expected_workspace_a)
.unwrap()
);
let mut replaced_workspace_a = expected_workspace_a.clone();
replaced_workspace_a.base_url = "https://replacement.runtime.test".to_string();
replaced_workspace_a.updated_at = "2".to_string();
assert_eq!(
store
.upsert_workspace_runtime_binding(replaced_workspace_a, true)
.unwrap(),
WorkspaceRuntimeBindingUpsert::Replaced
);
assert!(
!store
.workspace_runtime_binding_matches(&expected_workspace_a)
.unwrap()
);
assert!(
store
.revoke_workspace_runtime_binding("workspace-a", "shared", "3")
.unwrap()
);
drop(store);
@@ -7197,8 +7258,8 @@ mod tests {
runtime_id: crate::hosts::EMBEDDED_RUNTIME_ID.to_string(),
display_name: "Embedded Runtime".to_string(),
base_url: "in-process://embedded".to_string(),
public_key: Some(public_key),
public_key_fingerprint: None,
public_key,
public_key_fingerprint: String::new(),
created_at: "1".to_string(),
updated_at: "1".to_string(),
revoked_at: None,
@@ -7220,10 +7281,7 @@ mod tests {
.get_workspace_runtime_binding("workspace-a", crate::hosts::EMBEDDED_RUNTIME_ID)
.unwrap()
.unwrap();
assert_eq!(
persisted.public_key.as_deref(),
Some(second.public_key.as_str())
);
assert_eq!(persisted.public_key, second.public_key);
}
#[test]
+4 -10
View File
@@ -60,12 +60,9 @@ pub async fn verify_runtime_request_source_proof_with_store(
.get_workspace_runtime_binding(workspace_id, &unverified.iss)
.await
.map_err(|error| WorkerMutationSourceProofError::Authority(error.to_string()))?
.filter(|record| record.revoked_at.is_none() && record.public_key.is_some())
.ok_or(WorkerMutationSourceProofError::RevokedRuntimeTrust)?;
let public_key = trusted
.public_key
.as_deref()
.filter(|record| record.revoked_at.is_none())
.ok_or(WorkerMutationSourceProofError::RevokedRuntimeTrust)?;
let public_key = trusted.public_key.as_str();
let expected = RuntimeRequestSourceExpectation {
identity_id: &unverified.iss,
audience: audience.as_ref(),
@@ -209,12 +206,9 @@ async fn verify_worker_remove_source_with(
.get_workspace_runtime_binding(&config.workspace_id, &unverified.iss)
.await
.map_err(|error| WorkerMutationSourceProofError::Authority(error.to_string()))?
.filter(|record| record.revoked_at.is_none() && record.public_key.is_some())
.ok_or(WorkerMutationSourceProofError::RevokedRuntimeTrust)?;
let public_key = trusted
.public_key
.as_deref()
.filter(|record| record.revoked_at.is_none())
.ok_or(WorkerMutationSourceProofError::RevokedRuntimeTrust)?;
let public_key = trusted.public_key.as_str();
let expected = WorkerMutationSourceExpectation {
runtime_id: &unverified.iss,
audience: audience.as_ref(),