mirror of
https://github.com/hanzoai/bot.git
synced 2026-10-30 17:24:26 +00:00
Merged 3580 upstream commits from openclaw/main through a bridge branch that applied the openclaw→hanzo-bot rebrand before merging. Key upstream additions: - Android device diagnostics and notification actions - Device-auth v2 migration improvements - Docker CLI packaging fixes - Ollama discovery log demotion - Channel health monitoring - Slack native streaming - Linq iMessage channel - Gemini OAuth and FTS improvements - Inbound sender metadata - Daemon PATH improvements - Canvas host and onboarding enhancements - Security hardening (session files, exec allowlist)
69 lines
2.7 KiB
Swift
69 lines
2.7 KiB
Swift
import Foundation
|
|
|
|
struct ExecApprovalEvaluation {
|
|
let command: [String]
|
|
let displayCommand: String
|
|
let agentId: String?
|
|
let security: ExecSecurity
|
|
let ask: ExecAsk
|
|
let env: [String: String]
|
|
let resolution: ExecCommandResolution?
|
|
let allowlistResolutions: [ExecCommandResolution]
|
|
let allowlistMatches: [ExecAllowlistEntry]
|
|
let allowlistSatisfied: Bool
|
|
let allowlistMatch: ExecAllowlistEntry?
|
|
let skillAllow: Bool
|
|
}
|
|
|
|
enum ExecApprovalEvaluator {
|
|
static func evaluate(
|
|
command: [String],
|
|
rawCommand: String?,
|
|
cwd: String?,
|
|
envOverrides: [String: String]?,
|
|
agentId: String?) async -> ExecApprovalEvaluation
|
|
{
|
|
let trimmedAgent = agentId?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let normalizedAgentId = (trimmedAgent?.isEmpty == false) ? trimmedAgent : nil
|
|
let approvals = ExecApprovalsStore.resolve(agentId: normalizedAgentId)
|
|
let security = approvals.agent.security
|
|
let ask = approvals.agent.ask
|
|
let shellWrapper = ExecShellWrapperParser.extract(command: command, rawCommand: rawCommand).isWrapper
|
|
let env = HostEnvSanitizer.sanitize(overrides: envOverrides, shellWrapper: shellWrapper)
|
|
let displayCommand = ExecCommandFormatter.displayString(for: command, rawCommand: rawCommand)
|
|
let allowlistResolutions = ExecCommandResolution.resolveForAllowlist(
|
|
command: command,
|
|
rawCommand: rawCommand,
|
|
cwd: cwd,
|
|
env: env)
|
|
let allowlistMatches = security == .allowlist
|
|
? ExecAllowlistMatcher.matchAll(entries: approvals.allowlist, resolutions: allowlistResolutions)
|
|
: []
|
|
let allowlistSatisfied = security == .allowlist &&
|
|
!allowlistResolutions.isEmpty &&
|
|
allowlistMatches.count == allowlistResolutions.count
|
|
|
|
let skillAllow: Bool
|
|
if approvals.agent.autoAllowSkills, !allowlistResolutions.isEmpty {
|
|
let bins = await SkillBinsCache.shared.currentBins()
|
|
skillAllow = allowlistResolutions.allSatisfy { bins.contains($0.executableName) }
|
|
} else {
|
|
skillAllow = false
|
|
}
|
|
|
|
return ExecApprovalEvaluation(
|
|
command: command,
|
|
displayCommand: displayCommand,
|
|
agentId: normalizedAgentId,
|
|
security: security,
|
|
ask: ask,
|
|
env: env,
|
|
resolution: allowlistResolutions.first,
|
|
allowlistResolutions: allowlistResolutions,
|
|
allowlistMatches: allowlistMatches,
|
|
allowlistSatisfied: allowlistSatisfied,
|
|
allowlistMatch: allowlistSatisfied ? allowlistMatches.first : nil,
|
|
skillAllow: skillAllow)
|
|
}
|
|
}
|