use grpc::heddle::api::v1alpha1::{
ApproveThreadRequest, BeginWebAuthnAuthenticationRequest, CheckMergeEligibilityRequest,
CheckMergeEligibilityResponse, CreateGrantRequest, CreateInvitationRequest,
CreateRepositoryRequest, CreateServiceAccountRequest, DeleteGrantRequest,
DeleteNamespaceRequest, DeleteRepositoryRequest, GetCurrentUserNamespaceRequest,
GrantSupportAccessRequest, GrantTargetRef, Invitation as ProtoInvitation,
IssueServiceAccountCredentialRequest, IssuedCredentialResponse, ListGrantsRequest,
ListSpoolsRequest, ListSupportAccessGrantsRequest, ListThreadApprovalsRequest, MonorepoNode,
ResolveMonorepoRequest, RevokeApprovalRequest, RevokeSupportAccessRequest,
ServiceAccountResponse, SpoolSummary, SupportAccessGrant, ThreadApproval, UpdateGrantRequest,
UpdateNamespaceRequest, UpdateRepositoryRequest, grant_target_ref::Target as GrantTargetKind,
};
use tonic::Request;
use wire::ProtocolError;
use super::{
HostedGrpcClient,
helpers::{
status_to_protocol_error, to_protocol_grant, to_protocol_namespace, to_protocol_repository,
},
operation_id::ClientOperationId,
};
fn clone_request_for_retry<T: Clone>(request: &Request<T>) -> Request<T> {
let mut retry = Request::new(request.get_ref().clone());
*retry.metadata_mut() = request.metadata().clone();
retry
}
macro_rules! signed_request_call {
($self:ident, $client:ident, $rpc:ident, $path:expr, $request:expr) => {{
let path = $path;
let mut request = $request;
let retry_template = clone_request_for_retry(&request);
let sig_ctx = $self.apply_signed_auth(&mut request, path)?;
match $self.$client.$rpc(request).await {
Ok(response) => response.into_inner(),
Err(status)
if $crate::grpc_hosted::request_signing::requires_human_signature(&status) =>
{
let ctx = $self.require_human_sig_context(sig_ctx)?;
let action_url =
$crate::grpc_hosted::request_signing::action_url_from_status(&status);
let assertion = $self.request_human_signature(path, &ctx, action_url)?;
let mut retry = retry_template;
$self.apply_auth(&mut retry, path)?;
$crate::grpc_hosted::request_signing::attach_human(&mut retry, &ctx, &assertion)?;
$self
.$client
.$rpc(retry)
.await
.map_err(status_to_protocol_error)?
.into_inner()
}
Err(status) => return Err(status_to_protocol_error(status)),
}
}};
}
macro_rules! signed_call {
($self:ident, $client:ident, $rpc:ident, $path:expr, $msg:expr) => {{ signed_request_call!($self, $client, $rpc, $path, Request::new($msg)) }};
}
macro_rules! authed_call {
($self:ident, $rpc:ident, $grpc_method:literal, $msg:expr) => {{
signed_call!(
$self,
user,
$rpc,
concat!("/heddle.api.v1alpha1.RegistryService/", $grpc_method),
$msg
)
}};
}
macro_rules! workflow_call {
($self:ident, $rpc:ident, $grpc_method:literal, $msg:expr) => {{
signed_call!(
$self,
workflow,
$rpc,
concat!("/heddle.api.v1alpha1.WorkflowService/", $grpc_method),
$msg
)
}};
}
fn default_spool_settings_request() -> grpc::heddle::api::v1alpha1::SpoolSettings {
use grpc::heddle::api::v1alpha1::{
SpoolBootstrapKind, SpoolBootstrapSyncDirection, SpoolChildPolicy, SpoolHoldLifecycle,
SpoolInitialTooling, SpoolSettings, SpoolStateVisibility, SpoolSyncBehavior,
SpoolVisibility, SpoolWritePolicy,
};
SpoolSettings {
visibility: SpoolVisibility::Private as i32,
default_state_visibility: SpoolStateVisibility::Internal as i32,
bootstrap_kind: SpoolBootstrapKind::Empty as i32,
bootstrap_source: String::new(),
write_policy: SpoolWritePolicy::Developers as i32,
child_policy: SpoolChildPolicy::Maintainers as i32,
initial_tooling: Some(SpoolInitialTooling::default()),
sync_behavior: SpoolSyncBehavior::Manual as i32,
bootstrap_sync_direction: SpoolBootstrapSyncDirection::Pull as i32,
description: String::new(),
hold_lifecycle: SpoolHoldLifecycle::Unspecified as i32,
}
}
impl HostedGrpcClient {
pub(crate) async fn who_am_i(
&mut self,
) -> Result<grpc::heddle::api::v1alpha1::WhoAmIResponse, ProtocolError> {
Ok(signed_call!(
self,
auth,
who_am_i,
"/heddle.api.v1alpha1.IdentityService/WhoAmI",
grpc::heddle::api::v1alpha1::WhoAmIRequest {}
))
}
pub(crate) async fn create_service_account(
&mut self,
request: CreateServiceAccountRequest,
) -> Result<ServiceAccountResponse, ProtocolError> {
Ok(signed_call!(
self,
auth,
create_service_account,
"/heddle.api.v1alpha1.IdentityService/CreateServiceAccount",
request
))
}
pub(crate) async fn issue_service_account_credential(
&mut self,
request: Request<IssueServiceAccountCredentialRequest>,
) -> Result<IssuedCredentialResponse, ProtocolError> {
Ok(signed_request_call!(
self,
auth,
issue_service_account_credential,
"/heddle.api.v1alpha1.IdentityService/IssueServiceAccountCredential",
request
))
}
pub async fn begin_login(
&mut self,
username: &str,
) -> Result<(String, String, u64), ProtocolError> {
let request = Request::new(BeginWebAuthnAuthenticationRequest {
username: username.to_string(),
});
let response = self
.auth
.begin_web_authn_authentication(request)
.await
.map_err(status_to_protocol_error)?
.into_inner();
let expires_at_secs = response
.expires_at
.as_ref()
.map(|t| t.seconds.max(0) as u64)
.unwrap_or(0);
Ok((response.challenge_id, response.challenge, expires_at_secs))
}
pub async fn get_current_user_namespace(
&mut self,
) -> Result<wire::HostedNamespaceInfo, ProtocolError> {
let namespace = authed_call!(
self,
get_current_user_namespace,
"GetCurrentUserNamespace",
GetCurrentUserNamespaceRequest {}
);
Ok(to_protocol_namespace(namespace))
}
pub async fn list_spools(
&mut self,
repos_only: bool,
) -> Result<Vec<SpoolSummary>, ProtocolError> {
let response = authed_call!(
self,
list_spools,
"ListSpools",
ListSpoolsRequest { repos_only }
);
Ok(response.spools)
}
pub async fn create_namespace(
&mut self,
kind: &str,
slug: &str,
parent_path: Option<&str>,
display_name: Option<String>,
) -> Result<wire::HostedNamespaceInfo, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/CreateNamespace");
let namespace = authed_call!(
self,
create_namespace,
"CreateNamespace",
grpc::heddle::api::v1alpha1::CreateNamespaceRequest {
kind: parse_namespace_kind_arg(kind)? as i32,
slug: slug.to_string(),
parent_path: parent_path.unwrap_or_default().to_string(),
display_name: display_name.unwrap_or_default(),
settings: Some(default_spool_settings_request()),
client_operation_id: operation_id.to_wire(),
}
);
Ok(to_protocol_namespace(namespace))
}
pub async fn create_repository(
&mut self,
namespace_path: &str,
slug: &str,
) -> Result<wire::HostedRepositoryInfo, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/CreateRepository");
let repo = authed_call!(
self,
create_repository,
"CreateRepository",
CreateRepositoryRequest {
namespace_path: namespace_path.to_string(),
slug: slug.to_string(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(to_protocol_repository(repo))
}
pub async fn update_namespace(
&mut self,
full_path: &str,
new_slug: Option<&str>,
display_name: Option<Option<String>>,
) -> Result<wire::HostedNamespaceInfo, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/UpdateNamespace");
let (display_name, clear_display_name) = match display_name {
Some(Some(value)) => (value, false),
Some(None) => (String::new(), true),
None => (String::new(), false),
};
let namespace = authed_call!(
self,
update_namespace,
"UpdateNamespace",
UpdateNamespaceRequest {
full_path: full_path.to_string(),
new_slug: new_slug.unwrap_or_default().to_string(),
display_name,
clear_display_name,
client_operation_id: operation_id.to_wire(),
}
);
Ok(to_protocol_namespace(namespace))
}
pub async fn delete_namespace(&mut self, full_path: &str) -> Result<(), ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/DeleteNamespace");
authed_call!(
self,
delete_namespace,
"DeleteNamespace",
DeleteNamespaceRequest {
full_path: full_path.to_string(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(())
}
pub async fn update_repository(
&mut self,
full_path: &str,
new_slug: &str,
) -> Result<wire::HostedRepositoryInfo, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/UpdateRepository");
let repo = authed_call!(
self,
update_repository,
"UpdateRepository",
UpdateRepositoryRequest {
full_path: full_path.to_string(),
new_slug: new_slug.to_string(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(to_protocol_repository(repo))
}
pub async fn delete_repository(&mut self, full_path: &str) -> Result<(), ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/DeleteRepository");
authed_call!(
self,
delete_repository,
"DeleteRepository",
DeleteRepositoryRequest {
full_path: full_path.to_string(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(())
}
pub async fn create_grant(
&mut self,
subject: &str,
role: &str,
namespace_path: Option<&str>,
repo_path: Option<&str>,
) -> Result<wire::HostedGrantInfo, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/CreateGrant");
let target = build_target_ref(namespace_path, repo_path)?;
let grant = authed_call!(
self,
create_grant,
"CreateGrant",
CreateGrantRequest {
subject: subject.to_string(),
role: parse_hosted_role_arg(role)? as i32,
target,
client_operation_id: operation_id.to_wire(),
}
);
Ok(to_protocol_grant(grant))
}
pub async fn list_grants(
&mut self,
resource: Option<&str>,
) -> Result<Vec<wire::HostedGrantInfo>, ProtocolError> {
let response = authed_call!(
self,
list_grants,
"ListGrants",
ListGrantsRequest {
resource: resource.unwrap_or_default().to_string(),
}
);
Ok(response.grants.into_iter().map(to_protocol_grant).collect())
}
pub async fn update_grant(
&mut self,
subject: &str,
role: &str,
namespace_path: Option<&str>,
repo_path: Option<&str>,
) -> Result<wire::HostedGrantInfo, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/UpdateGrant");
let target = build_target_ref(namespace_path, repo_path)?;
let grant = authed_call!(
self,
update_grant,
"UpdateGrant",
UpdateGrantRequest {
subject: subject.to_string(),
role: parse_hosted_role_arg(role)? as i32,
target,
client_operation_id: operation_id.to_wire(),
}
);
Ok(to_protocol_grant(grant))
}
pub async fn delete_grant(
&mut self,
subject: &str,
namespace_path: Option<&str>,
repo_path: Option<&str>,
) -> Result<(), ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/DeleteGrant");
let target = build_target_ref(namespace_path, repo_path)?;
authed_call!(
self,
delete_grant,
"DeleteGrant",
DeleteGrantRequest {
subject: subject.to_string(),
target,
client_operation_id: operation_id.to_wire(),
}
);
Ok(())
}
pub async fn create_invitation(
&mut self,
email: &str,
namespace_path: &str,
role: &str,
) -> Result<ProtoInvitation, ProtocolError> {
let operation_id =
ClientOperationId::fresh("heddle.api.v1alpha1.RegistryService/CreateInvitation");
let invitation = authed_call!(
self,
create_invitation,
"CreateInvitation",
CreateInvitationRequest {
email: email.to_string(),
namespace_path: namespace_path.to_string(),
role: parse_hosted_role_arg(role)? as i32,
expires_at: None,
metadata: String::new(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(invitation)
}
pub async fn approve_thread(
&mut self,
repo_path: &str,
source_thread: &str,
target_thread: &str,
source_state: &str,
note: Option<&str>,
client_operation_id: String,
) -> Result<ThreadApproval, ProtocolError> {
let operation_id = ClientOperationId::caller_or_fresh(
"heddle.api.v1alpha1.WorkflowService/ApproveThread",
client_operation_id,
);
Ok(workflow_call!(
self,
approve_thread,
"ApproveThread",
ApproveThreadRequest {
repo_path: super::helpers::repository_ref(repo_path),
source_thread: source_thread.to_string(),
target_thread: target_thread.to_string(),
source_state: objects::object::StateId::parse(source_state)
.ok()
.and_then(super::helpers::proto_state_id),
note: note.unwrap_or_default().to_string(),
client_operation_id: operation_id.to_wire(),
}
))
}
pub async fn revoke_approval(
&mut self,
id: &str,
client_operation_id: String,
) -> Result<(), ProtocolError> {
let operation_id = ClientOperationId::caller_or_fresh(
"heddle.api.v1alpha1.WorkflowService/RevokeApproval",
client_operation_id,
);
workflow_call!(
self,
revoke_approval,
"RevokeApproval",
RevokeApprovalRequest {
id: id.to_string(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(())
}
pub async fn list_thread_approvals(
&mut self,
repo_path: &str,
source_thread: &str,
target_thread: &str,
) -> Result<Vec<ThreadApproval>, ProtocolError> {
Ok(workflow_call!(
self,
list_thread_approvals,
"ListThreadApprovals",
ListThreadApprovalsRequest {
repo_path: super::helpers::repository_ref(repo_path),
source_thread: source_thread.to_string(),
target_thread: target_thread.to_string(),
}
)
.approvals)
}
#[allow(clippy::too_many_arguments)]
pub async fn check_merge_eligibility(
&mut self,
repo_path: &str,
source_thread: &str,
target_thread: &str,
source_state: &str,
gated_action: &str,
changed_paths: Vec<String>,
author_user_id: Option<&str>,
) -> Result<CheckMergeEligibilityResponse, ProtocolError> {
Ok(workflow_call!(
self,
check_merge_eligibility,
"CheckMergeEligibility",
CheckMergeEligibilityRequest {
repo_path: super::helpers::repository_ref(repo_path),
source_thread: source_thread.to_string(),
target_thread: target_thread.to_string(),
source_state: objects::object::StateId::parse(source_state)
.ok()
.and_then(super::helpers::proto_state_id),
gated_action: gated_action.to_string(),
changed_paths,
author_user_id: author_user_id.unwrap_or_default().to_string(),
}
))
}
pub async fn grant_support_access(
&mut self,
operator_email: &str,
namespace_path: Option<&str>,
repo_path: Option<&str>,
ttl_seconds: u32,
reason: &str,
client_operation_id: String,
) -> Result<SupportAccessGrant, ProtocolError> {
let operation_id = ClientOperationId::caller_or_fresh(
"heddle.api.v1alpha1.RegistryService/GrantSupportAccess",
client_operation_id,
);
let target = build_target_ref(namespace_path, repo_path)?;
Ok(authed_call!(
self,
grant_support_access,
"GrantSupportAccess",
GrantSupportAccessRequest {
operator_email: operator_email.to_string(),
target,
ttl_seconds: Some(prost_types::Duration {
seconds: i64::from(ttl_seconds),
nanos: 0,
}),
reason: reason.to_string(),
client_operation_id: operation_id.to_wire(),
}
))
}
pub async fn list_support_access_grants(
&mut self,
namespace_path: Option<&str>,
repo_path: Option<&str>,
include_inactive: bool,
) -> Result<Vec<SupportAccessGrant>, ProtocolError> {
let target = build_target_ref(namespace_path, repo_path)?;
Ok(authed_call!(
self,
list_support_access_grants,
"ListSupportAccessGrants",
ListSupportAccessGrantsRequest {
target,
include_inactive,
}
)
.grants)
}
pub async fn revoke_support_access(
&mut self,
id: &str,
client_operation_id: String,
) -> Result<(), ProtocolError> {
let operation_id = ClientOperationId::caller_or_fresh(
"heddle.api.v1alpha1.RegistryService/RevokeSupportAccess",
client_operation_id,
);
authed_call!(
self,
revoke_support_access,
"RevokeSupportAccess",
RevokeSupportAccessRequest {
id: id.to_string(),
client_operation_id: operation_id.to_wire(),
}
);
Ok(())
}
pub async fn resolve_monorepo(
&mut self,
root_path: &str,
max_depth: Option<u32>,
) -> Result<MonorepoNode, ProtocolError> {
Ok(authed_call!(
self,
resolve_monorepo,
"ResolveMonorepo",
ResolveMonorepoRequest {
root_path: root_path.to_string(),
max_depth,
}
))
}
}
fn build_target_ref(
namespace_path: Option<&str>,
repo_path: Option<&str>,
) -> Result<Option<GrantTargetRef>, ProtocolError> {
match (
namespace_path.filter(|s| !s.is_empty()),
repo_path.filter(|s| !s.is_empty()),
) {
(Some(ns), None) => Ok(Some(GrantTargetRef {
target: Some(GrantTargetKind::NamespacePath(ns.to_string())),
})),
(None, Some(rp)) => Ok(Some(GrantTargetRef {
target: Some(GrantTargetKind::RepoPath(
super::helpers::repository_ref(rp).expect("non-empty repository path"),
)),
})),
_ => Err(ProtocolError::InvalidState(
"exactly one of namespace_path or repo_path must be set".into(),
)),
}
}
fn parse_namespace_kind_arg(
value: &str,
) -> Result<grpc::heddle::api::v1alpha1::NamespaceKind, ProtocolError> {
use grpc::heddle::api::v1alpha1::NamespaceKind;
match value.trim().to_ascii_lowercase().as_str() {
"user" => Ok(NamespaceKind::User),
"namespace" | "org" => Ok(NamespaceKind::Org),
"team" => Ok(NamespaceKind::Team),
other => Err(ProtocolError::InvalidState(format!(
"invalid namespace kind '{other}': expected user|namespace|team"
))),
}
}
fn parse_hosted_role_arg(
value: &str,
) -> Result<grpc::heddle::api::v1alpha1::HostedRole, ProtocolError> {
use grpc::heddle::api::v1alpha1::HostedRole;
match value.trim().to_ascii_lowercase().as_str() {
"reader" => Ok(HostedRole::Reader),
"developer" => Ok(HostedRole::Developer),
"maintainer" => Ok(HostedRole::Maintainer),
"admin" => Ok(HostedRole::Admin),
"owner" => Ok(HostedRole::Owner),
other => Err(ProtocolError::InvalidState(format!(
"invalid role '{other}': expected reader|developer|maintainer|admin|owner"
))),
}
}
#[cfg(test)]
mod request_shape_tests {
use grpc::heddle::api::v1alpha1::{
ClaimHandleRequest, GetHandleStatusRequest, HandlePrincipal,
IssueServiceAccountCredentialRequest, RequestHeldNameRequest, ResolveHandleRequest,
ResolveMonorepoRequest, identity_service_client::IdentityServiceClient,
};
use prost::Message;
use tonic::{Request, transport::Channel};
use super::clone_request_for_retry;
#[test]
fn credential_issue_retry_preserves_custom_proof_and_operation_id() {
let mut original = Request::new(IssueServiceAccountCredentialRequest {
service_account_id: "sa-1".to_string(),
public_key: vec![7; 32],
scope: "repo:acme/*".to_string(),
ttl_secs: None,
client_operation_id: "stable-op-1".to_string(),
});
original
.metadata_mut()
.insert("x-heddle-issue-sa-proof-ts", "1700000000".parse().unwrap());
original.metadata_mut().insert_bin(
"x-heddle-issue-sa-proof-sig-bin",
tonic::metadata::MetadataValue::from_bytes(b"service-account-proof"),
);
let retry = clone_request_for_retry(&original);
assert_eq!(retry.get_ref(), original.get_ref());
assert_eq!(retry.get_ref().client_operation_id, "stable-op-1");
assert_eq!(
retry
.metadata()
.get("x-heddle-issue-sa-proof-ts")
.and_then(|value| value.to_str().ok()),
Some("1700000000")
);
assert!(
retry
.metadata()
.get_bin("x-heddle-issue-sa-proof-sig-bin")
.is_some()
);
}
#[test]
fn resolve_monorepo_request_threads_optional_max_depth() {
let bounded = ResolveMonorepoRequest {
root_path: "acme/root".to_string(),
max_depth: Some(3),
};
assert_eq!(bounded.root_path, "acme/root");
assert_eq!(bounded.max_depth, Some(3));
let unbounded = ResolveMonorepoRequest {
root_path: "acme/root".to_string(),
max_depth: None,
};
assert_eq!(unbounded.max_depth, None);
}
#[test]
fn shared_handle_client_surface_is_generated_with_retry_keys() {
#[allow(dead_code)]
async fn compile_all_handle_calls(mut client: IdentityServiceClient<Channel>) {
let _ = client
.get_handle_status(GetHandleStatusRequest {
name: "octocat".to_string(),
})
.await;
let _ = client
.request_held_name(RequestHeldNameRequest {
name: "octocat".to_string(),
client_operation_id: "request-1".to_string(),
})
.await;
let _ = client
.claim_handle(ClaimHandleRequest {
name: "octocat".to_string(),
client_operation_id: "claim-1".to_string(),
})
.await;
let _ = client
.resolve_handle(ResolveHandleRequest {
name: "octocat".to_string(),
})
.await;
}
let _ = compile_all_handle_calls;
}
#[test]
fn shared_handle_principal_drops_the_legacy_subject_field() {
#[derive(Clone, PartialEq, Message)]
struct LegacyResolvedPrincipal {
#[prost(string, tag = "1")]
subject: String,
#[prost(string, tag = "2")]
display_name: String,
#[prost(string, tag = "3")]
handle: String,
#[prost(bool, tag = "4")]
resolved: bool,
#[prost(string, tag = "5")]
primary_handle: String,
#[prost(string, tag = "6")]
kind: String,
#[prost(bool, tag = "7")]
verified: bool,
#[prost(string, tag = "8")]
discriminator: String,
}
let legacy = LegacyResolvedPrincipal {
subject: "user:private".to_string(),
display_name: "Octo Cat".to_string(),
handle: "octocat".to_string(),
resolved: true,
primary_handle: "octocat".to_string(),
kind: "native".to_string(),
verified: true,
discriminator: String::new(),
};
let public = HandlePrincipal::decode(legacy.encode_to_vec().as_slice())
.expect("legacy public tags must decode");
assert_eq!(public.display_name, "Octo Cat");
assert_eq!(public.handle, "octocat");
assert_eq!(public.primary_handle, "octocat");
assert!(public.resolved);
assert!(public.verified);
let round_trip = LegacyResolvedPrincipal::decode(public.encode_to_vec().as_slice())
.expect("public principal must remain wire-compatible on tags 2-8");
assert!(
round_trip.subject.is_empty(),
"the reserved legacy subject tag must not survive public decoding"
);
let descriptor = prost_types::FileDescriptorSet::decode(grpc::FILE_DESCRIPTOR_SET)
.expect("the shared API descriptor must decode");
let principal = descriptor
.file
.iter()
.filter(|file| file.package.as_deref() == Some("heddle.api.v1alpha1"))
.flat_map(|file| &file.message_type)
.find(|message| message.name.as_deref() == Some("HandlePrincipal"))
.expect("the shared descriptor must define HandlePrincipal");
assert!(
principal
.field
.iter()
.all(|field| field.name.as_deref() != Some("subject")),
"HandlePrincipal must not expose subject at any tag"
);
assert!(principal.reserved_name.iter().any(|name| name == "subject"));
assert!(
principal.reserved_range.iter().any(|range| {
range.start.is_some_and(|start| start <= 1) && range.end.is_some_and(|end| end > 1)
}),
"HandlePrincipal must reserve legacy subject tag 1"
);
}
#[test]
fn workflow_mutations_and_credential_issue_use_shared_retry_chokepoints() {
let source = include_str!("user.rs");
let approve = source
.split("pub async fn approve_thread")
.nth(1)
.and_then(|tail| tail.split("pub async fn revoke_approval").next())
.expect("approve_thread source");
let revoke = source
.split("pub async fn revoke_approval")
.nth(1)
.and_then(|tail| tail.split("pub async fn list_thread_approvals").next())
.expect("revoke_approval source");
let issue = source
.split("pub(crate) async fn issue_service_account_credential")
.nth(1)
.and_then(|tail| tail.split("pub async fn begin_login").next())
.expect("credential issue source");
assert!(approve.contains("caller_or_fresh"));
assert!(revoke.contains("caller_or_fresh"));
assert!(issue.contains("signed_request_call!"));
}
}