cc-safety-net 0.7.0 → 0.7.1
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/bin/cc-safety-net.js +44 -28
- package/dist/index.js +35 -20
- package/package.json +1 -1
|
@@ -2305,7 +2305,23 @@ function analyzeGitWorktree(tokens) {
|
|
|
2305
2305
|
// src/core/rules-rm.ts
|
|
2306
2306
|
import { realpathSync } from "node:fs";
|
|
2307
2307
|
import { homedir as homedir3, tmpdir } from "node:os";
|
|
2308
|
-
import { normalize, resolve as resolve2 } from "node:path";
|
|
2308
|
+
import { normalize, resolve as resolve2, sep } from "node:path";
|
|
2309
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
2310
|
+
function normalizePathForComparison(p) {
|
|
2311
|
+
let normalized = normalize(p);
|
|
2312
|
+
if (IS_WINDOWS) {
|
|
2313
|
+
normalized = normalized.replace(/\//g, "\\");
|
|
2314
|
+
normalized = normalized.toLowerCase();
|
|
2315
|
+
if (normalized.length > 3 && normalized.endsWith("\\")) {
|
|
2316
|
+
normalized = normalized.slice(0, -1);
|
|
2317
|
+
}
|
|
2318
|
+
} else {
|
|
2319
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
2320
|
+
normalized = normalized.slice(0, -1);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
return normalized;
|
|
2324
|
+
}
|
|
2309
2325
|
var REASON_RM_RF = "rm -rf outside cwd is blocked. Use explicit paths within the current directory, or delete manually.";
|
|
2310
2326
|
var REASON_RM_RF_ROOT_HOME = "rm -rf targeting root or home directory is extremely dangerous and always blocked.";
|
|
2311
2327
|
function analyzeRm(tokens, options = {}) {
|
|
@@ -2430,7 +2446,9 @@ function isTempTarget(path, allowTmpdirVar) {
|
|
|
2430
2446
|
return true;
|
|
2431
2447
|
}
|
|
2432
2448
|
const systemTmpdir = tmpdir();
|
|
2433
|
-
|
|
2449
|
+
const normalizedTmpdir = normalizePathForComparison(systemTmpdir);
|
|
2450
|
+
const pathToCompare = normalizePathForComparison(normalized);
|
|
2451
|
+
if (pathToCompare.startsWith(`${normalizedTmpdir}${sep}`) || pathToCompare === normalizedTmpdir) {
|
|
2434
2452
|
return true;
|
|
2435
2453
|
}
|
|
2436
2454
|
if (allowTmpdirVar) {
|
|
@@ -2448,27 +2466,24 @@ function getHomeDirForRmPolicy() {
|
|
|
2448
2466
|
}
|
|
2449
2467
|
function isCwdHomeForRmPolicy(cwd, homeDir) {
|
|
2450
2468
|
try {
|
|
2451
|
-
|
|
2452
|
-
const normalizedHome = normalize(homeDir);
|
|
2453
|
-
return normalizedCwd === normalizedHome;
|
|
2469
|
+
return normalizePathForComparison(cwd) === normalizePathForComparison(homeDir);
|
|
2454
2470
|
} catch {
|
|
2455
2471
|
return false;
|
|
2456
2472
|
}
|
|
2457
2473
|
}
|
|
2458
2474
|
function isCwdSelfTarget(target, cwd) {
|
|
2459
|
-
if (target === "." || target === "./") {
|
|
2475
|
+
if (target === "." || target === "./" || target === ".\\") {
|
|
2460
2476
|
return true;
|
|
2461
2477
|
}
|
|
2462
2478
|
try {
|
|
2463
2479
|
const resolved = resolve2(cwd, target);
|
|
2464
2480
|
const realCwd = realpathSync(cwd);
|
|
2465
2481
|
const realResolved = realpathSync(resolved);
|
|
2466
|
-
return realResolved === realCwd;
|
|
2482
|
+
return normalizePathForComparison(realResolved) === normalizePathForComparison(realCwd);
|
|
2467
2483
|
} catch {
|
|
2468
2484
|
try {
|
|
2469
2485
|
const resolved = resolve2(cwd, target);
|
|
2470
|
-
|
|
2471
|
-
return resolved === normalizedCwd;
|
|
2486
|
+
return normalizePathForComparison(resolved) === normalizePathForComparison(cwd);
|
|
2472
2487
|
} catch {
|
|
2473
2488
|
return false;
|
|
2474
2489
|
}
|
|
@@ -2482,20 +2497,21 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
|
|
|
2482
2497
|
if (target.includes("$") || target.includes("`")) {
|
|
2483
2498
|
return false;
|
|
2484
2499
|
}
|
|
2485
|
-
if (target.startsWith("/")) {
|
|
2500
|
+
if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) {
|
|
2486
2501
|
try {
|
|
2487
|
-
const normalizedTarget =
|
|
2488
|
-
const normalizedCwd = `${
|
|
2502
|
+
const normalizedTarget = normalizePathForComparison(target);
|
|
2503
|
+
const normalizedCwd = `${normalizePathForComparison(originalCwd)}${sep}`;
|
|
2489
2504
|
return normalizedTarget.startsWith(normalizedCwd);
|
|
2490
2505
|
} catch {
|
|
2491
2506
|
return false;
|
|
2492
2507
|
}
|
|
2493
2508
|
}
|
|
2494
|
-
if (target.startsWith("./") || !target.includes("/")) {
|
|
2509
|
+
if (target.startsWith("./") || target.startsWith(".\\") || !target.includes("/") && !target.includes("\\")) {
|
|
2495
2510
|
try {
|
|
2496
2511
|
const resolved = resolve2(resolveCwd, target);
|
|
2497
|
-
const
|
|
2498
|
-
|
|
2512
|
+
const normalizedResolved = normalizePathForComparison(resolved);
|
|
2513
|
+
const normalizedOriginalCwd = normalizePathForComparison(originalCwd);
|
|
2514
|
+
return normalizedResolved.startsWith(`${normalizedOriginalCwd}${sep}`) || normalizedResolved === normalizedOriginalCwd;
|
|
2499
2515
|
} catch {
|
|
2500
2516
|
return false;
|
|
2501
2517
|
}
|
|
@@ -2505,8 +2521,9 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
|
|
|
2505
2521
|
}
|
|
2506
2522
|
try {
|
|
2507
2523
|
const resolved = resolve2(resolveCwd, target);
|
|
2508
|
-
const
|
|
2509
|
-
|
|
2524
|
+
const normalizedResolved = normalizePathForComparison(resolved);
|
|
2525
|
+
const normalizedCwd = normalizePathForComparison(originalCwd);
|
|
2526
|
+
return normalizedResolved.startsWith(`${normalizedCwd}${sep}`) || normalizedResolved === normalizedCwd;
|
|
2510
2527
|
} catch {
|
|
2511
2528
|
return false;
|
|
2512
2529
|
}
|
|
@@ -2514,9 +2531,7 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
|
|
|
2514
2531
|
function isHomeDirectory(cwd) {
|
|
2515
2532
|
const home = process.env.HOME ?? homedir3();
|
|
2516
2533
|
try {
|
|
2517
|
-
|
|
2518
|
-
const normalizedHome = normalize(home);
|
|
2519
|
-
return normalizedCwd === normalizedHome;
|
|
2534
|
+
return normalizePathForComparison(cwd) === normalizePathForComparison(home);
|
|
2520
2535
|
} catch {
|
|
2521
2536
|
return false;
|
|
2522
2537
|
}
|
|
@@ -3439,7 +3454,7 @@ function detectAllHooks(cwd, options) {
|
|
|
3439
3454
|
|
|
3440
3455
|
// src/bin/doctor/system-info.ts
|
|
3441
3456
|
import { spawn } from "node:child_process";
|
|
3442
|
-
var CURRENT_VERSION = "0.7.
|
|
3457
|
+
var CURRENT_VERSION = "0.7.1";
|
|
3443
3458
|
function getPackageVersion() {
|
|
3444
3459
|
return CURRENT_VERSION;
|
|
3445
3460
|
}
|
|
@@ -3608,6 +3623,7 @@ function printReport(report) {
|
|
|
3608
3623
|
|
|
3609
3624
|
// src/bin/explain/config.ts
|
|
3610
3625
|
import { existsSync as existsSync5 } from "node:fs";
|
|
3626
|
+
import { resolve as resolve3 } from "node:path";
|
|
3611
3627
|
|
|
3612
3628
|
// src/core/env.ts
|
|
3613
3629
|
function envTruthy(name) {
|
|
@@ -3637,7 +3653,7 @@ function getConfigSource(options) {
|
|
|
3637
3653
|
return { configSource: null, configValid: true };
|
|
3638
3654
|
}
|
|
3639
3655
|
function buildAnalyzeOptions(explainOptions) {
|
|
3640
|
-
const cwd = explainOptions?.cwd ?? process.cwd();
|
|
3656
|
+
const cwd = resolve3(explainOptions?.cwd ?? process.cwd());
|
|
3641
3657
|
const paranoidAll = envTruthy("SAFETY_NET_PARANOID");
|
|
3642
3658
|
return {
|
|
3643
3659
|
cwd,
|
|
@@ -4484,7 +4500,7 @@ function formatTraceJson(result) {
|
|
|
4484
4500
|
return JSON.stringify(result, null, 2);
|
|
4485
4501
|
}
|
|
4486
4502
|
// src/bin/help.ts
|
|
4487
|
-
var version = "0.7.
|
|
4503
|
+
var version = "0.7.1";
|
|
4488
4504
|
var INDENT = " ";
|
|
4489
4505
|
var PROGRAM_NAME = "cc-safety-net";
|
|
4490
4506
|
function formatOptionFlags(option) {
|
|
@@ -4852,7 +4868,7 @@ async function readStdinAsync() {
|
|
|
4852
4868
|
if (process.stdin.isTTY) {
|
|
4853
4869
|
return null;
|
|
4854
4870
|
}
|
|
4855
|
-
return new Promise((
|
|
4871
|
+
return new Promise((resolve4) => {
|
|
4856
4872
|
let data = "";
|
|
4857
4873
|
process.stdin.setEncoding("utf-8");
|
|
4858
4874
|
process.stdin.on("data", (chunk) => {
|
|
@@ -4860,10 +4876,10 @@ async function readStdinAsync() {
|
|
|
4860
4876
|
});
|
|
4861
4877
|
process.stdin.on("end", () => {
|
|
4862
4878
|
const trimmed = data.trim();
|
|
4863
|
-
|
|
4879
|
+
resolve4(trimmed || null);
|
|
4864
4880
|
});
|
|
4865
4881
|
process.stdin.on("error", () => {
|
|
4866
|
-
|
|
4882
|
+
resolve4(null);
|
|
4867
4883
|
});
|
|
4868
4884
|
});
|
|
4869
4885
|
}
|
|
@@ -4927,7 +4943,7 @@ async function printStatusline() {
|
|
|
4927
4943
|
|
|
4928
4944
|
// src/bin/verify-config.ts
|
|
4929
4945
|
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync } from "node:fs";
|
|
4930
|
-
import { resolve as
|
|
4946
|
+
import { resolve as resolve4 } from "node:path";
|
|
4931
4947
|
var HEADER = "Safety Net Config";
|
|
4932
4948
|
var SEPARATOR = "═".repeat(HEADER.length);
|
|
4933
4949
|
var SCHEMA_URL = "https://raw.githubusercontent.com/kenryu42/claude-code-safety-net/main/assets/cc-safety-net.schema.json";
|
|
@@ -4992,7 +5008,7 @@ function verifyConfig(options = {}) {
|
|
|
4992
5008
|
const result = validateConfigFile(projectConfig);
|
|
4993
5009
|
configsChecked.push({
|
|
4994
5010
|
scope: "Project",
|
|
4995
|
-
path:
|
|
5011
|
+
path: resolve4(projectConfig),
|
|
4996
5012
|
result
|
|
4997
5013
|
});
|
|
4998
5014
|
if (result.errors.length > 0) {
|
package/dist/index.js
CHANGED
|
@@ -1166,7 +1166,23 @@ function analyzeGitWorktree(tokens) {
|
|
|
1166
1166
|
// src/core/rules-rm.ts
|
|
1167
1167
|
import { realpathSync } from "node:fs";
|
|
1168
1168
|
import { homedir, tmpdir } from "node:os";
|
|
1169
|
-
import { normalize, resolve } from "node:path";
|
|
1169
|
+
import { normalize, resolve, sep } from "node:path";
|
|
1170
|
+
var IS_WINDOWS = process.platform === "win32";
|
|
1171
|
+
function normalizePathForComparison(p) {
|
|
1172
|
+
let normalized = normalize(p);
|
|
1173
|
+
if (IS_WINDOWS) {
|
|
1174
|
+
normalized = normalized.replace(/\//g, "\\");
|
|
1175
|
+
normalized = normalized.toLowerCase();
|
|
1176
|
+
if (normalized.length > 3 && normalized.endsWith("\\")) {
|
|
1177
|
+
normalized = normalized.slice(0, -1);
|
|
1178
|
+
}
|
|
1179
|
+
} else {
|
|
1180
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
1181
|
+
normalized = normalized.slice(0, -1);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
return normalized;
|
|
1185
|
+
}
|
|
1170
1186
|
var REASON_RM_RF = "rm -rf outside cwd is blocked. Use explicit paths within the current directory, or delete manually.";
|
|
1171
1187
|
var REASON_RM_RF_ROOT_HOME = "rm -rf targeting root or home directory is extremely dangerous and always blocked.";
|
|
1172
1188
|
function analyzeRm(tokens, options = {}) {
|
|
@@ -1291,7 +1307,9 @@ function isTempTarget(path, allowTmpdirVar) {
|
|
|
1291
1307
|
return true;
|
|
1292
1308
|
}
|
|
1293
1309
|
const systemTmpdir = tmpdir();
|
|
1294
|
-
|
|
1310
|
+
const normalizedTmpdir = normalizePathForComparison(systemTmpdir);
|
|
1311
|
+
const pathToCompare = normalizePathForComparison(normalized);
|
|
1312
|
+
if (pathToCompare.startsWith(`${normalizedTmpdir}${sep}`) || pathToCompare === normalizedTmpdir) {
|
|
1295
1313
|
return true;
|
|
1296
1314
|
}
|
|
1297
1315
|
if (allowTmpdirVar) {
|
|
@@ -1309,27 +1327,24 @@ function getHomeDirForRmPolicy() {
|
|
|
1309
1327
|
}
|
|
1310
1328
|
function isCwdHomeForRmPolicy(cwd, homeDir) {
|
|
1311
1329
|
try {
|
|
1312
|
-
|
|
1313
|
-
const normalizedHome = normalize(homeDir);
|
|
1314
|
-
return normalizedCwd === normalizedHome;
|
|
1330
|
+
return normalizePathForComparison(cwd) === normalizePathForComparison(homeDir);
|
|
1315
1331
|
} catch {
|
|
1316
1332
|
return false;
|
|
1317
1333
|
}
|
|
1318
1334
|
}
|
|
1319
1335
|
function isCwdSelfTarget(target, cwd) {
|
|
1320
|
-
if (target === "." || target === "./") {
|
|
1336
|
+
if (target === "." || target === "./" || target === ".\\") {
|
|
1321
1337
|
return true;
|
|
1322
1338
|
}
|
|
1323
1339
|
try {
|
|
1324
1340
|
const resolved = resolve(cwd, target);
|
|
1325
1341
|
const realCwd = realpathSync(cwd);
|
|
1326
1342
|
const realResolved = realpathSync(resolved);
|
|
1327
|
-
return realResolved === realCwd;
|
|
1343
|
+
return normalizePathForComparison(realResolved) === normalizePathForComparison(realCwd);
|
|
1328
1344
|
} catch {
|
|
1329
1345
|
try {
|
|
1330
1346
|
const resolved = resolve(cwd, target);
|
|
1331
|
-
|
|
1332
|
-
return resolved === normalizedCwd;
|
|
1347
|
+
return normalizePathForComparison(resolved) === normalizePathForComparison(cwd);
|
|
1333
1348
|
} catch {
|
|
1334
1349
|
return false;
|
|
1335
1350
|
}
|
|
@@ -1343,20 +1358,21 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
|
|
|
1343
1358
|
if (target.includes("$") || target.includes("`")) {
|
|
1344
1359
|
return false;
|
|
1345
1360
|
}
|
|
1346
|
-
if (target.startsWith("/")) {
|
|
1361
|
+
if (target.startsWith("/") || /^[A-Za-z]:[\\/]/.test(target)) {
|
|
1347
1362
|
try {
|
|
1348
|
-
const normalizedTarget =
|
|
1349
|
-
const normalizedCwd = `${
|
|
1363
|
+
const normalizedTarget = normalizePathForComparison(target);
|
|
1364
|
+
const normalizedCwd = `${normalizePathForComparison(originalCwd)}${sep}`;
|
|
1350
1365
|
return normalizedTarget.startsWith(normalizedCwd);
|
|
1351
1366
|
} catch {
|
|
1352
1367
|
return false;
|
|
1353
1368
|
}
|
|
1354
1369
|
}
|
|
1355
|
-
if (target.startsWith("./") || !target.includes("/")) {
|
|
1370
|
+
if (target.startsWith("./") || target.startsWith(".\\") || !target.includes("/") && !target.includes("\\")) {
|
|
1356
1371
|
try {
|
|
1357
1372
|
const resolved = resolve(resolveCwd, target);
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1373
|
+
const normalizedResolved = normalizePathForComparison(resolved);
|
|
1374
|
+
const normalizedOriginalCwd = normalizePathForComparison(originalCwd);
|
|
1375
|
+
return normalizedResolved.startsWith(`${normalizedOriginalCwd}${sep}`) || normalizedResolved === normalizedOriginalCwd;
|
|
1360
1376
|
} catch {
|
|
1361
1377
|
return false;
|
|
1362
1378
|
}
|
|
@@ -1366,8 +1382,9 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
|
|
|
1366
1382
|
}
|
|
1367
1383
|
try {
|
|
1368
1384
|
const resolved = resolve(resolveCwd, target);
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1385
|
+
const normalizedResolved = normalizePathForComparison(resolved);
|
|
1386
|
+
const normalizedCwd = normalizePathForComparison(originalCwd);
|
|
1387
|
+
return normalizedResolved.startsWith(`${normalizedCwd}${sep}`) || normalizedResolved === normalizedCwd;
|
|
1371
1388
|
} catch {
|
|
1372
1389
|
return false;
|
|
1373
1390
|
}
|
|
@@ -1375,9 +1392,7 @@ function isTargetWithinCwd(target, originalCwd, effectiveCwd) {
|
|
|
1375
1392
|
function isHomeDirectory(cwd) {
|
|
1376
1393
|
const home = process.env.HOME ?? homedir();
|
|
1377
1394
|
try {
|
|
1378
|
-
|
|
1379
|
-
const normalizedHome = normalize(home);
|
|
1380
|
-
return normalizedCwd === normalizedHome;
|
|
1395
|
+
return normalizePathForComparison(cwd) === normalizePathForComparison(home);
|
|
1381
1396
|
} catch {
|
|
1382
1397
|
return false;
|
|
1383
1398
|
}
|
package/package.json
CHANGED