@samiyev/guardian
Version:
Research-backed code quality guardian for AI-assisted development. Detects hardcodes, secrets, circular deps, framework leaks, entity exposure, and 9 architecture violations. Enforces Clean Architecture/DDD principles. Works with GitHub Copilot, Cursor, W
164 lines • 7.16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecretDetector = void 0;
const node_1 = require("@secretlint/node");
const SecretViolation_1 = require("../../domain/value-objects/SecretViolation");
const SecretExamples_1 = require("../../domain/constants/SecretExamples");
const rules_1 = require("../../shared/constants/rules");
/**
* Detects hardcoded secrets in TypeScript/JavaScript code
*
* Uses industry-standard Secretlint library to detect 350+ types of secrets
* including AWS keys, GitHub tokens, NPM tokens, SSH keys, API keys, and more.
*
* All detected secrets are marked as CRITICAL severity because they represent
* serious security risks that could lead to unauthorized access or data breaches.
*
* @example
* ```typescript
* const detector = new SecretDetector()
* const code = `const AWS_KEY = "AKIA1234567890ABCDEF"`
* const violations = await detector.detectAll(code, 'config.ts')
* // Returns array of SecretViolation objects with CRITICAL severity
* ```
*/
class SecretDetector {
secretlintConfig = {
rules: [
{
id: rules_1.EXTERNAL_PACKAGES.SECRETLINT_PRESET,
},
],
};
/**
* Detects all types of hardcoded secrets in the provided code
*
* @param code - Source code to analyze
* @param filePath - Path to the file being analyzed
* @returns Promise resolving to array of secret violations
*/
async detectAll(code, filePath) {
try {
const engine = await (0, node_1.createEngine)({
cwd: process.cwd(),
configFileJSON: this.secretlintConfig,
formatter: "stylish",
color: false,
});
const result = await engine.executeOnContent({
content: code,
filePath,
});
return this.parseOutputToViolations(result.output, filePath);
}
catch (_error) {
return [];
}
}
parseOutputToViolations(output, filePath) {
const violations = [];
if (!output || output.trim() === "") {
return violations;
}
const lines = output.split("\n");
for (const line of lines) {
const match = /^\s*(\d+):(\d+)\s+(error|warning)\s+(.+?)\s+(.+)$/.exec(line);
if (match) {
const [, lineNum, column, , message, ruleId] = match;
const secretType = this.extractSecretType(message, ruleId);
const violation = SecretViolation_1.SecretViolation.create(filePath, parseInt(lineNum, 10), parseInt(column, 10), secretType, message);
violations.push(violation);
}
}
return violations;
}
extractSecretType(message, ruleId) {
const lowerMessage = message.toLowerCase();
const ruleBasedType = this.extractByRuleId(ruleId, lowerMessage);
if (ruleBasedType) {
return ruleBasedType;
}
return this.extractByMessage(lowerMessage);
}
extractByRuleId(ruleId, lowerMessage) {
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.AWS)) {
return this.extractAwsType(lowerMessage);
}
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.GITHUB)) {
return this.extractGithubType(lowerMessage);
}
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.NPM)) {
return SecretExamples_1.SECRET_TYPE_NAMES.NPM_TOKEN;
}
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.GCP) || ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.GOOGLE)) {
return SecretExamples_1.SECRET_TYPE_NAMES.GCP_SERVICE_ACCOUNT_KEY;
}
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.PRIVATEKEY) || ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.SSH)) {
return this.extractSshType(lowerMessage);
}
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.SLACK)) {
return this.extractSlackType(lowerMessage);
}
if (ruleId.includes(SecretExamples_1.SECRET_KEYWORDS.BASICAUTH)) {
return SecretExamples_1.SECRET_TYPE_NAMES.BASIC_AUTH_CREDENTIALS;
}
return null;
}
extractAwsType(lowerMessage) {
if (lowerMessage.includes(SecretExamples_1.SECRET_KEYWORDS.ACCESS_KEY)) {
return SecretExamples_1.SECRET_TYPE_NAMES.AWS_ACCESS_KEY;
}
if (lowerMessage.includes(SecretExamples_1.SECRET_KEYWORDS.SECRET)) {
return SecretExamples_1.SECRET_TYPE_NAMES.AWS_SECRET_KEY;
}
return SecretExamples_1.SECRET_TYPE_NAMES.AWS_CREDENTIAL;
}
extractGithubType(lowerMessage) {
if (lowerMessage.includes(SecretExamples_1.SECRET_KEYWORDS.PERSONAL_ACCESS_TOKEN)) {
return SecretExamples_1.SECRET_TYPE_NAMES.GITHUB_PERSONAL_ACCESS_TOKEN;
}
if (lowerMessage.includes(SecretExamples_1.SECRET_KEYWORDS.OAUTH)) {
return SecretExamples_1.SECRET_TYPE_NAMES.GITHUB_OAUTH_TOKEN;
}
return SecretExamples_1.SECRET_TYPE_NAMES.GITHUB_TOKEN;
}
extractSshType(lowerMessage) {
const sshTypeMap = [
[SecretExamples_1.SECRET_KEYWORDS.RSA, SecretExamples_1.SECRET_TYPE_NAMES.SSH_RSA_PRIVATE_KEY],
[SecretExamples_1.SECRET_KEYWORDS.DSA, SecretExamples_1.SECRET_TYPE_NAMES.SSH_DSA_PRIVATE_KEY],
[SecretExamples_1.SECRET_KEYWORDS.ECDSA, SecretExamples_1.SECRET_TYPE_NAMES.SSH_ECDSA_PRIVATE_KEY],
[SecretExamples_1.SECRET_KEYWORDS.ED25519, SecretExamples_1.SECRET_TYPE_NAMES.SSH_ED25519_PRIVATE_KEY],
];
for (const [keyword, typeName] of sshTypeMap) {
if (lowerMessage.includes(keyword)) {
return typeName;
}
}
return SecretExamples_1.SECRET_TYPE_NAMES.SSH_PRIVATE_KEY;
}
extractSlackType(lowerMessage) {
if (lowerMessage.includes(SecretExamples_1.SECRET_KEYWORDS.BOT)) {
return SecretExamples_1.SECRET_TYPE_NAMES.SLACK_BOT_TOKEN;
}
if (lowerMessage.includes(SecretExamples_1.SECRET_KEYWORDS.USER)) {
return SecretExamples_1.SECRET_TYPE_NAMES.SLACK_USER_TOKEN;
}
return SecretExamples_1.SECRET_TYPE_NAMES.SLACK_TOKEN;
}
extractByMessage(lowerMessage) {
const messageTypeMap = [
[SecretExamples_1.SECRET_KEYWORDS.API_KEY, SecretExamples_1.SECRET_TYPE_NAMES.API_KEY],
[SecretExamples_1.SECRET_KEYWORDS.TOKEN, SecretExamples_1.SECRET_TYPE_NAMES.AUTHENTICATION_TOKEN],
[SecretExamples_1.SECRET_KEYWORDS.PASSWORD, SecretExamples_1.SECRET_TYPE_NAMES.PASSWORD],
[SecretExamples_1.SECRET_KEYWORDS.SECRET, SecretExamples_1.SECRET_TYPE_NAMES.SECRET],
];
for (const [keyword, typeName] of messageTypeMap) {
if (lowerMessage.includes(keyword)) {
return typeName;
}
}
return SecretExamples_1.SECRET_TYPE_NAMES.SENSITIVE_DATA;
}
}
exports.SecretDetector = SecretDetector;
//# sourceMappingURL=SecretDetector.js.map