review: harden readonly git checks and lint verification
This commit is contained in:
@@ -20,7 +20,7 @@ describe('verification helpers', () => {
|
||||
expect(isVerificationProfile('test')).toBe(true);
|
||||
expect(isVerificationProfile('typecheck')).toBe(true);
|
||||
expect(isVerificationProfile('build')).toBe(true);
|
||||
expect(isVerificationProfile('lint')).toBe(false);
|
||||
expect(isVerificationProfile('lint')).toBe(true);
|
||||
});
|
||||
|
||||
it('builds deterministic commands for each profile', () => {
|
||||
@@ -44,6 +44,49 @@ describe('verification helpers', () => {
|
||||
args: ['run', 'build'],
|
||||
requiredScript: 'build',
|
||||
});
|
||||
expect(buildVerificationCommand('lint', repoDir)).toMatchObject({
|
||||
file: 'npm',
|
||||
args: ['run', 'lint'],
|
||||
requiredScript: 'lint',
|
||||
});
|
||||
});
|
||||
|
||||
it('prefers lint:ci and lint:check before plain lint', () => {
|
||||
const repoDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), 'ejclaw-verification-lint-'),
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(repoDir, 'package.json'),
|
||||
JSON.stringify({
|
||||
scripts: {
|
||||
lint: 'eslint .',
|
||||
'lint:check': 'eslint --max-warnings 0 .',
|
||||
'lint:ci': 'eslint --format compact .',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(buildVerificationCommand('lint', repoDir)).toMatchObject({
|
||||
file: 'npm',
|
||||
args: ['run', 'lint:ci'],
|
||||
requiredScript: 'lint:ci',
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(repoDir, 'package.json'),
|
||||
JSON.stringify({
|
||||
scripts: {
|
||||
lint: 'eslint .',
|
||||
'lint:check': 'eslint --max-warnings 0 .',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(buildVerificationCommand('lint', repoDir)).toMatchObject({
|
||||
file: 'npm',
|
||||
args: ['run', 'lint:check'],
|
||||
requiredScript: 'lint:check',
|
||||
});
|
||||
});
|
||||
|
||||
it('selects the workspace package manager for verification commands', () => {
|
||||
@@ -250,6 +293,53 @@ describe('verification helpers', () => {
|
||||
expect(result.snapshotId).toBe(expectedSnapshotId);
|
||||
});
|
||||
|
||||
it('runs lint verification using the preferred lint script', async () => {
|
||||
const repoDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), 'ejclaw-verification-direct-lint-'),
|
||||
);
|
||||
fs.mkdirSync(path.join(repoDir, 'node_modules', '.bin'), {
|
||||
recursive: true,
|
||||
});
|
||||
fs.mkdirSync(path.join(repoDir, 'src'), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(repoDir, 'package.json'),
|
||||
JSON.stringify({
|
||||
name: 'verification-direct-lint',
|
||||
packageManager: 'bun@1.3.11',
|
||||
scripts: {
|
||||
'lint:check':
|
||||
"node -e \"process.stdout.write('lint-check:' + (process.env.CI || 'missing'))\"",
|
||||
},
|
||||
}),
|
||||
);
|
||||
fs.writeFileSync(path.join(repoDir, 'bun.lock'), '');
|
||||
fs.writeFileSync(
|
||||
path.join(repoDir, 'node_modules', '.bin', 'placeholder'),
|
||||
'',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(repoDir, 'src', 'index.ts'),
|
||||
'export const value = 1;\n',
|
||||
);
|
||||
ensureWorkspaceDependenciesInstalled(repoDir);
|
||||
|
||||
const expectedSnapshotId = computeVerificationSnapshot(repoDir).snapshotId;
|
||||
const result = await runVerificationRequest(
|
||||
{
|
||||
requestId: 'req-direct-lint',
|
||||
profile: 'lint',
|
||||
expectedSnapshotId,
|
||||
},
|
||||
{ repoDir },
|
||||
);
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.command).toContain('lint:check');
|
||||
expect(result.stdout).toContain('lint-check:1');
|
||||
expect(result.snapshotId).toBe(expectedSnapshotId);
|
||||
});
|
||||
|
||||
it('does not leak host secrets into direct verification commands', async () => {
|
||||
const repoDir = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), 'ejclaw-verification-direct-secret-'),
|
||||
|
||||
@@ -11,7 +11,12 @@ import {
|
||||
} from './workspace-package-manager.js';
|
||||
import { computeVerificationSnapshotId } from '../shared/verification-snapshot.js';
|
||||
|
||||
export const VERIFICATION_PROFILES = ['test', 'typecheck', 'build'] as const;
|
||||
export const VERIFICATION_PROFILES = [
|
||||
'test',
|
||||
'typecheck',
|
||||
'build',
|
||||
'lint',
|
||||
] as const;
|
||||
|
||||
export type VerificationProfile = (typeof VERIFICATION_PROFILES)[number];
|
||||
|
||||
@@ -91,12 +96,19 @@ export function buildVerificationCommand(
|
||||
profile: VerificationProfile,
|
||||
repoDir: string = process.cwd(),
|
||||
): VerificationCommandSpec {
|
||||
const scripts = readPackageScripts(repoDir);
|
||||
const scriptName =
|
||||
profile === 'test'
|
||||
? 'test'
|
||||
: profile === 'typecheck'
|
||||
? 'typecheck'
|
||||
: 'build';
|
||||
: profile === 'build'
|
||||
? 'build'
|
||||
: scripts['lint:ci']
|
||||
? 'lint:ci'
|
||||
: scripts['lint:check']
|
||||
? 'lint:check'
|
||||
: 'lint';
|
||||
const command = buildWorkspaceScriptCommand(repoDir, scriptName);
|
||||
return {
|
||||
file: command.file,
|
||||
|
||||
Reference in New Issue
Block a user