diff --git a/README.md b/README.md index f62139bf..edb423e8 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Everything stays on your machine: loopback-only bind, host-header enforcement, C The same engine runs headless for CI pipelines. SARIF output uploads directly to GitHub Code Scanning. -

nyx scan console output: HIGH taint findings across a JS and Python file with source → sink arrows

+

nyx scan console output: HIGH taint findings across a JS and Python file with source → sink arrows

```bash # Fail the job on medium or higher, emit SARIF diff --git a/assets/nyx-wordmark.svg b/assets/nyx-wordmark.svg index b989eb3c..d37fc586 100644 --- a/assets/nyx-wordmark.svg +++ b/assets/nyx-wordmark.svg @@ -6,5 +6,5 @@ font-weight="700" font-size="100" letter-spacing="-1" - fill="#5856d6">nyx + fill="#72f3d7">nyx diff --git a/assets/screenshots/cli-scan.gif b/assets/screenshots/cli-scan.gif index 7d3af3ab..83b370b7 100644 Binary files a/assets/screenshots/cli-scan.gif and b/assets/screenshots/cli-scan.gif differ diff --git a/assets/screenshots/cli-scan.png b/assets/screenshots/cli-scan.png index a30e7771..dc108a63 100644 Binary files a/assets/screenshots/cli-scan.png and b/assets/screenshots/cli-scan.png differ diff --git a/assets/screenshots/cli-scan_raw.gif b/assets/screenshots/cli-scan_raw.gif index 12030add..abbc9a96 100644 Binary files a/assets/screenshots/cli-scan_raw.gif and b/assets/screenshots/cli-scan_raw.gif differ diff --git a/assets/screenshots/cli-scan_raw.png b/assets/screenshots/cli-scan_raw.png index ef68b052..6917c7f1 100644 Binary files a/assets/screenshots/cli-scan_raw.png and b/assets/screenshots/cli-scan_raw.png differ diff --git a/assets/screenshots/demo.gif b/assets/screenshots/demo.gif index 90dcdaac..035e61f8 100644 Binary files a/assets/screenshots/demo.gif and b/assets/screenshots/demo.gif differ diff --git a/assets/screenshots/demo_raw.gif b/assets/screenshots/demo_raw.gif index 27fcfa47..497bde35 100644 Binary files a/assets/screenshots/demo_raw.gif and b/assets/screenshots/demo_raw.gif differ diff --git a/assets/screenshots/docs/cli-configshow.png b/assets/screenshots/docs/cli-configshow.png index f75d2c2b..7e6d28f0 100644 Binary files a/assets/screenshots/docs/cli-configshow.png and b/assets/screenshots/docs/cli-configshow.png differ diff --git a/assets/screenshots/docs/cli-explain-engine.png b/assets/screenshots/docs/cli-explain-engine.png index 5483463a..ce90f8f8 100644 Binary files a/assets/screenshots/docs/cli-explain-engine.png and b/assets/screenshots/docs/cli-explain-engine.png differ diff --git a/assets/screenshots/docs/cli-failon.png b/assets/screenshots/docs/cli-failon.png index a30e7771..dc108a63 100644 Binary files a/assets/screenshots/docs/cli-failon.png and b/assets/screenshots/docs/cli-failon.png differ diff --git a/assets/screenshots/docs/cli-failon_raw.png b/assets/screenshots/docs/cli-failon_raw.png index ef68b052..6917c7f1 100644 Binary files a/assets/screenshots/docs/cli-failon_raw.png and b/assets/screenshots/docs/cli-failon_raw.png differ diff --git a/assets/screenshots/docs/cli-idxstatus.png b/assets/screenshots/docs/cli-idxstatus.png index 54630758..87e7ef17 100644 Binary files a/assets/screenshots/docs/cli-idxstatus.png and b/assets/screenshots/docs/cli-idxstatus.png differ diff --git a/assets/screenshots/docs/cli-idxstatus_raw.png b/assets/screenshots/docs/cli-idxstatus_raw.png index 9dc03154..25f09ccf 100644 Binary files a/assets/screenshots/docs/cli-idxstatus_raw.png and b/assets/screenshots/docs/cli-idxstatus_raw.png differ diff --git a/assets/screenshots/docs/cli-rollup-tail.png b/assets/screenshots/docs/cli-rollup-tail.png index 8e6a0662..83050fe7 100644 Binary files a/assets/screenshots/docs/cli-rollup-tail.png and b/assets/screenshots/docs/cli-rollup-tail.png differ diff --git a/assets/screenshots/docs/serve-config.png b/assets/screenshots/docs/serve-config.png index ca68319c..04c405c9 100644 Binary files a/assets/screenshots/docs/serve-config.png and b/assets/screenshots/docs/serve-config.png differ diff --git a/assets/screenshots/docs/serve-config_raw.png b/assets/screenshots/docs/serve-config_raw.png index 159b00ee..64bdceed 100644 Binary files a/assets/screenshots/docs/serve-config_raw.png and b/assets/screenshots/docs/serve-config_raw.png differ diff --git a/assets/screenshots/docs/serve-explorer.png b/assets/screenshots/docs/serve-explorer.png index f5494b23..4b4c725b 100644 Binary files a/assets/screenshots/docs/serve-explorer.png and b/assets/screenshots/docs/serve-explorer.png differ diff --git a/assets/screenshots/docs/serve-explorer_raw.png b/assets/screenshots/docs/serve-explorer_raw.png index d2c6658c..3bbffd41 100644 Binary files a/assets/screenshots/docs/serve-explorer_raw.png and b/assets/screenshots/docs/serve-explorer_raw.png differ diff --git a/assets/screenshots/docs/serve-finding-detail.png b/assets/screenshots/docs/serve-finding-detail.png index a5ca2fb1..067b7081 100644 Binary files a/assets/screenshots/docs/serve-finding-detail.png and b/assets/screenshots/docs/serve-finding-detail.png differ diff --git a/assets/screenshots/docs/serve-finding-detail_raw.png b/assets/screenshots/docs/serve-finding-detail_raw.png index c3a896db..46d81650 100644 Binary files a/assets/screenshots/docs/serve-finding-detail_raw.png and b/assets/screenshots/docs/serve-finding-detail_raw.png differ diff --git a/assets/screenshots/docs/serve-findings-list.png b/assets/screenshots/docs/serve-findings-list.png index 882fdfb6..ebe6e80f 100644 Binary files a/assets/screenshots/docs/serve-findings-list.png and b/assets/screenshots/docs/serve-findings-list.png differ diff --git a/assets/screenshots/docs/serve-findings-list_raw.png b/assets/screenshots/docs/serve-findings-list_raw.png index 1c7d771a..c2106df9 100644 Binary files a/assets/screenshots/docs/serve-findings-list_raw.png and b/assets/screenshots/docs/serve-findings-list_raw.png differ diff --git a/assets/screenshots/docs/serve-overview.png b/assets/screenshots/docs/serve-overview.png index 7d0c161e..a7496753 100644 Binary files a/assets/screenshots/docs/serve-overview.png and b/assets/screenshots/docs/serve-overview.png differ diff --git a/assets/screenshots/docs/serve-overview_raw.png b/assets/screenshots/docs/serve-overview_raw.png index 5447a5a5..1f3a2e6b 100644 Binary files a/assets/screenshots/docs/serve-overview_raw.png and b/assets/screenshots/docs/serve-overview_raw.png differ diff --git a/assets/screenshots/docs/serve-rules.png b/assets/screenshots/docs/serve-rules.png index 1f32a4be..f0dadd14 100644 Binary files a/assets/screenshots/docs/serve-rules.png and b/assets/screenshots/docs/serve-rules.png differ diff --git a/assets/screenshots/docs/serve-rules_raw.png b/assets/screenshots/docs/serve-rules_raw.png index 9f248c78..5a41e1cc 100644 Binary files a/assets/screenshots/docs/serve-rules_raw.png and b/assets/screenshots/docs/serve-rules_raw.png differ diff --git a/assets/screenshots/docs/serve-scan-detail.png b/assets/screenshots/docs/serve-scan-detail.png index 312a7f36..a520d5bc 100644 Binary files a/assets/screenshots/docs/serve-scan-detail.png and b/assets/screenshots/docs/serve-scan-detail.png differ diff --git a/assets/screenshots/docs/serve-scan-detail_raw.png b/assets/screenshots/docs/serve-scan-detail_raw.png index 9531a857..acb0e013 100644 Binary files a/assets/screenshots/docs/serve-scan-detail_raw.png and b/assets/screenshots/docs/serve-scan-detail_raw.png differ diff --git a/assets/screenshots/docs/serve-scans.png b/assets/screenshots/docs/serve-scans.png index 7b73c602..710a7dbc 100644 Binary files a/assets/screenshots/docs/serve-scans.png and b/assets/screenshots/docs/serve-scans.png differ diff --git a/assets/screenshots/docs/serve-scans_raw.png b/assets/screenshots/docs/serve-scans_raw.png index 9d48ff22..72a14aab 100644 Binary files a/assets/screenshots/docs/serve-scans_raw.png and b/assets/screenshots/docs/serve-scans_raw.png differ diff --git a/assets/screenshots/docs/serve-triage.png b/assets/screenshots/docs/serve-triage.png index c40dfa8c..d5502934 100644 Binary files a/assets/screenshots/docs/serve-triage.png and b/assets/screenshots/docs/serve-triage.png differ diff --git a/assets/screenshots/docs/serve-triage_raw.png b/assets/screenshots/docs/serve-triage_raw.png index ce266957..a60aeef2 100644 Binary files a/assets/screenshots/docs/serve-triage_raw.png and b/assets/screenshots/docs/serve-triage_raw.png differ diff --git a/assets/screenshots/explorer.png b/assets/screenshots/explorer.png index 44f62968..a83f2f59 100644 Binary files a/assets/screenshots/explorer.png and b/assets/screenshots/explorer.png differ diff --git a/assets/screenshots/finding-detail.png b/assets/screenshots/finding-detail.png index 90ae41cd..ec9459d0 100644 Binary files a/assets/screenshots/finding-detail.png and b/assets/screenshots/finding-detail.png differ diff --git a/assets/screenshots/overview.png b/assets/screenshots/overview.png index 7d0c161e..a7496753 100644 Binary files a/assets/screenshots/overview.png and b/assets/screenshots/overview.png differ diff --git a/assets/screenshots/triage.png b/assets/screenshots/triage.png index c6807db6..e711acd8 100644 Binary files a/assets/screenshots/triage.png and b/assets/screenshots/triage.png differ diff --git a/docs/quickstart.md b/docs/quickstart.md index d1858910..1cdfbe3f 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -10,7 +10,7 @@ First run builds a SQLite index under `.nyx/`; later runs skip files whose conte ## What a finding looks like -

nyx scan output: HIGH taint flows from req.params.user, req.query.url, and req.query.path into exec/fetch/fs.readFileSync, framed by the brand purple gradient

+

nyx scan output: HIGH taint flows from req.params.user, req.query.url, and req.query.path into exec/fetch/fs.readFileSync, framed by the brand mint-cyan gradient

The same scan in console form: diff --git a/frontend/src/graph/styles.ts b/frontend/src/graph/styles.ts index 45181d16..52b89a93 100644 --- a/frontend/src/graph/styles.ts +++ b/frontend/src/graph/styles.ts @@ -25,8 +25,8 @@ const FALLBACK_PALETTE: GraphThemePalette = { textTertiary: '#9b9ba7', border: '#e5e5ea', borderLight: '#f0f0f4', - accent: '#5856d6', - accentSoft: '#ededfc', + accent: '#72f3d7', + accentSoft: 'rgba(114, 243, 215, 0.16)', success: '#2ecc71', warning: '#e67e22', danger: '#e74c3c', diff --git a/frontend/src/pages/OverviewPage.tsx b/frontend/src/pages/OverviewPage.tsx index 6660ec53..e10e6654 100644 --- a/frontend/src/pages/OverviewPage.tsx +++ b/frontend/src/pages/OverviewPage.tsx @@ -64,7 +64,7 @@ export function OverviewPage() { const categoryItems = (overview.issue_categories || []) .slice(0, 8) - .map((b) => ({ label: b.label, value: b.count, color: '#5856d6' })); + .map((b) => ({ label: b.label, value: b.count, color: '#72f3d7' })); const trendData = (trends || []).map((t) => ({ label: t.timestamp, diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 12bff2f7..399b42c6 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -9,8 +9,9 @@ --text-tertiary: #6e6e7a; --border: #e5e5ea; --border-light: #f0f0f4; - --accent: #5856d6; - --accent-light: #ededfc; + --accent: #72f3d7; + --accent-light: rgba(114, 243, 215, 0.16); + --accent-contrast: #063c35; --sev-high: #e74c3c; --sev-high-bg: #fdf0ef; --sev-medium: #e67e22; @@ -479,7 +480,7 @@ tr:hover td { } .btn-primary { background: var(--accent); - color: #fff; + color: var(--accent-contrast); border-color: var(--accent); } .btn-primary:hover { @@ -4379,7 +4380,7 @@ tr.selected td { } .mode-btn.active { background: var(--accent); - color: #fff; + color: var(--accent-contrast); } /* File tree */ @@ -4556,7 +4557,7 @@ tr.selected td { .explorer-inline-notice { padding: var(--space-2) var(--space-3); border-radius: var(--radius); - background: rgba(88, 86, 214, 0.08); + background: rgba(114, 243, 215, 0.16); color: var(--text-secondary); font-size: var(--text-sm); } @@ -5295,7 +5296,7 @@ tr.selected td { background: radial-gradient( circle at top left, - rgba(88, 86, 214, 0.08), + rgba(114, 243, 215, 0.16), transparent 28% ), linear-gradient(180deg, var(--bg), var(--bg-secondary)); @@ -5482,7 +5483,7 @@ tr.selected td { } .ssa-phi-section { padding: var(--space-1) var(--space-3); - background: rgba(88, 86, 214, 0.05); + background: rgba(114, 243, 215, 0.12); border-bottom: 1px solid var(--border); } .ssa-body-section { @@ -5566,7 +5567,7 @@ tr.selected td { color: var(--success); } .cap-badge-sanitizer { - background: rgba(88, 86, 214, 0.1); + background: rgba(114, 243, 215, 0.16); color: var(--accent); } .cap-badge-sink { @@ -5932,8 +5933,9 @@ tr.selected td { --text-tertiary: #7c7f88; --border: #2a2c33; --border-light: #1f2128; - --accent: #7d7afa; - --accent-light: #2a2756; + --accent: #72f3d7; + --accent-light: rgba(114, 243, 215, 0.16); + --accent-contrast: #063c35; --sev-high: #f06860; --sev-high-bg: #2c1716; --sev-medium: #f0a05a; @@ -5972,6 +5974,7 @@ tr.selected td { --border-light: #4a4a4a; --accent: #0000c8; --accent-light: #d8d8ff; + --accent-contrast: #ffffff; --sev-high: #b30000; --sev-high-bg: #ffe0e0; --sev-medium: #8a3b00; @@ -6010,6 +6013,7 @@ tr.selected td { --border-light: #b8b8b8; --accent: #8ab4ff; --accent-light: #1a2540; + --accent-contrast: #000000; --sev-high: #ff8a80; --sev-high-bg: #3a0000; --sev-medium: #ffc266; diff --git a/scripts/README.md b/scripts/README.md index 588901c2..0077e3c0 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -8,7 +8,7 @@ Local helpers for repo-wide checks and a couple of one-off tools. | `check.sh` | Verify only (no fixes). Mirrors the GitHub Actions CI workflow. | | `cached-cargo-test.sh` | Wrap `cargo test` with a source-hash cache; concurrent invocations of the same args share one run. | | `capture-screenshots.mjs`| Capture the README stills and demo GIF from a running `nyx serve`. Needs Playwright and ffmpeg. | -| `frame-screenshots.py` | Wrap a PNG in the brand purple gradient. Called by `capture-screenshots.mjs` as its final phase, but can be run standalone. | +| `frame-screenshots.py` | Wrap a PNG in the brand mint-cyan gradient. Called by `capture-screenshots.mjs` as its final phase, but can be run standalone. | Fixers stream their output (so you can see what changed); tests run quietly and only show output if they fail. Both scripts print a green/red summary at the end @@ -73,8 +73,9 @@ Stills are captured in two phases: `serve-scan-detail.png`, `serve-rules.png`, `serve-config.png`. Then `frame-screenshots.py` runs over every captured PNG and wraps it in -the brand purple gradient (1800x1113 outer, 1600x992 inner, 12px rounded -corners, top-left `#8a5bf5` to bottom-right `#4d1d97`). Finally, +the brand mint-led four-corner gradient (1800x1113 outer, 1600x992 inner, +12px rounded corners: TL `#72f3d7`, TR `#ff6aa2`, BL `#f8c56b`, BR +`#4cc9ff`). Finally, `docs/serve-overview.png` is copied to the top-level `overview.png` because that is the path the README references. diff --git a/scripts/capture-screenshots.mjs b/scripts/capture-screenshots.mjs index 77731cc2..b53b2d3a 100755 --- a/scripts/capture-screenshots.mjs +++ b/scripts/capture-screenshots.mjs @@ -21,7 +21,7 @@ * two-scan history (overview trend, scans list, * scan detail) plus the static-ish ones * (triage, explorer, rules, config) - * 7. frame — composite the brand purple gradient around every + * 7. frame — composite the brand mint-cyan gradient around every * captured PNG via scripts/frame-screenshots.py * * Prerequisites (script asserts each before starting): @@ -575,7 +575,7 @@ function applyFrames(captured, { natural = false } = {}) { if (paths.length === 0) return; saveRawCopies(paths); const label = natural ? 'natural-size' : 'fixed'; - console.error(`[frame] applying purple gradient frame (${label}) to ${paths.length} files`); + console.error(`[frame] applying mint-led four-corner frame (${label}) to ${paths.length} files`); const args = natural ? ['--natural', ...paths] : paths; execFileSync('python3', [FRAMER, ...args], { stdio: 'inherit' }); // Mirror the framed serve-overview.png to the top-level path the diff --git a/scripts/frame-screenshots.py b/scripts/frame-screenshots.py index 7ba354c4..ee388dee 100644 --- a/scripts/frame-screenshots.py +++ b/scripts/frame-screenshots.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -"""Frame Nyx screenshots with the brand purple gradient. +"""Frame Nyx screenshots with the brand mint-led four-corner gradient. Reads a list of PNG paths from argv (or all PNGs under assets/screenshots/ if no args) and overwrites each with a framed version: inner screenshot with rounded corners, centered on a -diagonal purple gradient (top-left #8a5bf5 → bottom-right #4d1d97). +four-corner mint-led gradient (TL #72f3d7, TR #ff6aa2, +BL #f8c56b, BR #4cc9ff). Two framing modes: - default inner is resampled to 1600x992, outer is 1800x1113. @@ -37,14 +38,12 @@ PAD_R = OUTER_W - INNER_W - PAD_L # 100 PAD_B = OUTER_H - INNER_H - PAD_T # 61 CORNER_RADIUS = 12 -# Four-corner bilinear gradient. Sampled from the existing CLI -# screenshots so every framed asset matches: top-left is the lightest -# (Tailwind violet-500), the off-diagonal corners are violet-600, and -# bottom-right is violet-900. -GRAD_TL = (139, 92, 246) # #8b5cf6 violet-500 -GRAD_TR = (124, 58, 237) # #7c3aed violet-600 -GRAD_BL = (124, 58, 237) # #7c3aed violet-600 -GRAD_BR = ( 76, 29, 149) # #4c1d95 violet-900 +# Four-corner bilinear gradient. The primary brand accent anchors the +# frame, with distinct warm/cool corners for richer screenshot depth. +GRAD_TL = (114, 243, 215) # #72f3d7 +GRAD_TR = (255, 106, 162) # #ff6aa2 +GRAD_BL = (248, 197, 107) # #f8c56b +GRAD_BR = ( 76, 201, 255) # #4cc9ff def make_gradient(w: int, h: int) -> Image.Image: @@ -135,7 +134,7 @@ def frame_one(src: Path, natural: bool = False) -> None: def frame_gif(src: Path) -> None: """Frame an animated GIF in place: every frame gets the same - purple gradient frame, then the result is re-encoded as a single- + mint-cyan gradient frame, then the result is re-encoded as a single- palette GIF. Calls ffmpeg for the final encode (Pillow's GIF output is noticeably worse for large animations). """ diff --git a/src/fmt.rs b/src/fmt.rs index 829a2f71..cbf585bd 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -177,7 +177,10 @@ pub fn render_welcome() -> String { out.push('\n'); for line in LOGO { - out.push_str(&format!(" {}\n", style(line).color256(141).bold())); + out.push_str(&format!( + " {}\n", + style(line).true_color(114, 243, 215).bold() + )); } out.push_str(&format!( diff --git a/src/symex/smt.rs b/src/symex/smt.rs index 0feb62b1..ca6a9414 100644 --- a/src/symex/smt.rs +++ b/src/symex/smt.rs @@ -54,7 +54,7 @@ use super::state::{PathConstraint, SymbolicState}; const MAX_SMT_QUERIES_PER_FINDING: u32 = 10; /// Per-query timeout in milliseconds (integer-only queries). -const SMT_QUERY_TIMEOUT_MS: u32 = 100; +const SMT_QUERY_TIMEOUT_MS: u32 = 500; /// Per-query timeout for queries involving string theory (ms). /// String theory (especially lexicographic ordering) is more expensive. @@ -114,6 +114,18 @@ enum Z3Expr { /// Variable map: SSA value → Z3 variable with implicit sort. type VarMap = HashMap; +/// Pay bundled Z3 static-init cost once per process so the first real +/// `check_path_feasibility()` call doesn't blow the per-query timeout. +fn warm_z3() { + static WARM: std::sync::OnceLock<()> = std::sync::OnceLock::new(); + WARM.get_or_init(|| { + let cfg = Config::new(); + z3::with_z3_config(&cfg, || { + let _ = Solver::new().check(); + }); + }); +} + // ───────────────────────────────────────────────────────────────────────────── // SmtContext // ───────────────────────────────────────────────────────────────────────────── @@ -124,7 +136,10 @@ impl SmtContext { SmtContext { cfg: Config::new(), queries_used: 0, + #[cfg(not(test))] timeout_ms: SMT_QUERY_TIMEOUT_MS, + #[cfg(test)] + timeout_ms: 5_000, } } @@ -153,6 +168,7 @@ impl SmtContext { return SmtResult::BudgetExhausted; } self.queries_used += 1; + warm_z3(); // Use with_z3_config to create a scoped Z3 context for this query. let base_timeout_ms = self.timeout_ms;