تخطٍّ إلى المحتوى

ما الجديد

سجل إصدارًا بإصدار لتطوير Fendix. صدر الإصدار v3.4.1 في سبتمبر 2026 — تُبنى صور المحرك الآن بلغة Go 1.27 وتشحن بها، فيرتفع سقف الوحدات المدعومة في govulncheck من 1.25؛ ولا تغييرات في الفاحصات أو البصمات أو رموز الخروج، ويبقى الحد الأدنى لإصدار وحدات Go عند 1.25. وفي v3.4.0 — لم يعد بالإمكان أن يبدو المسح مكتملًا وهو ليس كذلك: يسجّل كل محلل ما إذا كان قد عمل ولماذا لم يعمل، ويحمل التقرير كتلة تغطية تسمّي الفجوات، ويكتب مسح URL الذي لا يجد نقاط نهاية تقريره بدل أن يختفي، وتحوّل رايتان اختياريتان فجوة التغطية إلى بناء مُخفق. وفي v3.3.0 — لم تعد الترقية تقسم النتيجة التي تتابعها إلى مغلقة وجديدة، وصارت قائمة الفحوص تُبنى مما اكتمل لا مما جرى إعداده. وفي v3.2.0 — وفيه صار كل قرار حظر يشرح نفسه. تحمل نتيجة BLOCK الآن السياسة التي اتُّخذت بموجبها وصنف الدليل الذي برّرها، عبر تخزين Fendix نفسه وحتى ملف SARIF الذي تصدّره، فيصير خط الإنتاج المخفق قابلًا للتفسير من التقرير وحده. وتذكر النتائج المحجوزة سبب حجزها، وتأتي درجات الثقة مصحوبة بالقواعد التي أنتجتها، ويُوسم صراحةً أي بناء حُظر لمجرد أن فرض الثقة كان مُعطَّلًا. وأوقف الإصدار v3.1.0 ادعاء النتائج بأكثر مما أثبتته — من CORS بحرف بدل مع بيانات الاعتماد، إلى ترتيب أولويات تحديد المعدّل، وتقييم الترويسات بحسب نوع الاستجابة، وصياغة اجتياز المسارات، وبيانات الاعتماد الاختبارية، وقابلية تطبيق الاعتماديات. ومنح الإصدار v3.0 النتائج هوية مستقرة مبنية على القاعدة والملف والرمز والعملية بدل رقم السطر؛ أعد حفظ خطوط الأساس مرة واحدة بعد الترقية من إصدار أقدم منه.

Go 1.27 in the images

September 2026

  • The engine images build with and ship Go 1.27, so govulncheck loads any module whose go.mod requires Go 1.27 or older; the earlier ceiling was 1.25.
  • No scanner, fingerprint or exit-code changes. The Go module floor stays 1.25.
  • Hosted scans: release policy 2.0.0 is live — every whitebox analyzer is required, coverage gaps are owned and refunded once, and the verdict wording is the same in the app, the PR check, email and Slack.

A scan can no longer look complete when it wasn't

September 2026

  • Every analyzer now says whether it ran, and if not, why. Endpoint discovery, the spec parser, active probes, secrets, textscan, semgrep, govulncheck, pip, npm, the Python engine and each of its checks, and plugins are recorded once per scan in a fixed order with a closed, machine-readable reason: not applicable to this target, disabled by a flag you passed, a missing dependency in the environment, a target the analyzer does not support, or a failure with its cause. A scanner that was quietly absent from a report can no longer be mistaken for one that ran clean.
  • The report states its own coverage. A new metadata.coverage block says whether everything the run was configured to execute actually ran, names the gaps, lists the limitations, and records anything that was retried. Consumers that used to check only for a failed entry should read coverage.configured_complete instead: a missing dependency is a skip, and it is a gap.
  • A URL scan that finds zero endpoints writes its report instead of vanishing. It still exits 2, so scripts see the same code, but the report now exists with discovery recorded as failed/no_endpoints — Fendix Cloud used to store that case as a clean scan.
  • Two opt-in flags turn a coverage gap into a failing build. --fail-on-coverage-gap exits 2 when something the run was configured to execute was unavailable or failed; --require-analyzers a,b exits 2 when a named analyzer was not delivered, and a required analyzer disabled by another flag is reported as the contradiction it is. Both are off by default; nothing about the default exit codes changed.
  • A transient network failure in a dependency scanner is retried once, in process. govulncheck, pip and npm get one re-invocation on a network error or timeout, and the entry says attempts: 2. Nothing else is retried and the engine never re-runs itself.
  • Coverage is visible in every format. SARIF lists every analyzer that did not run as a tool notification and carries the coverage block; HTML and PDF reports show a coverage table under the verdict; the scan-end summary on the terminal is now that same table.
  • The Docker image ships a Go toolchain, so govulncheck runs inside it. Every earlier image recorded govulncheck as failed on any Go repository because the go command it depends on was not there. Module resolution uses Go's default proxy; set GOPRIVATE for private modules.
  • Two report semantics were corrected. pip with no manifest is skipped/not_applicable, not ok; an npm package.json without a lockfile is skipped/unsupported_target. Neither is a coverage gap; both stop confusing "nothing to scan" with "scanned clean".

An upgrade stops splitting your findings in two

September 2026

  • A finding you were already tracking is recognised after the identity change, instead of arriving as one closed issue and one new one. When finding identity moved in v3.0, anything tracking Fendix findings had no way to tell that the finding it knew and the finding it now saw were the same one — so one vulnerability could become two records, with two ids and two histories. Reports now carry the retired identity alongside the current one, purely so a consumer can join the two. It is a migration bridge and nothing scores or filters on it; the current identity is unchanged, so saved baselines and .fendix-ignore fingerprint rules keep matching exactly as before.
  • The list of checks a scan ran no longer includes checks it skipped. A report could name a scanner under checks_run while, in the same document, recording that the scanner never ran — because the list was built from what the scan was configured to do rather than from what it did. It is now built from what actually completed. You may see fewer entries than before on scans where a scanner was unavailable; that is the list becoming accurate, not coverage shrinking. What a scan actually covered, and every release decision made from it, are unchanged.

Every blocking decision explains itself

August 2026

  • A blocked build now tells you why, in the report itself. A BLOCK used to arrive in your SARIF as little more than the word BLOCK once it had been through Fendix's own storage and re-rendering — the reasoning existed, but not everywhere you could read it. Every finding now carries the decision, the policy it was made under, and the specific evidence that justified it, and the JSON and SARIF reports say exactly the same thing. You can answer "why did this fail my pipeline?" without opening Fendix.
  • You can see which evidence class allowed a block. A dependency blocked on a deterministic match in production code, a vulnerability blocked because user input provably reaches the dangerous call, and a finding blocked because two independent signals agreed are three different claims — and they now read as three different claims rather than one undifferentiated verdict.
  • A finding held back says why it was held back. "Held at WARN because nothing corroborates it", "the vulnerable component is never imported", "this credential is test fixture data" — each is now a stable machine-readable reason, not a sentence you would have had to parse.
  • Confidence scores are explainable line by line. Each score comes with the rules that produced it and what each contributed, so a 45 and a 75 are no longer just numbers.
  • A relaxed gate can no longer be mistaken for a normal one. If a build was blocked only because confidence enforcement was switched off, the report says so. Findings that do not block are no longer mislabelled as though they did.

Findings claim only what they proved

August 2026

  • A wildcard CORS policy with credentials is reported as a misconfiguration, not an exploit. Browsers reject that combination outright, so it can never produce the authenticated cross-origin read the CRITICAL rating was claiming. It is now MEDIUM and no longer fails a build. Origin reflection with credentials — the shape that genuinely is account-takeover grade — is unchanged.
  • Missing rate limiting is ranked by what abusing the endpoint is worth. One flat severity across a large API asserted that an unlimited login and an unlimited list read deserved equal urgency. Login, identity and expensive unauthenticated operations stay prominent; ordinary reads drop to informational.
  • Browser security headers are judged against the response they are on. A JSON API response is not a browser document, so a missing Content-Security-Policy on one is no longer graded as though it were.
  • A dynamic file path is no longer reported as a proven path traversal. Building a path from a variable is worth flagging; it is not the same claim as demonstrating traversal, and the wording now reflects that.
  • Obvious test credentials stop being treated as leaks. When both the location and the value agree that a string is fixture data, it is reported as informational. A real provider-issued secret is never de-escalated, wherever it sits.
  • An unresolved import is no longer read as proof a dependency is unused. Not being able to tell is different from knowing it is safe, and only positive evidence of non-use now lowers a dependency finding.

Semgrep findings hold still

August 2026

  • Every Semgrep finding was getting a brand-new identity on each scan. Its identity carried an internal temporary path that changed every single run, so a baseline or a suppression never matched it again — even when nothing in your code had changed at all. Semgrep findings now keep the same identity from one scan to the next, like every other finding.
  • Every unprotected route is its own finding again. Five Flask routes missing an auth decorator were collapsing into one finding, so suppressing the one you had reviewed silently suppressed the four you had not. Separately, these findings were showing "requires login" as their evidence — a placeholder Semgrep returns when it is not signed in — instead of the line of code that actually matched. You now see the code.

Older reports keep their own identity scheme

August 2026

  • Re-exporting a report saved before v3.0.0 labelled it with the new identity scheme while it still carried the old values. A tool reading that export could match those identities against the wrong things. A report now always declares which scheme its own identities were produced under, so old and new exports can never be confused for one another.

A finding keeps its identity when your code moves

