Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/platform/adapters/fs/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import {
import { describe, it } from "#veryfront/testing/bdd.ts";
import { withMockFetch } from "#veryfront/testing/mock-fetch.ts";
import {
createEnhancedAdapter,
createFSAdapterFromConfig,
enhanceAdapterWithFS,
getFSAdapterType,
isFSAdapterConfigured,
} from "./integration.ts";
import { denoAdapter } from "../deno.ts";
import { VeryfrontError } from "#veryfront/errors/types.ts";
import { isProxyWithoutHooks } from "#veryfront/platform/compat/error-introspection.ts";
import type { RuntimeAdapter } from "../base.ts";

describe("integration.ts", () => {
it("should export enhanceAdapterWithFS function", () => {
Expand Down Expand Up @@ -101,6 +104,27 @@ describe("integration.ts", () => {
assertEquals(getFSAdapterType({ fs: {} }), "local");
});

describe("createEnhancedAdapter", () => {
// SecureFs rejects Proxy adapters, so returning one here took hosted preview
// rendering down with a 400 on every request.
const stubFs = { symlinkSemantics: "none" } as unknown as RuntimeAdapter["fs"];

it("returns a non-Proxy adapter so SecureFs can accept it", () => {
const adapter = createEnhancedAdapter(denoAdapter, stubFs);

assertEquals(isProxyWithoutHooks(adapter), false);
assertExists(Object.getOwnPropertyDescriptor(adapter, "fs"));
});
Comment on lines +150 to +154

it("overrides fs and keeps the rest of the adapter usable", () => {
const adapter = createEnhancedAdapter(denoAdapter, stubFs);

assertStrictEquals(adapter.fs, stubFs);
assertEquals(typeof adapter.shutdown, "function");
assertStrictEquals(adapter.capabilities, denoAdapter.capabilities);
});
});

describe("enhanceAdapterWithFS error propagation", () => {
it("should preserve invalid retry configuration instead of changing filesystems", async () => {
let rejection: unknown;
Expand Down
46 changes: 38 additions & 8 deletions src/platform/adapters/fs/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,43 @@ function isLocalFS(config: FSIntegrationConfig): boolean {
return !config.fs?.type || config.fs.type === "local";
}

/**
* Override `fs` without a Proxy. SecureFs rejects Proxy adapters because their
* traps can run arbitrary code, so copy the adapter's members onto a real
* object with methods bound back to the original instance.
*/
export function createEnhancedAdapter(
adapter: RuntimeAdapter,
fs: RuntimeAdapter["fs"],
): RuntimeAdapter {
const enhanced: Record<PropertyKey, unknown> = {};
const chain: object[] = [];
for (
let current: object | null = adapter;
current !== null && current !== Object.prototype;
current = Object.getPrototypeOf(current)
) {
chain.push(current);
}

// Base first so subclass overrides win.
for (const source of chain.reverse()) {
for (const key of Reflect.ownKeys(source)) {
if (key === "constructor" || key === "fs") continue;
const value = Reflect.get(adapter, key);
enhanced[key] = typeof value === "function" ? value.bind(adapter) : value;
}
}

Object.defineProperty(enhanced, "fs", {
value: fs,
writable: false,
enumerable: true,
configurable: false,
Comment on lines +33 to +37

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 5 '\bcreateEnhancedAdapter\s*\(' src --glob '*.ts' --glob '*.tsx'
rg -n -C 4 -P '\.fs\s*=' src --glob '*.ts' --glob '*.tsx'

Repository: veryfront/veryfront-code

Length of output: 21932


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- base adapter ---'
fd -i 'base.ts' src/platform/adapters --type f -x sh -c 'cat -n "$1"' sh {}

printf '%s\n' '--- integration implementation ---'
cat -n src/platform/adapters/fs/integration.ts

printf '%s\n' '--- focused integration tests ---'
sed -n '1,210p' src/platform/adapters/fs/integration.test.ts

printf '%s\n' '--- RuntimeAdapter type and enhanced-adapter consumers ---'
rg -n -C 5 'RuntimeAdapter|enhancedAdapter|createEnhancedAdapter' src/platform src/server src/rendering --glob '*.ts' --glob '*.tsx' \
  | head -n 500

Repository: veryfront/veryfront-code

Length of output: 50380


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- direct factory call sites ---'
rg -n -C 8 '\bcreateEnhancedAdapter\s*\(' src --glob '*.ts' --glob '*.tsx'

printf '%s\n' '--- enhancement call sites ---'
rg -n -C 10 '\benhanceAdapterWithFS\s*\(' src --glob '*.ts' --glob '*.tsx'

printf '%s\n' '--- assignments on enhancement results and adapter parameters ---'
rg -n -C 3 '(enhancedAdapter|enhanced|adapter)\.fs\s*=' src/platform src/server src/rendering --glob '*.ts' --glob '*.tsx' \
  | head -n 400

printf '%s\n' '--- SecureFs adapter property handling ---'
rg -n -C 8 'adapter\.fs|Object\.getOwnPropertyDescriptor|defineProperty|immutable|writable' src/security/secure-fs.ts src/security/secure-fs.test.ts \
  | head -n 500

printf '%s\n' '--- strict-mode assignment probe ---'
node - <<'JS'
"use strict";
const prototype = { fs: { id: "base" } };
const enhanced = Object.create(prototype);
Object.defineProperty(enhanced, "fs", {
  value: { id: "remote" },
  writable: false,
  enumerable: true,
  configurable: false,
});
let outcome;
try {
  enhanced.fs = { id: "replacement" };
  outcome = "assignment completed";
} catch (error) {
  outcome = `${error.constructor.name}: ${error.message}`;
}
console.log(JSON.stringify({
  outcome,
  currentFs: enhanced.fs.id,
  ownDescriptor: Object.getOwnPropertyDescriptor(enhanced, "fs"),
}));
JS

Repository: veryfront/veryfront-code

Length of output: 50380


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- SecureFs adapter invariant ---'
sed -n '660,725p' src/security/secure-fs.ts

printf '%s\n' '--- existing replacement test ---'
sed -n '535,570p' src/security/secure-fs.test.ts

printf '%s\n' '--- exact enhanced-adapter assignment search ---'
rg -n -C 2 '(createEnhancedAdapter|enhanceAdapterWithFS|enhancedAdapter|enhanced)\.fs\s*=' src --glob '*.ts' --glob '*.tsx' || true

printf '%s\n' '--- strict-mode assignment probe ---'
node - <<'JS'
"use strict";
const prototype = { fs: { id: "base" } };
const enhanced = Object.create(prototype);
Object.defineProperty(enhanced, "fs", {
  value: { id: "remote" },
  writable: false,
  enumerable: true,
  configurable: false,
});
let outcome;
try {
  enhanced.fs = { id: "replacement" };
  outcome = "assignment completed";
} catch (error) {
  outcome = `${error.constructor.name}: ${error.message}`;
}
console.log(JSON.stringify({
  outcome,
  currentFs: enhanced.fs.id,
  ownDescriptor: Object.getOwnPropertyDescriptor(enhanced, "fs"),
}));
JS

Repository: veryfront/veryfront-code

Length of output: 4114


Expose the immutable fs contract in the return types.

createEnhancedAdapter defines fs as non-writable but returns RuntimeAdapter, whose mutable type permits assignments that throw at runtime. Use a distinct type with readonly fs, and preserve that type through enhanceAdapterWithFS.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/adapters/fs/integration.ts` around lines 33 - 37, Update
createEnhancedAdapter and enhanceAdapterWithFS to return a distinct adapter type
that declares fs as readonly, matching the non-writable property defined by
Object.defineProperty. Ensure the readonly fs contract is preserved through
enhanceAdapterWithFS while retaining the existing RuntimeAdapter behavior for
other properties.

Source: Coding guidelines

});
Comment on lines +33 to +38
return enhanced as unknown as RuntimeAdapter;
}

export function enhanceAdapterWithFS(
adapter: RuntimeAdapter,
config: FSIntegrationConfig,
Expand Down Expand Up @@ -50,14 +87,7 @@ export function enhanceAdapterWithFS(
const fsAdapter = await createFSAdapter(fsAdapterConfig);
const wrappedFS = wrapFSAdapter(fsAdapter);

const enhancedAdapter: RuntimeAdapter = new Proxy(adapter, {
get(target, prop, receiver) {
if (prop === "fs") return wrappedFS;

const value = Reflect.get(target, prop, receiver);
return typeof value === "function" ? value.bind(target) : value;
},
});
const enhancedAdapter = createEnhancedAdapter(adapter, wrappedFS);

logger.debug("FSAdapter initialized successfully", {
type: fsType,
Expand Down