Skip to content
Merged
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
44 changes: 44 additions & 0 deletions scripts/build/compile-binary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,50 @@ it("proxy binary embeds only the runtime-resolved proxy entrypoint", async () =>
}
});

it("proxy binary cannot reach declarative config worker modules", async () => {
const command = new Deno.Command(Deno.execPath(), {
args: ["info", "--json", "cli/proxy-main.ts"],
stdout: "piped",
stderr: "piped",
});
const output = await command.output();
assertEquals(
output.success,
true,
new TextDecoder().decode(output.stderr),
);

const info = JSON.parse(new TextDecoder().decode(output.stdout)) as {
roots?: string[];
modules?: Array<{
dependencies?: Array<{ code?: { specifier?: string } }>;
specifier?: string;
}>;
};
const modules = new Map(
(info.modules ?? []).map((module) => [module.specifier ?? "", module]),
);
const reachable = new Set(info.roots ?? []);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
const pending = [...reachable];
while (pending.length > 0) {
const specifier = pending.shift()!;
for (const dependency of modules.get(specifier)?.dependencies ?? []) {
const dependencySpecifier = dependency.code?.specifier;
if (!dependencySpecifier || reachable.has(dependencySpecifier)) continue;
reachable.add(dependencySpecifier);
pending.push(dependencySpecifier);
}
}
const evaluatorWorkerModules = [...reachable]
.filter((specifier) => specifier.includes("declarative-evaluator-worker"));

assertEquals(
evaluatorWorkerModules,
[],
"the proxy must not reach project config evaluation; it only forwards requests to the production server",
);
});

it("proxy release verifies lock freshness and publishes an exact SBOM", async () => {
const workflow = await Deno.readTextFile(".github/workflows/cicd.yml");
const denoConfig = JSON.parse(await Deno.readTextFile("deno.json")) as {
Expand Down
19 changes: 6 additions & 13 deletions scripts/build/compile-binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,12 @@ export const DEFAULT_INCLUDES = [
];

export const PROXY_INCLUDES = [
// Deliberately omits UNTRACEABLE_WORKER_INCLUDES, on build grounds only.
// Adding them fails the compile outright: the worker entry's graph wants
// @babel/types@7.29.8 plus @babel/helper-string-parser and
// @babel/helper-validator-identifier, while proxy-deno.lock pins
// @babel/types@7.29.0, and --frozen refuses to update the lock.
//
// This is NOT evidence that the proxy is safe. The lock already carries a
// babel parse toolchain (parser, generator, traverse, types), so "the deps
// are absent, therefore the worker never runs here" does not follow --
// the conflict is a version skew, not an absence. `cli/proxy-main.ts` does
// pull the evaluator's runner into its graph, so whether the proxy can reach
// a spawn at runtime is an open question, tracked in veryfront-issue-inbox#382.
// If it can, this list and the proxy lock have to be regenerated together.
// Deliberately omits UNTRACEABLE_WORKER_INCLUDES. The standalone proxy
// forwards project requests to the production server and never evaluates
// project config. Its entry graph must therefore remain unable to reach the
// declarative evaluator worker. compile-binary.test.ts enforces that runtime
// boundary. If project config evaluation is added to the proxy, embed every
// reachable worker here and regenerate the proxy lock in the same change.
//
// The proxy runtime is loaded after provider activation. Providers are
// statically referenced by cli/proxy-main.ts so --include does not embed the
Expand Down
5 changes: 4 additions & 1 deletion src/proxy/control-plane-signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ import {
verifyControlPlaneJwsSignature,
verifyDispatchJwsSignature,
} from "#veryfront/channels/control-plane.ts";
import { isRequestBodyTooLargeError, readBodyWithLimit } from "#veryfront/security/index.ts";
import {
isRequestBodyTooLargeError,
readBodyWithLimit,
} from "#veryfront/security/input-validation/limits.ts";
import { DEFAULT_MAX_BODY_SIZE_BYTES } from "#veryfront/utils/constants/index.ts";
import { isWellFormedString } from "#veryfront/utils/is-well-formed-string.ts";
import { isCanonicalOpaqueProjectIdentifier } from "#veryfront/utils/project-identity.ts";
Expand Down
Loading