August 2026

  • Adding a comment above a vulnerability used to turn it into a different vulnerability. A finding was identified partly by the line it sat on, so any edit above it gave it a new identity: your baseline stopped recognising it, your .fendix-ignore rule stopped suppressing it, and something you had already triaged came back as new work. Findings are now identified by what they are — which rule fired, in which file, in which function, about which operation — and not by where they happen to sit today. Scanned before and after an edit that moved every line of the file, every finding was still recognised; the old scheme lost roughly a quarter of them and reported the same issues over again as brand-new.
  • Findings no longer claim more than they proved. A path-traversal finding said "user input flows to filesystem path" even when Fendix had only seen the filesystem call and could not trace any user input reaching it. A fully proven SSRF, meanwhile, still described itself as "potential". The wording now follows the evidence: "Potential" when only the dangerous operation was observed, and a plain statement when the path from user input was actually traced. The finding does not change identity when its wording strengthens — it is the same issue, better understood.
  • GitHub now shows what Fendix actually believes about a finding. A placeholder API key in a test fixture — scored low-confidence, held as a warning, never going to fail your build — was still handed to GitHub ranked as High with nothing to say otherwise. An alert now carries the rule's inherent severity, Fendix's confidence in that specific instance, and the two combined, each stated separately. Where they disagree, the alert says so in the first line you read.
  • Rate limiting is tested with the method it reports. Fendix reported "no rate limiting observed" against POST /login having only ever sent a GET — a claim about a test that never happened. It now probes the operation's own method where that is safe: a passive scan will not fire twenty writes at your production API, and a DELETE is never burst-probed at any setting. Where an operation cannot be probed safely it is reported as not tested, rather than quietly counted as passing.
  • A rate-limit sweep reads as one finding instead of eight hundred locations. A sweep across a large API produced a single result carrying a separate location for every operation it touched, which no tool renders legibly. You now get a readable sample with the true total beside it, and the complete list is still attached.
  • Separate scan types stop clearing each other's GitHub alerts. A code scan and a live scan of the same repository were filed under one category, so whichever ran last marked everything the other had found as fixed. Each scan type now keeps its own set of alerts.
  • Before you upgrade, re-save your baselines. Because findings are identified differently now, a baseline written by an older version matches nothing — the first scan after upgrading would report every finding as new. Run --save-baseline once to regenerate it, and rewrite any .fendix-ignore rule that pins a fingerprint: value. Rules that match by path, category or rule id are unaffected. GitHub code-scanning alerts also re-file themselves once, under their new rule names.

صدر الإصدار v3.4.1 في سبتمبر 2026 — تُبنى صور المحرك الآن بلغة Go 1.27 وتشحن بها، فيرتفع سقف الوحدات المدعومة في govulncheck من 1.25؛ ولا تغييرات في الفاحصات أو البصمات أو رموز الخروج، ويبقى الحد الأدنى لإصدار وحدات Go عند 1.25. صدر الإصدار v3.4.0 في سبتمبر 2026 — لم يعد بالإمكان أن يبدو المسح مكتملًا وهو ليس كذلك: يسجّل كل محلل ما إذا كان قد عمل ولماذا لم يعمل، ويحمل التقرير كتلة تغطية تسمّي الفجوات، ويكتب مسح URL الذي لا يجد نقاط نهاية تقريره بدل أن يختفي، وتحوّل رايتان اختياريتان فجوة التغطية إلى بناء مُخفق. صدر الإصدار v3.3.0 في سبتمبر 2026 — ولم تعد الترقية تقسم النتيجة التي تتابعها إلى مغلقة وجديدة، وصارت قائمة الفحوص تُبنى مما اكتمل لا مما جرى إعداده. وفي v3.2.0 — وفيه صار كل قرار حظر يشرح نفسه. تحمل نتيجة BLOCK الآن السياسة التي اتُّخذت بموجبها وصنف الدليل الذي برّرها، عبر تخزين Fendix نفسه وحتى ملف SARIF الذي تصدّره، فيصير خط الإنتاج المخفق قابلًا للتفسير من التقرير وحده. وتذكر النتائج المحجوزة سبب حجزها، وتأتي درجات الثقة مصحوبة بالقواعد التي أنتجتها، ويُوسم صراحةً أي بناء حُظر لمجرد أن فرض الثقة كان مُعطَّلًا. وأوقف الإصدار v3.1.0 ادعاء النتائج بأكثر مما أثبتته — من CORS بحرف بدل مع بيانات الاعتماد، إلى ترتيب أولويات تحديد المعدّل، وتقييم الترويسات بحسب نوع الاستجابة، وصياغة اجتياز المسارات، وبيانات الاعتماد الاختبارية، وقابلية تطبيق الاعتماديات. ومنح الإصدار v3.0 النتائج هوية مستقرة مبنية على القاعدة التي أطلقت النتيجة، وفي أي ملف، وداخل أي دالة، وحول أي عملية. أعد حفظ خطوط الأساس مرة واحدة بعد الترقية من إصدار أقدم من v3.0، وأعد كتابة أي قاعدة .fendix-ignore تثبّت قيمة fingerprint: — أما القواعد التي تطابق بالمسار أو الفئة أو معرّف القاعدة فلا تتأثر.