From bfd8e0a693fa9a9add7881e646b0efc8b2999fd4 Mon Sep 17 00:00:00 2001 From: scgopi Date: Sun, 20 Sep 2026 14:11:11 -0700 Subject: [PATCH] Close exec() once, so remote delivery stops raising SyntaxError MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `f6b8af41` (the Windows daemon port) rewrote the installer's embedded python to an `exec('def w(p,c): …')` helper and closed the call twice: the emitted program ends `exec('…')');`. Python raises SyntaxError on the stray `')` before writing a byte. The fragment ends in `>/dev/null 2>&1 || true`, so nothing saw it. Every remote delivery since 2026-09-15 has been a silent no-op: no CLI shim at ~/.graphcode/bin/graphcode, no briefing, no wake digest, no PROMPT.md — on every remote host and Codespace, for the whole of 0.1.73. A loop there could not reach the graph, and one whose goal had been shed to a file booted pointing at instructions that were never delivered. Every existing test asserts on the script as *text* — that it mentions python3, that its manifest decodes, that it is `|| true`d — and none of that notices a program python will not parse. The new suite runs the real fragment under /bin/sh against a scratch HOME and checks what landed, including that the delivered shim itself compiles. Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: scgopi --- .../Sources/Sessions/RemoteGraphAccess.swift | 2 +- .../Tests/RemoteInstallerExecutionTests.swift | 117 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 graphcode/Tests/RemoteInstallerExecutionTests.swift diff --git a/GraphcodeKit/Sources/Sessions/RemoteGraphAccess.swift b/GraphcodeKit/Sources/Sessions/RemoteGraphAccess.swift index 0578360b..6ebe8ebb 100644 --- a/GraphcodeKit/Sources/Sessions/RemoteGraphAccess.swift +++ b/GraphcodeKit/Sources/Sessions/RemoteGraphAccess.swift @@ -160,7 +160,7 @@ public enum RemoteGraphAccess { + " else:\\n" + " with open(os.path.expanduser(p),\"wb\") as f: f.write(b)\\n" + " os.chmod(os.path.expanduser(p),0o755 if p.endswith(\"/graphcode\") else 0o644)\\n" - + "')'); " + + "'); " + "[w(p,c) for p,c in sorted(m.items())]; " + "len(sys.argv)>2 and open(os.path.expanduser(sys.argv[2]),'w').write(sys.argv[3])" var argv = ["python3", "-c", program, json.base64EncodedString()] diff --git a/graphcode/Tests/RemoteInstallerExecutionTests.swift b/graphcode/Tests/RemoteInstallerExecutionTests.swift new file mode 100644 index 00000000..78287b3a --- /dev/null +++ b/graphcode/Tests/RemoteInstallerExecutionTests.swift @@ -0,0 +1,117 @@ +import Foundation +import Testing + +@testable import GraphcodeKit + +/// The installer fragment `RemoteGraphAccess.installerScript` builds, **actually run**. +/// +/// Every other test of it asserts on the script as text — that it mentions `python3`, +/// that its manifest decodes, that it is `|| true`d. None of that notices a program that +/// python refuses to parse, and for five days none of it did: a stray `')` closed `exec(` +/// twice, so the whole delivery raised `SyntaxError` before writing a byte, silently, +/// because the fragment ends in `|| true`. Remote hosts and Codespaces got no CLI shim, +/// no briefing, no wake digest and no prompt file for the whole of 0.1.73. +/// +/// So these run the real thing against a scratch `HOME` and look at what landed. That is +/// the only assertion that could have caught it, and the only one that stays true when +/// someone edits the embedded python again. +@Suite +struct RemoteInstallerExecutionTests { + /// The installer is python, and a machine without it can only skip — never silently + /// pass, which is the failure mode this suite exists to end. + static var hasPython3: Bool { + let process = Process() + process.executableURL = URL(fileURLWithPath: "/usr/bin/env") + process.arguments = ["python3", "-c", ""] + process.standardOutput = FileHandle.nullDevice + process.standardError = FileHandle.nullDevice + guard (try? process.run()) != nil else { return false } + process.waitUntilExit() + return process.terminationStatus == 0 + } + + /// Runs `script` under `/bin/sh` with `HOME` pointed at a scratch directory, so the + /// `~/` paths the manifest uses expand somewhere disposable rather than over the + /// developer's own `~/.graphcode`. + private func run(_ script: String, home: URL) throws -> Int32 { + let process = Process() + process.executableURL = URL(fileURLWithPath: "/bin/sh") + process.arguments = ["-c", script] + var environment = ProcessInfo.processInfo.environment + environment["HOME"] = home.path + process.environment = environment + try process.run() + process.waitUntilExit() + return process.terminationStatus + } + + private func scratchHome() throws -> URL { + let home = URL(fileURLWithPath: NSTemporaryDirectory()) + .appendingPathComponent("graphcode-installer-\(UUID().uuidString)") + try FileManager.default.createDirectory(at: home, withIntermediateDirectories: true) + return home + } + + @Test(.enabled(if: hasPython3)) + func theInstallerActuallyWritesEveryFileItCarries() throws { + let home = try scratchHome() + defer { try? FileManager.default.removeItem(at: home) } + let shim = RemoteGraphAccess.cliInstallPath + let briefing = RemoteGraphAccess.briefingPath(forProjectPath: "/home/dev/widget") + let script = try #require( + RemoteGraphAccess.installerScript( + files: [shim: RemoteGraphAccess.cliShimSource, briefing: "briefing text"], + receipt: (path: RemoteGraphAccess.shimStampPath, content: "stamp-v1"), + neutered: false)) + + #expect(try run(script, home: home) == 0) + + func landed(_ homeRelative: String) -> String? { + let url = home.appendingPathComponent(String(homeRelative.dropFirst(2))) + return try? String(contentsOf: url, encoding: .utf8) + } + #expect(landed(shim) == RemoteGraphAccess.cliShimSource) + #expect(landed(briefing) == "briefing text") + // The receipt is the delivery's proof, written only after every file above landed. + #expect(landed(RemoteGraphAccess.shimStampPath) == "stamp-v1") + // The shim is executed by name on the remote host, so the bit matters. + let shimURL = home.appendingPathComponent(String(shim.dropFirst(2))) + #expect(FileManager.default.isExecutableFile(atPath: shimURL.path)) + } + + @Test(.enabled(if: hasPython3)) + func aDeliveredShimIsAProgramPythonCanRun() throws { + // The shim is delivered as source and then run as a command. A manifest that lands + // it byte-perfect is still useless if the bytes do not parse. + let home = try scratchHome() + defer { try? FileManager.default.removeItem(at: home) } + let script = try #require( + RemoteGraphAccess.installerScript( + files: [RemoteGraphAccess.cliInstallPath: RemoteGraphAccess.cliShimSource], + neutered: false)) + #expect(try run(script, home: home) == 0) + + let shim = home.appendingPathComponent( + String(RemoteGraphAccess.cliInstallPath.dropFirst(2))) + #expect(try run("python3 -m py_compile \(shim.path)", home: home) == 0) + } + + @Test(.enabled(if: hasPython3)) + func aFailedDeliveryIsSilentOnlyWhenItIsNeutered() throws { + // The two halves of the contract the prompt delivery depends on: neutered swallows a + // failure, un-neutered reports it, so a caller can chain a launch behind it. + let home = try scratchHome() + defer { try? FileManager.default.removeItem(at: home) } + // A path under a file rather than a directory: `makedirs` cannot create it. + let blocker = home.appendingPathComponent("blocker") + try "x".write(to: blocker, atomically: true, encoding: .utf8) + let doomed = "~/blocker/nested/PROMPT.md" + + let neutered = try #require(RemoteGraphAccess.installerScript(files: [doomed: "goal"])) + #expect(try run(neutered, home: home) == 0) + + let reporting = try #require( + RemoteGraphAccess.installerScript(files: [doomed: "goal"], neutered: false)) + #expect(try run(reporting, home: home) != 0) + } +}