Skip to content

Commit c98f53f

Browse files
committed
feat: use git credential helper for GitHub authentication
- Implement token retrieval from git credential helper - Try GITHUB_TOKEN env var first, then gh CLI, then git credentials - Support host system's configured credential storage (osxkeychain, etc.)
1 parent 1fc2fe1 commit c98f53f

1 file changed

Lines changed: 64 additions & 3 deletions

File tree

src/actions.rs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,66 @@ pub async fn execute_docker_action(
283283
Ok(())
284284
}
285285

286+
/// Get GitHub token from environment, gh CLI, or git credentials
287+
fn get_github_token() -> String {
288+
// Try GITHUB_TOKEN environment variable first
289+
if let Ok(token) = std::env::var("GITHUB_TOKEN") {
290+
if !token.is_empty() {
291+
println!(" {} Using GITHUB_TOKEN from environment", "→".cyan());
292+
return token;
293+
}
294+
}
295+
296+
// Try to get token from gh CLI
297+
if let Ok(output) = StdCommand::new("gh")
298+
.args(["auth", "token"])
299+
.output()
300+
{
301+
if output.status.success() {
302+
if let Ok(token) = String::from_utf8(output.stdout) {
303+
let token = token.trim().to_string();
304+
if !token.is_empty() {
305+
println!(" {} Using GitHub token from gh CLI", "→".cyan());
306+
return token;
307+
}
308+
}
309+
}
310+
}
311+
312+
// Try to get credentials from git credential helper
313+
if let Ok(mut child) = StdCommand::new("git")
314+
.args(["credential", "fill"])
315+
.stdin(std::process::Stdio::piped())
316+
.stdout(std::process::Stdio::piped())
317+
.spawn()
318+
{
319+
if let Some(mut stdin) = child.stdin.take() {
320+
use std::io::Write;
321+
let _ = stdin.write_all(b"protocol=https\nhost=github.com\n\n");
322+
}
323+
324+
if let Ok(output) = child.wait_with_output() {
325+
if output.status.success() {
326+
if let Ok(credentials) = String::from_utf8(output.stdout) {
327+
// Parse the credential output for password (which is the token)
328+
for line in credentials.lines() {
329+
if let Some(token) = line.strip_prefix("password=") {
330+
if !token.is_empty() {
331+
println!(" {} Using GitHub credentials from git", "→".cyan());
332+
return token.to_string();
333+
}
334+
}
335+
}
336+
}
337+
}
338+
}
339+
}
340+
341+
// No token available - use empty for local-only operations
342+
println!(" {} No GitHub token found (set GITHUB_TOKEN or use 'gh auth login')", "⚠".yellow());
343+
"".to_string()
344+
}
345+
286346
/// Set up GitHub Actions environment variables
287347
fn setup_github_env(inputs: Option<&std::collections::HashMap<String, serde_yaml::Value>>) -> std::collections::HashMap<String, String> {
288348
let mut env = std::collections::HashMap::new();
@@ -358,10 +418,11 @@ fn setup_github_env(inputs: Option<&std::collections::HashMap<String, serde_yaml
358418
}
359419
}
360420

361-
// Provide a default token if not supplied (for actions that require it)
362-
// Use a dummy token for local execution - many actions like checkout require this
421+
// Provide a token if not supplied
422+
// Try to use real credentials for GitHub authentication
363423
if !env.contains_key("INPUT_TOKEN") {
364-
env.insert("INPUT_TOKEN".to_string(), "local-magnolia-token".to_string());
424+
let token = get_github_token();
425+
env.insert("INPUT_TOKEN".to_string(), token);
365426
}
366427

367428
env

0 commit comments

Comments
 (0)