fix: address code review feedback — input validation + date parsing safety
- daily-scan.js: validate date in manifest.last_scan, fix data.used=0 falsy check - quota-audit.js: explicit null check for data.used - guard-health.js: validate date in health_check.last_check - weekly-full.js: path traversal guard for scriptPath Co-authored-by: qinfendebingshuo <207279273+qinfendebingshuo@users.noreply.github.com> Agent-Logs-Url: https://github.com/qinfendebingshuo/guanghulab/sessions/ed7579c8-d43e-4a14-bd91-b3ef6bc314ec
This commit is contained in:
parent
cfb2b68db1
commit
6625071a10
|
|
@ -48,9 +48,13 @@ function sense() {
|
||||||
|
|
||||||
// Check last scan freshness (48h threshold)
|
// Check last scan freshness (48h threshold)
|
||||||
if (manifest.last_scan) {
|
if (manifest.last_scan) {
|
||||||
const lastScanAge = Date.now() - new Date(manifest.last_scan).getTime();
|
const lastScanTime = new Date(manifest.last_scan).getTime();
|
||||||
|
if (isNaN(lastScanTime)) {
|
||||||
|
result.issues.push('infra-manifest.last_scan 日期格式无效');
|
||||||
|
}
|
||||||
|
const lastScanAge = isNaN(lastScanTime) ? 0 : Date.now() - lastScanTime;
|
||||||
const hours = Math.round(lastScanAge / (1000 * 60 * 60));
|
const hours = Math.round(lastScanAge / (1000 * 60 * 60));
|
||||||
if (hours > 48) {
|
if (!isNaN(lastScanTime) && hours > 48) {
|
||||||
result.issues.push(`infra-manifest 最后扫描距今 ${hours}h,超过 48h 阈值`);
|
result.issues.push(`infra-manifest 最后扫描距今 ${hours}h,超过 48h 阈值`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +129,7 @@ function auditQuotas() {
|
||||||
if (ledger.services) {
|
if (ledger.services) {
|
||||||
for (const [name, data] of Object.entries(ledger.services)) {
|
for (const [name, data] of Object.entries(ledger.services)) {
|
||||||
let usagePct = 0;
|
let usagePct = 0;
|
||||||
if (data.limit && data.used) {
|
if (data.limit && data.used !== undefined && data.used !== null) {
|
||||||
usagePct = Math.round((data.used / data.limit) * 100 * 10) / 10;
|
usagePct = Math.round((data.used / data.limit) * 100 * 10) / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,14 @@ function checkGuardHealth(filePath) {
|
||||||
|
|
||||||
// Check 5: Last heartbeat freshness (if available)
|
// Check 5: Last heartbeat freshness (if available)
|
||||||
if (guard.health_check?.last_check) {
|
if (guard.health_check?.last_check) {
|
||||||
const lastCheckAge = Date.now() - new Date(guard.health_check.last_check).getTime();
|
const lastCheckTime = new Date(guard.health_check.last_check).getTime();
|
||||||
const intervalMs = (guard.health_check.interval_hours || 6) * 60 * 60 * 1000;
|
if (!isNaN(lastCheckTime)) {
|
||||||
result.checks.heartbeat_fresh = lastCheckAge < intervalMs * 3; // 3x tolerance
|
const lastCheckAge = Date.now() - lastCheckTime;
|
||||||
|
const intervalMs = (guard.health_check.interval_hours || 6) * 60 * 60 * 1000;
|
||||||
|
result.checks.heartbeat_fresh = lastCheckAge < intervalMs * 3; // 3x tolerance
|
||||||
|
} else {
|
||||||
|
result.checks.heartbeat_fresh = null; // Invalid date
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result.checks.heartbeat_fresh = null; // No heartbeat recorded yet
|
result.checks.heartbeat_fresh = null; // No heartbeat recorded yet
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ function auditService(name, data) {
|
||||||
actions: []
|
actions: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data.limit && data.used !== undefined) {
|
if (data.limit && data.used !== undefined && data.used !== null) {
|
||||||
result.usage_percent = data.limit > 0
|
result.usage_percent = data.limit > 0
|
||||||
? Math.round((data.used / data.limit) * 100 * 10) / 10
|
? Math.round((data.used / data.limit) * 100 * 10) / 10
|
||||||
: 0;
|
: 0;
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,17 @@ function runPhase(name, scriptPath) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate scriptPath is within expected directory
|
||||||
|
const resolvedScript = path.resolve(scriptPath);
|
||||||
|
const resolvedScriptsDir = path.resolve(SCRIPTS_DIR);
|
||||||
|
if (!resolvedScript.startsWith(resolvedScriptsDir)) {
|
||||||
|
result.status = 'error';
|
||||||
|
result.error = `Script path outside expected directory: ${scriptPath}`;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result.output = execSync(`node "${scriptPath}"`, {
|
result.output = execSync(`node "${resolvedScript}"`, {
|
||||||
cwd: path.resolve(SKYEYE_DIR, '..'),
|
cwd: path.resolve(SKYEYE_DIR, '..'),
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue