@mocoto/mahoraga 0.14.6 → 0.14.7

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.
@@ -1,19 +1,32 @@
1
1
  // SPDX-License-Identifier: MIT
2
- import { execSync } from 'node:child_process';
2
+ import { execFileSync } from 'node:child_process';
3
+ import path from 'node:path';
3
4
  import { config } from '../config/index.js';
4
5
  import { getMessages } from '../messages/index.js';
5
- // Expressão regular para detectar shell metacharacters perigosos
6
- // que permitiriam injeção de comandos adicionais.
7
- // Bloqueia: ; | & ` $() ${} <> \n
8
- const SHELL_INJECTION_RE = /[;|&`]|\$[({]|\${|>|<|\\n/;
9
6
  /**
10
- * Valida que o comando não contém caracteres de injeção shell.
11
- * @param cmd - Comando a validar
12
- * @throws Error se o comando contiver padrões perigosos
7
+ * Allowlist de binários que o CLI pode executar externamente.
8
+ * Apenas comandos essenciais para operação do ferramenta são permitidos.
9
+ * Isso substitui a abordagem anterior de blacklist de caracteres shell,
10
+ * eliminando o vetor de injeção por shell intermediário.
13
11
  */
14
- function validarComando(cmd) {
15
- if (SHELL_INJECTION_RE.test(cmd)) {
16
- throw new Error(`Comando rejeitado por segurança: contém caracteres de injeção shell.`);
12
+ const BINARIOS_PERMITIDOS = new Set([
13
+ 'git',
14
+ 'npm',
15
+ 'npx',
16
+ 'node',
17
+ 'pnpm',
18
+ 'yarn',
19
+ 'corepack',
20
+ ]);
21
+ /**
22
+ * Valida que o binário está na allowlist.
23
+ * @param bin - Caminho ou nome do binário
24
+ * @throws Error se o binário não for permitido
25
+ */
26
+ function validarBinario(bin) {
27
+ const nome = path.basename(bin);
28
+ if (!BINARIOS_PERMITIDOS.has(nome)) {
29
+ throw new Error(getMessages().ExecSafeMensagens.binarioNaoPermitido(bin));
17
30
  }
18
31
  }
19
32
  function verificarSafeMode() {
@@ -22,28 +35,37 @@ function verificarSafeMode() {
22
35
  }
23
36
  }
24
37
  /**
25
- * Executa um comando shell de forma segura.
38
+ * Executa um binário de forma segura sem shell intermediário.
39
+ *
26
40
  * Bloqueia a execução quando SAFE_MODE está ativo e ALLOW_EXEC não está habilitado.
27
- * Também valida o comando contra injeção shell mesmo quando a execução é permitida.
28
- * @param cmd - Comando shell a executar
29
- * @param opts - Opções do execSync do Node.js
41
+ * Valida o binário contra uma allowlist de comandos permitidos.
42
+ * Força `shell: false` para eliminar o risco de injeção de comandos.
43
+ *
44
+ * @param bin - Binário a executar (ex: 'git', 'npm')
45
+ * @param args - Argumentos do binário (array de strings)
46
+ * @param opts - Opções adicionais do child_process
30
47
  * @returns Buffer ou string com a saída do comando
31
- * @throws Error se SAFE_MODE estiver ativo sem ALLOW_EXEC ou se o comando for inválido
48
+ * @throws Error se SAFE_MODE estiver ativo sem ALLOW_EXEC,
49
+ * se o binário não estiver na allowlist,
50
+ * ou se a execução falhar
32
51
  */
33
- export function executarShellSeguro(cmd, opts = {}) {
34
- validarComando(cmd);
52
+ export function executarShellSeguro(bin, args = [], opts = {}) {
53
+ validarBinario(bin);
35
54
  verificarSafeMode();
36
- return execSync(cmd, opts);
55
+ return execFileSync(bin, args, { ...opts, shell: false });
37
56
  }
38
57
  /**
39
58
  * Versão assíncrona do `executarShellSeguro`.
40
59
  * Wrapper async que delega ao sync, útil em contextos que já utilizam await.
41
- * @param cmd - Comando shell a executar
42
- * @param opts - Opções do execSync do Node.js
60
+ *
61
+ * @param bin - Binário a executar (ex: 'git', 'npm')
62
+ * @param args - Argumentos do binário (array de strings)
63
+ * @param opts - Opções adicionais do child_process
43
64
  * @returns Promise resolvida com Buffer ou string da saída do comando
44
- * @throws Error se SAFE_MODE estiver ativo sem ALLOW_EXEC
65
+ * @throws Error se SAFE_MODE estiver ativo sem ALLOW_EXEC,
66
+ * se o binário não estiver na allowlist,
67
+ * ou se a execução falhar
45
68
  */
46
- export function executarShellSeguroAsync(cmd, opts = {}) {
47
- // wrapper assíncrono que delega ao sync (usado onde já há await)
48
- return executarShellSeguro(cmd, opts);
69
+ export function executarShellSeguroAsync(bin, args = [], opts = {}) {
70
+ return executarShellSeguro(bin, args, opts);
49
71
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mocoto/mahoraga",
3
- "version": "0.14.6",
3
+ "version": "0.14.7",
4
4
  "type": "module",
5
5
  "description": "C.L.I modular para análise, diagnóstico e manutenção de projetos JavaScript/TypeScript e multi-stack leve",
6
6
  "author": "rei macaco",
@@ -116,46 +116,39 @@
116
116
  "THIRD-PARTY-NOTICES.txt"
117
117
  ],
118
118
  "dependencies": {
119
- "@babel/parser": "^8.0.0",
120
- "@babel/traverse": "^8.0.0",
121
- "@babel/types": "^8.0.0",
119
+ "@babel/parser": "^8.0.4",
120
+ "@babel/traverse": "^8.0.4",
121
+ "@babel/types": "^8.0.4",
122
122
  "chalk": "^5.6.2",
123
123
  "commander": "^15.0.0",
124
124
  "dotenv": "^17.4.2",
125
125
  "fast-xml-parser": "^5.9.3",
126
126
  "htmlparser2": "^12.0.0",
127
- "marked": "^18.0.5",
127
+ "marked": "^18.0.6",
128
128
  "micromatch": "^4.0.8",
129
129
  "minimatch": "^10.2.5",
130
130
  "openpgp": "^6.3.1",
131
131
  "ora": "^9.4.1",
132
132
  "p-limit": "^7.3.0",
133
+ "postcss": "^8.5.16",
133
134
  "postcss-sass": "^0.5.0",
134
135
  "postcss-scss": "^4.0.9",
135
136
  "xxhashjs": "^0.2.2",
136
- "yaml": "^2.9.0",
137
- "postcss": "^8.5.16"
137
+ "yaml": "^2.9.0"
138
138
  },
139
139
  "devDependencies": {
140
140
  "@types/micromatch": "^4.0.10",
141
- "@types/node": "^26.1.0",
142
- "@typescript-eslint/eslint-plugin": "^8.62.1",
143
- "@typescript-eslint/parser": "^8.62.1",
141
+ "@types/node": "^26.1.1",
144
142
  "@vitest/coverage-istanbul": "^4.1.8",
145
143
  "@vitest/coverage-v8": "^4.1.8",
146
144
  "autoprefixer": "^10.5.2",
147
- "eslint": "^10.6.0",
148
- "eslint-import-resolver-typescript": "^4.4.5",
149
- "eslint-plugin-import-x": "^4.17.1",
150
- "eslint-plugin-simple-import-sort": "^13.0.0",
151
- "eslint-plugin-unused-imports": "^4.4.1",
152
145
  "husky": "^9.1.7",
153
146
  "license-checker-rseidelsohn": "^5.0.1",
154
147
  "lint-staged": "^17.0.8",
155
148
  "rimraf": "^6.1.3",
156
- "tsc-alias": "^1.8.17",
149
+ "tsc-alias": "^1.9.0",
157
150
  "tsx": "^4.23.0",
158
- "typescript": "^6.0.3",
151
+ "typescript": "^7.0.2",
159
152
  "vitest": "^4.1.8"
160
153
  },
161
154
  "lint-staged": {