@productbrain/cli 0.1.0-beta.1768 → 0.1.0-beta.1774
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/dist/commands/files.d.ts +26 -0
- package/dist/commands/files.d.ts.map +1 -0
- package/dist/commands/files.js +160 -0
- package/dist/commands/files.js.map +1 -0
- package/dist/commands/files.test.d.ts +2 -0
- package/dist/commands/files.test.d.ts.map +1 -0
- package/dist/commands/files.test.js +243 -0
- package/dist/commands/files.test.js.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/productbrain-files.d.ts +94 -0
- package/dist/lib/productbrain-files.d.ts.map +1 -0
- package/dist/lib/productbrain-files.js +212 -0
- package/dist/lib/productbrain-files.js.map +1 -0
- package/dist/lib/productbrain-files.test.d.ts +2 -0
- package/dist/lib/productbrain-files.test.d.ts.map +1 -0
- package/dist/lib/productbrain-files.test.js +237 -0
- package/dist/lib/productbrain-files.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { classifyTree, DESCRIPTORS, resolvePbRoot, listProductbrainEntries, makeGitIgnoreChecker, detectExposures, planGitignoreLines, applyGitignoreFix } from './productbrain-files.js';
|
|
7
|
+
const find = (rows, path) => rows.find((r) => r.path === path);
|
|
8
|
+
describe('classifyTree (pure)', () => {
|
|
9
|
+
it('classifies a known pb-secret descriptor that is present and ignored', () => {
|
|
10
|
+
const rows = classifyTree({
|
|
11
|
+
presentEntries: ['config.local.json'],
|
|
12
|
+
isIgnored: () => true,
|
|
13
|
+
});
|
|
14
|
+
const row = find(rows, 'config.local.json');
|
|
15
|
+
expect(row.kind).toBe('pb-secret');
|
|
16
|
+
expect(row.present).toBe(true);
|
|
17
|
+
expect(row.gitignored).toBe(true);
|
|
18
|
+
expect(row.exposed).toBe(false);
|
|
19
|
+
expect(row.writer).toMatch(/connect/i);
|
|
20
|
+
});
|
|
21
|
+
it('marks a present pb-secret that is NOT ignored as exposed', () => {
|
|
22
|
+
const rows = classifyTree({
|
|
23
|
+
presentEntries: ['config.local.json'],
|
|
24
|
+
isIgnored: () => false,
|
|
25
|
+
});
|
|
26
|
+
expect(find(rows, 'config.local.json').exposed).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
it('shows absent descriptors as contract rows (present=false, not exposed)', () => {
|
|
29
|
+
const rows = classifyTree({ presentEntries: [], isIgnored: () => false });
|
|
30
|
+
const row = find(rows, 'preview.json');
|
|
31
|
+
expect(row.present).toBe(false);
|
|
32
|
+
expect(row.exposed).toBe(false); // never exposed when absent
|
|
33
|
+
});
|
|
34
|
+
it('classifies an unknown tracked (not-ignored) entry as committed', () => {
|
|
35
|
+
const rows = classifyTree({
|
|
36
|
+
presentEntries: ['soul.md'],
|
|
37
|
+
isIgnored: () => false,
|
|
38
|
+
});
|
|
39
|
+
expect(find(rows, 'soul.md').kind).toBe('committed');
|
|
40
|
+
});
|
|
41
|
+
it('FAILS OPEN: an unknown but gitignored entry is pb-owned (writer unknown), never committed', () => {
|
|
42
|
+
const rows = classifyTree({
|
|
43
|
+
presentEntries: ['mystery.json'],
|
|
44
|
+
isIgnored: () => true,
|
|
45
|
+
});
|
|
46
|
+
const row = find(rows, 'mystery.json');
|
|
47
|
+
expect(row.kind).toBe('pb-owned');
|
|
48
|
+
expect(row.writer).toMatch(/unknown/i);
|
|
49
|
+
});
|
|
50
|
+
it('git-absent (isIgnored returns null) → gitignored null, not exposed', () => {
|
|
51
|
+
const rows = classifyTree({
|
|
52
|
+
presentEntries: ['config.local.json'],
|
|
53
|
+
isIgnored: () => null,
|
|
54
|
+
});
|
|
55
|
+
const row = find(rows, 'config.local.json');
|
|
56
|
+
expect(row.gitignored).toBeNull();
|
|
57
|
+
expect(row.exposed).toBe(false); // cannot assert exposure without git
|
|
58
|
+
});
|
|
59
|
+
it('registry has the 12 known pb descriptors', () => {
|
|
60
|
+
expect(DESCRIPTORS).toHaveLength(12);
|
|
61
|
+
expect(DESCRIPTORS.map((d) => d.pattern)).toContain('.local/');
|
|
62
|
+
});
|
|
63
|
+
it('classifies .authoring-sync.json as pb-owned (present + not ignored → exposed)', () => {
|
|
64
|
+
const rows = classifyTree({ presentEntries: ['.authoring-sync.json'], isIgnored: () => false });
|
|
65
|
+
const row = rows.find((r) => r.path === '.authoring-sync.json');
|
|
66
|
+
expect(row.kind).toBe('pb-owned');
|
|
67
|
+
expect(row.exposed).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
it('an ABSENT descriptor that git already ignores is not exposed and not planned', () => {
|
|
70
|
+
// git ignores everything here, including absent contracted paths (wildcard / nested gitignore)
|
|
71
|
+
const rows = classifyTree({ presentEntries: [], isIgnored: () => true });
|
|
72
|
+
const local = rows.find((r) => r.path === '.local/');
|
|
73
|
+
expect(local.present).toBe(false);
|
|
74
|
+
expect(local.gitignored).toBe(true); // asked git even though absent
|
|
75
|
+
expect(planGitignoreLines(rows)).not.toContain('.productbrain/.local/'); // no redundant --fix line
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
function tmpRepo() {
|
|
79
|
+
const dir = mkdtempSync(join(tmpdir(), 'pbfiles-'));
|
|
80
|
+
execSync('git init -q', { cwd: dir });
|
|
81
|
+
mkdirSync(join(dir, '.productbrain'));
|
|
82
|
+
return dir;
|
|
83
|
+
}
|
|
84
|
+
describe('resolvePbRoot + adapters', () => {
|
|
85
|
+
it('resolves the git toplevel as root even from a subdir', () => {
|
|
86
|
+
const dir = tmpRepo();
|
|
87
|
+
try {
|
|
88
|
+
mkdirSync(join(dir, 'packages', 'cli'), { recursive: true });
|
|
89
|
+
const { root, git } = resolvePbRoot(join(dir, 'packages', 'cli'));
|
|
90
|
+
expect(git).toBe(true);
|
|
91
|
+
expect(root).toBe(execSync('git rev-parse --show-toplevel', { cwd: dir, encoding: 'utf8' }).trim());
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
rmSync(dir, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
it('lists present .productbrain entries, dirs suffixed with /', () => {
|
|
98
|
+
const dir = tmpRepo();
|
|
99
|
+
try {
|
|
100
|
+
writeFileSync(join(dir, '.productbrain', 'soul.md'), '#');
|
|
101
|
+
mkdirSync(join(dir, '.productbrain', 'drafts'));
|
|
102
|
+
const entries = listProductbrainEntries(dir);
|
|
103
|
+
expect(entries).toContain('soul.md');
|
|
104
|
+
expect(entries).toContain('drafts/');
|
|
105
|
+
}
|
|
106
|
+
finally {
|
|
107
|
+
rmSync(dir, { recursive: true, force: true });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
it('gitignore checker reports ignored vs not', () => {
|
|
111
|
+
const dir = tmpRepo();
|
|
112
|
+
try {
|
|
113
|
+
writeFileSync(join(dir, '.gitignore'), '.productbrain/config.local.json\n');
|
|
114
|
+
const isIgnored = makeGitIgnoreChecker(dir);
|
|
115
|
+
expect(isIgnored('.productbrain/config.local.json')).toBe(true);
|
|
116
|
+
expect(isIgnored('.productbrain/soul.md')).toBe(false);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
rmSync(dir, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
it('returns root null when no .productbrain is found (not a pb project)', () => {
|
|
123
|
+
const dir = mkdtempSync(join(tmpdir(), 'pbnone-')); // no git init, no .productbrain
|
|
124
|
+
try {
|
|
125
|
+
expect(resolvePbRoot(dir).root).toBeNull();
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
rmSync(dir, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
it('makeGitIgnoreChecker does NOT shell-execute a malicious filename (RCE guard)', () => {
|
|
132
|
+
const dir = tmpRepo();
|
|
133
|
+
try {
|
|
134
|
+
const evil = '$(touch pwned).md';
|
|
135
|
+
writeFileSync(join(dir, '.productbrain', evil), 'x');
|
|
136
|
+
const isIgnored = makeGitIgnoreChecker(dir);
|
|
137
|
+
isIgnored('.productbrain/' + evil); // must not evaluate the substitution
|
|
138
|
+
expect(existsSync(join(dir, 'pwned'))).toBe(false);
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
rmSync(dir, { recursive: true, force: true });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
it('resolvePbRoot reports isToplevel=true when git top carries .productbrain', () => {
|
|
145
|
+
const dir = tmpRepo(); // tmpRepo does git init + mkdir .productbrain
|
|
146
|
+
try {
|
|
147
|
+
expect(resolvePbRoot(dir).isToplevel).toBe(true);
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
rmSync(dir, { recursive: true, force: true });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
it('resolvePbRoot reports isToplevel=false outside a git repo', () => {
|
|
154
|
+
const dir = mkdtempSync(join(tmpdir(), 'pbnotop-')); // no git init
|
|
155
|
+
try {
|
|
156
|
+
expect(resolvePbRoot(dir).isToplevel).toBe(false);
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
rmSync(dir, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
describe('exposure + fix plan', () => {
|
|
164
|
+
const exposedSecret = { path: 'config.local.json', kind: 'pb-secret', writer: 'pb connect', when: '', present: true, gitignored: false, exposed: true };
|
|
165
|
+
const safeSecret = { ...exposedSecret, gitignored: true, exposed: false };
|
|
166
|
+
it('detectExposures flags exposed pb-secret as high severity', () => {
|
|
167
|
+
const ex = detectExposures([exposedSecret]);
|
|
168
|
+
expect(ex).toHaveLength(1);
|
|
169
|
+
expect(ex[0]).toMatchObject({ path: 'config.local.json', severity: 'high' });
|
|
170
|
+
});
|
|
171
|
+
it('detectExposures returns none when the secret is ignored', () => {
|
|
172
|
+
expect(detectExposures([safeSecret])).toHaveLength(0);
|
|
173
|
+
});
|
|
174
|
+
it('planGitignoreLines covers must/should not-yet-ignored descriptors, regardless of presence', () => {
|
|
175
|
+
// classify a tree where nothing is ignored and nothing present → all must/should should be planned.
|
|
176
|
+
const rows = classifyTree({ presentEntries: [], isIgnored: () => false });
|
|
177
|
+
const lines = planGitignoreLines(rows);
|
|
178
|
+
expect(lines).toContain('.productbrain/config.local.json');
|
|
179
|
+
expect(lines).toContain('.productbrain/session.json');
|
|
180
|
+
expect(lines).not.toContain('.productbrain/soul.md'); // committed, never planned
|
|
181
|
+
});
|
|
182
|
+
it('applyGitignoreFix is idempotent and appends only missing lines', () => {
|
|
183
|
+
const dir = tmpRepo();
|
|
184
|
+
try {
|
|
185
|
+
writeFileSync(join(dir, '.gitignore'), '.productbrain/config.local.json\n');
|
|
186
|
+
const res = applyGitignoreFix(dir, ['.productbrain/config.local.json', '.productbrain/session.json'], { dryRun: false });
|
|
187
|
+
expect(res.skipped).toContain('.productbrain/config.local.json');
|
|
188
|
+
expect(res.added).toContain('.productbrain/session.json');
|
|
189
|
+
const gi = readFileSync(join(dir, '.gitignore'), 'utf8');
|
|
190
|
+
expect(gi.match(/config\.local\.json/g)).toHaveLength(1); // not duplicated
|
|
191
|
+
expect(gi).toContain('.productbrain/session.json');
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
rmSync(dir, { recursive: true, force: true });
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
it('applyGitignoreFix --dry-run writes nothing', () => {
|
|
198
|
+
const dir = tmpRepo();
|
|
199
|
+
try {
|
|
200
|
+
const res = applyGitignoreFix(dir, ['.productbrain/session.json'], { dryRun: true });
|
|
201
|
+
expect(res.added).toContain('.productbrain/session.json');
|
|
202
|
+
expect(existsSync(join(dir, '.gitignore'))).toBe(false); // not created
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
rmSync(dir, { recursive: true, force: true });
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
it('applyGitignoreFix does not duplicate the header block across runs', () => {
|
|
209
|
+
const dir = tmpRepo();
|
|
210
|
+
try {
|
|
211
|
+
applyGitignoreFix(dir, ['.productbrain/config.local.json'], { dryRun: false });
|
|
212
|
+
applyGitignoreFix(dir, ['.productbrain/session.json'], { dryRun: false });
|
|
213
|
+
const gi = readFileSync(join(dir, '.gitignore'), 'utf8');
|
|
214
|
+
expect(gi.match(/# Product Brain pb-owned files/g) ?? []).toHaveLength(1);
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
rmSync(dir, { recursive: true, force: true });
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
it('applyGitignoreFix never duplicates a line already present (idempotent, no out-append)', () => {
|
|
221
|
+
const dir = tmpRepo();
|
|
222
|
+
try {
|
|
223
|
+
// even when a negation re-exposes the path, the line is NOT re-appended — the caller re-probes
|
|
224
|
+
// git and reports it instead (out-appending only grows the file and can't beat a nested file).
|
|
225
|
+
writeFileSync(join(dir, '.gitignore'), '.productbrain/config.local.json\n!.productbrain/config.local.json\n');
|
|
226
|
+
const res = applyGitignoreFix(dir, ['.productbrain/config.local.json'], { dryRun: false });
|
|
227
|
+
expect(res.skipped).toContain('.productbrain/config.local.json');
|
|
228
|
+
expect(res.added).not.toContain('.productbrain/config.local.json');
|
|
229
|
+
const gi = readFileSync(join(dir, '.gitignore'), 'utf8');
|
|
230
|
+
expect(gi.match(/^\.productbrain\/config\.local\.json$/gm) ?? []).toHaveLength(1); // not duplicated
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
rmSync(dir, { recursive: true, force: true });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
//# sourceMappingURL=productbrain-files.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"productbrain-files.test.js","sourceRoot":"","sources":["../../src/lib/productbrain-files.test.ts"],"names":[],"mappings":"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"}
|