@pretense/cli 0.6.6 → 0.6.9
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/README.md +31 -2
- package/dist/index.js +316 -27
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -22,6 +22,36 @@ Both install the `pretense` command — the package name is scoped, the binary i
|
|
|
22
22
|
|
|
23
23
|
Requires Node.js 20 or newer.
|
|
24
24
|
|
|
25
|
+
## Verifying a release
|
|
26
|
+
|
|
27
|
+
The released binaries are signed with Sigstore cosign (keyless — no key to
|
|
28
|
+
fetch or leak). Each release ships a `SHA256SUMS` file plus a
|
|
29
|
+
`SHA256SUMS.cosign.bundle` signature covering it. To verify a download:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
VERSION=0.6.8
|
|
33
|
+
TARGET=pretense-darwin-arm64
|
|
34
|
+
BASE="https://www.pretense.ai/releases/${VERSION}"
|
|
35
|
+
|
|
36
|
+
curl -fsSLO "${BASE}/SHA256SUMS"
|
|
37
|
+
curl -fsSLO "${BASE}/SHA256SUMS.cosign.bundle"
|
|
38
|
+
curl -fsSLO "${BASE}/${TARGET}"
|
|
39
|
+
|
|
40
|
+
cosign verify-blob \
|
|
41
|
+
--bundle SHA256SUMS.cosign.bundle \
|
|
42
|
+
--certificate-identity "https://github.com/pretense-a1/pretense/.github/workflows/release.yml@refs/tags/v${VERSION}" \
|
|
43
|
+
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
|
|
44
|
+
SHA256SUMS
|
|
45
|
+
|
|
46
|
+
grep " ${TARGET}$" SHA256SUMS | sha256sum -c - # shasum -a 256 -c - on macOS
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Verify the signature over `SHA256SUMS` *before* trusting any hash inside it —
|
|
50
|
+
checking a binary against an unverified checksum file proves nothing.
|
|
51
|
+
|
|
52
|
+
Full details, including the regexp form for automation and why npm provenance
|
|
53
|
+
is not used, are in [docs/verifying-releases.md](../docs/verifying-releases.md).
|
|
54
|
+
|
|
25
55
|
## First 5 minutes
|
|
26
56
|
|
|
27
57
|
1. Initialize Pretense in your repo.
|
|
@@ -106,5 +136,4 @@ MIT. See [LICENSE](./LICENSE).
|
|
|
106
136
|
|
|
107
137
|
- Homepage: https://pretense.ai
|
|
108
138
|
- Docs: https://pretense.ai/docs
|
|
109
|
-
-
|
|
110
|
-
- Issues: https://github.com/jimmymalhan/pretense/issues
|
|
139
|
+
- Support: https://pretense.ai/contact
|
package/dist/index.js
CHANGED
|
@@ -10383,6 +10383,97 @@ function listPresetIds() {
|
|
|
10383
10383
|
return Object.keys(COMPLIANCE_PRESETS);
|
|
10384
10384
|
}
|
|
10385
10385
|
|
|
10386
|
+
// ../packages/compliance-engine/dist/detector-frameworks.js
|
|
10387
|
+
init_esm_shims();
|
|
10388
|
+
var COMPLIANCE_FRAMEWORKS = ["SOC2", "ISO_27001", "ISO_27701", "NIST_800_53", "NIST_800_171", "FedRAMP", "FISMA", "NIS2", "NYDFS_500", "DORA", "APRA_CPS234", "HIPAA", "HITECH", "HITRUST", "GDPR", "UK_GDPR", "CCPA_CPRA", "LGPD", "PIPEDA", "POPIA", "PIPL", "PDPA_SG", "COPPA", "FERPA", "DPDP", "APPI", "PIPA_KR", "AU_PRIVACY", "FADP", "PDPA_TH", "CJIS", "IRS_1075", "SOX", "GLBA", "CMMC_L2", "PCI_DSS"];
|
|
10389
|
+
var DETECTOR_FRAMEWORKS = {
|
|
10390
|
+
"aba-routing": ["APRA_CPS234", "DORA", "GLBA", "NYDFS_500", "SOX"],
|
|
10391
|
+
"advertising-id": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10392
|
+
"anthropic-api-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10393
|
+
"anthropic-api-key-short": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10394
|
+
"aws-access-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10395
|
+
"aws-secret-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10396
|
+
"aws-temp-access-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10397
|
+
"azure-connection-string": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10398
|
+
"azure-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10399
|
+
"bank-account-labeled": ["APRA_CPS234", "DORA", "GLBA", "IRS_1075", "NYDFS_500", "SOX"],
|
|
10400
|
+
"bitcoin-address": ["DORA", "NYDFS_500"],
|
|
10401
|
+
"card-cvv": ["CCPA_CPRA", "GLBA", "PCI_DSS"],
|
|
10402
|
+
"clinical-diagnosis": ["HIPAA", "HITECH", "HITRUST"],
|
|
10403
|
+
"credit-card": ["APRA_CPS234", "CCPA_CPRA", "DORA", "GLBA", "PCI_DSS"],
|
|
10404
|
+
"cui-contract-number": ["CMMC_L2", "NIST_800_171"],
|
|
10405
|
+
"cui-part-number": ["CMMC_L2", "NIST_800_171"],
|
|
10406
|
+
"cui-program-code": ["CMMC_L2", "NIST_800_171"],
|
|
10407
|
+
"database-url": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10408
|
+
"dob": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "HIPAA", "HITECH", "HITRUST", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10409
|
+
"drivers-license": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "DPDP", "FADP", "FISMA", "GDPR", "IRS_1075", "ISO_27001", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10410
|
+
"email": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "GLBA", "HIPAA", "HITECH", "ISO_27001", "ISO_27701", "LGPD", "NIST_800_53", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10411
|
+
"email-labeled": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "GLBA", "HIPAA", "HITECH", "ISO_27001", "ISO_27701", "LGPD", "NIST_800_53", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10412
|
+
"env-secret": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10413
|
+
"env-secret-unquoted": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10414
|
+
"eth-wallet": ["DORA", "NYDFS_500"],
|
|
10415
|
+
"gcp-service-account": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10416
|
+
"generic-secret": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10417
|
+
"generic-secret-assignment": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10418
|
+
"github-fine-grained": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10419
|
+
"github-token": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10420
|
+
"github-token-split": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10421
|
+
"google-api-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10422
|
+
"google-oauth-refresh": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10423
|
+
"iban": ["DORA", "FADP", "GDPR", "GLBA", "UK_GDPR"],
|
|
10424
|
+
"iban-grouped": ["DORA", "FADP", "GDPR", "GLBA", "UK_GDPR"],
|
|
10425
|
+
"iban-spaced": ["DORA", "FADP", "GDPR", "GLBA", "UK_GDPR"],
|
|
10426
|
+
"icd10-bracketed": ["HIPAA", "HITECH", "HITRUST"],
|
|
10427
|
+
"icd10-code": ["HIPAA", "HITECH", "HITRUST"],
|
|
10428
|
+
"imei": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10429
|
+
"imsi": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10430
|
+
"insurance-member-id": ["HIPAA", "HITECH", "HITRUST"],
|
|
10431
|
+
"ip-address": ["AU_PRIVACY", "CCPA_CPRA", "CJIS", "FISMA", "FedRAMP", "GDPR", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_53", "SOC2", "UK_GDPR"],
|
|
10432
|
+
"ipv6-address": ["AU_PRIVACY", "CCPA_CPRA", "CJIS", "FISMA", "FedRAMP", "GDPR", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_53", "SOC2", "UK_GDPR"],
|
|
10433
|
+
"jwt-token": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10434
|
+
"mac-address": ["AU_PRIVACY", "CCPA_CPRA", "CJIS", "FISMA", "FedRAMP", "GDPR", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_53", "SOC2", "UK_GDPR"],
|
|
10435
|
+
"medical-record-number": ["HIPAA", "HITECH", "HITRUST"],
|
|
10436
|
+
"medicare-mbi-labeled": ["HIPAA", "HITECH", "HITRUST"],
|
|
10437
|
+
"national-id": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FISMA", "GDPR", "IRS_1075", "ISO_27001", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10438
|
+
"national-id-grouped": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FISMA", "GDPR", "IRS_1075", "ISO_27001", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10439
|
+
"npi-labeled": ["HIPAA", "HITECH", "HITRUST"],
|
|
10440
|
+
"openai-api-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10441
|
+
"passport": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "DPDP", "FADP", "FISMA", "GDPR", "IRS_1075", "ISO_27001", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10442
|
+
"phone-intl": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "GLBA", "HIPAA", "HITECH", "ISO_27001", "ISO_27701", "LGPD", "NIST_800_53", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10443
|
+
"phone-intl-labeled": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "GLBA", "HIPAA", "HITECH", "ISO_27001", "ISO_27701", "LGPD", "NIST_800_53", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10444
|
+
"phone-us": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "GLBA", "HIPAA", "HITECH", "ISO_27001", "ISO_27701", "LGPD", "NIST_800_53", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10445
|
+
"private-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10446
|
+
"private-key-block": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10447
|
+
"private-key-body": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10448
|
+
"sendgrid-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10449
|
+
"slack-token": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10450
|
+
"slack-webhook-url": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10451
|
+
"ssn": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "DPDP", "FADP", "FERPA", "FISMA", "GDPR", "GLBA", "HIPAA", "HITECH", "IRS_1075", "ISO_27001", "ISO_27701", "LGPD", "NIST_800_53", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10452
|
+
"stripe-publishable-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10453
|
+
"stripe-restricted-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10454
|
+
"stripe-secret-key": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10455
|
+
"swift-bic": ["FADP", "GDPR", "UK_GDPR"],
|
|
10456
|
+
"twilio-account-sid": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10457
|
+
"twilio-auth-token": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10458
|
+
"uk-nhs-number-labeled": ["GDPR", "UK_GDPR"],
|
|
10459
|
+
"uk-nino-labeled": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "CJIS", "DPDP", "FADP", "FISMA", "GDPR", "IRS_1075", "ISO_27001", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"],
|
|
10460
|
+
"us-ein": ["APRA_CPS234", "DORA", "GLBA", "IRS_1075", "NYDFS_500", "SOX"],
|
|
10461
|
+
"vat-number": ["FADP", "GDPR", "UK_GDPR"],
|
|
10462
|
+
"vault-token": ["APRA_CPS234", "DORA", "FISMA", "FedRAMP", "HITRUST", "ISO_27001", "ISO_27701", "NIS2", "NIST_800_171", "NIST_800_53", "NYDFS_500", "SOC2", "SOX"],
|
|
10463
|
+
"vehicle-vin": ["APPI", "AU_PRIVACY", "CCPA_CPRA", "COPPA", "DPDP", "FADP", "FERPA", "GDPR", "HIPAA", "HITECH", "HITRUST", "ISO_27701", "LGPD", "PDPA_SG", "PDPA_TH", "PIPA_KR", "PIPEDA", "PIPL", "POPIA", "UK_GDPR"]
|
|
10464
|
+
};
|
|
10465
|
+
function frameworksForDetector(detector) {
|
|
10466
|
+
return Object.prototype.hasOwnProperty.call(DETECTOR_FRAMEWORKS, detector) ? DETECTOR_FRAMEWORKS[detector] : [];
|
|
10467
|
+
}
|
|
10468
|
+
function detectorsMatchFramework(detectors, framework) {
|
|
10469
|
+
const want = framework.toUpperCase();
|
|
10470
|
+
return detectors.some((d) => frameworksForDetector(d).some((f) => f.toUpperCase() === want));
|
|
10471
|
+
}
|
|
10472
|
+
function resolveFrameworkName(input) {
|
|
10473
|
+
const want = input.toUpperCase();
|
|
10474
|
+
return COMPLIANCE_FRAMEWORKS.find((f) => f.toUpperCase() === want) ?? null;
|
|
10475
|
+
}
|
|
10476
|
+
|
|
10386
10477
|
// ../packages/scanner/dist/index.js
|
|
10387
10478
|
import { gunzipSync } from "zlib";
|
|
10388
10479
|
var SECRET_LABEL_TAILS = [
|
|
@@ -11282,7 +11373,125 @@ var EXTENDED_PATTERNS = [
|
|
|
11282
11373
|
pattern: /\b(?:patient|pt|resident|inpatient|outpatient)\b[\s\S]{0,25}?\bdiagnos(?:ed|is)\b(?:\s+(?:with|of))?\s+([A-Za-z][A-Za-z0-9()\- ]{2,45}?)(?=\s*(?:\[|[.;,]|\btoday\b|\bon file\b|$))/gid,
|
|
11283
11374
|
valueGroup: 1
|
|
11284
11375
|
},
|
|
11285
|
-
// ── CMMC L2 CUI
|
|
11376
|
+
// ── CMMC L2 / CUI — REAL marking conventions ────────────────────────────────
|
|
11377
|
+
//
|
|
11378
|
+
// Read this before quoting any CMMC_L2 number.
|
|
11379
|
+
//
|
|
11380
|
+
// The three detectors AFTER this block (`cui-part-number`, `cui-program-code`,
|
|
11381
|
+
// `cui-contract-number`) are fitted to our own corpus generator. Their comment
|
|
11382
|
+
// says so outright: it names the fixtures `PN-9FRUDT`, `PRG-1B3ZEK`,
|
|
11383
|
+
// `CTR-2025-270565`. `PN-`, `PRG-` and `CTR-` are prefixes the generator
|
|
11384
|
+
// invents; they are not a convention any defence contractor uses. Those three
|
|
11385
|
+
// are the ONLY kinds mapped to CMMC_L2 (`_CUI` in compliance.py), so the
|
|
11386
|
+
// framework's score has been the corpus measuring itself. Excluding them,
|
|
11387
|
+
// CMMC_L2 had n = 0.
|
|
11388
|
+
//
|
|
11389
|
+
// The detectors in THIS block are different in kind: every one matches a
|
|
11390
|
+
// marking published in a public standard, so a hit means the same thing in a
|
|
11391
|
+
// real contractor's repository as it does in our corpus.
|
|
11392
|
+
//
|
|
11393
|
+
// - CUI banner / portion markings ....... 32 CFR Part 2002, DoD CUI Registry
|
|
11394
|
+
// - Distribution statements A–F ......... DoDI 5230.24
|
|
11395
|
+
// - ECCN classifications ................ EAR, 15 CFR Part 774 (CCL)
|
|
11396
|
+
// - ITAR citations ...................... 22 CFR Parts 120–130
|
|
11397
|
+
// - National Stock Number ............... NATO/DoD 13-digit NSN
|
|
11398
|
+
// - CAGE code ........................... NATO Commercial And Government Entity
|
|
11399
|
+
//
|
|
11400
|
+
// Bare `CUI` is deliberately NOT matched: three letters that occur in ordinary
|
|
11401
|
+
// prose and identifiers would flood the egress path with false positives. Only
|
|
11402
|
+
// the structured forms — `CUI//CATEGORY` and the `(CUI)` portion mark — are
|
|
11403
|
+
// distinctive enough to be safe.
|
|
11404
|
+
{
|
|
11405
|
+
name: "cui-banner-marking",
|
|
11406
|
+
category: "proprietary",
|
|
11407
|
+
severity: "high",
|
|
11408
|
+
defaultAction: "redact",
|
|
11409
|
+
// `CUI//SP-CTI`, `CUI//SP-PROPIN`, `CUI//SP-EXPT`, `CUI//NOFORN`,
|
|
11410
|
+
// `CONTROLLED//SP-CTI`, and the multi-category `CUI//SP-CTI/SP-EXPT`.
|
|
11411
|
+
pattern: /\b(?:CUI|CONTROLLED)\/\/(?:[A-Z][A-Z0-9-]{1,15})(?:\/[A-Z][A-Z0-9-]{1,15})*\b/g
|
|
11412
|
+
},
|
|
11413
|
+
{
|
|
11414
|
+
name: "cui-portion-marking",
|
|
11415
|
+
category: "proprietary",
|
|
11416
|
+
severity: "medium",
|
|
11417
|
+
defaultAction: "redact",
|
|
11418
|
+
// Portion marks that precede a paragraph: `(CUI)`, `(CUI//SP-CTI)`.
|
|
11419
|
+
pattern: /\((?:CUI|CUI\/\/[A-Z][A-Z0-9-]{1,15})\)/g
|
|
11420
|
+
},
|
|
11421
|
+
{
|
|
11422
|
+
name: "cui-distribution-statement",
|
|
11423
|
+
category: "proprietary",
|
|
11424
|
+
severity: "high",
|
|
11425
|
+
defaultAction: "redact",
|
|
11426
|
+
// DoDI 5230.24. Statement A is public-release, but its PRESENCE still marks
|
|
11427
|
+
// the document as controlled-technical-data governed, so all of A–F match.
|
|
11428
|
+
pattern: /\bDISTRIBUTION\s+STATEMENT\s+[A-F]\b/gi
|
|
11429
|
+
},
|
|
11430
|
+
{
|
|
11431
|
+
name: "export-control-eccn",
|
|
11432
|
+
category: "proprietary",
|
|
11433
|
+
severity: "high",
|
|
11434
|
+
defaultAction: "redact",
|
|
11435
|
+
// Commerce Control List entries: one digit, a letter A–E, three digits
|
|
11436
|
+
// (`5A002`, `3A001`, `9D515`). That shape is NOT distinctive on its own — it
|
|
11437
|
+
// collides with version strings and identifiers, which this detector proved
|
|
11438
|
+
// when the label was optional:
|
|
11439
|
+
//
|
|
11440
|
+
// "release 5A002 build" → matched ← false positive
|
|
11441
|
+
// "v1.2.3 and 9D515" → matched ← false positive
|
|
11442
|
+
//
|
|
11443
|
+
// So the ECCN label is REQUIRED, matching the label-anchoring rule the rest
|
|
11444
|
+
// of this file follows for non-self-shaped kinds. Real documents carry it;
|
|
11445
|
+
// ECCNs are quoted as "ECCN 5A002", not bare.
|
|
11446
|
+
//
|
|
11447
|
+
// EAR99 is a separate detector below rather than an alternative here: with a
|
|
11448
|
+
// `valueGroup`, an alternative that does not participate in the capture
|
|
11449
|
+
// yields no value and the match is dropped — which is exactly what happened
|
|
11450
|
+
// when the two were combined (EAR99 silently stopped matching).
|
|
11451
|
+
pattern: /\b(?:ECCN|Export\s+Control\s+Classification\s+Number)\s*[:#=]?\s*(\d[A-E]\d{3}(?:\.[a-z](?:\.\d+)?)?)\b/gid,
|
|
11452
|
+
valueGroup: 1
|
|
11453
|
+
},
|
|
11454
|
+
{
|
|
11455
|
+
name: "export-control-ear99",
|
|
11456
|
+
category: "proprietary",
|
|
11457
|
+
severity: "medium",
|
|
11458
|
+
defaultAction: "redact",
|
|
11459
|
+
// A fixed literal, not a shape, so it needs no label anchor and cannot
|
|
11460
|
+
// collide with version strings the way the numeric ECCN form does.
|
|
11461
|
+
pattern: /\bEAR99\b/g
|
|
11462
|
+
},
|
|
11463
|
+
{
|
|
11464
|
+
name: "itar-citation",
|
|
11465
|
+
category: "proprietary",
|
|
11466
|
+
severity: "high",
|
|
11467
|
+
defaultAction: "redact",
|
|
11468
|
+
// ITAR lives at 22 CFR 120–130; USML categories are Roman numerals I–XXI.
|
|
11469
|
+
pattern: /\b(?:ITAR\b|22\s*C\.?F\.?R\.?\s*(?:Part\s*)?1[2-3]\d\b|USML\s+Category\s+(?:X{0,2}(?:IX|IV|V?I{0,3}))\b)/gi
|
|
11470
|
+
},
|
|
11471
|
+
{
|
|
11472
|
+
name: "national-stock-number",
|
|
11473
|
+
category: "proprietary",
|
|
11474
|
+
severity: "medium",
|
|
11475
|
+
defaultAction: "redact",
|
|
11476
|
+
// NSN: 4-digit FSC, 2-digit NCB, 7-digit item number, conventionally written
|
|
11477
|
+
// NNNN-NN-NNN-NNNN. Self-shaped and distinctive enough to need no label.
|
|
11478
|
+
pattern: /\b\d{4}-\d{2}-\d{3}-\d{4}\b/g
|
|
11479
|
+
},
|
|
11480
|
+
{
|
|
11481
|
+
name: "cage-code",
|
|
11482
|
+
category: "proprietary",
|
|
11483
|
+
severity: "medium",
|
|
11484
|
+
defaultAction: "redact",
|
|
11485
|
+
// A CAGE code is 5 alphanumerics — far too generic to match unanchored, so
|
|
11486
|
+
// this requires the label. Same reasoning as the other label-gated kinds.
|
|
11487
|
+
pattern: /\bCAGE(?:\s*(?:code|CD))?\s*[:#=]?\s*([0-9A-Z]{5})\b/gid,
|
|
11488
|
+
valueGroup: 1
|
|
11489
|
+
},
|
|
11490
|
+
// ── LEGACY: corpus-fitted CUI detectors ─────────────────────────────────────
|
|
11491
|
+
// These match prefixes our own generator invents. Kept so the historical
|
|
11492
|
+
// baseline stays comparable, but a CMMC_L2 figure resting on them is not a
|
|
11493
|
+
// measurement — see the block above. Prefer the standards-based detectors.
|
|
11494
|
+
//
|
|
11286
11495
|
// K2 precision: raised the shape floors so short ticket/Jira-style refs don't
|
|
11287
11496
|
// match. part/program require 5+ chars AND at least one letter after the prefix
|
|
11288
11497
|
// (excludes `PN-1234`); contract requires the full `CTR-<4-digit-year>-<4+>`
|
|
@@ -14833,11 +15042,13 @@ var AuditStore = class {
|
|
|
14833
15042
|
INSERT INTO audit_log
|
|
14834
15043
|
(timestamp, request_id, provider, model, direction,
|
|
14835
15044
|
original_size, processed_size, secrets_blocked, pii_redacted,
|
|
14836
|
-
mutations_applied, scan_duration_ms, mutation_duration_ms, action, details
|
|
15045
|
+
mutations_applied, scan_duration_ms, mutation_duration_ms, action, details,
|
|
15046
|
+
detector_kinds)
|
|
14837
15047
|
VALUES
|
|
14838
15048
|
(@timestamp, @requestId, @provider, @model, @direction,
|
|
14839
15049
|
@originalSize, @processedSize, @secretsBlocked, @piiRedacted,
|
|
14840
|
-
@mutationsApplied, @scanDurationMs, @mutationDurationMs, @action, @details
|
|
15050
|
+
@mutationsApplied, @scanDurationMs, @mutationDurationMs, @action, @details,
|
|
15051
|
+
@detectorKinds)
|
|
14841
15052
|
`);
|
|
14842
15053
|
this.pruneByAgeStmt = this.db.prepare(
|
|
14843
15054
|
`DELETE FROM audit_log WHERE id IN (
|
|
@@ -14868,7 +15079,8 @@ var AuditStore = class {
|
|
|
14868
15079
|
scan_duration_ms REAL NOT NULL DEFAULT 0,
|
|
14869
15080
|
mutation_duration_ms REAL NOT NULL DEFAULT 0,
|
|
14870
15081
|
action TEXT NOT NULL DEFAULT 'forwarded',
|
|
14871
|
-
details TEXT
|
|
15082
|
+
details TEXT,
|
|
15083
|
+
detector_kinds TEXT
|
|
14872
15084
|
);
|
|
14873
15085
|
|
|
14874
15086
|
CREATE INDEX IF NOT EXISTS idx_timestamp ON audit_log(timestamp);
|
|
@@ -14898,7 +15110,11 @@ var AuditStore = class {
|
|
|
14898
15110
|
scanDurationMs: entry.scanDurationMs,
|
|
14899
15111
|
mutationDurationMs: entry.mutationDurationMs,
|
|
14900
15112
|
action: entry.action,
|
|
14901
|
-
details: entry.details ? JSON.stringify(entry.details) : null
|
|
15113
|
+
details: entry.details ? JSON.stringify(entry.details) : null,
|
|
15114
|
+
// Deduped + sorted so the column is stable for a given set of findings:
|
|
15115
|
+
// two requests that tripped the same detectors serialise identically,
|
|
15116
|
+
// which keeps grouping and diffing meaningful.
|
|
15117
|
+
detectorKinds: entry.detectorKinds && entry.detectorKinds.length > 0 ? JSON.stringify([...new Set(entry.detectorKinds)].sort()) : null
|
|
14902
15118
|
});
|
|
14903
15119
|
if (this.pruneEveryInserts > 0 && ++this.insertsSincePrune >= this.pruneEveryInserts) {
|
|
14904
15120
|
this.insertsSincePrune = 0;
|
|
@@ -15030,7 +15246,20 @@ var AuditStore = class {
|
|
|
15030
15246
|
scanDurationMs: row["scan_duration_ms"],
|
|
15031
15247
|
mutationDurationMs: row["mutation_duration_ms"],
|
|
15032
15248
|
action: row["action"],
|
|
15033
|
-
details: row["details"] ? JSON.parse(row["details"]) : void 0
|
|
15249
|
+
details: row["details"] ? JSON.parse(row["details"]) : void 0,
|
|
15250
|
+
// Tolerate a malformed/legacy value rather than throwing: a corrupt column
|
|
15251
|
+
// in ONE row must not make the whole audit log unreadable, which is the
|
|
15252
|
+
// opposite of what an audit trail is for.
|
|
15253
|
+
detectorKinds: (() => {
|
|
15254
|
+
const raw2 = row["detector_kinds"];
|
|
15255
|
+
if (typeof raw2 !== "string" || raw2.length === 0) return void 0;
|
|
15256
|
+
try {
|
|
15257
|
+
const parsed = JSON.parse(raw2);
|
|
15258
|
+
return Array.isArray(parsed) ? parsed : void 0;
|
|
15259
|
+
} catch {
|
|
15260
|
+
return void 0;
|
|
15261
|
+
}
|
|
15262
|
+
})()
|
|
15034
15263
|
};
|
|
15035
15264
|
}
|
|
15036
15265
|
};
|
|
@@ -16238,6 +16467,11 @@ Upgrade to ${_upgradeTier === "enterprise" ? "Enterprise" : "Pro"} for ${_upgrad
|
|
|
16238
16467
|
if (deep.scanIncomplete) {
|
|
16239
16468
|
const reasons = [...deep.incompleteReasons];
|
|
16240
16469
|
safeLog({
|
|
16470
|
+
// The detector names that fired. The proxy already collected these in
|
|
16471
|
+
// `foundTypes` for telemetry; the audit row discarded them, which is why
|
|
16472
|
+
// an audit trail could not be filtered by compliance framework — frameworks
|
|
16473
|
+
// are defined over KINDS, and counts alone cannot say which kind was seen.
|
|
16474
|
+
detectorKinds: [...foundTypes],
|
|
16241
16475
|
timestamp: Date.now(),
|
|
16242
16476
|
requestId,
|
|
16243
16477
|
provider,
|
|
@@ -16278,6 +16512,11 @@ Upgrade to ${_upgradeTier === "enterprise" ? "Enterprise" : "Pro"} for ${_upgrad
|
|
|
16278
16512
|
}
|
|
16279
16513
|
if (config.blockMode === "reject" && sensitiveFound > 0) {
|
|
16280
16514
|
safeLog({
|
|
16515
|
+
// The detector names that fired. The proxy already collected these in
|
|
16516
|
+
// `foundTypes` for telemetry; the audit row discarded them, which is why
|
|
16517
|
+
// an audit trail could not be filtered by compliance framework — frameworks
|
|
16518
|
+
// are defined over KINDS, and counts alone cannot say which kind was seen.
|
|
16519
|
+
detectorKinds: [...foundTypes],
|
|
16281
16520
|
timestamp: Date.now(),
|
|
16282
16521
|
requestId,
|
|
16283
16522
|
provider,
|
|
@@ -16350,6 +16589,11 @@ Upgrade to ${_upgradeTier === "enterprise" ? "Enterprise" : "Pro"} for ${_upgrad
|
|
|
16350
16589
|
const riskResult = riskScorer.score(riskCtx);
|
|
16351
16590
|
if (riskResult.recommendation === "block") {
|
|
16352
16591
|
safeLog({
|
|
16592
|
+
// The detector names that fired. The proxy already collected these in
|
|
16593
|
+
// `foundTypes` for telemetry; the audit row discarded them, which is why
|
|
16594
|
+
// an audit trail could not be filtered by compliance framework — frameworks
|
|
16595
|
+
// are defined over KINDS, and counts alone cannot say which kind was seen.
|
|
16596
|
+
detectorKinds: [...foundTypes],
|
|
16353
16597
|
timestamp: Date.now(),
|
|
16354
16598
|
requestId,
|
|
16355
16599
|
provider,
|
|
@@ -16413,6 +16657,11 @@ Upgrade to ${_upgradeTier === "enterprise" ? "Enterprise" : "Pro"} for ${_upgrad
|
|
|
16413
16657
|
});
|
|
16414
16658
|
} catch {
|
|
16415
16659
|
safeLog({
|
|
16660
|
+
// The detector names that fired. The proxy already collected these in
|
|
16661
|
+
// `foundTypes` for telemetry; the audit row discarded them, which is why
|
|
16662
|
+
// an audit trail could not be filtered by compliance framework — frameworks
|
|
16663
|
+
// are defined over KINDS, and counts alone cannot say which kind was seen.
|
|
16664
|
+
detectorKinds: [...foundTypes],
|
|
16416
16665
|
timestamp: Date.now(),
|
|
16417
16666
|
requestId,
|
|
16418
16667
|
provider,
|
|
@@ -16445,6 +16694,11 @@ Upgrade to ${_upgradeTier === "enterprise" ? "Enterprise" : "Pro"} for ${_upgrad
|
|
|
16445
16694
|
const anyTokenized = tokensMutated > 0 || sensitiveFound > 0;
|
|
16446
16695
|
const action = anyTokenized ? "mutated" : "forwarded";
|
|
16447
16696
|
safeLog({
|
|
16697
|
+
// The detector names that fired. The proxy already collected these in
|
|
16698
|
+
// `foundTypes` for telemetry; the audit row discarded them, which is why
|
|
16699
|
+
// an audit trail could not be filtered by compliance framework — frameworks
|
|
16700
|
+
// are defined over KINDS, and counts alone cannot say which kind was seen.
|
|
16701
|
+
detectorKinds: [...foundTypes],
|
|
16448
16702
|
timestamp: Date.now(),
|
|
16449
16703
|
requestId,
|
|
16450
16704
|
provider,
|
|
@@ -17155,15 +17409,17 @@ function getNestedValue(obj, key) {
|
|
|
17155
17409
|
}
|
|
17156
17410
|
function setNestedValue(obj, key, value) {
|
|
17157
17411
|
const parts = key.split(".");
|
|
17412
|
+
const leaf = parts.pop();
|
|
17413
|
+
if (leaf === void 0) return;
|
|
17158
17414
|
let cur = obj;
|
|
17159
|
-
for (
|
|
17160
|
-
const
|
|
17161
|
-
if (
|
|
17415
|
+
for (const p of parts) {
|
|
17416
|
+
const child = cur[p];
|
|
17417
|
+
if (child == null || typeof child !== "object" || Array.isArray(child)) {
|
|
17162
17418
|
cur[p] = {};
|
|
17163
17419
|
}
|
|
17164
17420
|
cur = cur[p];
|
|
17165
17421
|
}
|
|
17166
|
-
cur[
|
|
17422
|
+
cur[leaf] = value;
|
|
17167
17423
|
}
|
|
17168
17424
|
function parseValue(raw2) {
|
|
17169
17425
|
if (raw2.startsWith("[") && raw2.endsWith("]")) {
|
|
@@ -17391,10 +17647,12 @@ async function resolvePlanTier(opts = {}) {
|
|
|
17391
17647
|
}
|
|
17392
17648
|
return tierFromBackend(apiKey);
|
|
17393
17649
|
}
|
|
17650
|
+
var QUOTA_PERIOD_DAYS = 7;
|
|
17394
17651
|
function collectUsage(dbPath) {
|
|
17395
17652
|
const now = /* @__PURE__ */ new Date();
|
|
17396
|
-
const
|
|
17397
|
-
const
|
|
17653
|
+
const periodMs = QUOTA_PERIOD_DAYS * 24 * 60 * 60 * 1e3;
|
|
17654
|
+
const monthStartTs = Date.now() - periodMs;
|
|
17655
|
+
const sinceMs = periodMs;
|
|
17398
17656
|
let store = null;
|
|
17399
17657
|
try {
|
|
17400
17658
|
store = new AuditStore(dbPath);
|
|
@@ -17403,8 +17661,10 @@ function collectUsage(dbPath) {
|
|
|
17403
17661
|
monthStartTs,
|
|
17404
17662
|
metrics: {
|
|
17405
17663
|
tenantId: "local",
|
|
17664
|
+
// The trailing window these numbers actually cover — previously the
|
|
17665
|
+
// calendar month, which did not match the aggregation OR the quota.
|
|
17406
17666
|
periodStart: new Date(monthStartTs).toISOString().split("T")[0],
|
|
17407
|
-
periodEnd:
|
|
17667
|
+
periodEnd: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
17408
17668
|
mutationsApplied: stats.totalMutationsApplied,
|
|
17409
17669
|
secretsBlocked: stats.totalSecretsBlocked,
|
|
17410
17670
|
piiRedacted: stats.totalPiiRedacted,
|
|
@@ -17420,9 +17680,8 @@ function collectUsage(dbPath) {
|
|
|
17420
17680
|
store?.close();
|
|
17421
17681
|
}
|
|
17422
17682
|
}
|
|
17423
|
-
function
|
|
17424
|
-
|
|
17425
|
-
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)).toISOString().split("T")[0];
|
|
17683
|
+
function resetCadenceLabel() {
|
|
17684
|
+
return `every ${QUOTA_PERIOD_DAYS} days`;
|
|
17426
17685
|
}
|
|
17427
17686
|
function priceLabel(tier) {
|
|
17428
17687
|
const cents = PLAN_CONFIGS[tier].pricePerSeatCents;
|
|
@@ -17471,7 +17730,8 @@ function emptyUsagePayload(resolution) {
|
|
|
17471
17730
|
...resolution.detail ? { tierDetail: resolution.detail } : {},
|
|
17472
17731
|
periodStart: null,
|
|
17473
17732
|
periodEnd: null,
|
|
17474
|
-
resetDate:
|
|
17733
|
+
resetDate: null,
|
|
17734
|
+
resetCadenceDays: QUOTA_PERIOD_DAYS,
|
|
17475
17735
|
usage: {
|
|
17476
17736
|
mutations: { current: 0, limit: planConfig ? planConfig.mutationsPerMonth : null, percent: 0, allowed: true },
|
|
17477
17737
|
scans: { current: 0, limit: planConfig ? planConfig.scansPerMonth : null, percent: 0, allowed: true }
|
|
@@ -17508,7 +17768,8 @@ function usageCommand() {
|
|
|
17508
17768
|
...resolution.detail ? { tierDetail: resolution.detail } : {},
|
|
17509
17769
|
periodStart: usageMetrics.periodStart,
|
|
17510
17770
|
periodEnd: usageMetrics.periodEnd,
|
|
17511
|
-
resetDate:
|
|
17771
|
+
resetDate: null,
|
|
17772
|
+
resetCadenceDays: QUOTA_PERIOD_DAYS,
|
|
17512
17773
|
usage: {
|
|
17513
17774
|
mutations: {
|
|
17514
17775
|
current: usageMetrics.mutationsApplied,
|
|
@@ -17532,7 +17793,7 @@ function usageCommand() {
|
|
|
17532
17793
|
);
|
|
17533
17794
|
return;
|
|
17534
17795
|
}
|
|
17535
|
-
const resetDate =
|
|
17796
|
+
const resetDate = resetCadenceLabel();
|
|
17536
17797
|
console.log(
|
|
17537
17798
|
chalk7.cyan(
|
|
17538
17799
|
"\n Pretense Usage \u2014 " + (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { month: "long", year: "numeric" })
|
|
@@ -18905,11 +19166,34 @@ function toSafeAuditRow(e) {
|
|
|
18905
19166
|
mutationsApplied: e.mutationsApplied,
|
|
18906
19167
|
secretsBlocked: e.secretsBlocked,
|
|
18907
19168
|
piiRedacted: e.piiRedacted,
|
|
18908
|
-
scanDurationMs: e.scanDurationMs
|
|
19169
|
+
scanDurationMs: e.scanDurationMs,
|
|
19170
|
+
// Detector NAMES only. This stays leak-proof: "ssn" records that a social
|
|
19171
|
+
// security number was seen, never the number. Carrying it is what lets the
|
|
19172
|
+
// row be attributed to a compliance framework at all.
|
|
19173
|
+
detectorKinds: e.detectorKinds ?? []
|
|
18909
19174
|
};
|
|
18910
19175
|
}
|
|
18911
19176
|
function auditCommand() {
|
|
18912
|
-
return new Command17("audit").description("Show recent mutation/tokenization audit entries (leak-proof; JSONL with --json)").option("-l, --limit <n>", "Number of entries to show", "20").option("--json", "Output as JSONL (one JSON object per line, jq-pipeable)", false).option("--db <path>", "Path to the audit database (default: ~/.pretense/audit.db)").
|
|
19177
|
+
return new Command17("audit").description("Show recent mutation/tokenization audit entries (leak-proof; JSONL with --json)").option("-l, --limit <n>", "Number of entries to show", "20").option("--json", "Output as JSONL (one JSON object per line, jq-pipeable)", false).option("--db <path>", "Path to the audit database (default: ~/.pretense/audit.db)").option(
|
|
19178
|
+
"--framework <name>",
|
|
19179
|
+
"Only entries whose detectors map to this compliance framework (e.g. HIPAA, SOC2, PCI_DSS). Use --list-frameworks to see all 36."
|
|
19180
|
+
).option("--list-frameworks", "List the compliance frameworks that can be filtered on", false).action((opts) => {
|
|
19181
|
+
if (opts.listFrameworks) {
|
|
19182
|
+
for (const f of COMPLIANCE_FRAMEWORKS) console.log(f);
|
|
19183
|
+
return;
|
|
19184
|
+
}
|
|
19185
|
+
let framework = null;
|
|
19186
|
+
if (opts.framework) {
|
|
19187
|
+
framework = resolveFrameworkName(opts.framework);
|
|
19188
|
+
if (!framework) {
|
|
19189
|
+
console.error(
|
|
19190
|
+
chalk16.red(`
|
|
19191
|
+
x Unknown framework: "${opts.framework}"
|
|
19192
|
+
`) + chalk16.dim(" Run ") + chalk16.cyan("pretense audit --list-frameworks") + chalk16.dim(" to see all 36.\n")
|
|
19193
|
+
);
|
|
19194
|
+
process.exit(1);
|
|
19195
|
+
}
|
|
19196
|
+
}
|
|
18913
19197
|
const limit = parseInt(opts.limit ?? "20", 10);
|
|
18914
19198
|
if (!Number.isFinite(limit) || limit <= 0) {
|
|
18915
19199
|
console.error(chalk16.red(`
|
|
@@ -18921,7 +19205,11 @@ function auditCommand() {
|
|
|
18921
19205
|
let rows;
|
|
18922
19206
|
try {
|
|
18923
19207
|
const store = new AuditStore(dbPath);
|
|
18924
|
-
|
|
19208
|
+
const readLimit = framework ? Math.max(limit * 20, 500) : limit;
|
|
19209
|
+
rows = store.getRecentEntries(readLimit).map(toSafeAuditRow);
|
|
19210
|
+
if (framework) {
|
|
19211
|
+
rows = rows.filter((r) => detectorsMatchFramework(r.detectorKinds ?? [], framework)).slice(0, limit);
|
|
19212
|
+
}
|
|
18925
19213
|
store.close();
|
|
18926
19214
|
} catch {
|
|
18927
19215
|
if (opts.json) {
|
|
@@ -19009,7 +19297,8 @@ function creditsCommand() {
|
|
|
19009
19297
|
tier,
|
|
19010
19298
|
tierSource: resolution.source,
|
|
19011
19299
|
...resolution.detail ? { tierDetail: resolution.detail } : {},
|
|
19012
|
-
resetDate:
|
|
19300
|
+
resetDate: null,
|
|
19301
|
+
resetCadenceDays: QUOTA_PERIOD_DAYS,
|
|
19013
19302
|
mutations: {
|
|
19014
19303
|
used: m.mutationsApplied,
|
|
19015
19304
|
limit: tier ? mutationLimit : null,
|
|
@@ -19028,7 +19317,7 @@ function creditsCommand() {
|
|
|
19028
19317
|
return;
|
|
19029
19318
|
}
|
|
19030
19319
|
console.log(chalk17.cyan("\n Pretense Credits"));
|
|
19031
|
-
console.log(chalk17.dim(` Plan: ${tierLabel(tier)} | Resets: ${
|
|
19320
|
+
console.log(chalk17.dim(` Plan: ${tierLabel(tier)} | Resets: ${resetCadenceLabel()}
|
|
19032
19321
|
`));
|
|
19033
19322
|
if (!tier) {
|
|
19034
19323
|
for (const line of unverifiedNote(resolution.detail)) {
|
|
@@ -19110,8 +19399,8 @@ function upgradeCommand() {
|
|
|
19110
19399
|
console.log(" " + chalk18.dim("\u2500".repeat(18 + col * TIERS.length)));
|
|
19111
19400
|
const rows = [
|
|
19112
19401
|
["Price", (t) => priceLabel(t)],
|
|
19113
|
-
["Mutations/
|
|
19114
|
-
["Requests/
|
|
19402
|
+
["Mutations/7d", (t) => quota(PLAN_CONFIGS[t].mutationsPerMonth)],
|
|
19403
|
+
["Requests/7d", (t) => quota(PLAN_CONFIGS[t].scansPerMonth)],
|
|
19115
19404
|
["Seats", (t) => seats(PLAN_CONFIGS[t].maxSeats)],
|
|
19116
19405
|
["SSO", (t) => yesNo(PLAN_CONFIGS[t].ssoEnabled)],
|
|
19117
19406
|
["On-prem", (t) => yesNo(PLAN_CONFIGS[t].onPremEnabled)]
|
|
@@ -19170,7 +19459,7 @@ function findClosestCommand(input, knownCommands) {
|
|
|
19170
19459
|
return bestDist <= 3 ? best : null;
|
|
19171
19460
|
}
|
|
19172
19461
|
var program = new Command20();
|
|
19173
|
-
program.name("pretense").description(chalk19.bold("AI firewall") + " \u2014 mutates proprietary code before LLM API calls").version("0.6.
|
|
19462
|
+
program.name("pretense").description(chalk19.bold("AI firewall") + " \u2014 mutates proprietary code before LLM API calls").version("0.6.9", "-v, --version").addHelpText("after", `
|
|
19174
19463
|
${chalk19.bold("Quick start:")}
|
|
19175
19464
|
${chalk19.cyan("pretense scan")} ${chalk19.dim("<file|dir>")} Scan for secrets and PII
|
|
19176
19465
|
${chalk19.cyan("pretense mutate")} ${chalk19.dim("<file>")} Preview code mutations
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pretense/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"typescript": "^5.4.0",
|
|
25
25
|
"vitest": "^1.0.0",
|
|
26
26
|
"@pretense/billing": "0.1.0",
|
|
27
|
+
"@pretense/compliance-engine": "0.1.0",
|
|
27
28
|
"@pretense/protocol": "0.1.0",
|
|
28
29
|
"@pretense/learner": "0.2.0",
|
|
29
30
|
"@pretense/mutator": "0.2.0",
|
|
30
|
-
"@pretense/compliance-engine": "0.1.0",
|
|
31
31
|
"@pretense/proxy": "0.1.0",
|
|
32
32
|
"@pretense/scanner": "0.2.0",
|
|
33
33
|
"@pretense/store": "0.2.0"
|
|
@@ -76,6 +76,6 @@
|
|
|
76
76
|
"dev": "tsx src/index.ts",
|
|
77
77
|
"postinstall": "node -e \"fs.existsSync('dist/postinstall.js') && import('./dist/postinstall.js')\" || true",
|
|
78
78
|
"test": "vitest run",
|
|
79
|
-
"lint": "tsc --noEmit"
|
|
79
|
+
"lint": "tsc --noEmit -p tsconfig.lint.json"
|
|
80
80
|
}
|
|
81
81
|
}
|