@neetru/cli 2.28.10 → 2.31.0
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/CHANGELOG.md +92 -1
- package/README.md +61 -17
- package/dist/commands/code.js +10 -1
- package/dist/commands/code.js.map +1 -1
- package/dist/commands/db-move.d.ts +50 -1
- package/dist/commands/db-move.js +137 -13
- package/dist/commands/db-move.js.map +1 -1
- package/dist/commands/db.js +17 -9
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts +45 -0
- package/dist/commands/deploy.js +181 -2
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/deployments.d.ts +7 -1
- package/dist/commands/deployments.js +59 -8
- package/dist/commands/deployments.js.map +1 -1
- package/dist/commands/dev-up.d.ts +7 -5
- package/dist/commands/dev-up.js +24 -23
- package/dist/commands/dev-up.js.map +1 -1
- package/dist/commands/docs-produto.d.ts +65 -0
- package/dist/commands/docs-produto.js +322 -0
- package/dist/commands/docs-produto.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +7 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/new.d.ts +2 -0
- package/dist/commands/new.js +2 -0
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/servers.d.ts +28 -0
- package/dist/commands/servers.js +126 -1
- package/dist/commands/servers.js.map +1 -1
- package/dist/index.js +110 -11
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +8 -1
- package/dist/lib/api-client.js +20 -2
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/compose-generator.d.ts +13 -9
- package/dist/lib/compose-generator.js +28 -60
- package/dist/lib/compose-generator.js.map +1 -1
- package/dist/lib/config-schema.d.ts +40 -6
- package/dist/lib/config-schema.js +11 -0
- package/dist/lib/config-schema.js.map +1 -1
- package/dist/lib/product-docs/check.d.ts +62 -0
- package/dist/lib/product-docs/check.js +489 -0
- package/dist/lib/product-docs/check.js.map +1 -0
- package/dist/lib/product-docs/config.d.ts +66 -0
- package/dist/lib/product-docs/config.js +234 -0
- package/dist/lib/product-docs/config.js.map +1 -0
- package/dist/lib/product-docs/dates.d.ts +17 -0
- package/dist/lib/product-docs/dates.js +41 -0
- package/dist/lib/product-docs/dates.js.map +1 -0
- package/dist/lib/product-docs/frontmatter.d.ts +43 -0
- package/dist/lib/product-docs/frontmatter.js +302 -0
- package/dist/lib/product-docs/frontmatter.js.map +1 -0
- package/dist/lib/product-docs/git.d.ts +16 -0
- package/dist/lib/product-docs/git.js +92 -0
- package/dist/lib/product-docs/git.js.map +1 -0
- package/dist/lib/product-docs/markdown.d.ts +27 -0
- package/dist/lib/product-docs/markdown.js +98 -0
- package/dist/lib/product-docs/markdown.js.map +1 -0
- package/dist/lib/product-docs/ops.d.ts +133 -0
- package/dist/lib/product-docs/ops.js +975 -0
- package/dist/lib/product-docs/ops.js.map +1 -0
- package/dist/lib/product-docs/structure.d.ts +61 -0
- package/dist/lib/product-docs/structure.js +239 -0
- package/dist/lib/product-docs/structure.js.map +1 -0
- package/dist/lib/product-docs/sync.d.ts +101 -0
- package/dist/lib/product-docs/sync.js +313 -0
- package/dist/lib/product-docs/sync.js.map +1 -0
- package/dist/lib/product-docs/taxonomy.d.ts +46 -0
- package/dist/lib/product-docs/taxonomy.js +163 -0
- package/dist/lib/product-docs/taxonomy.js.map +1 -0
- package/dist/lib/product-docs/templates.d.ts +53 -0
- package/dist/lib/product-docs/templates.js +245 -0
- package/dist/lib/product-docs/templates.js.map +1 -0
- package/dist/lib/public-secret-scan.d.ts +76 -0
- package/dist/lib/public-secret-scan.js +446 -0
- package/dist/lib/public-secret-scan.js.map +1 -0
- package/package.json +2 -1
- package/templates/dev/Dockerfile.agent +0 -39
- package/templates/dev/agent-entrypoint.sh +0 -41
- package/templates/dev/docker-compose.dev.yml +0 -63
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Varredura de segredo no pacote PÚBLICO antes do `neetru deploy` (2.30.0).
|
|
3
|
+
*
|
|
4
|
+
* Decisão do dono (2026-10-03): a credencial `nrt_` do produto é SÓ DE
|
|
5
|
+
* SERVIDOR. Hoje produtos carregam a chave no bundle do navegador
|
|
6
|
+
* (`NEXT_PUBLIC_NEETRU_API_KEY`, `NEXT_PUBLIC_NEETRU_PUBLIC_KEY`) — qualquer
|
|
7
|
+
* visitante abre o DevTools e copia. Este gate impede que um segredo saia no
|
|
8
|
+
* artefato servido ao público.
|
|
9
|
+
*
|
|
10
|
+
* O que é "público" (servido ao navegador): `.next/static/**`, `public/**`,
|
|
11
|
+
* `out/**`, `dist/**`, `build/**` — e, na stack `static`, o pacote inteiro.
|
|
12
|
+
* `node_modules/**` nunca entra (código de terceiros, não servido como asset).
|
|
13
|
+
*
|
|
14
|
+
* O que procuramos:
|
|
15
|
+
* 1. `nrt_[A-Za-z0-9_-]{20,}` — credencial de API do produto (Neetru).
|
|
16
|
+
* 2. `npk_[A-Za-z0-9_-]{20,}` — chave de produto Neetru.
|
|
17
|
+
* 3. `-----BEGIN … PRIVATE KEY-----` + material base64 — chave privada PEM
|
|
18
|
+
* (RSA/EC/OPENSSH/PKCS8). Só o cabeçalho (código de lib) não conta.
|
|
19
|
+
* 4. VALOR literal de env pública (`NEXT_PUBLIC_*`, `EXPO_PUBLIC_*`,
|
|
20
|
+
* `VITE_*`, `REACT_APP_*`, `PUBLIC_*`) cujo NOME contém KEY/SECRET/TOKEN —
|
|
21
|
+
* é exatamente o que o bundler injeta no JS do navegador.
|
|
22
|
+
* Exceção por FORMATO de valor sabidamente público: Stripe publishable
|
|
23
|
+
* (`pk_live_`/`pk_test_`), chave web Google/Firebase (`AIza…`), reCAPTCHA
|
|
24
|
+
* site key (`6L…`). Nome não isenta nada (`NEXT_PUBLIC_NEETRU_PUBLIC_KEY`
|
|
25
|
+
* é justamente a chave `nrt_` no navegador).
|
|
26
|
+
*
|
|
27
|
+
* Saída: NUNCA imprime o segredo. Mostra no máximo os 8 primeiros caracteres
|
|
28
|
+
* (e nunca mais que 1/4 do valor), seguidos de máscara.
|
|
29
|
+
*
|
|
30
|
+
* Sem dependências: o .tar.gz é lido em streaming (zlib + parser ustar/GNU/pax).
|
|
31
|
+
*/
|
|
32
|
+
import fs from 'node:fs';
|
|
33
|
+
import fsp from 'node:fs/promises';
|
|
34
|
+
import path from 'node:path';
|
|
35
|
+
import zlib from 'node:zlib';
|
|
36
|
+
export const PUBLIC_SECRET_PATTERNS = [
|
|
37
|
+
{ id: 'nrt_key', label: 'credencial nrt_ do produto (só de servidor)', re: /nrt_[A-Za-z0-9_-]{20,}/g },
|
|
38
|
+
{ id: 'npk_key', label: 'chave npk_ do produto', re: /npk_[A-Za-z0-9_-]{20,}/g },
|
|
39
|
+
{
|
|
40
|
+
id: 'private_key',
|
|
41
|
+
label: 'chave privada PEM',
|
|
42
|
+
// Exige MATERIAL de chave depois do cabeçalho (base64, com quebra real ou
|
|
43
|
+
// `\n` escapado de string JS) — o cabeçalho sozinho aparece em código de
|
|
44
|
+
// biblioteca (ex.: validação de PEM do `jose`) e não é segredo.
|
|
45
|
+
re: /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY-----(?:\\[nr]|\s)*[A-Za-z0-9+/=]{40,}/g,
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
/** Prefixos de env que os bundlers injetam no código do navegador/app. */
|
|
49
|
+
export const PUBLIC_ENV_PREFIXES = ['NEXT_PUBLIC_', 'EXPO_PUBLIC_', 'VITE_', 'REACT_APP_', 'PUBLIC_'];
|
|
50
|
+
const SENSITIVE_ENV_NAME_RE = /KEY|SECRET|TOKEN/i;
|
|
51
|
+
/** Valores curtos demais geram falso positivo em massa (ex.: "true", "1"). */
|
|
52
|
+
const MIN_ENV_VALUE_LENGTH = 12;
|
|
53
|
+
/** Formatos de valor que são públicos POR DESENHO do provedor. */
|
|
54
|
+
const KNOWN_PUBLIC_VALUE_SHAPES = [
|
|
55
|
+
/^pk_(live|test)_[A-Za-z0-9]+$/, // Stripe publishable key
|
|
56
|
+
/^AIza[0-9A-Za-z_-]{35}$/, // Google/Firebase web API key (restrita por domínio)
|
|
57
|
+
/^6L[0-9A-Za-z_-]{38}$/, // reCAPTCHA site key
|
|
58
|
+
];
|
|
59
|
+
export function isKnownPublicValue(value) {
|
|
60
|
+
return KNOWN_PUBLIC_VALUE_SHAPES.some((re) => re.test(value));
|
|
61
|
+
}
|
|
62
|
+
export function isPublicSensitiveEnvName(name) {
|
|
63
|
+
return PUBLIC_ENV_PREFIXES.some((p) => name.startsWith(p)) && SENSITIVE_ENV_NAME_RE.test(name);
|
|
64
|
+
}
|
|
65
|
+
// ─── Máscara ────────────────────────────────────────────────────────────────
|
|
66
|
+
/** Até 8 caracteres iniciais (nunca mais que 1/4 do valor) + máscara. */
|
|
67
|
+
export function maskSecret(value) {
|
|
68
|
+
const shown = Math.min(8, Math.floor(value.length / 4));
|
|
69
|
+
return `${value.slice(0, shown)}…[mascarado, ${value.length} caracteres]`;
|
|
70
|
+
}
|
|
71
|
+
// ─── Caminhos públicos ──────────────────────────────────────────────────────
|
|
72
|
+
const PUBLIC_TOP_DIRS = new Set(['public', 'out', 'dist', 'build']);
|
|
73
|
+
/** Normaliza o nome de membro do tar: `\` → `/`, sem `./` nem `/` iniciais. */
|
|
74
|
+
export function normalizeEntryPath(p) {
|
|
75
|
+
let s = p.replace(/\\/g, '/');
|
|
76
|
+
while (s.startsWith('./'))
|
|
77
|
+
s = s.slice(2);
|
|
78
|
+
s = s.replace(/^\/+/, '');
|
|
79
|
+
return s;
|
|
80
|
+
}
|
|
81
|
+
export function isPublicArtifactPath(relPath, stack) {
|
|
82
|
+
const p = normalizeEntryPath(relPath);
|
|
83
|
+
if (!p)
|
|
84
|
+
return false;
|
|
85
|
+
const segs = p.split('/');
|
|
86
|
+
if (segs.includes('node_modules'))
|
|
87
|
+
return false;
|
|
88
|
+
if (stack === 'static')
|
|
89
|
+
return true;
|
|
90
|
+
// `.next/static/**` em qualquer profundidade (monorepo: apps/web/.next/static).
|
|
91
|
+
for (let i = 0; i < segs.length - 1; i++) {
|
|
92
|
+
if (segs[i] === '.next' && segs[i + 1] === 'static')
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
return PUBLIC_TOP_DIRS.has(segs[0]) && segs.length > 1;
|
|
96
|
+
}
|
|
97
|
+
const BINARY_EXT = new Set([
|
|
98
|
+
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.avif', '.ico', '.bmp', '.tif', '.tiff',
|
|
99
|
+
'.woff', '.woff2', '.ttf', '.otf', '.eot',
|
|
100
|
+
'.mp4', '.webm', '.mov', '.mp3', '.wav', '.ogg', '.m4a',
|
|
101
|
+
'.pdf', '.zip', '.gz', '.br', '.zst', '.7z', '.wasm',
|
|
102
|
+
]);
|
|
103
|
+
/** Arquivos maiores que isso não são varridos (e são reportados como não varridos). */
|
|
104
|
+
export const MAX_SCAN_FILE_BYTES = 25 * 1024 * 1024;
|
|
105
|
+
export function isScannableFile(relPath) {
|
|
106
|
+
return !BINARY_EXT.has(path.extname(relPath).toLowerCase());
|
|
107
|
+
}
|
|
108
|
+
/** Varre um conteúdo de arquivo. Dedup por (arquivo, padrão). */
|
|
109
|
+
export function scanContent(file, content, envSecrets) {
|
|
110
|
+
const text = typeof content === 'string' ? content : content.toString('latin1');
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const pat of PUBLIC_SECRET_PATTERNS) {
|
|
113
|
+
pat.re.lastIndex = 0;
|
|
114
|
+
const m = pat.re.exec(text);
|
|
115
|
+
if (m)
|
|
116
|
+
out.push({ file, pattern: pat.id, label: pat.label, preview: maskSecret(m[0]) });
|
|
117
|
+
}
|
|
118
|
+
for (const env of envSecrets) {
|
|
119
|
+
if (text.includes(env.value)) {
|
|
120
|
+
out.push({
|
|
121
|
+
file,
|
|
122
|
+
pattern: `public_env:${env.name}`,
|
|
123
|
+
label: `valor da env pública ${env.name} (nome com KEY/SECRET/TOKEN vai pro navegador)`,
|
|
124
|
+
preview: maskSecret(env.value),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
// ─── Env pública com cara de segredo ────────────────────────────────────────
|
|
131
|
+
/** Parser mínimo de .env (KEY=VALUE, aspas simples/duplas, comentários). */
|
|
132
|
+
export function parseDotenv(content) {
|
|
133
|
+
const out = {};
|
|
134
|
+
for (const line of content.split(/\r?\n/)) {
|
|
135
|
+
const t = line.trim();
|
|
136
|
+
if (!t || t.startsWith('#'))
|
|
137
|
+
continue;
|
|
138
|
+
const body = t.startsWith('export ') ? t.slice(7) : t;
|
|
139
|
+
const eq = body.indexOf('=');
|
|
140
|
+
if (eq <= 0)
|
|
141
|
+
continue;
|
|
142
|
+
const k = body.slice(0, eq).trim();
|
|
143
|
+
let v = body.slice(eq + 1).trim();
|
|
144
|
+
if (v.length >= 2 && ((v[0] === '"' && v.endsWith('"')) || (v[0] === "'" && v.endsWith("'")))) {
|
|
145
|
+
v = v.slice(1, -1);
|
|
146
|
+
}
|
|
147
|
+
out[k] = v;
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
/** Arquivos .env que o bundler lê num build de produção (o `.env*` NÃO viaja no tarball). */
|
|
152
|
+
export const BUILD_ENV_FILES = ['.env', '.env.production', '.env.local', '.env.production.local'];
|
|
153
|
+
/**
|
|
154
|
+
* Coleta envs públicas com nome sensível a partir do ambiente do build:
|
|
155
|
+
* `.env*` do projeto, `--env-file` e `process.env` do CLI (o build roda com ele).
|
|
156
|
+
*/
|
|
157
|
+
export async function collectPublicEnvSecrets(cwd, envFile, processEnv = process.env) {
|
|
158
|
+
const merged = {};
|
|
159
|
+
const files = BUILD_ENV_FILES.map((f) => path.join(cwd, f));
|
|
160
|
+
if (envFile)
|
|
161
|
+
files.push(path.resolve(cwd, envFile));
|
|
162
|
+
for (const f of files) {
|
|
163
|
+
try {
|
|
164
|
+
Object.assign(merged, parseDotenv(await fsp.readFile(f, 'utf8')));
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* arquivo ausente/ilegível — ignora */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
for (const [k, v] of Object.entries(processEnv)) {
|
|
171
|
+
if (typeof v === 'string')
|
|
172
|
+
merged[k] = v;
|
|
173
|
+
}
|
|
174
|
+
const seen = new Set();
|
|
175
|
+
const out = [];
|
|
176
|
+
for (const [name, value] of Object.entries(merged)) {
|
|
177
|
+
if (!isPublicSensitiveEnvName(name))
|
|
178
|
+
continue;
|
|
179
|
+
if (value.length < MIN_ENV_VALUE_LENGTH || isKnownPublicValue(value))
|
|
180
|
+
continue;
|
|
181
|
+
const key = `${name}\u0000${value}`;
|
|
182
|
+
if (seen.has(key))
|
|
183
|
+
continue;
|
|
184
|
+
seen.add(key);
|
|
185
|
+
out.push({ name, value });
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
function readString(buf, start, len) {
|
|
190
|
+
const slice = buf.subarray(start, start + len);
|
|
191
|
+
const nul = slice.indexOf(0);
|
|
192
|
+
return slice.subarray(0, nul < 0 ? slice.length : nul).toString('utf8');
|
|
193
|
+
}
|
|
194
|
+
function readSize(buf) {
|
|
195
|
+
const field = buf.subarray(124, 136);
|
|
196
|
+
if (field[0] & 0x80) {
|
|
197
|
+
// base-256 (GNU, arquivos > 8 GiB)
|
|
198
|
+
let n = 0;
|
|
199
|
+
for (let i = 1; i < field.length; i++)
|
|
200
|
+
n = n * 256 + field[i];
|
|
201
|
+
return n;
|
|
202
|
+
}
|
|
203
|
+
const s = readString(buf, 124, 12).trim();
|
|
204
|
+
return s ? parseInt(s, 8) : 0;
|
|
205
|
+
}
|
|
206
|
+
function parseHeader(block) {
|
|
207
|
+
const name = readString(block, 0, 100);
|
|
208
|
+
const type = String.fromCharCode(block[156] || 48); // '\0' → '0'
|
|
209
|
+
const magic = readString(block, 257, 6);
|
|
210
|
+
const prefix = magic.startsWith('ustar') ? readString(block, 345, 155) : '';
|
|
211
|
+
return { name: prefix ? `${prefix}/${name}` : name, size: readSize(block), type };
|
|
212
|
+
}
|
|
213
|
+
function parsePaxPath(data) {
|
|
214
|
+
const text = data.toString('utf8');
|
|
215
|
+
let i = 0;
|
|
216
|
+
while (i < text.length) {
|
|
217
|
+
const sp = text.indexOf(' ', i);
|
|
218
|
+
if (sp < 0)
|
|
219
|
+
break;
|
|
220
|
+
const len = parseInt(text.slice(i, sp), 10);
|
|
221
|
+
if (!Number.isFinite(len) || len <= 0)
|
|
222
|
+
break;
|
|
223
|
+
const record = text.slice(sp + 1, i + len - 1); // sem o '\n' final
|
|
224
|
+
const eq = record.indexOf('=');
|
|
225
|
+
if (eq > 0 && record.slice(0, eq) === 'path')
|
|
226
|
+
return record.slice(eq + 1);
|
|
227
|
+
i += len;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
const META_MAX_BYTES = 1024 * 1024;
|
|
232
|
+
/**
|
|
233
|
+
* Lê um .tar.gz em streaming e chama `onFile` para cada arquivo regular que
|
|
234
|
+
* `want(nome, tamanho)` aceitar. Arquivos não desejados são pulados sem buffer.
|
|
235
|
+
*/
|
|
236
|
+
export async function walkTarGz(tarPath, want, onFile) {
|
|
237
|
+
let buf = Buffer.alloc(0);
|
|
238
|
+
let state = 'header';
|
|
239
|
+
let remaining = 0;
|
|
240
|
+
let pad = 0;
|
|
241
|
+
let cur = null;
|
|
242
|
+
let longName = null;
|
|
243
|
+
let paxPath = null;
|
|
244
|
+
let ended = false;
|
|
245
|
+
const finish = () => {
|
|
246
|
+
if (!cur)
|
|
247
|
+
return;
|
|
248
|
+
const data = cur.chunks ? Buffer.concat(cur.chunks) : null;
|
|
249
|
+
if (cur.type === 'L' && data) {
|
|
250
|
+
longName = readString(data, 0, data.length);
|
|
251
|
+
}
|
|
252
|
+
else if (cur.type === 'x' && data) {
|
|
253
|
+
paxPath = parsePaxPath(data) ?? paxPath;
|
|
254
|
+
}
|
|
255
|
+
else if ((cur.type === '0' || cur.type === '7') && data) {
|
|
256
|
+
onFile(cur.name, data);
|
|
257
|
+
}
|
|
258
|
+
cur = null;
|
|
259
|
+
};
|
|
260
|
+
const consume = () => {
|
|
261
|
+
let off = 0;
|
|
262
|
+
for (;;) {
|
|
263
|
+
if (ended) {
|
|
264
|
+
off = buf.length;
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if (state === 'header') {
|
|
268
|
+
if (buf.length - off < 512)
|
|
269
|
+
break;
|
|
270
|
+
const block = buf.subarray(off, off + 512);
|
|
271
|
+
off += 512;
|
|
272
|
+
if (block.every((b) => b === 0))
|
|
273
|
+
continue; // bloco zero (fim/padding)
|
|
274
|
+
const h = parseHeader(block);
|
|
275
|
+
let name = h.name;
|
|
276
|
+
const isMeta = h.type === 'L' || h.type === 'x' || h.type === 'g' || h.type === 'K';
|
|
277
|
+
if (!isMeta) {
|
|
278
|
+
name = paxPath ?? longName ?? name;
|
|
279
|
+
paxPath = null;
|
|
280
|
+
longName = null;
|
|
281
|
+
}
|
|
282
|
+
const regular = h.type === '0' || h.type === '7';
|
|
283
|
+
let collect = false;
|
|
284
|
+
if (h.type === 'L' || h.type === 'x')
|
|
285
|
+
collect = h.size <= META_MAX_BYTES;
|
|
286
|
+
else if (regular)
|
|
287
|
+
collect = want(name, h.size);
|
|
288
|
+
cur = { name, type: h.type, chunks: collect ? [] : null };
|
|
289
|
+
remaining = h.size;
|
|
290
|
+
pad = (512 - (h.size % 512)) % 512;
|
|
291
|
+
if (remaining === 0) {
|
|
292
|
+
finish();
|
|
293
|
+
state = pad ? 'pad' : 'header';
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
state = 'data';
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else if (state === 'data') {
|
|
300
|
+
const avail = buf.length - off;
|
|
301
|
+
if (avail === 0)
|
|
302
|
+
break;
|
|
303
|
+
const take = Math.min(avail, remaining);
|
|
304
|
+
if (cur?.chunks)
|
|
305
|
+
cur.chunks.push(Buffer.from(buf.subarray(off, off + take)));
|
|
306
|
+
off += take;
|
|
307
|
+
remaining -= take;
|
|
308
|
+
if (remaining === 0) {
|
|
309
|
+
finish();
|
|
310
|
+
state = pad ? 'pad' : 'header';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
const avail = buf.length - off;
|
|
315
|
+
if (avail === 0)
|
|
316
|
+
break;
|
|
317
|
+
const take = Math.min(avail, pad);
|
|
318
|
+
off += take;
|
|
319
|
+
pad -= take;
|
|
320
|
+
if (pad === 0)
|
|
321
|
+
state = 'header';
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
buf = buf.subarray(off);
|
|
325
|
+
};
|
|
326
|
+
await new Promise((resolve, reject) => {
|
|
327
|
+
const input = fs.createReadStream(tarPath);
|
|
328
|
+
const gunzip = zlib.createGunzip();
|
|
329
|
+
input.on('error', reject);
|
|
330
|
+
gunzip.on('error', (e) => reject(new Error(`pacote .tar.gz ilegível: ${e.message}`)));
|
|
331
|
+
gunzip.on('data', (chunk) => {
|
|
332
|
+
buf = buf.length ? Buffer.concat([buf, chunk]) : chunk;
|
|
333
|
+
try {
|
|
334
|
+
consume();
|
|
335
|
+
}
|
|
336
|
+
catch (e) {
|
|
337
|
+
ended = true;
|
|
338
|
+
reject(e);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
gunzip.on('end', () => resolve());
|
|
342
|
+
input.pipe(gunzip);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
/** Varre o tarball de deploy (o que de fato vai pro GCS). */
|
|
346
|
+
export async function scanTarballForPublicSecrets(tarPath, ctx) {
|
|
347
|
+
const findings = [];
|
|
348
|
+
const skippedLarge = [];
|
|
349
|
+
let scannedFiles = 0;
|
|
350
|
+
await walkTarGz(tarPath, (name, size) => {
|
|
351
|
+
if (!isPublicArtifactPath(name, ctx.stack) || !isScannableFile(name))
|
|
352
|
+
return false;
|
|
353
|
+
if (size > MAX_SCAN_FILE_BYTES) {
|
|
354
|
+
skippedLarge.push(normalizeEntryPath(name));
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
return true;
|
|
358
|
+
}, (name, data) => {
|
|
359
|
+
scannedFiles++;
|
|
360
|
+
findings.push(...scanContent(normalizeEntryPath(name), data, ctx.envSecrets));
|
|
361
|
+
});
|
|
362
|
+
return { findings, scannedFiles, skippedLarge };
|
|
363
|
+
}
|
|
364
|
+
/** Varre as pastas públicas no disco (target=cloud-run, onde não há tarball). */
|
|
365
|
+
export async function scanDirectoryForPublicSecrets(root, ctx) {
|
|
366
|
+
const findings = [];
|
|
367
|
+
const skippedLarge = [];
|
|
368
|
+
let scannedFiles = 0;
|
|
369
|
+
const starts = ctx.stack === 'static'
|
|
370
|
+
? ['.']
|
|
371
|
+
: ['.next/static', ...PUBLIC_TOP_DIRS].filter((d) => {
|
|
372
|
+
try {
|
|
373
|
+
return fs.statSync(path.join(root, d)).isDirectory();
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
async function walk(rel) {
|
|
380
|
+
let entries;
|
|
381
|
+
try {
|
|
382
|
+
entries = await fsp.readdir(path.join(root, rel), { withFileTypes: true });
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
for (const e of entries) {
|
|
388
|
+
const childRel = rel === '.' ? e.name : `${rel}/${e.name}`;
|
|
389
|
+
if (e.isSymbolicLink())
|
|
390
|
+
continue;
|
|
391
|
+
if (e.isDirectory()) {
|
|
392
|
+
if (e.name === 'node_modules' || e.name === '.git')
|
|
393
|
+
continue;
|
|
394
|
+
await walk(childRel);
|
|
395
|
+
}
|
|
396
|
+
else if (e.isFile()) {
|
|
397
|
+
if (!isPublicArtifactPath(childRel, ctx.stack) || !isScannableFile(childRel))
|
|
398
|
+
continue;
|
|
399
|
+
const abs = path.join(root, childRel);
|
|
400
|
+
const st = await fsp.stat(abs);
|
|
401
|
+
if (st.size > MAX_SCAN_FILE_BYTES) {
|
|
402
|
+
skippedLarge.push(childRel);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
scannedFiles++;
|
|
406
|
+
findings.push(...scanContent(childRel, await fsp.readFile(abs), ctx.envSecrets));
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
for (const s of starts)
|
|
411
|
+
await walk(s);
|
|
412
|
+
return { findings, scannedFiles, skippedLarge };
|
|
413
|
+
}
|
|
414
|
+
// ─── Mensagens ──────────────────────────────────────────────────────────────
|
|
415
|
+
export const ALLOW_PUBLIC_SECRET_FLAG = '--allow-public-secret';
|
|
416
|
+
/** Motivo mínimo do override (evita `--allow-public-secret x`). */
|
|
417
|
+
export const MIN_OVERRIDE_REASON_LENGTH = 10;
|
|
418
|
+
export function formatFindingsMessage(findings) {
|
|
419
|
+
const lines = findings
|
|
420
|
+
.slice(0, 20)
|
|
421
|
+
.map((f) => ` - ${f.file} — ${f.label} (${f.preview})`);
|
|
422
|
+
const more = findings.length > 20 ? [` … e mais ${findings.length - 20} achado(s).`] : [];
|
|
423
|
+
return [
|
|
424
|
+
`Segredo no pacote PÚBLICO (servido ao navegador): ${findings.length} achado(s). Deploy BLOQUEADO.`,
|
|
425
|
+
...lines,
|
|
426
|
+
...more,
|
|
427
|
+
'',
|
|
428
|
+
'Por quê: tudo em .next/static, public, out, dist e build é baixado por qualquer visitante — ',
|
|
429
|
+
'a chave vira pública na hora. A credencial nrt_ do produto é SÓ DE SERVIDOR.',
|
|
430
|
+
'Como corrigir:',
|
|
431
|
+
' 1. Tire a chave do código do navegador/app: nada de NEXT_PUBLIC_*_KEY/EXPO_PUBLIC_*_KEY com segredo.',
|
|
432
|
+
' 2. O navegador/app chama a API do SEU produto (/api/v1/...) com o token do usuário;',
|
|
433
|
+
' o backend usa @neetru/sdk com NEETRU_API_KEY (injetada no servidor pelo Core).',
|
|
434
|
+
' 3. Rode `neetru build` de novo e repita o deploy.',
|
|
435
|
+
`Emergência (fica registrado no deploy): ${ALLOW_PUBLIC_SECRET_FLAG} "<motivo>"`,
|
|
436
|
+
].join('\n');
|
|
437
|
+
}
|
|
438
|
+
/** Registro do override — só caminho e tipo de padrão, NUNCA o valor. */
|
|
439
|
+
export function buildOverrideRecord(reason, findings, now = new Date()) {
|
|
440
|
+
return {
|
|
441
|
+
reason,
|
|
442
|
+
findings: findings.map((f) => ({ file: f.file, pattern: f.pattern })),
|
|
443
|
+
at: now.toISOString(),
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
//# sourceMappingURL=public-secret-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-secret-scan.js","sourceRoot":"","sources":["../../src/lib/public-secret-scan.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neetru/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.31.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Neetru Developer Kit — scaffold, AI assistant, publish, build e deploy de produtos SaaS Neetru via Core (VM-based agents)",
|
|
6
6
|
"keywords": [
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"start": "node dist/index.js",
|
|
38
38
|
"test": "vitest run",
|
|
39
39
|
"test:watch": "vitest",
|
|
40
|
+
"prepare": "node -e \"try{if(require('fs').existsSync('.git'))require('child_process').execFileSync('git',['config','core.hooksPath','.githooks'],{stdio:'ignore'})}catch{}\"",
|
|
40
41
|
"prepublishOnly": "npm run build"
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Neetru Agent — modo dev (Docker container, sem systemd)
|
|
2
|
-
#
|
|
3
|
-
# Em produção, o agente roda como systemd service na VM.
|
|
4
|
-
# Em dev-local, roda como processo Node direto no container.
|
|
5
|
-
# O deploy do app SaaS é feito como child process (não systemd unit).
|
|
6
|
-
#
|
|
7
|
-
# Build:
|
|
8
|
-
# docker build -f Dockerfile.agent -t neetru-agent-dev .
|
|
9
|
-
|
|
10
|
-
FROM node:22-slim
|
|
11
|
-
|
|
12
|
-
# Dependências do agente em produção (apt, certbot, etc.)
|
|
13
|
-
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
14
|
-
curl ca-certificates systemctl \
|
|
15
|
-
&& rm -rf /var/lib/apt/lists/*
|
|
16
|
-
|
|
17
|
-
# Diretório do agente
|
|
18
|
-
WORKDIR /opt/neetru
|
|
19
|
-
|
|
20
|
-
# Baixa o agente mais recente do Core
|
|
21
|
-
ARG CORE_URL=https://core.neetru.com
|
|
22
|
-
ENV NEETRU_CORE_URL=${CORE_URL}
|
|
23
|
-
|
|
24
|
-
# Download do binário (fallback: usa curl se GCS não disponível)
|
|
25
|
-
RUN ARCH=$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/') && \
|
|
26
|
-
curl -fsSL -o /usr/local/bin/neetru-agent \
|
|
27
|
-
"${NEETRU_CORE_URL}/releases/latest/neetru-agent-linux-${ARCH}" || \
|
|
28
|
-
echo "Agente não encontrado no Core — será montado via volume" && \
|
|
29
|
-
chmod +x /usr/local/bin/neetru-agent || true
|
|
30
|
-
|
|
31
|
-
# Entrypoint: agente em modo dev
|
|
32
|
-
# - NEETRU_DEV_MODE=true desabilita systemd, usa child_process direto
|
|
33
|
-
# - NEETRU_APP_PORT define a porta onde o app SaaS vai rodar
|
|
34
|
-
COPY templates/dev/agent-entrypoint.sh /usr/local/bin/neetru-agent-entrypoint
|
|
35
|
-
RUN chmod +x /usr/local/bin/neetru-agent-entrypoint
|
|
36
|
-
|
|
37
|
-
EXPOSE 3000
|
|
38
|
-
|
|
39
|
-
ENTRYPOINT ["/usr/local/bin/neetru-agent-entrypoint"]
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Neetru Agent — entrypoint modo dev (Docker container)
|
|
3
|
-
#
|
|
4
|
-
# Em modo dev, o agente NAO usa systemd. Em vez disso:
|
|
5
|
-
# - Deploy = child process (npm install + node server)
|
|
6
|
-
# - Funções = child process (neetru-functions)
|
|
7
|
-
# - Healthcheck = /health endpoint no próprio agente
|
|
8
|
-
#
|
|
9
|
-
# Env vars obrigatórias:
|
|
10
|
-
# NEETRU_SERVER_ID — id do servidor (ex: dev-local-meuproduto)
|
|
11
|
-
# NEETRU_CORE_URL — URL do Core (ex: https://core.neetru.com)
|
|
12
|
-
# NEETRU_FIREBASE_PROJECT — projeto Firebase
|
|
13
|
-
# NEETRU_DEV_MODE — "true" ativa modo dev
|
|
14
|
-
|
|
15
|
-
set -e
|
|
16
|
-
|
|
17
|
-
echo "═══════════════════════════════════════════"
|
|
18
|
-
echo " Neetru Agent — Dev Mode"
|
|
19
|
-
echo " Server: ${NEETRU_SERVER_ID}"
|
|
20
|
-
echo " Core: ${NEETRU_CORE_URL}"
|
|
21
|
-
echo "═══════════════════════════════════════════"
|
|
22
|
-
|
|
23
|
-
# Verifica binário
|
|
24
|
-
if [ ! -f /usr/local/bin/neetru-agent ]; then
|
|
25
|
-
echo "[AGENT] Binário não encontrado. Montando via volume..."
|
|
26
|
-
echo "[AGENT] Certifique-se de que o agente está em /opt/neetru/neetru-agent"
|
|
27
|
-
ls -la /opt/neetru/ || true
|
|
28
|
-
fi
|
|
29
|
-
|
|
30
|
-
# Cria diretórios necessários
|
|
31
|
-
mkdir -p /var/cache/neetru /opt/neetru/deploys
|
|
32
|
-
|
|
33
|
-
# Inicia o agente
|
|
34
|
-
echo "[AGENT] Iniciando agente Neetru..."
|
|
35
|
-
exec node /usr/local/bin/neetru-agent 2>&1 || exec node /opt/neetru/neetru-agent 2>&1 || {
|
|
36
|
-
echo "[AGENT] ERRO: Não foi possível iniciar o agente."
|
|
37
|
-
echo "[AGENT] Verifique se o binário existe em /usr/local/bin/neetru-agent"
|
|
38
|
-
echo "[AGENT] ou monte o binário via volume em /opt/neetru/neetru-agent"
|
|
39
|
-
sleep 10
|
|
40
|
-
exit 1
|
|
41
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# Neetru Dev Local — emulador de VM ({{ENGINE}})
|
|
2
|
-
# Gerado por `neetru dev up`. Modifique o neetru.config.json e rode novamente.
|
|
3
|
-
#
|
|
4
|
-
# Este compose simula uma VM de produção Neetru:
|
|
5
|
-
# 1. Banco de dados ({{ENGINE}}) = mesmo engine que vai pra produção
|
|
6
|
-
# 2. Agente Neetru = recebe comandos do Core, faz deploy, npm install, healthcheck
|
|
7
|
-
# 3. App SaaS = deployado pelo agente, acessível em http://localhost:{{APP_PORT}}
|
|
8
|
-
#
|
|
9
|
-
# Uso:
|
|
10
|
-
# neetru dev up # gera este compose + sobe tudo
|
|
11
|
-
# docker compose -f neetru-compose.dev.yml up -d # manual
|
|
12
|
-
# docker compose -f neetru-compose.dev.yml down # desliga
|
|
13
|
-
|
|
14
|
-
services:
|
|
15
|
-
# ── Banco de dados ({{ENGINE}}) ────────────────────────────────────────────
|
|
16
|
-
database:
|
|
17
|
-
image: {{DB_IMAGE}}
|
|
18
|
-
container_name: neetru-dev-db
|
|
19
|
-
environment:
|
|
20
|
-
{{DB_ENV}}
|
|
21
|
-
ports:
|
|
22
|
-
- "{{DB_PORT}}:{{DB_INTERNAL_PORT}}"
|
|
23
|
-
volumes:
|
|
24
|
-
- neetru-db-data:{{DB_DATA_DIR}}
|
|
25
|
-
healthcheck:
|
|
26
|
-
{{DB_HEALTHCHECK}}
|
|
27
|
-
restart: unless-stopped
|
|
28
|
-
networks:
|
|
29
|
-
- neetru-dev-net
|
|
30
|
-
|
|
31
|
-
# ── Agente Neetru (modo dev — sem systemd) ────────────────────────────────
|
|
32
|
-
agent:
|
|
33
|
-
build:
|
|
34
|
-
context: .
|
|
35
|
-
dockerfile: Dockerfile.agent
|
|
36
|
-
container_name: neetru-dev-agent
|
|
37
|
-
environment:
|
|
38
|
-
- NEETRU_SERVER_ID=dev-local-{{PRODUCT_SLUG}}
|
|
39
|
-
- NEETRU_CORE_URL={{CORE_URL}}
|
|
40
|
-
- NEETRU_FIREBASE_PROJECT={{FIREBASE_PROJECT}}
|
|
41
|
-
- NEETRU_FIREBASE_API_KEY={{FIREBASE_API_KEY}}
|
|
42
|
-
- NEETRU_DEV_MODE=true
|
|
43
|
-
- NEETRU_APP_PORT={{APP_PORT}}
|
|
44
|
-
ports:
|
|
45
|
-
- "{{APP_PORT}}:{{APP_PORT}}"
|
|
46
|
-
volumes:
|
|
47
|
-
- /var/run/docker.sock:/var/run/docker.sock
|
|
48
|
-
- neetru-agent-data:/var/cache/neetru
|
|
49
|
-
- .:/app/product:cached
|
|
50
|
-
depends_on:
|
|
51
|
-
database:
|
|
52
|
-
condition: service_healthy
|
|
53
|
-
restart: unless-stopped
|
|
54
|
-
networks:
|
|
55
|
-
- neetru-dev-net
|
|
56
|
-
|
|
57
|
-
volumes:
|
|
58
|
-
neetru-db-data:
|
|
59
|
-
neetru-agent-data:
|
|
60
|
-
|
|
61
|
-
networks:
|
|
62
|
-
neetru-dev-net:
|
|
63
|
-
driver: bridge
|