vibecheck-ai 1.2.1 → 1.2.2
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 +1 -1
- package/dist/index.js +2095 -282
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1689,9 +1689,264 @@ function createDriftEvent(type, severity, file2, operation, description, context
|
|
|
1689
1689
|
context
|
|
1690
1690
|
};
|
|
1691
1691
|
}
|
|
1692
|
-
var FEATURE_KEYS, FEATURE_METADATA, PLAN_DEFINITIONS, TIER_ORDER, UPGRADE_URLS, VERDICT_THRESHOLDS, SEVERITY_PENALTIES, PERMISSIONS;
|
|
1692
|
+
var ENTITLEMENTS, FREE_ENTITLEMENTS, PRO_ENTITLEMENTS, FEATURE_KEYS, FEATURE_METADATA, PLAN_DEFINITIONS, TIER_ORDER, UPGRADE_URLS, VERDICT_THRESHOLDS, SEVERITY_PENALTIES, PERMISSIONS;
|
|
1693
1693
|
var init_dist = __esm({
|
|
1694
1694
|
"../../packages/shared-types/dist/index.js"() {
|
|
1695
|
+
ENTITLEMENTS = {
|
|
1696
|
+
// === FREE Tier Entitlements ===
|
|
1697
|
+
SCAN_UNLIMITED: "scan_unlimited",
|
|
1698
|
+
SHIP_GATE: "ship_gate",
|
|
1699
|
+
DOCTOR: "doctor",
|
|
1700
|
+
REPORTS_HTML: "reports_html",
|
|
1701
|
+
CHECKPOINT: "checkpoint",
|
|
1702
|
+
MISSIONS_VIEW: "missions_view",
|
|
1703
|
+
TEMPLATES_BROWSE: "templates_browse",
|
|
1704
|
+
TEMPLATES_INSTALL: "templates_install",
|
|
1705
|
+
TRUTHPACK_GENERATE: "truthpack_generate",
|
|
1706
|
+
TRUTHPACK_VALIDATE: "truthpack_validate",
|
|
1707
|
+
FORGE_BASIC: "forge_basic",
|
|
1708
|
+
PROMPT_TEMPLATES_BASIC: "prompt_templates_basic",
|
|
1709
|
+
WATCH_MODE: "watch_mode",
|
|
1710
|
+
TRACE_ANALYSIS: "trace_analysis",
|
|
1711
|
+
GITHUB_ACTION_WARN: "github_action_warn",
|
|
1712
|
+
FIREWALL_OBSERVE: "firewall_observe",
|
|
1713
|
+
FILE_LOCKING: "file_locking",
|
|
1714
|
+
// === PRO Tier Entitlements ===
|
|
1715
|
+
REALITY_MODE: "reality_mode",
|
|
1716
|
+
CONTEXT_ENGINE: "context_engine",
|
|
1717
|
+
ISL_STUDIO: "isl_studio",
|
|
1718
|
+
FIREWALL_AGENT: "firewall_agent",
|
|
1719
|
+
FIREWALL_ENFORCE: "firewall_enforce",
|
|
1720
|
+
FIREWALL_LOCKDOWN: "firewall_lockdown",
|
|
1721
|
+
AUTOFIX: "autofix",
|
|
1722
|
+
AUTOFIX_APPLY: "autofix_apply",
|
|
1723
|
+
CERTIFY: "certify",
|
|
1724
|
+
BADGE_VERIFIED: "badge_verified",
|
|
1725
|
+
CHAOS_AGENT: "chaos_agent",
|
|
1726
|
+
REPORTS_PDF: "reports_pdf",
|
|
1727
|
+
REPORTS_EXECUTIVE: "reports_executive",
|
|
1728
|
+
FORGE_EXTENDED: "forge_extended",
|
|
1729
|
+
REPLAY_VIEWER_FULL: "replay_viewer_full",
|
|
1730
|
+
PROOF_HISTORY: "proof_history",
|
|
1731
|
+
CLOUD_SYNC: "cloud_sync",
|
|
1732
|
+
TEAM_COLLABORATION: "team_collaboration",
|
|
1733
|
+
API_ACCESS: "api_access",
|
|
1734
|
+
WEBHOOKS: "webhooks",
|
|
1735
|
+
CI_GATE_BLOCK: "ci_gate_block",
|
|
1736
|
+
AI_GENERATION: "ai_generation",
|
|
1737
|
+
POLICIES: "policies",
|
|
1738
|
+
WORKFLOWS: "workflows",
|
|
1739
|
+
PRIORITY_SUPPORT: "priority_support",
|
|
1740
|
+
PROMPT_TEMPLATES_PRO: "prompt_templates_pro",
|
|
1741
|
+
// === Enterprise Tier Entitlements ===
|
|
1742
|
+
SSO: "sso",
|
|
1743
|
+
AUDIT_LOGS: "audit_logs",
|
|
1744
|
+
CUSTOM_POLICIES: "custom_policies",
|
|
1745
|
+
ON_PREM: "on_prem",
|
|
1746
|
+
SLA: "sla",
|
|
1747
|
+
DEDICATED_SUPPORT: "dedicated_support",
|
|
1748
|
+
FORGE_COMPREHENSIVE: "forge_comprehensive",
|
|
1749
|
+
PROMPT_TEMPLATES_CUSTOM: "prompt_templates_custom",
|
|
1750
|
+
COMPLIANCE_REPORTS: "compliance_reports"
|
|
1751
|
+
};
|
|
1752
|
+
FREE_ENTITLEMENTS = /* @__PURE__ */ new Set([
|
|
1753
|
+
ENTITLEMENTS.SCAN_UNLIMITED,
|
|
1754
|
+
ENTITLEMENTS.SHIP_GATE,
|
|
1755
|
+
ENTITLEMENTS.DOCTOR,
|
|
1756
|
+
ENTITLEMENTS.REPORTS_HTML,
|
|
1757
|
+
ENTITLEMENTS.CHECKPOINT,
|
|
1758
|
+
ENTITLEMENTS.MISSIONS_VIEW,
|
|
1759
|
+
ENTITLEMENTS.TEMPLATES_BROWSE,
|
|
1760
|
+
ENTITLEMENTS.TEMPLATES_INSTALL,
|
|
1761
|
+
ENTITLEMENTS.TRUTHPACK_GENERATE,
|
|
1762
|
+
ENTITLEMENTS.TRUTHPACK_VALIDATE,
|
|
1763
|
+
ENTITLEMENTS.FORGE_BASIC,
|
|
1764
|
+
ENTITLEMENTS.PROMPT_TEMPLATES_BASIC,
|
|
1765
|
+
ENTITLEMENTS.WATCH_MODE,
|
|
1766
|
+
ENTITLEMENTS.TRACE_ANALYSIS,
|
|
1767
|
+
ENTITLEMENTS.GITHUB_ACTION_WARN,
|
|
1768
|
+
ENTITLEMENTS.FIREWALL_OBSERVE,
|
|
1769
|
+
ENTITLEMENTS.FILE_LOCKING
|
|
1770
|
+
]);
|
|
1771
|
+
PRO_ENTITLEMENTS = /* @__PURE__ */ new Set([
|
|
1772
|
+
// Includes all FREE entitlements
|
|
1773
|
+
...FREE_ENTITLEMENTS,
|
|
1774
|
+
// Plus PRO-only entitlements
|
|
1775
|
+
ENTITLEMENTS.REALITY_MODE,
|
|
1776
|
+
ENTITLEMENTS.CONTEXT_ENGINE,
|
|
1777
|
+
ENTITLEMENTS.ISL_STUDIO,
|
|
1778
|
+
ENTITLEMENTS.FIREWALL_AGENT,
|
|
1779
|
+
ENTITLEMENTS.FIREWALL_ENFORCE,
|
|
1780
|
+
ENTITLEMENTS.FIREWALL_LOCKDOWN,
|
|
1781
|
+
ENTITLEMENTS.AUTOFIX,
|
|
1782
|
+
ENTITLEMENTS.AUTOFIX_APPLY,
|
|
1783
|
+
ENTITLEMENTS.CERTIFY,
|
|
1784
|
+
ENTITLEMENTS.BADGE_VERIFIED,
|
|
1785
|
+
ENTITLEMENTS.CHAOS_AGENT,
|
|
1786
|
+
ENTITLEMENTS.REPORTS_PDF,
|
|
1787
|
+
ENTITLEMENTS.REPORTS_EXECUTIVE,
|
|
1788
|
+
ENTITLEMENTS.FORGE_EXTENDED,
|
|
1789
|
+
ENTITLEMENTS.REPLAY_VIEWER_FULL,
|
|
1790
|
+
ENTITLEMENTS.PROOF_HISTORY,
|
|
1791
|
+
ENTITLEMENTS.CLOUD_SYNC,
|
|
1792
|
+
ENTITLEMENTS.TEAM_COLLABORATION,
|
|
1793
|
+
ENTITLEMENTS.API_ACCESS,
|
|
1794
|
+
ENTITLEMENTS.WEBHOOKS,
|
|
1795
|
+
ENTITLEMENTS.CI_GATE_BLOCK,
|
|
1796
|
+
ENTITLEMENTS.AI_GENERATION,
|
|
1797
|
+
ENTITLEMENTS.POLICIES,
|
|
1798
|
+
ENTITLEMENTS.WORKFLOWS,
|
|
1799
|
+
ENTITLEMENTS.PRIORITY_SUPPORT,
|
|
1800
|
+
ENTITLEMENTS.PROMPT_TEMPLATES_PRO
|
|
1801
|
+
]);
|
|
1802
|
+
/* @__PURE__ */ new Set([
|
|
1803
|
+
// Includes all PRO entitlements
|
|
1804
|
+
...PRO_ENTITLEMENTS,
|
|
1805
|
+
// Plus Enterprise-only entitlements
|
|
1806
|
+
ENTITLEMENTS.SSO,
|
|
1807
|
+
ENTITLEMENTS.AUDIT_LOGS,
|
|
1808
|
+
ENTITLEMENTS.CUSTOM_POLICIES,
|
|
1809
|
+
ENTITLEMENTS.ON_PREM,
|
|
1810
|
+
ENTITLEMENTS.SLA,
|
|
1811
|
+
ENTITLEMENTS.DEDICATED_SUPPORT,
|
|
1812
|
+
ENTITLEMENTS.FORGE_COMPREHENSIVE,
|
|
1813
|
+
ENTITLEMENTS.PROMPT_TEMPLATES_CUSTOM,
|
|
1814
|
+
ENTITLEMENTS.COMPLIANCE_REPORTS
|
|
1815
|
+
]);
|
|
1816
|
+
({
|
|
1817
|
+
[ENTITLEMENTS.REALITY_MODE]: {
|
|
1818
|
+
entitlement: ENTITLEMENTS.REALITY_MODE,
|
|
1819
|
+
title: "Reality Mode",
|
|
1820
|
+
description: "Browser-based runtime verification catches issues static analysis misses.",
|
|
1821
|
+
benefits: [
|
|
1822
|
+
"Browser-based route testing",
|
|
1823
|
+
"Screenshot evidence",
|
|
1824
|
+
"Runtime error detection",
|
|
1825
|
+
"Network request validation"
|
|
1826
|
+
],
|
|
1827
|
+
docsUrl: "/docs/reality-mode"
|
|
1828
|
+
},
|
|
1829
|
+
[ENTITLEMENTS.CONTEXT_ENGINE]: {
|
|
1830
|
+
entitlement: ENTITLEMENTS.CONTEXT_ENGINE,
|
|
1831
|
+
title: "Context Engine",
|
|
1832
|
+
description: "Full AI context generation for rules, agents, skills, and hooks.",
|
|
1833
|
+
benefits: [
|
|
1834
|
+
"Auto-generated AI rules",
|
|
1835
|
+
"Agent configuration",
|
|
1836
|
+
"Skill definitions",
|
|
1837
|
+
"Pre-commit hooks"
|
|
1838
|
+
],
|
|
1839
|
+
docsUrl: "/docs/context-engine"
|
|
1840
|
+
},
|
|
1841
|
+
[ENTITLEMENTS.ISL_STUDIO]: {
|
|
1842
|
+
entitlement: ENTITLEMENTS.ISL_STUDIO,
|
|
1843
|
+
title: "ISL Studio",
|
|
1844
|
+
description: "Intent Specification Language builder for spec-first development.",
|
|
1845
|
+
benefits: [
|
|
1846
|
+
"Visual ISL editor",
|
|
1847
|
+
"Contract generation",
|
|
1848
|
+
"Verification integration",
|
|
1849
|
+
"Export to code"
|
|
1850
|
+
],
|
|
1851
|
+
docsUrl: "/docs/isl-studio"
|
|
1852
|
+
},
|
|
1853
|
+
[ENTITLEMENTS.FIREWALL_ENFORCE]: {
|
|
1854
|
+
entitlement: ENTITLEMENTS.FIREWALL_ENFORCE,
|
|
1855
|
+
title: "Firewall Enforce Mode",
|
|
1856
|
+
description: "Block AI changes before they happen, not after.",
|
|
1857
|
+
benefits: [
|
|
1858
|
+
"Pre-save blocking",
|
|
1859
|
+
"Real-time validation",
|
|
1860
|
+
"Hallucination prevention",
|
|
1861
|
+
"Audit logging"
|
|
1862
|
+
],
|
|
1863
|
+
docsUrl: "/docs/firewall"
|
|
1864
|
+
},
|
|
1865
|
+
[ENTITLEMENTS.AUTOFIX_APPLY]: {
|
|
1866
|
+
entitlement: ENTITLEMENTS.AUTOFIX_APPLY,
|
|
1867
|
+
title: "Auto-Fix Apply",
|
|
1868
|
+
description: "AI-powered code repair with rollback support.",
|
|
1869
|
+
benefits: [
|
|
1870
|
+
"One-click fixes",
|
|
1871
|
+
"Rollback support",
|
|
1872
|
+
"Fix verification",
|
|
1873
|
+
"Batch application"
|
|
1874
|
+
],
|
|
1875
|
+
docsUrl: "/docs/autofix"
|
|
1876
|
+
},
|
|
1877
|
+
[ENTITLEMENTS.CERTIFY]: {
|
|
1878
|
+
entitlement: ENTITLEMENTS.CERTIFY,
|
|
1879
|
+
title: "Certify",
|
|
1880
|
+
description: "Generate proof bundles and certification for your code.",
|
|
1881
|
+
benefits: [
|
|
1882
|
+
"Signed proof bundles",
|
|
1883
|
+
"Verification endpoint",
|
|
1884
|
+
"Compliance documentation",
|
|
1885
|
+
"Badge generation"
|
|
1886
|
+
],
|
|
1887
|
+
docsUrl: "/docs/certify"
|
|
1888
|
+
},
|
|
1889
|
+
[ENTITLEMENTS.BADGE_VERIFIED]: {
|
|
1890
|
+
entitlement: ENTITLEMENTS.BADGE_VERIFIED,
|
|
1891
|
+
title: "Verified Ship Badge",
|
|
1892
|
+
description: "Show your code quality commitment with a verified badge.",
|
|
1893
|
+
benefits: [
|
|
1894
|
+
"Dynamic SVG badge",
|
|
1895
|
+
"Real-time Ship Score",
|
|
1896
|
+
"Verified checkmark",
|
|
1897
|
+
"README embed code"
|
|
1898
|
+
],
|
|
1899
|
+
docsUrl: "/docs/badges"
|
|
1900
|
+
},
|
|
1901
|
+
[ENTITLEMENTS.CHAOS_AGENT]: {
|
|
1902
|
+
entitlement: ENTITLEMENTS.CHAOS_AGENT,
|
|
1903
|
+
title: "Chaos Agent",
|
|
1904
|
+
description: "AI-powered bug hunting finds issues you would miss.",
|
|
1905
|
+
benefits: [
|
|
1906
|
+
"AI-powered exploration",
|
|
1907
|
+
"Edge case discovery",
|
|
1908
|
+
"Security testing",
|
|
1909
|
+
"Reproducible tests"
|
|
1910
|
+
],
|
|
1911
|
+
docsUrl: "/docs/chaos-agent"
|
|
1912
|
+
},
|
|
1913
|
+
[ENTITLEMENTS.CLOUD_SYNC]: {
|
|
1914
|
+
entitlement: ENTITLEMENTS.CLOUD_SYNC,
|
|
1915
|
+
title: "Cloud Sync",
|
|
1916
|
+
description: "Sync truthpacks and scan history across devices and team.",
|
|
1917
|
+
benefits: [
|
|
1918
|
+
"Cross-device access",
|
|
1919
|
+
"Team sharing",
|
|
1920
|
+
"Automatic backup",
|
|
1921
|
+
"90-day retention"
|
|
1922
|
+
],
|
|
1923
|
+
docsUrl: "/docs/cloud-sync"
|
|
1924
|
+
},
|
|
1925
|
+
[ENTITLEMENTS.TEAM_COLLABORATION]: {
|
|
1926
|
+
entitlement: ENTITLEMENTS.TEAM_COLLABORATION,
|
|
1927
|
+
title: "Team Collaboration",
|
|
1928
|
+
description: "Work together on code quality with your team.",
|
|
1929
|
+
benefits: [
|
|
1930
|
+
"Unlimited team members",
|
|
1931
|
+
"Role-based access",
|
|
1932
|
+
"Shared projects",
|
|
1933
|
+
"Team analytics"
|
|
1934
|
+
],
|
|
1935
|
+
docsUrl: "/docs/teams"
|
|
1936
|
+
},
|
|
1937
|
+
[ENTITLEMENTS.API_ACCESS]: {
|
|
1938
|
+
entitlement: ENTITLEMENTS.API_ACCESS,
|
|
1939
|
+
title: "API Access",
|
|
1940
|
+
description: "Integrate VibeCheck into your existing tools and workflows.",
|
|
1941
|
+
benefits: [
|
|
1942
|
+
"RESTful API",
|
|
1943
|
+
"Webhook support",
|
|
1944
|
+
"CI/CD integration",
|
|
1945
|
+
"Custom automation"
|
|
1946
|
+
],
|
|
1947
|
+
docsUrl: "/docs/api"
|
|
1948
|
+
}
|
|
1949
|
+
});
|
|
1695
1950
|
FEATURE_KEYS = {
|
|
1696
1951
|
// Dashboard features
|
|
1697
1952
|
CLOUD_SYNC: "cloud_sync",
|
|
@@ -2334,45 +2589,53 @@ var init_dist = __esm({
|
|
|
2334
2589
|
free: {
|
|
2335
2590
|
id: "free",
|
|
2336
2591
|
name: "Free",
|
|
2337
|
-
tagline: "
|
|
2592
|
+
tagline: "Everything you need to find issues",
|
|
2338
2593
|
price: 0,
|
|
2339
2594
|
priceLabel: "$0",
|
|
2340
2595
|
interval: "month",
|
|
2341
2596
|
features: [
|
|
2342
|
-
"
|
|
2343
|
-
"
|
|
2344
|
-
"
|
|
2345
|
-
"
|
|
2346
|
-
"
|
|
2347
|
-
"
|
|
2597
|
+
"Unlimited scans",
|
|
2598
|
+
"Unlimited ship decisions",
|
|
2599
|
+
"Doctor (health checks)",
|
|
2600
|
+
"HTML reports",
|
|
2601
|
+
"Checkpoint create/restore",
|
|
2602
|
+
"Mission packs (view)",
|
|
2603
|
+
"Template gallery + install",
|
|
2604
|
+
"Forge basic (5 rules)",
|
|
2605
|
+
"Watch mode",
|
|
2606
|
+
"7-day history"
|
|
2348
2607
|
],
|
|
2349
2608
|
limits: {
|
|
2350
2609
|
projects: 3,
|
|
2351
|
-
scansPerMonth:
|
|
2352
|
-
//
|
|
2610
|
+
scansPerMonth: -1,
|
|
2611
|
+
// Unlimited
|
|
2353
2612
|
seats: 1,
|
|
2354
2613
|
retentionDays: 7
|
|
2355
2614
|
},
|
|
2356
|
-
bestFor: "
|
|
2615
|
+
bestFor: "Finding issues in your codebase",
|
|
2357
2616
|
cta: "Current Plan",
|
|
2358
2617
|
ctaVariant: "secondary"
|
|
2359
2618
|
},
|
|
2360
2619
|
pro: {
|
|
2361
2620
|
id: "pro",
|
|
2362
2621
|
name: "Pro",
|
|
2363
|
-
tagline: "
|
|
2364
|
-
price:
|
|
2365
|
-
priceLabel: "$
|
|
2622
|
+
tagline: "Prevent issues and prove it",
|
|
2623
|
+
price: 19,
|
|
2624
|
+
priceLabel: "$19",
|
|
2366
2625
|
interval: "month",
|
|
2367
2626
|
features: [
|
|
2368
2627
|
"Everything in Free",
|
|
2369
|
-
"
|
|
2370
|
-
"
|
|
2371
|
-
"
|
|
2628
|
+
"Reality Mode (runtime verification)",
|
|
2629
|
+
"Context Engine (full AI context)",
|
|
2630
|
+
"ISL Studio (spec-first workflow)",
|
|
2631
|
+
"Firewall Agent (enforce + lockdown)",
|
|
2632
|
+
"Auto-Fix (apply fixes)",
|
|
2633
|
+
"Certify + Verified Badge",
|
|
2634
|
+
"Chaos Agent (AI bug hunting)",
|
|
2635
|
+
"PDF & executive reports",
|
|
2636
|
+
"Cloud sync & teams",
|
|
2372
2637
|
"API access & webhooks",
|
|
2373
|
-
"
|
|
2374
|
-
"90-day scan history",
|
|
2375
|
-
"Priority support"
|
|
2638
|
+
"90-day history"
|
|
2376
2639
|
],
|
|
2377
2640
|
limits: {
|
|
2378
2641
|
projects: -1,
|
|
@@ -2381,7 +2644,7 @@ var init_dist = __esm({
|
|
|
2381
2644
|
seats: -1,
|
|
2382
2645
|
retentionDays: 90
|
|
2383
2646
|
},
|
|
2384
|
-
bestFor: "
|
|
2647
|
+
bestFor: "Teams shipping production code with confidence",
|
|
2385
2648
|
popular: true,
|
|
2386
2649
|
cta: "Upgrade to Pro",
|
|
2387
2650
|
ctaVariant: "default"
|
|
@@ -2389,19 +2652,19 @@ var init_dist = __esm({
|
|
|
2389
2652
|
enterprise: {
|
|
2390
2653
|
id: "enterprise",
|
|
2391
2654
|
name: "Enterprise",
|
|
2392
|
-
tagline: "For organizations with
|
|
2655
|
+
tagline: "For organizations with compliance needs",
|
|
2393
2656
|
price: null,
|
|
2394
2657
|
priceLabel: "Custom",
|
|
2395
2658
|
interval: null,
|
|
2396
2659
|
features: [
|
|
2397
2660
|
"Everything in Pro",
|
|
2398
|
-
"SSO/SAML
|
|
2661
|
+
"SSO/SAML (Okta, Azure AD)",
|
|
2399
2662
|
"Audit logs (365-day retention)",
|
|
2400
2663
|
"Custom policies",
|
|
2401
2664
|
"On-premises deployment",
|
|
2402
|
-
"
|
|
2403
|
-
"
|
|
2404
|
-
"
|
|
2665
|
+
"Compliance reports",
|
|
2666
|
+
"Dedicated support",
|
|
2667
|
+
"SLA guarantee"
|
|
2405
2668
|
],
|
|
2406
2669
|
limits: {
|
|
2407
2670
|
projects: -1,
|
|
@@ -2409,7 +2672,7 @@ var init_dist = __esm({
|
|
|
2409
2672
|
seats: -1,
|
|
2410
2673
|
retentionDays: 365
|
|
2411
2674
|
},
|
|
2412
|
-
bestFor: "
|
|
2675
|
+
bestFor: "Organizations with security & compliance requirements",
|
|
2413
2676
|
cta: "Contact Sales",
|
|
2414
2677
|
ctaVariant: "outline"
|
|
2415
2678
|
}
|
|
@@ -16238,8 +16501,6 @@ var init_chunk_KVOEVY4C = __esm({
|
|
|
16238
16501
|
};
|
|
16239
16502
|
}
|
|
16240
16503
|
});
|
|
16241
|
-
|
|
16242
|
-
// ../../packages/core/dist/chunk-VCXA3YAU.js
|
|
16243
16504
|
function calculateHealthScore(counts) {
|
|
16244
16505
|
const penalty = counts.critical * SEVERITY_PENALTIES.critical + counts.high * SEVERITY_PENALTIES.high + counts.medium * SEVERITY_PENALTIES.medium + counts.low * SEVERITY_PENALTIES.low;
|
|
16245
16506
|
const score = Math.max(0, 100 - Math.min(100, penalty));
|
|
@@ -16518,6 +16779,173 @@ function formatShipScore(score) {
|
|
|
16518
16779
|
};
|
|
16519
16780
|
return `Ship Score: ${score.total}/100 ${verdictEmoji[score.verdict]} ${score.verdict}`;
|
|
16520
16781
|
}
|
|
16782
|
+
function generateProofBundle(score, input, options) {
|
|
16783
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
16784
|
+
const evidence = [];
|
|
16785
|
+
const routes = input.truthpack?.routes || [];
|
|
16786
|
+
for (const route of routes.slice(0, 10)) {
|
|
16787
|
+
evidence.push({
|
|
16788
|
+
type: "route_verified",
|
|
16789
|
+
subject: `${route.method || "GET"} ${route.path}`,
|
|
16790
|
+
result: "pass",
|
|
16791
|
+
confidence: 0.9,
|
|
16792
|
+
timestamp
|
|
16793
|
+
});
|
|
16794
|
+
}
|
|
16795
|
+
const envVars = input.truthpack?.env || [];
|
|
16796
|
+
for (const env2 of envVars.slice(0, 10)) {
|
|
16797
|
+
evidence.push({
|
|
16798
|
+
type: "env_verified",
|
|
16799
|
+
subject: env2.name,
|
|
16800
|
+
result: env2.present ? "pass" : "fail",
|
|
16801
|
+
confidence: env2.present ? 0.95 : 0.8,
|
|
16802
|
+
timestamp
|
|
16803
|
+
});
|
|
16804
|
+
}
|
|
16805
|
+
if (input.truthpack?.auth) {
|
|
16806
|
+
evidence.push({
|
|
16807
|
+
type: "auth_verified",
|
|
16808
|
+
subject: "Auth Configuration",
|
|
16809
|
+
result: score.metrics.authConfigured ? "pass" : "fail",
|
|
16810
|
+
confidence: 0.85,
|
|
16811
|
+
details: `${score.metrics.protectedRoutes} protected routes`,
|
|
16812
|
+
timestamp
|
|
16813
|
+
});
|
|
16814
|
+
}
|
|
16815
|
+
if (input.realityResults?.ran) {
|
|
16816
|
+
evidence.push({
|
|
16817
|
+
type: "reality_test",
|
|
16818
|
+
subject: "Reality Mode Verification",
|
|
16819
|
+
result: input.realityResults.routesFailed === 0 ? "pass" : "fail",
|
|
16820
|
+
confidence: 0.95,
|
|
16821
|
+
details: `${input.realityResults.routesPassed}/${input.realityResults.routesTested} passed`,
|
|
16822
|
+
timestamp
|
|
16823
|
+
});
|
|
16824
|
+
}
|
|
16825
|
+
if (input.mockDetectionResults) {
|
|
16826
|
+
evidence.push({
|
|
16827
|
+
type: "mock_scan",
|
|
16828
|
+
subject: "Mock Data Scan",
|
|
16829
|
+
result: input.mockDetectionResults.summary.total === 0 ? "pass" : "fail",
|
|
16830
|
+
confidence: 0.9,
|
|
16831
|
+
details: `${input.mockDetectionResults.summary.total} findings`,
|
|
16832
|
+
timestamp
|
|
16833
|
+
});
|
|
16834
|
+
}
|
|
16835
|
+
const verificationChain = [
|
|
16836
|
+
{
|
|
16837
|
+
step: 1,
|
|
16838
|
+
action: "Ghost Risk Analysis",
|
|
16839
|
+
result: `${score.metrics.verifiedRoutes}/${score.metrics.totalRoutes} routes verified`,
|
|
16840
|
+
scoreContribution: score.dimensions.ghostRisk
|
|
16841
|
+
},
|
|
16842
|
+
{
|
|
16843
|
+
step: 2,
|
|
16844
|
+
action: "Auth Coverage Analysis",
|
|
16845
|
+
result: `${score.metrics.protectedRoutes} routes protected`,
|
|
16846
|
+
scoreContribution: score.dimensions.authCoverage
|
|
16847
|
+
},
|
|
16848
|
+
{
|
|
16849
|
+
step: 3,
|
|
16850
|
+
action: "Env Integrity Check",
|
|
16851
|
+
result: `${score.metrics.presentEnvVars}/${score.metrics.requiredEnvVars} required vars present`,
|
|
16852
|
+
scoreContribution: score.dimensions.envIntegrity
|
|
16853
|
+
},
|
|
16854
|
+
{
|
|
16855
|
+
step: 4,
|
|
16856
|
+
action: "Runtime Proof Collection",
|
|
16857
|
+
result: score.metrics.realityModeRan ? `${score.metrics.routesTestedInReality} routes tested, ${Math.round(score.metrics.realityPassRate * 100)}% pass rate` : "Reality mode not executed",
|
|
16858
|
+
scoreContribution: score.dimensions.runtimeProof
|
|
16859
|
+
},
|
|
16860
|
+
{
|
|
16861
|
+
step: 5,
|
|
16862
|
+
action: "Contract Alignment Check",
|
|
16863
|
+
result: `${score.metrics.alignedContracts}/${score.metrics.totalContracts} contracts aligned`,
|
|
16864
|
+
scoreContribution: score.dimensions.contractsAlignment
|
|
16865
|
+
},
|
|
16866
|
+
{
|
|
16867
|
+
step: 6,
|
|
16868
|
+
action: "Mock Data Cleanliness",
|
|
16869
|
+
result: score.metrics.mockDataFindings === 0 ? "No mock data found" : `${score.metrics.mockDataFindings} mock data findings`,
|
|
16870
|
+
scoreContribution: score.dimensions.mockDataCleanliness
|
|
16871
|
+
}
|
|
16872
|
+
];
|
|
16873
|
+
let verdict;
|
|
16874
|
+
if (score.verdict === "SHIP" && score.total >= 80) {
|
|
16875
|
+
verdict = "PROVEN";
|
|
16876
|
+
} else if (score.verdict === "BLOCK") {
|
|
16877
|
+
verdict = "FAILED";
|
|
16878
|
+
} else {
|
|
16879
|
+
verdict = "INCOMPLETE_PROOF";
|
|
16880
|
+
}
|
|
16881
|
+
const bundleContent = {
|
|
16882
|
+
version: "1.0.0",
|
|
16883
|
+
timestamp,
|
|
16884
|
+
projectId: options?.projectId,
|
|
16885
|
+
commitHash: options?.commitHash,
|
|
16886
|
+
score,
|
|
16887
|
+
evidence,
|
|
16888
|
+
verificationChain,
|
|
16889
|
+
verdict
|
|
16890
|
+
};
|
|
16891
|
+
const contentString = JSON.stringify(bundleContent);
|
|
16892
|
+
const bundleId = crypto52.createHash("sha256").update(contentString).digest("hex").slice(0, 16);
|
|
16893
|
+
const bundle = {
|
|
16894
|
+
bundleId,
|
|
16895
|
+
...bundleContent
|
|
16896
|
+
};
|
|
16897
|
+
if (options?.signingKey) {
|
|
16898
|
+
const signatureValue = crypto52.createHmac("sha256", options.signingKey).update(JSON.stringify(bundle)).digest("base64");
|
|
16899
|
+
bundle.signature = {
|
|
16900
|
+
algorithm: "HMAC-SHA256",
|
|
16901
|
+
value: signatureValue,
|
|
16902
|
+
keyId: crypto52.createHash("sha256").update(options.signingKey).digest("hex").slice(0, 8),
|
|
16903
|
+
signedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
16904
|
+
};
|
|
16905
|
+
}
|
|
16906
|
+
return bundle;
|
|
16907
|
+
}
|
|
16908
|
+
function verifyProofBundle(bundle, signingKey) {
|
|
16909
|
+
const { bundleId, signature, ...content } = bundle;
|
|
16910
|
+
const contentString = JSON.stringify(content);
|
|
16911
|
+
const expectedId = crypto52.createHash("sha256").update(contentString).digest("hex").slice(0, 16);
|
|
16912
|
+
if (bundleId !== expectedId) {
|
|
16913
|
+
return { valid: false, reason: "Bundle ID does not match content hash" };
|
|
16914
|
+
}
|
|
16915
|
+
if (bundle.signature && signingKey) {
|
|
16916
|
+
const expectedSignature = crypto52.createHmac("sha256", signingKey).update(JSON.stringify({ bundleId, ...content })).digest("base64");
|
|
16917
|
+
if (bundle.signature.value !== expectedSignature) {
|
|
16918
|
+
return { valid: false, reason: "Signature verification failed" };
|
|
16919
|
+
}
|
|
16920
|
+
}
|
|
16921
|
+
return { valid: true };
|
|
16922
|
+
}
|
|
16923
|
+
function formatProofBundle(bundle) {
|
|
16924
|
+
const lines = [];
|
|
16925
|
+
lines.push("");
|
|
16926
|
+
lines.push("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557");
|
|
16927
|
+
lines.push("\u2551 VIBECHECK PROOF BUNDLE \u2551");
|
|
16928
|
+
lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
|
|
16929
|
+
lines.push(`\u2551 Bundle ID: ${bundle.bundleId.padEnd(50)} \u2551`);
|
|
16930
|
+
lines.push(`\u2551 Timestamp: ${bundle.timestamp.slice(0, 19).padEnd(50)} \u2551`);
|
|
16931
|
+
lines.push(`\u2551 Verdict: ${bundle.verdict.padEnd(50)} \u2551`);
|
|
16932
|
+
lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
|
|
16933
|
+
lines.push(`\u2551 Ship Score: ${bundle.score.total}/100`.padEnd(67) + " \u2551");
|
|
16934
|
+
lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
|
|
16935
|
+
lines.push("\u2551 Verification Chain: \u2551");
|
|
16936
|
+
for (const step of bundle.verificationChain) {
|
|
16937
|
+
const line = ` ${step.step}. ${step.action}: ${step.result}`.slice(0, 64);
|
|
16938
|
+
lines.push(`\u2551 ${line.padEnd(64)} \u2551`);
|
|
16939
|
+
}
|
|
16940
|
+
lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
|
|
16941
|
+
lines.push(`\u2551 Evidence Items: ${bundle.evidence.length}`.padEnd(67) + " \u2551");
|
|
16942
|
+
if (bundle.signature) {
|
|
16943
|
+
lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
|
|
16944
|
+
lines.push(`\u2551 Signed: ${bundle.signature.algorithm} (key: ${bundle.signature.keyId})`.padEnd(67) + " \u2551");
|
|
16945
|
+
}
|
|
16946
|
+
lines.push("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D");
|
|
16947
|
+
return lines.join("\n");
|
|
16948
|
+
}
|
|
16521
16949
|
function calculateHybridScore(input) {
|
|
16522
16950
|
const { islResult, traditionalScore, mode } = input;
|
|
16523
16951
|
if (mode === "isl" && islResult) {
|
|
@@ -16578,8 +17006,8 @@ function createISLScorer() {
|
|
|
16578
17006
|
return new ISLScorer();
|
|
16579
17007
|
}
|
|
16580
17008
|
var CATEGORY_SCORE_CONFIG, MAX_DIMENSION_SCORE, VERDICT_THRESHOLDS2, GHOST_WEIGHTS, SENSITIVE_ROUTE_PATTERNS, ShipScoreCalculator, shipScoreCalculator, ISL_WEIGHTS, ISL_VERDICT_THRESHOLDS, ISLScorer, islScorer;
|
|
16581
|
-
var
|
|
16582
|
-
"../../packages/core/dist/chunk-
|
|
17009
|
+
var init_chunk_GXXYXSWF = __esm({
|
|
17010
|
+
"../../packages/core/dist/chunk-GXXYXSWF.js"() {
|
|
16583
17011
|
init_dist();
|
|
16584
17012
|
init_dist();
|
|
16585
17013
|
CATEGORY_SCORE_CONFIG = {
|
|
@@ -25720,7 +26148,7 @@ var init_chunk_C5JUH5R4 = __esm({
|
|
|
25720
26148
|
}
|
|
25721
26149
|
});
|
|
25722
26150
|
|
|
25723
|
-
// ../../packages/core/dist/chunk-
|
|
26151
|
+
// ../../packages/core/dist/chunk-GZFCACMG.js
|
|
25724
26152
|
function getLogger2() {
|
|
25725
26153
|
if (!loggerInstance) {
|
|
25726
26154
|
loggerInstance = {
|
|
@@ -26298,8 +26726,8 @@ function gateFeature(userTier, feature, context) {
|
|
|
26298
26726
|
}
|
|
26299
26727
|
}
|
|
26300
26728
|
var CATEGORY_INFO, TIER_INFO, loggerInstance, registry, TIER_LEVELS, TierAccessError, devMode, UPGRADE_TRIGGERS, FeatureGatedError;
|
|
26301
|
-
var
|
|
26302
|
-
"../../packages/core/dist/chunk-
|
|
26729
|
+
var init_chunk_GZFCACMG = __esm({
|
|
26730
|
+
"../../packages/core/dist/chunk-GZFCACMG.js"() {
|
|
26303
26731
|
init_chunk_C5JUH5R4();
|
|
26304
26732
|
init_dist();
|
|
26305
26733
|
CATEGORY_INFO = {
|
|
@@ -26355,7 +26783,7 @@ var init_chunk_QJNHJVEI = __esm({
|
|
|
26355
26783
|
name: "PRO",
|
|
26356
26784
|
description: "Cloud features, team collaboration, API access",
|
|
26357
26785
|
color: "blue",
|
|
26358
|
-
price: "$
|
|
26786
|
+
price: "$19/dev/mo"
|
|
26359
26787
|
},
|
|
26360
26788
|
enterprise: {
|
|
26361
26789
|
name: "ENTERPRISE",
|
|
@@ -26577,7 +27005,7 @@ function createConcurrencyLimiter(config = {}) {
|
|
|
26577
27005
|
async function runWithConcurrency(items, operation, maxConcurrent) {
|
|
26578
27006
|
const semaphore = new Semaphore(maxConcurrent);
|
|
26579
27007
|
const results = [];
|
|
26580
|
-
const
|
|
27008
|
+
const promises3 = items.map(async (item, index) => {
|
|
26581
27009
|
await semaphore.acquire();
|
|
26582
27010
|
try {
|
|
26583
27011
|
const result = await operation(item, index);
|
|
@@ -26586,7 +27014,7 @@ async function runWithConcurrency(items, operation, maxConcurrent) {
|
|
|
26586
27014
|
semaphore.release();
|
|
26587
27015
|
}
|
|
26588
27016
|
});
|
|
26589
|
-
await Promise.all(
|
|
27017
|
+
await Promise.all(promises3);
|
|
26590
27018
|
return results;
|
|
26591
27019
|
}
|
|
26592
27020
|
function createSafetyGuard(config = {}) {
|
|
@@ -40726,8 +41154,8 @@ function extractCallsFromSource(source, filePath, options = {}) {
|
|
|
40726
41154
|
// ========================================
|
|
40727
41155
|
// Import Declarations
|
|
40728
41156
|
// ========================================
|
|
40729
|
-
ImportDeclaration(
|
|
40730
|
-
const node =
|
|
41157
|
+
ImportDeclaration(path62) {
|
|
41158
|
+
const node = path62.node;
|
|
40731
41159
|
const importInfo = extractImportInfo(node);
|
|
40732
41160
|
if (!opts.includeTypeImports && importInfo.isTypeOnly) {
|
|
40733
41161
|
return;
|
|
@@ -40747,8 +41175,8 @@ function extractCallsFromSource(source, filePath, options = {}) {
|
|
|
40747
41175
|
// ========================================
|
|
40748
41176
|
// Dynamic Imports
|
|
40749
41177
|
// ========================================
|
|
40750
|
-
"CallExpression|OptionalCallExpression"(
|
|
40751
|
-
const node =
|
|
41178
|
+
"CallExpression|OptionalCallExpression"(path62) {
|
|
41179
|
+
const node = path62.node;
|
|
40752
41180
|
if (node.callee.type === "Import") {
|
|
40753
41181
|
const arg = node.arguments[0];
|
|
40754
41182
|
let modulePath = "<dynamic>";
|
|
@@ -40784,8 +41212,8 @@ function extractCallsFromSource(source, filePath, options = {}) {
|
|
|
40784
41212
|
// ========================================
|
|
40785
41213
|
// Track Defined Symbols
|
|
40786
41214
|
// ========================================
|
|
40787
|
-
VariableDeclarator(
|
|
40788
|
-
const id =
|
|
41215
|
+
VariableDeclarator(path62) {
|
|
41216
|
+
const id = path62.node.id;
|
|
40789
41217
|
if (id.type === "Identifier") {
|
|
40790
41218
|
definedSymbols.add(id.name);
|
|
40791
41219
|
} else if (id.type === "ObjectPattern") {
|
|
@@ -40804,38 +41232,38 @@ function extractCallsFromSource(source, filePath, options = {}) {
|
|
|
40804
41232
|
}
|
|
40805
41233
|
}
|
|
40806
41234
|
},
|
|
40807
|
-
FunctionDeclaration(
|
|
40808
|
-
if (
|
|
40809
|
-
definedSymbols.add(
|
|
41235
|
+
FunctionDeclaration(path62) {
|
|
41236
|
+
if (path62.node.id) {
|
|
41237
|
+
definedSymbols.add(path62.node.id.name);
|
|
40810
41238
|
}
|
|
40811
|
-
for (const param of
|
|
41239
|
+
for (const param of path62.node.params) {
|
|
40812
41240
|
if (param.type === "Identifier") {
|
|
40813
41241
|
definedSymbols.add(param.name);
|
|
40814
41242
|
}
|
|
40815
41243
|
}
|
|
40816
41244
|
},
|
|
40817
|
-
ClassDeclaration(
|
|
40818
|
-
if (
|
|
40819
|
-
definedSymbols.add(
|
|
41245
|
+
ClassDeclaration(path62) {
|
|
41246
|
+
if (path62.node.id) {
|
|
41247
|
+
definedSymbols.add(path62.node.id.name);
|
|
40820
41248
|
}
|
|
40821
41249
|
},
|
|
40822
41250
|
// Arrow functions assigned to const
|
|
40823
|
-
ArrowFunctionExpression(
|
|
40824
|
-
for (const param of
|
|
41251
|
+
ArrowFunctionExpression(path62) {
|
|
41252
|
+
for (const param of path62.node.params) {
|
|
40825
41253
|
if (param.type === "Identifier") {
|
|
40826
41254
|
definedSymbols.add(param.name);
|
|
40827
41255
|
}
|
|
40828
41256
|
}
|
|
40829
41257
|
},
|
|
40830
41258
|
// Type declarations (TypeScript)
|
|
40831
|
-
TSTypeAliasDeclaration(
|
|
40832
|
-
definedSymbols.add(
|
|
41259
|
+
TSTypeAliasDeclaration(path62) {
|
|
41260
|
+
definedSymbols.add(path62.node.id.name);
|
|
40833
41261
|
},
|
|
40834
|
-
TSInterfaceDeclaration(
|
|
40835
|
-
definedSymbols.add(
|
|
41262
|
+
TSInterfaceDeclaration(path62) {
|
|
41263
|
+
definedSymbols.add(path62.node.id.name);
|
|
40836
41264
|
},
|
|
40837
|
-
TSEnumDeclaration(
|
|
40838
|
-
definedSymbols.add(
|
|
41265
|
+
TSEnumDeclaration(path62) {
|
|
41266
|
+
definedSymbols.add(path62.node.id.name);
|
|
40839
41267
|
}
|
|
40840
41268
|
});
|
|
40841
41269
|
} catch (error) {
|
|
@@ -41268,6 +41696,22 @@ function shouldBlock(violation, context) {
|
|
|
41268
41696
|
return false;
|
|
41269
41697
|
}
|
|
41270
41698
|
}
|
|
41699
|
+
function formatViolationMessage(violation) {
|
|
41700
|
+
const icon = violation.tier === "hard_block" ? "\u{1F6D1}" : violation.tier === "soft_block" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
|
|
41701
|
+
const lines = [
|
|
41702
|
+
`${icon} Blocked: ${violation.category}`,
|
|
41703
|
+
`Evidence: ${violation.evidence}`
|
|
41704
|
+
];
|
|
41705
|
+
if (violation.quickFixes.length > 0) {
|
|
41706
|
+
lines.push("Fix:");
|
|
41707
|
+
violation.quickFixes.slice(0, 3).forEach((fix) => {
|
|
41708
|
+
lines.push(` \u2705 ${fix.label}`);
|
|
41709
|
+
});
|
|
41710
|
+
} else if (violation.suggestion) {
|
|
41711
|
+
lines.push(`Fix: ${violation.suggestion}`);
|
|
41712
|
+
}
|
|
41713
|
+
return lines.join("\n");
|
|
41714
|
+
}
|
|
41271
41715
|
function createTieredViolation(rule, category, evidence, options = {}) {
|
|
41272
41716
|
return {
|
|
41273
41717
|
tier: options.tierOverride ?? getTierForRule(rule),
|
|
@@ -41327,9 +41771,35 @@ function getDefaultRules() {
|
|
|
41327
41771
|
new UnsafeSideEffectRule().toPolicy()
|
|
41328
41772
|
];
|
|
41329
41773
|
}
|
|
41330
|
-
|
|
41331
|
-
|
|
41332
|
-
|
|
41774
|
+
function createObserveModeManager(onComplete) {
|
|
41775
|
+
return new ObserveModeManager({
|
|
41776
|
+
observeDuration: 120,
|
|
41777
|
+
// 2 minutes
|
|
41778
|
+
observeSaveCount: 20,
|
|
41779
|
+
// or 20 saves
|
|
41780
|
+
onComplete
|
|
41781
|
+
});
|
|
41782
|
+
}
|
|
41783
|
+
function createAllowlistManager(projectRoot) {
|
|
41784
|
+
return new AllowlistManager(projectRoot);
|
|
41785
|
+
}
|
|
41786
|
+
async function isAllowed(projectRoot, type, value) {
|
|
41787
|
+
const manager = new AllowlistManager(projectRoot);
|
|
41788
|
+
await manager.load();
|
|
41789
|
+
switch (type) {
|
|
41790
|
+
case "route":
|
|
41791
|
+
return manager.isRouteAllowed(value);
|
|
41792
|
+
case "env":
|
|
41793
|
+
return manager.isEnvVarAllowed(value);
|
|
41794
|
+
case "path":
|
|
41795
|
+
return manager.isPathIgnored(value);
|
|
41796
|
+
default:
|
|
41797
|
+
return false;
|
|
41798
|
+
}
|
|
41799
|
+
}
|
|
41800
|
+
var DEFAULT_CONFIG10, DRIFT_WEIGHTS, ScopeCreepDetector, IntentValidator, DEFAULT_OPTIONS6, PARSER_OPTIONS, ClaimExtractor, DEFAULT_CONFIG25, BUILTIN_MODULES, EvidenceResolver, POLICY_LIMITS, VALID_SEVERITIES, PolicyEngine, UnblockPlanner, DEFAULT_CONFIG34, modeValidator, actionValidator, AgentFirewall, ContractGenerator, ContractVerifier, DEFAULT_WEIGHTS, TrustScorer, BEHAVIOR_TEMPLATES, ENTITY_TEMPLATES, ISLGenerator, globalGenerator, IntentStore, globalIntentStore, MissionService, globalMissionService, TIER_A_RULES, TIER_B_RULES, TIER_C_RULES, BaseRule, DEFAULT_CONFIG44, GhostRouteRule, DEFAULT_CONFIG54, GhostEnvRule, DEFAULT_CONFIG63, AuthDriftRule, DEFAULT_CONFIG72, ContractDriftRule, DEFAULT_CONFIG82, ScopeExplosionRule, DEFAULT_CONFIG92, UnsafeSideEffectRule, ObserveModeManager, DEFAULT_ALLOWLIST, ALLOWLIST_FILENAME, AllowlistManager;
|
|
41801
|
+
var init_chunk_4MEEGNJS = __esm({
|
|
41802
|
+
"../../packages/core/dist/chunk-4MEEGNJS.js"() {
|
|
41333
41803
|
init_chunk_DFJL4MLU();
|
|
41334
41804
|
init_chunk_SKXQ6JUA();
|
|
41335
41805
|
init_chunk_4EQXFW4J();
|
|
@@ -41589,23 +42059,23 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
41589
42059
|
/**
|
|
41590
42060
|
* Categorize a drift event
|
|
41591
42061
|
*/
|
|
41592
|
-
categorizeDrift(
|
|
41593
|
-
if (this.matchesSensitivePattern(
|
|
42062
|
+
categorizeDrift(path62, operation) {
|
|
42063
|
+
if (this.matchesSensitivePattern(path62)) {
|
|
41594
42064
|
return {
|
|
41595
42065
|
category: "sensitive_area",
|
|
41596
|
-
reason: `Path "${
|
|
42066
|
+
reason: `Path "${path62}" touches sensitive area (auth/billing/security)`
|
|
41597
42067
|
};
|
|
41598
42068
|
}
|
|
41599
|
-
if (this.isDependencyFile(
|
|
42069
|
+
if (this.isDependencyFile(path62) && operation !== "read") {
|
|
41600
42070
|
return {
|
|
41601
42071
|
category: "dependency_drift",
|
|
41602
|
-
reason: `Modifying dependency file "${
|
|
42072
|
+
reason: `Modifying dependency file "${path62}" without declaration`
|
|
41603
42073
|
};
|
|
41604
42074
|
}
|
|
41605
|
-
if (this.isInDifferentPackage(
|
|
42075
|
+
if (this.isInDifferentPackage(path62)) {
|
|
41606
42076
|
return {
|
|
41607
42077
|
category: "package_drift",
|
|
41608
|
-
reason: `Path "${
|
|
42078
|
+
reason: `Path "${path62}" is in a different package than declared scope`
|
|
41609
42079
|
};
|
|
41610
42080
|
}
|
|
41611
42081
|
if (!this.isAllowedOperation(operation)) {
|
|
@@ -41614,8 +42084,8 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
41614
42084
|
reason: `Operation "${operation}" not allowed in current plan`
|
|
41615
42085
|
};
|
|
41616
42086
|
}
|
|
41617
|
-
if (!this.isPathAllowed(
|
|
41618
|
-
const dir = this.getDirectory(
|
|
42087
|
+
if (!this.isPathAllowed(path62)) {
|
|
42088
|
+
const dir = this.getDirectory(path62);
|
|
41619
42089
|
if (dir && !this.existingDirectories.has(dir)) {
|
|
41620
42090
|
return {
|
|
41621
42091
|
category: "directory_outside_scope",
|
|
@@ -41624,12 +42094,12 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
41624
42094
|
}
|
|
41625
42095
|
return {
|
|
41626
42096
|
category: "unpredicted_file",
|
|
41627
|
-
reason: `File "${
|
|
42097
|
+
reason: `File "${path62}" not in predicted files or allowed patterns`
|
|
41628
42098
|
};
|
|
41629
42099
|
}
|
|
41630
42100
|
return {
|
|
41631
42101
|
category: "unpredicted_file",
|
|
41632
|
-
reason: `File "${
|
|
42102
|
+
reason: `File "${path62}" was not predicted by the change plan`
|
|
41633
42103
|
};
|
|
41634
42104
|
}
|
|
41635
42105
|
// ============================================================================
|
|
@@ -41729,15 +42199,15 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
41729
42199
|
}
|
|
41730
42200
|
return patterns;
|
|
41731
42201
|
}
|
|
41732
|
-
isPredictedFile(
|
|
42202
|
+
isPredictedFile(path62) {
|
|
41733
42203
|
if (!this.activePlan) return false;
|
|
41734
42204
|
return this.activePlan.predictedFiles.some(
|
|
41735
|
-
(predicted) => this.matchPath(
|
|
42205
|
+
(predicted) => this.matchPath(path62, predicted)
|
|
41736
42206
|
);
|
|
41737
42207
|
}
|
|
41738
|
-
isInScope(
|
|
42208
|
+
isInScope(path62, operation) {
|
|
41739
42209
|
if (!this.activePlan) return true;
|
|
41740
|
-
if (this.activePlan.blockedPatterns.some((pattern) => this.matchGlob(
|
|
42210
|
+
if (this.activePlan.blockedPatterns.some((pattern) => this.matchGlob(path62, pattern))) {
|
|
41741
42211
|
return false;
|
|
41742
42212
|
}
|
|
41743
42213
|
if (!this.activePlan.expectedOperations.includes(operation)) {
|
|
@@ -41745,33 +42215,33 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
41745
42215
|
return false;
|
|
41746
42216
|
}
|
|
41747
42217
|
}
|
|
41748
|
-
if (this.isPredictedFile(
|
|
42218
|
+
if (this.isPredictedFile(path62)) {
|
|
41749
42219
|
return true;
|
|
41750
42220
|
}
|
|
41751
|
-
return this.isPathAllowed(
|
|
42221
|
+
return this.isPathAllowed(path62);
|
|
41752
42222
|
}
|
|
41753
|
-
isPathAllowed(
|
|
42223
|
+
isPathAllowed(path62) {
|
|
41754
42224
|
if (!this.activePlan) return true;
|
|
41755
42225
|
return this.activePlan.allowedPatterns.some(
|
|
41756
|
-
(pattern) => this.matchGlob(
|
|
42226
|
+
(pattern) => this.matchGlob(path62, pattern)
|
|
41757
42227
|
);
|
|
41758
42228
|
}
|
|
41759
42229
|
isAllowedOperation(operation) {
|
|
41760
42230
|
if (!this.activePlan) return true;
|
|
41761
42231
|
return this.activePlan.expectedOperations.includes(operation) || operation === "read";
|
|
41762
42232
|
}
|
|
41763
|
-
matchesSensitivePattern(
|
|
42233
|
+
matchesSensitivePattern(path62) {
|
|
41764
42234
|
return this.config.sensitivePatterns.some(
|
|
41765
|
-
(pattern) => this.matchGlob(
|
|
42235
|
+
(pattern) => this.matchGlob(path62, pattern)
|
|
41766
42236
|
);
|
|
41767
42237
|
}
|
|
41768
|
-
isDependencyFile(
|
|
41769
|
-
const filename =
|
|
42238
|
+
isDependencyFile(path62) {
|
|
42239
|
+
const filename = path62.split("/").pop() ?? path62;
|
|
41770
42240
|
return this.config.dependencyFiles.some(
|
|
41771
|
-
(dep) => filename === dep ||
|
|
42241
|
+
(dep) => filename === dep || path62.endsWith(dep)
|
|
41772
42242
|
);
|
|
41773
42243
|
}
|
|
41774
|
-
isInDifferentPackage(
|
|
42244
|
+
isInDifferentPackage(path62) {
|
|
41775
42245
|
if (!this.activePlan) return false;
|
|
41776
42246
|
const getPackage = (p7) => {
|
|
41777
42247
|
for (const pkgDir of this.config.packageDirectories) {
|
|
@@ -41789,28 +42259,28 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
41789
42259
|
if (pkg2) allowedPackages.add(pkg2);
|
|
41790
42260
|
}
|
|
41791
42261
|
if (allowedPackages.size === 0) return false;
|
|
41792
|
-
const pathPackage = getPackage(
|
|
42262
|
+
const pathPackage = getPackage(path62);
|
|
41793
42263
|
if (!pathPackage) return false;
|
|
41794
42264
|
return !allowedPackages.has(pathPackage);
|
|
41795
42265
|
}
|
|
41796
|
-
matchPath(
|
|
41797
|
-
const normalizedPath = this.normalizePath(
|
|
42266
|
+
matchPath(path62, pattern) {
|
|
42267
|
+
const normalizedPath = this.normalizePath(path62);
|
|
41798
42268
|
const normalizedPattern = this.normalizePath(pattern);
|
|
41799
42269
|
return normalizedPath === normalizedPattern || normalizedPath.endsWith(`/${normalizedPattern}`);
|
|
41800
42270
|
}
|
|
41801
|
-
matchGlob(
|
|
41802
|
-
const normalizedPath = this.normalizePath(
|
|
42271
|
+
matchGlob(path62, pattern) {
|
|
42272
|
+
const normalizedPath = this.normalizePath(path62);
|
|
41803
42273
|
const normalizedPattern = this.normalizePath(pattern);
|
|
41804
42274
|
if (normalizedPath === normalizedPattern) return true;
|
|
41805
42275
|
const regexPattern = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "<<<GLOBSTAR>>>").replace(/\*/g, "[^/]*").replace(/<<<GLOBSTAR>>>/g, ".*").replace(/\?/g, ".");
|
|
41806
42276
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
41807
42277
|
return regex.test(normalizedPath);
|
|
41808
42278
|
}
|
|
41809
|
-
normalizePath(
|
|
41810
|
-
return
|
|
42279
|
+
normalizePath(path62) {
|
|
42280
|
+
return path62.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
41811
42281
|
}
|
|
41812
|
-
getDirectory(
|
|
41813
|
-
const parts =
|
|
42282
|
+
getDirectory(path62) {
|
|
42283
|
+
const parts = path62.split("/");
|
|
41814
42284
|
if (parts.length <= 1) return null;
|
|
41815
42285
|
return parts.slice(0, -1).join("/");
|
|
41816
42286
|
}
|
|
@@ -44150,6 +44620,693 @@ var init_chunk_YK33YEF4 = __esm({
|
|
|
44150
44620
|
this.logger.info("Agent firewall disposed");
|
|
44151
44621
|
}
|
|
44152
44622
|
};
|
|
44623
|
+
ContractGenerator = class {
|
|
44624
|
+
projectRoot;
|
|
44625
|
+
outputDir;
|
|
44626
|
+
contracts = /* @__PURE__ */ new Map();
|
|
44627
|
+
constructor(options) {
|
|
44628
|
+
this.projectRoot = options.projectRoot;
|
|
44629
|
+
this.outputDir = options.outputDir ?? path18.join(options.projectRoot, ".vibecheck", "contracts");
|
|
44630
|
+
}
|
|
44631
|
+
/**
|
|
44632
|
+
* Generate contracts from all detected sources
|
|
44633
|
+
*/
|
|
44634
|
+
async generateAll() {
|
|
44635
|
+
const contracts = [];
|
|
44636
|
+
const zodContracts = await this.generateFromZod();
|
|
44637
|
+
contracts.push(...zodContracts);
|
|
44638
|
+
const tsContracts = await this.generateFromTypeScript();
|
|
44639
|
+
contracts.push(...tsContracts);
|
|
44640
|
+
const openApiContracts = await this.generateFromOpenAPI();
|
|
44641
|
+
contracts.push(...openApiContracts);
|
|
44642
|
+
const inferredContracts = await this.inferFromRoutes();
|
|
44643
|
+
contracts.push(...inferredContracts);
|
|
44644
|
+
await this.saveContracts(contracts);
|
|
44645
|
+
return contracts;
|
|
44646
|
+
}
|
|
44647
|
+
/**
|
|
44648
|
+
* Generate contracts from Zod schemas
|
|
44649
|
+
*/
|
|
44650
|
+
async generateFromZod() {
|
|
44651
|
+
const contracts = [];
|
|
44652
|
+
const zodFiles = await this.findFiles(["**/*.ts", "**/*.tsx"], /z\.object|z\.string|z\.number/);
|
|
44653
|
+
for (const file2 of zodFiles) {
|
|
44654
|
+
try {
|
|
44655
|
+
const content = await fs15.promises.readFile(file2, "utf-8");
|
|
44656
|
+
const schemas = this.extractZodSchemas(content, file2);
|
|
44657
|
+
for (const schema of schemas) {
|
|
44658
|
+
const spec = this.zodSchemaToISL(schema);
|
|
44659
|
+
contracts.push({
|
|
44660
|
+
spec,
|
|
44661
|
+
metadata: {
|
|
44662
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44663
|
+
source: {
|
|
44664
|
+
type: "zod",
|
|
44665
|
+
file: path18.relative(this.projectRoot, file2),
|
|
44666
|
+
confidence: 0.9
|
|
44667
|
+
},
|
|
44668
|
+
version: "1.0.0"
|
|
44669
|
+
},
|
|
44670
|
+
filePath: path18.join(this.outputDir, `${schema.name}.isl.json`)
|
|
44671
|
+
});
|
|
44672
|
+
}
|
|
44673
|
+
} catch {
|
|
44674
|
+
}
|
|
44675
|
+
}
|
|
44676
|
+
return contracts;
|
|
44677
|
+
}
|
|
44678
|
+
/**
|
|
44679
|
+
* Generate contracts from TypeScript interfaces
|
|
44680
|
+
*/
|
|
44681
|
+
async generateFromTypeScript() {
|
|
44682
|
+
const contracts = [];
|
|
44683
|
+
const tsFiles = await this.findFiles(["**/*.ts", "**/*.d.ts"], /interface\s+\w+|type\s+\w+\s*=/);
|
|
44684
|
+
for (const file2 of tsFiles) {
|
|
44685
|
+
try {
|
|
44686
|
+
const content = await fs15.promises.readFile(file2, "utf-8");
|
|
44687
|
+
const interfaces = this.extractTypeScriptInterfaces(content, file2);
|
|
44688
|
+
for (const iface of interfaces) {
|
|
44689
|
+
const spec = this.interfaceToISL(iface);
|
|
44690
|
+
contracts.push({
|
|
44691
|
+
spec,
|
|
44692
|
+
metadata: {
|
|
44693
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44694
|
+
source: {
|
|
44695
|
+
type: "typescript",
|
|
44696
|
+
file: path18.relative(this.projectRoot, file2),
|
|
44697
|
+
line: iface.line,
|
|
44698
|
+
confidence: 0.85
|
|
44699
|
+
},
|
|
44700
|
+
version: "1.0.0"
|
|
44701
|
+
},
|
|
44702
|
+
filePath: path18.join(this.outputDir, `${iface.name}.isl.json`)
|
|
44703
|
+
});
|
|
44704
|
+
}
|
|
44705
|
+
} catch {
|
|
44706
|
+
}
|
|
44707
|
+
}
|
|
44708
|
+
return contracts;
|
|
44709
|
+
}
|
|
44710
|
+
/**
|
|
44711
|
+
* Generate contracts from OpenAPI specs
|
|
44712
|
+
*/
|
|
44713
|
+
async generateFromOpenAPI() {
|
|
44714
|
+
const contracts = [];
|
|
44715
|
+
const specFiles = await this.findFiles(
|
|
44716
|
+
["**/openapi.yaml", "**/openapi.json", "**/swagger.yaml", "**/swagger.json"],
|
|
44717
|
+
null
|
|
44718
|
+
);
|
|
44719
|
+
for (const file2 of specFiles) {
|
|
44720
|
+
try {
|
|
44721
|
+
const content = await fs15.promises.readFile(file2, "utf-8");
|
|
44722
|
+
const spec = file2.endsWith(".json") ? JSON.parse(content) : this.parseYaml(content);
|
|
44723
|
+
const operations = this.extractOpenAPIOperations(spec);
|
|
44724
|
+
for (const op of operations) {
|
|
44725
|
+
const islSpec = this.operationToISL(op);
|
|
44726
|
+
contracts.push({
|
|
44727
|
+
spec: islSpec,
|
|
44728
|
+
metadata: {
|
|
44729
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44730
|
+
source: {
|
|
44731
|
+
type: "openapi",
|
|
44732
|
+
file: path18.relative(this.projectRoot, file2),
|
|
44733
|
+
confidence: 0.95
|
|
44734
|
+
},
|
|
44735
|
+
version: "1.0.0"
|
|
44736
|
+
},
|
|
44737
|
+
filePath: path18.join(this.outputDir, `${op.operationId || op.path.replace(/\//g, "-")}.isl.json`)
|
|
44738
|
+
});
|
|
44739
|
+
}
|
|
44740
|
+
} catch {
|
|
44741
|
+
}
|
|
44742
|
+
}
|
|
44743
|
+
return contracts;
|
|
44744
|
+
}
|
|
44745
|
+
/**
|
|
44746
|
+
* Infer contracts from route handlers
|
|
44747
|
+
*/
|
|
44748
|
+
async inferFromRoutes() {
|
|
44749
|
+
const contracts = [];
|
|
44750
|
+
const routeFiles = await this.findFiles(
|
|
44751
|
+
["**/routes/**/*.ts", "**/api/**/*.ts", "**/pages/api/**/*.ts"],
|
|
44752
|
+
/app\.(get|post|put|delete|patch)|router\.(get|post|put|delete|patch)|export\s+(async\s+)?function\s+(GET|POST|PUT|DELETE|PATCH)/i
|
|
44753
|
+
);
|
|
44754
|
+
for (const file2 of routeFiles) {
|
|
44755
|
+
try {
|
|
44756
|
+
const content = await fs15.promises.readFile(file2, "utf-8");
|
|
44757
|
+
const handlers = this.extractRouteHandlers(content, file2);
|
|
44758
|
+
for (const handler of handlers) {
|
|
44759
|
+
const spec = this.handlerToISL(handler);
|
|
44760
|
+
contracts.push({
|
|
44761
|
+
spec,
|
|
44762
|
+
metadata: {
|
|
44763
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44764
|
+
source: {
|
|
44765
|
+
type: "inferred",
|
|
44766
|
+
file: path18.relative(this.projectRoot, file2),
|
|
44767
|
+
line: handler.line,
|
|
44768
|
+
confidence: 0.7
|
|
44769
|
+
},
|
|
44770
|
+
version: "1.0.0"
|
|
44771
|
+
},
|
|
44772
|
+
filePath: path18.join(this.outputDir, `${handler.name}.isl.json`)
|
|
44773
|
+
});
|
|
44774
|
+
}
|
|
44775
|
+
} catch {
|
|
44776
|
+
}
|
|
44777
|
+
}
|
|
44778
|
+
return contracts;
|
|
44779
|
+
}
|
|
44780
|
+
/**
|
|
44781
|
+
* Save contracts to disk
|
|
44782
|
+
*/
|
|
44783
|
+
async saveContracts(contracts) {
|
|
44784
|
+
await fs15.promises.mkdir(this.outputDir, { recursive: true });
|
|
44785
|
+
for (const contract of contracts) {
|
|
44786
|
+
await fs15.promises.writeFile(
|
|
44787
|
+
contract.filePath,
|
|
44788
|
+
JSON.stringify({ spec: contract.spec, metadata: contract.metadata }, null, 2)
|
|
44789
|
+
);
|
|
44790
|
+
this.contracts.set(contract.spec.domain, contract);
|
|
44791
|
+
}
|
|
44792
|
+
}
|
|
44793
|
+
/**
|
|
44794
|
+
* Get all loaded contracts
|
|
44795
|
+
*/
|
|
44796
|
+
getContracts() {
|
|
44797
|
+
return Array.from(this.contracts.values());
|
|
44798
|
+
}
|
|
44799
|
+
// Helper methods
|
|
44800
|
+
async findFiles(patterns, contentFilter) {
|
|
44801
|
+
const files = [];
|
|
44802
|
+
const walk = async (dir) => {
|
|
44803
|
+
try {
|
|
44804
|
+
const entries = await fs15.promises.readdir(dir, { withFileTypes: true });
|
|
44805
|
+
for (const entry of entries) {
|
|
44806
|
+
const fullPath = path18.join(dir, entry.name);
|
|
44807
|
+
if (entry.isDirectory()) {
|
|
44808
|
+
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
44809
|
+
await walk(fullPath);
|
|
44810
|
+
}
|
|
44811
|
+
} else if (entry.isFile()) {
|
|
44812
|
+
const matches = patterns.some((p7) => {
|
|
44813
|
+
const ext = path18.extname(entry.name);
|
|
44814
|
+
return p7.includes(ext) || p7.includes("*");
|
|
44815
|
+
});
|
|
44816
|
+
if (matches) {
|
|
44817
|
+
if (contentFilter) {
|
|
44818
|
+
try {
|
|
44819
|
+
const content = await fs15.promises.readFile(fullPath, "utf-8");
|
|
44820
|
+
if (contentFilter.test(content)) {
|
|
44821
|
+
files.push(fullPath);
|
|
44822
|
+
}
|
|
44823
|
+
} catch {
|
|
44824
|
+
}
|
|
44825
|
+
} else {
|
|
44826
|
+
files.push(fullPath);
|
|
44827
|
+
}
|
|
44828
|
+
}
|
|
44829
|
+
}
|
|
44830
|
+
}
|
|
44831
|
+
} catch {
|
|
44832
|
+
}
|
|
44833
|
+
};
|
|
44834
|
+
await walk(this.projectRoot);
|
|
44835
|
+
return files;
|
|
44836
|
+
}
|
|
44837
|
+
extractZodSchemas(content, _file) {
|
|
44838
|
+
const schemas = [];
|
|
44839
|
+
const regex = /(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*z\.object\s*\(\s*\{([^}]+)\}/g;
|
|
44840
|
+
let match;
|
|
44841
|
+
while ((match = regex.exec(content)) !== null) {
|
|
44842
|
+
schemas.push({ name: match[1], schema: match[2] });
|
|
44843
|
+
}
|
|
44844
|
+
return schemas;
|
|
44845
|
+
}
|
|
44846
|
+
extractTypeScriptInterfaces(_content, _file) {
|
|
44847
|
+
return [];
|
|
44848
|
+
}
|
|
44849
|
+
extractOpenAPIOperations(_spec) {
|
|
44850
|
+
return [];
|
|
44851
|
+
}
|
|
44852
|
+
extractRouteHandlers(_content, _file) {
|
|
44853
|
+
return [];
|
|
44854
|
+
}
|
|
44855
|
+
zodSchemaToISL(schema) {
|
|
44856
|
+
return {
|
|
44857
|
+
version: "1.0",
|
|
44858
|
+
domain: schema.name,
|
|
44859
|
+
behaviors: [{
|
|
44860
|
+
name: `validate${schema.name}`,
|
|
44861
|
+
input: { fields: [] },
|
|
44862
|
+
output: { success: { type: schema.name } }
|
|
44863
|
+
}]
|
|
44864
|
+
};
|
|
44865
|
+
}
|
|
44866
|
+
interfaceToISL(iface) {
|
|
44867
|
+
return {
|
|
44868
|
+
version: "1.0",
|
|
44869
|
+
domain: iface.name,
|
|
44870
|
+
behaviors: []
|
|
44871
|
+
};
|
|
44872
|
+
}
|
|
44873
|
+
operationToISL(op) {
|
|
44874
|
+
return {
|
|
44875
|
+
version: "1.0",
|
|
44876
|
+
domain: op.operationId ?? op.path,
|
|
44877
|
+
behaviors: [{
|
|
44878
|
+
name: `${op.method}${op.path.replace(/\//g, "_")}`,
|
|
44879
|
+
input: { fields: [] },
|
|
44880
|
+
output: {}
|
|
44881
|
+
}]
|
|
44882
|
+
};
|
|
44883
|
+
}
|
|
44884
|
+
handlerToISL(handler) {
|
|
44885
|
+
return {
|
|
44886
|
+
version: "1.0",
|
|
44887
|
+
domain: handler.name,
|
|
44888
|
+
behaviors: [{
|
|
44889
|
+
name: handler.name,
|
|
44890
|
+
description: `${handler.method} ${handler.path}`,
|
|
44891
|
+
input: { fields: [] },
|
|
44892
|
+
output: {}
|
|
44893
|
+
}]
|
|
44894
|
+
};
|
|
44895
|
+
}
|
|
44896
|
+
parseYaml(_content) {
|
|
44897
|
+
return {};
|
|
44898
|
+
}
|
|
44899
|
+
};
|
|
44900
|
+
ContractVerifier = class {
|
|
44901
|
+
projectRoot;
|
|
44902
|
+
contractsDir;
|
|
44903
|
+
contracts = /* @__PURE__ */ new Map();
|
|
44904
|
+
strict;
|
|
44905
|
+
constructor(options) {
|
|
44906
|
+
this.projectRoot = options.projectRoot;
|
|
44907
|
+
this.contractsDir = options.contractsDir ?? path18.join(options.projectRoot, ".vibecheck", "contracts");
|
|
44908
|
+
this.strict = options.strict ?? false;
|
|
44909
|
+
}
|
|
44910
|
+
/**
|
|
44911
|
+
* Load contracts from disk
|
|
44912
|
+
*/
|
|
44913
|
+
async loadContracts() {
|
|
44914
|
+
try {
|
|
44915
|
+
const files = await fs15.promises.readdir(this.contractsDir);
|
|
44916
|
+
for (const file2 of files) {
|
|
44917
|
+
if (file2.endsWith(".isl.json")) {
|
|
44918
|
+
try {
|
|
44919
|
+
const content = await fs15.promises.readFile(
|
|
44920
|
+
path18.join(this.contractsDir, file2),
|
|
44921
|
+
"utf-8"
|
|
44922
|
+
);
|
|
44923
|
+
const data = JSON.parse(content);
|
|
44924
|
+
this.contracts.set(data.spec.domain, {
|
|
44925
|
+
spec: data.spec,
|
|
44926
|
+
metadata: data.metadata,
|
|
44927
|
+
filePath: path18.join(this.contractsDir, file2)
|
|
44928
|
+
});
|
|
44929
|
+
} catch {
|
|
44930
|
+
}
|
|
44931
|
+
}
|
|
44932
|
+
}
|
|
44933
|
+
} catch {
|
|
44934
|
+
}
|
|
44935
|
+
}
|
|
44936
|
+
/**
|
|
44937
|
+
* Verify a file against its contracts
|
|
44938
|
+
*/
|
|
44939
|
+
async verifyFile(filePath) {
|
|
44940
|
+
const violations = [];
|
|
44941
|
+
let verifiedBehaviors = 0;
|
|
44942
|
+
let totalBehaviors = 0;
|
|
44943
|
+
try {
|
|
44944
|
+
const content = await fs15.promises.readFile(filePath, "utf-8");
|
|
44945
|
+
const relativePath = path18.relative(this.projectRoot, filePath);
|
|
44946
|
+
for (const [domain, contract] of this.contracts) {
|
|
44947
|
+
if (this.isApplicable(relativePath, contract)) {
|
|
44948
|
+
for (const behavior of contract.spec.behaviors) {
|
|
44949
|
+
totalBehaviors++;
|
|
44950
|
+
const behaviorViolations = await this.verifyBehavior(
|
|
44951
|
+
content,
|
|
44952
|
+
behavior,
|
|
44953
|
+
domain,
|
|
44954
|
+
relativePath
|
|
44955
|
+
);
|
|
44956
|
+
if (behaviorViolations.length === 0) {
|
|
44957
|
+
verifiedBehaviors++;
|
|
44958
|
+
} else {
|
|
44959
|
+
violations.push(...behaviorViolations);
|
|
44960
|
+
}
|
|
44961
|
+
}
|
|
44962
|
+
}
|
|
44963
|
+
}
|
|
44964
|
+
} catch {
|
|
44965
|
+
violations.push({
|
|
44966
|
+
type: "contract_drift",
|
|
44967
|
+
severity: "error",
|
|
44968
|
+
message: `Could not read file: ${filePath}`,
|
|
44969
|
+
file: filePath,
|
|
44970
|
+
contractName: "unknown",
|
|
44971
|
+
autoFixable: false
|
|
44972
|
+
});
|
|
44973
|
+
}
|
|
44974
|
+
const coverage = totalBehaviors > 0 ? verifiedBehaviors / totalBehaviors * 100 : 100;
|
|
44975
|
+
return {
|
|
44976
|
+
passed: violations.filter((v) => v.severity === "error").length === 0,
|
|
44977
|
+
violations,
|
|
44978
|
+
verifiedBehaviors,
|
|
44979
|
+
totalBehaviors,
|
|
44980
|
+
coverage,
|
|
44981
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
44982
|
+
};
|
|
44983
|
+
}
|
|
44984
|
+
/**
|
|
44985
|
+
* Verify all files in the project
|
|
44986
|
+
*/
|
|
44987
|
+
async verifyAll() {
|
|
44988
|
+
const allViolations = [];
|
|
44989
|
+
let totalVerified = 0;
|
|
44990
|
+
let totalBehaviors = 0;
|
|
44991
|
+
const files = await this.findSourceFiles();
|
|
44992
|
+
for (const file2 of files) {
|
|
44993
|
+
const result = await this.verifyFile(file2);
|
|
44994
|
+
allViolations.push(...result.violations);
|
|
44995
|
+
totalVerified += result.verifiedBehaviors;
|
|
44996
|
+
totalBehaviors += result.totalBehaviors;
|
|
44997
|
+
}
|
|
44998
|
+
const coverage = totalBehaviors > 0 ? totalVerified / totalBehaviors * 100 : 100;
|
|
44999
|
+
return {
|
|
45000
|
+
passed: allViolations.filter((v) => v.severity === "error").length === 0,
|
|
45001
|
+
violations: allViolations,
|
|
45002
|
+
verifiedBehaviors: totalVerified,
|
|
45003
|
+
totalBehaviors,
|
|
45004
|
+
coverage,
|
|
45005
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
45006
|
+
};
|
|
45007
|
+
}
|
|
45008
|
+
/**
|
|
45009
|
+
* Verify a single code change against contracts (for firewall integration)
|
|
45010
|
+
*/
|
|
45011
|
+
async verifyChange(filePath, oldContent, newContent) {
|
|
45012
|
+
const violations = [];
|
|
45013
|
+
const relativePath = path18.relative(this.projectRoot, filePath);
|
|
45014
|
+
for (const [domain, contract] of this.contracts) {
|
|
45015
|
+
if (this.isApplicable(relativePath, contract)) {
|
|
45016
|
+
const driftViolations = this.detectDrift(
|
|
45017
|
+
oldContent,
|
|
45018
|
+
newContent,
|
|
45019
|
+
contract.spec,
|
|
45020
|
+
relativePath
|
|
45021
|
+
);
|
|
45022
|
+
violations.push(...driftViolations);
|
|
45023
|
+
for (const behavior of contract.spec.behaviors) {
|
|
45024
|
+
const behaviorViolations = await this.verifyBehavior(
|
|
45025
|
+
newContent,
|
|
45026
|
+
behavior,
|
|
45027
|
+
domain,
|
|
45028
|
+
relativePath
|
|
45029
|
+
);
|
|
45030
|
+
violations.push(...behaviorViolations);
|
|
45031
|
+
}
|
|
45032
|
+
}
|
|
45033
|
+
}
|
|
45034
|
+
return violations;
|
|
45035
|
+
}
|
|
45036
|
+
/**
|
|
45037
|
+
* Get all loaded contracts
|
|
45038
|
+
*/
|
|
45039
|
+
getContracts() {
|
|
45040
|
+
return Array.from(this.contracts.values());
|
|
45041
|
+
}
|
|
45042
|
+
// Private helpers
|
|
45043
|
+
isApplicable(_filePath, _contract) {
|
|
45044
|
+
return true;
|
|
45045
|
+
}
|
|
45046
|
+
async verifyBehavior(content, behavior, contractName, filePath) {
|
|
45047
|
+
const violations = [];
|
|
45048
|
+
if (behavior.input.fields.length > 0) {
|
|
45049
|
+
const inputViolations = this.checkInputValidation(
|
|
45050
|
+
content,
|
|
45051
|
+
behavior,
|
|
45052
|
+
contractName,
|
|
45053
|
+
filePath
|
|
45054
|
+
);
|
|
45055
|
+
violations.push(...inputViolations);
|
|
45056
|
+
}
|
|
45057
|
+
if (behavior.preconditions) {
|
|
45058
|
+
for (const pre of behavior.preconditions) {
|
|
45059
|
+
if (!this.checkConstraint(content, pre)) {
|
|
45060
|
+
violations.push({
|
|
45061
|
+
type: "constraint_violation",
|
|
45062
|
+
severity: this.strict ? "error" : "warning",
|
|
45063
|
+
message: `Precondition not enforced: ${pre.message ?? pre.expression}`,
|
|
45064
|
+
file: filePath,
|
|
45065
|
+
contractName,
|
|
45066
|
+
behaviorName: behavior.name,
|
|
45067
|
+
suggestion: `Add validation: ${pre.expression}`,
|
|
45068
|
+
autoFixable: true
|
|
45069
|
+
});
|
|
45070
|
+
}
|
|
45071
|
+
}
|
|
45072
|
+
}
|
|
45073
|
+
if (behavior.postconditions) {
|
|
45074
|
+
for (const post of behavior.postconditions) {
|
|
45075
|
+
if (!this.checkConstraint(content, post)) {
|
|
45076
|
+
violations.push({
|
|
45077
|
+
type: "constraint_violation",
|
|
45078
|
+
severity: this.strict ? "error" : "warning",
|
|
45079
|
+
message: `Postcondition not guaranteed: ${post.message ?? post.expression}`,
|
|
45080
|
+
file: filePath,
|
|
45081
|
+
contractName,
|
|
45082
|
+
behaviorName: behavior.name,
|
|
45083
|
+
suggestion: `Ensure: ${post.expression}`,
|
|
45084
|
+
autoFixable: false
|
|
45085
|
+
});
|
|
45086
|
+
}
|
|
45087
|
+
}
|
|
45088
|
+
}
|
|
45089
|
+
if (behavior.errors && behavior.errors.length > 0) {
|
|
45090
|
+
const errorViolations = this.checkErrorHandling(
|
|
45091
|
+
content,
|
|
45092
|
+
behavior,
|
|
45093
|
+
contractName,
|
|
45094
|
+
filePath
|
|
45095
|
+
);
|
|
45096
|
+
violations.push(...errorViolations);
|
|
45097
|
+
}
|
|
45098
|
+
return violations;
|
|
45099
|
+
}
|
|
45100
|
+
checkInputValidation(content, behavior, contractName, filePath) {
|
|
45101
|
+
const violations = [];
|
|
45102
|
+
for (const field of behavior.input.fields) {
|
|
45103
|
+
const hasValidation = content.includes(`${field.name}`) && (content.includes("validate") || content.includes("z.") || content.includes("if ("));
|
|
45104
|
+
if (field.required && !hasValidation) {
|
|
45105
|
+
violations.push({
|
|
45106
|
+
type: "missing_field",
|
|
45107
|
+
severity: this.strict ? "error" : "warning",
|
|
45108
|
+
message: `Required field "${field.name}" lacks validation`,
|
|
45109
|
+
file: filePath,
|
|
45110
|
+
contractName,
|
|
45111
|
+
behaviorName: behavior.name,
|
|
45112
|
+
suggestion: `Add validation for "${field.name}"`,
|
|
45113
|
+
autoFixable: true
|
|
45114
|
+
});
|
|
45115
|
+
}
|
|
45116
|
+
}
|
|
45117
|
+
return violations;
|
|
45118
|
+
}
|
|
45119
|
+
checkConstraint(_content, _constraint) {
|
|
45120
|
+
return true;
|
|
45121
|
+
}
|
|
45122
|
+
checkErrorHandling(content, behavior, contractName, filePath) {
|
|
45123
|
+
const violations = [];
|
|
45124
|
+
for (const error of behavior.errors ?? []) {
|
|
45125
|
+
const hasErrorHandling = content.includes("catch") || content.includes("throw") || content.includes(error);
|
|
45126
|
+
if (!hasErrorHandling) {
|
|
45127
|
+
violations.push({
|
|
45128
|
+
type: "unverified_behavior",
|
|
45129
|
+
severity: "warning",
|
|
45130
|
+
message: `Error "${error}" not explicitly handled`,
|
|
45131
|
+
file: filePath,
|
|
45132
|
+
contractName,
|
|
45133
|
+
behaviorName: behavior.name,
|
|
45134
|
+
suggestion: `Add error handling for ${error}`,
|
|
45135
|
+
autoFixable: false
|
|
45136
|
+
});
|
|
45137
|
+
}
|
|
45138
|
+
}
|
|
45139
|
+
return violations;
|
|
45140
|
+
}
|
|
45141
|
+
detectDrift(oldContent, newContent, spec, filePath) {
|
|
45142
|
+
const violations = [];
|
|
45143
|
+
for (const behavior of spec.behaviors) {
|
|
45144
|
+
if (this.signatureChanged(oldContent, newContent, behavior.name)) {
|
|
45145
|
+
violations.push({
|
|
45146
|
+
type: "contract_drift",
|
|
45147
|
+
severity: "warning",
|
|
45148
|
+
message: `Behavior "${behavior.name}" signature may have changed`,
|
|
45149
|
+
file: filePath,
|
|
45150
|
+
contractName: spec.domain,
|
|
45151
|
+
behaviorName: behavior.name,
|
|
45152
|
+
suggestion: "Review contract compatibility",
|
|
45153
|
+
autoFixable: false
|
|
45154
|
+
});
|
|
45155
|
+
}
|
|
45156
|
+
}
|
|
45157
|
+
return violations;
|
|
45158
|
+
}
|
|
45159
|
+
signatureChanged(oldContent, newContent, behaviorName) {
|
|
45160
|
+
const oldMatch = oldContent.match(new RegExp(`function\\s+${behaviorName}\\s*\\([^)]*\\)`));
|
|
45161
|
+
const newMatch = newContent.match(new RegExp(`function\\s+${behaviorName}\\s*\\([^)]*\\)`));
|
|
45162
|
+
if (!oldMatch || !newMatch) return false;
|
|
45163
|
+
return oldMatch[0] !== newMatch[0];
|
|
45164
|
+
}
|
|
45165
|
+
async findSourceFiles() {
|
|
45166
|
+
const files = [];
|
|
45167
|
+
const walk = async (dir) => {
|
|
45168
|
+
try {
|
|
45169
|
+
const entries = await fs15.promises.readdir(dir, { withFileTypes: true });
|
|
45170
|
+
for (const entry of entries) {
|
|
45171
|
+
const fullPath = path18.join(dir, entry.name);
|
|
45172
|
+
if (entry.isDirectory()) {
|
|
45173
|
+
if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
45174
|
+
await walk(fullPath);
|
|
45175
|
+
}
|
|
45176
|
+
} else if (entry.isFile()) {
|
|
45177
|
+
if (entry.name.endsWith(".ts") || entry.name.endsWith(".tsx")) {
|
|
45178
|
+
files.push(fullPath);
|
|
45179
|
+
}
|
|
45180
|
+
}
|
|
45181
|
+
}
|
|
45182
|
+
} catch {
|
|
45183
|
+
}
|
|
45184
|
+
};
|
|
45185
|
+
await walk(this.projectRoot);
|
|
45186
|
+
return files;
|
|
45187
|
+
}
|
|
45188
|
+
};
|
|
45189
|
+
DEFAULT_WEIGHTS = {
|
|
45190
|
+
coverageWeight: 0.2,
|
|
45191
|
+
verificationWeight: 0.25,
|
|
45192
|
+
stabilityWeight: 0.15,
|
|
45193
|
+
qualityWeight: 0.15,
|
|
45194
|
+
errorHandlingWeight: 0.15,
|
|
45195
|
+
inputValidationWeight: 0.1,
|
|
45196
|
+
trustThreshold: 85,
|
|
45197
|
+
reviewThreshold: 60
|
|
45198
|
+
};
|
|
45199
|
+
TrustScorer = class {
|
|
45200
|
+
options;
|
|
45201
|
+
constructor(options = {}) {
|
|
45202
|
+
this.options = { ...DEFAULT_WEIGHTS, ...options };
|
|
45203
|
+
}
|
|
45204
|
+
/**
|
|
45205
|
+
* Calculate trust score from verification results and contracts
|
|
45206
|
+
*/
|
|
45207
|
+
calculate(verificationResult, contracts) {
|
|
45208
|
+
const dimensions = this.calculateDimensions(verificationResult, contracts);
|
|
45209
|
+
const overall = this.calculateOverall(dimensions);
|
|
45210
|
+
const breakdown = this.createBreakdown(verificationResult, contracts);
|
|
45211
|
+
return {
|
|
45212
|
+
overall,
|
|
45213
|
+
dimensions,
|
|
45214
|
+
grade: this.getGrade(overall),
|
|
45215
|
+
verdict: this.getVerdict(overall),
|
|
45216
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45217
|
+
breakdown
|
|
45218
|
+
};
|
|
45219
|
+
}
|
|
45220
|
+
/**
|
|
45221
|
+
* Calculate individual dimension scores
|
|
45222
|
+
*/
|
|
45223
|
+
calculateDimensions(result, contracts) {
|
|
45224
|
+
const contractCoverage = result.coverage;
|
|
45225
|
+
const verificationRate = result.totalBehaviors > 0 ? result.verifiedBehaviors / result.totalBehaviors * 100 : 100;
|
|
45226
|
+
const driftViolations = result.violations.filter((v) => v.type === "contract_drift");
|
|
45227
|
+
const stability = Math.max(0, 100 - driftViolations.length * 10);
|
|
45228
|
+
const contractQuality = contracts.length > 0 ? contracts.reduce((sum, c) => sum + c.metadata.source.confidence, 0) / contracts.length * 100 : 50;
|
|
45229
|
+
const errorViolations = result.violations.filter((v) => v.type === "unverified_behavior");
|
|
45230
|
+
const errorHandling = Math.max(0, 100 - errorViolations.length * 15);
|
|
45231
|
+
const inputViolations = result.violations.filter((v) => v.type === "missing_field");
|
|
45232
|
+
const inputValidation = Math.max(0, 100 - inputViolations.length * 20);
|
|
45233
|
+
return {
|
|
45234
|
+
contractCoverage,
|
|
45235
|
+
verificationRate,
|
|
45236
|
+
stability,
|
|
45237
|
+
contractQuality,
|
|
45238
|
+
errorHandling,
|
|
45239
|
+
inputValidation
|
|
45240
|
+
};
|
|
45241
|
+
}
|
|
45242
|
+
/**
|
|
45243
|
+
* Calculate overall score from dimensions
|
|
45244
|
+
*/
|
|
45245
|
+
calculateOverall(dimensions) {
|
|
45246
|
+
const weighted = dimensions.contractCoverage * this.options.coverageWeight + dimensions.verificationRate * this.options.verificationWeight + dimensions.stability * this.options.stabilityWeight + dimensions.contractQuality * this.options.qualityWeight + dimensions.errorHandling * this.options.errorHandlingWeight + dimensions.inputValidation * this.options.inputValidationWeight;
|
|
45247
|
+
return Math.round(Math.min(100, Math.max(0, weighted)));
|
|
45248
|
+
}
|
|
45249
|
+
/**
|
|
45250
|
+
* Create breakdown of factors
|
|
45251
|
+
*/
|
|
45252
|
+
createBreakdown(result, contracts) {
|
|
45253
|
+
const errorViolations = result.violations.filter((v) => v.severity === "error");
|
|
45254
|
+
const warningViolations = result.violations.filter((v) => v.severity === "warning");
|
|
45255
|
+
const highConfidence = contracts.filter((c) => c.metadata.source.confidence >= 0.9);
|
|
45256
|
+
const mediumConfidence = contracts.filter(
|
|
45257
|
+
(c) => c.metadata.source.confidence >= 0.7 && c.metadata.source.confidence < 0.9
|
|
45258
|
+
);
|
|
45259
|
+
const lowConfidence = contracts.filter((c) => c.metadata.source.confidence < 0.7);
|
|
45260
|
+
return {
|
|
45261
|
+
totalBehaviors: result.totalBehaviors,
|
|
45262
|
+
verifiedBehaviors: result.verifiedBehaviors,
|
|
45263
|
+
violations: {
|
|
45264
|
+
errors: errorViolations.length,
|
|
45265
|
+
warnings: warningViolations.length,
|
|
45266
|
+
total: result.violations.length
|
|
45267
|
+
},
|
|
45268
|
+
contracts: {
|
|
45269
|
+
total: contracts.length,
|
|
45270
|
+
highConfidence: highConfidence.length,
|
|
45271
|
+
mediumConfidence: mediumConfidence.length,
|
|
45272
|
+
lowConfidence: lowConfidence.length
|
|
45273
|
+
}
|
|
45274
|
+
};
|
|
45275
|
+
}
|
|
45276
|
+
/**
|
|
45277
|
+
* Get letter grade from score
|
|
45278
|
+
*/
|
|
45279
|
+
getGrade(score) {
|
|
45280
|
+
if (score >= 90) return "A";
|
|
45281
|
+
if (score >= 80) return "B";
|
|
45282
|
+
if (score >= 70) return "C";
|
|
45283
|
+
if (score >= 60) return "D";
|
|
45284
|
+
return "F";
|
|
45285
|
+
}
|
|
45286
|
+
/**
|
|
45287
|
+
* Get verdict from score
|
|
45288
|
+
*/
|
|
45289
|
+
getVerdict(score) {
|
|
45290
|
+
if (score >= this.options.trustThreshold) return "TRUSTED";
|
|
45291
|
+
if (score >= this.options.reviewThreshold) return "NEEDS_REVIEW";
|
|
45292
|
+
return "UNTRUSTED";
|
|
45293
|
+
}
|
|
45294
|
+
/**
|
|
45295
|
+
* Calculate a quick score from violations only (for firewall use)
|
|
45296
|
+
*/
|
|
45297
|
+
calculateFromViolations(violations) {
|
|
45298
|
+
if (violations.length === 0) return 100;
|
|
45299
|
+
const errorPenalty = violations.filter((v) => v.severity === "error").length * 15;
|
|
45300
|
+
const warningPenalty = violations.filter((v) => v.severity === "warning").length * 5;
|
|
45301
|
+
return Math.max(0, 100 - errorPenalty - warningPenalty);
|
|
45302
|
+
}
|
|
45303
|
+
/**
|
|
45304
|
+
* Update options
|
|
45305
|
+
*/
|
|
45306
|
+
setOptions(options) {
|
|
45307
|
+
this.options = { ...this.options, ...options };
|
|
45308
|
+
}
|
|
45309
|
+
};
|
|
44153
45310
|
BEHAVIOR_TEMPLATES = {
|
|
44154
45311
|
// Authentication patterns
|
|
44155
45312
|
login: {
|
|
@@ -44802,20 +45959,20 @@ domain ${params.domainName} version "${params.version}"
|
|
|
44802
45959
|
}
|
|
44803
45960
|
return this.currentIntent;
|
|
44804
45961
|
}
|
|
44805
|
-
isPathAllowed(
|
|
44806
|
-
return intent.allowedPaths.some((pattern) => this.matchPath(
|
|
45962
|
+
isPathAllowed(path62, intent) {
|
|
45963
|
+
return intent.allowedPaths.some((pattern) => this.matchPath(path62, pattern));
|
|
44807
45964
|
}
|
|
44808
|
-
isPathExcluded(
|
|
45965
|
+
isPathExcluded(path62, intent) {
|
|
44809
45966
|
if (!intent.excludedPaths) return false;
|
|
44810
|
-
return intent.excludedPaths.some((pattern) => this.matchPath(
|
|
45967
|
+
return intent.excludedPaths.some((pattern) => this.matchPath(path62, pattern));
|
|
44811
45968
|
}
|
|
44812
|
-
isInTargetFiles(
|
|
45969
|
+
isInTargetFiles(path62, targetFiles) {
|
|
44813
45970
|
return targetFiles.some(
|
|
44814
|
-
(target) =>
|
|
45971
|
+
(target) => path62 === target || path62.endsWith(target) || this.matchPath(path62, target)
|
|
44815
45972
|
);
|
|
44816
45973
|
}
|
|
44817
|
-
matchPath(
|
|
44818
|
-
const normalizedPath =
|
|
45974
|
+
matchPath(path62, pattern) {
|
|
45975
|
+
const normalizedPath = path62.replace(/\\/g, "/");
|
|
44819
45976
|
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
44820
45977
|
if (normalizedPath === normalizedPattern) return true;
|
|
44821
45978
|
if (normalizedPattern.includes("*")) {
|
|
@@ -45242,22 +46399,22 @@ domain ${params.domainName} version "${params.version}"
|
|
|
45242
46399
|
// ============================================================================
|
|
45243
46400
|
// Path Matching Utilities
|
|
45244
46401
|
// ============================================================================
|
|
45245
|
-
isPathInScope(
|
|
46402
|
+
isPathInScope(path62, scope) {
|
|
45246
46403
|
if (scope.targetFiles && scope.targetFiles.length > 0) {
|
|
45247
46404
|
return scope.targetFiles.some(
|
|
45248
|
-
(target) =>
|
|
46405
|
+
(target) => path62 === target || path62.endsWith(target) || this.matchGlob(path62, target)
|
|
45249
46406
|
);
|
|
45250
46407
|
}
|
|
45251
|
-
return scope.allowedPaths.some((pattern) => this.matchGlob(
|
|
46408
|
+
return scope.allowedPaths.some((pattern) => this.matchGlob(path62, pattern));
|
|
45252
46409
|
}
|
|
45253
|
-
isPathExcluded(
|
|
45254
|
-
return scope.excludedPaths.some((pattern) => this.matchGlob(
|
|
46410
|
+
isPathExcluded(path62, scope) {
|
|
46411
|
+
return scope.excludedPaths.some((pattern) => this.matchGlob(path62, pattern));
|
|
45255
46412
|
}
|
|
45256
|
-
matchesSensitivePattern(
|
|
45257
|
-
return policy.sensitivePatterns.some((pattern) => this.matchGlob(
|
|
46413
|
+
matchesSensitivePattern(path62, policy) {
|
|
46414
|
+
return policy.sensitivePatterns.some((pattern) => this.matchGlob(path62, pattern));
|
|
45258
46415
|
}
|
|
45259
|
-
matchGlob(
|
|
45260
|
-
const normalizedPath =
|
|
46416
|
+
matchGlob(path62, pattern) {
|
|
46417
|
+
const normalizedPath = path62.replace(/\\/g, "/");
|
|
45261
46418
|
const normalizedPattern = pattern.replace(/\\/g, "/");
|
|
45262
46419
|
if (normalizedPath === normalizedPattern) return true;
|
|
45263
46420
|
if (normalizedPattern.includes("*")) {
|
|
@@ -45341,6 +46498,15 @@ domain ${params.domainName} version "${params.version}"
|
|
|
45341
46498
|
"contract-drift"
|
|
45342
46499
|
// Contract violation
|
|
45343
46500
|
];
|
|
46501
|
+
TIER_C_RULES = [
|
|
46502
|
+
"missing-error-handling",
|
|
46503
|
+
"rate-limiting-suggestion",
|
|
46504
|
+
"validation-suggestion",
|
|
46505
|
+
"low-confidence",
|
|
46506
|
+
"excessive-claims",
|
|
46507
|
+
"scope-explosion",
|
|
46508
|
+
"unsafe-side-effect"
|
|
46509
|
+
];
|
|
45344
46510
|
BaseRule = class {
|
|
45345
46511
|
config;
|
|
45346
46512
|
constructor(config = {}) {
|
|
@@ -45504,20 +46670,20 @@ domain ${params.domainName} version "${params.version}"
|
|
|
45504
46670
|
suggestion
|
|
45505
46671
|
);
|
|
45506
46672
|
}
|
|
45507
|
-
isExternalPath(
|
|
46673
|
+
isExternalPath(path62) {
|
|
45508
46674
|
if (!this.config.allowedExternalPaths) return false;
|
|
45509
46675
|
return this.config.allowedExternalPaths.some(
|
|
45510
|
-
(pattern) => this.matchPattern(
|
|
46676
|
+
(pattern) => this.matchPattern(path62, pattern)
|
|
45511
46677
|
);
|
|
45512
46678
|
}
|
|
45513
46679
|
/**
|
|
45514
46680
|
* Normalize path by removing query strings and fragments
|
|
45515
46681
|
*/
|
|
45516
|
-
normalizePath(
|
|
45517
|
-
return
|
|
46682
|
+
normalizePath(path62) {
|
|
46683
|
+
return path62.split("?")[0].split("#")[0];
|
|
45518
46684
|
}
|
|
45519
|
-
isApiPath(
|
|
45520
|
-
const normalized = this.normalizePath(
|
|
46685
|
+
isApiPath(path62) {
|
|
46686
|
+
const normalized = this.normalizePath(path62);
|
|
45521
46687
|
if (!this.config.apiPrefixes || this.config.apiPrefixes.length === 0) {
|
|
45522
46688
|
return normalized.startsWith("/");
|
|
45523
46689
|
}
|
|
@@ -45546,8 +46712,8 @@ domain ${params.domainName} version "${params.version}"
|
|
|
45546
46712
|
}
|
|
45547
46713
|
return similar.slice(0, 3);
|
|
45548
46714
|
}
|
|
45549
|
-
generateSuggestion(
|
|
45550
|
-
const normalized = this.normalizePath(
|
|
46715
|
+
generateSuggestion(path62, context) {
|
|
46716
|
+
const normalized = this.normalizePath(path62);
|
|
45551
46717
|
if (context) {
|
|
45552
46718
|
const similar = this.findSimilarRoutes(normalized, context);
|
|
45553
46719
|
if (similar.length > 0) {
|
|
@@ -46294,6 +47460,492 @@ domain ${params.domainName} version "${params.version}"
|
|
|
46294
47460
|
return "Review this code for potential security issues";
|
|
46295
47461
|
}
|
|
46296
47462
|
};
|
|
47463
|
+
ObserveModeManager = class _ObserveModeManager {
|
|
47464
|
+
state;
|
|
47465
|
+
onComplete;
|
|
47466
|
+
constructor(options = {}) {
|
|
47467
|
+
this.state = {
|
|
47468
|
+
startTime: Date.now(),
|
|
47469
|
+
saveCount: 0,
|
|
47470
|
+
observeDuration: options.observeDuration ?? 120,
|
|
47471
|
+
observeSaveCount: options.observeSaveCount ?? 20,
|
|
47472
|
+
isActive: true,
|
|
47473
|
+
detectedPatterns: /* @__PURE__ */ new Map(),
|
|
47474
|
+
observedViolations: [],
|
|
47475
|
+
suggestedAllows: []
|
|
47476
|
+
};
|
|
47477
|
+
this.onComplete = options.onComplete;
|
|
47478
|
+
}
|
|
47479
|
+
/**
|
|
47480
|
+
* Check if observe mode is still active
|
|
47481
|
+
*/
|
|
47482
|
+
isObserving() {
|
|
47483
|
+
if (!this.state.isActive) return false;
|
|
47484
|
+
const elapsedSeconds = (Date.now() - this.state.startTime) / 1e3;
|
|
47485
|
+
const timeExpired = elapsedSeconds >= this.state.observeDuration;
|
|
47486
|
+
const savesReached = this.state.saveCount >= this.state.observeSaveCount;
|
|
47487
|
+
if (timeExpired || savesReached) {
|
|
47488
|
+
this.complete();
|
|
47489
|
+
return false;
|
|
47490
|
+
}
|
|
47491
|
+
return true;
|
|
47492
|
+
}
|
|
47493
|
+
/**
|
|
47494
|
+
* Get the remaining time/saves before observe mode ends
|
|
47495
|
+
*/
|
|
47496
|
+
getProgress() {
|
|
47497
|
+
const elapsedSeconds = (Date.now() - this.state.startTime) / 1e3;
|
|
47498
|
+
const timeProgress = elapsedSeconds / this.state.observeDuration;
|
|
47499
|
+
const saveProgress = this.state.saveCount / this.state.observeSaveCount;
|
|
47500
|
+
const progressPercent = Math.max(timeProgress, saveProgress) * 100;
|
|
47501
|
+
return {
|
|
47502
|
+
elapsedSeconds: Math.round(elapsedSeconds),
|
|
47503
|
+
remainingSeconds: Math.max(0, this.state.observeDuration - elapsedSeconds),
|
|
47504
|
+
saveCount: this.state.saveCount,
|
|
47505
|
+
remainingSaves: Math.max(0, this.state.observeSaveCount - this.state.saveCount),
|
|
47506
|
+
progressPercent: Math.min(100, Math.round(progressPercent))
|
|
47507
|
+
};
|
|
47508
|
+
}
|
|
47509
|
+
/**
|
|
47510
|
+
* Record a save event during observation
|
|
47511
|
+
*/
|
|
47512
|
+
recordSave(filePath) {
|
|
47513
|
+
if (!this.state.isActive) return;
|
|
47514
|
+
this.state.saveCount++;
|
|
47515
|
+
this.detectFilePatterns(filePath);
|
|
47516
|
+
this.isObserving();
|
|
47517
|
+
}
|
|
47518
|
+
/**
|
|
47519
|
+
* Record a violation that was observed (not blocked) during learning
|
|
47520
|
+
*/
|
|
47521
|
+
recordViolation(violation) {
|
|
47522
|
+
if (!this.state.isActive) return;
|
|
47523
|
+
this.state.observedViolations.push(violation);
|
|
47524
|
+
this.analyzeViolationForPatterns(violation);
|
|
47525
|
+
}
|
|
47526
|
+
/**
|
|
47527
|
+
* Record a code pattern observed during a save
|
|
47528
|
+
*/
|
|
47529
|
+
recordPattern(type, pattern, filePath, regex) {
|
|
47530
|
+
if (!this.state.isActive) return;
|
|
47531
|
+
const key = `${type}:${pattern}`;
|
|
47532
|
+
const existing = this.state.detectedPatterns.get(key);
|
|
47533
|
+
if (existing) {
|
|
47534
|
+
existing.count++;
|
|
47535
|
+
existing.lastSeen = Date.now();
|
|
47536
|
+
if (!existing.files.includes(filePath)) {
|
|
47537
|
+
existing.files.push(filePath);
|
|
47538
|
+
}
|
|
47539
|
+
if (existing.count >= 3) {
|
|
47540
|
+
existing.suggestedAllow = true;
|
|
47541
|
+
}
|
|
47542
|
+
} else {
|
|
47543
|
+
this.state.detectedPatterns.set(key, {
|
|
47544
|
+
type,
|
|
47545
|
+
pattern,
|
|
47546
|
+
regex,
|
|
47547
|
+
count: 1,
|
|
47548
|
+
firstSeen: Date.now(),
|
|
47549
|
+
lastSeen: Date.now(),
|
|
47550
|
+
files: [filePath],
|
|
47551
|
+
suggestedAllow: false
|
|
47552
|
+
});
|
|
47553
|
+
}
|
|
47554
|
+
}
|
|
47555
|
+
/**
|
|
47556
|
+
* Get current suggested allows based on observations
|
|
47557
|
+
*/
|
|
47558
|
+
getSuggestedAllows() {
|
|
47559
|
+
return this.state.suggestedAllows;
|
|
47560
|
+
}
|
|
47561
|
+
/**
|
|
47562
|
+
* Get observed violations (would have blocked but didn't)
|
|
47563
|
+
*/
|
|
47564
|
+
getObservedViolations() {
|
|
47565
|
+
return this.state.observedViolations;
|
|
47566
|
+
}
|
|
47567
|
+
/**
|
|
47568
|
+
* Complete observe mode and generate final suggestions
|
|
47569
|
+
*/
|
|
47570
|
+
complete() {
|
|
47571
|
+
if (!this.state.isActive) return;
|
|
47572
|
+
this.state.isActive = false;
|
|
47573
|
+
this.generateSuggestedAllows();
|
|
47574
|
+
if (this.onComplete) {
|
|
47575
|
+
this.onComplete(this.state.suggestedAllows);
|
|
47576
|
+
}
|
|
47577
|
+
}
|
|
47578
|
+
/**
|
|
47579
|
+
* Detect patterns from file paths
|
|
47580
|
+
*/
|
|
47581
|
+
detectFilePatterns(filePath) {
|
|
47582
|
+
if (filePath.includes(".gen.") || filePath.includes("generated/")) {
|
|
47583
|
+
this.recordPattern("generated_file", filePath.replace(/[^/]+$/, "*"), filePath);
|
|
47584
|
+
}
|
|
47585
|
+
const aliasMatch = filePath.match(/^@([^/]+)/);
|
|
47586
|
+
if (aliasMatch) {
|
|
47587
|
+
this.recordPattern("path_alias", `@${aliasMatch[1]}/*`, filePath);
|
|
47588
|
+
}
|
|
47589
|
+
}
|
|
47590
|
+
/**
|
|
47591
|
+
* Analyze violations for learnable patterns
|
|
47592
|
+
*/
|
|
47593
|
+
analyzeViolationForPatterns(violation) {
|
|
47594
|
+
const evidence = violation.evidence;
|
|
47595
|
+
if (violation.rule === "ghost-route" && evidence.includes("${")) {
|
|
47596
|
+
const dynamicMatch = evidence.match(/\/api\/[^/]*\$\{[^}]+\}/);
|
|
47597
|
+
if (dynamicMatch) {
|
|
47598
|
+
this.recordPattern(
|
|
47599
|
+
"dynamic_route",
|
|
47600
|
+
dynamicMatch[0],
|
|
47601
|
+
violation.filePath ?? "",
|
|
47602
|
+
"^/api/[a-z]+/\\${[^}]+}$"
|
|
47603
|
+
);
|
|
47604
|
+
}
|
|
47605
|
+
}
|
|
47606
|
+
if (violation.rule === "ghost-route") {
|
|
47607
|
+
const wrapperMatch = evidence.match(/(api|client|fetch|axios)\.[a-z]+\s*\(['"]([^'"]+)/i);
|
|
47608
|
+
if (wrapperMatch) {
|
|
47609
|
+
this.recordPattern(
|
|
47610
|
+
"api_wrapper",
|
|
47611
|
+
wrapperMatch[2],
|
|
47612
|
+
violation.filePath ?? ""
|
|
47613
|
+
);
|
|
47614
|
+
}
|
|
47615
|
+
}
|
|
47616
|
+
if (violation.rule === "ghost-env") {
|
|
47617
|
+
const envMatch = evidence.match(/([A-Z]+_)/);
|
|
47618
|
+
if (envMatch) {
|
|
47619
|
+
const prefix = envMatch[1];
|
|
47620
|
+
if (prefix.length <= 10) {
|
|
47621
|
+
this.recordPattern(
|
|
47622
|
+
"env_prefix",
|
|
47623
|
+
`${prefix}*`,
|
|
47624
|
+
violation.filePath ?? "",
|
|
47625
|
+
`^${prefix}[A-Z_]+$`
|
|
47626
|
+
);
|
|
47627
|
+
}
|
|
47628
|
+
}
|
|
47629
|
+
}
|
|
47630
|
+
}
|
|
47631
|
+
/**
|
|
47632
|
+
* Generate final suggested allows from detected patterns
|
|
47633
|
+
*/
|
|
47634
|
+
generateSuggestedAllows() {
|
|
47635
|
+
const allows = [];
|
|
47636
|
+
for (const [, pattern] of this.state.detectedPatterns) {
|
|
47637
|
+
if (!pattern.suggestedAllow && pattern.count < 2) continue;
|
|
47638
|
+
let type;
|
|
47639
|
+
switch (pattern.type) {
|
|
47640
|
+
case "dynamic_route":
|
|
47641
|
+
type = "dynamic_route";
|
|
47642
|
+
break;
|
|
47643
|
+
case "api_wrapper":
|
|
47644
|
+
case "framework_pattern":
|
|
47645
|
+
type = "route_prefix";
|
|
47646
|
+
break;
|
|
47647
|
+
case "env_prefix":
|
|
47648
|
+
type = "env_var";
|
|
47649
|
+
break;
|
|
47650
|
+
case "generated_file":
|
|
47651
|
+
case "path_alias":
|
|
47652
|
+
type = "ignored_path";
|
|
47653
|
+
break;
|
|
47654
|
+
default:
|
|
47655
|
+
continue;
|
|
47656
|
+
}
|
|
47657
|
+
allows.push({
|
|
47658
|
+
type,
|
|
47659
|
+
pattern: pattern.pattern,
|
|
47660
|
+
regex: pattern.regex,
|
|
47661
|
+
confidence: Math.min(1, pattern.count / 5),
|
|
47662
|
+
reason: `Seen ${pattern.count} times in ${pattern.files.length} files`,
|
|
47663
|
+
seenCount: pattern.count
|
|
47664
|
+
});
|
|
47665
|
+
}
|
|
47666
|
+
allows.sort((a, b) => b.confidence - a.confidence);
|
|
47667
|
+
this.state.suggestedAllows = allows;
|
|
47668
|
+
}
|
|
47669
|
+
/**
|
|
47670
|
+
* Force complete observe mode early
|
|
47671
|
+
*/
|
|
47672
|
+
forceComplete() {
|
|
47673
|
+
this.complete();
|
|
47674
|
+
return this.state.suggestedAllows;
|
|
47675
|
+
}
|
|
47676
|
+
/**
|
|
47677
|
+
* Reset observe mode to start fresh
|
|
47678
|
+
*/
|
|
47679
|
+
reset() {
|
|
47680
|
+
this.state = {
|
|
47681
|
+
startTime: Date.now(),
|
|
47682
|
+
saveCount: 0,
|
|
47683
|
+
observeDuration: this.state.observeDuration,
|
|
47684
|
+
observeSaveCount: this.state.observeSaveCount,
|
|
47685
|
+
isActive: true,
|
|
47686
|
+
detectedPatterns: /* @__PURE__ */ new Map(),
|
|
47687
|
+
observedViolations: [],
|
|
47688
|
+
suggestedAllows: []
|
|
47689
|
+
};
|
|
47690
|
+
}
|
|
47691
|
+
/**
|
|
47692
|
+
* Serialize state for persistence
|
|
47693
|
+
*/
|
|
47694
|
+
toJSON() {
|
|
47695
|
+
return {
|
|
47696
|
+
startTime: this.state.startTime,
|
|
47697
|
+
saveCount: this.state.saveCount,
|
|
47698
|
+
observeDuration: this.state.observeDuration,
|
|
47699
|
+
observeSaveCount: this.state.observeSaveCount,
|
|
47700
|
+
isActive: this.state.isActive,
|
|
47701
|
+
detectedPatterns: Array.from(this.state.detectedPatterns.entries()),
|
|
47702
|
+
observedViolations: this.state.observedViolations,
|
|
47703
|
+
suggestedAllows: this.state.suggestedAllows
|
|
47704
|
+
};
|
|
47705
|
+
}
|
|
47706
|
+
/**
|
|
47707
|
+
* Restore state from persisted data
|
|
47708
|
+
*/
|
|
47709
|
+
static fromJSON(data) {
|
|
47710
|
+
const manager = new _ObserveModeManager({
|
|
47711
|
+
observeDuration: data.observeDuration,
|
|
47712
|
+
observeSaveCount: data.observeSaveCount
|
|
47713
|
+
});
|
|
47714
|
+
manager.state.startTime = data.startTime;
|
|
47715
|
+
manager.state.saveCount = data.saveCount;
|
|
47716
|
+
manager.state.isActive = data.isActive;
|
|
47717
|
+
manager.state.observedViolations = data.observedViolations;
|
|
47718
|
+
manager.state.suggestedAllows = data.suggestedAllows;
|
|
47719
|
+
if (Array.isArray(data.detectedPatterns)) {
|
|
47720
|
+
manager.state.detectedPatterns = new Map(data.detectedPatterns);
|
|
47721
|
+
}
|
|
47722
|
+
return manager;
|
|
47723
|
+
}
|
|
47724
|
+
};
|
|
47725
|
+
DEFAULT_ALLOWLIST = {
|
|
47726
|
+
allowedRoutePrefixes: [],
|
|
47727
|
+
allowedDynamicRoutes: [],
|
|
47728
|
+
ignoredPaths: [
|
|
47729
|
+
"**/node_modules/**",
|
|
47730
|
+
"**/.git/**",
|
|
47731
|
+
"**/dist/**",
|
|
47732
|
+
"**/build/**",
|
|
47733
|
+
"**/*.gen.ts",
|
|
47734
|
+
"**/*.generated.*"
|
|
47735
|
+
],
|
|
47736
|
+
allowedEnvVars: []
|
|
47737
|
+
};
|
|
47738
|
+
ALLOWLIST_FILENAME = "firewall.allow.json";
|
|
47739
|
+
AllowlistManager = class {
|
|
47740
|
+
allowlist;
|
|
47741
|
+
projectRoot;
|
|
47742
|
+
loaded = false;
|
|
47743
|
+
constructor(projectRoot) {
|
|
47744
|
+
this.projectRoot = projectRoot;
|
|
47745
|
+
this.allowlist = { ...DEFAULT_ALLOWLIST };
|
|
47746
|
+
}
|
|
47747
|
+
/**
|
|
47748
|
+
* Get the path to the allowlist file
|
|
47749
|
+
*/
|
|
47750
|
+
get filePath() {
|
|
47751
|
+
return path18.join(this.projectRoot, ".vibecheck", ALLOWLIST_FILENAME);
|
|
47752
|
+
}
|
|
47753
|
+
/**
|
|
47754
|
+
* Load the allowlist from disk
|
|
47755
|
+
*/
|
|
47756
|
+
async load() {
|
|
47757
|
+
try {
|
|
47758
|
+
const content = await fs102.readFile(this.filePath, "utf-8");
|
|
47759
|
+
const parsed = JSON.parse(content);
|
|
47760
|
+
this.allowlist = {
|
|
47761
|
+
allowedRoutePrefixes: parsed.allowedRoutePrefixes ?? [],
|
|
47762
|
+
allowedDynamicRoutes: parsed.allowedDynamicRoutes ?? [],
|
|
47763
|
+
ignoredPaths: parsed.ignoredPaths ?? DEFAULT_ALLOWLIST.ignoredPaths,
|
|
47764
|
+
allowedEnvVars: parsed.allowedEnvVars ?? [],
|
|
47765
|
+
_autoGenerated: parsed._autoGenerated
|
|
47766
|
+
};
|
|
47767
|
+
this.loaded = true;
|
|
47768
|
+
} catch {
|
|
47769
|
+
this.allowlist = { ...DEFAULT_ALLOWLIST };
|
|
47770
|
+
this.loaded = true;
|
|
47771
|
+
}
|
|
47772
|
+
return this.allowlist;
|
|
47773
|
+
}
|
|
47774
|
+
/**
|
|
47775
|
+
* Save the allowlist to disk
|
|
47776
|
+
*/
|
|
47777
|
+
async save() {
|
|
47778
|
+
const dir = path18.dirname(this.filePath);
|
|
47779
|
+
try {
|
|
47780
|
+
await fs102.mkdir(dir, { recursive: true });
|
|
47781
|
+
} catch {
|
|
47782
|
+
}
|
|
47783
|
+
const content = JSON.stringify(this.allowlist, null, 2);
|
|
47784
|
+
await fs102.writeFile(this.filePath, content, "utf-8");
|
|
47785
|
+
}
|
|
47786
|
+
/**
|
|
47787
|
+
* Get the current allowlist
|
|
47788
|
+
*/
|
|
47789
|
+
get() {
|
|
47790
|
+
return this.allowlist;
|
|
47791
|
+
}
|
|
47792
|
+
/**
|
|
47793
|
+
* Check if a route is allowed
|
|
47794
|
+
*/
|
|
47795
|
+
isRouteAllowed(routePath) {
|
|
47796
|
+
for (const prefix of this.allowlist.allowedRoutePrefixes) {
|
|
47797
|
+
if (routePath.startsWith(prefix)) {
|
|
47798
|
+
return true;
|
|
47799
|
+
}
|
|
47800
|
+
}
|
|
47801
|
+
for (const pattern of this.allowlist.allowedDynamicRoutes) {
|
|
47802
|
+
try {
|
|
47803
|
+
const regex = new RegExp(pattern);
|
|
47804
|
+
if (regex.test(routePath)) {
|
|
47805
|
+
return true;
|
|
47806
|
+
}
|
|
47807
|
+
} catch {
|
|
47808
|
+
}
|
|
47809
|
+
}
|
|
47810
|
+
return false;
|
|
47811
|
+
}
|
|
47812
|
+
/**
|
|
47813
|
+
* Check if a file path should be ignored
|
|
47814
|
+
*/
|
|
47815
|
+
isPathIgnored(filePath) {
|
|
47816
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
47817
|
+
for (const pattern of this.allowlist.ignoredPaths) {
|
|
47818
|
+
if (this.matchGlob(normalized, pattern)) {
|
|
47819
|
+
return true;
|
|
47820
|
+
}
|
|
47821
|
+
}
|
|
47822
|
+
return false;
|
|
47823
|
+
}
|
|
47824
|
+
/**
|
|
47825
|
+
* Check if an env var is allowed
|
|
47826
|
+
*/
|
|
47827
|
+
isEnvVarAllowed(varName) {
|
|
47828
|
+
for (const allowed of this.allowlist.allowedEnvVars) {
|
|
47829
|
+
if (allowed.endsWith("*")) {
|
|
47830
|
+
const prefix = allowed.slice(0, -1);
|
|
47831
|
+
if (varName.startsWith(prefix)) {
|
|
47832
|
+
return true;
|
|
47833
|
+
}
|
|
47834
|
+
} else if (varName === allowed) {
|
|
47835
|
+
return true;
|
|
47836
|
+
}
|
|
47837
|
+
}
|
|
47838
|
+
return false;
|
|
47839
|
+
}
|
|
47840
|
+
/**
|
|
47841
|
+
* Add a route prefix to the allowlist
|
|
47842
|
+
*/
|
|
47843
|
+
async addRoutePrefix(prefix) {
|
|
47844
|
+
if (!this.allowlist.allowedRoutePrefixes.includes(prefix)) {
|
|
47845
|
+
this.allowlist.allowedRoutePrefixes.push(prefix);
|
|
47846
|
+
await this.save();
|
|
47847
|
+
}
|
|
47848
|
+
}
|
|
47849
|
+
/**
|
|
47850
|
+
* Add a dynamic route pattern to the allowlist
|
|
47851
|
+
*/
|
|
47852
|
+
async addDynamicRoute(pattern) {
|
|
47853
|
+
try {
|
|
47854
|
+
new RegExp(pattern);
|
|
47855
|
+
} catch {
|
|
47856
|
+
throw new Error(`Invalid regex pattern: ${pattern}`);
|
|
47857
|
+
}
|
|
47858
|
+
if (!this.allowlist.allowedDynamicRoutes.includes(pattern)) {
|
|
47859
|
+
this.allowlist.allowedDynamicRoutes.push(pattern);
|
|
47860
|
+
await this.save();
|
|
47861
|
+
}
|
|
47862
|
+
}
|
|
47863
|
+
/**
|
|
47864
|
+
* Add an ignored path pattern
|
|
47865
|
+
*/
|
|
47866
|
+
async addIgnoredPath(pattern) {
|
|
47867
|
+
if (!this.allowlist.ignoredPaths.includes(pattern)) {
|
|
47868
|
+
this.allowlist.ignoredPaths.push(pattern);
|
|
47869
|
+
await this.save();
|
|
47870
|
+
}
|
|
47871
|
+
}
|
|
47872
|
+
/**
|
|
47873
|
+
* Add an allowed env var
|
|
47874
|
+
*/
|
|
47875
|
+
async addEnvVar(varName) {
|
|
47876
|
+
if (!this.allowlist.allowedEnvVars.includes(varName)) {
|
|
47877
|
+
this.allowlist.allowedEnvVars.push(varName);
|
|
47878
|
+
await this.save();
|
|
47879
|
+
}
|
|
47880
|
+
}
|
|
47881
|
+
/**
|
|
47882
|
+
* Remove a route prefix from the allowlist
|
|
47883
|
+
*/
|
|
47884
|
+
async removeRoutePrefix(prefix) {
|
|
47885
|
+
const index = this.allowlist.allowedRoutePrefixes.indexOf(prefix);
|
|
47886
|
+
if (index !== -1) {
|
|
47887
|
+
this.allowlist.allowedRoutePrefixes.splice(index, 1);
|
|
47888
|
+
await this.save();
|
|
47889
|
+
}
|
|
47890
|
+
}
|
|
47891
|
+
/**
|
|
47892
|
+
* Add entries from observe mode suggestions
|
|
47893
|
+
*/
|
|
47894
|
+
async addFromObserveMode(suggestions) {
|
|
47895
|
+
for (const suggestion of suggestions) {
|
|
47896
|
+
switch (suggestion.type) {
|
|
47897
|
+
case "route_prefix":
|
|
47898
|
+
if (!this.allowlist.allowedRoutePrefixes.includes(suggestion.pattern)) {
|
|
47899
|
+
this.allowlist.allowedRoutePrefixes.push(suggestion.pattern);
|
|
47900
|
+
}
|
|
47901
|
+
break;
|
|
47902
|
+
case "dynamic_route":
|
|
47903
|
+
if (!this.allowlist.allowedDynamicRoutes.includes(suggestion.pattern)) {
|
|
47904
|
+
this.allowlist.allowedDynamicRoutes.push(suggestion.pattern);
|
|
47905
|
+
}
|
|
47906
|
+
break;
|
|
47907
|
+
case "env_var":
|
|
47908
|
+
if (!this.allowlist.allowedEnvVars.includes(suggestion.pattern)) {
|
|
47909
|
+
this.allowlist.allowedEnvVars.push(suggestion.pattern);
|
|
47910
|
+
}
|
|
47911
|
+
break;
|
|
47912
|
+
case "ignored_path":
|
|
47913
|
+
if (!this.allowlist.ignoredPaths.includes(suggestion.pattern)) {
|
|
47914
|
+
this.allowlist.ignoredPaths.push(suggestion.pattern);
|
|
47915
|
+
}
|
|
47916
|
+
break;
|
|
47917
|
+
}
|
|
47918
|
+
}
|
|
47919
|
+
this.allowlist._autoGenerated = {
|
|
47920
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
47921
|
+
entries: suggestions.map((s) => ({
|
|
47922
|
+
type: s.type,
|
|
47923
|
+
pattern: s.pattern,
|
|
47924
|
+
reason: s.reason
|
|
47925
|
+
}))
|
|
47926
|
+
};
|
|
47927
|
+
await this.save();
|
|
47928
|
+
}
|
|
47929
|
+
/**
|
|
47930
|
+
* Clear auto-generated entries after user review
|
|
47931
|
+
*/
|
|
47932
|
+
async clearAutoGenerated() {
|
|
47933
|
+
delete this.allowlist._autoGenerated;
|
|
47934
|
+
await this.save();
|
|
47935
|
+
}
|
|
47936
|
+
/**
|
|
47937
|
+
* Simple glob matching (supports ** and *)
|
|
47938
|
+
*/
|
|
47939
|
+
matchGlob(path62, pattern) {
|
|
47940
|
+
let regexStr = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "{{DOUBLE_STAR}}").replace(/\*/g, "[^/]*").replace(/{{DOUBLE_STAR}}/g, ".*");
|
|
47941
|
+
regexStr = `^${regexStr}$`;
|
|
47942
|
+
try {
|
|
47943
|
+
return new RegExp(regexStr).test(path62);
|
|
47944
|
+
} catch {
|
|
47945
|
+
return false;
|
|
47946
|
+
}
|
|
47947
|
+
}
|
|
47948
|
+
};
|
|
46297
47949
|
}
|
|
46298
47950
|
});
|
|
46299
47951
|
function createQuickChain(claim, verified, source, details) {
|
|
@@ -46559,6 +48211,121 @@ async function resetVerificationEngine() {
|
|
|
46559
48211
|
globalEngine = null;
|
|
46560
48212
|
}
|
|
46561
48213
|
}
|
|
48214
|
+
function sanitizeCode(code) {
|
|
48215
|
+
let sanitized = code;
|
|
48216
|
+
sanitized = sanitized.replace(/\beval\s*\(/g, '(function(){throw new Error("Security violation: eval removed")})(');
|
|
48217
|
+
sanitized = sanitized.replace(/new\s+Function\s*\(/g, "/* REMOVED: Function constructor */ undefined(");
|
|
48218
|
+
const secretPatterns = [
|
|
48219
|
+
/(?:api[_-]?key|apikey)\s*[:=]\s*["'`]([A-Za-z0-9_\-]{20,})["'`]/gi,
|
|
48220
|
+
/(?:secret|password|passwd|pwd)\s*[:=]\s*["'`]([^"'`]{8,})["'`]/gi,
|
|
48221
|
+
/(?:token)\s*[:=]\s*["'`]([A-Za-z0-9_\-\.]{20,})["'`]/gi
|
|
48222
|
+
];
|
|
48223
|
+
for (const pattern of secretPatterns) {
|
|
48224
|
+
sanitized = sanitized.replace(pattern, (match) => {
|
|
48225
|
+
if (match.includes("process.env") || match.includes("import.meta.env")) {
|
|
48226
|
+
return match;
|
|
48227
|
+
}
|
|
48228
|
+
if (match.toLowerCase().includes("example") || match.toLowerCase().includes("placeholder")) {
|
|
48229
|
+
return match;
|
|
48230
|
+
}
|
|
48231
|
+
const keyMatch = match.match(/^([a-z_]+)\s*[:=]/i);
|
|
48232
|
+
const envKey = keyMatch ? keyMatch[1].toUpperCase().replace(/[^A-Z0-9]/g, "_") : "SECRET";
|
|
48233
|
+
return `${keyMatch ? keyMatch[1] + " = " : ""}process.env.${envKey}`;
|
|
48234
|
+
});
|
|
48235
|
+
}
|
|
48236
|
+
sanitized = sanitized.replace(/from\s+["'`]https?:\/\/[^"'`]+["'`]/g, 'from "/* REMOVED: HTTP import */"');
|
|
48237
|
+
return sanitized;
|
|
48238
|
+
}
|
|
48239
|
+
async function validateAndSanitizeFiles(files, config) {
|
|
48240
|
+
const validator = await getCodeValidator(config);
|
|
48241
|
+
const validFiles = [];
|
|
48242
|
+
const errors = [];
|
|
48243
|
+
const warnings = [];
|
|
48244
|
+
for (const file2 of files) {
|
|
48245
|
+
if (file2.path.includes("..") || file2.path.startsWith("/")) {
|
|
48246
|
+
errors.push({
|
|
48247
|
+
filePath: file2.path,
|
|
48248
|
+
type: "invalid_path",
|
|
48249
|
+
message: "Path traversal or absolute path detected"
|
|
48250
|
+
});
|
|
48251
|
+
continue;
|
|
48252
|
+
}
|
|
48253
|
+
const validExtensions = /\.(ts|tsx|js|jsx|json|md|sql|yaml|yml|css|scss|html|txt|sh|env)$/i;
|
|
48254
|
+
if (!validExtensions.test(file2.path) && !file2.path.toLowerCase().includes("dockerfile")) {
|
|
48255
|
+
errors.push({
|
|
48256
|
+
filePath: file2.path,
|
|
48257
|
+
type: "invalid_path",
|
|
48258
|
+
message: `Invalid file extension: ${file2.path}`
|
|
48259
|
+
});
|
|
48260
|
+
continue;
|
|
48261
|
+
}
|
|
48262
|
+
if (["typescript", "javascript"].includes(file2.language) || /\.(ts|tsx|js|jsx)$/i.test(file2.path)) {
|
|
48263
|
+
const result = await validator.validate(file2.content, file2.path);
|
|
48264
|
+
for (const error of result.errors) {
|
|
48265
|
+
errors.push({
|
|
48266
|
+
filePath: file2.path,
|
|
48267
|
+
type: error.type,
|
|
48268
|
+
message: error.message
|
|
48269
|
+
});
|
|
48270
|
+
}
|
|
48271
|
+
for (const warning of result.warnings) {
|
|
48272
|
+
warnings.push({
|
|
48273
|
+
filePath: file2.path,
|
|
48274
|
+
message: warning.message
|
|
48275
|
+
});
|
|
48276
|
+
}
|
|
48277
|
+
const hasSecurityIssues = result.warnings.some((w) => w.type === "security");
|
|
48278
|
+
const hasCriticalErrors = result.errors.some((e) => e.severity === "critical");
|
|
48279
|
+
if (hasSecurityIssues || hasCriticalErrors) {
|
|
48280
|
+
const sanitizedContent = sanitizeCode(file2.content);
|
|
48281
|
+
validFiles.push({
|
|
48282
|
+
...file2,
|
|
48283
|
+
content: sanitizedContent,
|
|
48284
|
+
description: `${file2.description} (sanitized)`
|
|
48285
|
+
});
|
|
48286
|
+
} else {
|
|
48287
|
+
validFiles.push(file2);
|
|
48288
|
+
}
|
|
48289
|
+
} else {
|
|
48290
|
+
validFiles.push(file2);
|
|
48291
|
+
}
|
|
48292
|
+
}
|
|
48293
|
+
const issueCount = errors.length + warnings.length;
|
|
48294
|
+
let qualityScore = 100 - issueCount * 5;
|
|
48295
|
+
qualityScore = Math.max(0, Math.min(100, qualityScore));
|
|
48296
|
+
const criticalErrors = errors.filter(
|
|
48297
|
+
(e) => e.type === "security" || e.type === "syntax" || e.type === "invalid_path"
|
|
48298
|
+
);
|
|
48299
|
+
const isProductionReady = criticalErrors.length === 0 && validFiles.length > 0;
|
|
48300
|
+
return {
|
|
48301
|
+
validFiles,
|
|
48302
|
+
errors,
|
|
48303
|
+
warnings,
|
|
48304
|
+
qualityScore,
|
|
48305
|
+
isProductionReady
|
|
48306
|
+
};
|
|
48307
|
+
}
|
|
48308
|
+
async function calculateShipScore2(files, config) {
|
|
48309
|
+
const result = await validateAndSanitizeFiles(files, config);
|
|
48310
|
+
const issues = [
|
|
48311
|
+
...result.errors.map((e) => `[ERROR] ${e.filePath}: ${e.message}`),
|
|
48312
|
+
...result.warnings.map((w) => `[WARN] ${w.filePath}: ${w.message}`)
|
|
48313
|
+
];
|
|
48314
|
+
let verdict;
|
|
48315
|
+
if (result.qualityScore >= 80 && result.isProductionReady) {
|
|
48316
|
+
verdict = "SHIP";
|
|
48317
|
+
} else if (result.qualityScore >= 60) {
|
|
48318
|
+
verdict = "WARN";
|
|
48319
|
+
} else {
|
|
48320
|
+
verdict = "BLOCK";
|
|
48321
|
+
}
|
|
48322
|
+
return {
|
|
48323
|
+
score: result.qualityScore,
|
|
48324
|
+
verdict,
|
|
48325
|
+
issues,
|
|
48326
|
+
isProductionReady: result.isProductionReady
|
|
48327
|
+
};
|
|
48328
|
+
}
|
|
46562
48329
|
async function getCodeValidator(config) {
|
|
46563
48330
|
if (!globalValidator) {
|
|
46564
48331
|
globalValidator = new CodeValidator(config);
|
|
@@ -46573,8 +48340,8 @@ function getDriftDetector(config) {
|
|
|
46573
48340
|
return globalDetector;
|
|
46574
48341
|
}
|
|
46575
48342
|
var DEFAULT_CONFIG11, BUILTIN_TYPES, WELLKNOWN_ENV, HallucinationDetector, SOURCE_RELIABILITY, DEFAULT_VERIFIER_CONFIG, DEFAULT_CALIBRATION_CONFIG, DEFAULT_CONFIG26, EvidenceChainBuilder, truthpackCache, truthpackVerifier, BUILTIN_MODULES2, packageJsonCache, packageJsonVerifier, filesystemVerifier, astVerifier, gitVerifier, typescriptVerifier, runtimeVerifier, ALL_VERIFIERS, DEFAULT_CONFIG35, ConfidenceCalibrator, globalCalibrator, DEFAULT_CONFIG45, VerificationEngine, globalEngine, DEFAULT_CONFIG55, MultiSourceVerifier, DEFAULT_CONFIG64, KNOWN_PACKAGES, HALLUCINATION_PATTERNS, SECURITY_PATTERNS2, CodeValidator, globalValidator, SAFETY_LIMITS2, DEFAULT_CONFIG73, ROUTE_FRAMEWORKS, DriftDetector, globalDetector;
|
|
46576
|
-
var
|
|
46577
|
-
"../../packages/core/dist/chunk-
|
|
48343
|
+
var init_chunk_WS67ECG2 = __esm({
|
|
48344
|
+
"../../packages/core/dist/chunk-WS67ECG2.js"() {
|
|
46578
48345
|
init_chunk_A4CYIMGM();
|
|
46579
48346
|
init_chunk_SKXQ6JUA();
|
|
46580
48347
|
init_chunk_4EQXFW4J();
|
|
@@ -48682,16 +50449,38 @@ var init_chunk_RPKCC72C = __esm({
|
|
|
48682
50449
|
{ pattern: /return\s+(?:null|undefined|{});\s*\/\/\s*placeholder/gi, type: "invented_pattern" }
|
|
48683
50450
|
];
|
|
48684
50451
|
SECURITY_PATTERNS2 = [
|
|
50452
|
+
// Critical: Code execution
|
|
48685
50453
|
{ pattern: /eval\s*\(/g, message: "Avoid eval() - it can execute arbitrary code", severity: "critical" },
|
|
48686
50454
|
{ pattern: /new\s+Function\s*\(/g, message: "Avoid new Function() - similar risks to eval()", severity: "critical" },
|
|
50455
|
+
{ pattern: /\bsetTimeout\s*\(\s*["'`]/g, message: "setTimeout with string argument is dangerous", severity: "critical" },
|
|
50456
|
+
{ pattern: /\bsetInterval\s*\(\s*["'`]/g, message: "setInterval with string argument is dangerous", severity: "critical" },
|
|
50457
|
+
// High: XSS and injection
|
|
48687
50458
|
{ pattern: /innerHTML\s*=/g, message: "innerHTML can lead to XSS - use textContent or sanitize", severity: "high" },
|
|
48688
50459
|
{ pattern: /document\.write\s*\(/g, message: "document.write is dangerous and deprecated", severity: "high" },
|
|
48689
50460
|
{ pattern: /dangerouslySetInnerHTML/g, message: "dangerouslySetInnerHTML can lead to XSS", severity: "medium" },
|
|
50461
|
+
{ pattern: /\bchild_process\s*\.\s*exec\s*\(/g, message: "child_process.exec() can be dangerous - use execFile", severity: "high" },
|
|
50462
|
+
{ pattern: /\bchild_process\s*\.\s*execSync\s*\(/g, message: "child_process.execSync() can be dangerous", severity: "high" },
|
|
50463
|
+
// Critical: Secrets
|
|
48690
50464
|
{ pattern: /(?:password|secret|api_key|apikey|token)\s*[:=]\s*['"`][^'"`]{8,}['"`]/gi, message: "Potential hardcoded secret detected", severity: "critical" },
|
|
50465
|
+
{ pattern: /sk[-_](?:live|test)[-_][A-Za-z0-9]{20,}/g, message: "Stripe secret key detected", severity: "critical" },
|
|
50466
|
+
{ pattern: /ghp_[A-Za-z0-9]{36,}/g, message: "GitHub personal access token detected", severity: "critical" },
|
|
50467
|
+
{ pattern: /github_pat_[A-Za-z0-9_]{22,}/g, message: "GitHub fine-grained token detected", severity: "critical" },
|
|
50468
|
+
{ pattern: /xox[baprs]-[A-Za-z0-9\-]{10,}/g, message: "Slack token detected", severity: "critical" },
|
|
50469
|
+
{ pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g, message: "Private key detected in code", severity: "critical" },
|
|
50470
|
+
{ pattern: /AKIA[A-Z0-9]{16}/g, message: "AWS access key detected", severity: "critical" },
|
|
50471
|
+
// Critical: Injection
|
|
48691
50472
|
{ pattern: /(?:SELECT|INSERT|UPDATE|DELETE).*\+.*(?:req\.|params\.|query\.)/gi, message: "Potential SQL injection - use parameterized queries", severity: "critical" },
|
|
48692
50473
|
{ pattern: /\$\{.*(?:req\.|params\.|query\.).*\}/g, message: "Template literal with user input - potential injection", severity: "high" },
|
|
48693
50474
|
{ pattern: /exec\s*\(\s*(?:req\.|params\.|query\.)/g, message: "Command injection risk - sanitize input", severity: "critical" },
|
|
48694
|
-
{ pattern: /\.createReadStream\s*\(\s*(?:req\.|params\.|query\.)/g, message: "Path traversal risk - validate file paths", severity: "high" }
|
|
50475
|
+
{ pattern: /\.createReadStream\s*\(\s*(?:req\.|params\.|query\.)/g, message: "Path traversal risk - validate file paths", severity: "high" },
|
|
50476
|
+
// High: Dynamic imports
|
|
50477
|
+
{ pattern: /\brequire\s*\(\s*[^"'`\s]/g, message: "Dynamic require is dangerous", severity: "high" },
|
|
50478
|
+
{ pattern: /\b__dirname\s*\+\s*[^"'`]/g, message: "Dynamic path construction can be dangerous", severity: "high" },
|
|
50479
|
+
{ pattern: /from\s+["'`]https?:\/\//g, message: "HTTP import detected - use npm packages", severity: "high" },
|
|
50480
|
+
{ pattern: /import\s*\(\s*["'`]https?:\/\//g, message: "Dynamic HTTP import detected", severity: "high" },
|
|
50481
|
+
// Medium: Destructive operations
|
|
50482
|
+
{ pattern: /\bfs\s*\.\s*(?:unlink|rmdir|rm)Sync?\s*\(/g, message: "Destructive file operation detected", severity: "medium" },
|
|
50483
|
+
{ pattern: /\bprocess\.exit\s*\(/g, message: "process.exit() detected - may cause unexpected termination", severity: "medium" }
|
|
48695
50484
|
];
|
|
48696
50485
|
CodeValidator = class {
|
|
48697
50486
|
config;
|
|
@@ -60529,6 +62318,7 @@ __export(dist_exports, {
|
|
|
60529
62318
|
AdvancedContextManager: () => AdvancedContextManager,
|
|
60530
62319
|
AdvancedScanner: () => AdvancedScanner,
|
|
60531
62320
|
AgentFirewall: () => AgentFirewall,
|
|
62321
|
+
AllowlistManager: () => AllowlistManager,
|
|
60532
62322
|
ArchitectAgent: () => ArchitectAgent,
|
|
60533
62323
|
AuditLogger: () => AuditLogger,
|
|
60534
62324
|
AuthDriftRule: () => AuthDriftRule,
|
|
@@ -60578,7 +62368,9 @@ __export(dist_exports, {
|
|
|
60578
62368
|
ContextSync: () => ContextSync,
|
|
60579
62369
|
ContextValidator: () => ContextValidator,
|
|
60580
62370
|
ContractDriftRule: () => ContractDriftRule,
|
|
62371
|
+
ContractGenerator: () => ContractGenerator,
|
|
60581
62372
|
ContractScanner: () => ContractScanner,
|
|
62373
|
+
ContractVerifier: () => ContractVerifier,
|
|
60582
62374
|
ContractsSchema: () => ContractsSchema2,
|
|
60583
62375
|
DARK_THEME_CSS: () => DARK_THEME_CSS,
|
|
60584
62376
|
DARK_THEME_VARS: () => DARK_THEME_VARS,
|
|
@@ -60712,6 +62504,7 @@ __export(dist_exports, {
|
|
|
60712
62504
|
MultiLevelCache: () => MultiLevelCache,
|
|
60713
62505
|
MultiSourceVerifier: () => MultiSourceVerifier,
|
|
60714
62506
|
NODE_TYPE_COLORS: () => NODE_TYPE_COLORS,
|
|
62507
|
+
ObserveModeManager: () => ObserveModeManager,
|
|
60715
62508
|
Orchestrator: () => Orchestrator,
|
|
60716
62509
|
PATTERNS: () => PATTERNS,
|
|
60717
62510
|
PHASE_RULE_CONFIGS: () => PHASE_RULE_CONFIGS,
|
|
@@ -60784,7 +62577,10 @@ __export(dist_exports, {
|
|
|
60784
62577
|
SkillsLoader: () => SkillsLoader,
|
|
60785
62578
|
SsrfGuard: () => SsrfGuard,
|
|
60786
62579
|
TEST_CONTEXT_PATTERNS: () => TEST_CONTEXT_PATTERNS,
|
|
62580
|
+
TIER_A_RULES: () => TIER_A_RULES,
|
|
62581
|
+
TIER_B_RULES: () => TIER_B_RULES,
|
|
60787
62582
|
TIER_CONFIGS: () => TIER_CONFIGS,
|
|
62583
|
+
TIER_C_RULES: () => TIER_C_RULES,
|
|
60788
62584
|
TIER_INFO: () => TIER_INFO,
|
|
60789
62585
|
TOOL_NAME: () => TOOL_NAME,
|
|
60790
62586
|
TOOL_URI: () => TOOL_URI,
|
|
@@ -60797,6 +62593,7 @@ __export(dist_exports, {
|
|
|
60797
62593
|
TranslatorAssumption: () => TranslatorAssumption,
|
|
60798
62594
|
TranslatorOutput: () => TranslatorOutput,
|
|
60799
62595
|
TranslatorQuestion: () => TranslatorQuestion,
|
|
62596
|
+
TrustScorer: () => TrustScorer,
|
|
60800
62597
|
TruthpackGenerator: () => TruthpackGenerator,
|
|
60801
62598
|
TruthpackValidators: () => TruthpackValidators,
|
|
60802
62599
|
UPGRADE_TRIGGERS: () => UPGRADE_TRIGGERS,
|
|
@@ -60857,7 +62654,6 @@ __export(dist_exports, {
|
|
|
60857
62654
|
calculateScoreFromCounts: () => calculateScoreFromCounts,
|
|
60858
62655
|
calculateScoreFromPassRate: () => calculateScoreFromPassRate,
|
|
60859
62656
|
calculateSecurityScore: () => calculateSecurityScore,
|
|
60860
|
-
calculateShipScore: () => calculateShipScore,
|
|
60861
62657
|
calculateWorkerCount: () => calculateWorkerCount,
|
|
60862
62658
|
checkCommandAccess: () => checkCommandAccess,
|
|
60863
62659
|
checkConfig: () => checkConfig,
|
|
@@ -60889,6 +62685,7 @@ __export(dist_exports, {
|
|
|
60889
62685
|
createActionClassifier: () => createActionClassifier,
|
|
60890
62686
|
createAggressiveModeManager: () => createAggressiveModeManager,
|
|
60891
62687
|
createAllowlistFix: () => createAllowlistFix,
|
|
62688
|
+
createAllowlistManager: () => createAllowlistManager,
|
|
60892
62689
|
createBadgeGenerator: () => createBadgeGenerator,
|
|
60893
62690
|
createBatchDetector: () => createBatchDetector,
|
|
60894
62691
|
createCacheKey: () => createCacheKey,
|
|
@@ -60920,6 +62717,7 @@ __export(dist_exports, {
|
|
|
60920
62717
|
createLearningStorage: () => createLearningStorage,
|
|
60921
62718
|
createLearningSystem: () => createLearningSystem,
|
|
60922
62719
|
createMissionGrouper: () => createMissionGrouper,
|
|
62720
|
+
createObserveModeManager: () => createObserveModeManager,
|
|
60923
62721
|
createParallelAnalyzer: () => createParallelAnalyzer,
|
|
60924
62722
|
createPluginLoader: () => createPluginLoader,
|
|
60925
62723
|
createPluginManager: () => createPluginManager,
|
|
@@ -60943,6 +62741,7 @@ __export(dist_exports, {
|
|
|
60943
62741
|
createSsrfGuard: () => createSsrfGuard,
|
|
60944
62742
|
createTelemetryService: () => createTelemetryService,
|
|
60945
62743
|
createTempFile: () => createTempFile,
|
|
62744
|
+
createTieredViolation: () => createTieredViolation,
|
|
60946
62745
|
createTimeoutManager: () => createTimeoutManager,
|
|
60947
62746
|
createUrlAllowlist: () => createUrlAllowlist,
|
|
60948
62747
|
createVideoStorageService: () => createVideoStorageService,
|
|
@@ -60999,7 +62798,6 @@ __export(dist_exports, {
|
|
|
60999
62798
|
findReferencedVariables: () => findReferencedVariables,
|
|
61000
62799
|
findRelevantTemplates: () => findRelevantTemplates,
|
|
61001
62800
|
findRunningServer: () => findRunningServer,
|
|
61002
|
-
findSimilar: () => findSimilar2,
|
|
61003
62801
|
findUnusedFunctions: () => findUnusedFunctions,
|
|
61004
62802
|
findingToSarifResult: () => findingToSarifResult,
|
|
61005
62803
|
fingerprint: () => fingerprint,
|
|
@@ -61017,6 +62815,7 @@ __export(dist_exports, {
|
|
|
61017
62815
|
formatMetrics: () => formatMetrics,
|
|
61018
62816
|
formatNumber: () => formatNumber,
|
|
61019
62817
|
formatProgress: () => formatProgress,
|
|
62818
|
+
formatProofBundle: () => formatProofBundle,
|
|
61020
62819
|
formatReceipt: () => formatReceipt,
|
|
61021
62820
|
formatReceiptSummary: () => formatReceiptSummary,
|
|
61022
62821
|
formatScanReport: () => formatScanReport,
|
|
@@ -61028,6 +62827,7 @@ __export(dist_exports, {
|
|
|
61028
62827
|
formatTierBadge: () => formatTierBadge,
|
|
61029
62828
|
formatUpgradePrompt: () => formatUpgradePrompt,
|
|
61030
62829
|
formatVerdict: () => formatVerdict,
|
|
62830
|
+
formatViolationMessage: () => formatViolationMessage,
|
|
61031
62831
|
gateFeature: () => gateFeature,
|
|
61032
62832
|
generateAIContract: () => generateAIContract,
|
|
61033
62833
|
generateAuditId: () => generateAuditId,
|
|
@@ -61055,6 +62855,7 @@ __export(dist_exports, {
|
|
|
61055
62855
|
generatePRWorkflow: () => generatePRWorkflow,
|
|
61056
62856
|
generatePdfBuffer: () => generatePdfBuffer,
|
|
61057
62857
|
generatePdfReport: () => generatePdfReport,
|
|
62858
|
+
generateProofBundle: () => generateProofBundle,
|
|
61058
62859
|
generateRealityCheckPdf: () => generateRealityCheckPdf,
|
|
61059
62860
|
generateRealityCheckReport: () => generateRealityCheckReport,
|
|
61060
62861
|
generateReceipt: () => generateReceipt,
|
|
@@ -61085,6 +62886,7 @@ __export(dist_exports, {
|
|
|
61085
62886
|
getCheckpointAge: () => getCheckpointAge,
|
|
61086
62887
|
getCircuitBreaker: () => getCircuitBreaker,
|
|
61087
62888
|
getClaimExtractor: () => getClaimExtractor,
|
|
62889
|
+
getCodeValidator: () => getCodeValidator,
|
|
61088
62890
|
getCommand: () => getCommand,
|
|
61089
62891
|
getCommandsByCategory: () => getCommandsByCategory,
|
|
61090
62892
|
getCommandsByTier: () => getCommandsByTier,
|
|
@@ -61191,6 +62993,7 @@ __export(dist_exports, {
|
|
|
61191
62993
|
htmlToPdf: () => htmlToPdf,
|
|
61192
62994
|
initTempCleanup: () => initTempCleanup,
|
|
61193
62995
|
invalidateCache: () => invalidateCache,
|
|
62996
|
+
isAllowed: () => isAllowed,
|
|
61194
62997
|
isBlockedIp: () => isBlockedIp,
|
|
61195
62998
|
isCategoryRelevantForPhase: () => isCategoryRelevantForPhase,
|
|
61196
62999
|
isConfidenceLevel: () => isConfidenceLevel,
|
|
@@ -61334,6 +63137,7 @@ __export(dist_exports, {
|
|
|
61334
63137
|
runWithConcurrency: () => runWithConcurrency,
|
|
61335
63138
|
runtimeVerifier: () => runtimeVerifier,
|
|
61336
63139
|
sanitize: () => sanitize,
|
|
63140
|
+
sanitizeCode: () => sanitizeCode,
|
|
61337
63141
|
sanitizeFilePath: () => sanitizeFilePath,
|
|
61338
63142
|
sarifToJson: () => sarifToJson,
|
|
61339
63143
|
scanCodeQuality: () => scanCodeQuality,
|
|
@@ -61380,6 +63184,7 @@ __export(dist_exports, {
|
|
|
61380
63184
|
unregisterCommand: () => unregisterCommand,
|
|
61381
63185
|
unregisterTempFile: () => unregisterTempFile,
|
|
61382
63186
|
updateManifest: () => updateManifest,
|
|
63187
|
+
validateAndSanitizeFiles: () => validateAndSanitizeFiles,
|
|
61383
63188
|
validateCallAgainstImports: () => validateCallAgainstImports,
|
|
61384
63189
|
validateContract: () => validateContract,
|
|
61385
63190
|
validateIssue: () => validateIssue,
|
|
@@ -61389,6 +63194,7 @@ __export(dist_exports, {
|
|
|
61389
63194
|
validateRule: () => validateRule,
|
|
61390
63195
|
validateTranslatorOutput: () => validateTranslatorOutput,
|
|
61391
63196
|
verdictToBadgeStatus: () => verdictToBadgeStatus,
|
|
63197
|
+
verifyProofBundle: () => verifyProofBundle,
|
|
61392
63198
|
verifyReceipt: () => verifyReceipt,
|
|
61393
63199
|
verifyReceiptSignature: () => verifyReceiptSignature,
|
|
61394
63200
|
visualizePath: () => visualizePath,
|
|
@@ -68210,24 +70016,25 @@ var init_dist3 = __esm({
|
|
|
68210
70016
|
init_chunk_BQ2JBTLZ();
|
|
68211
70017
|
init_chunk_DJEFLCF2();
|
|
68212
70018
|
init_chunk_KVOEVY4C();
|
|
68213
|
-
|
|
70019
|
+
init_chunk_GXXYXSWF();
|
|
68214
70020
|
init_chunk_C6QLUUAJ();
|
|
68215
70021
|
init_chunk_KCZC5WTF();
|
|
68216
70022
|
init_chunk_HUPNY5JN();
|
|
68217
70023
|
init_chunk_NUMYYREJ();
|
|
68218
70024
|
init_chunk_2D2X5IRQ();
|
|
68219
70025
|
init_chunk_F5SN54L7();
|
|
68220
|
-
|
|
70026
|
+
init_chunk_GZFCACMG();
|
|
68221
70027
|
init_chunk_3T7PUIDN();
|
|
68222
70028
|
init_chunk_BXUMCGJG();
|
|
68223
70029
|
init_chunk_ENJMGXRB();
|
|
68224
70030
|
init_chunk_ENJMGXRB();
|
|
68225
70031
|
init_chunk_VB6M3WM5();
|
|
68226
70032
|
init_chunk_VB6M3WM5();
|
|
68227
|
-
|
|
70033
|
+
init_chunk_4MEEGNJS();
|
|
70034
|
+
init_chunk_4MEEGNJS();
|
|
68228
70035
|
init_chunk_DFJL4MLU();
|
|
68229
|
-
|
|
68230
|
-
|
|
70036
|
+
init_chunk_WS67ECG2();
|
|
70037
|
+
init_chunk_WS67ECG2();
|
|
68231
70038
|
init_chunk_A4CYIMGM();
|
|
68232
70039
|
init_chunk_SKXQ6JUA();
|
|
68233
70040
|
init_chunk_4EQXFW4J();
|
|
@@ -73864,6 +75671,8 @@ ${content}`;
|
|
|
73864
75671
|
codeValidator = null;
|
|
73865
75672
|
driftDetector = null;
|
|
73866
75673
|
mockDetectorScanner = null;
|
|
75674
|
+
contractVerifier = null;
|
|
75675
|
+
truthpackGenerator = null;
|
|
73867
75676
|
initialized = false;
|
|
73868
75677
|
constructor(options) {
|
|
73869
75678
|
this.options = { ...DEFAULT_OPTIONS7, ...options };
|
|
@@ -73931,6 +75740,28 @@ ${content}`;
|
|
|
73931
75740
|
})()
|
|
73932
75741
|
);
|
|
73933
75742
|
}
|
|
75743
|
+
initPromises.push(
|
|
75744
|
+
(async () => {
|
|
75745
|
+
this.contractVerifier = new ContractVerifier({
|
|
75746
|
+
projectRoot: this.options.projectRoot,
|
|
75747
|
+
strict: false
|
|
75748
|
+
});
|
|
75749
|
+
await this.contractVerifier.loadContracts();
|
|
75750
|
+
this.truthpackGenerator = new TruthpackGenerator({
|
|
75751
|
+
projectRoot: this.options.projectRoot,
|
|
75752
|
+
outputDir: path18.join(this.options.projectRoot, ".vibecheck", "truthpack"),
|
|
75753
|
+
scanners: {
|
|
75754
|
+
routes: true,
|
|
75755
|
+
env: true,
|
|
75756
|
+
auth: true,
|
|
75757
|
+
contracts: true,
|
|
75758
|
+
uiGraph: false
|
|
75759
|
+
},
|
|
75760
|
+
watchMode: false,
|
|
75761
|
+
watchDebounceMs: 1e3
|
|
75762
|
+
});
|
|
75763
|
+
})()
|
|
75764
|
+
);
|
|
73934
75765
|
await Promise.all(initPromises);
|
|
73935
75766
|
this.initialized = true;
|
|
73936
75767
|
const initTime = Date.now() - startTime;
|
|
@@ -74069,6 +75900,47 @@ ${content}`;
|
|
|
74069
75900
|
error: mockDetection.summary.bySeverity.error
|
|
74070
75901
|
});
|
|
74071
75902
|
}
|
|
75903
|
+
let contractVerification;
|
|
75904
|
+
if (this.contractVerifier) {
|
|
75905
|
+
this.logger.debug("Starting contract verification");
|
|
75906
|
+
let truthpackContext;
|
|
75907
|
+
if (this.truthpackGenerator) {
|
|
75908
|
+
try {
|
|
75909
|
+
const truthpack = await this.truthpackGenerator.generate();
|
|
75910
|
+
truthpackContext = this.contractVerifier.createContext({
|
|
75911
|
+
routes: truthpack.routes,
|
|
75912
|
+
env: truthpack.env,
|
|
75913
|
+
auth: truthpack.auth
|
|
75914
|
+
});
|
|
75915
|
+
} catch {
|
|
75916
|
+
truthpackContext = this.contractVerifier.createContext();
|
|
75917
|
+
}
|
|
75918
|
+
}
|
|
75919
|
+
contractVerification = await this.contractVerifier.verifyAll(truthpackContext);
|
|
75920
|
+
for (const violation of contractVerification.violations) {
|
|
75921
|
+
findings.push({
|
|
75922
|
+
id: `contract-${violation.contractName}-${violation.behaviorName ?? "unknown"}-${violation.line ?? 0}`,
|
|
75923
|
+
type: this.mapViolationToType(violation.type),
|
|
75924
|
+
severity: violation.severity === "error" ? "error" : violation.severity === "warning" ? "warning" : "info",
|
|
75925
|
+
message: violation.message,
|
|
75926
|
+
file: violation.file,
|
|
75927
|
+
line: violation.line ?? null,
|
|
75928
|
+
column: violation.column ?? null,
|
|
75929
|
+
evidence: violation.evidence ?? [],
|
|
75930
|
+
confidence: violation.confidence ?? 0.7,
|
|
75931
|
+
verified: true,
|
|
75932
|
+
suggestion: violation.suggestion,
|
|
75933
|
+
autoFixable: violation.autoFixable,
|
|
75934
|
+
category: "hallucination"
|
|
75935
|
+
// Contract violations are potential hallucinations
|
|
75936
|
+
});
|
|
75937
|
+
}
|
|
75938
|
+
this.logger.debug("Contract verification complete", {
|
|
75939
|
+
verdict: contractVerification.verdict,
|
|
75940
|
+
violations: contractVerification.violations.length,
|
|
75941
|
+
coverage: contractVerification.coverage
|
|
75942
|
+
});
|
|
75943
|
+
}
|
|
74072
75944
|
const durationMs = Date.now() - startTime;
|
|
74073
75945
|
const metrics = {
|
|
74074
75946
|
durationMs,
|
|
@@ -74460,6 +76332,16 @@ ${content}`;
|
|
|
74460
76332
|
};
|
|
74461
76333
|
return typeMap[category] ?? "invented_pattern";
|
|
74462
76334
|
}
|
|
76335
|
+
mapViolationToType(violationType) {
|
|
76336
|
+
const typeMap = {
|
|
76337
|
+
"type_mismatch": "fake_type",
|
|
76338
|
+
"missing_field": "fake_type",
|
|
76339
|
+
"constraint_violation": "invented_pattern",
|
|
76340
|
+
"contract_drift": "type_drift",
|
|
76341
|
+
"unverified_behavior": "fake_api"
|
|
76342
|
+
};
|
|
76343
|
+
return typeMap[violationType] ?? "invented_pattern";
|
|
76344
|
+
}
|
|
74463
76345
|
isAutoFixable(type) {
|
|
74464
76346
|
const autoFixable = /* @__PURE__ */ new Set([
|
|
74465
76347
|
"fake_import",
|
|
@@ -81358,10 +83240,10 @@ ${content}`;
|
|
|
81358
83240
|
};
|
|
81359
83241
|
}
|
|
81360
83242
|
}
|
|
81361
|
-
const
|
|
83243
|
+
const isAllowed2 = this.config.allowedRoutes.some(
|
|
81362
83244
|
(pattern) => this.matchesPattern(pathname, pattern)
|
|
81363
83245
|
);
|
|
81364
|
-
if (!
|
|
83246
|
+
if (!isAllowed2) {
|
|
81365
83247
|
return {
|
|
81366
83248
|
allowed: false,
|
|
81367
83249
|
reason: "URL does not match any allowed pattern"
|
|
@@ -82349,11 +84231,13 @@ __export(scoring_exports, {
|
|
|
82349
84231
|
createISLScorer: () => createISLScorer,
|
|
82350
84232
|
createShipScoreCalculator: () => createShipScoreCalculator,
|
|
82351
84233
|
determineVerdict: () => determineVerdict,
|
|
84234
|
+
formatProofBundle: () => formatProofBundle,
|
|
82352
84235
|
formatScore: () => formatScore,
|
|
82353
84236
|
formatScoreOutOf100: () => formatScoreOutOf100,
|
|
82354
84237
|
formatScorePercent: () => formatScorePercent,
|
|
82355
84238
|
formatShipScore: () => formatShipScore,
|
|
82356
84239
|
formatVerdict: () => formatVerdict,
|
|
84240
|
+
generateProofBundle: () => generateProofBundle,
|
|
82357
84241
|
getCategoryForEngine: () => getCategoryForEngine,
|
|
82358
84242
|
getCategoryNames: () => getCategoryNames,
|
|
82359
84243
|
getCategoryWeight: () => getCategoryWeight,
|
|
@@ -82364,11 +84248,12 @@ __export(scoring_exports, {
|
|
|
82364
84248
|
getVerdictFromScore: () => getVerdictFromScore,
|
|
82365
84249
|
islScorer: () => islScorer,
|
|
82366
84250
|
shipScoreCalculator: () => shipScoreCalculator,
|
|
82367
|
-
toSeverityCounts: () => toSeverityCounts
|
|
84251
|
+
toSeverityCounts: () => toSeverityCounts,
|
|
84252
|
+
verifyProofBundle: () => verifyProofBundle
|
|
82368
84253
|
});
|
|
82369
84254
|
var init_scoring = __esm({
|
|
82370
84255
|
"../../packages/core/dist/scoring/index.js"() {
|
|
82371
|
-
|
|
84256
|
+
init_chunk_GXXYXSWF();
|
|
82372
84257
|
init_chunk_RRAR6G52();
|
|
82373
84258
|
}
|
|
82374
84259
|
});
|
|
@@ -82379,11 +84264,15 @@ __export(validation_exports, {
|
|
|
82379
84264
|
CodeValidator: () => CodeValidator,
|
|
82380
84265
|
DriftDetector: () => DriftDetector,
|
|
82381
84266
|
HallucinationDetector: () => HallucinationDetector,
|
|
82382
|
-
MultiSourceVerifier: () => MultiSourceVerifier
|
|
84267
|
+
MultiSourceVerifier: () => MultiSourceVerifier,
|
|
84268
|
+
calculateShipScore: () => calculateShipScore2,
|
|
84269
|
+
getCodeValidator: () => getCodeValidator,
|
|
84270
|
+
sanitizeCode: () => sanitizeCode,
|
|
84271
|
+
validateAndSanitizeFiles: () => validateAndSanitizeFiles
|
|
82383
84272
|
});
|
|
82384
84273
|
var init_validation = __esm({
|
|
82385
84274
|
"../../packages/core/dist/validation/index.js"() {
|
|
82386
|
-
|
|
84275
|
+
init_chunk_WS67ECG2();
|
|
82387
84276
|
init_chunk_A4CYIMGM();
|
|
82388
84277
|
init_chunk_SKXQ6JUA();
|
|
82389
84278
|
init_chunk_4EQXFW4J();
|
|
@@ -83183,7 +85072,7 @@ async function configureOutput(currentConfig) {
|
|
|
83183
85072
|
}
|
|
83184
85073
|
|
|
83185
85074
|
// src/lib/version.ts
|
|
83186
|
-
var CLI_VERSION = "1.2.
|
|
85075
|
+
var CLI_VERSION = "1.2.2" ;
|
|
83187
85076
|
var CLI_NAME = "vibecheck-ai" ;
|
|
83188
85077
|
|
|
83189
85078
|
// src/ui/command-header.tsx
|
|
@@ -84439,11 +86328,6 @@ async function showLoginScreen() {
|
|
|
84439
86328
|
label: "\u{1F4E7} " + chalk9.white("Email & Password"),
|
|
84440
86329
|
hint: "Classic login"
|
|
84441
86330
|
},
|
|
84442
|
-
{
|
|
84443
|
-
value: "github",
|
|
84444
|
-
label: "\u{1F419} " + chalk9.white("Continue with GitHub"),
|
|
84445
|
-
hint: "OAuth login"
|
|
84446
|
-
},
|
|
84447
86331
|
{
|
|
84448
86332
|
value: "google",
|
|
84449
86333
|
label: "\u{1F50D} " + chalk9.white("Continue with Google"),
|
|
@@ -84474,8 +86358,6 @@ async function showLoginScreen() {
|
|
|
84474
86358
|
return await apiKeyLogin();
|
|
84475
86359
|
case "email":
|
|
84476
86360
|
return await emailLogin();
|
|
84477
|
-
case "github":
|
|
84478
|
-
return await oauthLogin("GitHub");
|
|
84479
86361
|
case "google":
|
|
84480
86362
|
return await oauthLogin("Google");
|
|
84481
86363
|
case "magic":
|
|
@@ -84777,7 +86659,7 @@ async function signupFlow() {
|
|
|
84777
86659
|
},
|
|
84778
86660
|
{
|
|
84779
86661
|
value: "pro",
|
|
84780
|
-
label: "\u2B50 " + chalk9.yellow("Pro") + chalk9.dim(" - $
|
|
86662
|
+
label: "\u2B50 " + chalk9.yellow("Pro") + chalk9.dim(" - $19/dev/mo"),
|
|
84781
86663
|
hint: "Cloud sync, team collaboration, API access"
|
|
84782
86664
|
},
|
|
84783
86665
|
{
|
|
@@ -84837,7 +86719,7 @@ async function showLoginSuccess(session) {
|
|
|
84837
86719
|
};
|
|
84838
86720
|
const tierLabels = {
|
|
84839
86721
|
free: "\u{1F193} Free",
|
|
84840
|
-
pro: "\u2B50 Pro ($
|
|
86722
|
+
pro: "\u2B50 Pro ($19/dev/mo)",
|
|
84841
86723
|
enterprise: "\u{1F3E2} Enterprise"
|
|
84842
86724
|
};
|
|
84843
86725
|
console.log(" " + chalk9.dim("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
|
|
@@ -84920,6 +86802,10 @@ async function initializeFromCredentials() {
|
|
|
84920
86802
|
function getCurrentTier() {
|
|
84921
86803
|
return currentSession.tier;
|
|
84922
86804
|
}
|
|
86805
|
+
async function getCurrentTierAsync() {
|
|
86806
|
+
await initializeFromCredentials();
|
|
86807
|
+
return currentSession.tier;
|
|
86808
|
+
}
|
|
84923
86809
|
function isAuthenticated() {
|
|
84924
86810
|
return currentSession.authenticated;
|
|
84925
86811
|
}
|
|
@@ -84934,6 +86820,24 @@ var EXIT_CODES = {
|
|
|
84934
86820
|
TIER_GATE: 10,
|
|
84935
86821
|
INTERRUPTED: 130
|
|
84936
86822
|
};
|
|
86823
|
+
async function checkEntitlements() {
|
|
86824
|
+
await initializeFromCredentials();
|
|
86825
|
+
const tier = getCurrentTier();
|
|
86826
|
+
const authenticated = isAuthenticated();
|
|
86827
|
+
return {
|
|
86828
|
+
isPro: tier === "pro" || tier === "enterprise",
|
|
86829
|
+
isEnterprise: tier === "enterprise",
|
|
86830
|
+
currentTier: tier,
|
|
86831
|
+
authenticated
|
|
86832
|
+
};
|
|
86833
|
+
}
|
|
86834
|
+
async function isPro() {
|
|
86835
|
+
await initializeFromCredentials();
|
|
86836
|
+
return currentSession.tier === "pro" || currentSession.tier === "enterprise";
|
|
86837
|
+
}
|
|
86838
|
+
function isProSync() {
|
|
86839
|
+
return currentSession.tier === "pro" || currentSession.tier === "enterprise";
|
|
86840
|
+
}
|
|
84937
86841
|
|
|
84938
86842
|
// src/ui/upgrade-prompt.ts
|
|
84939
86843
|
function renderUpgradePrompt(options) {
|
|
@@ -87241,60 +89145,16 @@ async function scanCommand(options) {
|
|
|
87241
89145
|
const startTime = Date.now();
|
|
87242
89146
|
const performanceTracker = getPerformanceTracker();
|
|
87243
89147
|
const phaseTimings = {};
|
|
87244
|
-
let quotaStatus = null;
|
|
87245
89148
|
const scanStartTime = Date.now();
|
|
87246
89149
|
try {
|
|
87247
89150
|
validateOptions(options);
|
|
87248
89151
|
checkSystemRequirements();
|
|
87249
89152
|
const isAuth = await isAuthenticatedAsync();
|
|
87250
|
-
if (!isAuth) {
|
|
89153
|
+
if (!isAuth && !options.quiet) {
|
|
87251
89154
|
logger2.warn("");
|
|
87252
89155
|
logger2.warn(chalk9.yellow("\u26A0\uFE0F Not authenticated - scan usage cannot be tracked."));
|
|
87253
|
-
logger2.warn(chalk9.gray(" Run `vibecheck login` to authenticate and
|
|
87254
|
-
logger2.warn(chalk9.gray(" Free tier: 5 scans/month | Pro tier: Unlimited scans"));
|
|
89156
|
+
logger2.warn(chalk9.gray(" Run `vibecheck login` to authenticate and sync to cloud."));
|
|
87255
89157
|
logger2.warn("");
|
|
87256
|
-
} else {
|
|
87257
|
-
const quotaCheck = await checkScanAllowed();
|
|
87258
|
-
if (!quotaCheck.success) {
|
|
87259
|
-
if (quotaCheck.error?.code === "QUOTA_EXCEEDED") {
|
|
87260
|
-
const details = quotaCheck.error.details;
|
|
87261
|
-
logger2.error("");
|
|
87262
|
-
logger2.error(chalk9.red("\u274C Scan quota exceeded!"));
|
|
87263
|
-
logger2.error("");
|
|
87264
|
-
logger2.error(chalk9.white(` You've used all ${details?.limit ?? 5} free scans this month.`));
|
|
87265
|
-
if (details?.resetsAt) {
|
|
87266
|
-
const resetDate = new Date(details.resetsAt);
|
|
87267
|
-
logger2.error(chalk9.gray(` Quota resets: ${resetDate.toLocaleDateString()}`));
|
|
87268
|
-
}
|
|
87269
|
-
logger2.error("");
|
|
87270
|
-
logger2.error(chalk9.cyan(" \u{1F680} Upgrade to Pro for unlimited scans:"));
|
|
87271
|
-
logger2.error(chalk9.cyan(" https://vibecheckai.dev/pricing?action=checkout&plan=pro"));
|
|
87272
|
-
logger2.error("");
|
|
87273
|
-
process.exit(10);
|
|
87274
|
-
} else if (quotaCheck.error?.code === "NETWORK_ERROR") {
|
|
87275
|
-
logger2.warn("");
|
|
87276
|
-
logger2.warn(chalk9.yellow("\u26A0\uFE0F Could not verify scan quota (offline mode)."));
|
|
87277
|
-
logger2.warn(chalk9.gray(" Scan will proceed but usage may not be tracked."));
|
|
87278
|
-
logger2.warn("");
|
|
87279
|
-
} else {
|
|
87280
|
-
logger2.warn("");
|
|
87281
|
-
logger2.warn(chalk9.yellow(`\u26A0\uFE0F Quota check warning: ${quotaCheck.error?.message}`));
|
|
87282
|
-
logger2.warn("");
|
|
87283
|
-
}
|
|
87284
|
-
} else if (quotaCheck.data) {
|
|
87285
|
-
quotaStatus = quotaCheck.data;
|
|
87286
|
-
if (quotaStatus.tier === "free" && quotaStatus.limit !== -1) {
|
|
87287
|
-
const remaining = quotaStatus.remaining;
|
|
87288
|
-
if (remaining <= 2) {
|
|
87289
|
-
logger2.warn("");
|
|
87290
|
-
logger2.warn(chalk9.yellow(`\u26A0\uFE0F ${formatQuotaMessage(quotaStatus)}`));
|
|
87291
|
-
if (remaining <= 1) {
|
|
87292
|
-
logger2.warn(chalk9.gray(" Upgrade to Pro for unlimited scans: vibecheck upgrade"));
|
|
87293
|
-
}
|
|
87294
|
-
logger2.warn("");
|
|
87295
|
-
}
|
|
87296
|
-
}
|
|
87297
|
-
}
|
|
87298
89158
|
}
|
|
87299
89159
|
const configLoadStart = Date.now();
|
|
87300
89160
|
let config;
|
|
@@ -87544,20 +89404,17 @@ async function scanCommand(options) {
|
|
|
87544
89404
|
quiet: options.quiet,
|
|
87545
89405
|
logger: logger2
|
|
87546
89406
|
});
|
|
87547
|
-
if (!options.json && !options.quiet &&
|
|
89407
|
+
if (!options.json && !options.quiet && !isProSync()) {
|
|
87548
89408
|
printForgeUpgradeSuggestion(userTier, logger2);
|
|
87549
89409
|
}
|
|
87550
89410
|
}
|
|
87551
89411
|
if (await isAuthenticatedAsync()) {
|
|
87552
89412
|
const scanDuration = Date.now() - scanStartTime;
|
|
87553
|
-
|
|
89413
|
+
await recordScan({
|
|
87554
89414
|
scanType: "full",
|
|
87555
89415
|
projectPath: process.cwd(),
|
|
87556
89416
|
duration: scanDuration
|
|
87557
89417
|
});
|
|
87558
|
-
if (recordResult.success && recordResult.data) {
|
|
87559
|
-
quotaStatus = recordResult.data;
|
|
87560
|
-
}
|
|
87561
89418
|
}
|
|
87562
89419
|
if (options.json) {
|
|
87563
89420
|
const commandResult = {
|
|
@@ -87645,34 +89502,7 @@ async function scanCommand(options) {
|
|
|
87645
89502
|
logger2.dim(`Size: ${formatBytes(outputSize)}`);
|
|
87646
89503
|
}
|
|
87647
89504
|
logger2.dim(`Duration: ${formatDuration(results.duration)}`);
|
|
87648
|
-
if (
|
|
87649
|
-
logger2.newline();
|
|
87650
|
-
const remaining = quotaStatus.remaining;
|
|
87651
|
-
const used = quotaStatus.used;
|
|
87652
|
-
const limit = quotaStatus.limit;
|
|
87653
|
-
if (remaining === 0) {
|
|
87654
|
-
console.log(colors.error("\u2501".repeat(50)));
|
|
87655
|
-
console.log(`${chalk9.red("\u26A0")} ${chalk9.bold.red("No scans remaining this month")}`);
|
|
87656
|
-
console.log(colors.error("\u2501".repeat(50)));
|
|
87657
|
-
console.log("");
|
|
87658
|
-
console.log(chalk9.white(` You've used all ${limit} free scans.`));
|
|
87659
|
-
console.log("");
|
|
87660
|
-
console.log(chalk9.cyan(" \u{1F680} Upgrade to Pro for unlimited scans:"));
|
|
87661
|
-
console.log(chalk9.cyan(" vibecheck upgrade"));
|
|
87662
|
-
console.log("");
|
|
87663
|
-
} else if (remaining <= 2) {
|
|
87664
|
-
console.log(colors.warning("\u2501".repeat(50)));
|
|
87665
|
-
console.log(`${chalk9.yellow("\u26A1")} ${chalk9.bold(`${remaining} scan${remaining === 1 ? "" : "s"} remaining`)}`);
|
|
87666
|
-
console.log(colors.warning("\u2501".repeat(50)));
|
|
87667
|
-
console.log("");
|
|
87668
|
-
console.log(chalk9.gray(` Used: ${used}/${limit} scans this month`));
|
|
87669
|
-
console.log("");
|
|
87670
|
-
console.log(chalk9.cyan(" Upgrade to Pro for unlimited scans: vibecheck upgrade"));
|
|
87671
|
-
console.log("");
|
|
87672
|
-
} else {
|
|
87673
|
-
logger2.dim(`Scans remaining: ${remaining}/${limit} this month`);
|
|
87674
|
-
}
|
|
87675
|
-
} else if (!isAuthenticated() && !options.quiet) {
|
|
89505
|
+
if (!isAuthenticated() && !options.quiet) {
|
|
87676
89506
|
logger2.newline();
|
|
87677
89507
|
console.log(colors.primary("\u2501".repeat(50)));
|
|
87678
89508
|
console.log(`${symbols.raw.star} ${chalk9.bold("Pro Features Available")}`);
|
|
@@ -88485,10 +90315,10 @@ function formatCategory(category) {
|
|
|
88485
90315
|
};
|
|
88486
90316
|
return categoryMap[category] || category;
|
|
88487
90317
|
}
|
|
88488
|
-
function renderFixCTA(hasFixableIssues,
|
|
90318
|
+
function renderFixCTA(hasFixableIssues, isPro2 = false) {
|
|
88489
90319
|
const lines = [];
|
|
88490
90320
|
if (hasFixableIssues) {
|
|
88491
|
-
if (
|
|
90321
|
+
if (isPro2) {
|
|
88492
90322
|
lines.push(chalk9.cyan("Fix these in 1 click: ") + chalk9.bold("vibecheck fix -i"));
|
|
88493
90323
|
} else {
|
|
88494
90324
|
lines.push(chalk9.cyan("Fix these in 1 click: ") + chalk9.bold("vibecheck fix -i"));
|
|
@@ -88677,7 +90507,7 @@ async function runQuickstartClean(projectRoot, showExplain) {
|
|
|
88677
90507
|
console.log(` ${chalk9.cyan("\u2022")} Video replay viewer`);
|
|
88678
90508
|
console.log(` ${chalk9.cyan("\u2022")} Chaos Agent for stress testing`);
|
|
88679
90509
|
console.log("");
|
|
88680
|
-
console.log(`${chalk9.dim("Start
|
|
90510
|
+
console.log(`${chalk9.dim("Start 7-day free trial:")} ${chalk9.cyan("vibecheck upgrade --trial")}`);
|
|
88681
90511
|
console.log("");
|
|
88682
90512
|
console.log(chalk9.bold("Next step:"));
|
|
88683
90513
|
console.log(` ${chalk9.cyan("vibecheck certify")} ${chalk9.dim("\u2014")} Get your first Ship Score`);
|
|
@@ -88946,7 +90776,7 @@ async function initCommand(options) {
|
|
|
88946
90776
|
}
|
|
88947
90777
|
try {
|
|
88948
90778
|
const { TruthpackGenerator: TruthpackGenerator2 } = await Promise.resolve().then(() => (init_truthpack(), truthpack_exports));
|
|
88949
|
-
const { calculateShipScore:
|
|
90779
|
+
const { calculateShipScore: calculateShipScore3, getTopFixableIssues: getTopFixableIssues2 } = await Promise.resolve().then(() => (init_scoring(), scoring_exports));
|
|
88950
90780
|
const { DriftDetector: DriftDetector2 } = await Promise.resolve().then(() => (init_validation(), validation_exports));
|
|
88951
90781
|
const scanStartTime = Date.now();
|
|
88952
90782
|
const generator = new TruthpackGenerator2({
|
|
@@ -88976,7 +90806,7 @@ async function initCommand(options) {
|
|
|
88976
90806
|
message: item.details,
|
|
88977
90807
|
autoFixable: true
|
|
88978
90808
|
}));
|
|
88979
|
-
const score =
|
|
90809
|
+
const score = calculateShipScore3({
|
|
88980
90810
|
truthpack: {
|
|
88981
90811
|
routes: truthpack.routes || [],
|
|
88982
90812
|
env: truthpack.env?.map((e) => ({ name: e.name, required: e.required })) || [],
|
|
@@ -89126,13 +90956,12 @@ async function initCommand(options) {
|
|
|
89126
90956
|
}
|
|
89127
90957
|
console.log(JSON.stringify(jsonOutput, null, 2));
|
|
89128
90958
|
} else if (quickModeResult) {
|
|
89129
|
-
const userTier = getCurrentTier();
|
|
89130
90959
|
console.log(renderQuickInitOutput(
|
|
89131
90960
|
quickModeResult.score,
|
|
89132
90961
|
quickModeResult.findings,
|
|
89133
90962
|
duration,
|
|
89134
90963
|
{
|
|
89135
|
-
isPro:
|
|
90964
|
+
isPro: isProSync(),
|
|
89136
90965
|
projectPath: process.cwd()
|
|
89137
90966
|
}
|
|
89138
90967
|
));
|
|
@@ -89175,11 +91004,9 @@ async function initCommand(options) {
|
|
|
89175
91004
|
console.log(` ${symbols.info} ${instruction}`);
|
|
89176
91005
|
}
|
|
89177
91006
|
}
|
|
89178
|
-
if (forgeResult?.ran) {
|
|
91007
|
+
if (forgeResult?.ran && !isProSync()) {
|
|
89179
91008
|
const userTier = getCurrentTier();
|
|
89180
|
-
|
|
89181
|
-
printForgeUpgradeSuggestion(userTier, logger2);
|
|
89182
|
-
}
|
|
91009
|
+
printForgeUpgradeSuggestion(userTier, logger2);
|
|
89183
91010
|
}
|
|
89184
91011
|
}
|
|
89185
91012
|
} catch (error) {
|
|
@@ -90814,10 +92641,9 @@ async function shipCommand(options) {
|
|
|
90814
92641
|
}
|
|
90815
92642
|
}
|
|
90816
92643
|
if (ready && !options.quiet) {
|
|
90817
|
-
const
|
|
90818
|
-
const isPro = userTier === "pro" || userTier === "enterprise";
|
|
92644
|
+
const isPro2 = isProSync();
|
|
90819
92645
|
logger2.newline();
|
|
90820
|
-
if (
|
|
92646
|
+
if (isPro2 && isAuthenticated()) {
|
|
90821
92647
|
console.log(`
|
|
90822
92648
|
${colors.primary("\u2501".repeat(50))}
|
|
90823
92649
|
${colors.success("\u2713")} ${chalk9.bold("Ship Badge Ready!")} ${colors.muted("(Pro Feature)")}
|
|
@@ -92236,8 +94062,7 @@ var DEFAULT_HTML_FILENAME = "vibecheck-report.html";
|
|
|
92236
94062
|
var DEFAULT_PDF_FILENAME = "vibecheck-report.pdf";
|
|
92237
94063
|
var PRO_REPORT_TYPES = ["executive-summary", "detailed-technical", "compliance"];
|
|
92238
94064
|
function checkReportTierGate(options) {
|
|
92239
|
-
|
|
92240
|
-
if (currentTier === "pro" || currentTier === "enterprise") {
|
|
94065
|
+
if (isProSync()) {
|
|
92241
94066
|
return null;
|
|
92242
94067
|
}
|
|
92243
94068
|
if (options.type && PRO_REPORT_TYPES.includes(options.type)) {
|
|
@@ -93169,7 +94994,6 @@ function findProjectRootSync(startDir) {
|
|
|
93169
94994
|
}
|
|
93170
94995
|
|
|
93171
94996
|
// src/commands/forge.ts
|
|
93172
|
-
init_credentials();
|
|
93173
94997
|
function printForgeValue(logger2) {
|
|
93174
94998
|
logger2.newline();
|
|
93175
94999
|
logger2.info(chalk9.bold.magenta("What Forge Does For You:"));
|
|
@@ -93319,21 +95143,15 @@ var forgeCommand = new Command("forge").description("Generate AI context rules t
|
|
|
93319
95143
|
logger2.error('Not in a VibeCheck project. Run "vibecheck init" first.');
|
|
93320
95144
|
process.exit(1);
|
|
93321
95145
|
}
|
|
93322
|
-
|
|
93323
|
-
try {
|
|
93324
|
-
const result = await loadCredentials();
|
|
93325
|
-
if (result.valid && result.credentials) {
|
|
93326
|
-
userTier = result.credentials.tier ?? "free";
|
|
93327
|
-
}
|
|
93328
|
-
} catch {
|
|
93329
|
-
}
|
|
95146
|
+
const userTier = await getCurrentTierAsync();
|
|
93330
95147
|
const tierConfig = options.tier ? { tier: options.tier, maxRules: getTierLimit(options.tier) } : getForgeConfigForTier(userTier);
|
|
93331
95148
|
const platforms = options.platform === "both" ? ["cursor", "windsurf"] : [options.platform ?? "cursor"];
|
|
95149
|
+
const isPro2 = userTier === "pro" || userTier === "enterprise";
|
|
93332
95150
|
const config = {
|
|
93333
95151
|
tier: tierConfig.tier,
|
|
93334
95152
|
maxRules: tierConfig.maxRules,
|
|
93335
95153
|
incremental: options.incremental ?? true,
|
|
93336
|
-
generateContract: options.contract ??
|
|
95154
|
+
generateContract: options.contract ?? isPro2,
|
|
93337
95155
|
verbose: globalOpts.verbose ?? false,
|
|
93338
95156
|
platforms
|
|
93339
95157
|
};
|
|
@@ -93353,12 +95171,13 @@ var forgeCommand = new Command("forge").description("Generate AI context rules t
|
|
|
93353
95171
|
return;
|
|
93354
95172
|
}
|
|
93355
95173
|
printForgeStats(output, logger2, globalOpts.verbose ?? false);
|
|
93356
|
-
if (
|
|
95174
|
+
if (!isPro2) {
|
|
93357
95175
|
logger2.newline();
|
|
93358
95176
|
logger2.info(chalk9.cyan("Tip: Upgrade to Pro for more rules and AI Contract"));
|
|
93359
95177
|
logger2.dim(" - 20 rules instead of 5");
|
|
93360
95178
|
logger2.dim(" - AI Contract with forbidden/required patterns");
|
|
93361
95179
|
logger2.dim(" - Security, performance, and testing rules");
|
|
95180
|
+
logger2.dim(" Run: vibecheck upgrade");
|
|
93362
95181
|
}
|
|
93363
95182
|
logger2.newline();
|
|
93364
95183
|
logger2.success("Forge complete! Your AI assistant now has accurate project context.");
|
|
@@ -93376,7 +95195,6 @@ function getTierLimit(tier) {
|
|
|
93376
95195
|
};
|
|
93377
95196
|
return limits[tier];
|
|
93378
95197
|
}
|
|
93379
|
-
init_credentials();
|
|
93380
95198
|
var API_BASE = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
|
|
93381
95199
|
function getBadgeUrl(projectId, style, verified) {
|
|
93382
95200
|
const endpoint = verified ? "verified" : "svg";
|
|
@@ -93400,14 +95218,7 @@ async function badgeCommand(options) {
|
|
|
93400
95218
|
json: options.json
|
|
93401
95219
|
});
|
|
93402
95220
|
const authenticated = isAuthenticated();
|
|
93403
|
-
|
|
93404
|
-
if (authenticated) {
|
|
93405
|
-
const credResult = await loadCredentials();
|
|
93406
|
-
if (credResult.success && credResult.credentials) {
|
|
93407
|
-
const tier = credResult.credentials.user?.tier;
|
|
93408
|
-
isPro = tier === "pro" || tier === "enterprise";
|
|
93409
|
-
}
|
|
93410
|
-
}
|
|
95221
|
+
const isPro2 = authenticated ? await isPro() : false;
|
|
93411
95222
|
if (!options.json && !options.quiet) {
|
|
93412
95223
|
safeRenderHeader({
|
|
93413
95224
|
command: "badge",
|
|
@@ -93417,9 +95228,9 @@ async function badgeCommand(options) {
|
|
|
93417
95228
|
vitals: [
|
|
93418
95229
|
{
|
|
93419
95230
|
label: "BADGE STATUS",
|
|
93420
|
-
status: authenticated ?
|
|
93421
|
-
value:
|
|
93422
|
-
percentage:
|
|
95231
|
+
status: authenticated ? isPro2 ? "optimal" : "stable" : "warning",
|
|
95232
|
+
value: isPro2 ? "Pro badges available" : "Basic badges",
|
|
95233
|
+
percentage: isPro2 ? 100 : 50
|
|
93423
95234
|
}
|
|
93424
95235
|
],
|
|
93425
95236
|
diagnostics: [
|
|
@@ -93428,8 +95239,8 @@ async function badgeCommand(options) {
|
|
|
93428
95239
|
message: authenticated ? "Authenticated" : "Not authenticated"
|
|
93429
95240
|
},
|
|
93430
95241
|
{
|
|
93431
|
-
level:
|
|
93432
|
-
message:
|
|
95242
|
+
level: isPro2 ? "pass" : "info",
|
|
95243
|
+
message: isPro2 ? "Verified badges enabled" : "Upgrade for verified badges"
|
|
93433
95244
|
}
|
|
93434
95245
|
]
|
|
93435
95246
|
});
|
|
@@ -93484,7 +95295,7 @@ async function badgeCommand(options) {
|
|
|
93484
95295
|
markdown: getMarkdownEmbed(projectId, style, false),
|
|
93485
95296
|
html: getHtmlEmbed(projectId, style, false)
|
|
93486
95297
|
},
|
|
93487
|
-
verified:
|
|
95298
|
+
verified: isPro2 ? {
|
|
93488
95299
|
url: getBadgeUrl(projectId, style, true),
|
|
93489
95300
|
markdown: getMarkdownEmbed(projectId, style, true),
|
|
93490
95301
|
html: getHtmlEmbed(projectId, style, true)
|
|
@@ -93500,14 +95311,14 @@ async function badgeCommand(options) {
|
|
|
93500
95311
|
console.log("");
|
|
93501
95312
|
console.log(chalk9.cyan(" " + badges.basic.markdown));
|
|
93502
95313
|
console.log("");
|
|
93503
|
-
if (
|
|
95314
|
+
if (isPro2 && badges.verified) {
|
|
93504
95315
|
console.log(chalk9.bold(" \u2705 Verified Badge ") + chalk9.dim("(Pro)"));
|
|
93505
95316
|
console.log("");
|
|
93506
95317
|
console.log(chalk9.dim(" Shows verified status with detailed score:"));
|
|
93507
95318
|
console.log("");
|
|
93508
95319
|
console.log(chalk9.cyan(" " + badges.verified.markdown));
|
|
93509
95320
|
console.log("");
|
|
93510
|
-
} else if (!
|
|
95321
|
+
} else if (!isPro2) {
|
|
93511
95322
|
console.log("");
|
|
93512
95323
|
console.log(chalk9.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
93513
95324
|
console.log("");
|
|
@@ -93544,7 +95355,7 @@ init_scoring();
|
|
|
93544
95355
|
init_truthpack();
|
|
93545
95356
|
|
|
93546
95357
|
// ../../packages/core/dist/firewall/index.js
|
|
93547
|
-
|
|
95358
|
+
init_chunk_4MEEGNJS();
|
|
93548
95359
|
init_chunk_DFJL4MLU();
|
|
93549
95360
|
init_chunk_SKXQ6JUA();
|
|
93550
95361
|
init_chunk_4EQXFW4J();
|
|
@@ -93643,7 +95454,7 @@ async function certifyCommand(options) {
|
|
|
93643
95454
|
result.verdict = result.score >= threshold ? "CERTIFIED" : result.score >= 70 ? "NEEDS_WORK" : "NOT_READY";
|
|
93644
95455
|
result.passed = result.verdict === "CERTIFIED";
|
|
93645
95456
|
result.duration = Date.now() - startTime;
|
|
93646
|
-
result.proofBundlePath = await
|
|
95457
|
+
result.proofBundlePath = await generateProofBundle2(context, result, projectRoot);
|
|
93647
95458
|
if (result.passed) {
|
|
93648
95459
|
const outputDir = options.output ?? path18__default.join(projectRoot, ".vibecheck", "certification");
|
|
93649
95460
|
result.certificatePath = await generateCertificate(context, result, outputDir);
|
|
@@ -94097,7 +95908,7 @@ function generateBadgeUrl(projectId, score) {
|
|
|
94097
95908
|
const label = score >= 85 ? "certified" : "score";
|
|
94098
95909
|
return `https://img.shields.io/badge/VibeCheck-${label}%20${score}%25-${color}`;
|
|
94099
95910
|
}
|
|
94100
|
-
async function
|
|
95911
|
+
async function generateProofBundle2(context, result, projectRoot) {
|
|
94101
95912
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
94102
95913
|
const bundleName = `proof_${timestamp}`;
|
|
94103
95914
|
const proofsDir = path18__default.join(projectRoot, ".vibecheck", "proofs");
|
|
@@ -94348,22 +96159,25 @@ async function realityRunCommand(options) {
|
|
|
94348
96159
|
const startTime = Date.now();
|
|
94349
96160
|
const runId = nanoid(12);
|
|
94350
96161
|
try {
|
|
94351
|
-
const
|
|
94352
|
-
if (
|
|
96162
|
+
const entitlements = await checkEntitlements();
|
|
96163
|
+
if (!entitlements.isPro) {
|
|
94353
96164
|
if (options.json) {
|
|
94354
96165
|
console.log(JSON.stringify({
|
|
94355
96166
|
success: false,
|
|
94356
96167
|
error: "Pro feature required",
|
|
94357
|
-
|
|
94358
|
-
|
|
96168
|
+
code: "UPGRADE_REQUIRED",
|
|
96169
|
+
entitlement: "reality_mode",
|
|
96170
|
+
message: "Reality Mode requires Pro. Upgrade to unlock runtime verification.",
|
|
96171
|
+
upgradeUrl: "https://app.vibecheck.dev/checkout?plan=pro"
|
|
94359
96172
|
}, null, 2));
|
|
94360
96173
|
} else {
|
|
94361
96174
|
logger2.error("");
|
|
94362
|
-
logger2.error(colors.error(" Reality Mode
|
|
96175
|
+
logger2.error(colors.error(" Reality Mode requires Pro"));
|
|
94363
96176
|
logger2.error("");
|
|
94364
|
-
logger2.error(colors.muted(" Runtime verification with proof bundles requires Pro
|
|
96177
|
+
logger2.error(colors.muted(" Runtime verification with proof bundles requires Pro."));
|
|
94365
96178
|
logger2.error("");
|
|
94366
|
-
logger2.error(colors.info(" Upgrade
|
|
96179
|
+
logger2.error(colors.info(" Upgrade: vibecheck upgrade"));
|
|
96180
|
+
logger2.error(colors.info(" Or visit: https://app.vibecheck.dev/checkout?plan=pro"));
|
|
94367
96181
|
logger2.error("");
|
|
94368
96182
|
}
|
|
94369
96183
|
process.exit(1);
|
|
@@ -95027,8 +96841,7 @@ async function findLatestProofBundle() {
|
|
|
95027
96841
|
return bundles.length > 0 ? bundles[0].name : null;
|
|
95028
96842
|
}
|
|
95029
96843
|
async function openReplayViewer(bundlePath, runId, logger2, options) {
|
|
95030
|
-
const
|
|
95031
|
-
const hasFull = currentTier === "pro" || currentTier === "enterprise";
|
|
96844
|
+
const hasFull = isProSync();
|
|
95032
96845
|
if (!hasFull && !options.json) {
|
|
95033
96846
|
console.log("");
|
|
95034
96847
|
console.log(chalk9.cyan("\u2713") + " Replay viewer available");
|
|
@@ -95036,7 +96849,7 @@ async function openReplayViewer(bundlePath, runId, logger2, options) {
|
|
|
95036
96849
|
console.log(chalk9.dim(" Free tier: Basic run summary"));
|
|
95037
96850
|
console.log(chalk9.dim(" Pro tier: Full video + timeline + request trace"));
|
|
95038
96851
|
console.log("");
|
|
95039
|
-
console.log(chalk9.dim(` Upgrade:
|
|
96852
|
+
console.log(chalk9.dim(` Upgrade: vibecheck upgrade`));
|
|
95040
96853
|
console.log("");
|
|
95041
96854
|
}
|
|
95042
96855
|
const existingReport = path18__default.join(bundlePath, "report.html");
|