chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
const testFileDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const projectRoot = path.resolve(testFileDir, '..', '..');
|
||||
const checkerScript = path.join(projectRoot, 'scripts', 'tools', 'check-import-boundaries.js');
|
||||
|
||||
function writeFile(root: string, relPath: string, content: string) {
|
||||
const fullPath = path.join(root, relPath);
|
||||
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
||||
fs.writeFileSync(fullPath, content, 'utf8');
|
||||
}
|
||||
|
||||
function runChecker(tempProjectRoot: string) {
|
||||
return spawnSync('node', [checkerScript], {
|
||||
cwd: tempProjectRoot,
|
||||
env: {
|
||||
...process.env,
|
||||
QIMING_BOUNDARY_PROJECT_ROOT: tempProjectRoot,
|
||||
},
|
||||
encoding: 'utf8',
|
||||
});
|
||||
}
|
||||
|
||||
function withTempProject(assertion: (root: string) => void) {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'qiming-boundary-'));
|
||||
try {
|
||||
assertion(root);
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
describe('check-import-boundaries script', () => {
|
||||
it('passes for valid main/renderer separation', () => {
|
||||
withTempProject((root) => {
|
||||
writeFile(root, 'src/main/bootstrap/startup.ts', 'export const start = () => 1;\n');
|
||||
writeFile(root, 'src/main/main.ts', "import { start } from './bootstrap/startup';\nstart();\n");
|
||||
writeFile(root, 'src/renderer/services/core/api.ts', 'export const call = () => 1;\n');
|
||||
writeFile(
|
||||
root,
|
||||
'src/renderer/components/pages/Home.tsx',
|
||||
"import { call } from '@renderer/services/core/api';\nexport const Home = () => call();\n",
|
||||
);
|
||||
|
||||
const result = runChecker(root);
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stdout).toContain('Import boundary check passed.');
|
||||
});
|
||||
});
|
||||
|
||||
it('fails when renderer imports main code directly', () => {
|
||||
withTempProject((root) => {
|
||||
writeFile(root, 'src/main/bootstrap/startup.ts', 'export const start = () => 1;\n');
|
||||
writeFile(
|
||||
root,
|
||||
'src/renderer/components/pages/Home.tsx',
|
||||
"import { start } from '@main/bootstrap/startup';\nexport const Home = () => start();\n",
|
||||
);
|
||||
|
||||
const result = runChecker(root);
|
||||
expect(result.status).toBe(1);
|
||||
expect(result.stderr).toContain('[renderer-process-boundary]');
|
||||
});
|
||||
});
|
||||
|
||||
it('fails when importing bridge files', () => {
|
||||
withTempProject((root) => {
|
||||
writeFile(root, 'src/main/bootstrap/startup.ts', 'export const start = () => 1;\n');
|
||||
writeFile(root, 'src/main/startup.ts', "export * from './bootstrap/startup';\n");
|
||||
writeFile(root, 'src/main/main.ts', "import { start } from '@/main/startup';\nstart();\n");
|
||||
|
||||
const result = runChecker(root);
|
||||
expect(result.status).toBe(1);
|
||||
expect(result.stderr).toContain('[no-bridge-imports]');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,52 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { createRequire } from 'node:module';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
const testFileDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const projectRootByFs = path.resolve(testFileDir, '..', '..');
|
||||
const require = createRequire(import.meta.url);
|
||||
const { getProjectRoot, resolveFromProject } = require(path.join(
|
||||
projectRootByFs,
|
||||
'scripts',
|
||||
'utils',
|
||||
'project-paths.js',
|
||||
));
|
||||
|
||||
describe('scripts project path contracts', () => {
|
||||
it('resolves Electron client root correctly', () => {
|
||||
const root = getProjectRoot();
|
||||
expect(root).toBe(projectRootByFs);
|
||||
expect(fs.existsSync(path.join(root, 'package.json'))).toBe(true);
|
||||
expect(fs.existsSync(path.join(root, 'scripts'))).toBe(true);
|
||||
});
|
||||
|
||||
it('resolves resources and node_modules from project root', () => {
|
||||
expect(resolveFromProject('resources')).toBe(path.join(projectRootByFs, 'resources'));
|
||||
expect(resolveFromProject('node_modules')).toBe(path.join(projectRootByFs, 'node_modules'));
|
||||
});
|
||||
|
||||
it('keeps moved scripts wired to shared project-path helper', () => {
|
||||
const scripts = [
|
||||
'scripts/prepare/prepare-uv.js',
|
||||
'scripts/prepare/prepare-node.js',
|
||||
'scripts/prepare/prepare-git.js',
|
||||
'scripts/prepare/prepare-lanproxy.js',
|
||||
'scripts/build/sign-uv-mac.js',
|
||||
'scripts/build/dist-current-platform.js',
|
||||
'scripts/tools/check-startup-ports.js',
|
||||
'scripts/tools/generate-tray-icons.js',
|
||||
'scripts/tools/test-integrated-node.js',
|
||||
];
|
||||
|
||||
const legacyPattern = /path\.resolve\(__dirname,\s*'\.\.'\)/;
|
||||
|
||||
for (const relPath of scripts) {
|
||||
const fullPath = path.join(projectRootByFs, relPath);
|
||||
const content = fs.readFileSync(fullPath, 'utf8');
|
||||
expect(content).toContain('project-paths');
|
||||
expect(content).not.toMatch(legacyPattern);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
generateSandboxMatrixDocument,
|
||||
renderSandboxMatrixMarkdown,
|
||||
stringifySandboxMatrixJson,
|
||||
} from "@main/services/sandbox/sandboxMatrix";
|
||||
|
||||
const testFileDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const projectRoot = path.resolve(testFileDir, "..", "..");
|
||||
const repoRoot = path.resolve(projectRoot, "..", "..");
|
||||
|
||||
const docsDir = path.join(repoRoot, "docs");
|
||||
const jsonPath = path.join(docsDir, "sandbox-matrix.generated.json");
|
||||
const mdPath = path.join(docsDir, "sandbox-matrix.generated.md");
|
||||
|
||||
function ensureDir(dir: string): void {
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
describe("sandbox matrix artifact consistency", () => {
|
||||
it("should generate deterministic matrix artifacts and keep repository baseline in sync", () => {
|
||||
const doc = generateSandboxMatrixDocument();
|
||||
const generatedJson = stringifySandboxMatrixJson(doc);
|
||||
const generatedMd = renderSandboxMatrixMarkdown(doc);
|
||||
const writeMode = process.env.SANDBOX_MATRIX_WRITE === "1";
|
||||
|
||||
if (writeMode) {
|
||||
ensureDir(docsDir);
|
||||
fs.writeFileSync(jsonPath, generatedJson, "utf8");
|
||||
fs.writeFileSync(mdPath, generatedMd, "utf8");
|
||||
}
|
||||
|
||||
expect(fs.existsSync(jsonPath)).toBe(true);
|
||||
expect(fs.existsSync(mdPath)).toBe(true);
|
||||
|
||||
const baselineJson = fs.readFileSync(jsonPath, "utf8");
|
||||
const baselineMd = fs.readFileSync(mdPath, "utf8");
|
||||
|
||||
expect(baselineJson).toBe(generatedJson);
|
||||
expect(baselineMd).toBe(generatedMd);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
|
||||
const testFileDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const projectRoot = path.resolve(testFileDir, "..", "..");
|
||||
const modulePath = path.join(
|
||||
projectRoot,
|
||||
"scripts",
|
||||
"mcp",
|
||||
"sandboxed-bash-security.mjs",
|
||||
);
|
||||
|
||||
type SecurityModule = {
|
||||
buildSandboxHelperEnv: (
|
||||
baseEnv: Record<string, string>,
|
||||
sandboxPath?: string,
|
||||
) => Record<string, string>;
|
||||
resolveSandboxWorkingDirectory: (
|
||||
requestedCwd: string,
|
||||
sandboxMode: string,
|
||||
writableRoots: string[],
|
||||
) => string;
|
||||
};
|
||||
|
||||
let securityMod: SecurityModule;
|
||||
|
||||
beforeAll(async () => {
|
||||
securityMod = (await import(pathToFileURL(modulePath).href)) as SecurityModule;
|
||||
});
|
||||
|
||||
describe("sandboxed-bash security helpers", () => {
|
||||
it("should filter sensitive env vars and keep only safe env keys", () => {
|
||||
const env = securityMod.buildSandboxHelperEnv(
|
||||
{
|
||||
PATH: "C:\\Windows\\System32",
|
||||
TEMP: "C:\\Temp",
|
||||
HOME: "C:\\Users\\demo",
|
||||
COMSPEC: "C:\\Windows\\System32\\cmd.exe",
|
||||
PATHEXT: ".COM;.EXE;.BAT;.CMD",
|
||||
SystemDrive: "C:",
|
||||
ANTHROPIC_API_KEY: "secret-anthropic",
|
||||
OPENAI_API_KEY: "secret-openai",
|
||||
},
|
||||
"",
|
||||
);
|
||||
|
||||
expect(env.PATH).toBe("C:\\Windows\\System32");
|
||||
expect(env.TEMP).toBe("C:\\Temp");
|
||||
expect(env.HOME).toBe("C:\\Users\\demo");
|
||||
expect(env.COMSPEC).toBe("C:\\Windows\\System32\\cmd.exe");
|
||||
expect(env.PATHEXT).toBe(".COM;.EXE;.BAT;.CMD");
|
||||
expect(env.SystemDrive).toBe("C:");
|
||||
expect(env.ANTHROPIC_API_KEY).toBeUndefined();
|
||||
expect(env.OPENAI_API_KEY).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should prepend sandbox tool path to PATH", () => {
|
||||
const env = securityMod.buildSandboxHelperEnv(
|
||||
{
|
||||
PATH: "C:\\Windows\\System32",
|
||||
},
|
||||
"C:\\sandbox\\bin",
|
||||
);
|
||||
|
||||
expect(env.PATH.startsWith("C:\\sandbox\\bin;")).toBe(true);
|
||||
});
|
||||
|
||||
it("should fallback cwd to first writable root when outside workspace", () => {
|
||||
const root = path.resolve("/workspace/project");
|
||||
const outside = path.resolve("/outside/path");
|
||||
const cwd = securityMod.resolveSandboxWorkingDirectory(
|
||||
outside,
|
||||
"workspace-write",
|
||||
[root],
|
||||
);
|
||||
expect(cwd).toBe(root);
|
||||
});
|
||||
|
||||
it("should keep cwd unchanged when already inside writable root", () => {
|
||||
const root = path.resolve("/workspace/project");
|
||||
const inside = path.resolve("/workspace/project/subdir");
|
||||
const cwd = securityMod.resolveSandboxWorkingDirectory(
|
||||
inside,
|
||||
"workspace-write",
|
||||
[root],
|
||||
);
|
||||
expect(cwd).toBe(inside);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user