static-code-analysis
について
このスキルは、リンター、フォーマッター、セキュリティスキャナーを使用した静的コード解析を実装し、バグや脆弱性を早期に発見します。コード標準の強制、セキュリティ問題の検出、CI/CDパイプラインでのコードレビュー自動化にご利用ください。実行前の自動チェックを通じて、コード品質の維持を支援します。
クイックインストール
Claude Code
推奨npx skills add aj-geddes/useful-ai-prompts/plugin add https://github.com/aj-geddes/useful-ai-promptsgit clone https://github.com/aj-geddes/useful-ai-prompts.git ~/.claude/skills/static-code-analysisこのコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします
ドキュメント
Static Code Analysis
Overview
Use automated tools to analyze code without executing it, catching bugs, security issues, and style violations early.
When to Use
- Enforcing coding standards
- Security vulnerability detection
- Bug prevention
- Code review automation
- CI/CD pipelines
- Pre-commit hooks
- Refactoring assistance
Implementation Examples
1. ESLint Configuration
// .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'
}]
}
};
2. Python Linting (pylint + mypy)
# .pylintrc
[MASTER]
ignore=venv,.git,__pycache__
jobs=4
[MESSAGES CONTROL]
disable=
missing-docstring,
too-few-public-methods
[FORMAT]
max-line-length=100
max-module-lines=1000
[DESIGN]
max-args=5
max-locals=15
max-returns=6
max-branches=12
max-statements=50
# mypy.ini
[mypy]
python_version = 3.10
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_calls = True
warn_redundant_casts = True
warn_unused_ignores = True
strict_equality = True
3. Pre-commit Hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: check-merge-conflict
- id: detect-private-key
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.50.0
hooks:
- id: eslint
files: \.[jt]sx?$
types: [file]
- repo: https://github.com/psf/black
rev: 23.9.1
hooks:
- id: black
- repo: https://github.com/PyCQA/pylint
rev: v3.0.0
hooks:
- id: pylint
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.5.1
hooks:
- id: mypy
additional_dependencies: [types-requests]
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.58.0
hooks:
- id: trufflehog
entry: trufflehog filesystem --directory .
4. SonarQube Integration
# sonar-project.properties
sonar.projectKey=my-project
sonar.projectName=My Project
sonar.projectVersion=1.0
sonar.sources=src
sonar.tests=tests
sonar.exclusions=**/node_modules/**,**/*.test.ts
sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.qualitygate.wait=true
# Quality gates
sonar.coverage.exclusions=**/*.test.ts
# .github/workflows/sonar.yml
name: SonarQube Analysis
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
sonar:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- 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 }}
5. Custom AST Analysis
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));
6. Security Scanning
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));
Best Practices
✅ DO
- Run linters in CI/CD
- Use pre-commit hooks
- Configure IDE integration
- Fix issues incrementally
- Document custom rules
- Share configuration across team
- Automate security scanning
❌ DON'T
- Ignore all warnings
- Skip linter setup
- Commit lint violations
- Use overly strict rules initially
- Skip security scans
- Disable rules without reason
Tools
- JavaScript/TypeScript: ESLint, TSLint, Prettier
- Python: Pylint, Flake8, Black, Bandit
- Java: PMD, Checkstyle, SpotBugs
- Security: Snyk, Semgrep, Bandit, TruffleHog
- Multi-language: SonarQube, CodeQL
Resources
GitHub リポジトリ
関連スキル
content-collections
メタThis skill provides a production-tested setup for Content Collections, a TypeScript-first tool that transforms Markdown/MDX files into type-safe data collections with Zod validation. Use it when building blogs, documentation sites, or content-heavy Vite + React applications to ensure type safety and automatic content validation. It covers everything from Vite plugin configuration and MDX compilation to deployment optimization and schema validation.
sglang
メタSGLang is a high-performance LLM serving framework that specializes in fast, structured generation for JSON, regex, and agentic workflows using its RadixAttention prefix caching. It delivers significantly faster inference, especially for tasks with repeated prefixes, making it ideal for complex, structured outputs and multi-turn conversations. Choose SGLang over alternatives like vLLM when you need constrained decoding or are building applications with extensive prefix sharing.
cloudflare-turnstile
メタThis skill provides comprehensive guidance for implementing Cloudflare Turnstile as a CAPTCHA-alternative bot protection system. It covers integration for forms, login pages, API endpoints, and frameworks like React/Next.js/Hono, while handling invisible challenges that maintain user experience. Use it when migrating from reCAPTCHA, debugging error codes, or implementing token validation and E2E tests.
cloudflare-cron-triggers
テストThis skill provides comprehensive knowledge for implementing Cloudflare Cron Triggers to schedule Workers using cron expressions. It covers setting up periodic tasks, maintenance jobs, and automated workflows while handling common issues like invalid cron expressions and timezone problems. Developers can use it for configuring scheduled handlers, testing cron triggers, and integrating with Workflows and Green Compute.
