Skip to content

Commit 1546340

Browse files
committed
refactor: replace is_local_host check with interactive confirmation
Removes the Ollama-only localhost restriction and instead prompts the user interactively when --allow-secrets is passed, showing which secrets and which provider would receive the diff. Non-interactive environments still block unconditionally.
1 parent 1cdeecb commit 1546340

1 file changed

Lines changed: 31 additions & 29 deletions

File tree

src/app.rs

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -121,26 +121,47 @@ impl App {
121121
}
122122

123123
// Cloud providers: always block when secrets detected
124-
if self.config.provider != crate::config::Provider::Ollama {
125-
return Err(Error::SecretsDetected {
126-
patterns: secrets.iter().map(|s| s.pattern_name.clone()).collect(),
127-
});
128-
}
129-
130-
// Ollama: only allow with --allow-secrets and verified-local host
131124
if !self.cli.allow_secrets {
132125
return Err(Error::SecretsDetected {
133126
patterns: secrets.iter().map(|s| s.pattern_name.clone()).collect(),
134127
});
135128
}
136129

137-
if !Self::is_local_host(&self.config.ollama_host) {
130+
// --allow-secrets passed: always require interactive confirmation
131+
if std::io::stdin().is_terminal() {
132+
progress.finish();
133+
eprintln!("\nwarning: Potential secrets detected in staged changes.");
134+
for s in &secrets {
135+
eprintln!(
136+
" {} in {} (line ~{})",
137+
s.pattern_name,
138+
s.file,
139+
s.line.unwrap_or(0)
140+
);
141+
}
142+
eprintln!(
143+
"Provider: {} ({})",
144+
self.config.provider,
145+
if self.config.provider == crate::config::Provider::Ollama {
146+
&self.config.ollama_host
147+
} else {
148+
"cloud API"
149+
}
150+
);
151+
eprint!("Send diff to LLM anyway? [y/N] ");
152+
let mut input = String::new();
153+
std::io::stdin().read_line(&mut input).ok();
154+
if !input.trim().eq_ignore_ascii_case("y") {
155+
return Err(Error::SecretsDetected {
156+
patterns: secrets.iter().map(|s| s.pattern_name.clone()).collect(),
157+
});
158+
}
159+
} else {
160+
// Non-interactive: always block even with --allow-secrets
138161
return Err(Error::SecretsDetected {
139162
patterns: secrets.iter().map(|s| s.pattern_name.clone()).collect(),
140163
});
141164
}
142-
143-
progress.info("Proceeding with local Ollama (data stays local)");
144165
}
145166

146167
if self.cancel_token.is_cancelled() {
@@ -1383,23 +1404,4 @@ fi
13831404

13841405
Ok(())
13851406
}
1386-
1387-
// ─── Security Helpers ───
1388-
1389-
/// Check if a URL host resolves to a loopback address (localhost, 127.0.0.1, ::1).
1390-
fn is_local_host(url: &str) -> bool {
1391-
// Parse out the host from the URL
1392-
let host = url
1393-
.strip_prefix("http://")
1394-
.or_else(|| url.strip_prefix("https://"))
1395-
.unwrap_or(url)
1396-
.split('/')
1397-
.next()
1398-
.unwrap_or("")
1399-
.split(':')
1400-
.next()
1401-
.unwrap_or("");
1402-
1403-
matches!(host, "localhost" | "127.0.0.1" | "::1" | "[::1]")
1404-
}
14051407
}

0 commit comments

Comments
 (0)