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:
copilot-swe-agent[bot] 2026-03-24 14:34:06 +00:00
parent cfb2b68db1
commit 6625071a10
4 changed files with 26 additions and 8 deletions

View File

@ -48,9 +48,13 @@ function sense() {
// Check last scan freshness (48h threshold)
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));
if (hours > 48) {
if (!isNaN(lastScanTime) && hours > 48) {
result.issues.push(`infra-manifest 最后扫描距今 ${hours}h超过 48h 阈值`);
}
}
@ -125,7 +129,7 @@ function auditQuotas() {
if (ledger.services) {
for (const [name, data] of Object.entries(ledger.services)) {
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;
}

View File

@ -69,9 +69,14 @@ function checkGuardHealth(filePath) {
// Check 5: Last heartbeat freshness (if available)
if (guard.health_check?.last_check) {
const lastCheckAge = Date.now() - new Date(guard.health_check.last_check).getTime();
const intervalMs = (guard.health_check.interval_hours || 6) * 60 * 60 * 1000;
result.checks.heartbeat_fresh = lastCheckAge < intervalMs * 3; // 3x tolerance
const lastCheckTime = new Date(guard.health_check.last_check).getTime();
if (!isNaN(lastCheckTime)) {
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 {
result.checks.heartbeat_fresh = null; // No heartbeat recorded yet
}

View File

@ -48,7 +48,7 @@ function auditService(name, data) {
actions: []
};
if (data.limit && data.used !== undefined) {
if (data.limit && data.used !== undefined && data.used !== null) {
result.usage_percent = data.limit > 0
? Math.round((data.used / data.limit) * 100 * 10) / 10
: 0;

View File

@ -47,8 +47,17 @@ function runPhase(name, scriptPath) {
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 {
result.output = execSync(`node "${scriptPath}"`, {
result.output = execSync(`node "${resolvedScript}"`, {
cwd: path.resolve(SKYEYE_DIR, '..'),
encoding: 'utf8',
timeout: 60000,