From 14e620173327f9467100b0b0a6419cca9162b1f8 Mon Sep 17 00:00:00 2001 From: Michael Neale <14976+michaelneale@users.noreply.github.com> Date: Thu, 13 Aug 2026 12:01:50 +1000 Subject: [PATCH 1/2] fix(setup): verify GitHub star credentials directly Co-authored-by: Michael Neale <14976+michaelneale@users.noreply.github.com> Signed-off-by: Michael Neale <14976+michaelneale@users.noreply.github.com> --- .../src/setup/github_runner.rs | 55 ++++++++++++++----- crates/mesh-llm-commands/src/setup/summary.rs | 16 ++++-- docs/specs/mesh-setup-installer.md | 2 +- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/crates/mesh-llm-commands/src/setup/github_runner.rs b/crates/mesh-llm-commands/src/setup/github_runner.rs index 19cc2a6d8d..00e9902e06 100644 --- a/crates/mesh-llm-commands/src/setup/github_runner.rs +++ b/crates/mesh-llm-commands/src/setup/github_runner.rs @@ -20,20 +20,21 @@ impl GhCommand { const fn args(self) -> &'static [&'static str] { match self { Self::CheckAvailability => &["--version"], - Self::CheckAuthentication => { - &["auth", "status", "--active", "--hostname", "github.com"] - } + Self::CheckAuthentication => &["api", "--hostname", "github.com", "/user", "--silent"], Self::CheckViewerHasStarred => &[ - "repo", - "view", - GITHUB_REPOSITORY, - "--json", - "viewerHasStarred", + "api", + "--hostname", + "github.com", + "graphql", + "-f", + "query=query { repository(owner: \"Mesh-LLM\", name: \"mesh-llm\") { viewerHasStarred } }", "--jq", - ".viewerHasStarred", + ".data.repository.viewerHasStarred", ], Self::StarRepository => &[ "api", + "--hostname", + "github.com", "--method", "PUT", "/user/starred/Mesh-LLM/mesh-llm", @@ -45,11 +46,11 @@ impl GhCommand { pub(crate) const fn display_name(self) -> &'static str { match self { Self::CheckAvailability => "gh --version", - Self::CheckAuthentication => "gh auth status --active --hostname github.com", - Self::CheckViewerHasStarred => { - "gh repo view Mesh-LLM/mesh-llm --json viewerHasStarred --jq .viewerHasStarred" + Self::CheckAuthentication => "gh api --hostname github.com /user --silent", + Self::CheckViewerHasStarred => "gh api --hostname github.com graphql ", + Self::StarRepository => { + "gh api --hostname github.com --method PUT /user/starred/Mesh-LLM/mesh-llm --silent" } - Self::StarRepository => "gh api --method PUT /user/starred/Mesh-LLM/mesh-llm --silent", } } } @@ -98,6 +99,34 @@ impl Default for ProcessGhCommandRunner { } } +#[cfg(test)] +mod tests { + use super::GhCommand; + + #[test] + fn github_api_commands_are_pinned_to_dot_com() { + for command in [ + GhCommand::CheckAuthentication, + GhCommand::CheckViewerHasStarred, + GhCommand::StarRepository, + ] { + assert!( + command.args().windows(2).any(|args| args == ["--hostname", "github.com"]), + "{} must explicitly target github.com", + command.display_name() + ); + } + } + + #[test] + fn authentication_probe_checks_the_selected_api_credential() { + assert_eq!( + GhCommand::CheckAuthentication.args(), + &["api", "--hostname", "github.com", "/user", "--silent"] + ); + } +} + impl GhCommandRunner for ProcessGhCommandRunner { fn run(&mut self, command: GhCommand) -> Result { let mut child = Command::new("gh") diff --git a/crates/mesh-llm-commands/src/setup/summary.rs b/crates/mesh-llm-commands/src/setup/summary.rs index 3e7ad04034..2ea0aa241e 100644 --- a/crates/mesh-llm-commands/src/setup/summary.rs +++ b/crates/mesh-llm-commands/src/setup/summary.rs @@ -45,7 +45,7 @@ pub(crate) fn print_setup_summary(plan: &SetupPlan, actions: &CliSetupActions<'_ eprintln!("- Runtime: {}", runtime_summary(plan, actions)); eprintln!("- Service: {}", service_summary(plan, actions)); eprintln!( - "- GitHub: {}", + "- GitHub star: {}", super::github::github_summary(plan, &actions.github_outcome) ); return; @@ -55,7 +55,7 @@ pub(crate) fn print_setup_summary(plan: &SetupPlan, actions: &CliSetupActions<'_ eprintln!(" Runtime {}", runtime_brief(plan, actions)); eprintln!(" Service {}", service_brief(plan, actions)); if let Some(github) = github_brief(actions) { - eprintln!(" GitHub {github}"); + eprintln!(" GitHub star {github}"); } } @@ -170,8 +170,12 @@ fn github_brief(actions: &CliSetupActions<'_>) -> Option { | super::github::SetupGitHubOutcome::EligibilityCheckFailed(_) => { Some(style_warn("not starred")) } - super::github::SetupGitHubOutcome::CliUnavailable => Some(style_muted("gh unavailable")), - super::github::SetupGitHubOutcome::NotAuthenticated => Some(style_muted("gh signed out")), + super::github::SetupGitHubOutcome::CliUnavailable => { + Some(style_muted("skipped; gh unavailable")) + } + super::github::SetupGitHubOutcome::NotAuthenticated => { + Some(style_muted("skipped; gh not authenticated")) + } super::github::SetupGitHubOutcome::NotEvaluated => Some(style_muted("not recorded")), _ => None, } @@ -225,7 +229,7 @@ mod tests { assert_eq!( github_brief(&actions).map(|brief| strip_ansi_styles(&brief)), - Some("gh unavailable".to_string()) + Some("skipped; gh unavailable".to_string()) ); } @@ -235,7 +239,7 @@ mod tests { assert_eq!( github_brief(&actions).map(|brief| strip_ansi_styles(&brief)), - Some("gh signed out".to_string()) + Some("skipped; gh not authenticated".to_string()) ); } } diff --git a/docs/specs/mesh-setup-installer.md b/docs/specs/mesh-setup-installer.md index 17e99ca357..cc781f9628 100644 --- a/docs/specs/mesh-setup-installer.md +++ b/docs/specs/mesh-setup-installer.md @@ -112,7 +112,7 @@ After successful core setup, an interactive setup may offer to star Eligibility: - `gh` is on PATH -- `gh auth status --active --hostname github.com` succeeds +- `gh api --hostname github.com /user --silent` succeeds using the account selected by `gh` - the authenticated viewer has not already starred the repo - a visible interactive prompt is shown From ac99ee5e8b03e3c903d4da2533534d7f9a5b19f3 Mon Sep 17 00:00:00 2001 From: Michael Neale <14976+michaelneale@users.noreply.github.com> Date: Fri, 14 Aug 2026 18:14:22 +1000 Subject: [PATCH 2/2] Fix setup GitHub runner lint failures Co-authored-by: Michael Neale <14976+michaelneale@users.noreply.github.com> Signed-off-by: Michael Neale <14976+michaelneale@users.noreply.github.com> --- .../src/setup/github_runner.rs | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/crates/mesh-llm-commands/src/setup/github_runner.rs b/crates/mesh-llm-commands/src/setup/github_runner.rs index 00e9902e06..bcf210962d 100644 --- a/crates/mesh-llm-commands/src/setup/github_runner.rs +++ b/crates/mesh-llm-commands/src/setup/github_runner.rs @@ -4,7 +4,6 @@ use std::process::{Command, Stdio}; use std::thread; use std::time::{Duration, Instant}; -const GITHUB_REPOSITORY: &str = "Mesh-LLM/mesh-llm"; const GH_COMMAND_TIMEOUT: Duration = Duration::from_secs(10); const GH_POLL_INTERVAL: Duration = Duration::from_millis(25); @@ -99,34 +98,6 @@ impl Default for ProcessGhCommandRunner { } } -#[cfg(test)] -mod tests { - use super::GhCommand; - - #[test] - fn github_api_commands_are_pinned_to_dot_com() { - for command in [ - GhCommand::CheckAuthentication, - GhCommand::CheckViewerHasStarred, - GhCommand::StarRepository, - ] { - assert!( - command.args().windows(2).any(|args| args == ["--hostname", "github.com"]), - "{} must explicitly target github.com", - command.display_name() - ); - } - } - - #[test] - fn authentication_probe_checks_the_selected_api_credential() { - assert_eq!( - GhCommand::CheckAuthentication.args(), - &["api", "--hostname", "github.com", "/user", "--silent"] - ); - } -} - impl GhCommandRunner for ProcessGhCommandRunner { fn run(&mut self, command: GhCommand) -> Result { let mut child = Command::new("gh") @@ -184,3 +155,34 @@ impl GhCommandRunner for ProcessGhCommandRunner { } } } + +#[cfg(test)] +mod tests { + use super::GhCommand; + + #[test] + fn github_api_commands_are_pinned_to_dot_com() { + for command in [ + GhCommand::CheckAuthentication, + GhCommand::CheckViewerHasStarred, + GhCommand::StarRepository, + ] { + assert!( + command + .args() + .windows(2) + .any(|args| args == ["--hostname", "github.com"]), + "{} must explicitly target github.com", + command.display_name() + ); + } + } + + #[test] + fn authentication_probe_checks_the_selected_api_credential() { + assert_eq!( + GhCommand::CheckAuthentication.args(), + &["api", "--hostname", "github.com", "/user", "--silent"] + ); + } +}