From 7e680b26e70bee8b288510b652cf71090d5dfcf9 Mon Sep 17 00:00:00 2001 From: Greyforge Admin Date: Tue, 19 May 2026 23:13:04 -0400 Subject: [PATCH] Restrict GitHub workflow uninstall detection --- src/cortex-cli/src/github_cmd.rs | 6 +- .../tests/github_uninstall_workflow.rs | 81 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/cortex-cli/tests/github_uninstall_workflow.rs diff --git a/src/cortex-cli/src/github_cmd.rs b/src/cortex-cli/src/github_cmd.rs index 83763b3bd..cdcfcafbf 100644 --- a/src/cortex-cli/src/github_cmd.rs +++ b/src/cortex-cli/src/github_cmd.rs @@ -584,6 +584,10 @@ fn get_help_message() -> String { .to_string() } +fn is_cortex_generated_workflow(content: &str) -> bool { + content.contains("# Generated by: cortex github install") +} + /// Check GitHub Actions installation status. async fn run_status(args: StatusArgs) -> Result<()> { let repo_path = args.path.unwrap_or_else(|| PathBuf::from(".")); @@ -695,7 +699,7 @@ async fn run_uninstall(args: UninstallArgs) -> Result<()> { if path.exists() { // Verify it's a Cortex workflow if let Ok(content) = std::fs::read_to_string(&path) - && (content.contains("Cortex") || content.contains("cortex")) + && is_cortex_generated_workflow(&content) { found_workflow = Some(path); break; diff --git a/src/cortex-cli/tests/github_uninstall_workflow.rs b/src/cortex-cli/tests/github_uninstall_workflow.rs new file mode 100644 index 000000000..4227ff31b --- /dev/null +++ b/src/cortex-cli/tests/github_uninstall_workflow.rs @@ -0,0 +1,81 @@ +use std::process::Command; + +use tempfile::tempdir; + +#[test] +fn github_uninstall_rejects_unrelated_workflow_mentioning_cortex() { + let repo_dir = tempdir().unwrap(); + let workflows_dir = repo_dir.path().join(".github").join("workflows"); + std::fs::create_dir_all(&workflows_dir).unwrap(); + let workflow_path = workflows_dir.join("ci.yml"); + std::fs::write( + &workflow_path, + r#"name: CI +on: [push] +# notify cortex team on failure +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo unrelated +"#, + ) + .unwrap(); + + let output = Command::new(env!("CARGO_BIN_EXE_Cortex")) + .args([ + "github", + "uninstall", + "--path", + repo_dir.path().to_str().unwrap(), + "--workflow-name", + "ci", + "--force", + ]) + .output() + .unwrap(); + + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(!output.status.success()); + assert!( + stderr.contains("Cortex workflow 'ci' not found"), + "unexpected stderr: {stderr}" + ); + assert!(workflow_path.exists(), "unrelated workflow was deleted"); +} + +#[test] +fn github_uninstall_removes_generated_workflow() { + let repo_dir = tempdir().unwrap(); + let workflows_dir = repo_dir.path().join(".github").join("workflows"); + std::fs::create_dir_all(&workflows_dir).unwrap(); + let workflow_path = workflows_dir.join("Cortex.yml"); + std::fs::write( + &workflow_path, + r#"# Cortex CI/CD Automation +# Generated by: cortex github install +name: Cortex +"#, + ) + .unwrap(); + + let output = Command::new(env!("CARGO_BIN_EXE_Cortex")) + .args([ + "github", + "uninstall", + "--path", + repo_dir.path().to_str().unwrap(), + "--workflow-name", + "Cortex", + "--force", + ]) + .output() + .unwrap(); + + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(output.status.success(), "unexpected stderr: {stderr}"); + assert!( + !workflow_path.exists(), + "generated workflow was not deleted" + ); +}