@pretense/cli 0.6.16 → 0.6.18
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/{chunk-MH6CXHTM.js → chunk-QT5E625F.js} +1 -1
- package/dist/index.js +177 -53
- package/dist/postinstall.js +1 -1
- package/package.json +5 -5
|
@@ -17,7 +17,7 @@ function versionFromPackageJson() {
|
|
|
17
17
|
return void 0;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
var PRETENSE_VERSION = (true ? "0.6.
|
|
20
|
+
var PRETENSE_VERSION = (true ? "0.6.18" : void 0) ?? versionFromPackageJson() ?? "0.0.0-unknown";
|
|
21
21
|
|
|
22
22
|
export {
|
|
23
23
|
PRETENSE_VERSION
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
PRETENSE_VERSION
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QT5E625F.js";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__toESM,
|
|
@@ -3892,10 +3892,10 @@ var Minipass = class extends EventEmitter {
|
|
|
3892
3892
|
* Return a void Promise that resolves once the stream ends.
|
|
3893
3893
|
*/
|
|
3894
3894
|
async promise() {
|
|
3895
|
-
return new Promise((
|
|
3895
|
+
return new Promise((resolve8, reject) => {
|
|
3896
3896
|
this.on(DESTROYED, () => reject(new Error("stream destroyed")));
|
|
3897
3897
|
this.on("error", (er) => reject(er));
|
|
3898
|
-
this.on("end", () =>
|
|
3898
|
+
this.on("end", () => resolve8());
|
|
3899
3899
|
});
|
|
3900
3900
|
}
|
|
3901
3901
|
/**
|
|
@@ -3919,7 +3919,7 @@ var Minipass = class extends EventEmitter {
|
|
|
3919
3919
|
return Promise.resolve({ done: false, value: res });
|
|
3920
3920
|
if (this[EOF])
|
|
3921
3921
|
return stop();
|
|
3922
|
-
let
|
|
3922
|
+
let resolve8;
|
|
3923
3923
|
let reject;
|
|
3924
3924
|
const onerr = (er) => {
|
|
3925
3925
|
this.off("data", ondata);
|
|
@@ -3933,19 +3933,19 @@ var Minipass = class extends EventEmitter {
|
|
|
3933
3933
|
this.off("end", onend);
|
|
3934
3934
|
this.off(DESTROYED, ondestroy);
|
|
3935
3935
|
this.pause();
|
|
3936
|
-
|
|
3936
|
+
resolve8({ value, done: !!this[EOF] });
|
|
3937
3937
|
};
|
|
3938
3938
|
const onend = () => {
|
|
3939
3939
|
this.off("error", onerr);
|
|
3940
3940
|
this.off("data", ondata);
|
|
3941
3941
|
this.off(DESTROYED, ondestroy);
|
|
3942
3942
|
stop();
|
|
3943
|
-
|
|
3943
|
+
resolve8({ done: true, value: void 0 });
|
|
3944
3944
|
};
|
|
3945
3945
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
3946
3946
|
return new Promise((res2, rej) => {
|
|
3947
3947
|
reject = rej;
|
|
3948
|
-
|
|
3948
|
+
resolve8 = res2;
|
|
3949
3949
|
this.once(DESTROYED, ondestroy);
|
|
3950
3950
|
this.once("error", onerr);
|
|
3951
3951
|
this.once("end", onend);
|
|
@@ -4917,9 +4917,9 @@ var PathBase = class {
|
|
|
4917
4917
|
if (this.#asyncReaddirInFlight) {
|
|
4918
4918
|
await this.#asyncReaddirInFlight;
|
|
4919
4919
|
} else {
|
|
4920
|
-
let
|
|
4920
|
+
let resolve8 = () => {
|
|
4921
4921
|
};
|
|
4922
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
4922
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
|
|
4923
4923
|
try {
|
|
4924
4924
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
4925
4925
|
withFileTypes: true
|
|
@@ -4932,7 +4932,7 @@ var PathBase = class {
|
|
|
4932
4932
|
children.provisional = 0;
|
|
4933
4933
|
}
|
|
4934
4934
|
this.#asyncReaddirInFlight = void 0;
|
|
4935
|
-
|
|
4935
|
+
resolve8();
|
|
4936
4936
|
}
|
|
4937
4937
|
return children.slice(0, children.provisional);
|
|
4938
4938
|
}
|
|
@@ -10413,7 +10413,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
10413
10413
|
});
|
|
10414
10414
|
if (!chunk) {
|
|
10415
10415
|
if (i === 1) {
|
|
10416
|
-
await new Promise((
|
|
10416
|
+
await new Promise((resolve8) => setTimeout(resolve8));
|
|
10417
10417
|
maxReadCount = 3;
|
|
10418
10418
|
continue;
|
|
10419
10419
|
}
|
|
@@ -14408,7 +14408,7 @@ import { createHmac, hkdfSync, randomBytes as randomBytes2 } from "crypto";
|
|
|
14408
14408
|
import { createHash, randomBytes } from "crypto";
|
|
14409
14409
|
import { readFileSync as readFileSync4, existsSync as existsSync22 } from "fs";
|
|
14410
14410
|
import { homedir as homedir2 } from "os";
|
|
14411
|
-
import { join as join22, dirname, parse } from "path";
|
|
14411
|
+
import { join as join22, dirname, parse, resolve } from "path";
|
|
14412
14412
|
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync2, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
14413
14413
|
import { homedir } from "os";
|
|
14414
14414
|
import { join as join4 } from "path";
|
|
@@ -14481,6 +14481,7 @@ function tighten(path2, exact, kind) {
|
|
|
14481
14481
|
);
|
|
14482
14482
|
}
|
|
14483
14483
|
}
|
|
14484
|
+
var PROJECT_ROOT_ENV = "PRETENSE_PROJECT_ROOT";
|
|
14484
14485
|
var KEYS_DIR_NAME = join22(".pretense", "keys");
|
|
14485
14486
|
function keysDir() {
|
|
14486
14487
|
return join22(homedir2(), KEYS_DIR_NAME);
|
|
@@ -14503,7 +14504,25 @@ var PROJECT_MARKERS = [
|
|
|
14503
14504
|
".hg",
|
|
14504
14505
|
".svn"
|
|
14505
14506
|
];
|
|
14507
|
+
function markersAt(dir, home) {
|
|
14508
|
+
return dir === home ? PROJECT_MARKERS.filter((m) => m !== ".pretense") : PROJECT_MARKERS;
|
|
14509
|
+
}
|
|
14506
14510
|
function findProjectRoot(filePath) {
|
|
14511
|
+
let dir = dirname(filePath);
|
|
14512
|
+
const { root } = parse(dir);
|
|
14513
|
+
const startDir = dir;
|
|
14514
|
+
const home = homedir2();
|
|
14515
|
+
while (true) {
|
|
14516
|
+
if (markersAt(dir, home).some((m) => existsSync22(join22(dir, m)))) {
|
|
14517
|
+
return dir;
|
|
14518
|
+
}
|
|
14519
|
+
if (dir === root) return startDir;
|
|
14520
|
+
const parent = dirname(dir);
|
|
14521
|
+
if (parent === dir) return startDir;
|
|
14522
|
+
dir = parent;
|
|
14523
|
+
}
|
|
14524
|
+
}
|
|
14525
|
+
function legacyFindProjectRoot(filePath) {
|
|
14507
14526
|
let dir = dirname(filePath);
|
|
14508
14527
|
const { root } = parse(dir);
|
|
14509
14528
|
const startDir = dir;
|
|
@@ -14517,6 +14536,21 @@ function findProjectRoot(filePath) {
|
|
|
14517
14536
|
dir = parent;
|
|
14518
14537
|
}
|
|
14519
14538
|
}
|
|
14539
|
+
function resolveProjectRoot(filePath) {
|
|
14540
|
+
const override2 = process.env[PROJECT_ROOT_ENV];
|
|
14541
|
+
if (override2 && override2.trim()) return resolve(override2.trim());
|
|
14542
|
+
return findProjectRoot(filePath);
|
|
14543
|
+
}
|
|
14544
|
+
function candidateProjectRoots(filePath) {
|
|
14545
|
+
const out = [];
|
|
14546
|
+
const override2 = process.env[PROJECT_ROOT_ENV];
|
|
14547
|
+
if (override2 && override2.trim()) out.push(resolve(override2.trim()));
|
|
14548
|
+
out.push(findProjectRoot(filePath));
|
|
14549
|
+
out.push(dirname(filePath));
|
|
14550
|
+
out.push(legacyFindProjectRoot(filePath));
|
|
14551
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14552
|
+
return out.filter((r) => seen.has(r) ? false : (seen.add(r), true));
|
|
14553
|
+
}
|
|
14520
14554
|
function findProjectRootForDir(dir) {
|
|
14521
14555
|
return findProjectRoot(join22(dir, "__pretense_probe__"));
|
|
14522
14556
|
}
|
|
@@ -16335,7 +16369,7 @@ import { join as join5 } from "path";
|
|
|
16335
16369
|
import { parse as parseYaml } from "yaml";
|
|
16336
16370
|
import { readFileSync as readFileSync23 } from "fs";
|
|
16337
16371
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
16338
|
-
import { dirname as dirname3, join as join23, resolve } from "path";
|
|
16372
|
+
import { dirname as dirname3, join as join23, resolve as resolve2 } from "path";
|
|
16339
16373
|
import https from "https";
|
|
16340
16374
|
|
|
16341
16375
|
// ../packages/tls/dist/index.js
|
|
@@ -16471,7 +16505,7 @@ function versionFromCliPackageJson() {
|
|
|
16471
16505
|
}
|
|
16472
16506
|
} catch {
|
|
16473
16507
|
}
|
|
16474
|
-
const parent =
|
|
16508
|
+
const parent = resolve2(dir, "..");
|
|
16475
16509
|
if (parent === dir) break;
|
|
16476
16510
|
dir = parent;
|
|
16477
16511
|
}
|
|
@@ -16480,11 +16514,11 @@ function versionFromCliPackageJson() {
|
|
|
16480
16514
|
return void 0;
|
|
16481
16515
|
}
|
|
16482
16516
|
function productVersion() {
|
|
16483
|
-
return override ?? (true ? "0.6.
|
|
16517
|
+
return override ?? (true ? "0.6.18" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
|
|
16484
16518
|
}
|
|
16485
16519
|
var UNKNOWN_COMMIT = "unknown";
|
|
16486
16520
|
function bakedCommitSha() {
|
|
16487
|
-
return "
|
|
16521
|
+
return "220d098b1829361f3d0043fb24275e5fdfb84429".length > 0 ? "220d098b1829361f3d0043fb24275e5fdfb84429" : UNKNOWN_COMMIT;
|
|
16488
16522
|
}
|
|
16489
16523
|
var FEATURE_TIERS = {
|
|
16490
16524
|
compliance_export: "pro",
|
|
@@ -17235,6 +17269,57 @@ function toSecretFindings(matches) {
|
|
|
17235
17269
|
function isBase64Blob(text) {
|
|
17236
17270
|
return text.length >= 256 && !/\s/.test(text) && /^[A-Za-z0-9+/_=-]+$/.test(text);
|
|
17237
17271
|
}
|
|
17272
|
+
var BLOB_SECRET_INDICATORS = [
|
|
17273
|
+
/AKIA[0-9A-Z]{16}/,
|
|
17274
|
+
// AWS access key id
|
|
17275
|
+
/ASIA[0-9A-Z]{16}/,
|
|
17276
|
+
// AWS temporary access key id
|
|
17277
|
+
/gh[opsu]_[A-Za-z0-9]{36}/,
|
|
17278
|
+
// GitHub PAT / OAuth / app / refresh
|
|
17279
|
+
/github_pat_[0-9A-Za-z_]{22,}/,
|
|
17280
|
+
// GitHub fine-grained PAT
|
|
17281
|
+
/sk-ant-[A-Za-z0-9_-]{24,}/,
|
|
17282
|
+
// Anthropic API key
|
|
17283
|
+
/sk_live_[A-Za-z0-9]{20,}/,
|
|
17284
|
+
// Stripe live secret key
|
|
17285
|
+
/rk_live_[A-Za-z0-9]{20,}/,
|
|
17286
|
+
// Stripe live restricted key
|
|
17287
|
+
/AIza[0-9A-Za-z_-]{35}/,
|
|
17288
|
+
// Google API key
|
|
17289
|
+
/xox[baprs]-[0-9A-Za-z-]{10,}/,
|
|
17290
|
+
// Slack token
|
|
17291
|
+
/npm_[A-Za-z0-9]{36}/,
|
|
17292
|
+
// npm token
|
|
17293
|
+
/glpat-[0-9A-Za-z_-]{20}/,
|
|
17294
|
+
// GitLab PAT
|
|
17295
|
+
/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/
|
|
17296
|
+
// PEM private key banner
|
|
17297
|
+
];
|
|
17298
|
+
function blobSecretIndicator(text) {
|
|
17299
|
+
for (const re of BLOB_SECRET_INDICATORS) {
|
|
17300
|
+
if (re.test(text)) return re.source.slice(0, 24);
|
|
17301
|
+
}
|
|
17302
|
+
return null;
|
|
17303
|
+
}
|
|
17304
|
+
var BLOB_DECODE_SCAN_MAX_CHARS = 4 * 1024 * 1024;
|
|
17305
|
+
function decodedTextIfLikelyText(text) {
|
|
17306
|
+
if (text.length > BLOB_DECODE_SCAN_MAX_CHARS) return null;
|
|
17307
|
+
let buf;
|
|
17308
|
+
try {
|
|
17309
|
+
buf = Buffer.from(text.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
17310
|
+
} catch {
|
|
17311
|
+
return null;
|
|
17312
|
+
}
|
|
17313
|
+
if (buf.length === 0) return null;
|
|
17314
|
+
const sample = Math.min(buf.length, 4096);
|
|
17315
|
+
let printable = 0;
|
|
17316
|
+
for (let i = 0; i < sample; i++) {
|
|
17317
|
+
const b = buf[i] ?? 0;
|
|
17318
|
+
if (b === 9 || b === 10 || b === 13 || b >= 32 && b <= 126) printable++;
|
|
17319
|
+
}
|
|
17320
|
+
if (printable / sample < 0.85) return null;
|
|
17321
|
+
return buf.toString("utf8");
|
|
17322
|
+
}
|
|
17238
17323
|
var CONTROL_CHAR_RE = /[\u0000-\u001f]/;
|
|
17239
17324
|
var CONTROL_CHAR_RE_G = /[\u0000-\u001f]/g;
|
|
17240
17325
|
function tokenizeBodyDeep(body, scanText, derivation) {
|
|
@@ -17272,11 +17357,39 @@ function tokenizeBodyDeep(body, scanText, derivation) {
|
|
|
17272
17357
|
}
|
|
17273
17358
|
return out;
|
|
17274
17359
|
};
|
|
17275
|
-
const
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17360
|
+
const redactWholeBlob = (text, type) => {
|
|
17361
|
+
const { content, mutations } = mutateSecrets(
|
|
17362
|
+
text,
|
|
17363
|
+
[{ value: text, offset: 0, length: text.length, type }],
|
|
17364
|
+
derivation
|
|
17365
|
+
);
|
|
17366
|
+
for (const mu of mutations) {
|
|
17367
|
+
if (!secretMap.has(mu.replacement)) secretMap.set(mu.replacement, mu.original);
|
|
17368
|
+
}
|
|
17369
|
+
foundTypes.add(type);
|
|
17370
|
+
secretsTokenized++;
|
|
17371
|
+
return content;
|
|
17372
|
+
};
|
|
17373
|
+
const scanBlobLeaf = (text) => {
|
|
17374
|
+
const ind = blobSecretIndicator(text);
|
|
17375
|
+
if (ind) return redactWholeBlob(text, `unscannable-blob:${ind}`);
|
|
17376
|
+
const decoded = decodedTextIfLikelyText(text);
|
|
17377
|
+
if (decoded !== null) {
|
|
17378
|
+
const s = scanText(decoded);
|
|
17379
|
+
if (s.incomplete) {
|
|
17380
|
+
scanIncomplete = true;
|
|
17381
|
+
droppedFindings += s.limits.droppedFindings;
|
|
17382
|
+
for (const r of s.limits.reasons) incompleteReasons.add(r);
|
|
17383
|
+
}
|
|
17384
|
+
if (toSecretFindings(s.matches).length > 0) {
|
|
17385
|
+
return redactWholeBlob(text, "unscannable-blob:encoded-secret");
|
|
17386
|
+
}
|
|
17279
17387
|
}
|
|
17388
|
+
skippedUnscannable++;
|
|
17389
|
+
return text;
|
|
17390
|
+
};
|
|
17391
|
+
const tokenizeLeaf = (text) => {
|
|
17392
|
+
if (isBase64Blob(text)) return scanBlobLeaf(text);
|
|
17280
17393
|
return tokenizeText(text);
|
|
17281
17394
|
};
|
|
17282
17395
|
const stack = [body];
|
|
@@ -17989,14 +18102,14 @@ if (isMain) {
|
|
|
17989
18102
|
init_esm_shims();
|
|
17990
18103
|
import net from "net";
|
|
17991
18104
|
function isPortFree(port) {
|
|
17992
|
-
return new Promise((
|
|
18105
|
+
return new Promise((resolve8) => {
|
|
17993
18106
|
const srv = net.createServer();
|
|
17994
18107
|
srv.once("error", () => {
|
|
17995
|
-
srv.close(() =>
|
|
17996
|
-
|
|
18108
|
+
srv.close(() => resolve8(false));
|
|
18109
|
+
resolve8(false);
|
|
17997
18110
|
});
|
|
17998
18111
|
srv.once("listening", () => {
|
|
17999
|
-
srv.close(() =>
|
|
18112
|
+
srv.close(() => resolve8(true));
|
|
18000
18113
|
});
|
|
18001
18114
|
srv.listen(port);
|
|
18002
18115
|
});
|
|
@@ -18662,7 +18775,7 @@ import { Command as Command5, Option, InvalidArgumentError as InvalidArgumentErr
|
|
|
18662
18775
|
import chalk5 from "chalk";
|
|
18663
18776
|
import { readFileSync as readFileSync8, statSync as statSync3, readdirSync as readdirSync2, openSync, readSync, closeSync } from "fs";
|
|
18664
18777
|
import { execSync as execSync3 } from "child_process";
|
|
18665
|
-
import { resolve as
|
|
18778
|
+
import { resolve as resolve3, join as join8, extname as extname2, basename } from "path";
|
|
18666
18779
|
|
|
18667
18780
|
// src/safe-output.ts
|
|
18668
18781
|
init_esm_shims();
|
|
@@ -18789,7 +18902,7 @@ function isBinaryFile(filePath) {
|
|
|
18789
18902
|
}
|
|
18790
18903
|
var SEVERITY_ORDER = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
18791
18904
|
function collectFiles(target) {
|
|
18792
|
-
const abs =
|
|
18905
|
+
const abs = resolve3(target);
|
|
18793
18906
|
let stat;
|
|
18794
18907
|
try {
|
|
18795
18908
|
stat = statSync3(abs);
|
|
@@ -20469,7 +20582,7 @@ import {
|
|
|
20469
20582
|
readFileSync as readFileSync13,
|
|
20470
20583
|
mkdirSync as mkdirSync3
|
|
20471
20584
|
} from "fs";
|
|
20472
|
-
import { join as join15, resolve as
|
|
20585
|
+
import { join as join15, resolve as resolve4 } from "path";
|
|
20473
20586
|
var HOOK_SCRIPTS = {
|
|
20474
20587
|
"pre-commit": `#!/bin/sh
|
|
20475
20588
|
# Pretense AI Firewall \u2014 pre-commit hook
|
|
@@ -20511,7 +20624,7 @@ function installCommand() {
|
|
|
20511
20624
|
"-m, --mode <mode>",
|
|
20512
20625
|
"Hook mode: pre-commit, pre-push (omit to install both)"
|
|
20513
20626
|
).option("-f, --force", "Overwrite existing hooks without prompting", false).option("-d, --dir <path>", "Project directory (defaults to cwd)", ".").action((opts) => {
|
|
20514
|
-
const dir =
|
|
20627
|
+
const dir = resolve4(opts.dir);
|
|
20515
20628
|
const force = opts.force;
|
|
20516
20629
|
const modeArg = opts.mode;
|
|
20517
20630
|
if (modeArg && !VALID_MODES.includes(modeArg)) {
|
|
@@ -20887,7 +21000,7 @@ init_esm_shims();
|
|
|
20887
21000
|
import { Command as Command15 } from "commander";
|
|
20888
21001
|
import chalk14 from "chalk";
|
|
20889
21002
|
import { existsSync as existsSync14, writeFileSync as writeFileSync6 } from "fs";
|
|
20890
|
-
import { join as join17, resolve as
|
|
21003
|
+
import { join as join17, resolve as resolve5 } from "path";
|
|
20891
21004
|
var DEFAULT_CONFIG_YAML = `scan:
|
|
20892
21005
|
secrets: block
|
|
20893
21006
|
pii: redact
|
|
@@ -20914,7 +21027,7 @@ verbose: false
|
|
|
20914
21027
|
`;
|
|
20915
21028
|
function quickstartCommand() {
|
|
20916
21029
|
return new Command15("quickstart").description("One-command setup: init + install hooks + show next steps").option("-d, --dir <path>", "Directory to scan", ".").option("--dry-run", "Print what would be written without writing", false).action(async (opts) => {
|
|
20917
|
-
const dir =
|
|
21030
|
+
const dir = resolve5(opts.dir);
|
|
20918
21031
|
console.log(chalk14.bold.cyan("\n Pretense Quickstart\n"));
|
|
20919
21032
|
console.log(chalk14.dim(" Setting up AI firewall for this project...\n"));
|
|
20920
21033
|
console.log(chalk14.dim(" [1/4] Scanning codebase..."));
|
|
@@ -20971,7 +21084,7 @@ import { Command as Command16, Option as Option2 } from "commander";
|
|
|
20971
21084
|
import chalk16 from "chalk";
|
|
20972
21085
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, chmodSync as chmodSync4, existsSync as existsSync15 } from "fs";
|
|
20973
21086
|
import { createHash as createHash3 } from "crypto";
|
|
20974
|
-
import { resolve as
|
|
21087
|
+
import { resolve as resolve6, extname as extname4 } from "path";
|
|
20975
21088
|
|
|
20976
21089
|
// src/secret-crypto.ts
|
|
20977
21090
|
init_esm_shims();
|
|
@@ -21156,7 +21269,7 @@ function preflightReversalMap(mapPath, absFile, content, contentSha, force) {
|
|
|
21156
21269
|
to overwrite it deliberately.`
|
|
21157
21270
|
};
|
|
21158
21271
|
}
|
|
21159
|
-
const existingFile = existing.file ?
|
|
21272
|
+
const existingFile = existing.file ? resolve6(existing.file) : void 0;
|
|
21160
21273
|
if (existingFile && existingFile !== absFile) {
|
|
21161
21274
|
if (force) {
|
|
21162
21275
|
return { action: "write", generation: 1, supersededSha: existing.originalSha };
|
|
@@ -21326,8 +21439,8 @@ async function runMutate(file, opts = {}) {
|
|
|
21326
21439
|
return 0;
|
|
21327
21440
|
}
|
|
21328
21441
|
reportUnmutatable(unmutatable);
|
|
21329
|
-
const absFile =
|
|
21330
|
-
const projectRoot =
|
|
21442
|
+
const absFile = resolve6(file);
|
|
21443
|
+
const projectRoot = resolveProjectRoot(absFile);
|
|
21331
21444
|
const result = mutateSecrets(content, findings, { projectRoot, keysDir: opts.keysDir });
|
|
21332
21445
|
let effectiveMap;
|
|
21333
21446
|
if (preview) {
|
|
@@ -21480,7 +21593,7 @@ init_esm_shims();
|
|
|
21480
21593
|
import { Command as Command17 } from "commander";
|
|
21481
21594
|
import chalk17 from "chalk";
|
|
21482
21595
|
import { readFileSync as readFileSync16, existsSync as existsSync16, statSync as statSync6 } from "fs";
|
|
21483
|
-
import { resolve as
|
|
21596
|
+
import { resolve as resolve7 } from "path";
|
|
21484
21597
|
import { createHash as createHash4 } from "crypto";
|
|
21485
21598
|
function sha256Hex3(s) {
|
|
21486
21599
|
return createHash4("sha256").update(s, "utf8").digest("hex");
|
|
@@ -21539,7 +21652,7 @@ function loadReversalMap(mapPath) {
|
|
|
21539
21652
|
}
|
|
21540
21653
|
function runReverse(file, opts = {}) {
|
|
21541
21654
|
const reverseStartMs = Date.now();
|
|
21542
|
-
const absPath =
|
|
21655
|
+
const absPath = resolve7(file);
|
|
21543
21656
|
if (!existsSync16(absPath) || !statSync6(absPath).isFile()) {
|
|
21544
21657
|
console.error(chalk17.red(`
|
|
21545
21658
|
x File not found: ${file}
|
|
@@ -21561,30 +21674,41 @@ function runReverse(file, opts = {}) {
|
|
|
21561
21674
|
const mapFile = loadReversalMap(mapPath);
|
|
21562
21675
|
let plainMutations;
|
|
21563
21676
|
if (mapFile.encrypted) {
|
|
21564
|
-
const
|
|
21565
|
-
const
|
|
21566
|
-
|
|
21567
|
-
|
|
21568
|
-
|
|
21569
|
-
|
|
21570
|
-
|
|
21571
|
-
|
|
21572
|
-
|
|
21573
|
-
|
|
21677
|
+
const keySource = mapFile.file ?? absPath;
|
|
21678
|
+
const roots = candidateProjectRoots(keySource);
|
|
21679
|
+
let decrypted;
|
|
21680
|
+
let anyKeyPresent = false;
|
|
21681
|
+
for (const root of roots) {
|
|
21682
|
+
const key = readProjectKey(root, opts.keysDir);
|
|
21683
|
+
if (!key) continue;
|
|
21684
|
+
anyKeyPresent = true;
|
|
21685
|
+
try {
|
|
21686
|
+
decrypted = mapFile.mutations.map((m) => ({
|
|
21687
|
+
original: decryptSecret(m.original, key),
|
|
21688
|
+
replacement: m.replacement
|
|
21689
|
+
}));
|
|
21690
|
+
break;
|
|
21691
|
+
} catch {
|
|
21692
|
+
decrypted = void 0;
|
|
21693
|
+
}
|
|
21574
21694
|
}
|
|
21575
|
-
|
|
21576
|
-
|
|
21577
|
-
original: decryptSecret(m.original, key),
|
|
21578
|
-
replacement: m.replacement
|
|
21579
|
-
}));
|
|
21580
|
-
} catch {
|
|
21695
|
+
if (!decrypted) {
|
|
21696
|
+
const looked = roots.join("\n ");
|
|
21581
21697
|
console.error(
|
|
21582
21698
|
chalk17.red(`
|
|
21583
|
-
x
|
|
21699
|
+
x Encryption key not found for this file \u2014 cannot decrypt the reversal map.`) + (anyKeyPresent ? chalk17.dim(`
|
|
21700
|
+
A key was present but did not decrypt this map (wrong key or corrupt data).`) : chalk17.dim(`
|
|
21701
|
+
No key was found under any known project location for this file.`)) + chalk17.dim(`
|
|
21702
|
+
Looked under these project roots (keys dir ${opts.keysDir ?? "~/.pretense/keys"}):`) + chalk17.dim(`
|
|
21703
|
+
${looked}`) + chalk17.dim(`
|
|
21704
|
+
Run \`reverse\` on the SAME machine and HOME where you mutated the file,`) + chalk17.dim(`
|
|
21705
|
+
or set ${chalk17.cyan("PRETENSE_PROJECT_ROOT")} to the project root used at mutate time.`) + chalk17.dim(`
|
|
21706
|
+
File left untouched.
|
|
21584
21707
|
`)
|
|
21585
21708
|
);
|
|
21586
21709
|
return 1;
|
|
21587
21710
|
}
|
|
21711
|
+
plainMutations = decrypted;
|
|
21588
21712
|
} else {
|
|
21589
21713
|
plainMutations = mapFile.mutations.map((m) => ({ original: m.original, replacement: m.replacement }));
|
|
21590
21714
|
}
|
package/dist/postinstall.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pretense/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.18",
|
|
4
4
|
"description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
"tsx": "^4.0.0",
|
|
24
24
|
"typescript": "^5.4.0",
|
|
25
25
|
"vitest": "^1.0.0",
|
|
26
|
+
"@pretense/billing": "0.1.0",
|
|
26
27
|
"@pretense/protocol": "0.1.0",
|
|
27
28
|
"@pretense/compliance-engine": "0.1.0",
|
|
28
|
-
"@pretense/
|
|
29
|
+
"@pretense/learner": "0.2.0",
|
|
29
30
|
"@pretense/mutator": "0.2.0",
|
|
31
|
+
"@pretense/proxy": "0.1.0",
|
|
30
32
|
"@pretense/scanner": "0.2.0",
|
|
31
33
|
"@pretense/scanner-rs": "0.2.0",
|
|
32
|
-
"@pretense/store": "0.2.0"
|
|
33
|
-
"@pretense/billing": "0.1.0",
|
|
34
|
-
"@pretense/learner": "0.2.0"
|
|
34
|
+
"@pretense/store": "0.2.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public",
|