refactor: centralize test credential constants into testing::credentials (#829)

* refactor: centralize test credential constants into testing::credentials

Scattered test credential strings (API keys, OAuth tokens, crypto keys,
Telegram tokens, session tokens) across ~25 files made security auditing
harder and created unnecessary duplication. Centralize all test-only fake
credentials into a new `src/testing/credentials.rs` module with named
constants and a shared `test_secrets_store()` helper.

- Convert `src/testing.rs` to directory module (`src/testing/mod.rs`)
- Add `src/testing/credentials.rs` with ~30 named constants
- Replace hardcoded literals in 24 source files
- Deduplicate `test_store()` helper (was copy-pasted in 3 files)
- Leave leak_detector/shell/signature tests as-is (inline values
  aid readability for pattern detection tests)

[skip-regression-check]

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>

* refactor: replace real Telegram bot token with obviously fake test stub

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

* Update src/testing/credentials.rs

Co-authored-by: Copilot <[email protected]>

* Update src/testing/credentials.rs

Co-authored-by: Copilot <[email protected]>

* refactor: address PR review feedback on test credentials

- Fix TEST_CRYPTO_KEY doc comment ("32-byte hex" → "32-character key string")
- Rename confusing "real"/"fake" Anthropic constant names and values
- Change TEST_STRIPE_KEY from "sk-live" to "sk_test_fake123" to avoid scanners
- Use test_secrets_store() helper in orchestrator and http tool tests
- Clarify config_round_trip.rs doc comment about integration test visibility

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Copilot <[email protected]>
This commit is contained in:
Henry Park
2026-03-10 13:25:32 -07:00
committed by GitHub
co-authored by Claude Opus 4.6 Copilot
parent 24d4fbb8a7
commit 76375f2eaa
25 changed files with 314 additions and 201 deletions
+2 -2
View File
@@ -768,11 +768,11 @@ mod tests {
/// Create a stub manager for schema tests (these don't call execute).
fn test_manager_stub() -> Arc<ExtensionManager> {
use crate::secrets::{InMemorySecretsStore, SecretsCrypto};
use crate::testing::credentials::TEST_CRYPTO_KEY;
use crate::tools::ToolRegistry;
use crate::tools::mcp::session::McpSessionManager;
let master_key =
secrecy::SecretString::from("0123456789abcdef0123456789abcdef".to_string());
let master_key = secrecy::SecretString::from(TEST_CRYPTO_KEY.to_string());
let crypto = Arc::new(SecretsCrypto::new(master_key).unwrap());
Arc::new(ExtensionManager::new(
+5 -25
View File
@@ -609,6 +609,7 @@ impl Tool for HttpTool {
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::credentials::{TEST_OPENAI_API_KEY, test_secrets_store};
#[test]
fn test_http_tool_schema_headers_is_array() {
@@ -868,12 +869,7 @@ mod tests {
let tool = HttpTool::new().with_credentials(
registry,
// secrets_store is not used in requires_approval, just needs to be present
Arc::new(crate::secrets::InMemorySecretsStore::new(Arc::new(
crate::secrets::SecretsCrypto::new(secrecy::SecretString::from(
"0123456789abcdef0123456789abcdef".to_string(),
))
.unwrap(),
))),
Arc::new(test_secrets_store()),
);
let params = serde_json::json!({
@@ -890,15 +886,7 @@ mod tests {
let registry = Arc::new(SharedCredentialRegistry::new());
// Empty registry - no credential mappings
let tool = HttpTool::new().with_credentials(
registry,
Arc::new(crate::secrets::InMemorySecretsStore::new(Arc::new(
crate::secrets::SecretsCrypto::new(secrecy::SecretString::from(
"0123456789abcdef0123456789abcdef".to_string(),
))
.unwrap(),
))),
);
let tool = HttpTool::new().with_credentials(registry, Arc::new(test_secrets_store()));
let params = serde_json::json!({
"method": "GET",
@@ -926,7 +914,7 @@ mod tests {
let params = serde_json::json!({
"method": "GET",
"url": "https://example.com",
"headers": {"X-Custom": "Bearer sk-test123"}
"headers": {"X-Custom": format!("Bearer {TEST_OPENAI_API_KEY}")}
});
assert_eq!(tool.requires_approval(&params), ApprovalRequirement::Always);
}
@@ -957,15 +945,7 @@ mod tests {
let registry = Arc::new(SharedCredentialRegistry::new());
registry.add_mappings(vec![CredentialMapping::bearer("test_key", "api.test.com")]);
let tool = HttpTool::new().with_credentials(
registry,
Arc::new(crate::secrets::InMemorySecretsStore::new(Arc::new(
crate::secrets::SecretsCrypto::new(secrecy::SecretString::from(
"0123456789abcdef0123456789abcdef".to_string(),
))
.unwrap(),
))),
);
let tool = HttpTool::new().with_credentials(registry, Arc::new(test_secrets_store()));
// These calls should not panic in multi-thread runtime
let params_no_auth = serde_json::json!({
+6 -13
View File
@@ -1748,14 +1748,10 @@ mod tests {
#[tokio::test]
async fn test_parse_credentials_missing_secret() {
use crate::secrets::{InMemorySecretsStore, SecretsCrypto};
use secrecy::SecretString;
use crate::testing::credentials::test_secrets_store;
let manager = Arc::new(ContextManager::new(5));
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let secrets: Arc<dyn SecretsStore + Send + Sync> =
Arc::new(InMemorySecretsStore::new(crypto));
let secrets: Arc<dyn SecretsStore + Send + Sync> = Arc::new(test_secrets_store());
let tool = CreateJobTool::new(manager).with_secrets(Arc::clone(&secrets));
@@ -1772,20 +1768,17 @@ mod tests {
#[tokio::test]
async fn test_parse_credentials_valid() {
use crate::secrets::{CreateSecretParams, InMemorySecretsStore, SecretsCrypto};
use secrecy::SecretString;
use crate::secrets::CreateSecretParams;
use crate::testing::credentials::{TEST_GITHUB_TOKEN, test_secrets_store};
let manager = Arc::new(ContextManager::new(5));
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let secrets: Arc<dyn SecretsStore + Send + Sync> =
Arc::new(InMemorySecretsStore::new(Arc::clone(&crypto)));
let secrets: Arc<dyn SecretsStore + Send + Sync> = Arc::new(test_secrets_store());
// Store a secret
secrets
.create(
"user1",
CreateSecretParams::new("github_token", "ghp_test123"),
CreateSecretParams::new("github_token", TEST_GITHUB_TOKEN),
)
.await
.unwrap();
+5 -8
View File
@@ -158,16 +158,13 @@ impl Tool for SecretDeleteTool {
mod tests {
use std::sync::Arc;
use secrecy::SecretString;
use super::*;
use crate::context::JobContext;
use crate::secrets::{CreateSecretParams, InMemorySecretsStore, SecretsCrypto};
use crate::secrets::CreateSecretParams;
use crate::testing::credentials::{TEST_OPENAI_API_KEY_SHORT, test_secrets_store};
fn test_store() -> Arc<InMemorySecretsStore> {
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
Arc::new(InMemorySecretsStore::new(crypto))
fn test_store() -> Arc<crate::secrets::InMemorySecretsStore> {
Arc::new(test_secrets_store())
}
fn test_ctx() -> JobContext {
@@ -183,7 +180,7 @@ mod tests {
store
.create(
&ctx.user_id,
CreateSecretParams::new("openai_key", "sk-test"),
CreateSecretParams::new("openai_key", TEST_OPENAI_API_KEY_SHORT),
)
.await
.unwrap();
+3 -2
View File
@@ -480,6 +480,7 @@ pub fn validate_tool_schema(schema: &serde_json::Value, path: &str) -> Vec<Strin
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::credentials::TEST_REDACT_SECRET;
/// A simple no-op tool for testing.
#[derive(Debug)]
@@ -602,12 +603,12 @@ mod tests {
#[test]
fn test_redact_params_replaces_sensitive_key() {
let params = serde_json::json!({"name": "openai_key", "value": "sk-secret"});
let params = serde_json::json!({"name": "openai_key", "value": TEST_REDACT_SECRET});
let redacted = redact_params(&params, &["value"]);
assert_eq!(redacted["name"], "openai_key");
assert_eq!(redacted["value"], "[REDACTED]");
// Original unchanged
assert_eq!(params["value"], "sk-secret");
assert_eq!(params["value"], TEST_REDACT_SECRET);
}
#[test]
+8 -9
View File
@@ -365,22 +365,18 @@ fn base64_encode(input: &[u8]) -> String {
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::sync::Arc;
use secrecy::SecretString;
use crate::secrets::{
CreateSecretParams, CredentialLocation, CredentialMapping, InMemorySecretsStore,
SecretsCrypto, SecretsStore,
SecretsStore,
};
use crate::testing::credentials::{TEST_OPENAI_API_KEY, test_secrets_store};
use crate::tools::wasm::credential_injector::{
CredentialInjector, base64_encode, host_matches_pattern,
};
fn test_store() -> InMemorySecretsStore {
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
InMemorySecretsStore::new(crypto)
test_secrets_store()
}
#[test]
@@ -406,7 +402,10 @@ mod tests {
async fn test_inject_bearer() {
let store = test_store();
store
.create("user1", CreateSecretParams::new("openai_key", "sk-test123"))
.create(
"user1",
CreateSecretParams::new("openai_key", TEST_OPENAI_API_KEY),
)
.await
.unwrap();
@@ -428,7 +427,7 @@ mod tests {
assert_eq!(
result.headers.get("Authorization"),
Some(&"Bearer sk-test123".to_string())
Some(&format!("Bearer {TEST_OPENAI_API_KEY}"))
);
}
+8 -4
View File
@@ -694,6 +694,7 @@ mod tests {
use tempfile::TempDir;
use crate::testing::credentials::{TEST_OAUTH_CLIENT_ID, TEST_OAUTH_CLIENT_SECRET};
use crate::tools::wasm::loader::{WasmLoadError, check_wit_version_compat, discover_tools};
#[test]
@@ -834,8 +835,8 @@ mod tests {
oauth: Some(OAuthConfigSchema {
authorization_url: "https://accounts.google.com/o/oauth2/v2/auth".to_string(),
token_url: "https://oauth2.googleapis.com/token".to_string(),
client_id: Some("test-client-id".to_string()),
client_secret: Some("test-client-secret".to_string()),
client_id: Some(TEST_OAUTH_CLIENT_ID.to_string()),
client_secret: Some(TEST_OAUTH_CLIENT_SECRET.to_string()),
..Default::default()
}),
..Default::default()
@@ -848,8 +849,11 @@ mod tests {
let config = config.unwrap();
assert_eq!(config.token_url, "https://oauth2.googleapis.com/token");
assert_eq!(config.client_id, "test-client-id");
assert_eq!(config.client_secret, Some("test-client-secret".to_string()));
assert_eq!(config.client_id, TEST_OAUTH_CLIENT_ID);
assert_eq!(
config.client_secret,
Some(TEST_OAUTH_CLIENT_SECRET.to_string())
);
assert_eq!(config.secret_name, "google_oauth_token");
assert_eq!(config.provider, Some("google".to_string()));
}
+29 -49
View File
@@ -1223,6 +1223,11 @@ fn coerce_params_to_schema(
mod tests {
use std::sync::Arc;
use crate::testing::credentials::{
TEST_BEARER_TOKEN_123, TEST_GOOGLE_OAUTH_FRESH, TEST_GOOGLE_OAUTH_LEGACY,
TEST_GOOGLE_OAUTH_TOKEN, TEST_OAUTH_CLIENT_ID, TEST_OAUTH_CLIENT_SECRET,
test_secrets_store,
};
use crate::tools::wasm::capabilities::Capabilities;
use crate::tools::wasm::runtime::{WasmRuntimeConfig, WasmToolRuntime};
@@ -1290,12 +1295,12 @@ mod tests {
let mut h = HashMap::new();
h.insert(
"Authorization".to_string(),
"Bearer test-token-123".to_string(),
format!("Bearer {TEST_BEARER_TOKEN_123}"),
);
h
},
query_params: HashMap::new(),
secret_value: "test-token-123".to_string(),
secret_value: TEST_BEARER_TOKEN_123.to_string(),
}];
let store_data = StoreData::new(
@@ -1311,7 +1316,7 @@ mod tests {
store_data.inject_host_credentials("www.googleapis.com", &mut headers, &mut url);
assert_eq!(
headers.get("Authorization"),
Some(&"Bearer test-token-123".to_string())
Some(&format!("Bearer {TEST_BEARER_TOKEN_123}"))
);
// Should not inject for non-matching host
@@ -1387,13 +1392,9 @@ mod tests {
#[tokio::test]
async fn test_resolve_host_credentials_no_http_cap() {
use crate::secrets::{InMemorySecretsStore, SecretsCrypto};
use crate::tools::wasm::wrapper::resolve_host_credentials;
use secrecy::SecretString;
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let store = InMemorySecretsStore::new(crypto);
let store = test_secrets_store();
let caps = Capabilities::default();
let result = resolve_host_credentials(&caps, Some(&store), "user1", None).await;
@@ -1405,21 +1406,17 @@ mod tests {
use std::collections::HashMap;
use crate::secrets::{
CreateSecretParams, CredentialLocation, CredentialMapping, InMemorySecretsStore,
SecretsCrypto, SecretsStore,
CreateSecretParams, CredentialLocation, CredentialMapping, SecretsStore,
};
use crate::tools::wasm::capabilities::HttpCapability;
use crate::tools::wasm::wrapper::resolve_host_credentials;
use secrecy::SecretString;
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let store = InMemorySecretsStore::new(crypto);
let store = test_secrets_store();
store
.create(
"user1",
CreateSecretParams::new("google_oauth_token", "ya29.test-token"),
CreateSecretParams::new("google_oauth_token", TEST_GOOGLE_OAUTH_TOKEN),
)
.await
.unwrap();
@@ -1447,7 +1444,7 @@ mod tests {
assert_eq!(result[0].host_patterns, vec!["www.googleapis.com"]);
assert_eq!(
result[0].headers.get("Authorization"),
Some(&"Bearer ya29.test-token".to_string())
Some(&format!("Bearer {TEST_GOOGLE_OAUTH_TOKEN}"))
);
}
@@ -1455,16 +1452,11 @@ mod tests {
async fn test_resolve_host_credentials_missing_secret() {
use std::collections::HashMap;
use crate::secrets::{
CredentialLocation, CredentialMapping, InMemorySecretsStore, SecretsCrypto,
};
use crate::secrets::{CredentialLocation, CredentialMapping};
use crate::tools::wasm::capabilities::HttpCapability;
use crate::tools::wasm::wrapper::resolve_host_credentials;
use secrecy::SecretString;
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let store = InMemorySecretsStore::new(crypto);
let store = test_secrets_store();
// No secret stored, should silently skip
let mut credentials = HashMap::new();
@@ -1494,23 +1486,19 @@ mod tests {
use std::collections::HashMap;
use crate::secrets::{
CreateSecretParams, CredentialLocation, CredentialMapping, InMemorySecretsStore,
SecretsCrypto, SecretsStore,
CreateSecretParams, CredentialLocation, CredentialMapping, SecretsStore,
};
use crate::tools::wasm::capabilities::HttpCapability;
use crate::tools::wasm::wrapper::{OAuthRefreshConfig, resolve_host_credentials};
use secrecy::SecretString;
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let store = InMemorySecretsStore::new(crypto);
let store = test_secrets_store();
// Store a token that expires 2 hours from now (well within buffer)
let expires_at = chrono::Utc::now() + chrono::Duration::hours(2);
store
.create(
"user1",
CreateSecretParams::new("google_oauth_token", "ya29.fresh-token")
CreateSecretParams::new("google_oauth_token", TEST_GOOGLE_OAUTH_FRESH)
.with_expiry(expires_at),
)
.await
@@ -1536,8 +1524,8 @@ mod tests {
let oauth_config = OAuthRefreshConfig {
token_url: "https://oauth2.googleapis.com/token".to_string(),
client_id: "test-client-id".to_string(),
client_secret: Some("test-client-secret".to_string()),
client_id: TEST_OAUTH_CLIENT_ID.to_string(),
client_secret: Some(TEST_OAUTH_CLIENT_SECRET.to_string()),
secret_name: "google_oauth_token".to_string(),
provider: Some("google".to_string()),
};
@@ -1548,7 +1536,7 @@ mod tests {
assert_eq!(result.len(), 1);
assert_eq!(
result[0].headers.get("Authorization"),
Some(&"Bearer ya29.fresh-token".to_string())
Some(&format!("Bearer {TEST_GOOGLE_OAUTH_FRESH}"))
);
}
@@ -1557,16 +1545,12 @@ mod tests {
use std::collections::HashMap;
use crate::secrets::{
CreateSecretParams, CredentialLocation, CredentialMapping, InMemorySecretsStore,
SecretsCrypto, SecretsStore,
CreateSecretParams, CredentialLocation, CredentialMapping, SecretsStore,
};
use crate::tools::wasm::capabilities::HttpCapability;
use crate::tools::wasm::wrapper::resolve_host_credentials;
use secrecy::SecretString;
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let store = InMemorySecretsStore::new(crypto);
let store = test_secrets_store();
// Store an expired token
let expires_at = chrono::Utc::now() - chrono::Duration::hours(1);
@@ -1606,22 +1590,18 @@ mod tests {
use std::collections::HashMap;
use crate::secrets::{
CreateSecretParams, CredentialLocation, CredentialMapping, InMemorySecretsStore,
SecretsCrypto, SecretsStore,
CreateSecretParams, CredentialLocation, CredentialMapping, SecretsStore,
};
use crate::tools::wasm::capabilities::HttpCapability;
use crate::tools::wasm::wrapper::{OAuthRefreshConfig, resolve_host_credentials};
use secrecy::SecretString;
let key = "0123456789abcdef0123456789abcdef";
let crypto = Arc::new(SecretsCrypto::new(SecretString::from(key.to_string())).unwrap());
let store = InMemorySecretsStore::new(crypto);
let store = test_secrets_store();
// Legacy token: no expires_at set
store
.create(
"user1",
CreateSecretParams::new("google_oauth_token", "ya29.legacy-token"),
CreateSecretParams::new("google_oauth_token", TEST_GOOGLE_OAUTH_LEGACY),
)
.await
.unwrap();
@@ -1646,8 +1626,8 @@ mod tests {
let oauth_config = OAuthRefreshConfig {
token_url: "https://oauth2.googleapis.com/token".to_string(),
client_id: "test-client-id".to_string(),
client_secret: Some("test-client-secret".to_string()),
client_id: TEST_OAUTH_CLIENT_ID.to_string(),
client_secret: Some(TEST_OAUTH_CLIENT_SECRET.to_string()),
secret_name: "google_oauth_token".to_string(),
provider: Some("google".to_string()),
};
@@ -1658,7 +1638,7 @@ mod tests {
assert_eq!(result.len(), 1);
assert_eq!(
result[0].headers.get("Authorization"),
Some(&"Bearer ya29.legacy-token".to_string())
Some(&format!("Bearer {TEST_GOOGLE_OAUTH_LEGACY}"))
);
}