@arcadialdev/arcality 2.6.4 → 2.6.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.
package/package.json
CHANGED
package/scripts/gen-and-run.mjs
CHANGED
|
@@ -795,6 +795,17 @@ async function main() {
|
|
|
795
795
|
_origProcessExit(code);
|
|
796
796
|
};
|
|
797
797
|
|
|
798
|
+
// ── RESTORE RAW MODE FOR WINDOWS FIX ──
|
|
799
|
+
// @clack/prompts pausea stdin y desactiva raw mode al terminar un menú.
|
|
800
|
+
// Debemos reactivarlo aquí para que nuestro interceptor global de Ctrl+C
|
|
801
|
+
// siga funcionando durante toda la misión.
|
|
802
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
803
|
+
try {
|
|
804
|
+
process.stdin.setRawMode(true);
|
|
805
|
+
process.stdin.resume();
|
|
806
|
+
} catch(e) {}
|
|
807
|
+
}
|
|
808
|
+
|
|
798
809
|
const cancelHandler = () => {
|
|
799
810
|
sigintCount++;
|
|
800
811
|
if (sigintCount > 3) {
|
|
@@ -1192,12 +1203,31 @@ async function main() {
|
|
|
1192
1203
|
console.log(chalk.gray('\n Press Enter to return to menu...'));
|
|
1193
1204
|
await new Promise(resolve => {
|
|
1194
1205
|
const onKey = (key) => {
|
|
1195
|
-
|
|
1206
|
+
const keyStr = String(key);
|
|
1207
|
+
if (keyStr.includes('\r') || keyStr.includes('\n') || keyStr === '\u0003') {
|
|
1196
1208
|
process.stdin.off('data', onKey);
|
|
1197
|
-
|
|
1209
|
+
|
|
1210
|
+
// Restaurar stdin en modo normal para @clack/prompts
|
|
1211
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
1212
|
+
process.stdin.setRawMode(false);
|
|
1213
|
+
}
|
|
1214
|
+
process.stdin.pause();
|
|
1215
|
+
|
|
1216
|
+
if (keyStr === '\u0003') process.emit('SIGINT'); // Ctrl+C = salir
|
|
1198
1217
|
else resolve();
|
|
1199
1218
|
}
|
|
1200
1219
|
};
|
|
1220
|
+
|
|
1221
|
+
// ── BUGFIX: @clack/prompts llama explícitamente a process.stdin.pause()
|
|
1222
|
+
// al terminar cada select()/text(). En Node.js, agregar un listener 'data'
|
|
1223
|
+
// a un stream EXPLÍCITAMENTE pausado NO lo reactiva automáticamente.
|
|
1224
|
+
// Resultado: el event loop queda vacío y el proceso termina antes de que
|
|
1225
|
+
// el usuario pueda presionar Enter.
|
|
1226
|
+
// Solución: llamar resume() explícitamente antes de registrar el listener.
|
|
1227
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
1228
|
+
process.stdin.setRawMode(true); // raw mode para capturar Enter inmediatamente
|
|
1229
|
+
}
|
|
1230
|
+
process.stdin.resume(); // ← CRÍTICO: reactiva stdin para mantener el event loop vivo
|
|
1201
1231
|
process.stdin.on('data', onKey);
|
|
1202
1232
|
});
|
|
1203
1233
|
|
|
@@ -23,6 +23,10 @@ export class SecurityScanner {
|
|
|
23
23
|
* @returns A promise that resolves to an array of found vulnerabilities.
|
|
24
24
|
*/
|
|
25
25
|
async runAllScans(): Promise<SecurityFinding[]> {
|
|
26
|
+
if (this.page.isClosed()) {
|
|
27
|
+
if (process.env.DEBUG) console.log('[QA-SEC] Security scan skipped because page is closed.');
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
26
30
|
if (process.env.DEBUG) console.log('[QA-SEC] Starting comprehensive security scan...');
|
|
27
31
|
|
|
28
32
|
// Scan 1: Audit HTTP Security Headers
|
|
@@ -46,6 +50,7 @@ export class SecurityScanner {
|
|
|
46
50
|
* A basic test for open redirect vulnerabilities on the current URL.
|
|
47
51
|
*/
|
|
48
52
|
async testOpenRedirect(): Promise<void> {
|
|
53
|
+
if (this.page.isClosed()) return;
|
|
49
54
|
const url = new URL(this.page.url());
|
|
50
55
|
const redirectParams = ['redirect', 'next', 'url', 'returnTo', 'dest'];
|
|
51
56
|
|
|
@@ -2675,6 +2675,11 @@ var SecurityScanner = class {
|
|
|
2675
2675
|
* @returns A promise that resolves to an array of found vulnerabilities.
|
|
2676
2676
|
*/
|
|
2677
2677
|
async runAllScans() {
|
|
2678
|
+
if (this.page.isClosed()) {
|
|
2679
|
+
if (process.env.DEBUG)
|
|
2680
|
+
console.log("[QA-SEC] Security scan skipped because page is closed.");
|
|
2681
|
+
return [];
|
|
2682
|
+
}
|
|
2678
2683
|
if (process.env.DEBUG)
|
|
2679
2684
|
console.log("[QA-SEC] Starting comprehensive security scan...");
|
|
2680
2685
|
const headerVulnerabilities = await audit_http_headers(this.page);
|
|
@@ -2690,6 +2695,8 @@ var SecurityScanner = class {
|
|
|
2690
2695
|
* A basic test for open redirect vulnerabilities on the current URL.
|
|
2691
2696
|
*/
|
|
2692
2697
|
async testOpenRedirect() {
|
|
2698
|
+
if (this.page.isClosed())
|
|
2699
|
+
return;
|
|
2693
2700
|
const url = new URL(this.page.url());
|
|
2694
2701
|
const redirectParams = ["redirect", "next", "url", "returnTo", "dest"];
|
|
2695
2702
|
for (const param of redirectParams) {
|
|
@@ -4017,36 +4024,40 @@ Acci\xF3n bloqueada: Bucle de tipo ${loopType} sobre los elementos ${Array.from(
|
|
|
4017
4024
|
});
|
|
4018
4025
|
}
|
|
4019
4026
|
}
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
const
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4027
|
+
if (!page.isClosed()) {
|
|
4028
|
+
try {
|
|
4029
|
+
const scanner = new SecurityScanner(page);
|
|
4030
|
+
const securityReport = await scanner.runAllScans();
|
|
4031
|
+
if (securityReport && securityReport.length > 0) {
|
|
4032
|
+
await testInfo.attach("security_report", {
|
|
4033
|
+
body: JSON.stringify(securityReport, null, 2),
|
|
4034
|
+
contentType: "application/json"
|
|
4035
|
+
});
|
|
4036
|
+
console.log(`>>ARCALITY_STATUS>> \u{1F6E1}\uFE0F Escaneo de seguridad completado. ${securityReport.length} problemas encontrados.`);
|
|
4037
|
+
try {
|
|
4038
|
+
for (const v of securityReport) {
|
|
4039
|
+
const sev = v.severity || "Info";
|
|
4040
|
+
const mappedSeverity = sev === "Critical" ? "critical" : sev === "High" ? "important" : "suggestion";
|
|
4041
|
+
await pushRule({
|
|
4042
|
+
rule_type: "SECURITY",
|
|
4043
|
+
title: `Security: ${v.category} (${v.severity})`,
|
|
4044
|
+
description: `${v.description}
|
|
4037
4045
|
Evidence: ${JSON.stringify(v.evidence).substring(0, 400)}`,
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4046
|
+
severity: mappedSeverity
|
|
4047
|
+
}).catch(() => {
|
|
4048
|
+
});
|
|
4049
|
+
}
|
|
4050
|
+
} catch (e) {
|
|
4051
|
+
console.warn(">>ARCALITY_STATUS>> \u26A0\uFE0F Fall\xF3 persistir hallazgos de seguridad en Memoria Colectiva.");
|
|
4041
4052
|
}
|
|
4042
|
-
}
|
|
4043
|
-
console.
|
|
4053
|
+
} else {
|
|
4054
|
+
console.log(`>>ARCALITY_STATUS>> \u{1F6E1}\uFE0F Escaneo de seguridad completado. No se encontraron problemas.`);
|
|
4044
4055
|
}
|
|
4045
|
-
}
|
|
4046
|
-
console.
|
|
4056
|
+
} catch (e) {
|
|
4057
|
+
console.error("Error in Security Scan:", e.message);
|
|
4047
4058
|
}
|
|
4048
|
-
}
|
|
4049
|
-
console.
|
|
4059
|
+
} else {
|
|
4060
|
+
console.warn(">>ARCALITY_STATUS>> \u{1F6E1}\uFE0F Escaneo de seguridad omitido porque el navegador o la pesta\xF1a colaps\xF3/cerr\xF3.");
|
|
4050
4061
|
}
|
|
4051
4062
|
if (!aiMarkedSuccess && !failReason) {
|
|
4052
4063
|
if (stepCount >= maxSteps)
|