Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
61 changes: 61 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,19 @@ 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";
import type { FSAdapter } from "./veryfront/types.ts";
import { wrapFSAdapter } from "./wrapper.ts";
import { createSecureFs } from "#veryfront/security/secure-fs.ts";

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

describe("remote filesystem reaches SecureFs", () => {
// Two gates broke hosted preview in sequence: SecureFs rejected the Proxy
// adapter, then rejected the wrapped fs because an unimplemented optional
// capability was published as an own `undefined`.
function bareRemoteFs(): FSAdapter {
return {
readFile: () => Promise.resolve(""),
writeFile: () => Promise.resolve(),
exists: () => Promise.resolve(true),
mkdir: () => Promise.resolve(),
remove: () => Promise.resolve(),
stat: () =>
Promise.resolve({
isSymlink: false,
isDirectory: false,
isFile: true,
size: 0,
mtime: null,
}),
// deno-lint-ignore require-yield
async *readDir() {},
} as unknown as FSAdapter;
}

it("produces an adapter SecureFs accepts", () => {
const adapter = createEnhancedAdapter(
denoAdapter,
wrapFSAdapter(bareRemoteFs()) as unknown as RuntimeAdapter["fs"],
);

assertExists(createSecureFs({ baseDir: "/project", adapter }));
});
});

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
29 changes: 21 additions & 8 deletions src/platform/adapters/fs/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@ 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. Inheriting from the adapter keeps its methods,
* accessors and identity live, while `fs` is the one own data property SecureFs
* requires.
*/
export function createEnhancedAdapter(
adapter: RuntimeAdapter,
fs: RuntimeAdapter["fs"],
): RuntimeAdapter {
const enhanced = Object.create(adapter) as RuntimeAdapter;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

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

rg -n -C 5 'implements\s+RuntimeAdapter|:\s*RuntimeAdapter|RuntimeAdapter\s*=' \
  src/platform/adapters --glob '*.ts' --glob '*.tsx'
rg -n -C 5 -P 'this\.[A-Za-z_$][A-Za-z0-9_$]*\s*(=|\+=|-=|\+\+|--)' \
  src/platform/adapters --glob '*.ts' --glob '*.tsx'
rg -n -C 3 -P '#[A-Za-z_$][A-Za-z0-9_$]*' \
  src/platform/adapters --glob '*.ts' --glob '*.tsx'

Repository: veryfront/veryfront-code

Length of output: 50381


🏁 Script executed:

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

printf '%s\n' '--- integration.ts ---'
cat -n src/platform/adapters/fs/integration.ts | sed -n '1,130p'

printf '%s\n' '--- RuntimeAdapter definitions and enhanced-adapter usages ---'
rg -n -C 8 'interface RuntimeAdapter|type RuntimeAdapter|createEnhancedAdapter|isProxyWithoutHooks|Object\.create\(adapter\)' src --glob '*.ts' --glob '*.tsx'

printf '%s\n' '--- concrete adapter declarations ---'
rg -n -C 4 'class .*Adapter|implements RuntimeAdapter|RuntimeAdapter<' src/platform/adapters --glob '*.ts' --glob '*.tsx'

printf '%s\n' '--- receiver-dependent methods in the concrete adapter ---'
rg -n -C 4 '^\s*(public\s+|private\s+|protected\s+)?(async\s+)?[A-Za-z_$][A-Za-z0-9_$]*\s*\([^)]*\)\s*\{|^\s*(async\s+)?[A-Za-z_$][A-Za-z0-9_$]*\s*=' src/platform/adapters/fs/veryfront/adapter.ts

Repository: veryfront/veryfront-code

Length of output: 50381


🏁 Script executed:

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

printf '%s\n' '--- adapter class fields and methods relevant to receiver identity ---'
sed -n '1,380p' src/platform/adapters/fs/veryfront/adapter.ts
sed -n '1080,1245p' src/platform/adapters/fs/veryfront/adapter.ts
sed -n '1245,1375p' src/platform/adapters/fs/veryfront/adapter.ts

printf '%s\n' '--- direct calls on enhanced adapters and adapter method extraction ---'
rg -n -C 5 'createEnhancedAdapter|enhanced|RuntimeAdapter|\.fs\s*=' src/platform/adapters src --glob '*.ts' --glob '*.tsx' \
  | head -n 1200

Repository: veryfront/veryfront-code

Length of output: 50383


🏁 Script executed:

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

python3 - <<'PY'
from pathlib import Path
p = Path("src/platform/adapters/fs/veryfront/adapter.ts")
text = p.read_text()
for i, line in enumerate(text.splitlines(), 1):
    if "this." in line and any(op in line for op in ("=", "+=", "-=", "++", "--")):
        print(f"{i}: {line.strip()}")
PY

printf '%s\n' '--- private fields in adapter and related classes ---'
rg -n -C 3 '#[A-Za-z_$][A-Za-z0-9_$]*|WeakMap|WeakSet' src/platform/adapters/fs --glob '*.ts' --glob '*.tsx'

printf '%s\n' '--- all RuntimeAdapter property assignments and method calls ---'
rg -n -C 3 '\b(adapter|runtimeAdapter|enhanced)\.[A-Za-z_$][A-Za-z0-9_$]*\s*(=|\()|Object\.assign\([^)]*\b(adapter|runtimeAdapter|enhanced)\b' src --glob '*.ts' --glob '*.tsx'

Repository: veryfront/veryfront-code

Length of output: 50381


🏁 Script executed:

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

printf '%s\n' '--- concise symbol inventory ---'
ast-grep outline src/platform/adapters/fs/integration.ts
ast-grep outline src/platform/adapters/fs/veryfront/adapter.ts

printf '%s\n' '--- factory and detector implementations ---'
rg -n -C 12 'function createEnhancedAdapter|const createEnhancedAdapter|isProxyWithoutHooks|class SecureFs|new SecureFs' src --glob '*.ts' --glob '*.tsx'

Repository: veryfront/veryfront-code

Length of output: 50381


🏁 Script executed:

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

printf '%s\n' '--- RuntimeAdapter contract ---'
cat -n src/platform/adapters/base.ts | sed -n '1,240p'

printf '%s\n' '--- runtime adapter implementations ---'
for f in \
  src/platform/adapters/deno.ts \
  src/platform/adapters/runtime/node/adapter.ts \
  src/platform/adapters/runtime/bun/adapter.ts \
  src/platform/adapters/runtime/cloudflare/adapter.ts \
  src/platform/adapters/mock.ts
do
  if [ -f "$f" ]; then
    printf '\n--- %s ---\n' "$f"
    cat -n "$f" | sed -n '1,260p'
  fi
done

printf '%s\n' '--- exact integration call sites ---'
rg -n -C 12 'enhanceAdapterWithFS|createEnhancedAdapter' src --glob '*.ts' --glob '*.tsx'

Repository: veryfront/veryfront-code

Length of output: 50380


🏁 Script executed:

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

printf '%s\n' '--- SecureFs adapter validation and use ---'
rg -n -C 12 'Object\.getOwnPropertyDescriptor|isProxyWithoutHooks|adapter\.fs|RuntimeAdapter' \
  src/security/secure-fs.ts src/security --glob '*.ts' --glob '*.tsx' | head -n 1600

printf '%s\n' '--- proxy detector implementation ---'
rg -n -C 20 'export function isProxyWithoutHooks|const isProxyWithoutHooks|function isProxyWithoutHooks' \
  src/platform/compat src/errors --glob '*.ts' --glob '*.tsx'

printf '%s\n' '--- RuntimeAdapter receiver-sensitive assignments ---'
python3 - <<'PY'
from pathlib import Path
for p in Path("src/platform/adapters").rglob("*.ts"):
    text = p.read_text()
    if "implements RuntimeAdapter" not in text:
        continue
    print(f"\n--- {p} ---")
    for i, line in enumerate(text.splitlines(), 1):
        if "this." in line and any(op in line for op in ("=", "+=", "-=", "++", "--")):
            print(f"{i}: {line.strip()}")
PY

Repository: veryfront/veryfront-code

Length of output: 50381


🏁 Script executed:

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

printf '%s\n' '--- all RuntimeAdapter classes and their method bodies ---'
rg -l 'implements RuntimeAdapter' src/platform/adapters --glob '*.ts' --glob '*.tsx' |
while IFS= read -r f; do
  printf '\n--- %s ---\n' "$f"
  rg -n -C 6 'implements RuntimeAdapter|^\s*(async\s+)?[A-Za-z_$][A-Za-z0-9_$]*\s*\(' "$f" | head -n 500
done

printf '%s\n' '--- RuntimeAdapter fs mutability in code ---'
rg -n -C 5 '\bfs\s*[:=]|readonly fs|adapter\.fs\s*=' src/platform/adapters src --glob '*.ts' --glob '*.tsx' | head -n 1200

Repository: veryfront/veryfront-code

Length of output: 50380


🏁 Script executed:

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

printf '%s\n' '--- focused integration tests ---'
cat -n src/platform/adapters/fs/integration.test.ts | sed -n '130,230p'

printf '%s\n' '--- concrete runtime adapter state writes ---'
for f in \
  src/platform/adapters/runtime/deno/adapter.ts \
  src/platform/adapters/runtime/node/adapter.ts \
  src/platform/adapters/runtime/bun/adapter.ts \
  src/platform/adapters/runtime/cloudflare/adapter.ts
do
  printf '\n--- %s ---\n' "$f"
  rg -n 'this\.|private|#|^[[:space:]]*(async[[:space:]]+)?[A-Za-z_$][A-Za-z0-9_$]*\(' "$f"
done

printf '%s\n' '--- standalone receiver and descriptor probe ---'
node - <<'JS'
"use strict";

class RuntimeAdapterLike {
  constructor() {
    this.servers = {
      calls: 0,
      shutdown() {
        this.calls++;
      },
    };
    this.serve = () => this.servers;
  }

  shutdown() {
    this.servers.shutdown();
  }
}

const original = new RuntimeAdapterLike();
const enhanced = Object.create(original);
Object.defineProperty(enhanced, "fs", {
  value: { marker: "remote" },
  writable: false,
  enumerable: true,
  configurable: false,
});

enhanced.shutdown();
const before = original.servers.calls;
const fsDescriptor = Object.getOwnPropertyDescriptor(enhanced, "fs");

let assignmentError = false;
try {
  enhanced.fs = { marker: "replacement" };
} catch {
  assignmentError = true;
}

console.log(JSON.stringify({
  shutdownReceiverIsEnhanced: enhanced.shutdown === original.shutdown,
  shutdownStateCallCountOnOriginalState: before,
  arrowServeUsesOriginalState: enhanced.serve() === original.servers,
  fsWritable: fsDescriptor?.writable,
  assignmentError,
}));
JS

Repository: veryfront/veryfront-code

Length of output: 5713


🏁 Script executed:

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

printf '%s\n' '--- exact runtime-adapter method implementations ---'
cat -n src/platform/adapters/runtime/deno/adapter.ts
cat -n src/platform/adapters/runtime/shared/server-lifecycle.ts | sed -n '1,220p'

printf '%s\n' '--- methods that mutate receiver state in runtime adapter classes ---'
python3 - <<'PY'
from pathlib import Path
files = [
    Path("src/platform/adapters/runtime/deno/adapter.ts"),
    Path("src/platform/adapters/runtime/node/adapter.ts"),
    Path("src/platform/adapters/runtime/bun/adapter.ts"),
    Path("src/platform/adapters/runtime/cloudflare/adapter.ts"),
]
for p in files:
    print(f"--- {p} ---")
    for i, line in enumerate(p.read_text().splitlines(), 1):
        stripped = line.strip()
        if "this." in stripped or "#" in stripped:
            print(f"{i}: {stripped}")
PY

Repository: veryfront/veryfront-code

Length of output: 7464


Reject proxy adapters before Object.create(adapter). A proxy passed as adapter becomes the enhanced object's prototype. SecureFs can accept the non-proxy enhanced object while inherited property reads still execute proxy traps.

🤖 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` at line 32, Validate that adapter is
not a proxy before the Object.create(adapter) call in the enhancement flow.
Reject proxy adapters before assigning them as the enhanced object's prototype,
while preserving the existing handling for non-proxy RuntimeAdapter instances.

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

});
return enhanced;
}

export function enhanceAdapterWithFS(
adapter: RuntimeAdapter,
config: FSIntegrationConfig,
Expand Down Expand Up @@ -50,14 +70,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
4 changes: 4 additions & 0 deletions src/security/secure-fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,10 @@ export class SecureFs {
snapshotReader = captureSnapshotReadCapability(
suppliedFileSystem,
"SecureFs filesystem",
// FSAdapterWrapper freezes every optional capability slot, publishing
// `undefined` for the ones no adapter implements. Treat that as absent,
// as the wrapper itself does, instead of rejecting the filesystem.
true,
);
} catch (_) {
invalidSecureFsOption("SecureFs filesystem snapshot capability is invalid");
Expand Down