Source commit: 01875e88a3e25379c309489f9f057dd97c0d37de Public tree identity: sha256:8f37a1aa0cc8f408975daf9cabbe193f8f4c169c6d25e8795e67a3ed5083c76b
271 lines
9.4 KiB
Rust
271 lines
9.4 KiB
Rust
use anyhow::Result;
|
|
use clusterflux_core::Digest;
|
|
use serde_json::{json, Value};
|
|
|
|
use crate::client::{authenticated_or_local_trusted_request, JsonLineSession};
|
|
use crate::config::StoredCliSession;
|
|
use crate::{confirmation_required_report, KeyAddArgs, KeyListArgs, KeyRevokeArgs};
|
|
|
|
#[cfg(test)]
|
|
pub(crate) fn key_add_report(args: KeyAddArgs) -> Result<Value> {
|
|
key_add_report_with_session(args, None)
|
|
}
|
|
|
|
pub(crate) fn key_add_report_with_session(
|
|
args: KeyAddArgs,
|
|
stored_session: Option<&StoredCliSession>,
|
|
) -> Result<Value> {
|
|
let coordinator = effective_coordinator(&args.scope.coordinator, stored_session);
|
|
if let Some(coordinator) = &coordinator {
|
|
let tenant = effective_session_value(stored_session, &args.scope.tenant, |session| {
|
|
&session.tenant
|
|
});
|
|
let project = effective_session_value(stored_session, &args.scope.project, |session| {
|
|
&session.project
|
|
});
|
|
let user =
|
|
effective_session_value(stored_session, &args.scope.user, |session| &session.user);
|
|
let agent = args.agent.clone();
|
|
let public_key_fingerprint = Digest::sha256(&args.public_key);
|
|
let mut session = JsonLineSession::connect(coordinator)?;
|
|
let response = session.request(authenticated_or_local_trusted_request(
|
|
coordinator,
|
|
stored_session,
|
|
json!({
|
|
"type": "register_agent_public_key",
|
|
"agent": agent,
|
|
"public_key": args.public_key,
|
|
}),
|
|
json!({
|
|
"type": "register_agent_public_key",
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
"agent": agent,
|
|
"public_key": args.public_key,
|
|
}),
|
|
)?)?;
|
|
let record = response.get("record").cloned().unwrap_or_else(|| {
|
|
json!({
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
"agent": agent,
|
|
"public_key_fingerprint": public_key_fingerprint,
|
|
"scopes": ["project:read", "project:run"],
|
|
"human_account_creation_privilege": false,
|
|
"browser_interaction_required_each_run": false,
|
|
})
|
|
});
|
|
return Ok(json!({
|
|
"command": "key add",
|
|
"coordinator": coordinator,
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
"agent": agent,
|
|
"public_key_fingerprint": record
|
|
.get("public_key_fingerprint")
|
|
.cloned()
|
|
.unwrap_or_else(|| json!(public_key_fingerprint)),
|
|
"credential_scope": {
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"actions": record
|
|
.get("scopes")
|
|
.cloned()
|
|
.unwrap_or_else(|| json!(["project:read", "project:run"])),
|
|
"human_account_creation_privilege": record
|
|
.get("human_account_creation_privilege")
|
|
.cloned()
|
|
.unwrap_or(json!(false)),
|
|
},
|
|
"browser_interaction_required_each_run": record
|
|
.get("browser_interaction_required_each_run")
|
|
.cloned()
|
|
.unwrap_or(json!(false)),
|
|
"attribution": {
|
|
"registered_by_user": user,
|
|
"agent": agent,
|
|
"credential_kind": "public_key",
|
|
},
|
|
"response": response,
|
|
"coordinator_session_requests": session.requests(),
|
|
}));
|
|
}
|
|
Ok(json!({
|
|
"command": "key add",
|
|
"status": "planned_without_coordinator",
|
|
"agent": args.agent,
|
|
"public_key_fingerprint": Digest::sha256(args.public_key),
|
|
"browser_interaction_required_each_run": false,
|
|
}))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub(crate) fn key_list_report(args: KeyListArgs) -> Result<Value> {
|
|
key_list_report_with_session(args, None)
|
|
}
|
|
|
|
pub(crate) fn key_list_report_with_session(
|
|
args: KeyListArgs,
|
|
stored_session: Option<&StoredCliSession>,
|
|
) -> Result<Value> {
|
|
let coordinator = effective_coordinator(&args.scope.coordinator, stored_session);
|
|
if let Some(coordinator) = &coordinator {
|
|
let tenant = effective_session_value(stored_session, &args.scope.tenant, |session| {
|
|
&session.tenant
|
|
});
|
|
let project = effective_session_value(stored_session, &args.scope.project, |session| {
|
|
&session.project
|
|
});
|
|
let user =
|
|
effective_session_value(stored_session, &args.scope.user, |session| &session.user);
|
|
let mut session = JsonLineSession::connect(coordinator)?;
|
|
let response = session.request(authenticated_or_local_trusted_request(
|
|
coordinator,
|
|
stored_session,
|
|
json!({
|
|
"type": "list_agent_public_keys",
|
|
}),
|
|
json!({
|
|
"type": "list_agent_public_keys",
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
}),
|
|
)?)?;
|
|
return Ok(json!({
|
|
"command": "key list",
|
|
"coordinator": coordinator,
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
"records": response
|
|
.get("records")
|
|
.cloned()
|
|
.unwrap_or_else(|| json!([])),
|
|
"credential_scope": {
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"listed_for_user": user,
|
|
"human_account_creation_privilege": false,
|
|
},
|
|
"response": response,
|
|
"coordinator_session_requests": session.requests(),
|
|
}));
|
|
}
|
|
Ok(json!({
|
|
"command": "key list",
|
|
"status": "requires_coordinator",
|
|
"records": [],
|
|
}))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub(crate) fn key_revoke_report(args: KeyRevokeArgs) -> Result<Value> {
|
|
key_revoke_report_with_session(args, None)
|
|
}
|
|
|
|
pub(crate) fn key_revoke_report_with_session(
|
|
args: KeyRevokeArgs,
|
|
stored_session: Option<&StoredCliSession>,
|
|
) -> Result<Value> {
|
|
if !args.yes {
|
|
return Ok(confirmation_required_report(
|
|
"key revoke",
|
|
"revoke_agent_public_key",
|
|
json!({
|
|
"coordinator": args.scope.coordinator,
|
|
"tenant": args.scope.tenant,
|
|
"project": args.scope.project,
|
|
"user": args.scope.user,
|
|
"agent": args.agent,
|
|
}),
|
|
format!("clusterflux key revoke --agent {} --yes", args.agent),
|
|
));
|
|
}
|
|
let coordinator = effective_coordinator(&args.scope.coordinator, stored_session);
|
|
if let Some(coordinator) = &coordinator {
|
|
let tenant = effective_session_value(stored_session, &args.scope.tenant, |session| {
|
|
&session.tenant
|
|
});
|
|
let project = effective_session_value(stored_session, &args.scope.project, |session| {
|
|
&session.project
|
|
});
|
|
let user =
|
|
effective_session_value(stored_session, &args.scope.user, |session| &session.user);
|
|
let agent = args.agent.clone();
|
|
let mut session = JsonLineSession::connect(coordinator)?;
|
|
let response = session.request(authenticated_or_local_trusted_request(
|
|
coordinator,
|
|
stored_session,
|
|
json!({
|
|
"type": "revoke_agent_public_key",
|
|
"agent": agent,
|
|
}),
|
|
json!({
|
|
"type": "revoke_agent_public_key",
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
"agent": agent,
|
|
}),
|
|
)?)?;
|
|
return Ok(json!({
|
|
"command": "key revoke",
|
|
"coordinator": coordinator,
|
|
"requires_confirmation": !args.yes,
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"user": user,
|
|
"agent": agent,
|
|
"revoked": response
|
|
.pointer("/record/revoked")
|
|
.cloned()
|
|
.unwrap_or(json!(true)),
|
|
"credential_scope": {
|
|
"tenant": tenant,
|
|
"project": project,
|
|
"revoked_for_user": user,
|
|
"human_account_creation_privilege": false,
|
|
},
|
|
"attribution": {
|
|
"revoked_by_user": user,
|
|
"agent": agent,
|
|
"credential_kind": "public_key",
|
|
},
|
|
"response": response,
|
|
"coordinator_session_requests": session.requests(),
|
|
}));
|
|
}
|
|
Ok(json!({
|
|
"command": "key revoke",
|
|
"status": "requires_coordinator",
|
|
"requires_confirmation": !args.yes,
|
|
"agent": args.agent,
|
|
}))
|
|
}
|
|
|
|
fn effective_coordinator(
|
|
requested: &Option<String>,
|
|
stored_session: Option<&StoredCliSession>,
|
|
) -> Option<String> {
|
|
requested.clone().or_else(|| {
|
|
stored_session
|
|
.filter(|session| session.session_secret.is_some())
|
|
.map(|session| session.coordinator.clone())
|
|
})
|
|
}
|
|
|
|
fn effective_session_value(
|
|
stored_session: Option<&StoredCliSession>,
|
|
requested: &str,
|
|
value: impl FnOnce(&StoredCliSession) -> &String,
|
|
) -> String {
|
|
stored_session
|
|
.filter(|session| session.session_secret.is_some())
|
|
.map(value)
|
|
.cloned()
|
|
.unwrap_or_else(|| requested.to_owned())
|
|
}
|