@nac3/forge-cli 1.9.0 → 1.9.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/dist/chat/server.d.ts.map +1 -1
- package/dist/chat/server.js +47 -32
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/tools/orchestrator_write.d.ts +4 -0
- package/dist/chat/tools/orchestrator_write.d.ts.map +1 -1
- package/dist/chat/tools/orchestrator_write.js +35 -8
- package/dist/chat/tools/orchestrator_write.js.map +1 -1
- package/dist/core/operate_guard.d.ts +12 -0
- package/dist/core/operate_guard.d.ts.map +1 -1
- package/dist/core/operate_guard.js +70 -5
- package/dist/core/operate_guard.js.map +1 -1
- package/dist/core/provider_models.d.ts.map +1 -1
- package/dist/core/provider_models.js +7 -5
- package/dist/core/provider_models.js.map +1 -1
- package/dist/core/public_origin.d.ts +56 -0
- package/dist/core/public_origin.d.ts.map +1 -0
- package/dist/core/public_origin.js +142 -0
- package/dist/core/public_origin.js.map +1 -0
- package/dist/docs/doctrine/operate-mode.md +23 -1
- package/dist/nac3/internal_manifest.d.ts.map +1 -1
- package/dist/nac3/internal_manifest.js +1 -0
- package/dist/nac3/internal_manifest.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/doctrine/operate-mode.md +23 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/chat/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAA2D,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAKjG,OAAO,EAAoD,KAAK,aAAa,EAAoB,MAAM,aAAa,CAAC;AAErH,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAC;AAczB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAsBjD,OAAO,EAAyD,KAAK,eAAe,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/chat/server.ts"],"names":[],"mappings":"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"}
|
package/dist/chat/server.js
CHANGED
|
@@ -42,7 +42,8 @@ import { VERSION } from '../version.js';
|
|
|
42
42
|
import { readProjectIdentityCached, formatProjectIdentityLines } from '../core/project_identity.js';
|
|
43
43
|
import { buildDoctrineDigestLines } from './doctrine_digest.js';
|
|
44
44
|
import { acquireProjectLock, DuplicateInstanceError } from './instance_lock.js';
|
|
45
|
-
import { profilePromptLines, initProfile, activeProfile, operateEnabled } from '../core/forge_profile.js';
|
|
45
|
+
import { profilePromptLines, initProfile, activeProfile, operateEnabled, operateConfig } from '../core/forge_profile.js';
|
|
46
|
+
import { checkMutatingRequest, publicOrigins } from '../core/public_origin.js';
|
|
46
47
|
import { isAllowedSlot, listAllowedSlots } from '../core/provider_keys.js';
|
|
47
48
|
import { toolStatusSection, startToolStatusRefresh, environmentLines } from './tool_status.js';
|
|
48
49
|
import { RelayPublisher } from '../relay/relay_publisher.js';
|
|
@@ -115,6 +116,40 @@ export async function startChatServer(opts) {
|
|
|
115
116
|
try {
|
|
116
117
|
console.error('[yf] perfil de despliegue activo: "' + (prof.name || 'default') + '"'
|
|
117
118
|
+ (prof.read_only ? ' (READ-ONLY diagnostico)' : ''));
|
|
119
|
+
/* Operate mode (Pablo 2026-10-10): el boot log es la UNICA visibilidad
|
|
120
|
+
* que tiene el operador sobre lo que este despliegue puede cambiar, asi
|
|
121
|
+
* que enumera el alcance REAL (no solo que esta encendido) -- y con
|
|
122
|
+
* allowlists vacios lo dice, porque entonces no puede cambiar nada. */
|
|
123
|
+
const op = operateConfig();
|
|
124
|
+
if (op) {
|
|
125
|
+
const files = (op.config_files?.allow || []).filter((g) => typeof g === 'string' && g.trim());
|
|
126
|
+
const tables = (op.config_tables?.allow || []).filter((t) => typeof t === 'string' && t.trim());
|
|
127
|
+
const orch = op.orchestrator?.kind || '';
|
|
128
|
+
const parts = [
|
|
129
|
+
files.length ? files.length + ' glob(s) de archivos' : 'sin archivos',
|
|
130
|
+
tables.length ? tables.length + ' tabla(s)' : 'sin tablas',
|
|
131
|
+
orch ? 'orquestador ' + orch : 'sin orquestador',
|
|
132
|
+
];
|
|
133
|
+
console.error('[yf] OPERATE MODE ON -- alcance: ' + parts.join(', ')
|
|
134
|
+
+ '; aprobacion ' + (op.require_approval === false ? 'DESACTIVADA' : 'por modal')
|
|
135
|
+
+ '; journal en ' + (op.journal_dir || '.forge/changes'));
|
|
136
|
+
if (!files.length && !tables.length && !orch) {
|
|
137
|
+
console.error('[yf] OPERATE MODE sin alcance declarado: el asistente NO puede cambiar nada '
|
|
138
|
+
+ 'todavia (declara operate.config_files.allow / config_tables.allow / orchestrator).');
|
|
139
|
+
}
|
|
140
|
+
if (files.length)
|
|
141
|
+
console.error('[yf] archivos: ' + files.join(', '));
|
|
142
|
+
if (tables.length)
|
|
143
|
+
console.error('[yf] tablas: ' + tables.join(', '));
|
|
144
|
+
}
|
|
145
|
+
/* Servido detras de un reverse proxy: sin esto, todo request mutante
|
|
146
|
+
* del panel se rechaza por Host/Origin no-loopback. Decirlo en el boot
|
|
147
|
+
* es la diferencia entre "no valida la key" y saber por que. */
|
|
148
|
+
const po = publicOrigins();
|
|
149
|
+
if (po.length) {
|
|
150
|
+
console.error('[yf] origen publico autorizado (YF_PUBLIC_ORIGIN): '
|
|
151
|
+
+ po.map((o) => o.origin || o.hostname).join(', '));
|
|
152
|
+
}
|
|
118
153
|
}
|
|
119
154
|
catch { /* noop */ }
|
|
120
155
|
}
|
|
@@ -1353,38 +1388,18 @@ function relayForward(event, data) {
|
|
|
1353
1388
|
* panel's own requests carry Origin http://127.0.0.1:<port>, so
|
|
1354
1389
|
* legitimate traffic passes; non-browser clients (tests, relay)
|
|
1355
1390
|
* send no Origin and are unaffected. No feature is lost. */
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
const c = h.indexOf(':');
|
|
1366
|
-
return c >= 0 ? h.slice(0, c) : h;
|
|
1367
|
-
}
|
|
1391
|
+
/* La lista de loopback y el parseo del Host viven en core/public_origin.ts,
|
|
1392
|
+
* junto con la decision pura que testea `public-origin`. */
|
|
1393
|
+
/* El panel liga 127.0.0.1 y exige Host + Origin loopback en todo request
|
|
1394
|
+
* mutante (DNS-rebinding + CSRF). Eso vale para el modo normal (tunel SSH),
|
|
1395
|
+
* pero el embed residente se publica por un vhost con auth_request, y ahi
|
|
1396
|
+
* nginx reenvia `Host: forge.<host>` y el navegador manda ese Origin: TODO
|
|
1397
|
+
* POST caia con 403 -- validar la API key, mandar un mensaje, aprobar un
|
|
1398
|
+
* modal (visto desplegando ADIP-Kikan, 2026-10-10). El despliegue declara su
|
|
1399
|
+
* origen publico legitimo en YF_PUBLIC_ORIGIN; lo demas sigue rechazado. */
|
|
1368
1400
|
function isLocalMutatingRequestOk(req) {
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
return { ok: false, reason: 'Host no-loopback rechazado (posible DNS-rebinding): ' + host.slice(0, 60) };
|
|
1372
|
-
}
|
|
1373
|
-
const origin = req.headers.origin;
|
|
1374
|
-
if (typeof origin === 'string' && origin && origin.toLowerCase() !== 'null') {
|
|
1375
|
-
let oh;
|
|
1376
|
-
try {
|
|
1377
|
-
oh = new URL(origin).hostname.toLowerCase();
|
|
1378
|
-
}
|
|
1379
|
-
catch {
|
|
1380
|
-
return { ok: false, reason: 'Origin malformado' };
|
|
1381
|
-
}
|
|
1382
|
-
const normalized = oh.startsWith('[') ? oh : oh; /* URL.hostname already strips ipv6 brackets to bare ::1 on Node */
|
|
1383
|
-
if (!LOOPBACK_HOSTS.has(normalized) && !LOOPBACK_HOSTS.has('[' + normalized + ']')) {
|
|
1384
|
-
return { ok: false, reason: 'Origin cross-site rechazado (CSRF): ' + origin.slice(0, 80) };
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
return { ok: true };
|
|
1401
|
+
const r = checkMutatingRequest(String(req.headers.host ?? ''), req.headers.origin, publicOrigins());
|
|
1402
|
+
return r.ok ? { ok: true } : { ok: false, reason: r.reason || 'rechazado' };
|
|
1388
1403
|
}
|
|
1389
1404
|
const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
1390
1405
|
async function route(req, res, ctx) {
|