feat(workspaces): define project runtime source authority

Route probe and user materialization through one projectRuntimeSource seam, where persisted Git source overrides the host-only convenience root and must belong to Git project data.

Lock default revision, explicit revision, and subdirectory semantics with real Docker acceptance. Enforce provider-probe internals structurally and document that the current Docker POC needs a locally built image because its default reference is unpublished.
This commit is contained in:
Mohamed Boudra
2026-08-12 20:53:05 +02:00
parent 527b252497
commit 33afa7283b
24 changed files with 750 additions and 74 deletions
+88 -2
View File
@@ -41,6 +41,11 @@ export async function findWorkspaceBoundaryViolations(repoRoot) {
const governed =
external ||
(!isTestFile(importer) && (ownsMigratedSurface(importer) || publicOwners.has(importer)));
for (const specifier of staticSpecifiers(sourceFile)) {
if (!isTestFile(importer) && isForbiddenInternal(importer, specifier)) {
violations.push(violation(importer, specifier, "module-entrypoint"));
}
}
for (const load of moduleLoads(sourceFile)) {
if (load.specifier === null) {
if (governed) violations.push(violation(importer, "<computed>", "nonliteral-module-load"));
@@ -91,6 +96,8 @@ function staticSpecifiers(sourceFile) {
function moduleLoads(sourceFile) {
const loads = [];
const constants = constantBindings(sourceFile);
const loaderAliases = moduleLoaderAliases(sourceFile);
visit(sourceFile);
return loads;
@@ -98,15 +105,88 @@ function moduleLoads(sourceFile) {
if (
ts.isCallExpression(node) &&
(node.expression.kind === ts.SyntaxKind.ImportKeyword ||
(ts.isIdentifier(node.expression) && node.expression.text === "require"))
(ts.isIdentifier(node.expression) && loaderAliases.has(node.expression.text)))
) {
const argument = node.arguments.length === 1 ? node.arguments[0] : undefined;
loads.push({ specifier: argument && ts.isStringLiteral(argument) ? argument.text : null });
loads.push({ specifier: argument ? constantString(argument, constants) : null });
}
ts.forEachChild(node, visit);
}
}
function constantBindings(sourceFile) {
const constants = new Map();
let changed = true;
while (changed) {
changed = false;
for (const statement of sourceFile.statements) {
if (!ts.isVariableStatement(statement)) continue;
if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
for (const declaration of statement.declarationList.declarations) {
if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
const value = constantString(declaration.initializer, constants);
if (value === null || constants.get(declaration.name.text) === value) continue;
constants.set(declaration.name.text, value);
changed = true;
}
}
}
return constants;
}
function moduleLoaderAliases(sourceFile) {
const aliases = new Set(["require"]);
let changed = true;
while (changed) {
changed = false;
for (const statement of sourceFile.statements) {
if (!ts.isVariableStatement(statement)) continue;
for (const declaration of statement.declarationList.declarations) {
if (
!ts.isIdentifier(declaration.name) ||
!declaration.initializer ||
!ts.isIdentifier(declaration.initializer) ||
!aliases.has(declaration.initializer.text) ||
aliases.has(declaration.name.text)
) {
continue;
}
aliases.add(declaration.name.text);
changed = true;
}
}
}
return aliases;
}
function constantString(expression, constants) {
if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) {
return expression.text;
}
if (ts.isIdentifier(expression)) return constants.get(expression.text) ?? null;
if (ts.isParenthesizedExpression(expression)) {
return constantString(expression.expression, constants);
}
if (
ts.isBinaryExpression(expression) &&
expression.operatorToken.kind === ts.SyntaxKind.PlusToken
) {
const left = constantString(expression.left, constants);
const right = constantString(expression.right, constants);
return left === null || right === null ? null : left + right;
}
if (ts.isTemplateExpression(expression)) {
let value = expression.head.text;
for (const span of expression.templateSpans) {
const substitution = constantString(span.expression, constants);
if (substitution === null) return null;
value += substitution + span.literal.text;
}
return value;
}
return null;
}
function isPublicEntryPoint(specifier) {
return /workspace-(?:runtime|helper)\/index\.(?:js|ts)$/.test(specifier);
}
@@ -125,6 +205,12 @@ function isHostCapability(specifier) {
function isForbiddenInternal(importer, specifier) {
const target = resolveSpecifier(importer, specifier);
if (!target || !target.includes("/internal/")) return false;
if (target.includes("/provider-probe/internal/")) {
return !(
importer.endsWith("/provider-probe/index.ts") ||
importer.includes("/provider-probe/internal/")
);
}
if (target.includes("/workspace-runtime/command/internal/")) {
return !(
importer.endsWith("/workspace-runtime/command/index.ts") ||
+38 -1
View File
@@ -88,7 +88,7 @@ test("the AST guard rejects computed loading and dynamic host/internal bypasses"
"module-entrypoint",
"nonliteral-module-load",
"nonliteral-module-load",
"nonliteral-module-load",
"workspace-host-access",
"workspace-host-access",
"workspace-host-access",
"workspace-host-access",
@@ -96,6 +96,36 @@ test("the AST guard rejects computed loading and dynamic host/internal bypasses"
);
});
test("the AST guard rejects every statically resolvable provider probe internal import", async (t) => {
const root = await fixtureRoot(t);
await source(
root,
"packages/server/src/server/session/computed.ts",
'import { createService as direct } from "../provider-probe/internal/service.js";\n' +
'import { createService as alias } from "@getpaseo/server/provider-probe/internal/service.js";\n' +
'export { createService } from "../provider-probe/internal/service.js";\n' +
'const internal = "../provider-probe/" + "internal/service.js";\n' +
"const load = require;\n" +
'void require("../provider-probe/internal/service.js");\n' +
'void import("../provider-probe/" + "internal/service.js");\n' +
'void import(`../provider-probe/${"internal"}/service.js`);\n' +
"void import(internal);\n" +
"void load(internal);\n" +
"void direct; void alias;\n",
);
const violations = await findWorkspaceBoundaryViolations(root);
assert.equal(violations.length, 8);
assert.deepEqual(new Set(violations.map(({ rule }) => rule)), new Set(["module-entrypoint"]));
assert.deepEqual(
new Set(violations.map((violation) => violation.import)),
new Set([
"../provider-probe/internal/service.js",
"@getpaseo/server/provider-probe/internal/service.js",
]),
);
});
test("owned integrations, explicit legacy code, and fixture contract imports pass", async (t) => {
const root = await fixtureRoot(t);
await copyFile(path.join(repoRoot, ".oxlintrc.json"), path.join(root, ".oxlintrc.json"));
@@ -104,6 +134,13 @@ test("owned integrations, explicit legacy code, and fixture contract imports pas
"packages/server/src/server/workspace-runtime/index.ts",
'import { service } from "./internal/service.js"; void service;\n',
);
await source(
root,
"packages/server/src/server/provider-probe/index.ts",
'import { createService } from "./internal/service.js";\n' +
'export { createProbeStore } from "./internal/probe-store.js";\n' +
"void createService;\n",
);
await source(
root,
"packages/server/src/server/workspace-runtime/command/index.ts",