From a89d33ca0ac870c152c2b56f2c6c9b95eb1104dd Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Mon, 9 Feb 2026 17:54:38 +0100 Subject: [PATCH 01/22] Update create.rs --- .../src/commands/authorization/create.rs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/create.rs b/tools/rust-tools/run-manager/src/commands/authorization/create.rs index 8a84623c0..a280240cb 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/create.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/create.rs @@ -1,23 +1,39 @@ use crate::commands::Command; use anchor_client::solana_sdk::pubkey::Pubkey; +use anchor_client::solana_sdk::system_program; use anyhow::Result; use async_trait::async_trait; use clap::Args; -use psyche_solana_rpc::SolanaBackend; use psyche_solana_rpc::instructions; +use psyche_solana_rpc::SolanaBackend; #[derive(Debug, Clone, Args)] #[command()] pub struct CommandJoinAuthorizationCreate { - #[clap(long, env)] - pub authorizer: Pubkey, + #[clap(long, env, conflicts_with = "permissionless")] + pub authorizer: Option, + + /// Create a permissionless authorization (uses system program ID) + #[clap(long, conflicts_with = "authorizer")] + pub permissionless: bool, } #[async_trait] impl Command for CommandJoinAuthorizationCreate { async fn execute(self, backend: SolanaBackend) -> Result<()> { - let Self { authorizer } = self; + let Self { + authorizer, + permissionless, + } = self; + + let authorizer = if permissionless { + system_program::ID + } else { + authorizer.ok_or_else(|| { + anyhow::anyhow!("Either --authorizer or --permissionless must be provided") + })? + }; let payer = backend.get_payer(); let grantor = backend.get_payer(); From a566407401df619d96b17acab17811709f6f6a68 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Mon, 9 Feb 2026 17:58:45 +0100 Subject: [PATCH 02/22] Update delete.rs --- .../src/commands/authorization/delete.rs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/delete.rs b/tools/rust-tools/run-manager/src/commands/authorization/delete.rs index 4a6a99917..f09727b32 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/delete.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/delete.rs @@ -1,23 +1,39 @@ use crate::commands::Command; use anchor_client::solana_sdk::pubkey::Pubkey; +use anchor_client::solana_sdk::system_program; use anyhow::Result; use async_trait::async_trait; use clap::Args; -use psyche_solana_rpc::SolanaBackend; use psyche_solana_rpc::instructions; +use psyche_solana_rpc::SolanaBackend; #[derive(Debug, Clone, Args)] #[command()] pub struct CommandJoinAuthorizationDelete { - #[clap(long, env)] - pub authorizer: Pubkey, + #[clap(long, env, conflicts_with = "permissionless")] + pub authorizer: Option, + + /// Delete a permissionless authorization (uses system program ID) + #[clap(long, conflicts_with = "authorizer")] + pub permissionless: bool, } #[async_trait] impl Command for CommandJoinAuthorizationDelete { async fn execute(self, backend: SolanaBackend) -> Result<()> { - let Self { authorizer } = self; + let Self { + authorizer, + permissionless, + } = self; + + let authorizer = if permissionless { + system_program::ID + } else { + authorizer.ok_or_else(|| { + anyhow::anyhow!("Either --authorizer or --permissionless must be provided") + })? + }; let grantor = backend.get_payer(); let grantee = authorizer; From 2523b93d01c2c6f398faf2f28ad7c0c0bc860b6b Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Mon, 9 Feb 2026 17:59:03 +0100 Subject: [PATCH 03/22] Update can_join.rs --- .../run-manager/src/commands/can_join.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/can_join.rs b/tools/rust-tools/run-manager/src/commands/can_join.rs index 64a6469dd..215764c1b 100644 --- a/tools/rust-tools/run-manager/src/commands/can_join.rs +++ b/tools/rust-tools/run-manager/src/commands/can_join.rs @@ -1,7 +1,8 @@ use crate::commands::Command; use anchor_client::solana_sdk::pubkey::Pubkey; -use anyhow::Result; +use anchor_client::solana_sdk::system_program; use anyhow::bail; +use anyhow::Result; use async_trait::async_trait; use clap::Args; use psyche_coordinator::RunState; @@ -13,8 +14,11 @@ use psyche_solana_rpc::SolanaBackend; pub struct CommandCanJoin { #[clap(short, long, env)] pub run_id: String, - #[clap(long, env)] + #[clap(long, env, conflicts_with = "permissionless")] pub authorizer: Option, + /// Check permissionless authorization (uses system program ID) + #[clap(long, conflicts_with = "authorizer")] + pub permissionless: bool, #[clap(long, env, alias = "wallet", alias = "user", value_name = "PUBKEY")] pub address: Pubkey, } @@ -25,9 +29,16 @@ impl Command for CommandCanJoin { let Self { run_id, authorizer, + permissionless, address, } = self; + let authorizer = if permissionless { + Some(system_program::ID) + } else { + authorizer + }; + let coordinator_instance = psyche_solana_coordinator::find_coordinator_instance(&run_id); let coordinator_instance_state = backend .get_coordinator_instance(&coordinator_instance) From 0cc646d796a1acdec486e9a951ffec976c50ab67 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Mon, 9 Feb 2026 18:00:43 +0100 Subject: [PATCH 04/22] Update read.rs --- .../run-manager/src/commands/authorization/read.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/read.rs b/tools/rust-tools/run-manager/src/commands/authorization/read.rs index b69970d03..bf71c1960 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/read.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/read.rs @@ -12,8 +12,11 @@ use psyche_solana_rpc::SolanaBackend; pub struct CommandJoinAuthorizationRead { #[clap(long, env)] pub join_authority: Pubkey, - #[clap(long, env)] + #[clap(long, env, conflicts_with = "permissionless")] pub authorizer: Option, + /// Read permissionless authorization (uses system program ID) + #[clap(long, conflicts_with = "authorizer")] + pub permissionless: bool, } #[async_trait] @@ -22,10 +25,15 @@ impl Command for CommandJoinAuthorizationRead { let Self { join_authority, authorizer, + permissionless, } = self; let grantor = join_authority; - let grantee = authorizer.unwrap_or(system_program::ID); + let grantee = if permissionless { + system_program::ID + } else { + authorizer.unwrap_or(system_program::ID) + }; let scope = psyche_solana_coordinator::logic::JOIN_RUN_AUTHORIZATION_SCOPE; println!("Authorization Grantor: {}", grantor); From 6f4e3bab92319935d2e591cbc716320ec8aa60f6 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Mon, 9 Feb 2026 18:03:48 +0100 Subject: [PATCH 05/22] Update integration_tests.rs --- .../run-manager/tests/integration_tests.rs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tools/rust-tools/run-manager/tests/integration_tests.rs b/tools/rust-tools/run-manager/tests/integration_tests.rs index edb623d39..31734640f 100644 --- a/tools/rust-tools/run-manager/tests/integration_tests.rs +++ b/tools/rust-tools/run-manager/tests/integration_tests.rs @@ -4,20 +4,20 @@ mod common; use anchor_client::{ - Cluster, solana_sdk::{commitment_config::CommitmentConfig, signature::Signer}, + Cluster, }; -use common::{TestClient, TestValidator, create_test_keypair}; +use common::{create_test_keypair, TestClient, TestValidator}; use psyche_coordinator::RunState; use psyche_solana_rpc::SolanaBackend; use run_manager::commands::{ - Command, authorization::{ CommandJoinAuthorizationCreate, CommandJoinAuthorizationDelete, CommandJoinAuthorizationRead, }, can_join::CommandCanJoin, run::{CommandCloseRun, CommandCreateRun, CommandJsonDumpRun, CommandSetPaused}, + Command, }; use serial_test::serial; @@ -263,7 +263,8 @@ async fn test_join_authorization_create_and_read() { .expect("Failed to create backend"); let create_params = CommandJoinAuthorizationCreate { - authorizer: grantee_pubkey, + authorizer: Some(grantee_pubkey), + permissionless: false, }; create_params @@ -276,6 +277,7 @@ async fn test_join_authorization_create_and_read() { let read_params = CommandJoinAuthorizationRead { join_authority: grantor_arc.pubkey(), authorizer: Some(grantee_pubkey), + permissionless: false, }; read_params @@ -305,7 +307,8 @@ async fn test_join_authorization_delete() { .expect("Failed to create backend"); let create_params = CommandJoinAuthorizationCreate { - authorizer: grantee_pubkey, + authorizer: Some(grantee_pubkey), + permissionless: false, }; create_params @@ -316,7 +319,8 @@ async fn test_join_authorization_delete() { tokio::time::sleep(std::time::Duration::from_millis(500)).await; let delete_params = CommandJoinAuthorizationDelete { - authorizer: grantee_pubkey, + authorizer: Some(grantee_pubkey), + permissionless: false, }; delete_params @@ -375,6 +379,7 @@ async fn test_can_join_paused_run() { let can_join_params = CommandCanJoin { run_id: run_id.clone(), authorizer: None, + permissionless: false, address: wallet_arc.pubkey(), }; @@ -425,7 +430,8 @@ async fn test_full_authorization_workflow() { // 2. Create authorization for user let auth_params = CommandJoinAuthorizationCreate { - authorizer: user_pubkey, + authorizer: Some(user_pubkey), + permissionless: false, }; auth_params @@ -439,6 +445,7 @@ async fn test_full_authorization_workflow() { let can_join_params = CommandCanJoin { run_id: run_id.clone(), authorizer: Some(user_pubkey), + permissionless: false, address: user_pubkey, }; @@ -651,7 +658,8 @@ async fn test_join_authorization_delegate() { let grantee_pubkey = grantee_keypair.pubkey(); let create_params = CommandJoinAuthorizationCreate { - authorizer: grantee_pubkey, + authorizer: Some(grantee_pubkey), + permissionless: false, }; create_params From 808f5e97e68c6dd01eee5296bab3ec562b9b3336 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:31:52 +0100 Subject: [PATCH 06/22] Create types.rs --- .../src/commands/authorization/types.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tools/rust-tools/run-manager/src/commands/authorization/types.rs diff --git a/tools/rust-tools/run-manager/src/commands/authorization/types.rs b/tools/rust-tools/run-manager/src/commands/authorization/types.rs new file mode 100644 index 000000000..c2a4bd156 --- /dev/null +++ b/tools/rust-tools/run-manager/src/commands/authorization/types.rs @@ -0,0 +1,34 @@ +use anchor_client::solana_sdk::pubkey::Pubkey; +use anchor_client::solana_sdk::system_program; +use std::str::FromStr; + +#[derive(Debug, Clone)] +pub enum Authorization { + Address(Pubkey), + Permissionless, +} + +impl Authorization { + /// Convert to Pubkey. Permissionless maps to system_program::ID (11111111...) + pub fn to_pubkey(&self) -> Pubkey { + match self { + Authorization::Address(pubkey) => *pubkey, + Authorization::Permissionless => system_program::ID, + } + } +} + +impl FromStr for Authorization { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + if s.eq_ignore_ascii_case("permissionless") { + Ok(Authorization::Permissionless) + } else { + let pubkey = Pubkey::from_str(s) + .map_err(|e| anyhow::anyhow!("Invalid pubkey '{}': {}", s, e))?; + Ok(Authorization::Address(pubkey)) + } + } +} + From c01b45b394c657dd9833c6986389138081ff4eea Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:32:56 +0100 Subject: [PATCH 07/22] Update mod.rs --- tools/rust-tools/run-manager/src/commands/authorization/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/mod.rs b/tools/rust-tools/run-manager/src/commands/authorization/mod.rs index aa3ab50e5..33a7d75ee 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/mod.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/mod.rs @@ -2,8 +2,10 @@ pub mod create; pub mod delegate; pub mod delete; pub mod read; +pub mod types; pub use create::*; pub use delegate::*; pub use delete::*; pub use read::*; +pub use types::*; From cc36214b4d599f430ac2115ef413721877a67c95 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:33:08 +0100 Subject: [PATCH 08/22] Update create.rs --- .../src/commands/authorization/create.rs | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/create.rs b/tools/rust-tools/run-manager/src/commands/authorization/create.rs index a280240cb..354feba3f 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/create.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/create.rs @@ -1,6 +1,5 @@ use crate::commands::Command; -use anchor_client::solana_sdk::pubkey::Pubkey; -use anchor_client::solana_sdk::system_program; +use crate::commands::authorization::Authorization; use anyhow::Result; use async_trait::async_trait; use clap::Args; @@ -11,29 +10,15 @@ use psyche_solana_rpc::SolanaBackend; #[derive(Debug, Clone, Args)] #[command()] pub struct CommandJoinAuthorizationCreate { - #[clap(long, env, conflicts_with = "permissionless")] - pub authorizer: Option, - - /// Create a permissionless authorization (uses system program ID) - #[clap(long, conflicts_with = "authorizer")] - pub permissionless: bool, + /// Authorization type: either a pubkey address or "permissionless" (maps to system program ID) + #[clap(long, env)] + pub authorization: Authorization, } #[async_trait] impl Command for CommandJoinAuthorizationCreate { async fn execute(self, backend: SolanaBackend) -> Result<()> { - let Self { - authorizer, - permissionless, - } = self; - - let authorizer = if permissionless { - system_program::ID - } else { - authorizer.ok_or_else(|| { - anyhow::anyhow!("Either --authorizer or --permissionless must be provided") - })? - }; + let authorizer = self.authorization.to_pubkey(); let payer = backend.get_payer(); let grantor = backend.get_payer(); From e1b37f0c46eb78a5a47aaec7de0d995b245ce04e Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:33:25 +0100 Subject: [PATCH 09/22] Update read.rs --- .../src/commands/authorization/read.rs | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/read.rs b/tools/rust-tools/run-manager/src/commands/authorization/read.rs index bf71c1960..c167c80ce 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/read.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/read.rs @@ -1,6 +1,6 @@ use crate::commands::Command; +use crate::commands::authorization::Authorization; use anchor_client::solana_sdk::pubkey::Pubkey; -use anchor_client::solana_sdk::system_program; use anyhow::Result; use async_trait::async_trait; use clap::Args; @@ -12,28 +12,16 @@ use psyche_solana_rpc::SolanaBackend; pub struct CommandJoinAuthorizationRead { #[clap(long, env)] pub join_authority: Pubkey, - #[clap(long, env, conflicts_with = "permissionless")] - pub authorizer: Option, - /// Read permissionless authorization (uses system program ID) - #[clap(long, conflicts_with = "authorizer")] - pub permissionless: bool, + /// Authorization type: either a pubkey address or "permissionless" (maps to system program ID) + #[clap(long, env)] + pub authorization: Authorization, } #[async_trait] impl Command for CommandJoinAuthorizationRead { async fn execute(self, backend: SolanaBackend) -> Result<()> { - let Self { - join_authority, - authorizer, - permissionless, - } = self; - - let grantor = join_authority; - let grantee = if permissionless { - system_program::ID - } else { - authorizer.unwrap_or(system_program::ID) - }; + let grantor = self.join_authority; + let grantee = self.authorization.to_pubkey(); let scope = psyche_solana_coordinator::logic::JOIN_RUN_AUTHORIZATION_SCOPE; println!("Authorization Grantor: {}", grantor); From d9a2d2546afc36f26a17e3a8377017c78e0a217a Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:33:39 +0100 Subject: [PATCH 10/22] Update delete.rs --- .../src/commands/authorization/delete.rs | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/delete.rs b/tools/rust-tools/run-manager/src/commands/authorization/delete.rs index f09727b32..ebd743e3e 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/delete.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/delete.rs @@ -1,6 +1,5 @@ use crate::commands::Command; -use anchor_client::solana_sdk::pubkey::Pubkey; -use anchor_client::solana_sdk::system_program; +use crate::commands::authorization::Authorization; use anyhow::Result; use async_trait::async_trait; use clap::Args; @@ -11,29 +10,15 @@ use psyche_solana_rpc::SolanaBackend; #[derive(Debug, Clone, Args)] #[command()] pub struct CommandJoinAuthorizationDelete { - #[clap(long, env, conflicts_with = "permissionless")] - pub authorizer: Option, - - /// Delete a permissionless authorization (uses system program ID) - #[clap(long, conflicts_with = "authorizer")] - pub permissionless: bool, + /// Authorization type: either a pubkey address or "permissionless" (maps to system program ID) + #[clap(long, env)] + pub authorization: Authorization, } #[async_trait] impl Command for CommandJoinAuthorizationDelete { async fn execute(self, backend: SolanaBackend) -> Result<()> { - let Self { - authorizer, - permissionless, - } = self; - - let authorizer = if permissionless { - system_program::ID - } else { - authorizer.ok_or_else(|| { - anyhow::anyhow!("Either --authorizer or --permissionless must be provided") - })? - }; + let authorizer = self.authorization.to_pubkey(); let grantor = backend.get_payer(); let grantee = authorizer; From f99272695361c793fb2bd700d79c7504742e2a57 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:33:53 +0100 Subject: [PATCH 11/22] Update can_join.rs --- .../run-manager/src/commands/can_join.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/tools/rust-tools/run-manager/src/commands/can_join.rs b/tools/rust-tools/run-manager/src/commands/can_join.rs index 215764c1b..ac4a64459 100644 --- a/tools/rust-tools/run-manager/src/commands/can_join.rs +++ b/tools/rust-tools/run-manager/src/commands/can_join.rs @@ -1,6 +1,6 @@ use crate::commands::Command; +use crate::commands::authorization::Authorization; use anchor_client::solana_sdk::pubkey::Pubkey; -use anchor_client::solana_sdk::system_program; use anyhow::bail; use anyhow::Result; use async_trait::async_trait; @@ -14,11 +14,9 @@ use psyche_solana_rpc::SolanaBackend; pub struct CommandCanJoin { #[clap(short, long, env)] pub run_id: String, - #[clap(long, env, conflicts_with = "permissionless")] - pub authorizer: Option, - /// Check permissionless authorization (uses system program ID) - #[clap(long, conflicts_with = "authorizer")] - pub permissionless: bool, + /// Authorization type: either a pubkey address or "permissionless" (maps to system program ID) + #[clap(long, env)] + pub authorization: Option, #[clap(long, env, alias = "wallet", alias = "user", value_name = "PUBKEY")] pub address: Pubkey, } @@ -28,16 +26,11 @@ impl Command for CommandCanJoin { async fn execute(self, backend: SolanaBackend) -> Result<()> { let Self { run_id, - authorizer, - permissionless, + authorization, address, } = self; - let authorizer = if permissionless { - Some(system_program::ID) - } else { - authorizer - }; + let authorizer = authorization.map(|auth| auth.to_pubkey()); let coordinator_instance = psyche_solana_coordinator::find_coordinator_instance(&run_id); let coordinator_instance_state = backend From 7fc4b7bc2dbc6777f97897e17928f6a59234f5b7 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:34:08 +0100 Subject: [PATCH 12/22] Update integration_tests.rs --- .../run-manager/tests/integration_tests.rs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/tools/rust-tools/run-manager/tests/integration_tests.rs b/tools/rust-tools/run-manager/tests/integration_tests.rs index 31734640f..3f3404b69 100644 --- a/tools/rust-tools/run-manager/tests/integration_tests.rs +++ b/tools/rust-tools/run-manager/tests/integration_tests.rs @@ -12,7 +12,7 @@ use psyche_coordinator::RunState; use psyche_solana_rpc::SolanaBackend; use run_manager::commands::{ authorization::{ - CommandJoinAuthorizationCreate, CommandJoinAuthorizationDelete, + Authorization, CommandJoinAuthorizationCreate, CommandJoinAuthorizationDelete, CommandJoinAuthorizationRead, }, can_join::CommandCanJoin, @@ -263,8 +263,7 @@ async fn test_join_authorization_create_and_read() { .expect("Failed to create backend"); let create_params = CommandJoinAuthorizationCreate { - authorizer: Some(grantee_pubkey), - permissionless: false, + authorization: Authorization::Address(grantee_pubkey), }; create_params @@ -276,8 +275,7 @@ async fn test_join_authorization_create_and_read() { let read_params = CommandJoinAuthorizationRead { join_authority: grantor_arc.pubkey(), - authorizer: Some(grantee_pubkey), - permissionless: false, + authorization: Authorization::Address(grantee_pubkey), }; read_params @@ -307,8 +305,7 @@ async fn test_join_authorization_delete() { .expect("Failed to create backend"); let create_params = CommandJoinAuthorizationCreate { - authorizer: Some(grantee_pubkey), - permissionless: false, + authorization: Authorization::Address(grantee_pubkey), }; create_params @@ -319,8 +316,7 @@ async fn test_join_authorization_delete() { tokio::time::sleep(std::time::Duration::from_millis(500)).await; let delete_params = CommandJoinAuthorizationDelete { - authorizer: Some(grantee_pubkey), - permissionless: false, + authorization: Authorization::Address(grantee_pubkey), }; delete_params @@ -378,8 +374,7 @@ async fn test_can_join_paused_run() { let can_join_params = CommandCanJoin { run_id: run_id.clone(), - authorizer: None, - permissionless: false, + authorization: None, address: wallet_arc.pubkey(), }; @@ -430,8 +425,7 @@ async fn test_full_authorization_workflow() { // 2. Create authorization for user let auth_params = CommandJoinAuthorizationCreate { - authorizer: Some(user_pubkey), - permissionless: false, + authorization: Authorization::Address(user_pubkey), }; auth_params @@ -444,8 +438,7 @@ async fn test_full_authorization_workflow() { // 3. Check can-join for authorized user let can_join_params = CommandCanJoin { run_id: run_id.clone(), - authorizer: Some(user_pubkey), - permissionless: false, + authorization: Some(Authorization::Address(user_pubkey)), address: user_pubkey, }; @@ -658,8 +651,7 @@ async fn test_join_authorization_delegate() { let grantee_pubkey = grantee_keypair.pubkey(); let create_params = CommandJoinAuthorizationCreate { - authorizer: Some(grantee_pubkey), - permissionless: false, + authorization: Authorization::Address(grantee_pubkey), }; create_params From 99925a255d8b1524516d94237ec277ded9a51bdc Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:34:20 +0100 Subject: [PATCH 13/22] Update create-permissionless-run.sh --- scripts/create-permissionless-run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/create-permissionless-run.sh b/scripts/create-permissionless-run.sh index 582974fff..5bce1db5e 100755 --- a/scripts/create-permissionless-run.sh +++ b/scripts/create-permissionless-run.sh @@ -43,7 +43,7 @@ cargo run --release --bin run-manager -- \ join-authorization-create \ --wallet-private-key-path ${WALLET_FILE} \ --rpc "${RPC}" \ - --authorizer 11111111111111111111111111111111 + --authorization permissionless echo -e "\n[+] Creating training run..." cargo run --release --bin run-manager -- \ From 7e127c8e2185a69115b4c6dfdac264771b4a9dc3 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:34:36 +0100 Subject: [PATCH 14/22] Update setup-test-run.sh --- scripts/setup-test-run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup-test-run.sh b/scripts/setup-test-run.sh index 3a2a74f22..77849d4e3 100755 --- a/scripts/setup-test-run.sh +++ b/scripts/setup-test-run.sh @@ -45,7 +45,7 @@ nix run .#run-manager -- \ join-authorization-create \ --wallet-private-key-path "${WALLET_FILE}" \ --rpc "${RPC}" \ - --authorizer 11111111111111111111111111111111 + --authorization permissionless echo "[+] Creating run..." nix run .#run-manager -- \ From e38f77af5210f040535358be90196e4cf0347167 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:34:50 +0100 Subject: [PATCH 15/22] Update authentication.md --- psyche-book/src/enduser/authentication.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/psyche-book/src/enduser/authentication.md b/psyche-book/src/enduser/authentication.md index 42916048f..5cb65a1cf 100644 --- a/psyche-book/src/enduser/authentication.md +++ b/psyche-book/src/enduser/authentication.md @@ -20,7 +20,7 @@ A Training run can be configured to be restricted to only a set of whitelisted k ## Permissionless Runs -Permissionless runs are open to anyone without any `authorization` required. The owner of the run can set this for a run when creating it. This type of authorization can be made by creating an `authorization` with a special `authorizer` valid for everyone: `11111111111111111111111111111111` +Permissionless runs are open to anyone without any `authorization` required. The owner of the run can set this for a run when creating it. This type of authorization can be made by using the `permissionless` authorization type, which maps to the system program ID (`11111111111111111111111111111111`). A CLI is provided for this: @@ -28,7 +28,7 @@ A CLI is provided for this: run-manager join-authorization-create \ --rpc [RPC] \ --wallet-private-key-path [JOIN_AUTHORITY_KEYPAIR_FILE] \ - --authorizer 11111111111111111111111111111111 + --authorization permissionless ``` ## Permissioned Runs @@ -49,7 +49,7 @@ For the `join_authority` to issues new `authorization`, a CLI is provided: run-manager join-authorization-create \ --rpc [RPC] \ --wallet-private-key-path [JOIN_AUTHORITY_KEYPAIR_FILE] \ - --authorizer [USER_MASTER_PUBKEY] + --authorization [USER_MASTER_PUBKEY] ``` For the `authorizer` to then set a list of delegate, the following CLI is provided: @@ -69,7 +69,7 @@ Removing the authorization is also possible through CLI: run-manager join-authorization-delete \ --rpc [RPC] \ --wallet-private-key-path [JOIN_AUTHORITY_KEYPAIR_FILE] \ - --authorizer [USER_MASTER_PUBKEY] + --authorization [USER_MASTER_PUBKEY] ``` ## Further information From afb59ea6b2ced7493b9a9a631c1723b3d2af7802 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:35:06 +0100 Subject: [PATCH 16/22] Update create-run.md --- psyche-book/src/enduser/create-run.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/psyche-book/src/enduser/create-run.md b/psyche-book/src/enduser/create-run.md index 7a9354ca1..34ce404fc 100644 --- a/psyche-book/src/enduser/create-run.md +++ b/psyche-book/src/enduser/create-run.md @@ -22,13 +22,13 @@ We’ll need a keypair file that manages join permissions. This can be the defau #### Join Authority for Public Runs -If we're looking to make a permissionless run (anyone can join), we'll need to create an authorization that's valid for everyone. In this case, if we set the authorizer to be `11111111111111111111111111111111` in the following command it will be valid for everyone so any other client can join the created run without additional restrictions. +If we're looking to make a permissionless run (anyone can join), we'll need to create an authorization that's valid for everyone. This can be done by using the `permissionless` authorization type, which maps to the system program ID (`11111111111111111111111111111111`) and allows any client to join the created run without additional restrictions. ```sh run-manager join-authorization-create \ --rpc [RPC] \ --wallet-private-key-path [SOLANA_KEY_FILE] \ - --authorizer 11111111111111111111111111111111 + --authorization permissionless ``` In this case the `SOLANA_KEY_FILE` needs to be the path to a Solana keypair that is creating the authorization for this specific run. @@ -45,7 +45,7 @@ First, create the authorization with the following parameters: run-manager join-authorization-create \ --rpc [RPC] \ --wallet-private-key-path ~/.config/solana/owner.json \ - --authorizer $(solana-keygen pubkey ~/.config/solana/joiner.json) + --authorization $(solana-keygen pubkey ~/.config/solana/joiner.json) ``` This command uses the public key of the user you want to allow to join and the keypair of the run owner to create the appropriate authorization. The `solana-keygen pubkey` command just gives you the public key derivated from the keypair file. From dfe3c16b9937ff18b2745a317ab22d663183fb6e Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 10:46:09 +0100 Subject: [PATCH 17/22] fmt --- tools/rust-tools/run-manager/tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/rust-tools/run-manager/tests/integration_tests.rs b/tools/rust-tools/run-manager/tests/integration_tests.rs index 3f3404b69..ff4d14936 100644 --- a/tools/rust-tools/run-manager/tests/integration_tests.rs +++ b/tools/rust-tools/run-manager/tests/integration_tests.rs @@ -7,7 +7,7 @@ use anchor_client::{ solana_sdk::{commitment_config::CommitmentConfig, signature::Signer}, Cluster, }; -use common::{create_test_keypair, TestClient, TestValidator}; +use common::{TestClient, TestValidator, create_test_keypair}; use psyche_coordinator::RunState; use psyche_solana_rpc::SolanaBackend; use run_manager::commands::{ From 547ba83093dd052ae15f1ecd5125ba88a4101f44 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 11:28:40 +0100 Subject: [PATCH 18/22] Update delete.rs --- .../rust-tools/run-manager/src/commands/authorization/delete.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/delete.rs b/tools/rust-tools/run-manager/src/commands/authorization/delete.rs index ebd743e3e..5c88bb352 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/delete.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/delete.rs @@ -4,8 +4,8 @@ use anyhow::Result; use async_trait::async_trait; use clap::Args; -use psyche_solana_rpc::instructions; use psyche_solana_rpc::SolanaBackend; +use psyche_solana_rpc::instructions; #[derive(Debug, Clone, Args)] #[command()] From c7ec365dd6972b6caf47f37860f0fd18f2e086d8 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 11:29:00 +0100 Subject: [PATCH 19/22] Update can_join.rs --- tools/rust-tools/run-manager/src/commands/can_join.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/rust-tools/run-manager/src/commands/can_join.rs b/tools/rust-tools/run-manager/src/commands/can_join.rs index ac4a64459..5321729fd 100644 --- a/tools/rust-tools/run-manager/src/commands/can_join.rs +++ b/tools/rust-tools/run-manager/src/commands/can_join.rs @@ -1,8 +1,8 @@ use crate::commands::Command; use crate::commands::authorization::Authorization; use anchor_client::solana_sdk::pubkey::Pubkey; -use anyhow::bail; use anyhow::Result; +use anyhow::bail; use async_trait::async_trait; use clap::Args; use psyche_coordinator::RunState; From 5159bdcda3e01f007972f2ead1095bc9990ab00b Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 11:29:17 +0100 Subject: [PATCH 20/22] Update integration_tests.rs --- tools/rust-tools/run-manager/tests/integration_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/rust-tools/run-manager/tests/integration_tests.rs b/tools/rust-tools/run-manager/tests/integration_tests.rs index ff4d14936..2fb03dc8a 100644 --- a/tools/rust-tools/run-manager/tests/integration_tests.rs +++ b/tools/rust-tools/run-manager/tests/integration_tests.rs @@ -4,20 +4,20 @@ mod common; use anchor_client::{ - solana_sdk::{commitment_config::CommitmentConfig, signature::Signer}, Cluster, + solana_sdk::{commitment_config::CommitmentConfig, signature::Signer}, }; use common::{TestClient, TestValidator, create_test_keypair}; use psyche_coordinator::RunState; use psyche_solana_rpc::SolanaBackend; use run_manager::commands::{ + Command, authorization::{ Authorization, CommandJoinAuthorizationCreate, CommandJoinAuthorizationDelete, CommandJoinAuthorizationRead, }, can_join::CommandCanJoin, run::{CommandCloseRun, CommandCreateRun, CommandJsonDumpRun, CommandSetPaused}, - Command, }; use serial_test::serial; From 65b120ed3382b2211f8e545405e6ec402dd5f383 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 11:29:31 +0100 Subject: [PATCH 21/22] Update types.rs --- tools/rust-tools/run-manager/src/commands/authorization/types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/types.rs b/tools/rust-tools/run-manager/src/commands/authorization/types.rs index c2a4bd156..bb65a7a78 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/types.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/types.rs @@ -31,4 +31,3 @@ impl FromStr for Authorization { } } } - From 52ad0a1bf36535ab73bd463fb2ebb82b84d13b87 Mon Sep 17 00:00:00 2001 From: Desant pivo Date: Sun, 15 Feb 2026 11:32:12 +0100 Subject: [PATCH 22/22] Update create.rs --- .../rust-tools/run-manager/src/commands/authorization/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/rust-tools/run-manager/src/commands/authorization/create.rs b/tools/rust-tools/run-manager/src/commands/authorization/create.rs index 354feba3f..ad1de702c 100644 --- a/tools/rust-tools/run-manager/src/commands/authorization/create.rs +++ b/tools/rust-tools/run-manager/src/commands/authorization/create.rs @@ -4,8 +4,8 @@ use anyhow::Result; use async_trait::async_trait; use clap::Args; -use psyche_solana_rpc::instructions; use psyche_solana_rpc::SolanaBackend; +use psyche_solana_rpc::instructions; #[derive(Debug, Clone, Args)] #[command()]