Buckets:
localhost1978/localhost / LOCALHOST1978 /SSK_DocGen /Tests /SSK_DocGenTests /ACPResourceReadTests.swift
| import Foundation | |
| import Testing | |
| @testable import SSK_DocGen | |
| #if canImport(Darwin) | |
| import Darwin | |
| #endif | |
| ("ACP resource reads") | |
| struct ACPResourceReadTests { | |
| ("An allowlisted resource returns bounded and redacted content") | |
| func allowlistedResourceIsRead() async throws { | |
| let workspace = try makeTemporaryDirectory() | |
| defer { try? FileManager.default.removeItem(at: workspace) } | |
| let context = try ACPRequestContext(workspaceURL: workspace) | |
| let reader = RecordingResourceReader(contents: [ | |
| .doccIndex: "{\"file\":\"/private/example/Secret.swift\"}" | |
| ]) | |
| let service = ACPService(context: context, resourceReader: reader) | |
| let response = try await decodedResponse( | |
| service, | |
| line: "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"resources/read\",\"params\":{\"uri\":\"file:///SSK_Ledger_Vault/docc_index.json\"}}" | |
| ) | |
| let result = try #require(response["result"] as? [String: Any]) | |
| let contents = try #require(result["contents"] as? [[String: Any]]) | |
| let resource = try #require(contents.first) | |
| let text = try #require(resource["text"] as? String) | |
| #expect(resource["mimeType"] as? String == "application/json") | |
| #expect(!text.contains("/private/example/Secret.swift")) | |
| #expect(text.contains("<redacted-path>")) | |
| let readCount = await reader.readCount() | |
| #expect(readCount == 1) | |
| } | |
| ("An unknown resource is rejected before any read") | |
| func unknownResourceIsRejectedBeforeRead() async throws { | |
| let workspace = try makeTemporaryDirectory() | |
| defer { try? FileManager.default.removeItem(at: workspace) } | |
| let context = try ACPRequestContext(workspaceURL: workspace) | |
| let reader = RecordingResourceReader(contents: [:]) | |
| let service = ACPService(context: context, resourceReader: reader) | |
| let response = try await decodedResponse( | |
| service, | |
| line: "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"resources/read\",\"params\":{\"uri\":\"file:///SSK_Ledger_Vault/other.json\"}}" | |
| ) | |
| let error = try #require(response["error"] as? [String: Any]) | |
| #expect(error["code"] as? Int == -32004) | |
| let readCount = await reader.readCount() | |
| #expect(readCount == 0) | |
| } | |
| ("A missing approved resource returns typed not-found behavior") | |
| func missingResourceReturnsNotFound() async throws { | |
| let workspace = try makeTemporaryDirectory() | |
| defer { try? FileManager.default.removeItem(at: workspace) } | |
| let context = try ACPRequestContext(workspaceURL: workspace) | |
| let service = ACPService(context: context, resourceReader: RecordingResourceReader(contents: [:])) | |
| let response = try await decodedResponse( | |
| service, | |
| line: "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"resources/read\",\"params\":{\"uri\":\"file:///SSK_Ledger_Vault/graph.json\"}}" | |
| ) | |
| let error = try #require(response["error"] as? [String: Any]) | |
| #expect(error["code"] as? Int == -32004) | |
| } | |
| ("A server without a vault stays available and reports the resource as unavailable") | |
| func serverWithoutVaultStaysAvailable() async throws { | |
| let workspace = try makeTemporaryDirectory() | |
| defer { try? FileManager.default.removeItem(at: workspace) } | |
| let context = try ACPRequestContext(workspaceURL: workspace) | |
| let service = ACPService(context: context, resourceReader: ACPUnavailableResourceReader()) | |
| let response = try await decodedResponse( | |
| service, | |
| line: "{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"resources/read\",\"params\":{\"uri\":\"file:///SSK_Ledger_Vault/graph.json\"}}" | |
| ) | |
| let error = try #require(response["error"] as? [String: Any]) | |
| #expect(error["code"] as? Int == -32003) | |
| } | |
| ("The current DocC index size is below its P0 limit") | |
| func currentIndexSizeIsAccepted() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| try fixture.write(byteCount: 1_456_000, to: "docc_index.json", json: true) | |
| let content = try await fixture.reader().read(fixture.resource(.doccIndex)) | |
| #expect(content.utf8.count == 1_456_000) | |
| } | |
| ("Each approved resource accepts its exact byte limit", arguments: [ | |
| (ACPResourceHandler.doccIndex, "docc_index.json", 2 * 1024 * 1024), | |
| (ACPResourceHandler.codebaseGraph, "graph.json", 256 * 1024), | |
| (ACPResourceHandler.masterMarkdownIndex, "DocC_Index.md", 256 * 1024), | |
| (ACPResourceHandler.refreshStatus, "refresh_status.json", 64 * 1024), | |
| ]) | |
| func exactPerResourceLimitsAreAccepted( | |
| handler: ACPResourceHandler, | |
| leafName: String, | |
| limit: Int | |
| ) async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| try fixture.write( | |
| byteCount: limit, | |
| to: leafName, | |
| json: handler != .masterMarkdownIndex | |
| ) | |
| let content = try await fixture.reader().read(fixture.resource(handler)) | |
| #expect(content.utf8.count == limit) | |
| } | |
| ("Each approved resource enforces its own byte limit", arguments: [ | |
| (ACPResourceHandler.doccIndex, "docc_index.json", 2 * 1024 * 1024), | |
| (ACPResourceHandler.codebaseGraph, "graph.json", 256 * 1024), | |
| (ACPResourceHandler.masterMarkdownIndex, "DocC_Index.md", 256 * 1024), | |
| (ACPResourceHandler.refreshStatus, "refresh_status.json", 64 * 1024), | |
| ]) | |
| func perResourceLimitsAreEnforced( | |
| handler: ACPResourceHandler, | |
| leafName: String, | |
| limit: Int | |
| ) async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| try fixture.write( | |
| byteCount: limit + 1, | |
| to: leafName, | |
| json: handler != .masterMarkdownIndex | |
| ) | |
| let reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.resourceTooLarge) { | |
| try await reader.read(fixture.resource(handler)) | |
| } | |
| } | |
| ("A missing physical resource returns the typed not-found error") | |
| func missingPhysicalResourceIsRejected() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.resourceNotFound) { | |
| try await reader.read(fixture.resource(.codebaseGraph)) | |
| } | |
| } | |
| ("Registration metadata cannot change the fixed resource mapping") | |
| func mismatchedRegistrationIsRejected() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let resource = ACPResourceRegistration( | |
| uri: "file:///SSK_Ledger_Vault/docc_index.json", | |
| name: "DocC Index", | |
| mimeType: "text/plain", | |
| handler: .doccIndex | |
| ) | |
| let reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try await reader.read(resource) | |
| } | |
| } | |
| ("A vault root identity mismatch is rejected with a fixed typed error") | |
| func replacedVaultRootIsRejected() throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let hooks = ACPDescriptorReadHooks(rootIdentityForValidation: { identity in | |
| ApprovedRootIdentity(device: identity.device, inode: identity.inode ^ 1) | |
| }) | |
| #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try fixture.reader(hooks: hooks) | |
| } | |
| } | |
| ("A resource leaf symbolic link is rejected") | |
| func leafSymlinkIsRejected() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let outside = fixture.root.appendingPathComponent("outside.json") | |
| try "outside".write(to: outside, atomically: true, encoding: .utf8) | |
| try FileManager.default.createSymbolicLink( | |
| at: fixture.vault.appendingPathComponent("docc_index.json"), | |
| withDestinationURL: outside | |
| ) | |
| let reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try await reader.read(fixture.resource(.doccIndex)) | |
| } | |
| } | |
| ("An opened approved-root descriptor is not redirected by root replacement") | |
| func openedApprovedRootIsPinnedDuringReplacement() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| try #"{"value":"approved"}"#.write(to: fixture.vault.appendingPathComponent("docc_index.json"), atomically: true, encoding: .utf8) | |
| let outside = fixture.root.appendingPathComponent("outside", isDirectory: true) | |
| try FileManager.default.createDirectory(at: outside, withIntermediateDirectories: true) | |
| try #"{"value":"outside"}"#.write(to: outside.appendingPathComponent("docc_index.json"), atomically: true, encoding: .utf8) | |
| let openedVault = fixture.root.appendingPathComponent("opened-vault", isDirectory: true) | |
| let hooks = ACPDescriptorReadHooks(afterOpeningApprovedRoot: { | |
| try? FileManager.default.moveItem(at: fixture.vault, to: openedVault) | |
| try? FileManager.default.createSymbolicLink(at: fixture.vault, withDestinationURL: outside) | |
| }) | |
| let content = try await fixture.reader(hooks: hooks).read(fixture.resource(.doccIndex)) | |
| #expect(content == #"{"value":"approved"}"#) | |
| } | |
| ("An opened leaf descriptor does not return replacement content") | |
| func openedLeafIsPinnedDuringReplacement() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let leaf = fixture.vault.appendingPathComponent("docc_index.json") | |
| let movedLeaf = fixture.vault.appendingPathComponent("opened-index.json") | |
| let outside = fixture.root.appendingPathComponent("outside.json") | |
| try #"{"value":"approved"}"#.write(to: leaf, atomically: true, encoding: .utf8) | |
| try #"{"value":"outside"}"#.write(to: outside, atomically: true, encoding: .utf8) | |
| let hooks = ACPDescriptorReadHooks(afterOpeningLeaf: { | |
| try? FileManager.default.moveItem(at: leaf, to: movedLeaf) | |
| try? FileManager.default.createSymbolicLink(at: leaf, withDestinationURL: outside) | |
| }) | |
| let reader = try fixture.reader(hooks: hooks) | |
| do { | |
| let content = try await reader.read(fixture.resource(.doccIndex)) | |
| #expect(content == #"{"value":"approved"}"#) | |
| #expect(content != #"{"value":"outside"}"#) | |
| } catch { | |
| #expect(error as? ACPResourceReadError == .unreadableResource) | |
| } | |
| } | |
| ("Directories and FIFOs cannot be read as resources") | |
| func specialFilesAreRejected() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let leaf = fixture.vault.appendingPathComponent("docc_index.json") | |
| try FileManager.default.createDirectory(at: leaf, withIntermediateDirectories: true) | |
| var reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try await reader.read(fixture.resource(.doccIndex)) | |
| } | |
| try FileManager.default.removeItem(at: leaf) | |
| #if canImport(Darwin) | |
| #expect(mkfifo(leaf.path, S_IRUSR | S_IWUSR) == 0) | |
| reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try await reader.read(fixture.resource(.doccIndex)) | |
| } | |
| #endif | |
| } | |
| ("Invalid UTF-8 is rejected") | |
| func invalidUTF8IsRejected() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| try Data([0xFF]).write(to: fixture.vault.appendingPathComponent("docc_index.json")) | |
| let reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try await reader.read(fixture.resource(.doccIndex)) | |
| } | |
| } | |
| ("Invalid JSON is rejected before the response boundary") | |
| func invalidJSONIsRejected() async throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| try "not-json".write( | |
| to: fixture.vault.appendingPathComponent("docc_index.json"), | |
| atomically: true, | |
| encoding: .utf8 | |
| ) | |
| let reader = try fixture.reader() | |
| await #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try await reader.read(fixture.resource(.doccIndex)) | |
| } | |
| } | |
| ("Redaction removes paths and sensitive JSON values and is idempotent") | |
| func sensitiveContentIsRedacted() { | |
| let content = #"{"/private/key/Secret.swift":{"file":"/private/My Project/Secret.swift"},"private_key":"key-data","nested":{"url":"ssk://spec:resource"}}"# | |
| let once = ACPResourceContentRedactor.redactingAbsolutePaths(in: content) | |
| let twice = ACPResourceContentRedactor.redactingAbsolutePaths(in: once) | |
| #expect(once == twice) | |
| #expect(once.contains("<redacted-path>")) | |
| #expect(once.contains("<redacted-sensitive-value>")) | |
| #expect(!once.contains("My Project")) | |
| #expect(!once.contains("/private/key/Secret.swift")) | |
| #expect(!once.contains("key-data")) | |
| #expect(once.contains("ssk:\\/\\/spec:resource") || once.contains("ssk://spec:resource")) | |
| } | |
| ("Plain text redaction handles secrets, incomplete PEM data, paths, and line bounds") | |
| func plainTextSensitiveContentIsRedacted() { | |
| let content = """ | |
| password: hunter2 | |
| Authorization: Bearer abc.def | |
| First /private/a.swift, then keep this text. | |
| URL file:///Users/example/Secret.swift; keep this too. | |
| -----BEGIN PRIVATE KEY----- | |
| unterminated-private-key-data | |
| """ | |
| let redacted = ACPResourceContentRedactor.redactingAbsolutePaths(in: content) | |
| #expect(!redacted.contains("hunter2")) | |
| #expect(!redacted.contains("abc.def")) | |
| #expect(!redacted.contains("/private/a.swift")) | |
| #expect(!redacted.contains("file:///Users/example/Secret.swift")) | |
| #expect(!redacted.contains("unterminated-private-key-data")) | |
| #expect(redacted.contains("then keep this text.")) | |
| #expect(redacted.contains("keep this too.")) | |
| } | |
| ("Quoted absolute paths with spaces are fully redacted") | |
| func quotedPathWithSpacesIsRedacted() { | |
| let content = #"Source: "/private/My Project/Secret.swift" and '/Users/example/Other Project/File.swift'."# | |
| let redacted = ACPResourceContentRedactor.redactingAbsolutePaths(in: content) | |
| #expect(!redacted.contains("My Project")) | |
| #expect(!redacted.contains("Other Project")) | |
| #expect(!redacted.contains("Secret.swift")) | |
| #expect(!redacted.contains("File.swift")) | |
| #expect(redacted.contains(#""<redacted-path>""#)) | |
| #expect(redacted.contains("'<redacted-path>'")) | |
| } | |
| ("Unsafe maximum byte limits are rejected before reading") | |
| func unsafeMaximumLimitIsRejected() throws { | |
| let fixture = try ResourceFixture() | |
| defer { fixture.remove() } | |
| let limits = ACPResourceReadLimits( | |
| doccIndexBytes: Int.max, | |
| codebaseGraphBytes: 1, | |
| masterMarkdownIndexBytes: 1, refreshStatusBytes: 1 | |
| ) | |
| #expect(throws: ACPResourceReadError.unreadableResource) { | |
| try ACPVaultLedgerResourceReader(paths: fixture.context.paths, limits: limits) | |
| } | |
| } | |
| private func decodedResponse(_ service: ACPService, line: String) async throws -> [String: Any] { | |
| let responseData = await service.response(for: line) | |
| let data = try #require(responseData) | |
| return try #require(JSONSerialization.jsonObject(with: data) as? [String: Any]) | |
| } | |
| private func makeTemporaryDirectory() throws -> URL { | |
| let directory = FileManager.default.temporaryDirectory | |
| .appendingPathComponent("SSKDocGen-\(UUID().uuidString)", isDirectory: true) | |
| try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) | |
| return directory | |
| } | |
| } | |
| private struct ResourceFixture: @unchecked Sendable { | |
| let root: URL | |
| let workspace: URL | |
| let vault: URL | |
| let context: ACPRequestContext | |
| init() throws { | |
| root = FileManager.default.temporaryDirectory | |
| .appendingPathComponent("SSKDocGenResource-\(UUID().uuidString)", isDirectory: true) | |
| workspace = root.appendingPathComponent("workspace", isDirectory: true) | |
| vault = root.appendingPathComponent("vault", isDirectory: true) | |
| try FileManager.default.createDirectory(at: workspace, withIntermediateDirectories: true) | |
| try FileManager.default.createDirectory(at: vault, withIntermediateDirectories: true) | |
| context = try ACPRequestContext(workspaceURL: workspace, vaultURL: vault) | |
| } | |
| func reader(hooks: ACPDescriptorReadHooks = .none) throws -> ACPVaultLedgerResourceReader { | |
| try ACPVaultLedgerResourceReader(paths: context.paths, hooks: hooks) | |
| } | |
| func resource(_ handler: ACPResourceHandler) -> ACPResourceRegistration { | |
| switch handler { | |
| case .doccIndex: | |
| return context.registry.resource(uri: "file:///SSK_Ledger_Vault/docc_index.json")! | |
| case .codebaseGraph: | |
| return context.registry.resource(uri: "file:///SSK_Ledger_Vault/graph.json")! | |
| case .masterMarkdownIndex: | |
| return context.registry.resource(uri: "file:///SSK_Ledger_Vault/DocC_Index.md")! | |
| case .refreshStatus: | |
| return context.registry.resource(uri: "file:///SSK_Ledger_Vault/refresh_status.json")! | |
| } | |
| } | |
| func write(byteCount: Int, to leafName: String, json: Bool = false) throws { | |
| let data: Data | |
| if json { | |
| precondition(byteCount >= 8) | |
| var value = Data(#"{"x":""#.utf8) | |
| value.append(Data(repeating: 0x61, count: byteCount - 8)) | |
| value.append(contentsOf: Data(#""}"#.utf8)) | |
| data = value | |
| } else { | |
| data = Data(repeating: 0x61, count: byteCount) | |
| } | |
| try data.write( | |
| to: vault.appendingPathComponent(leafName), | |
| options: .atomic | |
| ) | |
| } | |
| func remove() { | |
| try? FileManager.default.removeItem(at: root) | |
| } | |
| } | |
| private actor RecordingResourceReader: ACPResourceReading { | |
| private let contents: [ACPResourceHandler: String] | |
| private var count = 0 | |
| init(contents: [ACPResourceHandler: String]) { | |
| self.contents = contents | |
| } | |
| func read(_ resource: ACPResourceRegistration) async throws -> String { | |
| count += 1 | |
| guard let content = contents[resource.handler] else { | |
| throw ACPResourceReadError.resourceNotFound | |
| } | |
| return content | |
| } | |
| func readCount() -> Int { count } | |
| } | |
Xet Storage Details
- Size:
- 19.1 kB
- Xet hash:
- f338eb932de75fe8f7c483f0d642409c5f23dfe565d73fb734313ba46609ab68
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.