@ingeniomaps/cauce 0.65.0 → 0.66.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 +17 -0
- package/engine/hooks/shell.js +38 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,23 @@ desde este repositorio no va, porque el que lee no puede actuar sobre eso. Cuand
|
|
|
14
14
|
unas pocas líneas casi siempre es porque cuenta cómo se descubrió el problema o por qué se eligió el
|
|
15
15
|
diseño — eso vive en el commit y en el código.
|
|
16
16
|
|
|
17
|
+
## [0.66.0] - 2026-09-07
|
|
18
|
+
|
|
19
|
+
### Corregido
|
|
20
|
+
|
|
21
|
+
- **`shell-boundary` ignoraba el `cd` del propio comando.** Resolvía las rutas relativas contra el
|
|
22
|
+
directorio que le entrega tu runner, no contra el que el comando elige antes de escribir, así que
|
|
23
|
+
juzgaba una ruta que nadie iba a escribir. Fallaba para los dos lados: `cd <fuera de tus raíces> &&
|
|
24
|
+
echo x > nota.md` pasaba sin decir nada y el archivo se escribía afuera; y con el runner abierto en
|
|
25
|
+
otro directorio, un `cd` a un lugar legítimo se frenaba nombrando una ruta que no estaba en el
|
|
26
|
+
comando.
|
|
27
|
+
|
|
28
|
+
Ahora cada escritura se juzga contra el `cd` que la precede. **Lo que te pide algo**: un `cd` cuyo
|
|
29
|
+
destino no se puede saber acá —`cd $TRABAJO`, `cd -`— deja sin juzgar a toda ruta relativa que venga
|
|
30
|
+
después, y eso se bloquea pidiendo la ruta absoluta o el `cd` en un comando aparte. Es deliberado y
|
|
31
|
+
es el criterio que ya regía para el índice: un guard que no puede verificar no autoriza. Una ruta
|
|
32
|
+
absoluta no depende del `cd` y se sigue juzgando igual.
|
|
33
|
+
|
|
17
34
|
## [0.65.0] - 2026-09-07
|
|
18
35
|
|
|
19
36
|
### Cambiado
|
package/engine/hooks/shell.js
CHANGED
|
@@ -264,11 +264,47 @@ function writeTargets(command) {
|
|
|
264
264
|
// el guard frena `> /dev/null 2>&1`, y lo primero que hace quien lo sufre es apagarlo entero.
|
|
265
265
|
const NEUTRAL = [/^\/dev\/(?:null|stdout|stderr|tty|fd\/)/, new RegExp(`^${os.tmpdir()}(?:/|$)`)]
|
|
266
266
|
|
|
267
|
+
// A dónde deja parado un `cd`. `null` significa que no se sabe, que no es lo mismo que la raíz: un
|
|
268
|
+
// destino con variable o un `cd -` dependen de un estado que este proceso no tiene.
|
|
269
|
+
function cdTarget(argument, base) {
|
|
270
|
+
if (argument === undefined) return os.homedir()
|
|
271
|
+
if (argument === '-' || /[$`\u0000]/.test(argument)) return null
|
|
272
|
+
if (/^~(?=$|\/)/.test(argument)) return argument.replace(/^~/, os.homedir())
|
|
273
|
+
return path.resolve(base, argument)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Las escrituras de un comando, cada una con el directorio contra el que hay que resolverla. El `cd`
|
|
277
|
+
// del propio comando cambia eso para todo lo que viene después y es lo primero que el shell ejecuta;
|
|
278
|
+
// sin mirarlo, el guard juzgaba una ruta que nadie iba a escribir, y fallaba en los dos sentidos.
|
|
279
|
+
//
|
|
280
|
+
// Se recorre por tramos y se lleva la cuenta, en vez de mirar sólo el primero como hace `gitDirectory`.
|
|
281
|
+
// Ahí alcanza porque un comando elige un repositorio; acá cada escritura puede caer bajo un `cd`
|
|
282
|
+
// distinto, y juzgar la primera contra el último sería cambiar un error de lugar en vez de arreglarlo.
|
|
283
|
+
//
|
|
284
|
+
// Los tramos salen del texto ya sin comillas, así que un `;` adentro de una cadena no parte nada.
|
|
285
|
+
function writesWithBase(command, cwd) {
|
|
286
|
+
const found = []
|
|
287
|
+
let base = cwd
|
|
288
|
+
for (const segment of unquoted(command).split(/[;&|\n]+/)) {
|
|
289
|
+
const cd = segment.match(/^\s*cd(?:\s+(\S+))?\s*$/)
|
|
290
|
+
if (cd) { base = base === null ? null : cdTarget(cd[1], base); continue }
|
|
291
|
+
for (const raw of writeTargets(segment)) found.push({ raw, base })
|
|
292
|
+
}
|
|
293
|
+
return found
|
|
294
|
+
}
|
|
295
|
+
|
|
267
296
|
function shellBoundary(input) {
|
|
268
297
|
const allowed = writableRoots(input)
|
|
269
298
|
if (!allowed) return
|
|
270
|
-
for (const raw of
|
|
271
|
-
|
|
299
|
+
for (const { raw, base } of writesWithBase(commandOf(input), cwdOf(input))) {
|
|
300
|
+
// Una ruta absoluta no depende del `cd`, así que un destino que no se sabe no la vuelve injuzgable.
|
|
301
|
+
// Al revés sí: sin saber desde dónde se resuelve, una relativa no se puede verificar, y un guard que
|
|
302
|
+
// no puede verificar no autoriza —el criterio que fijó el 031 para el índice—.
|
|
303
|
+
if (!path.isAbsolute(raw) && base === null) {
|
|
304
|
+
block(`el comando hace \`cd\` a un destino que no se puede resolver acá, así que no hay contra qué `
|
|
305
|
+
+ `resolver ${raw}. Escribí la ruta absoluta, o hacé el \`cd\` en un comando aparte.`)
|
|
306
|
+
}
|
|
307
|
+
const file = path.resolve(base, raw)
|
|
272
308
|
if (NEUTRAL.some((pattern) => pattern.test(file))) continue
|
|
273
309
|
if (outsideRoots(file, allowed)) {
|
|
274
310
|
block(`el comando escribe en ${file}, fuera de las raíces declaradas en ops.config.json. ${DECLARE_IT}`)
|