clckernel 1.2.6 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +51 -118
- package/README.md +48 -116
- package/package.json +14 -2
- package/src/adapters/agent-os.js +183 -0
- package/src/catalog.js +16 -0
- package/src/detector.js +2 -0
- package/src/index.js +11 -0
- package/src/ui.js +79 -35
- package/tools/audit.js +0 -0
- package/tools/audit.py +0 -0
- package/tools/check_custom.js +0 -0
- package/tools/check_custom.py +0 -0
- package/tools/check_db_efficiency.py +0 -0
- package/tools/check_domain_data.js +100 -0
- package/tools/check_hitl.js +93 -0
- package/tools/check_responsive.js +0 -0
- package/tools/check_seo.js +1 -1
- package/tools/check_symlinks.js +76 -0
- package/tools/scan_secrets.js +12 -1
- package/tools/scan_secrets.py +0 -0
- package/AGENTS.md +0 -124
- package/docs/Journal/001-adr-clckernel-governance.md +0 -18
- package/test/adapters/astro.test.js +0 -102
- package/test/adapters/base.test.js +0 -86
- package/test/adapters/django.test.js +0 -95
- package/test/adapters/fastapi.test.js +0 -88
- package/test/adapters/go.test.js +0 -81
- package/test/adapters/laravel.test.js +0 -106
- package/test/adapters/nextjs.test.js +0 -113
- package/test/adapters/rails.test.js +0 -108
- package/test/adapters/rust.test.js +0 -83
- package/test/catalog.test.js +0 -170
- package/test/config.test.js +0 -512
- package/test/detector.test.js +0 -345
- package/test/doctor.test.js +0 -302
- package/test/generator.test.js +0 -419
- package/test/guards_new.test.js +0 -95
- package/test/helpers.js +0 -36
- package/test/integration/cli-flow.test.js +0 -270
- package/test/technologies/celery_guard.test.js +0 -185
- package/test/technologies/detector.test.js +0 -342
- package/test/technologies/docker_guard.test.js +0 -187
- package/test/technologies/integration.test.js +0 -123
- package/test/technologies/postgres_guard.test.js +0 -87
- package/test/technologies/redis_guard.test.js +0 -128
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
const { describe, it } = require('node:test');
|
|
2
|
-
const assert = require('node:assert');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const { execSync } = require('child_process');
|
|
6
|
-
const { createTmpProject, teardown } = require('../helpers');
|
|
7
|
-
|
|
8
|
-
const CLI_PATH = path.join(__dirname, '..', '..', 'bin', 'cli.js');
|
|
9
|
-
|
|
10
|
-
describe('Integration: Full CLI Flow', () => {
|
|
11
|
-
describe('runCli() doctor command', () => {
|
|
12
|
-
it('runs doctor and exits 0 on healthy project', () => {
|
|
13
|
-
const dir = createTmpProject({
|
|
14
|
-
'AGENTS.md': '# AGENTS\n',
|
|
15
|
-
'sdds/.gitkeep': '',
|
|
16
|
-
'docs/Journal/001-adr.md': '# ADR\n',
|
|
17
|
-
'tools/audit.js': 'module.exports = {};\n',
|
|
18
|
-
'tools/check_scan.js': 'module.exports = function() {};\n',
|
|
19
|
-
'.husky/pre-commit': '#!/usr/bin/env sh\necho test\n',
|
|
20
|
-
});
|
|
21
|
-
try {
|
|
22
|
-
const result = execSync(`node "${CLI_PATH}" doctor "${dir}"`, {
|
|
23
|
-
encoding: 'utf-8',
|
|
24
|
-
timeout: 15000,
|
|
25
|
-
});
|
|
26
|
-
assert.ok(result.includes('HEALTHY'), 'doctor should report HEALTHY');
|
|
27
|
-
assert.ok(result.includes('CLC KERNEL DOCTOR') || result.includes('CLC FORGE DOCTOR'), 'should show doctor header');
|
|
28
|
-
assert.ok(result.includes('[PASS]'), 'should show PASS checks');
|
|
29
|
-
} finally {
|
|
30
|
-
teardown(dir);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('runs doctor and reports issues on unhealthy project', () => {
|
|
35
|
-
const dir = createTmpProject({
|
|
36
|
-
'package.json': '{}',
|
|
37
|
-
});
|
|
38
|
-
try {
|
|
39
|
-
const result = execSync(`node "${CLI_PATH}" doctor "${dir}"`, {
|
|
40
|
-
encoding: 'utf-8',
|
|
41
|
-
timeout: 15000,
|
|
42
|
-
});
|
|
43
|
-
assert.ok(result.includes('[FAIL]'), 'doctor should report FAIL checks');
|
|
44
|
-
assert.ok(!result.includes('HEALTHY'), 'should not be HEALTHY');
|
|
45
|
-
assert.ok(result.includes('issue(s) detected'), 'should report issue count');
|
|
46
|
-
} finally {
|
|
47
|
-
teardown(dir);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('resolves target directory from second argument', () => {
|
|
52
|
-
const dir = createTmpProject({
|
|
53
|
-
'AGENTS.md': '# AGENTS\n',
|
|
54
|
-
'sdds/.gitkeep': '',
|
|
55
|
-
'docs/Journal/001-adr.md': '# ADR\n',
|
|
56
|
-
'tools/check_scan.js': 'module.exports = function() {};\n',
|
|
57
|
-
'.husky/pre-commit': '#!/usr/bin/env sh\necho test\n',
|
|
58
|
-
});
|
|
59
|
-
try {
|
|
60
|
-
const result = execSync(`node "${CLI_PATH}" doctor "${dir}"`, {
|
|
61
|
-
encoding: 'utf-8',
|
|
62
|
-
timeout: 15000,
|
|
63
|
-
});
|
|
64
|
-
// The output should show the target directory path
|
|
65
|
-
assert.ok(result.includes(dir), 'output should show target directory');
|
|
66
|
-
} finally {
|
|
67
|
-
teardown(dir);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('uses cwd when no directory argument is provided', () => {
|
|
72
|
-
// Create a healthy project in a temp dir and run from there
|
|
73
|
-
const dir = createTmpProject({
|
|
74
|
-
'AGENTS.md': '# AGENTS\n',
|
|
75
|
-
'sdds/.gitkeep': '',
|
|
76
|
-
'docs/Journal/001-adr.md': '# ADR\n',
|
|
77
|
-
'tools/check_scan.js': 'module.exports = function() {};\n',
|
|
78
|
-
'.husky/pre-commit': '#!/usr/bin/env sh\necho test\n',
|
|
79
|
-
});
|
|
80
|
-
try {
|
|
81
|
-
const result = execSync(`node "${CLI_PATH}" doctor`, {
|
|
82
|
-
encoding: 'utf-8',
|
|
83
|
-
timeout: 15000,
|
|
84
|
-
cwd: dir,
|
|
85
|
-
});
|
|
86
|
-
assert.ok(result.includes('HEALTHY'), 'doctor should use cwd');
|
|
87
|
-
assert.ok(result.includes(dir), 'should show cwd path');
|
|
88
|
-
} finally {
|
|
89
|
-
teardown(dir);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
describe('runCli() default flow (non-doctor)', () => {
|
|
95
|
-
it('resolves target directory from first argument', () => {
|
|
96
|
-
const dir = createTmpProject({
|
|
97
|
-
'package.json': JSON.stringify({ dependencies: { next: '14.0.0' } }),
|
|
98
|
-
});
|
|
99
|
-
try {
|
|
100
|
-
// The default flow will try to printBanner → autoDetectStack → promptOptions
|
|
101
|
-
// promptOptions reads stdin so it will hang — use timeout and check output
|
|
102
|
-
try {
|
|
103
|
-
execSync(`node "${CLI_PATH}" "${dir}"`, {
|
|
104
|
-
encoding: 'utf-8',
|
|
105
|
-
timeout: 3000,
|
|
106
|
-
input: '1\n',
|
|
107
|
-
});
|
|
108
|
-
} catch (e) {
|
|
109
|
-
// May exit non-zero due to prompt timeout, but we check the output
|
|
110
|
-
const output = e.stdout || e.stderr || '';
|
|
111
|
-
// Should at least detect the stack (Next.js)
|
|
112
|
-
assert.ok(output.length > 0, 'should produce output');
|
|
113
|
-
}
|
|
114
|
-
} finally {
|
|
115
|
-
teardown(dir);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('runCli() with --doctor flag', () => {
|
|
121
|
-
it('accepts --doctor flag as alternative to doctor command', () => {
|
|
122
|
-
const dir = createTmpProject({
|
|
123
|
-
'AGENTS.md': '# AGENTS\n',
|
|
124
|
-
'sdds/.gitkeep': '',
|
|
125
|
-
'docs/Journal/001-adr.md': '# ADR\n',
|
|
126
|
-
'tools/check_scan.js': 'module.exports = function() {};\n',
|
|
127
|
-
'.husky/pre-commit': '#!/usr/bin/env sh\necho test\n',
|
|
128
|
-
});
|
|
129
|
-
try {
|
|
130
|
-
const result = execSync(`node "${CLI_PATH}" --doctor "${dir}"`, {
|
|
131
|
-
encoding: 'utf-8',
|
|
132
|
-
timeout: 15000,
|
|
133
|
-
});
|
|
134
|
-
assert.ok(result.includes('HEALTHY'), '--doctor flag should run doctor');
|
|
135
|
-
assert.ok(result.includes('CLC KERNEL DOCTOR') || result.includes('CLC FORGE DOCTOR'), 'should show doctor header');
|
|
136
|
-
} finally {
|
|
137
|
-
teardown(dir);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('doctor detects all hook types', () => {
|
|
143
|
-
it('detects .githooks/pre-commit via CLI', () => {
|
|
144
|
-
const dir = createTmpProject({
|
|
145
|
-
'AGENTS.md': '# AGENTS\n',
|
|
146
|
-
'sdds/.gitkeep': '',
|
|
147
|
-
'docs/Journal/001-adr.md': '# ADR\n',
|
|
148
|
-
'tools/check_lint.py': 'def check():\n return True\n',
|
|
149
|
-
'.githooks/pre-commit': '#!/usr/bin/env bash\necho test\n',
|
|
150
|
-
});
|
|
151
|
-
try {
|
|
152
|
-
const result = execSync(`node "${CLI_PATH}" doctor "${dir}"`, {
|
|
153
|
-
encoding: 'utf-8',
|
|
154
|
-
timeout: 15000,
|
|
155
|
-
});
|
|
156
|
-
// .githooks should satisfy the pre-commit check
|
|
157
|
-
assert.ok(result.includes('[PASS]') && result.includes('pre-commit git hooks'), '.githooks should PASS');
|
|
158
|
-
} finally {
|
|
159
|
-
teardown(dir);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('validates Python tool parsing via CLI', () => {
|
|
164
|
-
const dir = createTmpProject({
|
|
165
|
-
'AGENTS.md': '# AGENTS\n',
|
|
166
|
-
'sdds/.gitkeep': '',
|
|
167
|
-
'docs/Journal/001-adr.md': '# ADR\n',
|
|
168
|
-
'tools/check_syntax.py': 'x = 1\n',
|
|
169
|
-
'.husky/pre-commit': '#!/usr/bin/env sh\necho test\n',
|
|
170
|
-
});
|
|
171
|
-
try {
|
|
172
|
-
const result = execSync(`node "${CLI_PATH}" doctor "${dir}"`, {
|
|
173
|
-
encoding: 'utf-8',
|
|
174
|
-
timeout: 15000,
|
|
175
|
-
});
|
|
176
|
-
assert.ok(result.includes('tool/check_syntax.py parses'), 'should validate Python tool');
|
|
177
|
-
assert.ok(result.includes('[PASS]') && result.includes('check_syntax.py parses'), 'valid Python should PASS');
|
|
178
|
-
} finally {
|
|
179
|
-
teardown(dir);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
describe('Integration: Component Composition', () => {
|
|
186
|
-
it('autoDetectStack + generateHarness creates valid project structure', () => {
|
|
187
|
-
const { autoDetectStack } = require('../../src/detector');
|
|
188
|
-
const { generateHarness } = require('../../src/generator');
|
|
189
|
-
|
|
190
|
-
const dir = createTmpProject({
|
|
191
|
-
'package.json': JSON.stringify({ dependencies: { next: '14.0.0' } }),
|
|
192
|
-
});
|
|
193
|
-
try {
|
|
194
|
-
const config = autoDetectStack(dir);
|
|
195
|
-
assert.strictEqual(config.framework, 'Next.js (App Router)', 'should detect Next.js');
|
|
196
|
-
|
|
197
|
-
generateHarness(dir, config);
|
|
198
|
-
|
|
199
|
-
// Verify all expected artifacts
|
|
200
|
-
assert.ok(fs.existsSync(path.join(dir, 'AGENTS.md')), 'AGENTS.md should exist');
|
|
201
|
-
assert.ok(fs.existsSync(path.join(dir, 'sdds')), 'sdds/ should exist');
|
|
202
|
-
assert.ok(fs.existsSync(path.join(dir, 'docs', 'Journal')), 'docs/Journal/ should exist');
|
|
203
|
-
assert.ok(fs.existsSync(path.join(dir, 'tools')), 'tools/ should exist');
|
|
204
|
-
assert.ok(fs.existsSync(path.join(dir, '.husky', 'pre-commit')), '.husky/pre-commit should exist');
|
|
205
|
-
|
|
206
|
-
// Verify AGENTS.md content
|
|
207
|
-
const agents = fs.readFileSync(path.join(dir, 'AGENTS.md'), 'utf-8');
|
|
208
|
-
assert.ok(agents.includes('Next.js'), 'AGENTS.md should mention Next.js');
|
|
209
|
-
assert.ok(agents.includes('FRONTEND'), 'AGENTS.md should mention FRONTEND');
|
|
210
|
-
} finally {
|
|
211
|
-
teardown(dir);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it('autoDetectStack fallback + generateHarness creates backend structure', () => {
|
|
216
|
-
const { autoDetectStack } = require('../../src/detector');
|
|
217
|
-
const { generateHarness } = require('../../src/generator');
|
|
218
|
-
|
|
219
|
-
const dir = createTmpProject({
|
|
220
|
-
'go.mod': 'module example.com\n\ngo 1.21\n',
|
|
221
|
-
});
|
|
222
|
-
try {
|
|
223
|
-
const config = autoDetectStack(dir);
|
|
224
|
-
assert.strictEqual(config.framework, 'Go (Golang)', 'should detect Go');
|
|
225
|
-
|
|
226
|
-
generateHarness(dir, config);
|
|
227
|
-
|
|
228
|
-
assert.ok(fs.existsSync(path.join(dir, 'AGENTS.md')), 'AGENTS.md should exist');
|
|
229
|
-
assert.ok(fs.existsSync(path.join(dir, 'sdds')), 'sdds/ should exist');
|
|
230
|
-
assert.ok(fs.existsSync(path.join(dir, '.githooks', 'pre-commit')), '.githooks/pre-commit should exist');
|
|
231
|
-
|
|
232
|
-
const agents = fs.readFileSync(path.join(dir, 'AGENTS.md'), 'utf-8');
|
|
233
|
-
assert.ok(agents.includes('Go'), 'AGENTS.md should mention Go');
|
|
234
|
-
assert.ok(agents.includes('BACKEND'), 'AGENTS.md should mention BACKEND');
|
|
235
|
-
} finally {
|
|
236
|
-
teardown(dir);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
it('detect → generate → doctor reports HEALTHY', () => {
|
|
241
|
-
const { autoDetectStack } = require('../../src/detector');
|
|
242
|
-
const { generateHarness } = require('../../src/generator');
|
|
243
|
-
const { runDoctor } = require('../../src/doctor');
|
|
244
|
-
|
|
245
|
-
const dir = createTmpProject({
|
|
246
|
-
'package.json': JSON.stringify({ dependencies: { next: '14.0.0' } }),
|
|
247
|
-
});
|
|
248
|
-
try {
|
|
249
|
-
// Step 1: Detect
|
|
250
|
-
const config = autoDetectStack(dir);
|
|
251
|
-
assert.strictEqual(config.framework, 'Next.js (App Router)');
|
|
252
|
-
|
|
253
|
-
// Step 2: Generate
|
|
254
|
-
generateHarness(dir, config);
|
|
255
|
-
|
|
256
|
-
// Step 3: Doctor should report HEALTHY
|
|
257
|
-
let capturedOutput = '';
|
|
258
|
-
const originalLog = console.log;
|
|
259
|
-
console.log = (...args) => { capturedOutput += args.join(' ') + '\n'; };
|
|
260
|
-
try {
|
|
261
|
-
runDoctor(dir);
|
|
262
|
-
assert.ok(capturedOutput.includes('HEALTHY'), 'after detect+generate, doctor should be HEALTHY');
|
|
263
|
-
} finally {
|
|
264
|
-
console.log = originalLog;
|
|
265
|
-
}
|
|
266
|
-
} finally {
|
|
267
|
-
teardown(dir);
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
});
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLC Forge — Celery guard integration tests.
|
|
3
|
-
* Tests celery_guard.py via subprocess against fixture projects.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { describe, it } = require('node:test');
|
|
7
|
-
const assert = require('node:assert');
|
|
8
|
-
const { spawn, spawnSync } = require('child_process');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const fs = require('fs');
|
|
11
|
-
const os = require('os');
|
|
12
|
-
const { createTmpProject, teardown } = require('../helpers');
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Run celery_guard.py against a target directory.
|
|
16
|
-
* Returns a promise resolving to the parsed JSON result.
|
|
17
|
-
*/
|
|
18
|
-
function runCeleryGuard(targetDir) {
|
|
19
|
-
return new Promise((resolve, reject) => {
|
|
20
|
-
const script = path.join(__dirname, '../../tools/celery_guard.py');
|
|
21
|
-
const proc = spawn('python3', [script, targetDir], { cwd: targetDir });
|
|
22
|
-
let stdout = '';
|
|
23
|
-
let stderr = '';
|
|
24
|
-
proc.stdout.on('data', (d) => (stdout += d));
|
|
25
|
-
proc.stderr.on('data', (d) => (stderr += d));
|
|
26
|
-
proc.on('close', (code) => {
|
|
27
|
-
try {
|
|
28
|
-
const result = JSON.parse(stdout);
|
|
29
|
-
resolve(result);
|
|
30
|
-
} catch {
|
|
31
|
-
reject(new Error(`Failed to parse guard output: ${stderr || stdout}`));
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
proc.on('error', reject);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Create a git repo in dir and commit an initial empty file.
|
|
40
|
-
*/
|
|
41
|
-
function initGitRepo(dir) {
|
|
42
|
-
fs.writeFileSync(path.join(dir, '.gitkeep'), '');
|
|
43
|
-
spawnSync('git', ['init'], { cwd: dir });
|
|
44
|
-
spawnSync('git', ['config', 'user.email', 'test@test.com'], { cwd: dir });
|
|
45
|
-
spawnSync('git', ['config', 'user.name', 'Test'], { cwd: dir });
|
|
46
|
-
spawnSync('git', ['add', '.'], { cwd: dir });
|
|
47
|
-
spawnSync('git', ['commit', '-m', 'initial'], { cwd: dir });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
describe('celery_guard', () => {
|
|
51
|
-
it('skips when no git diff is available (no git repo)', async () => {
|
|
52
|
-
const dir = createTmpProject({});
|
|
53
|
-
try {
|
|
54
|
-
const result = await runCeleryGuard(dir);
|
|
55
|
-
assert.strictEqual(result.skipped, true, 'should be skipped');
|
|
56
|
-
assert.strictEqual(result.name, 'celery_guard');
|
|
57
|
-
} finally {
|
|
58
|
-
teardown(dir);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('finds violations: hardcoded broker_url in Celery()', async () => {
|
|
63
|
-
const dir = createTmpProject({});
|
|
64
|
-
initGitRepo(dir);
|
|
65
|
-
|
|
66
|
-
// Create a new file with a violation
|
|
67
|
-
fs.writeFileSync(
|
|
68
|
-
path.join(dir, 'tasks.py'),
|
|
69
|
-
`from celery import Celery\napp = Celery("myapp", broker_url="redis://localhost")\n`
|
|
70
|
-
);
|
|
71
|
-
spawnSync('git', ['add', 'tasks.py'], { cwd: dir });
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
const result = await runCeleryGuard(dir);
|
|
75
|
-
assert.strictEqual(result.exit_code, 1, 'should exit with error code');
|
|
76
|
-
assert.strictEqual(result.skipped, false);
|
|
77
|
-
assert.ok(result.data.findings.length > 0, 'should have findings');
|
|
78
|
-
const issues = result.data.findings.map((f) => f.issue);
|
|
79
|
-
assert.ok(issues.includes('hardcoded_broker_url'), 'should detect hardcoded broker_url');
|
|
80
|
-
} finally {
|
|
81
|
-
teardown(dir);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('finds violations: hardcoded result_backend', async () => {
|
|
86
|
-
const dir = createTmpProject({});
|
|
87
|
-
initGitRepo(dir);
|
|
88
|
-
|
|
89
|
-
fs.writeFileSync(
|
|
90
|
-
path.join(dir, 'tasks.py'),
|
|
91
|
-
`from celery import Celery\napp = Celery(broker_url="redis://localhost", result_backend="redis://localhost")\n`
|
|
92
|
-
);
|
|
93
|
-
spawnSync('git', ['add', 'tasks.py'], { cwd: dir });
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const result = await runCeleryGuard(dir);
|
|
97
|
-
assert.strictEqual(result.exit_code, 1);
|
|
98
|
-
const issues = result.data.findings.map((f) => f.issue);
|
|
99
|
-
assert.ok(issues.includes('hardcoded_result_backend'), 'should detect hardcoded result_backend');
|
|
100
|
-
} finally {
|
|
101
|
-
teardown(dir);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('finds violations: Celery with both broker_url and result_backend', async () => {
|
|
106
|
-
const dir = createTmpProject({});
|
|
107
|
-
initGitRepo(dir);
|
|
108
|
-
|
|
109
|
-
fs.writeFileSync(
|
|
110
|
-
path.join(dir, 'tasks.py'),
|
|
111
|
-
`from celery import Celery\napp = Celery("myapp", broker_url="redis://localhost", result_backend="redis://localhost")\n`
|
|
112
|
-
);
|
|
113
|
-
spawnSync('git', ['add', 'tasks.py'], { cwd: dir });
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
const result = await runCeleryGuard(dir);
|
|
117
|
-
assert.strictEqual(result.exit_code, 1);
|
|
118
|
-
const issues = result.data.findings.map((f) => f.issue);
|
|
119
|
-
assert.ok(issues.includes('hardcoded_broker_url'), 'should detect hardcoded broker_url');
|
|
120
|
-
assert.ok(issues.includes('hardcoded_result_backend'), 'should detect hardcoded result_backend');
|
|
121
|
-
assert.strictEqual(result.data.findings.length, 2, 'should find both violations');
|
|
122
|
-
} finally {
|
|
123
|
-
teardown(dir);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('no violations: properly configured @shared_task with ignore_result=True', async () => {
|
|
128
|
-
const dir = createTmpProject({});
|
|
129
|
-
initGitRepo(dir);
|
|
130
|
-
|
|
131
|
-
fs.writeFileSync(
|
|
132
|
-
path.join(dir, 'tasks.py'),
|
|
133
|
-
`from celery import shared_task\n@shared_task(ignore_result=True)\ndef add(x, y):\n return x + y\n`
|
|
134
|
-
);
|
|
135
|
-
spawnSync('git', ['add', 'tasks.py'], { cwd: dir });
|
|
136
|
-
|
|
137
|
-
try {
|
|
138
|
-
const result = await runCeleryGuard(dir);
|
|
139
|
-
assert.strictEqual(result.exit_code, 0, 'should exit cleanly');
|
|
140
|
-
assert.strictEqual(result.skipped, false);
|
|
141
|
-
assert.strictEqual(result.data.findings.length, 0, 'should have no findings');
|
|
142
|
-
} finally {
|
|
143
|
-
teardown(dir);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('no violations: properly configured Celery without hardcoded URLs', async () => {
|
|
148
|
-
const dir = createTmpProject({});
|
|
149
|
-
initGitRepo(dir);
|
|
150
|
-
|
|
151
|
-
fs.writeFileSync(
|
|
152
|
-
path.join(dir, 'tasks.py'),
|
|
153
|
-
`import os\nfrom celery import Celery\napp = Celery("myapp")\napp.conf.broker_url = os.environ.get("BROKER_URL")\napp.conf.result_backend = os.environ.get("RESULT_BACKEND")\n`
|
|
154
|
-
);
|
|
155
|
-
spawnSync('git', ['add', 'tasks.py'], { cwd: dir });
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
const result = await runCeleryGuard(dir);
|
|
159
|
-
assert.strictEqual(result.exit_code, 0, 'should exit cleanly');
|
|
160
|
-
assert.strictEqual(result.data.findings.length, 0, 'should have no findings');
|
|
161
|
-
} finally {
|
|
162
|
-
teardown(dir);
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('no violations: no celery in project (empty findings)', async () => {
|
|
167
|
-
const dir = createTmpProject({});
|
|
168
|
-
initGitRepo(dir);
|
|
169
|
-
|
|
170
|
-
fs.writeFileSync(
|
|
171
|
-
path.join(dir, 'main.py'),
|
|
172
|
-
`def hello():\n return "world"\n`
|
|
173
|
-
);
|
|
174
|
-
spawnSync('git', ['add', 'main.py'], { cwd: dir });
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const result = await runCeleryGuard(dir);
|
|
178
|
-
assert.strictEqual(result.exit_code, 0, 'should exit cleanly');
|
|
179
|
-
assert.strictEqual(result.skipped, false);
|
|
180
|
-
assert.strictEqual(result.data.findings.length, 0, 'should have no findings');
|
|
181
|
-
} finally {
|
|
182
|
-
teardown(dir);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
});
|