import Foundation import Testing @testable import OpenClaw struct ExecSkillBinTrustTests { @Test func `build trust index resolves skill bin paths`() throws { let fixture = try Self.makeExecutable(named: "jq") defer { try? FileManager.default.removeItem(at: fixture.root) } let trust = SkillBinsCache._testBuildTrustIndex( report: Self.makeReport(bins: ["jq"]), searchPaths: [fixture.root.path]) #expect(trust.names == ["jq"]) #expect(trust.pathsByName["jq"] == [fixture.path]) } @Test func `skill auto allow accepts trusted resolved skill bin path`() throws { let fixture = try Self.makeExecutable(named: "jq") defer { try? FileManager.default.removeItem(at: fixture.root) } let trust = SkillBinsCache._testBuildTrustIndex( report: Self.makeReport(bins: ["jq"]), searchPaths: [fixture.root.path]) let resolution = ExecCommandResolution( rawExecutable: "jq", resolvedPath: fixture.path, executableName: "jq", cwd: nil) #expect(ExecApprovalEvaluator._testIsSkillAutoAllowed([resolution], trustedBinsByName: trust.pathsByName)) } @Test func `skill auto allow rejects same basename at different path`() throws { let trusted = try Self.makeExecutable(named: "jq") let untrusted = try Self.makeExecutable(named: "jq") defer { try? FileManager.default.removeItem(at: trusted.root) try? FileManager.default.removeItem(at: untrusted.root) } let trust = SkillBinsCache._testBuildTrustIndex( report: Self.makeReport(bins: ["jq"]), searchPaths: [trusted.root.path]) let resolution = ExecCommandResolution( rawExecutable: "jq", resolvedPath: untrusted.path, executableName: "jq", cwd: nil) #expect(!ExecApprovalEvaluator._testIsSkillAutoAllowed([resolution], trustedBinsByName: trust.pathsByName)) } private static func makeExecutable(named name: String) throws -> (root: URL, path: String) { let root = FileManager.default.temporaryDirectory .appendingPathComponent("openclaw-skill-bin-\(UUID().uuidString)", isDirectory: true) try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) let file = root.appendingPathComponent(name) try "#!/bin/sh\nexit 0\n".write(to: file, atomically: true, encoding: .utf8) try FileManager.default.setAttributes( [.posixPermissions: NSNumber(value: Int16(0o755))], ofItemAtPath: file.path) return (root, file.path) } private static func makeReport(bins: [String]) -> SkillsStatusReport { SkillsStatusReport( workspaceDir: "/tmp/workspace", managedSkillsDir: "/tmp/skills", skills: [ SkillStatus( name: "test-skill", description: "test", source: "local", filePath: "/tmp/skills/test-skill/SKILL.md", baseDir: "/tmp/skills/test-skill", skillKey: "test-skill", primaryEnv: nil, emoji: nil, homepage: nil, always: false, disabled: false, eligible: true, requirements: SkillRequirements(bins: bins, env: [], config: []), missing: SkillMissing(bins: [], env: [], config: []), configChecks: [], install: []) ]) } }