repo-cloak-cli 1.2.4 → 1.3.2
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/.github/workflows/release.yml +92 -92
- package/LICENSE +21 -21
- package/README.md +138 -118
- package/bin/repo-cloak.js +9 -9
- package/package.json +50 -50
- package/src/cli.js +86 -84
- package/src/commands/pull.js +582 -352
- package/src/commands/push.js +250 -235
- package/src/core/anonymizer.js +128 -128
- package/src/core/copier.js +139 -139
- package/src/core/crypto.js +128 -128
- package/src/core/git.js +61 -0
- package/src/core/mapper.js +235 -235
- package/src/core/scanner.js +137 -137
- package/src/index.js +8 -8
- package/src/ui/banner.js +70 -70
- package/src/ui/fileSelector.js +256 -256
- package/src/ui/prompts.js +165 -165
- package/tests/anonymizer.test.js +127 -127
- package/tests/copier.test.js +94 -94
- package/tests/crypto.test.js +106 -106
- package/tests/git.test.js +103 -0
- package/tests/mapper.test.js +166 -166
- package/tests/scanner.test.js +100 -100
- package/medium.md +0 -319
package/tests/mapper.test.js
CHANGED
|
@@ -1,166 +1,166 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mapper Tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
createMapping,
|
|
8
|
-
saveMapping,
|
|
9
|
-
loadRawMapping,
|
|
10
|
-
mergeMapping,
|
|
11
|
-
hasMapping
|
|
12
|
-
} from '../src/core/mapper.js';
|
|
13
|
-
import { existsSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'fs';
|
|
14
|
-
import { join } from 'path';
|
|
15
|
-
import { tmpdir } from 'os';
|
|
16
|
-
|
|
17
|
-
describe('Mapper Module', () => {
|
|
18
|
-
let testDir;
|
|
19
|
-
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
testDir = join(tmpdir(), `repo-cloak-test-${Date.now()}`);
|
|
22
|
-
mkdirSync(testDir, { recursive: true });
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
afterEach(() => {
|
|
26
|
-
if (existsSync(testDir)) {
|
|
27
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('createMapping', () => {
|
|
32
|
-
it('should create a valid mapping object', () => {
|
|
33
|
-
const mapping = createMapping({
|
|
34
|
-
sourceDir: '/path/to/source',
|
|
35
|
-
destDir: '/path/to/dest',
|
|
36
|
-
replacements: [{ original: 'Test', replacement: 'Demo' }],
|
|
37
|
-
files: [{ original: 'file.js', cloaked: 'file.js' }]
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
expect(mapping.version).toBe('1.1.0');
|
|
41
|
-
expect(mapping.tool).toBe('repo-cloak');
|
|
42
|
-
expect(mapping.encrypted).toBe(true);
|
|
43
|
-
expect(mapping.files).toHaveLength(1);
|
|
44
|
-
expect(mapping.stats.totalFiles).toBe(1);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should encrypt sensitive data', () => {
|
|
48
|
-
const mapping = createMapping({
|
|
49
|
-
sourceDir: '/secret/path',
|
|
50
|
-
destDir: '/dest/path',
|
|
51
|
-
replacements: [{ original: 'SecretWord', replacement: 'Public' }],
|
|
52
|
-
files: [{ original: 'secret.js', cloaked: 'public.js' }]
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// Source path should be encrypted (contains :)
|
|
56
|
-
expect(mapping.source.path).toContain(':');
|
|
57
|
-
// Replacements original should be encrypted
|
|
58
|
-
expect(mapping.replacements[0].original).toContain(':');
|
|
59
|
-
expect(mapping.replacements[0].encrypted).toBe(true);
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe('saveMapping / loadRawMapping', () => {
|
|
64
|
-
it('should save and load mapping file', () => {
|
|
65
|
-
const mapping = {
|
|
66
|
-
version: '1.0.0',
|
|
67
|
-
files: [{ original: 'a.js', cloaked: 'b.js' }]
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
saveMapping(testDir, mapping);
|
|
71
|
-
|
|
72
|
-
expect(hasMapping(testDir)).toBe(true);
|
|
73
|
-
|
|
74
|
-
const loaded = loadRawMapping(testDir);
|
|
75
|
-
expect(loaded.version).toBe('1.0.0');
|
|
76
|
-
expect(loaded.files).toHaveLength(1);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should return null for non-existent mapping', () => {
|
|
80
|
-
const loaded = loadRawMapping('/non/existent/path');
|
|
81
|
-
expect(loaded).toBeNull();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('hasMapping', () => {
|
|
86
|
-
it('should return true when mapping exists', () => {
|
|
87
|
-
writeFileSync(join(testDir, '.repo-cloak-map.json'), '{}');
|
|
88
|
-
expect(hasMapping(testDir)).toBe(true);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should return false when mapping does not exist', () => {
|
|
92
|
-
expect(hasMapping(testDir)).toBe(false);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
describe('mergeMapping', () => {
|
|
97
|
-
it('should merge new files with existing mapping', () => {
|
|
98
|
-
const existing = {
|
|
99
|
-
version: '1.0.0',
|
|
100
|
-
files: [
|
|
101
|
-
{ original: 'a.js', cloaked: 'a.js' },
|
|
102
|
-
{ original: 'b.js', cloaked: 'b.js' }
|
|
103
|
-
],
|
|
104
|
-
stats: { totalFiles: 2 }
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const newFiles = [
|
|
108
|
-
{ original: 'c.js', cloaked: 'c.js' },
|
|
109
|
-
{ original: 'd.js', cloaked: 'd.js' }
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
const merged = mergeMapping(existing, newFiles);
|
|
113
|
-
|
|
114
|
-
expect(merged.files).toHaveLength(4);
|
|
115
|
-
expect(merged.stats.totalFiles).toBe(4);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should avoid duplicate files', () => {
|
|
119
|
-
const existing = {
|
|
120
|
-
version: '1.0.0',
|
|
121
|
-
files: [
|
|
122
|
-
{ original: 'a.js', cloaked: 'a.js' },
|
|
123
|
-
{ original: 'b.js', cloaked: 'b.js' }
|
|
124
|
-
],
|
|
125
|
-
stats: { totalFiles: 2 }
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const newFiles = [
|
|
129
|
-
{ original: 'b.js', cloaked: 'b.js' }, // Duplicate
|
|
130
|
-
{ original: 'c.js', cloaked: 'c.js' } // New
|
|
131
|
-
];
|
|
132
|
-
|
|
133
|
-
const merged = mergeMapping(existing, newFiles);
|
|
134
|
-
|
|
135
|
-
expect(merged.files).toHaveLength(3); // Not 4
|
|
136
|
-
expect(merged.stats.totalFiles).toBe(3);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('should track pull history', () => {
|
|
140
|
-
const existing = {
|
|
141
|
-
version: '1.0.0',
|
|
142
|
-
files: [],
|
|
143
|
-
stats: { totalFiles: 0 }
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const merged = mergeMapping(existing, [{ original: 'a.js', cloaked: 'a.js' }]);
|
|
147
|
-
|
|
148
|
-
expect(merged.pullHistory).toHaveLength(1);
|
|
149
|
-
expect(merged.pullHistory[0].filesAdded).toBe(1);
|
|
150
|
-
expect(merged.pullHistory[0].timestamp).toBeDefined();
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('should append to existing pull history', () => {
|
|
154
|
-
const existing = {
|
|
155
|
-
version: '1.0.0',
|
|
156
|
-
files: [{ original: 'a.js', cloaked: 'a.js' }],
|
|
157
|
-
stats: { totalFiles: 1 },
|
|
158
|
-
pullHistory: [{ timestamp: '2024-01-01', filesAdded: 1, totalFiles: 1 }]
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const merged = mergeMapping(existing, [{ original: 'b.js', cloaked: 'b.js' }]);
|
|
162
|
-
|
|
163
|
-
expect(merged.pullHistory).toHaveLength(2);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Mapper Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
import {
|
|
7
|
+
createMapping,
|
|
8
|
+
saveMapping,
|
|
9
|
+
loadRawMapping,
|
|
10
|
+
mergeMapping,
|
|
11
|
+
hasMapping
|
|
12
|
+
} from '../src/core/mapper.js';
|
|
13
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'fs';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import { tmpdir } from 'os';
|
|
16
|
+
|
|
17
|
+
describe('Mapper Module', () => {
|
|
18
|
+
let testDir;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
testDir = join(tmpdir(), `repo-cloak-test-${Date.now()}`);
|
|
22
|
+
mkdirSync(testDir, { recursive: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
if (existsSync(testDir)) {
|
|
27
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('createMapping', () => {
|
|
32
|
+
it('should create a valid mapping object', () => {
|
|
33
|
+
const mapping = createMapping({
|
|
34
|
+
sourceDir: '/path/to/source',
|
|
35
|
+
destDir: '/path/to/dest',
|
|
36
|
+
replacements: [{ original: 'Test', replacement: 'Demo' }],
|
|
37
|
+
files: [{ original: 'file.js', cloaked: 'file.js' }]
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
expect(mapping.version).toBe('1.1.0');
|
|
41
|
+
expect(mapping.tool).toBe('repo-cloak');
|
|
42
|
+
expect(mapping.encrypted).toBe(true);
|
|
43
|
+
expect(mapping.files).toHaveLength(1);
|
|
44
|
+
expect(mapping.stats.totalFiles).toBe(1);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should encrypt sensitive data', () => {
|
|
48
|
+
const mapping = createMapping({
|
|
49
|
+
sourceDir: '/secret/path',
|
|
50
|
+
destDir: '/dest/path',
|
|
51
|
+
replacements: [{ original: 'SecretWord', replacement: 'Public' }],
|
|
52
|
+
files: [{ original: 'secret.js', cloaked: 'public.js' }]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Source path should be encrypted (contains :)
|
|
56
|
+
expect(mapping.source.path).toContain(':');
|
|
57
|
+
// Replacements original should be encrypted
|
|
58
|
+
expect(mapping.replacements[0].original).toContain(':');
|
|
59
|
+
expect(mapping.replacements[0].encrypted).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('saveMapping / loadRawMapping', () => {
|
|
64
|
+
it('should save and load mapping file', () => {
|
|
65
|
+
const mapping = {
|
|
66
|
+
version: '1.0.0',
|
|
67
|
+
files: [{ original: 'a.js', cloaked: 'b.js' }]
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
saveMapping(testDir, mapping);
|
|
71
|
+
|
|
72
|
+
expect(hasMapping(testDir)).toBe(true);
|
|
73
|
+
|
|
74
|
+
const loaded = loadRawMapping(testDir);
|
|
75
|
+
expect(loaded.version).toBe('1.0.0');
|
|
76
|
+
expect(loaded.files).toHaveLength(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should return null for non-existent mapping', () => {
|
|
80
|
+
const loaded = loadRawMapping('/non/existent/path');
|
|
81
|
+
expect(loaded).toBeNull();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('hasMapping', () => {
|
|
86
|
+
it('should return true when mapping exists', () => {
|
|
87
|
+
writeFileSync(join(testDir, '.repo-cloak-map.json'), '{}');
|
|
88
|
+
expect(hasMapping(testDir)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should return false when mapping does not exist', () => {
|
|
92
|
+
expect(hasMapping(testDir)).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('mergeMapping', () => {
|
|
97
|
+
it('should merge new files with existing mapping', () => {
|
|
98
|
+
const existing = {
|
|
99
|
+
version: '1.0.0',
|
|
100
|
+
files: [
|
|
101
|
+
{ original: 'a.js', cloaked: 'a.js' },
|
|
102
|
+
{ original: 'b.js', cloaked: 'b.js' }
|
|
103
|
+
],
|
|
104
|
+
stats: { totalFiles: 2 }
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const newFiles = [
|
|
108
|
+
{ original: 'c.js', cloaked: 'c.js' },
|
|
109
|
+
{ original: 'd.js', cloaked: 'd.js' }
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
const merged = mergeMapping(existing, newFiles);
|
|
113
|
+
|
|
114
|
+
expect(merged.files).toHaveLength(4);
|
|
115
|
+
expect(merged.stats.totalFiles).toBe(4);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should avoid duplicate files', () => {
|
|
119
|
+
const existing = {
|
|
120
|
+
version: '1.0.0',
|
|
121
|
+
files: [
|
|
122
|
+
{ original: 'a.js', cloaked: 'a.js' },
|
|
123
|
+
{ original: 'b.js', cloaked: 'b.js' }
|
|
124
|
+
],
|
|
125
|
+
stats: { totalFiles: 2 }
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const newFiles = [
|
|
129
|
+
{ original: 'b.js', cloaked: 'b.js' }, // Duplicate
|
|
130
|
+
{ original: 'c.js', cloaked: 'c.js' } // New
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
const merged = mergeMapping(existing, newFiles);
|
|
134
|
+
|
|
135
|
+
expect(merged.files).toHaveLength(3); // Not 4
|
|
136
|
+
expect(merged.stats.totalFiles).toBe(3);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should track pull history', () => {
|
|
140
|
+
const existing = {
|
|
141
|
+
version: '1.0.0',
|
|
142
|
+
files: [],
|
|
143
|
+
stats: { totalFiles: 0 }
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const merged = mergeMapping(existing, [{ original: 'a.js', cloaked: 'a.js' }]);
|
|
147
|
+
|
|
148
|
+
expect(merged.pullHistory).toHaveLength(1);
|
|
149
|
+
expect(merged.pullHistory[0].filesAdded).toBe(1);
|
|
150
|
+
expect(merged.pullHistory[0].timestamp).toBeDefined();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should append to existing pull history', () => {
|
|
154
|
+
const existing = {
|
|
155
|
+
version: '1.0.0',
|
|
156
|
+
files: [{ original: 'a.js', cloaked: 'a.js' }],
|
|
157
|
+
stats: { totalFiles: 1 },
|
|
158
|
+
pullHistory: [{ timestamp: '2024-01-01', filesAdded: 1, totalFiles: 1 }]
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const merged = mergeMapping(existing, [{ original: 'b.js', cloaked: 'b.js' }]);
|
|
162
|
+
|
|
163
|
+
expect(merged.pullHistory).toHaveLength(2);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
package/tests/scanner.test.js
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Scanner Tests
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
-
import { getAllFiles, isBinaryFile } from '../src/core/scanner.js';
|
|
7
|
-
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'fs';
|
|
8
|
-
import { join } from 'path';
|
|
9
|
-
import { tmpdir } from 'os';
|
|
10
|
-
|
|
11
|
-
describe('Scanner Module', () => {
|
|
12
|
-
let testDir;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
testDir = join(tmpdir(), `repo-cloak-scanner-test-${Date.now()}`);
|
|
16
|
-
mkdirSync(testDir, { recursive: true });
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
if (existsSync(testDir)) {
|
|
21
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('getAllFiles', () => {
|
|
26
|
-
it('should find all files in directory', () => {
|
|
27
|
-
writeFileSync(join(testDir, 'a.js'), 'content');
|
|
28
|
-
writeFileSync(join(testDir, 'b.js'), 'content');
|
|
29
|
-
|
|
30
|
-
const files = getAllFiles(testDir);
|
|
31
|
-
|
|
32
|
-
expect(files).toHaveLength(2);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('should find files in nested directories', () => {
|
|
36
|
-
const nestedDir = join(testDir, 'src', 'components');
|
|
37
|
-
mkdirSync(nestedDir, { recursive: true });
|
|
38
|
-
|
|
39
|
-
writeFileSync(join(testDir, 'index.js'), 'content');
|
|
40
|
-
writeFileSync(join(nestedDir, 'Button.js'), 'content');
|
|
41
|
-
|
|
42
|
-
const files = getAllFiles(testDir);
|
|
43
|
-
|
|
44
|
-
expect(files).toHaveLength(2);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should ignore node_modules', () => {
|
|
48
|
-
const nodeModules = join(testDir, 'node_modules', 'package');
|
|
49
|
-
mkdirSync(nodeModules, { recursive: true });
|
|
50
|
-
|
|
51
|
-
writeFileSync(join(testDir, 'index.js'), 'content');
|
|
52
|
-
writeFileSync(join(nodeModules, 'index.js'), 'content');
|
|
53
|
-
|
|
54
|
-
const files = getAllFiles(testDir);
|
|
55
|
-
|
|
56
|
-
expect(files).toHaveLength(1);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should ignore .git directories', () => {
|
|
60
|
-
const gitDir = join(testDir, '.git', 'objects');
|
|
61
|
-
mkdirSync(gitDir, { recursive: true });
|
|
62
|
-
|
|
63
|
-
writeFileSync(join(testDir, 'index.js'), 'content');
|
|
64
|
-
writeFileSync(join(gitDir, 'abc123'), 'content');
|
|
65
|
-
|
|
66
|
-
const files = getAllFiles(testDir);
|
|
67
|
-
|
|
68
|
-
expect(files).toHaveLength(1);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should return empty array for empty directory', () => {
|
|
72
|
-
const files = getAllFiles(testDir);
|
|
73
|
-
expect(files).toHaveLength(0);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('isBinaryFile', () => {
|
|
78
|
-
it('should detect common binary extensions', () => {
|
|
79
|
-
expect(isBinaryFile('image.png')).toBe(true);
|
|
80
|
-
expect(isBinaryFile('image.jpg')).toBe(true);
|
|
81
|
-
expect(isBinaryFile('archive.zip')).toBe(true);
|
|
82
|
-
expect(isBinaryFile('doc.pdf')).toBe(true);
|
|
83
|
-
expect(isBinaryFile('lib.dll')).toBe(true);
|
|
84
|
-
expect(isBinaryFile('app.exe')).toBe(true);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should detect text files', () => {
|
|
88
|
-
expect(isBinaryFile('code.js')).toBe(false);
|
|
89
|
-
expect(isBinaryFile('style.css')).toBe(false);
|
|
90
|
-
expect(isBinaryFile('data.json')).toBe(false);
|
|
91
|
-
expect(isBinaryFile('README.md')).toBe(false);
|
|
92
|
-
expect(isBinaryFile('code.ts')).toBe(false);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should handle paths with directories', () => {
|
|
96
|
-
expect(isBinaryFile('/path/to/image.png')).toBe(true);
|
|
97
|
-
expect(isBinaryFile('src/components/Button.js')).toBe(false);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Scanner Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
6
|
+
import { getAllFiles, isBinaryFile } from '../src/core/scanner.js';
|
|
7
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { tmpdir } from 'os';
|
|
10
|
+
|
|
11
|
+
describe('Scanner Module', () => {
|
|
12
|
+
let testDir;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
testDir = join(tmpdir(), `repo-cloak-scanner-test-${Date.now()}`);
|
|
16
|
+
mkdirSync(testDir, { recursive: true });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
if (existsSync(testDir)) {
|
|
21
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('getAllFiles', () => {
|
|
26
|
+
it('should find all files in directory', () => {
|
|
27
|
+
writeFileSync(join(testDir, 'a.js'), 'content');
|
|
28
|
+
writeFileSync(join(testDir, 'b.js'), 'content');
|
|
29
|
+
|
|
30
|
+
const files = getAllFiles(testDir);
|
|
31
|
+
|
|
32
|
+
expect(files).toHaveLength(2);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should find files in nested directories', () => {
|
|
36
|
+
const nestedDir = join(testDir, 'src', 'components');
|
|
37
|
+
mkdirSync(nestedDir, { recursive: true });
|
|
38
|
+
|
|
39
|
+
writeFileSync(join(testDir, 'index.js'), 'content');
|
|
40
|
+
writeFileSync(join(nestedDir, 'Button.js'), 'content');
|
|
41
|
+
|
|
42
|
+
const files = getAllFiles(testDir);
|
|
43
|
+
|
|
44
|
+
expect(files).toHaveLength(2);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should ignore node_modules', () => {
|
|
48
|
+
const nodeModules = join(testDir, 'node_modules', 'package');
|
|
49
|
+
mkdirSync(nodeModules, { recursive: true });
|
|
50
|
+
|
|
51
|
+
writeFileSync(join(testDir, 'index.js'), 'content');
|
|
52
|
+
writeFileSync(join(nodeModules, 'index.js'), 'content');
|
|
53
|
+
|
|
54
|
+
const files = getAllFiles(testDir);
|
|
55
|
+
|
|
56
|
+
expect(files).toHaveLength(1);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should ignore .git directories', () => {
|
|
60
|
+
const gitDir = join(testDir, '.git', 'objects');
|
|
61
|
+
mkdirSync(gitDir, { recursive: true });
|
|
62
|
+
|
|
63
|
+
writeFileSync(join(testDir, 'index.js'), 'content');
|
|
64
|
+
writeFileSync(join(gitDir, 'abc123'), 'content');
|
|
65
|
+
|
|
66
|
+
const files = getAllFiles(testDir);
|
|
67
|
+
|
|
68
|
+
expect(files).toHaveLength(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should return empty array for empty directory', () => {
|
|
72
|
+
const files = getAllFiles(testDir);
|
|
73
|
+
expect(files).toHaveLength(0);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('isBinaryFile', () => {
|
|
78
|
+
it('should detect common binary extensions', () => {
|
|
79
|
+
expect(isBinaryFile('image.png')).toBe(true);
|
|
80
|
+
expect(isBinaryFile('image.jpg')).toBe(true);
|
|
81
|
+
expect(isBinaryFile('archive.zip')).toBe(true);
|
|
82
|
+
expect(isBinaryFile('doc.pdf')).toBe(true);
|
|
83
|
+
expect(isBinaryFile('lib.dll')).toBe(true);
|
|
84
|
+
expect(isBinaryFile('app.exe')).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should detect text files', () => {
|
|
88
|
+
expect(isBinaryFile('code.js')).toBe(false);
|
|
89
|
+
expect(isBinaryFile('style.css')).toBe(false);
|
|
90
|
+
expect(isBinaryFile('data.json')).toBe(false);
|
|
91
|
+
expect(isBinaryFile('README.md')).toBe(false);
|
|
92
|
+
expect(isBinaryFile('code.ts')).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should handle paths with directories', () => {
|
|
96
|
+
expect(isBinaryFile('/path/to/image.png')).toBe(true);
|
|
97
|
+
expect(isBinaryFile('src/components/Button.js')).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|