#include #include #include #include #include "fold/detect/hardcoded_credential.hpp" #include "fold/report/finding.hpp" namespace { std::unique_ptr parse(const std::string& code) { return clang::tooling::buildASTFromCodeWithArgs(code, {"-std=c++20"}, "input.cpp"); } } // namespace TEST_CASE("hardcoded-credential: JWT literal is flagged", "[hardcoded-credential][jwt]") { auto unit = parse(R"( const char *token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].kind == fold::FindingKind::HardcodedCredential); REQUIRE(findings[0].message.find("JWT") != std::string::npos); } TEST_CASE("hardcoded-credential: AWS access key id is flagged", "[hardcoded-credential][aws]") { auto unit = parse(R"( const char *access_key = "AKIA1234567890ABCDEF"; )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].message.find("AWS") != std::string::npos); } TEST_CASE("hardcoded-credential: generic private key armour is flagged", "[hardcoded-credential][pem]") { auto unit = parse(R"( const char *key = "-----BEGIN OPENSSH PRIVATE KEY-----\nabc\n-----END OPENSSH PRIVATE KEY-----"; )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].message.find("private key") != std::string::npos); } TEST_CASE("hardcoded-credential: secret-looking literal assigned to api_key is flagged", "[hardcoded-credential][heuristic]") { auto unit = parse(R"( const char *api_key = "AbCdEfGhIjKlMnOpQr9_123"; )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].message.find("secret-looking") != std::string::npos); } TEST_CASE("hardcoded-credential: placeholder api key literal is not flagged", "[hardcoded-credential][placeholder][negative]") { auto unit = parse(R"( const char *api_key = "your_api_key_here"; )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.empty()); } TEST_CASE("hardcoded-credential: matcher and regex vocabulary are not credentials", "[hardcoded-credential][vocabulary]") { auto unit = parse(R"( struct Text { unsigned long rfind(const char*, unsigned long) const; }; bool recognizes(Text value) { return value.rfind("sk_live_1234567890abcdef", 0) == 0; } namespace std { struct regex { explicit regex(const char*); }; } std::regex private_key_pattern("-----BEGIN [A-Z ]*PRIVATE KEY-----"); )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.empty()); } TEST_CASE("hardcoded-credential: direct secret comparison remains reportable", "[hardcoded-credential][comparison]") { auto unit = parse(R"( extern "C" int strcmp(const char*, const char*); bool accepts(const char* provided) { return strcmp(provided, "sk_live_1234567890abcdef") == 0; } )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); } TEST_CASE("hardcoded-credential: Stripe test key is flagged", "[hardcoded-credential][stripe-test]") { auto unit = parse(R"( const char *secret = "sk_test_51NvTExampleSecretValue"; )"); REQUIRE(unit); auto findings = fold::detectHardcodedCredentialInContext(unit->getASTContext()); REQUIRE(findings.size() == 1); REQUIRE(findings[0].message.find("Stripe test key") != std::string::npos); }