344 lines · 12.1 KB · TypeScript
RawDownload
import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, describe, it } from "@effect/vitest";import { EnvironmentId, type PersistedSavedEnvironmentRecord } from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Schema from "effect/Schema"; import * as DesktopConfig from "../app/DesktopConfig.ts";import * as DesktopEnvironment from "../app/DesktopEnvironment.ts";import * as ElectronSafeStorage from "../electron/ElectronSafeStorage.ts";import * as DesktopSavedEnvironments from "./DesktopSavedEnvironments.ts"; const textDecoder = new TextDecoder();const textEncoder = new TextEncoder(); const savedRegistryRecord: PersistedSavedEnvironmentRecord = {  environmentId: EnvironmentId.make("environment-1"),  label: "Remote environment",  httpBaseUrl: "https://remote.example.com/",  wsBaseUrl: "wss://remote.example.com/",  createdAt: "2026-04-09T00:00:00.000Z",  lastConnectedAt: "2026-04-09T01:00:00.000Z",  desktopSsh: {    alias: "devbox",    hostname: "devbox.example.com",    username: "julius",    port: 22,  },}; const SavedEnvironmentRegistryDocumentProbe = Schema.Struct({  version: Schema.Number,  records: Schema.Array(Schema.Unknown),});const decodeSavedEnvironmentRegistryDocumentProbe = Schema.decodeEffect(  Schema.fromJsonString(SavedEnvironmentRegistryDocumentProbe),); function makeSafeStorageLayer(input: {  readonly available: boolean;  readonly availabilityError?: unknown;  readonly encryptError?: unknown;  readonly decryptError?: unknown;}) {  return Layer.succeed(ElectronSafeStorage.ElectronSafeStorage, {    isEncryptionAvailable:      input.availabilityError === undefined        ? Effect.succeed(input.available)        : Effect.fail(            new ElectronSafeStorage.ElectronSafeStorageAvailabilityError({              cause: input.availabilityError,            }),          ),    encryptString: (value) =>      input.encryptError === undefined        ? Effect.succeed(textEncoder.encode(`enc:${value}`))        : Effect.fail(            new ElectronSafeStorage.ElectronSafeStorageEncryptError({              cause: input.encryptError,            }),          ),    decryptString: (value) => {      if (input.decryptError !== undefined) {        return Effect.fail(          new ElectronSafeStorage.ElectronSafeStorageDecryptError({            cause: input.decryptError,          }),        );      }       const decoded = textDecoder.decode(value);      if (!decoded.startsWith("enc:")) {        return Effect.fail(          new ElectronSafeStorage.ElectronSafeStorageDecryptError({            cause: new Error("invalid secret"),          }),        );      }      return Effect.succeed(decoded.slice("enc:".length));    },  } satisfies ElectronSafeStorage.ElectronSafeStorageShape);} function makeLayer(  baseDir: string,  options?: {    readonly availableSecretStorage?: boolean;    readonly availabilityError?: unknown;    readonly encryptError?: unknown;    readonly decryptError?: unknown;  },) {  const environmentLayer = DesktopEnvironment.layer({    dirname: "/repo/apps/desktop/src",    homeDirectory: baseDir,    platform: "darwin",    processArch: "x64",    appVersion: "1.2.3",    appPath: "/repo",    isPackaged: true,    resourcesPath: "/missing/resources",    runningUnderArm64Translation: false,  }).pipe(    Layer.provide(      Layer.mergeAll(NodeServices.layer, DesktopConfig.layerTest({ T3CODE_HOME: baseDir })),    ),  );   return DesktopSavedEnvironments.layer.pipe(    Layer.provideMerge(environmentLayer),    Layer.provideMerge(      makeSafeStorageLayer({        available: options?.availableSecretStorage ?? true,        availabilityError: options?.availabilityError,        encryptError: options?.encryptError,        decryptError: options?.decryptError,      }),    ),    Layer.provideMerge(NodeServices.layer),  );} const withSavedEnvironments = <A, E, R>(  effect: Effect.Effect<A, E, R | DesktopSavedEnvironments.DesktopSavedEnvironments>,  options?: {    readonly availableSecretStorage?: boolean;    readonly availabilityError?: unknown;    readonly encryptError?: unknown;    readonly decryptError?: unknown;  },) =>  Effect.gen(function* () {    const fileSystem = yield* FileSystem.FileSystem;    const baseDir = yield* fileSystem.makeTempDirectoryScoped({      prefix: "t3-desktop-saved-environments-test-",    });    return yield* effect.pipe(Effect.provide(makeLayer(baseDir, options)));  }).pipe(Effect.provide(NodeServices.layer), Effect.scoped); describe("DesktopSavedEnvironments", () => {  it.effect("persists and reloads saved environment metadata", () =>    withSavedEnvironments(      Effect.gen(function* () {        const environment = yield* DesktopEnvironment.DesktopEnvironment;        const fileSystem = yield* FileSystem.FileSystem;        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* savedEnvironments.setRegistry([savedRegistryRecord]);         assert.deepEqual(yield* savedEnvironments.getRegistry, [savedRegistryRecord]);        const persisted = yield* decodeSavedEnvironmentRegistryDocumentProbe(          yield* fileSystem.readFileString(environment.savedEnvironmentRegistryPath),        );        assert.equal(persisted.version, 1);        assert.lengthOf(persisted.records, 1);      }),    ),  );   it.effect("loads lenient saved environment registry documents", () =>    withSavedEnvironments(      Effect.gen(function* () {        const environment = yield* DesktopEnvironment.DesktopEnvironment;        const fileSystem = yield* FileSystem.FileSystem;        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true });        yield* fileSystem.writeFileString(          environment.savedEnvironmentRegistryPath,          `{            // Same optional envelope shape as browser saved environments.            "version": 1,            "records": [              {                "environmentId": "${savedRegistryRecord.environmentId}",                "label": "Remote environment",                "httpBaseUrl": "https://remote.example.com/",                "wsBaseUrl": "wss://remote.example.com/",                "createdAt": "2026-04-09T00:00:00.000Z",                "lastConnectedAt": "2026-04-09T01:00:00.000Z",                "desktopSsh": {                  "alias": "devbox",                  "hostname": "devbox.example.com",                  "username": "julius",                  "port": 22,                },              },            ],          }\n`,        );         assert.deepEqual(yield* savedEnvironments.getRegistry, [savedRegistryRecord]);      }),    ),  );   it.effect("persists encrypted saved environment secrets when encryption is available", () =>    withSavedEnvironments(      Effect.gen(function* () {        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* savedEnvironments.setRegistry([savedRegistryRecord]);         assert.isTrue(          yield* savedEnvironments.setSecret({            environmentId: savedRegistryRecord.environmentId,            secret: "bearer-token",          }),        );         assert.deepEqual(          yield* savedEnvironments.getSecret(savedRegistryRecord.environmentId),          Option.some("bearer-token"),        );      }),    ),  );   it.effect("returns false when writing secrets while encryption is unavailable", () =>    withSavedEnvironments(      Effect.gen(function* () {        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* savedEnvironments.setRegistry([savedRegistryRecord]);         assert.isFalse(          yield* savedEnvironments.setSecret({            environmentId: savedRegistryRecord.environmentId,            secret: "next-token",          }),        );      }),      { availableSecretStorage: false },    ),  );   it.effect("surfaces typed safe storage availability failures", () => {    const cause = new Error("safe storage unavailable");    return withSavedEnvironments(      Effect.gen(function* () {        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* savedEnvironments.setRegistry([savedRegistryRecord]);         const error = yield* savedEnvironments          .setSecret({            environmentId: savedRegistryRecord.environmentId,            secret: "next-token",          })          .pipe(Effect.flip);         assert.instanceOf(error, ElectronSafeStorage.ElectronSafeStorageAvailabilityError);        assert.equal(error.cause, cause);      }),      { availabilityError: cause },    );  });   it.effect("removes saved environment secrets", () =>    withSavedEnvironments(      Effect.gen(function* () {        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* savedEnvironments.setRegistry([savedRegistryRecord]);        yield* savedEnvironments.setSecret({          environmentId: savedRegistryRecord.environmentId,          secret: "bearer-token",        });         yield* savedEnvironments.removeSecret(savedRegistryRecord.environmentId);         assert.isTrue(          Option.isNone(yield* savedEnvironments.getSecret(savedRegistryRecord.environmentId)),        );      }),    ),  );   it.effect("treats empty saved environment documents as empty", () =>    withSavedEnvironments(      Effect.gen(function* () {        const environment = yield* DesktopEnvironment.DesktopEnvironment;        const fileSystem = yield* FileSystem.FileSystem;        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true });        yield* fileSystem.writeFileString(environment.savedEnvironmentRegistryPath, "{}\n");         assert.deepEqual(yield* savedEnvironments.getRegistry, []);        assert.isTrue(          Option.isNone(yield* savedEnvironments.getSecret(savedRegistryRecord.environmentId)),        );      }),    ),  );   it.effect("treats malformed saved environment documents as empty", () =>    withSavedEnvironments(      Effect.gen(function* () {        const environment = yield* DesktopEnvironment.DesktopEnvironment;        const fileSystem = yield* FileSystem.FileSystem;        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true });        yield* fileSystem.writeFileString(environment.savedEnvironmentRegistryPath, "{not-json");         assert.deepEqual(yield* savedEnvironments.getRegistry, []);        assert.isTrue(          Option.isNone(yield* savedEnvironments.getSecret(savedRegistryRecord.environmentId)),        );      }),    ),  );   it.effect("returns false when writing a secret without metadata", () =>    withSavedEnvironments(      Effect.gen(function* () {        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;         assert.isFalse(          yield* savedEnvironments.setSecret({            environmentId: savedRegistryRecord.environmentId,            secret: "bearer-token",          }),        );      }),    ),  );   it.effect("preserves encrypted secrets when metadata is rewritten", () =>    withSavedEnvironments(      Effect.gen(function* () {        const savedEnvironments = yield* DesktopSavedEnvironments.DesktopSavedEnvironments;        yield* savedEnvironments.setRegistry([savedRegistryRecord]);        yield* savedEnvironments.setSecret({          environmentId: savedRegistryRecord.environmentId,          secret: "bearer-token",        });         yield* savedEnvironments.setRegistry([savedRegistryRecord]);         assert.deepEqual(yield* savedEnvironments.getRegistry, [savedRegistryRecord]);        assert.deepEqual(          yield* savedEnvironments.getSecret(savedRegistryRecord.environmentId),          Option.some("bearer-token"),        );      }),    ),  );});