computeRiskLevel function

Compute risk level from analysis.

Implementation

SecurityRiskLevel computeRiskLevel(CommandSecurityAnalysis a) {
  // Critical: sudo + remove, eval with substitution, fork bombs.
  if (a.hasSudo && a.hasRemove) return SecurityRiskLevel.critical;
  if (a.hasEval && a.hasCommandSubstitution) return SecurityRiskLevel.critical;
  if (a.hasSudo && a.hasChown) return SecurityRiskLevel.critical;

  // High: sudo, eval, exec, remove with glob.
  if (a.hasSudo) return SecurityRiskLevel.high;
  if (a.hasEval) return SecurityRiskLevel.high;
  if (a.hasExec) return SecurityRiskLevel.high;
  if (a.hasRemove && a.hasGlobbing) return SecurityRiskLevel.high;
  if (a.hasRemove &&
      a.writtenPaths.any((p) => p == '/' || p == '~' || p.startsWith('/'))) {
    return SecurityRiskLevel.high;
  }

  // Medium: network access, disk writes with variable expansion, command
  // substitution, remove.
  if (a.hasNetworkAccess) return SecurityRiskLevel.medium;
  if (a.hasDiskWrite && a.hasVariableExpansion) return SecurityRiskLevel.medium;
  if (a.hasCommandSubstitution) return SecurityRiskLevel.medium;
  if (a.hasRemove) return SecurityRiskLevel.medium;
  if (a.hasChown) return SecurityRiskLevel.medium;

  // Low: disk writes, redirections, backgrounding, piping.
  if (a.hasDiskWrite) return SecurityRiskLevel.low;
  if (a.hasRedirection) return SecurityRiskLevel.low;
  if (a.hasBackgroundExec) return SecurityRiskLevel.low;
  if (a.hasSubshell) return SecurityRiskLevel.low;

  // Safe: read-only commands, piping between safe commands.
  if (a.hasPiping) return SecurityRiskLevel.low;
  if (a.hasGlobbing) return SecurityRiskLevel.low;

  return SecurityRiskLevel.safe;
}