Compare commits

..

3 Commits

3 changed files with 29 additions and 3 deletions

8
.gitignore vendored
View File

@@ -1,6 +1,8 @@
/target /target
IMPLEMENTATION_PLAN.md IMPLEMENTATION_PLAN.md
# Config files (may contain GitHub tokens) # Config files that may contain GitHub tokens
*.toml # Note: User config files are stored in platform-specific directories outside the repo
config.toml # (e.g., ~/.config/gh-celebs/config.toml on Linux)
# This prevents accidental commits if someone creates config.toml in the project root
/config.toml

View File

@@ -11,6 +11,22 @@ pub struct GitHubClient {
impl GitHubClient { impl GitHubClient {
pub fn new(token: Option<String>) -> Result<Self> { pub fn new(token: Option<String>) -> Result<Self> {
// Validate token format if provided
if let Some(ref t) = token {
if !t.is_empty() {
// GitHub classic tokens start with 'ghp_'
// Fine-grained tokens start with 'github_pat_'
// OAuth tokens don't have a specific prefix
let is_valid_format = t.starts_with("ghp_") ||
t.starts_with("github_pat_") ||
t.len() >= 20; // Generic check for reasonable token length
if !is_valid_format {
anyhow::bail!("Invalid GitHub token format. Token should start with 'ghp_' (classic) or 'github_pat_' (fine-grained)");
}
}
}
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert(USER_AGENT, HeaderValue::from_static("gh-celebs")); headers.insert(USER_AGENT, HeaderValue::from_static("gh-celebs"));
headers.insert(ACCEPT, HeaderValue::from_static("application/vnd.github.v3+json")); headers.insert(ACCEPT, HeaderValue::from_static("application/vnd.github.v3+json"));

View File

@@ -3,6 +3,8 @@ use crate::github::GitHubClient;
use crate::models::{RateLimitInfo, Repo, SearchResponse, SearchResult}; use crate::models::{RateLimitInfo, Repo, SearchResponse, SearchResult};
use anyhow::Result; use anyhow::Result;
use std::collections::HashMap; use std::collections::HashMap;
use std::time::Duration;
use tokio::time::sleep;
pub struct SearchEngine { pub struct SearchEngine {
db: Database, db: Database,
@@ -105,6 +107,12 @@ impl SearchEngine {
if last_rate_limit.remaining < 3 { if last_rate_limit.remaining < 3 {
println!("\nWarning: Rate limit running low ({} remaining)", last_rate_limit.remaining); println!("\nWarning: Rate limit running low ({} remaining)", last_rate_limit.remaining);
} }
// Client-side rate limiting: wait 3 seconds between requests
// This respects both anonymous (10/min = 6s) and authenticated (30/min = 2s) limits
if idx < total - 1 {
sleep(Duration::from_secs(3)).await;
}
} }
println!("\n✓ Updated {} repositories", total); println!("\n✓ Updated {} repositories", total);