antigravity-devkit 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -26
- package/package.json +2 -2
- package/template/ARCHITECTURE.md +0 -148
- package/template/README.md +0 -421
- package/template/agents/backend-specialist.md +0 -137
- package/template/agents/database-architect.md +0 -114
- package/template/agents/debugger.md +0 -108
- package/template/agents/devops-engineer.md +0 -125
- package/template/agents/documentation-writer.md +0 -109
- package/template/agents/explorer-agent.md +0 -107
- package/template/agents/frontend-specialist.md +0 -231
- package/template/agents/orchestrator.md +0 -100
- package/template/agents/performance-optimizer.md +0 -109
- package/template/agents/project-planner.md +0 -123
- package/template/agents/security-auditor.md +0 -107
- package/template/agents/test-engineer.md +0 -133
- package/template/rules/GEMINI.md +0 -180
- package/template/scripts/README.md +0 -317
- package/template/scripts/checklist.py +0 -170
- package/template/scripts/lint_runner.py +0 -253
- package/template/scripts/schema_validator.py +0 -277
- package/template/scripts/security_scan.py +0 -354
- package/template/scripts/verify_all.py +0 -243
- package/template/scripts/vitest_runner.py +0 -203
- package/template/scripts/xunit_runner.py +0 -235
- package/template/skills/api-patterns/SKILL.md +0 -116
- package/template/skills/architecture/SKILL.md +0 -98
- package/template/skills/aspnet-patterns/SKILL.md +0 -122
- package/template/skills/azure-aks/SKILL.md +0 -136
- package/template/skills/azure-devops/SKILL.md +0 -123
- package/template/skills/azure-keyvault/SKILL.md +0 -100
- package/template/skills/brainstorming/SKILL.md +0 -96
- package/template/skills/clean-code/SKILL.md +0 -84
- package/template/skills/csharp-patterns/SKILL.md +0 -155
- package/template/skills/documentation-templates/SKILL.md +0 -127
- package/template/skills/frontend-design/SKILL.md +0 -199
- package/template/skills/frontend-design/animation-guide.md +0 -217
- package/template/skills/frontend-design/design-systems.md +0 -230
- package/template/skills/frontend-design/ux-psychology.md +0 -128
- package/template/skills/gitops-patterns/SKILL.md +0 -105
- package/template/skills/grafana-logging/SKILL.md +0 -107
- package/template/skills/intelligent-routing/SKILL.md +0 -75
- package/template/skills/plan-writing/SKILL.md +0 -96
- package/template/skills/sqlserver-design/SKILL.md +0 -97
- package/template/skills/systematic-debugging/SKILL.md +0 -98
- package/template/skills/testing-patterns/SKILL.md +0 -102
- package/template/skills/vitest-testing/SKILL.md +0 -116
- package/template/skills/vue3-patterns/SKILL.md +0 -235
- package/template/skills/vulnerability-scanner/SKILL.md +0 -104
- package/template/skills/xunit-testing/SKILL.md +0 -127
- package/template/workflows/brainstorm.md +0 -69
- package/template/workflows/code.md +0 -82
- package/template/workflows/create.md +0 -79
- package/template/workflows/debug.md +0 -83
- package/template/workflows/deploy.md +0 -101
- package/template/workflows/orchestrate.md +0 -86
- package/template/workflows/plan.md +0 -79
- package/template/workflows/review.md +0 -85
- package/template/workflows/status.md +0 -90
- package/template/workflows/test.md +0 -89
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Security Scanner - Security vulnerability detection and analysis
|
|
4
|
-
Used by security-auditor agent to scan for security issues.
|
|
5
|
-
|
|
6
|
-
Usage:
|
|
7
|
-
python security_scan.py <project_path>
|
|
8
|
-
python security_scan.py <project_path> --severity high
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import subprocess
|
|
12
|
-
import sys
|
|
13
|
-
import re
|
|
14
|
-
import json
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import Tuple, Dict, Any, List
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def run_command(cmd: list[str], cwd: str = ".") -> Tuple[int, str]:
|
|
20
|
-
"""Run a command and return exit code and output."""
|
|
21
|
-
try:
|
|
22
|
-
result = subprocess.run(
|
|
23
|
-
cmd,
|
|
24
|
-
cwd=cwd,
|
|
25
|
-
capture_output=True,
|
|
26
|
-
text=True,
|
|
27
|
-
timeout=300
|
|
28
|
-
)
|
|
29
|
-
return result.returncode, result.stdout + result.stderr
|
|
30
|
-
except subprocess.TimeoutExpired:
|
|
31
|
-
return 1, "Command timed out after 5 minutes"
|
|
32
|
-
except FileNotFoundError:
|
|
33
|
-
return 1, f"Command not found: {cmd[0]}"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def scan_hardcoded_secrets(project_path: str) -> List[Dict[str, str]]:
|
|
37
|
-
"""Scan for hardcoded secrets and credentials."""
|
|
38
|
-
findings = []
|
|
39
|
-
path = Path(project_path)
|
|
40
|
-
|
|
41
|
-
# Patterns to search for
|
|
42
|
-
secret_patterns = {
|
|
43
|
-
'password': r'password\s*=\s*["\'](?!.*\{.*\})([^"\']+)["\']',
|
|
44
|
-
'api_key': r'(api[_-]?key|apikey)\s*[=:]\s*["\']([^"\']+)["\']',
|
|
45
|
-
'secret': r'secret\s*[=:]\s*["\'](?!.*\{.*\})([^"\']+)["\']',
|
|
46
|
-
'token': r'(access[_-]?token|auth[_-]?token)\s*[=:]\s*["\']([^"\']+)["\']',
|
|
47
|
-
'connection_string': r'(connectionstring|connection[_-]string)\s*[=:]\s*["\'](?!.*\{.*\})([^"\']+)["\']',
|
|
48
|
-
'private_key': r'(private[_-]?key|privatekey)\s*[=:]\s*["\']([^"\']+)["\']',
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# File extensions to scan
|
|
52
|
-
extensions = ['.cs', '.ts', '.js', '.vue', '.json', '.config', '.yaml', '.yml']
|
|
53
|
-
|
|
54
|
-
for ext in extensions:
|
|
55
|
-
for file_path in path.glob(f"**/*{ext}"):
|
|
56
|
-
# Skip node_modules, bin, obj directories
|
|
57
|
-
if any(skip in str(file_path) for skip in ['node_modules', 'bin', 'obj', '.git']):
|
|
58
|
-
continue
|
|
59
|
-
|
|
60
|
-
try:
|
|
61
|
-
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
62
|
-
content = f.read()
|
|
63
|
-
|
|
64
|
-
for pattern_name, pattern in secret_patterns.items():
|
|
65
|
-
matches = re.finditer(pattern, content, re.IGNORECASE)
|
|
66
|
-
for match in matches:
|
|
67
|
-
# Skip if it looks like a placeholder or environment variable
|
|
68
|
-
matched_value = match.group(0)
|
|
69
|
-
if any(skip in matched_value.lower() for skip in ['example', 'placeholder', 'your_', 'xxx', '***', 'env.']):
|
|
70
|
-
continue
|
|
71
|
-
|
|
72
|
-
findings.append({
|
|
73
|
-
'type': pattern_name,
|
|
74
|
-
'file': str(file_path.relative_to(path)),
|
|
75
|
-
'line': content[:match.start()].count('\n') + 1,
|
|
76
|
-
'severity': 'HIGH',
|
|
77
|
-
'message': f'Potential hardcoded {pattern_name.replace("_", " ")}'
|
|
78
|
-
})
|
|
79
|
-
except Exception:
|
|
80
|
-
continue
|
|
81
|
-
|
|
82
|
-
return findings
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def scan_npm_vulnerabilities(project_path: str) -> List[Dict[str, str]]:
|
|
86
|
-
"""Scan npm packages for known vulnerabilities."""
|
|
87
|
-
findings = []
|
|
88
|
-
package_json = Path(project_path) / "package.json"
|
|
89
|
-
|
|
90
|
-
if not package_json.exists():
|
|
91
|
-
return findings
|
|
92
|
-
|
|
93
|
-
# Run npm audit
|
|
94
|
-
code, output = run_command(["npm", "audit", "--json"], project_path)
|
|
95
|
-
|
|
96
|
-
try:
|
|
97
|
-
audit_data = json.loads(output)
|
|
98
|
-
|
|
99
|
-
# Parse vulnerabilities
|
|
100
|
-
if 'vulnerabilities' in audit_data:
|
|
101
|
-
for pkg_name, vuln_info in audit_data['vulnerabilities'].items():
|
|
102
|
-
severity = vuln_info.get('severity', 'unknown').upper()
|
|
103
|
-
|
|
104
|
-
findings.append({
|
|
105
|
-
'type': 'npm_vulnerability',
|
|
106
|
-
'file': 'package.json',
|
|
107
|
-
'package': pkg_name,
|
|
108
|
-
'severity': severity,
|
|
109
|
-
'message': f"{pkg_name}: {vuln_info.get('via', ['Unknown issue'])[0] if isinstance(vuln_info.get('via'), list) else 'Vulnerability detected'}"
|
|
110
|
-
})
|
|
111
|
-
except json.JSONDecodeError:
|
|
112
|
-
# Fallback to text parsing
|
|
113
|
-
if 'vulnerabilities' in output.lower():
|
|
114
|
-
findings.append({
|
|
115
|
-
'type': 'npm_vulnerability',
|
|
116
|
-
'file': 'package.json',
|
|
117
|
-
'severity': 'UNKNOWN',
|
|
118
|
-
'message': 'npm audit found vulnerabilities (run npm audit for details)'
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
return findings
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def scan_dotnet_vulnerabilities(project_path: str) -> List[Dict[str, str]]:
|
|
125
|
-
"""Scan .NET packages for known vulnerabilities."""
|
|
126
|
-
findings = []
|
|
127
|
-
|
|
128
|
-
# Check if dotnet is available
|
|
129
|
-
code, _ = run_command(["dotnet", "--version"])
|
|
130
|
-
if code != 0:
|
|
131
|
-
return findings
|
|
132
|
-
|
|
133
|
-
# Run dotnet list package --vulnerable
|
|
134
|
-
code, output = run_command(["dotnet", "list", "package", "--vulnerable"], project_path)
|
|
135
|
-
|
|
136
|
-
if code == 0 and output:
|
|
137
|
-
lines = output.split('\n')
|
|
138
|
-
for line in lines:
|
|
139
|
-
if 'vulnerable' in line.lower() or 'severity' in line.lower():
|
|
140
|
-
findings.append({
|
|
141
|
-
'type': 'nuget_vulnerability',
|
|
142
|
-
'file': 'packages',
|
|
143
|
-
'severity': 'MEDIUM',
|
|
144
|
-
'message': line.strip()
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
return findings
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def scan_insecure_patterns(project_path: str) -> List[Dict[str, str]]:
|
|
151
|
-
"""Scan for insecure coding patterns."""
|
|
152
|
-
findings = []
|
|
153
|
-
path = Path(project_path)
|
|
154
|
-
|
|
155
|
-
insecure_patterns = {
|
|
156
|
-
'sql_injection': {
|
|
157
|
-
'pattern': r'(ExecuteRawSql|FromSqlRaw|ExecuteSqlCommand)\s*\([^)]*\+',
|
|
158
|
-
'message': 'Potential SQL injection - avoid string concatenation in SQL queries',
|
|
159
|
-
'severity': 'HIGH'
|
|
160
|
-
},
|
|
161
|
-
'xss': {
|
|
162
|
-
'pattern': r'innerHTML\s*=\s*(?!["\']\s*["\'])',
|
|
163
|
-
'message': 'Potential XSS vulnerability - avoid innerHTML with user input',
|
|
164
|
-
'severity': 'HIGH'
|
|
165
|
-
},
|
|
166
|
-
'weak_crypto': {
|
|
167
|
-
'pattern': r'(MD5|SHA1)\.Create\(',
|
|
168
|
-
'message': 'Weak cryptographic algorithm - use SHA256 or stronger',
|
|
169
|
-
'severity': 'MEDIUM'
|
|
170
|
-
},
|
|
171
|
-
'eval_usage': {
|
|
172
|
-
'pattern': r'\beval\s*\(',
|
|
173
|
-
'message': 'Dangerous eval() usage - avoid evaluating dynamic code',
|
|
174
|
-
'severity': 'HIGH'
|
|
175
|
-
},
|
|
176
|
-
'http_not_https': {
|
|
177
|
-
'pattern': r'http://(?!localhost|127\.0\.0\.1)',
|
|
178
|
-
'message': 'HTTP URL detected - use HTTPS for external resources',
|
|
179
|
-
'severity': 'MEDIUM'
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
extensions = ['.cs', '.ts', '.js', '.vue']
|
|
184
|
-
|
|
185
|
-
for ext in extensions:
|
|
186
|
-
for file_path in path.glob(f"**/*{ext}"):
|
|
187
|
-
if any(skip in str(file_path) for skip in ['node_modules', 'bin', 'obj', '.git']):
|
|
188
|
-
continue
|
|
189
|
-
|
|
190
|
-
try:
|
|
191
|
-
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
|
|
192
|
-
content = f.read()
|
|
193
|
-
|
|
194
|
-
for pattern_name, pattern_info in insecure_patterns.items():
|
|
195
|
-
matches = re.finditer(pattern_info['pattern'], content, re.IGNORECASE)
|
|
196
|
-
for match in matches:
|
|
197
|
-
findings.append({
|
|
198
|
-
'type': pattern_name,
|
|
199
|
-
'file': str(file_path.relative_to(path)),
|
|
200
|
-
'line': content[:match.start()].count('\n') + 1,
|
|
201
|
-
'severity': pattern_info['severity'],
|
|
202
|
-
'message': pattern_info['message']
|
|
203
|
-
})
|
|
204
|
-
except Exception:
|
|
205
|
-
continue
|
|
206
|
-
|
|
207
|
-
return findings
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def check_security_headers(project_path: str) -> List[Dict[str, str]]:
|
|
211
|
-
"""Check for security header configurations."""
|
|
212
|
-
findings = []
|
|
213
|
-
path = Path(project_path)
|
|
214
|
-
|
|
215
|
-
# Check for ASP.NET security configurations
|
|
216
|
-
startup_files = list(path.glob("**/Startup.cs")) + list(path.glob("**/Program.cs"))
|
|
217
|
-
|
|
218
|
-
for startup_file in startup_files:
|
|
219
|
-
try:
|
|
220
|
-
with open(startup_file, 'r', encoding='utf-8') as f:
|
|
221
|
-
content = f.read()
|
|
222
|
-
|
|
223
|
-
# Check for HSTS
|
|
224
|
-
if 'UseHsts' not in content:
|
|
225
|
-
findings.append({
|
|
226
|
-
'type': 'missing_hsts',
|
|
227
|
-
'file': str(startup_file.relative_to(path)),
|
|
228
|
-
'severity': 'MEDIUM',
|
|
229
|
-
'message': 'HSTS not configured - add app.UseHsts()'
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
# Check for HTTPS redirection
|
|
233
|
-
if 'UseHttpsRedirection' not in content:
|
|
234
|
-
findings.append({
|
|
235
|
-
'type': 'missing_https_redirect',
|
|
236
|
-
'file': str(startup_file.relative_to(path)),
|
|
237
|
-
'severity': 'MEDIUM',
|
|
238
|
-
'message': 'HTTPS redirection not configured'
|
|
239
|
-
})
|
|
240
|
-
except Exception:
|
|
241
|
-
continue
|
|
242
|
-
|
|
243
|
-
return findings
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def format_report(all_findings: List[Dict[str, str]], severity_filter: str = None) -> Tuple[str, int]:
|
|
247
|
-
"""Format security scan report."""
|
|
248
|
-
# Filter by severity if specified
|
|
249
|
-
if severity_filter:
|
|
250
|
-
all_findings = [f for f in all_findings if f['severity'] == severity_filter.upper()]
|
|
251
|
-
|
|
252
|
-
# Group by severity
|
|
253
|
-
by_severity = {'HIGH': [], 'MEDIUM': [], 'LOW': [], 'UNKNOWN': []}
|
|
254
|
-
for finding in all_findings:
|
|
255
|
-
severity = finding.get('severity', 'UNKNOWN')
|
|
256
|
-
by_severity[severity].append(finding)
|
|
257
|
-
|
|
258
|
-
report = []
|
|
259
|
-
report.append("=" * 60)
|
|
260
|
-
report.append("🔒 SECURITY SCAN REPORT")
|
|
261
|
-
report.append("=" * 60)
|
|
262
|
-
|
|
263
|
-
report.append("")
|
|
264
|
-
report.append("📊 Summary:")
|
|
265
|
-
report.append(f" Total findings: {len(all_findings)}")
|
|
266
|
-
report.append(f" HIGH: {len(by_severity['HIGH'])} 🔴")
|
|
267
|
-
report.append(f" MEDIUM: {len(by_severity['MEDIUM'])} 🟡")
|
|
268
|
-
report.append(f" LOW: {len(by_severity['LOW'])} 🟢")
|
|
269
|
-
|
|
270
|
-
# Report HIGH severity issues
|
|
271
|
-
if by_severity['HIGH']:
|
|
272
|
-
report.append("")
|
|
273
|
-
report.append("🔴 HIGH Severity Issues:")
|
|
274
|
-
for finding in by_severity['HIGH'][:15]:
|
|
275
|
-
report.append(f" • {finding['file']}:{finding.get('line', '?')}")
|
|
276
|
-
report.append(f" {finding['message']}")
|
|
277
|
-
if len(by_severity['HIGH']) > 15:
|
|
278
|
-
report.append(f" ... and {len(by_severity['HIGH']) - 15} more")
|
|
279
|
-
|
|
280
|
-
# Report MEDIUM severity issues
|
|
281
|
-
if by_severity['MEDIUM']:
|
|
282
|
-
report.append("")
|
|
283
|
-
report.append("🟡 MEDIUM Severity Issues:")
|
|
284
|
-
for finding in by_severity['MEDIUM'][:10]:
|
|
285
|
-
report.append(f" • {finding['file']}:{finding.get('line', '?')}")
|
|
286
|
-
report.append(f" {finding['message']}")
|
|
287
|
-
if len(by_severity['MEDIUM']) > 10:
|
|
288
|
-
report.append(f" ... and {len(by_severity['MEDIUM']) - 10} more")
|
|
289
|
-
|
|
290
|
-
report.append("")
|
|
291
|
-
report.append("=" * 60)
|
|
292
|
-
|
|
293
|
-
# Determine exit code
|
|
294
|
-
if by_severity['HIGH']:
|
|
295
|
-
report.append("❌ Security scan failed - HIGH severity issues found")
|
|
296
|
-
return "\n".join(report), 1
|
|
297
|
-
elif by_severity['MEDIUM']:
|
|
298
|
-
report.append("⚠️ Security scan completed with warnings")
|
|
299
|
-
return "\n".join(report), 0
|
|
300
|
-
else:
|
|
301
|
-
report.append("✅ No security issues found")
|
|
302
|
-
return "\n".join(report), 0
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def main():
|
|
306
|
-
if len(sys.argv) < 2:
|
|
307
|
-
print("Usage: python security_scan.py <project_path> [--severity high|medium|low]")
|
|
308
|
-
sys.exit(1)
|
|
309
|
-
|
|
310
|
-
project_path = sys.argv[1]
|
|
311
|
-
severity_filter = None
|
|
312
|
-
|
|
313
|
-
if "--severity" in sys.argv:
|
|
314
|
-
sev_index = sys.argv.index("--severity") + 1
|
|
315
|
-
if sev_index < len(sys.argv):
|
|
316
|
-
severity_filter = sys.argv[sev_index]
|
|
317
|
-
|
|
318
|
-
print("🔒 Security Scanner")
|
|
319
|
-
print("=" * 60)
|
|
320
|
-
print(f"Project: {project_path}")
|
|
321
|
-
if severity_filter:
|
|
322
|
-
print(f"Severity filter: {severity_filter.upper()}")
|
|
323
|
-
print()
|
|
324
|
-
|
|
325
|
-
all_findings = []
|
|
326
|
-
|
|
327
|
-
# Run scans
|
|
328
|
-
print("Scanning for hardcoded secrets...")
|
|
329
|
-
all_findings.extend(scan_hardcoded_secrets(project_path))
|
|
330
|
-
|
|
331
|
-
print("Scanning npm vulnerabilities...")
|
|
332
|
-
all_findings.extend(scan_npm_vulnerabilities(project_path))
|
|
333
|
-
|
|
334
|
-
print("Scanning .NET vulnerabilities...")
|
|
335
|
-
all_findings.extend(scan_dotnet_vulnerabilities(project_path))
|
|
336
|
-
|
|
337
|
-
print("Scanning for insecure patterns...")
|
|
338
|
-
all_findings.extend(scan_insecure_patterns(project_path))
|
|
339
|
-
|
|
340
|
-
print("Checking security headers...")
|
|
341
|
-
all_findings.extend(check_security_headers(project_path))
|
|
342
|
-
|
|
343
|
-
print()
|
|
344
|
-
print("-" * 60)
|
|
345
|
-
|
|
346
|
-
# Generate and print report
|
|
347
|
-
report, exit_code = format_report(all_findings, severity_filter)
|
|
348
|
-
print(report)
|
|
349
|
-
|
|
350
|
-
sys.exit(exit_code)
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if __name__ == "__main__":
|
|
354
|
-
main()
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Verify All - Comprehensive project verification
|
|
4
|
-
Run before deployment or releases.
|
|
5
|
-
|
|
6
|
-
Usage:
|
|
7
|
-
python .agent-antigravity/scripts/verify_all.py .
|
|
8
|
-
python .agent-antigravity/scripts/verify_all.py . --url http://localhost:3000
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import subprocess
|
|
12
|
-
import sys
|
|
13
|
-
import os
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
from datetime import datetime
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def run_command(cmd: list[str], cwd: str = ".") -> tuple[int, str]:
|
|
19
|
-
"""Run a command and return exit code and output."""
|
|
20
|
-
try:
|
|
21
|
-
result = subprocess.run(
|
|
22
|
-
cmd,
|
|
23
|
-
cwd=cwd,
|
|
24
|
-
capture_output=True,
|
|
25
|
-
text=True,
|
|
26
|
-
timeout=600
|
|
27
|
-
)
|
|
28
|
-
return result.returncode, result.stdout + result.stderr
|
|
29
|
-
except subprocess.TimeoutExpired:
|
|
30
|
-
return 1, "Command timed out"
|
|
31
|
-
except FileNotFoundError:
|
|
32
|
-
return 1, f"Command not found: {cmd[0]}"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class Verifier:
|
|
36
|
-
def __init__(self, project_path: str, url: str = None):
|
|
37
|
-
self.project_path = project_path
|
|
38
|
-
self.url = url
|
|
39
|
-
self.results = []
|
|
40
|
-
|
|
41
|
-
def add_result(self, category: str, name: str, passed: bool, details: str = ""):
|
|
42
|
-
self.results.append({
|
|
43
|
-
"category": category,
|
|
44
|
-
"name": name,
|
|
45
|
-
"passed": passed,
|
|
46
|
-
"details": details
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
def run_all(self):
|
|
50
|
-
"""Run all verification checks."""
|
|
51
|
-
print("=" * 70)
|
|
52
|
-
print("COMPREHENSIVE PROJECT VERIFICATION")
|
|
53
|
-
print(f"Started: {datetime.now().isoformat()}")
|
|
54
|
-
print("=" * 70)
|
|
55
|
-
|
|
56
|
-
self.verify_security()
|
|
57
|
-
self.verify_code_quality()
|
|
58
|
-
self.verify_tests()
|
|
59
|
-
self.verify_build()
|
|
60
|
-
self.verify_dependencies()
|
|
61
|
-
|
|
62
|
-
if self.url:
|
|
63
|
-
self.verify_runtime(self.url)
|
|
64
|
-
|
|
65
|
-
self.print_summary()
|
|
66
|
-
|
|
67
|
-
def verify_security(self):
|
|
68
|
-
"""Security verification."""
|
|
69
|
-
print("\n[SECURITY]")
|
|
70
|
-
|
|
71
|
-
# Check for secrets
|
|
72
|
-
secret_patterns = [
|
|
73
|
-
("password", "password="),
|
|
74
|
-
("api_key", "apikey="),
|
|
75
|
-
("secret", "secret="),
|
|
76
|
-
("connection_string", "connectionstring="),
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
for name, pattern in secret_patterns:
|
|
80
|
-
code, output = run_command(
|
|
81
|
-
["grep", "-ri", pattern, "--include=*.cs", "--include=*.ts"],
|
|
82
|
-
self.project_path
|
|
83
|
-
)
|
|
84
|
-
passed = code != 0 or not output.strip()
|
|
85
|
-
self.add_result("Security", f"No hardcoded {name}", passed)
|
|
86
|
-
print(f" {'✅' if passed else '❌'} No hardcoded {name}")
|
|
87
|
-
|
|
88
|
-
# npm audit
|
|
89
|
-
package_json = Path(self.project_path) / "package.json"
|
|
90
|
-
if package_json.exists():
|
|
91
|
-
code, output = run_command(["npm", "audit", "--audit-level=critical"], self.project_path)
|
|
92
|
-
passed = code == 0
|
|
93
|
-
self.add_result("Security", "npm audit (critical)", passed, output[:200])
|
|
94
|
-
print(f" {'✅' if passed else '❌'} npm audit (critical)")
|
|
95
|
-
|
|
96
|
-
def verify_code_quality(self):
|
|
97
|
-
"""Code quality verification."""
|
|
98
|
-
print("\n[CODE QUALITY]")
|
|
99
|
-
|
|
100
|
-
# Frontend lint
|
|
101
|
-
package_json = Path(self.project_path) / "package.json"
|
|
102
|
-
if package_json.exists():
|
|
103
|
-
code, output = run_command(["npm", "run", "lint"], self.project_path)
|
|
104
|
-
passed = code == 0
|
|
105
|
-
self.add_result("Code Quality", "Frontend lint", passed)
|
|
106
|
-
print(f" {'✅' if passed else '❌'} Frontend lint")
|
|
107
|
-
|
|
108
|
-
# TypeScript
|
|
109
|
-
code, output = run_command(["npx", "tsc", "--noEmit"], self.project_path)
|
|
110
|
-
passed = code == 0
|
|
111
|
-
self.add_result("Code Quality", "TypeScript check", passed)
|
|
112
|
-
print(f" {'✅' if passed else '❌'} TypeScript check")
|
|
113
|
-
|
|
114
|
-
# Backend lint (if applicable)
|
|
115
|
-
csproj_files = list(Path(self.project_path).glob("**/*.csproj"))
|
|
116
|
-
if csproj_files:
|
|
117
|
-
code, output = run_command(["dotnet", "format", "--verify-no-changes"], self.project_path)
|
|
118
|
-
passed = code == 0
|
|
119
|
-
self.add_result("Code Quality", "C# formatting", passed)
|
|
120
|
-
print(f" {'✅' if passed else '❌'} C# formatting")
|
|
121
|
-
|
|
122
|
-
def verify_tests(self):
|
|
123
|
-
"""Test verification."""
|
|
124
|
-
print("\n[TESTS]")
|
|
125
|
-
|
|
126
|
-
# Frontend tests
|
|
127
|
-
package_json = Path(self.project_path) / "package.json"
|
|
128
|
-
if package_json.exists():
|
|
129
|
-
code, output = run_command(["npm", "run", "test", "--", "--run"], self.project_path)
|
|
130
|
-
passed = code == 0
|
|
131
|
-
self.add_result("Tests", "Frontend tests", passed)
|
|
132
|
-
print(f" {'✅' if passed else '❌'} Frontend tests")
|
|
133
|
-
|
|
134
|
-
# Backend tests
|
|
135
|
-
sln_files = list(Path(self.project_path).glob("*.sln"))
|
|
136
|
-
if sln_files:
|
|
137
|
-
code, output = run_command(["dotnet", "test"], self.project_path)
|
|
138
|
-
passed = code == 0
|
|
139
|
-
self.add_result("Tests", "Backend tests", passed)
|
|
140
|
-
print(f" {'✅' if passed else '❌'} Backend tests")
|
|
141
|
-
|
|
142
|
-
def verify_build(self):
|
|
143
|
-
"""Build verification."""
|
|
144
|
-
print("\n[BUILD]")
|
|
145
|
-
|
|
146
|
-
# Frontend build
|
|
147
|
-
package_json = Path(self.project_path) / "package.json"
|
|
148
|
-
if package_json.exists():
|
|
149
|
-
code, output = run_command(["npm", "run", "build"], self.project_path)
|
|
150
|
-
passed = code == 0
|
|
151
|
-
self.add_result("Build", "Frontend build", passed)
|
|
152
|
-
print(f" {'✅' if passed else '❌'} Frontend build")
|
|
153
|
-
|
|
154
|
-
# Backend build
|
|
155
|
-
sln_files = list(Path(self.project_path).glob("*.sln"))
|
|
156
|
-
if sln_files:
|
|
157
|
-
code, output = run_command(["dotnet", "build", "-c", "Release"], self.project_path)
|
|
158
|
-
passed = code == 0
|
|
159
|
-
self.add_result("Build", "Backend build", passed)
|
|
160
|
-
print(f" {'✅' if passed else '❌'} Backend build")
|
|
161
|
-
|
|
162
|
-
def verify_dependencies(self):
|
|
163
|
-
"""Dependency verification."""
|
|
164
|
-
print("\n[DEPENDENCIES]")
|
|
165
|
-
|
|
166
|
-
# npm outdated
|
|
167
|
-
package_json = Path(self.project_path) / "package.json"
|
|
168
|
-
if package_json.exists():
|
|
169
|
-
code, output = run_command(["npm", "outdated"], self.project_path)
|
|
170
|
-
# outdated returns 1 if there are outdated packages
|
|
171
|
-
self.add_result("Dependencies", "npm packages", True, "Check npm outdated for details")
|
|
172
|
-
print(f" ℹ️ npm outdated check complete")
|
|
173
|
-
|
|
174
|
-
# dotnet outdated (if tool installed)
|
|
175
|
-
sln_files = list(Path(self.project_path).glob("*.sln"))
|
|
176
|
-
if sln_files:
|
|
177
|
-
code, output = run_command(["dotnet", "list", "package", "--outdated"], self.project_path)
|
|
178
|
-
self.add_result("Dependencies", "NuGet packages", True, "Check dotnet list package for details")
|
|
179
|
-
print(f" ℹ️ NuGet outdated check complete")
|
|
180
|
-
|
|
181
|
-
def verify_runtime(self, url: str):
|
|
182
|
-
"""Runtime verification (if URL provided)."""
|
|
183
|
-
print("\n[RUNTIME]")
|
|
184
|
-
|
|
185
|
-
# Health check
|
|
186
|
-
code, output = run_command(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", f"{url}/health"])
|
|
187
|
-
passed = output.strip() == "200"
|
|
188
|
-
self.add_result("Runtime", "Health check", passed)
|
|
189
|
-
print(f" {'✅' if passed else '❌'} Health check")
|
|
190
|
-
|
|
191
|
-
def print_summary(self):
|
|
192
|
-
"""Print verification summary."""
|
|
193
|
-
print("\n" + "=" * 70)
|
|
194
|
-
print("VERIFICATION SUMMARY")
|
|
195
|
-
print("=" * 70)
|
|
196
|
-
|
|
197
|
-
categories = {}
|
|
198
|
-
for r in self.results:
|
|
199
|
-
cat = r["category"]
|
|
200
|
-
if cat not in categories:
|
|
201
|
-
categories[cat] = []
|
|
202
|
-
categories[cat].append(r)
|
|
203
|
-
|
|
204
|
-
total_passed = 0
|
|
205
|
-
total_count = 0
|
|
206
|
-
|
|
207
|
-
for cat, items in categories.items():
|
|
208
|
-
print(f"\n{cat}:")
|
|
209
|
-
for item in items:
|
|
210
|
-
status = "✅" if item["passed"] else "❌"
|
|
211
|
-
print(f" {status} {item['name']}")
|
|
212
|
-
total_count += 1
|
|
213
|
-
if item["passed"]:
|
|
214
|
-
total_passed += 1
|
|
215
|
-
|
|
216
|
-
print("\n" + "-" * 70)
|
|
217
|
-
print(f"Total: {total_passed}/{total_count} checks passed")
|
|
218
|
-
|
|
219
|
-
if total_passed < total_count:
|
|
220
|
-
print("\n❌ Some checks failed. Review and fix before deployment.")
|
|
221
|
-
sys.exit(1)
|
|
222
|
-
else:
|
|
223
|
-
print("\n✅ All checks passed! Ready for deployment.")
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
def main():
|
|
227
|
-
if len(sys.argv) < 2:
|
|
228
|
-
print("Usage: python verify_all.py <project_path> [--url <url>]")
|
|
229
|
-
sys.exit(1)
|
|
230
|
-
|
|
231
|
-
project_path = sys.argv[1]
|
|
232
|
-
url = None
|
|
233
|
-
if "--url" in sys.argv:
|
|
234
|
-
url_index = sys.argv.index("--url") + 1
|
|
235
|
-
if url_index < len(sys.argv):
|
|
236
|
-
url = sys.argv[url_index]
|
|
237
|
-
|
|
238
|
-
verifier = Verifier(project_path, url)
|
|
239
|
-
verifier.run_all()
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if __name__ == "__main__":
|
|
243
|
-
main()
|