RuntimeVerifierTests.swift
97 lines 4.7 KB
Raw
sha256:bd1eb24434d281fe65142038c1bf217493421f5a86880c22dff7e6037d2d4700 feat(companion): add production macOS distribution path Human minor ⚠ breaking 25 days ago
1 import CryptoKit
2 import Foundation
3 import XCTest
4 @testable import KnowtationSecurity
5
6 final class RuntimeVerifierTests: XCTestCase {
7 func testVerifiesExactRegularFile() throws {
8 let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
9 try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
10 defer { try? FileManager.default.removeItem(at: root) }
11 let file = root.appendingPathComponent("runtime/file.txt")
12 try FileManager.default.createDirectory(at: file.deletingLastPathComponent(), withIntermediateDirectories: true)
13 let data = Data("known payload".utf8)
14 try data.write(to: file)
15 let digest = SHA256.hash(data: data).map { String(format: "%02x", $0) }.joined()
16 let manifest = RuntimeManifest(
17 schema: 1,
18 releaseVersion: KnowtationReleaseContract.version,
19 releaseBuild: KnowtationReleaseContract.build,
20 architecture: KnowtationReleaseContract.architecture,
21 files: [.init(path: "runtime/file.txt", sha256: digest, bytes: UInt64(data.count), executable: false)]
22 )
23 XCTAssertNoThrow(try RuntimeVerifier.verifyTree(root: root, manifest: manifest))
24 }
25
26 func testRejectsDigestSubstitution() throws {
27 let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
28 try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
29 defer { try? FileManager.default.removeItem(at: root) }
30 let file = root.appendingPathComponent("file.txt")
31 try Data("substituted".utf8).write(to: file)
32 let manifest = RuntimeManifest(
33 schema: 1,
34 releaseVersion: KnowtationReleaseContract.version,
35 releaseBuild: KnowtationReleaseContract.build,
36 architecture: KnowtationReleaseContract.architecture,
37 files: [.init(path: "file.txt", sha256: String(repeating: "0", count: 64), bytes: 11, executable: false)]
38 )
39 XCTAssertThrowsError(try RuntimeVerifier.verifyTree(root: root, manifest: manifest))
40 }
41
42 func testRejectsTraversalPath() throws {
43 let manifest = RuntimeManifest(
44 schema: 1,
45 releaseVersion: KnowtationReleaseContract.version,
46 releaseBuild: KnowtationReleaseContract.build,
47 architecture: KnowtationReleaseContract.architecture,
48 files: [.init(path: "../escape", sha256: String(repeating: "0", count: 64), bytes: 0, executable: false)]
49 )
50 XCTAssertThrowsError(try RuntimeVerifier.verifyTree(root: FileManager.default.temporaryDirectory, manifest: manifest)) {
51 XCTAssertEqual($0 as? RuntimeVerificationError, .invalidPath("../escape"))
52 }
53 }
54
55 func testRejectsUnmanifestedFile() throws {
56 let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
57 try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true)
58 defer { try? FileManager.default.removeItem(at: root) }
59 let expectedData = Data()
60 try expectedData.write(to: root.appendingPathComponent("expected.txt"))
61 try Data("unexpected".utf8).write(to: root.appendingPathComponent("substitution.txt"))
62 let manifest = RuntimeManifest(
63 schema: 1,
64 releaseVersion: KnowtationReleaseContract.version,
65 releaseBuild: KnowtationReleaseContract.build,
66 architecture: KnowtationReleaseContract.architecture,
67 files: [.init(
68 path: "expected.txt",
69 sha256: SHA256.hash(data: expectedData).map { String(format: "%02x", $0) }.joined(),
70 bytes: 0,
71 executable: false
72 )]
73 )
74 XCTAssertThrowsError(try RuntimeVerifier.verifyTree(root: root, manifest: manifest)) {
75 XCTAssertEqual($0 as? RuntimeVerificationError, .extraFile("substitution.txt"))
76 }
77 }
78
79 func testRejectsDuplicateManifestEntry() throws {
80 let entry = RuntimeManifest.Entry(
81 path: "file.txt",
82 sha256: String(repeating: "0", count: 64),
83 bytes: 0,
84 executable: false
85 )
86 let manifest = RuntimeManifest(
87 schema: 1,
88 releaseVersion: KnowtationReleaseContract.version,
89 releaseBuild: KnowtationReleaseContract.build,
90 architecture: KnowtationReleaseContract.architecture,
91 files: [entry, entry]
92 )
93 XCTAssertThrowsError(try RuntimeVerifier.verifyTree(root: FileManager.default.temporaryDirectory, manifest: manifest)) {
94 XCTAssertEqual($0 as? RuntimeVerificationError, .duplicateEntry("file.txt"))
95 }
96 }
97 }
File History 1 commit
sha256:bd1eb24434d281fe65142038c1bf217493421f5a86880c22dff7e6037d2d4700 feat(companion): add production macOS distribution path Human minor ⚠ 25 days ago