Loading...
Loading...
Compare original and translation side by side
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:security/recommended'
],
plugins: ['@typescript-eslint', 'security', 'import'],
rules: {
'no-console': ['warn', { allow: ['error', 'warn'] }],
'no-unused-vars': 'error',
'prefer-const': 'error',
'eqeqeq': ['error', 'always'],
'no-eval': 'error',
'security/detect-object-injection': 'warn',
'security/detect-non-literal-regexp': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'error',
'import/order': ['error', {
'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
'newlines-between': 'always'
}]
}
};// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:security/recommended'
],
plugins: ['@typescript-eslint', 'security', 'import'],
rules: {
'no-console': ['warn', { allow: ['error', 'warn'] }],
'no-unused-vars': 'error',
'prefer-const': 'error',
'eqeqeq': ['error', 'always'],
'no-eval': 'error',
'security/detect-object-injection': 'warn',
'security/detect-non-literal-regexp': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-function-return-type': 'error',
'import/order': ['error', {
'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
'newlines-between': 'always'
}]
}
};undefinedundefined
```python
```pythonundefinedundefinedundefinedundefinedundefinedundefinedundefinedundefined
```yaml
```yaml - name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- name: Quality Gate Check
uses: sonarsource/sonarqube-quality-gate-action@master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}undefined - name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- name: Quality Gate Check
uses: sonarsource/sonarqube-quality-gate-action@master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}undefinedimport * as ts from 'typescript';
import * as fs from 'fs';
interface Issue {
file: string;
line: number;
column: number;
message: string;
severity: 'error' | 'warning' | 'info';
rule: string;
}
class CustomLinter {
private issues: Issue[] = [];
lintFile(filePath: string): Issue[] {
this.issues = [];
const sourceCode = fs.readFileSync(filePath, 'utf-8');
const sourceFile = ts.createSourceFile(
filePath,
sourceCode,
ts.ScriptTarget.Latest,
true
);
this.visit(sourceFile, filePath);
return this.issues;
}
private visit(node: ts.Node, filePath: string): void {
// Check for console.log
if (
ts.isCallExpression(node) &&
ts.isPropertyAccessExpression(node.expression) &&
node.expression.expression.getText() === 'console' &&
node.expression.name.getText() === 'log'
) {
const { line, character } = ts.getLineAndCharacterOfPosition(
node.getSourceFile(),
node.getStart()
);
this.issues.push({
file: filePath,
line: line + 1,
column: character + 1,
message: 'Unexpected console.log statement',
severity: 'warning',
rule: 'no-console'
});
}
// Check for any type
if (
ts.isTypeReferenceNode(node) &&
node.typeName.getText() === 'any'
) {
const { line, character } = ts.getLineAndCharacterOfPosition(
node.getSourceFile(),
node.getStart()
);
this.issues.push({
file: filePath,
line: line + 1,
column: character + 1,
message: 'Avoid using any type',
severity: 'warning',
rule: 'no-any'
});
}
// Check for long functions
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
const body = node.body;
if (body && body.getFullText().split('\n').length > 50) {
const { line, character } = ts.getLineAndCharacterOfPosition(
node.getSourceFile(),
node.getStart()
);
this.issues.push({
file: filePath,
line: line + 1,
column: character + 1,
message: 'Function is too long (>50 lines)',
severity: 'warning',
rule: 'max-lines-per-function'
});
}
}
ts.forEachChild(node, child => this.visit(child, filePath));
}
formatIssues(issues: Issue[]): string {
if (issues.length === 0) {
return 'No issues found.';
}
return issues.map(issue =>
`${issue.file}:${issue.line}:${issue.column} - ${issue.severity}: ${issue.message} (${issue.rule})`
).join('\n');
}
}
// Usage
const linter = new CustomLinter();
const issues = linter.lintFile('./src/example.ts');
console.log(linter.formatIssues(issues));import * as ts from 'typescript';
import * as fs from 'fs';
interface Issue {
file: string;
line: number;
column: number;
message: string;
severity: 'error' | 'warning' | 'info';
rule: string;
}
class CustomLinter {
private issues: Issue[] = [];
lintFile(filePath: string): Issue[] {
this.issues = [];
const sourceCode = fs.readFileSync(filePath, 'utf-8');
const sourceFile = ts.createSourceFile(
filePath,
sourceCode,
ts.ScriptTarget.Latest,
true
);
this.visit(sourceFile, filePath);
return this.issues;
}
private visit(node: ts.Node, filePath: string): void {
// Check for console.log
if (
ts.isCallExpression(node) &&
ts.isPropertyAccessExpression(node.expression) &&
node.expression.expression.getText() === 'console' &&
node.expression.name.getText() === 'log'
) {
const { line, character } = ts.getLineAndCharacterOfPosition(
node.getSourceFile(),
node.getStart()
);
this.issues.push({
file: filePath,
line: line + 1,
column: character + 1,
message: 'Unexpected console.log statement',
severity: 'warning',
rule: 'no-console'
});
}
// Check for any type
if (
ts.isTypeReferenceNode(node) &&
node.typeName.getText() === 'any'
) {
const { line, character } = ts.getLineAndCharacterOfPosition(
node.getSourceFile(),
node.getStart()
);
this.issues.push({
file: filePath,
line: line + 1,
column: character + 1,
message: 'Avoid using any type',
severity: 'warning',
rule: 'no-any'
});
}
// Check for long functions
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
const body = node.body;
if (body && body.getFullText().split('\n').length > 50) {
const { line, character } = ts.getLineAndCharacterOfPosition(
node.getSourceFile(),
node.getStart()
);
this.issues.push({
file: filePath,
line: line + 1,
column: character + 1,
message: 'Function is too long (>50 lines)',
severity: 'warning',
rule: 'max-lines-per-function'
});
}
}
ts.forEachChild(node, child => this.visit(child, filePath));
}
formatIssues(issues: Issue[]): string {
if (issues.length === 0) {
return 'No issues found.';
}
return issues.map(issue =>
`${issue.file}:${issue.line}:${issue.column} - ${issue.severity}: ${issue.message} (${issue.rule})`
).join('\n');
}
}
// Usage
const linter = new CustomLinter();
const issues = linter.lintFile('./src/example.ts');
console.log(linter.formatIssues(issues));import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
interface SecurityIssue {
severity: 'critical' | 'high' | 'medium' | 'low';
title: string;
description: string;
file?: string;
line?: number;
remediation?: string;
}
class SecurityScanner {
async scanDependencies(): Promise<SecurityIssue[]> {
try {
const { stdout } = await execAsync('npm audit --json');
const auditResult = JSON.parse(stdout);
const issues: SecurityIssue[] = [];
for (const [name, advisory] of Object.entries(auditResult.vulnerabilities || {})) {
const vuln = advisory as any;
issues.push({
severity: vuln.severity,
title: vuln.via[0]?.title || name,
description: vuln.via[0]?.url || '',
remediation: `Update ${name} to ${vuln.fixAvailable || 'latest'}`
});
}
return issues;
} catch (error) {
console.error('Dependency scan failed:', error);
return [];
}
}
async scanSecrets(directory: string): Promise<SecurityIssue[]> {
const issues: SecurityIssue[] = [];
// Simple regex-based secret detection
const patterns = [
{ name: 'API Key', pattern: /api[_-]?key['"]?\s*[:=]\s*['"]([a-zA-Z0-9]{32,})['"]/ },
{ name: 'AWS Key', pattern: /(AKIA[0-9A-Z]{16})/ },
{ name: 'Private Key', pattern: /-----BEGIN (RSA |EC )?PRIVATE KEY-----/ },
{ name: 'Password', pattern: /password['"]?\s*[:=]\s*['"]((?!<%= ).{8,})['"]/ }
];
// Scan files
const files = this.getFiles(directory);
for (const file of files) {
const content = fs.readFileSync(file, 'utf-8');
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
for (const { name, pattern } of patterns) {
if (pattern.test(lines[i])) {
issues.push({
severity: 'critical',
title: `Potential ${name} detected`,
description: `Found in ${file}:${i + 1}`,
file,
line: i + 1,
remediation: 'Remove secret and use environment variables'
});
}
}
}
}
return issues;
}
private getFiles(dir: string): string[] {
// Implementation to recursively get files
return [];
}
generateReport(issues: SecurityIssue[]): string {
let report = '# Security Scan Report\n\n';
const grouped = issues.reduce((acc, issue) => {
acc[issue.severity] = acc[issue.severity] || [];
acc[issue.severity].push(issue);
return acc;
}, {} as Record<string, SecurityIssue[]>);
for (const [severity, items] of Object.entries(grouped)) {
report += `## ${severity.toUpperCase()} (${items.length})\n\n`;
for (const issue of items) {
report += `### ${issue.title}\n`;
report += `${issue.description}\n`;
if (issue.remediation) {
report += `**Remediation:** ${issue.remediation}\n`;
}
report += '\n';
}
}
return report;
}
}
// Usage
const scanner = new SecurityScanner();
const depIssues = await scanner.scanDependencies();
const secretIssues = await scanner.scanSecrets('./src');
const allIssues = [...depIssues, ...secretIssues];
console.log(scanner.generateReport(allIssues));import { exec } from 'child_process';
import { promisify } from 'util';
const execAsync = promisify(exec);
interface SecurityIssue {
severity: 'critical' | 'high' | 'medium' | 'low';
title: string;
description: string;
file?: string;
line?: number;
remediation?: string;
}
class SecurityScanner {
async scanDependencies(): Promise<SecurityIssue[]> {
try {
const { stdout } = await execAsync('npm audit --json');
const auditResult = JSON.parse(stdout);
const issues: SecurityIssue[] = [];
for (const [name, advisory] of Object.entries(auditResult.vulnerabilities || {})) {
const vuln = advisory as any;
issues.push({
severity: vuln.severity,
title: vuln.via[0]?.title || name,
description: vuln.via[0]?.url || '',
remediation: `Update ${name} to ${vuln.fixAvailable || 'latest'}`
});
}
return issues;
} catch (error) {
console.error('Dependency scan failed:', error);
return [];
}
}
async scanSecrets(directory: string): Promise<SecurityIssue[]> {
const issues: SecurityIssue[] = [];
// Simple regex-based secret detection
const patterns = [
{ name: 'API Key', pattern: /api[_-]?key['"]?\s*[:=]\s*['"]([a-zA-Z0-9]{32,})['"]/ },
{ name: 'AWS Key', pattern: /(AKIA[0-9A-Z]{16})/ },
{ name: 'Private Key', pattern: /-----BEGIN (RSA |EC )?PRIVATE KEY-----/ },
{ name: 'Password', pattern: /password['"]?\s*[:=]\s*['"]((?!<%= ).{8,})['"]/ }
];
// Scan files
const files = this.getFiles(directory);
for (const file of files) {
const content = fs.readFileSync(file, 'utf-8');
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
for (const { name, pattern } of patterns) {
if (pattern.test(lines[i])) {
issues.push({
severity: 'critical',
title: `Potential ${name} detected`,
description: `Found in ${file}:${i + 1}`,
file,
line: i + 1,
remediation: 'Remove secret and use environment variables'
});
}
}
}
}
return issues;
}
private getFiles(dir: string): string[] {
// Implementation to recursively get files
return [];
}
generateReport(issues: SecurityIssue[]): string {
let report = '# Security Scan Report\n\n';
const grouped = issues.reduce((acc, issue) => {
acc[issue.severity] = acc[issue.severity] || [];
acc[issue.severity].push(issue);
return acc;
}, {} as Record<string, SecurityIssue[]>);
for (const [severity, items] of Object.entries(grouped)) {
report += `## ${severity.toUpperCase()} (${items.length})\n\n`;
for (const issue of items) {
report += `### ${issue.title}\n`;
report += `${issue.description}\n`;
if (issue.remediation) {
report += `**Remediation:** ${issue.remediation}\n`;
}
report += '\n';
}
}
return report;
}
}
// Usage
const scanner = new SecurityScanner();
const depIssues = await scanner.scanDependencies();
const secretIssues = await scanner.scanSecrets('./src');
const allIssues = [...depIssues, ...secretIssues];
console.log(scanner.generateReport(allIssues));