@pretense/cli 0.6.12 → 0.6.13
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.
|
@@ -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.13" : 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-HWSWJ4EC.js";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__toESM,
|
|
@@ -12171,6 +12171,19 @@ var SECRET_PATTERNS = [
|
|
|
12171
12171
|
defaultAction: "block",
|
|
12172
12172
|
pattern: /\bgithub_pat_[A-Za-z0-9_]{22,}\b/g
|
|
12173
12173
|
},
|
|
12174
|
+
// FIX 1 (v0.6.13) — HuggingFace access tokens. `hf_` user and fine-grained
|
|
12175
|
+
// access tokens are `hf_` + 34+ base62 chars. Confirmed leaking on 0.6.12:
|
|
12176
|
+
// an `hf_` token in bare prose scanned clean (a real credential egressed to
|
|
12177
|
+
// the LLM) because no `hf_`/`huggingface` pattern existed. The `hf_` prefix
|
|
12178
|
+
// plus a 34+ base62 body is a near-zero-false-positive signal. Critical/block
|
|
12179
|
+
// because a live model-registry token grants push access to private models.
|
|
12180
|
+
{
|
|
12181
|
+
name: "huggingface-token",
|
|
12182
|
+
category: "secret",
|
|
12183
|
+
severity: "critical",
|
|
12184
|
+
defaultAction: "block",
|
|
12185
|
+
pattern: /\bhf_[A-Za-z0-9]{34,}\b/g
|
|
12186
|
+
},
|
|
12174
12187
|
{
|
|
12175
12188
|
name: "gitlab-token",
|
|
12176
12189
|
category: "secret",
|
|
@@ -12745,8 +12758,9 @@ var ENV_PATTERNS = [
|
|
|
12745
12758
|
// variable references (`$VAR`, `${VAR}`, `process.env.X`, `os.environ…`),
|
|
12746
12759
|
// connection URLs (handled by `database-url`), and values that begin with a
|
|
12747
12760
|
// recognised structured-secret prefix (Stripe `sk_`/`pk_`/`rk_`, OpenAI
|
|
12748
|
-
// `sk-`, Slack `xox*`, GitHub `gh*_`/`glpat-`,
|
|
12749
|
-
// Stripe webhook `whsec_`) are deliberately skipped
|
|
12761
|
+
// `sk-`, Slack `xox*`, GitHub `gh*_`/`glpat-`, HuggingFace `hf_`, AWS
|
|
12762
|
+
// `AKIA`, Google `AIza`, Stripe webhook `whsec_`) are deliberately skipped
|
|
12763
|
+
// so a generic
|
|
12750
12764
|
// `KEY=variable` reference is not flagged and the dedicated, higher-fidelity
|
|
12751
12765
|
// patterns above own those matches. Placed last so more-specific patterns
|
|
12752
12766
|
// win overlap deduplication on ties.
|
|
@@ -12760,7 +12774,7 @@ var ENV_PATTERNS = [
|
|
|
12760
12774
|
// specific env-var names rather than generic secret-label tails, so they do
|
|
12761
12775
|
// not belong in the shared vocabulary.
|
|
12762
12776
|
pattern: new RegExp(
|
|
12763
|
-
`(?<![A-Za-z0-9])(?:[A-Z0-9]+[._-])*(?:${ENV_SECRET_LABEL_ALTERNATION}|DATABASE_URL|VAULT_TOKEN)\\s*[=:]\\s*(?!['"\\s])(?!\\$)(?!process\\.env)(?!os\\.environ)(?![A-Za-z][A-Za-z0-9+.-]*:\\/\\/)(?!sk[-_]|pk_|rk_|whsec_|xox[bpors]-|ghp_|gho_|ghs_|glpat-|AKIA|AIza)[A-Za-z0-9/+._@:!#%^&*?~-]{8,}`,
|
|
12777
|
+
`(?<![A-Za-z0-9])(?:[A-Z0-9]+[._-])*(?:${ENV_SECRET_LABEL_ALTERNATION}|DATABASE_URL|VAULT_TOKEN)\\s*[=:]\\s*(?!['"\\s])(?!\\$)(?!process\\.env)(?!os\\.environ)(?![A-Za-z][A-Za-z0-9+.-]*:\\/\\/)(?!sk[-_]|pk_|rk_|whsec_|xox[bpors]-|ghp_|gho_|ghs_|glpat-|hf_|AKIA|AIza)[A-Za-z0-9/+._@:!#%^&*?~-]{8,}`,
|
|
12764
12778
|
"gi"
|
|
12765
12779
|
),
|
|
12766
12780
|
// PRECISION: reject `PASSWORD=changeme`, `PASSWORD=<your-password>` and
|
|
@@ -13827,6 +13841,8 @@ function overlapsAny(m, sorted) {
|
|
|
13827
13841
|
}
|
|
13828
13842
|
async function scanLevel2(text, language, opts = {}) {
|
|
13829
13843
|
const lang = language ?? opts.language ?? "typescript";
|
|
13844
|
+
const t0 = performance.now();
|
|
13845
|
+
const elapsed = () => Math.round((performance.now() - t0) * 100) / 100;
|
|
13830
13846
|
const base = opts.presidioUrl ? await scanWithPresidio(text, opts.presidioUrl, opts) : scan(text, opts);
|
|
13831
13847
|
const l1Matches = base.matches.map((m) => ({ ...m, level: 1 }));
|
|
13832
13848
|
const l1Findings = base.findings.map((f) => ({ ...f, level: 1 }));
|
|
@@ -13834,6 +13850,8 @@ async function scanLevel2(text, language, opts = {}) {
|
|
|
13834
13850
|
...base,
|
|
13835
13851
|
matches: l1Matches,
|
|
13836
13852
|
findings: l1Findings,
|
|
13853
|
+
// Real wall time up to this early return, not the L1 sub-phase alone.
|
|
13854
|
+
durationMs: elapsed(),
|
|
13837
13855
|
l2: status
|
|
13838
13856
|
});
|
|
13839
13857
|
const native = loadNative();
|
|
@@ -13911,7 +13929,9 @@ async function scanLevel2(text, language, opts = {}) {
|
|
|
13911
13929
|
matches: merged,
|
|
13912
13930
|
findings: mergedFindings,
|
|
13913
13931
|
scannedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13914
|
-
|
|
13932
|
+
// Real elapsed wall time for the full L1+L2 scan (was base.durationMs, the
|
|
13933
|
+
// L1-only time, which undercounted the AST work ~25x — see FIX 3/TASK-16).
|
|
13934
|
+
durationMs: elapsed(),
|
|
13915
13935
|
patternCount: base.patternCount,
|
|
13916
13936
|
// Bounded-work state is a property of the underlying scan and MUST survive
|
|
13917
13937
|
// this merge — dropping it here would re-create the silent-incomplete hole
|
|
@@ -16425,11 +16445,11 @@ function versionFromCliPackageJson() {
|
|
|
16425
16445
|
return void 0;
|
|
16426
16446
|
}
|
|
16427
16447
|
function productVersion() {
|
|
16428
|
-
return override ?? (true ? "0.6.
|
|
16448
|
+
return override ?? (true ? "0.6.13" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
|
|
16429
16449
|
}
|
|
16430
16450
|
var UNKNOWN_COMMIT = "unknown";
|
|
16431
16451
|
function bakedCommitSha() {
|
|
16432
|
-
return "
|
|
16452
|
+
return "a36bf5d80a91cfd8fbf57e6c5a6a9b9114826309".length > 0 ? "a36bf5d80a91cfd8fbf57e6c5a6a9b9114826309" : UNKNOWN_COMMIT;
|
|
16433
16453
|
}
|
|
16434
16454
|
var FEATURE_TIERS = {
|
|
16435
16455
|
compliance_export: "pro",
|
|
@@ -18323,9 +18343,24 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
18323
18343
|
".idea",
|
|
18324
18344
|
".vscode"
|
|
18325
18345
|
]);
|
|
18346
|
+
function isSkippableWalkError(err) {
|
|
18347
|
+
const code = err?.code;
|
|
18348
|
+
return code === "EACCES" || code === "EPERM" || code === "ENOENT" || code === "ELOOP" || code === "ENOTDIR";
|
|
18349
|
+
}
|
|
18326
18350
|
function walkDir(dir) {
|
|
18327
18351
|
const files = [];
|
|
18328
|
-
|
|
18352
|
+
let entries;
|
|
18353
|
+
try {
|
|
18354
|
+
entries = readdirSync2(dir, { withFileTypes: true });
|
|
18355
|
+
} catch (err) {
|
|
18356
|
+
if (isSkippableWalkError(err)) {
|
|
18357
|
+
const code = err.code;
|
|
18358
|
+
console.error(chalk4.yellow(` Skipping unreadable path (${code}): ${dir}`));
|
|
18359
|
+
return files;
|
|
18360
|
+
}
|
|
18361
|
+
throw err;
|
|
18362
|
+
}
|
|
18363
|
+
for (const entry of entries) {
|
|
18329
18364
|
if (entry.isDirectory()) {
|
|
18330
18365
|
if (entry.name.startsWith(".") || SKIP_DIRS.has(entry.name)) continue;
|
|
18331
18366
|
files.push(...walkDir(join7(dir, entry.name)));
|
|
@@ -18378,6 +18413,18 @@ function l2LanguageFor(filePath) {
|
|
|
18378
18413
|
if (!filePath) return void 0;
|
|
18379
18414
|
return L2_LANGUAGE_BY_EXT[extname2(filePath).toLowerCase()];
|
|
18380
18415
|
}
|
|
18416
|
+
var L2_LARGE_FILE_WARN_BYTES = 5 * 1024 * 1024;
|
|
18417
|
+
function warnIfLargeForL2(byteLength, filePath) {
|
|
18418
|
+
if (byteLength <= L2_LARGE_FILE_WARN_BYTES) return false;
|
|
18419
|
+
const mb = (byteLength / (1024 * 1024)).toFixed(1);
|
|
18420
|
+
const where = filePath ? ` \u2014 ${basename(filePath)}` : "";
|
|
18421
|
+
console.error(
|
|
18422
|
+
chalk4.yellow(
|
|
18423
|
+
` Note: L2 AST scanning is slow on very large files (${mb}MB${where}); this may take a while.`
|
|
18424
|
+
)
|
|
18425
|
+
);
|
|
18426
|
+
return true;
|
|
18427
|
+
}
|
|
18381
18428
|
async function scanContent(content, opts, filePath) {
|
|
18382
18429
|
return withLocations(await scanContentRaw(content, opts, filePath), content);
|
|
18383
18430
|
}
|
|
@@ -18421,6 +18468,7 @@ async function scanContentRaw(content, opts, filePath) {
|
|
|
18421
18468
|
}
|
|
18422
18469
|
};
|
|
18423
18470
|
}
|
|
18471
|
+
warnIfLargeForL2(Buffer.byteLength(content, "utf-8"), filePath);
|
|
18424
18472
|
const result = await scanLevel2(content, language, scanOpts);
|
|
18425
18473
|
if (opts.level === 2) {
|
|
18426
18474
|
const only2 = result.matches.filter((m) => m.level === 2);
|
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.13",
|
|
4
4
|
"description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"tsx": "^4.0.0",
|
|
24
24
|
"typescript": "^5.4.0",
|
|
25
25
|
"vitest": "^1.0.0",
|
|
26
|
-
"@pretense/compliance-engine": "0.1.0",
|
|
27
|
-
"@pretense/billing": "0.1.0",
|
|
28
26
|
"@pretense/protocol": "0.1.0",
|
|
29
27
|
"@pretense/learner": "0.2.0",
|
|
28
|
+
"@pretense/compliance-engine": "0.1.0",
|
|
30
29
|
"@pretense/mutator": "0.2.0",
|
|
30
|
+
"@pretense/billing": "0.1.0",
|
|
31
31
|
"@pretense/proxy": "0.1.0",
|
|
32
32
|
"@pretense/scanner": "0.2.0",
|
|
33
33
|
"@pretense/scanner-rs": "0.2.0",
|