moving
This commit is contained in:
@@ -22,13 +22,157 @@
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { readFileSync, existsSync, statSync, readdirSync } from 'node:fs';
|
||||
import {
|
||||
copyFileSync,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
readFileSync,
|
||||
readdirSync,
|
||||
renameSync,
|
||||
rmSync,
|
||||
statSync,
|
||||
symlinkSync,
|
||||
writeFileSync,
|
||||
} from 'node:fs';
|
||||
import { execFileSync, spawnSync } from 'node:child_process';
|
||||
import { createHash } from 'node:crypto';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join, resolve } from 'node:path';
|
||||
|
||||
const REPO_ROOT = resolve(__dirname, '..');
|
||||
const SCRIPT_PATH = join(REPO_ROOT, 'scripts', 'oss-subtree-split.sh');
|
||||
const DRIFT_SCRIPT_PATH = join(REPO_ROOT, 'scripts', 'oss-drift-check.sh');
|
||||
const DRIFT_NODE_PATH = join(REPO_ROOT, 'scripts', 'oss-drift-check.mjs');
|
||||
const DRIFT_BASELINE_PATH = join(REPO_ROOT, 'scripts', 'oss-drift-baseline.json');
|
||||
const RETIRED_PARITY_SCRIPT_PATH = join(REPO_ROOT, 'scripts', 'parity-check.sh');
|
||||
const SUPERSEDED_PLAN_PATH = join(
|
||||
REPO_ROOT,
|
||||
'docs',
|
||||
'plans',
|
||||
'E-4-OSS-EXTRACTION-VERIFIED-2026-05-20.md',
|
||||
);
|
||||
const PACKAGES_DIR = join(REPO_ROOT, 'packages');
|
||||
|
||||
function normalizedDriftHash(content: string): string {
|
||||
return createHash('sha256')
|
||||
.update(content.replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n'), 'utf-8')
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
function commitFixtureRepo(repo: string): void {
|
||||
execFileSync('git', ['init', '--quiet'], { cwd: repo, stdio: 'ignore' });
|
||||
execFileSync('git', ['config', 'core.autocrlf', 'false'], { cwd: repo, stdio: 'ignore' });
|
||||
execFileSync('git', ['config', 'user.email', 'drift-test@example.invalid'], {
|
||||
cwd: repo,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
execFileSync('git', ['config', 'user.name', 'Drift Test'], { cwd: repo, stdio: 'ignore' });
|
||||
execFileSync('git', ['add', '--all'], { cwd: repo, stdio: 'ignore' });
|
||||
execFileSync('git', ['commit', '--quiet', '-m', 'fixture'], { cwd: repo, stdio: 'ignore' });
|
||||
}
|
||||
|
||||
function createDriftFixture() {
|
||||
const tempRoot = mkdtempSync(join(tmpdir(), 'waggle oss drift-'));
|
||||
const monoRepo = join(tempRoot, 'mono');
|
||||
const ossRepo = join(tempRoot, 'oss');
|
||||
const canonicalRoot = join(monoRepo, 'packages', 'hive-mind-core', 'src');
|
||||
const ossRoot = join(ossRepo, 'packages', 'core', 'src');
|
||||
const scriptsRoot = join(monoRepo, 'scripts');
|
||||
const canonicalAdaptation = "import { logger } from '@waggle/core';\n";
|
||||
const ossAdaptation = "import { logger } from './logger.js';\r\n";
|
||||
const baseline = {
|
||||
schemaVersion: 1,
|
||||
mapping: {
|
||||
canonical: 'packages/hive-mind-core/src',
|
||||
oss: 'packages/core/src',
|
||||
ignoredDirectories: ['dist', 'node_modules'],
|
||||
ignoredFileSuffixes: ['.test.ts', '.tsbuildinfo'],
|
||||
},
|
||||
parityPaths: [
|
||||
{
|
||||
path: 'equal.ts',
|
||||
sha256: normalizedDriftHash('export const equal = true;\n'),
|
||||
},
|
||||
],
|
||||
intentionalAdaptations: [
|
||||
{
|
||||
path: 'logger.ts',
|
||||
kinds: ['import', 'logger'],
|
||||
canonicalSha256: normalizedDriftHash(canonicalAdaptation),
|
||||
ossSha256: normalizedDriftHash(ossAdaptation),
|
||||
},
|
||||
],
|
||||
knownReviewedBlockers: [] as Array<Record<string, string>>,
|
||||
unreviewedDifferences: [] as Array<Record<string, string>>,
|
||||
forbiddenExports: {
|
||||
paths: [
|
||||
'mind/evolution-runs.ts',
|
||||
'mind/execution-traces.ts',
|
||||
'mind/improvement-signals.ts',
|
||||
],
|
||||
pathPrefixes: ['vault.ts', 'compliance/'],
|
||||
markers: [
|
||||
{ path: 'mind/db.ts', token: 'install_audit' },
|
||||
{ path: 'mind/schema.ts', token: 'install_audit' },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
mkdirSync(join(canonicalRoot, 'mind'), { recursive: true });
|
||||
mkdirSync(join(ossRoot, 'mind'), { recursive: true });
|
||||
mkdirSync(scriptsRoot, { recursive: true });
|
||||
copyFileSync(DRIFT_NODE_PATH, join(scriptsRoot, 'oss-drift-check.mjs'));
|
||||
writeFileSync(join(canonicalRoot, 'equal.ts'), 'export const equal = true;\n');
|
||||
writeFileSync(join(ossRoot, 'equal.ts'), 'export const equal = true;\r\n');
|
||||
writeFileSync(join(canonicalRoot, 'logger.ts'), canonicalAdaptation);
|
||||
writeFileSync(join(ossRoot, 'logger.ts'), ossAdaptation);
|
||||
writeFileSync(join(canonicalRoot, 'mind', 'evolution-runs.ts'), 'private implementation\n');
|
||||
|
||||
const writeBaseline = () =>
|
||||
writeFileSync(
|
||||
join(scriptsRoot, 'oss-drift-baseline.json'),
|
||||
`${JSON.stringify(baseline, null, 2)}\n`,
|
||||
);
|
||||
writeBaseline();
|
||||
commitFixtureRepo(monoRepo);
|
||||
commitFixtureRepo(ossRepo);
|
||||
|
||||
return {
|
||||
tempRoot,
|
||||
monoRepo,
|
||||
ossRepo,
|
||||
canonicalRoot,
|
||||
ossRoot,
|
||||
baseline,
|
||||
writeBaseline,
|
||||
run: () =>
|
||||
spawnSync(process.execPath, ['scripts/oss-drift-check.mjs', ossRepo], {
|
||||
cwd: monoRepo,
|
||||
encoding: 'utf-8',
|
||||
env: { ...process.env, OSS_HIVE_MIND_DIR: undefined },
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function resolveBashExecutable(): string {
|
||||
if (process.platform !== 'win32') return 'bash';
|
||||
|
||||
let current = resolve(execFileSync('git', ['--exec-path'], { encoding: 'utf-8' }).trim());
|
||||
for (let depth = 0; depth < 6; depth += 1) {
|
||||
for (const candidate of [
|
||||
join(current, 'bash.exe'),
|
||||
join(current, 'bin', 'bash.exe'),
|
||||
join(current, 'usr', 'bin', 'bash.exe'),
|
||||
]) {
|
||||
if (existsSync(candidate)) return candidate;
|
||||
}
|
||||
current = resolve(current, '..');
|
||||
}
|
||||
|
||||
throw new Error('Git Bash was not found relative to the active git.exe installation.');
|
||||
}
|
||||
|
||||
describe('oss-subtree-split.sh — static guards', () => {
|
||||
it('script exists at the documented path', () => {
|
||||
expect(existsSync(SCRIPT_PATH)).toBe(true);
|
||||
@@ -140,7 +284,400 @@ describe('oss-subtree-split.sh — package-level shape', () => {
|
||||
const pkg = JSON.parse(readFileSync(join(PACKAGES_DIR, name, 'package.json'), 'utf-8'));
|
||||
expect(
|
||||
pkg.license,
|
||||
`${name} must be Apache-2.0 to ship via the OSS subtree-split (matches the OSS repo's license).`,
|
||||
`${name} must be Apache-2.0 to participate in the curated OSS distribution.`,
|
||||
).toBe('Apache-2.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hive-mind publication boundary', () => {
|
||||
it('keeps the canonical monorepo core package private', () => {
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(join(PACKAGES_DIR, 'hive-mind-core', 'package.json'), 'utf-8'),
|
||||
);
|
||||
|
||||
expect(
|
||||
pkg.private,
|
||||
'The canonical package contains Waggle-only source and must never be published directly.',
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('routes mirror remediation through a curated forward-port, never a raw split push', () => {
|
||||
const splitScript = readFileSync(SCRIPT_PATH, 'utf-8');
|
||||
const driftScript = readFileSync(DRIFT_NODE_PATH, 'utf-8');
|
||||
|
||||
expect(splitScript).toContain('DO NOT push them raw');
|
||||
expect(splitScript).toContain('NOT OSS-publishable as-is');
|
||||
expect(driftScript).toContain('curated forward-port');
|
||||
expect(driftScript).not.toContain(
|
||||
'regenerate the mirror via scripts/oss-subtree-split.sh',
|
||||
);
|
||||
});
|
||||
|
||||
it('validates detached split commits before replacing named export branches', () => {
|
||||
const content = readFileSync(SCRIPT_PATH, 'utf-8');
|
||||
const splitAt = content.indexOf('CANDIDATE_SHA=$(git subtree split --prefix="$PREFIX" | tail -n 1)');
|
||||
const promoteAt = content.indexOf('git update-ref --stdin');
|
||||
|
||||
expect(content).not.toContain('git subtree split --prefix="$PREFIX" --branch=');
|
||||
expect(content).toContain('VALIDATED_BRANCHES+=("$BRANCH")');
|
||||
expect(content).toContain('EXPECTED_OLD_SHAS');
|
||||
expect(content).toContain('if ! WORKTREE_LIST=$(git worktree list --porcelain); then');
|
||||
expect(content).not.toMatch(/git worktree list --porcelain\s*\|/);
|
||||
expect(splitAt).toBeGreaterThan(-1);
|
||||
expect(promoteAt).toBeGreaterThan(splitAt);
|
||||
});
|
||||
|
||||
it('preserves the last validated ref and removes a rejected candidate', () => {
|
||||
const tempRepo = mkdtempSync(join(tmpdir(), 'waggle-oss-split-'));
|
||||
const bash = resolveBashExecutable();
|
||||
const runGit = (...args: string[]): string =>
|
||||
execFileSync('git', args, { cwd: tempRepo, encoding: 'utf-8' }).trim();
|
||||
|
||||
try {
|
||||
mkdirSync(join(tempRepo, 'packages', 'hive-mind-test', 'src'), { recursive: true });
|
||||
mkdirSync(join(tempRepo, 'packages', 'hive-mind-bad', 'src'), { recursive: true });
|
||||
mkdirSync(join(tempRepo, 'scripts'), { recursive: true });
|
||||
writeFileSync(join(tempRepo, 'packages', 'hive-mind-test', 'src', 'index.ts'), 'export {};\n');
|
||||
writeFileSync(join(tempRepo, 'packages', 'hive-mind-bad', 'src', 'index.ts'), 'export {};\n');
|
||||
copyFileSync(SCRIPT_PATH, join(tempRepo, 'scripts', 'oss-subtree-split.sh'));
|
||||
runGit('init');
|
||||
runGit('config', 'user.email', 'oss-guard@example.invalid');
|
||||
runGit('config', 'user.name', 'OSS Guard Test');
|
||||
runGit('add', '.');
|
||||
runGit('commit', '-m', 'initial safe package');
|
||||
|
||||
const first = spawnSync(
|
||||
bash,
|
||||
['scripts/oss-subtree-split.sh', 'hive-mind-test', 'hive-mind-bad'],
|
||||
{ cwd: tempRepo, encoding: 'utf-8' },
|
||||
);
|
||||
expect(first.status, first.stderr).toBe(0);
|
||||
const stableBefore = runGit('rev-parse', 'oss-hive-mind-test-export');
|
||||
const secondStableBefore = runGit('rev-parse', 'oss-hive-mind-bad-export');
|
||||
|
||||
writeFileSync(
|
||||
join(tempRepo, 'packages', 'hive-mind-test', 'src', 'index.ts'),
|
||||
'export const changed = true;\n',
|
||||
);
|
||||
mkdirSync(join(tempRepo, 'packages', 'hive-mind-bad', 'packages'), { recursive: true });
|
||||
writeFileSync(
|
||||
join(tempRepo, 'packages', 'hive-mind-bad', 'packages', 'leak.txt'),
|
||||
'must be rejected\n',
|
||||
);
|
||||
runGit('add', '.');
|
||||
runGit('commit', '-m', 'introduce forbidden top-level path');
|
||||
|
||||
const rejected = spawnSync(
|
||||
bash,
|
||||
['scripts/oss-subtree-split.sh', 'hive-mind-test', 'hive-mind-bad'],
|
||||
{ cwd: tempRepo, encoding: 'utf-8' },
|
||||
);
|
||||
expect(rejected.status, rejected.stderr).toBe(2);
|
||||
expect(runGit('rev-parse', 'oss-hive-mind-test-export')).toBe(stableBefore);
|
||||
expect(runGit('rev-parse', 'oss-hive-mind-bad-export')).toBe(secondStableBefore);
|
||||
expect(runGit('branch', '--list', '*-candidate-*')).toBe('');
|
||||
|
||||
const missingPackage = spawnSync(
|
||||
bash,
|
||||
['scripts/oss-subtree-split.sh', 'hive-mind-missing'],
|
||||
{ cwd: tempRepo, encoding: 'utf-8' },
|
||||
);
|
||||
expect(missingPackage.status, missingPackage.stderr).toBe(2);
|
||||
expect(runGit('rev-parse', 'oss-hive-mind-test-export')).toBe(stableBefore);
|
||||
|
||||
rmSync(join(tempRepo, 'packages', 'hive-mind-bad', 'packages'), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
writeFileSync(
|
||||
join(tempRepo, 'packages', 'hive-mind-bad', 'src', 'index.ts'),
|
||||
'export const changedToo = true;\n',
|
||||
);
|
||||
runGit('add', '.');
|
||||
runGit('commit', '-m', 'make both candidates safe');
|
||||
|
||||
const blockedRefLock = join(
|
||||
tempRepo,
|
||||
'.git',
|
||||
'refs',
|
||||
'heads',
|
||||
'oss-hive-mind-bad-export.lock',
|
||||
);
|
||||
writeFileSync(blockedRefLock, 'locked\n');
|
||||
const rejectedTransaction = spawnSync(
|
||||
bash,
|
||||
['scripts/oss-subtree-split.sh', 'hive-mind-test', 'hive-mind-bad'],
|
||||
{ cwd: tempRepo, encoding: 'utf-8' },
|
||||
);
|
||||
expect(rejectedTransaction.status, rejectedTransaction.stderr).toBe(4);
|
||||
expect(runGit('rev-parse', 'oss-hive-mind-test-export')).toBe(stableBefore);
|
||||
expect(runGit('rev-parse', 'oss-hive-mind-bad-export')).toBe(secondStableBefore);
|
||||
} finally {
|
||||
rmSync(tempRepo, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('invalidates the historical raw-push plan', () => {
|
||||
const content = readFileSync(SUPERSEDED_PLAN_PATH, 'utf-8');
|
||||
|
||||
expect(content).toContain('SUPERSEDED');
|
||||
expect(content).toContain('DO NOT FOLLOW');
|
||||
expect(content).not.toMatch(/git push\s/);
|
||||
});
|
||||
|
||||
it('uses Node as the primary drift checker and keeps the shell entrypoint thin', () => {
|
||||
const wrapper = readFileSync(DRIFT_SCRIPT_PATH, 'utf-8');
|
||||
const checker = readFileSync(DRIFT_NODE_PATH, 'utf-8');
|
||||
|
||||
expect(wrapper).toContain('oss-drift-check.mjs');
|
||||
expect(wrapper).not.toMatch(/\b(find|awk|comm|diff)\b/);
|
||||
expect(checker).toContain('KNOWN REVIEWED BLOCKERS');
|
||||
expect(checker).toContain('UNREVIEWED DIFFERENCES');
|
||||
expect(checker).toContain('FORBIDDEN EXPORTS');
|
||||
});
|
||||
|
||||
it('pins parity and reviewed adaptations without storing proprietary source', () => {
|
||||
const baseline = JSON.parse(readFileSync(DRIFT_BASELINE_PATH, 'utf-8')) as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
const serializedBaseline = JSON.stringify(baseline);
|
||||
|
||||
expect(serializedBaseline.match(/[Ss]ha256/g)).toHaveLength(
|
||||
((baseline.intentionalAdaptations as unknown[])?.length ?? 0) * 2 +
|
||||
((baseline.parityPaths as unknown[])?.length ?? 0),
|
||||
);
|
||||
expect(serializedBaseline).not.toMatch(/"(content|source|excerpt)"\s*:/);
|
||||
});
|
||||
|
||||
it('accepts only the exact reviewed adaptation and intentional exclusion state', () => {
|
||||
const fixture = createDriftFixture();
|
||||
try {
|
||||
const clean = fixture.run();
|
||||
expect(clean.status, `${clean.stdout}\n${clean.stderr}`).toBe(0);
|
||||
expect(clean.stdout).toContain('REVIEWED ADAPTATIONS: 1');
|
||||
expect(clean.stdout).toContain('INTENTIONAL OSS EXCLUSIONS: 1');
|
||||
|
||||
writeFileSync(join(fixture.canonicalRoot, 'equal.ts'), 'export const changed = true;\n');
|
||||
writeFileSync(join(fixture.ossRoot, 'equal.ts'), 'export const changed = true;\n');
|
||||
const changedParity = fixture.run();
|
||||
expect(changedParity.status, changedParity.stderr).toBe(1);
|
||||
expect(changedParity.stdout).toContain('equal.ts');
|
||||
|
||||
writeFileSync(join(fixture.canonicalRoot, 'equal.ts'), 'export const equal = true;\n');
|
||||
writeFileSync(join(fixture.ossRoot, 'equal.ts'), 'export const equal = true;\r\n');
|
||||
writeFileSync(join(fixture.ossRoot, 'logger.ts'), 'changed after review\n');
|
||||
const changedHash = fixture.run();
|
||||
expect(changedHash.status, changedHash.stderr).toBe(1);
|
||||
expect(changedHash.stdout).toContain('UNREVIEWED DIFFERENCES');
|
||||
expect(changedHash.stdout).toContain('logger.ts');
|
||||
} finally {
|
||||
rmSync(fixture.tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('separates known blockers, new differences, and forbidden exports', () => {
|
||||
const fixture = createDriftFixture();
|
||||
try {
|
||||
writeFileSync(join(fixture.canonicalRoot, 'blocker.ts'), 'canonical\n');
|
||||
writeFileSync(join(fixture.ossRoot, 'blocker.ts'), 'oss\n');
|
||||
fixture.baseline.knownReviewedBlockers.push({
|
||||
path: 'blocker.ts',
|
||||
state: 'different',
|
||||
disposition: 'forward-port',
|
||||
});
|
||||
fixture.writeBaseline();
|
||||
const blocker = fixture.run();
|
||||
expect(blocker.status, blocker.stderr).toBe(1);
|
||||
expect(blocker.stdout).toContain('KNOWN REVIEWED BLOCKERS');
|
||||
expect(blocker.stdout).toContain('blocker.ts');
|
||||
|
||||
writeFileSync(join(fixture.canonicalRoot, 'listed-unreviewed.ts'), 'canonical\n');
|
||||
writeFileSync(join(fixture.ossRoot, 'listed-unreviewed.ts'), 'oss\n');
|
||||
fixture.baseline.unreviewedDifferences.push({
|
||||
path: 'listed-unreviewed.ts',
|
||||
state: 'different',
|
||||
});
|
||||
fixture.writeBaseline();
|
||||
const listedUnreviewed = fixture.run();
|
||||
expect(listedUnreviewed.status, listedUnreviewed.stderr).toBe(1);
|
||||
expect(listedUnreviewed.stdout).toContain('listed-unreviewed.ts');
|
||||
|
||||
writeFileSync(join(fixture.ossRoot, 'new-drift.ts'), 'unreviewed\n');
|
||||
const unreviewed = fixture.run();
|
||||
expect(unreviewed.status, unreviewed.stderr).toBe(1);
|
||||
expect(unreviewed.stdout).toContain('UNREVIEWED DIFFERENCES');
|
||||
expect(unreviewed.stdout).toContain('new-drift.ts');
|
||||
|
||||
writeFileSync(
|
||||
join(fixture.ossRoot, 'mind', 'evolution-runs.ts'),
|
||||
'forbidden implementation\n',
|
||||
);
|
||||
writeFileSync(join(fixture.ossRoot, 'mind', 'db.ts'), 'const install_audit = true;\n');
|
||||
const forbidden = fixture.run();
|
||||
expect(forbidden.status, forbidden.stderr).toBe(1);
|
||||
expect(forbidden.stdout).toContain('FORBIDDEN EXPORTS');
|
||||
expect(forbidden.stdout).toContain('FORBIDDEN-OSS-CONTENT');
|
||||
expect(forbidden.stdout).toContain('FORBIDDEN-OSS-MARKER');
|
||||
|
||||
rmSync(join(fixture.ossRoot, 'mind', 'evolution-runs.ts'));
|
||||
writeFileSync(join(fixture.ossRoot, 'mind', 'db.ts'), '// install_audit is private\n');
|
||||
const commentMention = fixture.run();
|
||||
expect(commentMention.status, commentMention.stderr).toBe(1);
|
||||
expect(commentMention.stdout).toContain('FORBIDDEN-OSS-MARKER');
|
||||
|
||||
writeFileSync(
|
||||
join(fixture.ossRoot, 'mind', 'db.ts'),
|
||||
'/* install_audit is private */ const install_audit = true;\n',
|
||||
);
|
||||
const afterClosedComment = fixture.run();
|
||||
expect(afterClosedComment.status, afterClosedComment.stderr).toBe(1);
|
||||
expect(afterClosedComment.stdout).toContain('FORBIDDEN-OSS-MARKER');
|
||||
|
||||
for (const source of [
|
||||
'const INSTALL_AUDIT = true;\n',
|
||||
'// decoy\u2028const install_audit = true;\n',
|
||||
'// decoy\u2029const install_audit = true;\n',
|
||||
'const matcher = /[//]/; const INSTALL_AUDIT = true;\n',
|
||||
'const matcher = /[/*]/; const install_audit = true;\n',
|
||||
'const sql = `\n// install_audit\n`;\n',
|
||||
'const sql = "\\\n// install_audit";\n',
|
||||
]) {
|
||||
writeFileSync(join(fixture.ossRoot, 'mind', 'db.ts'), source);
|
||||
const bypassAttempt = fixture.run();
|
||||
expect(bypassAttempt.status, bypassAttempt.stderr).toBe(1);
|
||||
expect(bypassAttempt.stdout).toContain('FORBIDDEN-OSS-MARKER');
|
||||
}
|
||||
} finally {
|
||||
rmSync(fixture.tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('returns configuration error for a non-worktree or any mapped symlink', () => {
|
||||
const fixture = createDriftFixture();
|
||||
try {
|
||||
const plainDirectory = join(fixture.tempRoot, 'plain');
|
||||
mkdirSync(join(plainDirectory, 'packages', 'core', 'src'), { recursive: true });
|
||||
writeFileSync(join(plainDirectory, 'packages', 'core', 'src', 'file.ts'), 'export {};\n');
|
||||
const nonWorktree = spawnSync(
|
||||
process.execPath,
|
||||
['scripts/oss-drift-check.mjs', plainDirectory],
|
||||
{
|
||||
cwd: fixture.monoRepo,
|
||||
encoding: 'utf-8',
|
||||
env: { ...process.env, GIT_CEILING_DIRECTORIES: fixture.tempRoot },
|
||||
},
|
||||
);
|
||||
expect(nonWorktree.status).toBe(2);
|
||||
expect(nonWorktree.stderr).toContain('Git worktree');
|
||||
|
||||
const target = join(fixture.canonicalRoot, 'junction-target');
|
||||
mkdirSync(target);
|
||||
symlinkSync(
|
||||
target,
|
||||
join(fixture.canonicalRoot, 'mapped-link'),
|
||||
process.platform === 'win32' ? 'junction' : 'dir',
|
||||
);
|
||||
const symlink = fixture.run();
|
||||
expect(symlink.status, symlink.stdout).toBe(2);
|
||||
expect(symlink.stderr).toContain('symlink');
|
||||
|
||||
rmSync(join(fixture.canonicalRoot, 'mapped-link'), { recursive: true, force: true });
|
||||
const ossTarget = join(fixture.ossRoot, 'junction-target');
|
||||
mkdirSync(ossTarget);
|
||||
symlinkSync(
|
||||
ossTarget,
|
||||
join(fixture.ossRoot, 'mapped-link'),
|
||||
process.platform === 'win32' ? 'junction' : 'dir',
|
||||
);
|
||||
const ossSymlink = fixture.run();
|
||||
expect(ossSymlink.status, ossSymlink.stdout).toBe(2);
|
||||
expect(ossSymlink.stderr).toContain('symlink');
|
||||
|
||||
rmSync(join(fixture.ossRoot, 'mapped-link'), { recursive: true, force: true });
|
||||
writeFileSync(join(fixture.canonicalRoot, 'CaseCollision.ts'), 'canonical\n');
|
||||
writeFileSync(join(fixture.ossRoot, 'casecollision.ts'), 'oss\n');
|
||||
const caseCollision = fixture.run();
|
||||
expect(caseCollision.status, caseCollision.stdout).toBe(2);
|
||||
expect(caseCollision.stderr).toContain('case collision');
|
||||
} finally {
|
||||
rmSync(fixture.tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it.each(['canonical', 'oss'] as const)(
|
||||
'rejects a symlink in the %s mapped-path ancestry',
|
||||
(side) => {
|
||||
const fixture = createDriftFixture();
|
||||
try {
|
||||
const mappedPackage =
|
||||
side === 'canonical'
|
||||
? join(fixture.monoRepo, 'packages', 'hive-mind-core')
|
||||
: join(fixture.ossRepo, 'packages', 'core');
|
||||
const outsidePackage = join(fixture.tempRoot, `${side}-outside-package`);
|
||||
renameSync(mappedPackage, outsidePackage);
|
||||
symlinkSync(
|
||||
outsidePackage,
|
||||
mappedPackage,
|
||||
process.platform === 'win32' ? 'junction' : 'dir',
|
||||
);
|
||||
|
||||
const result = fixture.run();
|
||||
expect(result.status, result.stdout).toBe(2);
|
||||
expect(result.stderr).toContain('ancestor symlink');
|
||||
} finally {
|
||||
rmSync(fixture.tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it('rejects baseline policy tampering and unknown schema fields', () => {
|
||||
const fixture = createDriftFixture();
|
||||
try {
|
||||
fixture.baseline.forbiddenExports.paths.pop();
|
||||
fixture.writeBaseline();
|
||||
const weakenedPolicy = fixture.run();
|
||||
expect(weakenedPolicy.status).toBe(2);
|
||||
expect(weakenedPolicy.stderr).toContain('forbiddenExports.paths');
|
||||
|
||||
fixture.baseline.forbiddenExports.paths.push('mind/improvement-signals.ts');
|
||||
const malformed = fixture.baseline as typeof fixture.baseline & { source?: string };
|
||||
malformed.source = 'private source must never be accepted';
|
||||
fixture.writeBaseline();
|
||||
const extraField = fixture.run();
|
||||
expect(extraField.status).toBe(2);
|
||||
expect(extraField.stderr).toContain('unexpected keys');
|
||||
} finally {
|
||||
rmSync(fixture.tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('blocks dirty mapped bytes even when the editable baseline is changed to match them', () => {
|
||||
const fixture = createDriftFixture();
|
||||
try {
|
||||
const changedCanonical = "import { logger } from '@waggle/changed';\n";
|
||||
const changedOss = "import { logger } from './changed.js';\n";
|
||||
writeFileSync(join(fixture.canonicalRoot, 'logger.ts'), changedCanonical);
|
||||
writeFileSync(join(fixture.ossRoot, 'logger.ts'), changedOss);
|
||||
fixture.baseline.intentionalAdaptations[0].canonicalSha256 =
|
||||
normalizedDriftHash(changedCanonical);
|
||||
fixture.baseline.intentionalAdaptations[0].ossSha256 = normalizedDriftHash(changedOss);
|
||||
fixture.writeBaseline();
|
||||
|
||||
const tampered = fixture.run();
|
||||
expect(tampered.status, tampered.stderr).toBe(1);
|
||||
expect(tampered.stdout).toContain('SCOPED-DIRTY canonical');
|
||||
expect(tampered.stdout).toContain('SCOPED-DIRTY OSS');
|
||||
} finally {
|
||||
rmSync(fixture.tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('fails closed instead of executing the retired pre-migration parity workflow', () => {
|
||||
const content = readFileSync(RETIRED_PARITY_SCRIPT_PATH, 'utf-8');
|
||||
|
||||
expect(content).toContain('RETIRED');
|
||||
expect(content).toContain('exit 2');
|
||||
expect(content).not.toContain('packages/core/src/mind');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user