Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

## Table of Contents

- [What's new (2026-06-21) — Dependency Vulnerability Scanning (OSV)](#whats-new-2026-06-21--dependency-vulnerability-scanning-osv)
- [What's new (2026-06-21) — JSON Schema Validation](#whats-new-2026-06-21--json-schema-validation)
- [What's new (2026-06-20) — SARIF 2.1.0 Findings Export](#whats-new-2026-06-20--sarif-210-findings-export)
- [What's new (2026-06-20) — Text PII Detection & Redaction](#whats-new-2026-06-20--text-pii-detection--redaction)
Expand Down Expand Up @@ -110,6 +111,12 @@

---

## What's new (2026-06-21) — Dependency Vulnerability Scanning (OSV)

Match the SBOM against known CVEs. Full reference: [`docs/source/Eng/doc/new_features/v58_features_doc.rst`](docs/source/Eng/doc/new_features/v58_features_doc.rst).

- **`scan_components` / `match_package` / `is_affected` / `findings_to_sarif`** (`AC_scan_vulns`, `ac_scan_vulns`): `build_sbom` only *inventoried* dependencies and `to_sarif` only *exported* findings — nothing ever **produced** a vulnerability finding. This matches the SBOM's `(ecosystem, name, version)` components against an [OSV](https://osv.dev) advisory database (sweeping `introduced`/`fixed`/`last_affected` ranges, PEP-503 name normalization, severity→SARIF level) and bridges results into the existing SARIF exporter for GitHub/Azure DevOps code scanning. The advisory DB is **injected as data** (offline, deterministic); the live `osv.dev` query is an optional `fetcher` seam. Pure-stdlib `re`.

## What's new (2026-06-21) — JSON Schema Validation

Validate nested JSON against a real schema. Full reference: [`docs/source/Eng/doc/new_features/v57_features_doc.rst`](docs/source/Eng/doc/new_features/v57_features_doc.rst).
Expand Down
7 changes: 7 additions & 0 deletions README/README_zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

## 目录

- [本次更新 (2026-06-21) — 依赖项漏洞扫描(OSV)](#本次更新-2026-06-21--依赖项漏洞扫描osv)
- [本次更新 (2026-06-21) — JSON Schema 验证](#本次更新-2026-06-21--json-schema-验证)
- [本次更新 (2026-06-20) — SARIF 2.1.0 发现项目导出](#本次更新-2026-06-20--sarif-210-发现项目导出)
- [本次更新 (2026-06-20) — 文本 PII 检测与遮蔽](#本次更新-2026-06-20--文本-pii-检测与遮蔽)
Expand Down Expand Up @@ -109,6 +110,12 @@

---

## 本次更新 (2026-06-21) — 依赖项漏洞扫描(OSV)

以 SBOM 比对已知 CVE。完整参考:[`docs/source/Zh/doc/new_features/v58_features_doc.rst`](../docs/source/Zh/doc/new_features/v58_features_doc.rst)。

- **`scan_components` / `match_package` / `is_affected` / `findings_to_sarif`**(`AC_scan_vulns`、`ac_scan_vulns`):`build_sbom` 只会*盘点*依赖项,`to_sarif` 只会*导出*发现项目 —— 从未真正**产生**漏洞发现项目。本功能以 SBOM 的 `(ecosystem, name, version)` 组件比对 [OSV](https://osv.dev) 咨询数据库(扫描 `introduced`/`fixed`/`last_affected` 范围、PEP-503 名称规范化、严重度对应 SARIF 等级),并把结果桥接到既有 SARIF 导出器供 GitHub/Azure DevOps 代码扫描。咨询数据库以**数据注入**(离线、确定性);线上 `osv.dev` 查询为可选的 `fetcher` 接缝。纯标准库 `re`。

## 本次更新 (2026-06-21) — JSON Schema 验证

以真正的 schema 验证嵌套 JSON。完整参考:[`docs/source/Zh/doc/new_features/v57_features_doc.rst`](../docs/source/Zh/doc/new_features/v57_features_doc.rst)。
Expand Down
7 changes: 7 additions & 0 deletions README/README_zh-TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

## 目錄

- [本次更新 (2026-06-21) — 相依套件漏洞掃描(OSV)](#本次更新-2026-06-21--相依套件漏洞掃描osv)
- [本次更新 (2026-06-21) — JSON Schema 驗證](#本次更新-2026-06-21--json-schema-驗證)
- [本次更新 (2026-06-20) — SARIF 2.1.0 發現項目匯出](#本次更新-2026-06-20--sarif-210-發現項目匯出)
- [本次更新 (2026-06-20) — 文字 PII 偵測與遮蔽](#本次更新-2026-06-20--文字-pii-偵測與遮蔽)
Expand Down Expand Up @@ -109,6 +110,12 @@

---

## 本次更新 (2026-06-21) — 相依套件漏洞掃描(OSV)

以 SBOM 比對已知 CVE。完整參考:[`docs/source/Zh/doc/new_features/v58_features_doc.rst`](../docs/source/Zh/doc/new_features/v58_features_doc.rst)。

- **`scan_components` / `match_package` / `is_affected` / `findings_to_sarif`**(`AC_scan_vulns`、`ac_scan_vulns`):`build_sbom` 只會*盤點*相依套件,`to_sarif` 只會*匯出*發現項目 —— 從未真正**產生**漏洞發現項目。本功能以 SBOM 的 `(ecosystem, name, version)` 元件比對 [OSV](https://osv.dev) 諮詢資料庫(掃描 `introduced`/`fixed`/`last_affected` 範圍、PEP-503 名稱正規化、嚴重度對應 SARIF 等級),並把結果橋接到既有 SARIF 匯出器供 GitHub/Azure DevOps 程式碼掃描。諮詢資料庫以**資料注入**(離線、具決定性);線上 `osv.dev` 查詢為選用的 `fetcher` 接縫。純標準函式庫 `re`。

## 本次更新 (2026-06-21) — JSON Schema 驗證

以真正的 schema 驗證巢狀 JSON。完整參考:[`docs/source/Zh/doc/new_features/v57_features_doc.rst`](../docs/source/Zh/doc/new_features/v57_features_doc.rst)。
Expand Down
72 changes: 72 additions & 0 deletions docs/source/Eng/doc/new_features/v58_features_doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
Dependency Vulnerability Scanning (OSV)
=======================================

``build_sbom`` *inventories* dependencies and ``to_sarif`` *exports* findings,
but nothing in between ever **produced** a vulnerability finding — there was no
advisory matching at all. This closes that loop: given the SBOM's
``(ecosystem, name, version)`` components and an `OSV <https://osv.dev>`_
advisory database, ``scan_components`` reports which packages are affected, and
``findings_to_sarif`` bridges the results straight into the existing SARIF
exporter for GitHub / Azure DevOps code scanning.

The advisory database is **injected as plain data** (a list of OSV records), so
matching is fully offline and deterministic; the live ``osv.dev`` query is a
separate, optional ``fetcher`` seam. Pure standard library (``re``); imports no
``PySide6``.

Headless API
------------

.. code-block:: python

from je_auto_control import (
build_sbom, scan_components, findings_to_sarif, write_sarif)

advisories = [{
"id": "GHSA-foo", "summary": "RCE in foo",
"database_specific": {"severity": "HIGH"},
"affected": [{
"package": {"ecosystem": "PyPI", "name": "foo"},
"ranges": [{"type": "ECOSYSTEM",
"events": [{"introduced": "0"}, {"fixed": "1.2.0"}]}],
}],
}]

sbom = build_sbom("je_auto_control")
findings = scan_components(sbom["components"], advisories)
# findings: [{id, package, version, summary, severity, fixed, aliases}]
write_sarif(findings_to_sarif(findings), "vulns.sarif",
tool_name="AutoControl-VulnScan")

``is_affected(version, osv_range)`` evaluates one OSV range by sweeping its
``introduced`` / ``fixed`` / ``last_affected`` events; ``match_package`` checks
a single package against the database (explicit ``versions`` **or** ranges);
``scan_components`` runs the whole SBOM. Package names are compared with PEP-503
normalization, and the OSV severity word (``CRITICAL`` / ``HIGH`` /
``MODERATE`` / ``LOW``) maps to a SARIF ``error`` / ``warning`` / ``note``
level (defaulting to ``warning``).

Version ordering is a pragmatic numeric comparison: release components compare
as integers and a pre-release suffix (``1.2.0-rc1``) sorts before the final
release. Git ranges and full CVSS-vector scoring are out of scope.

Live advisories (optional)
--------------------------

Pass a ``fetcher`` callable to pull advisories at scan time (e.g. from the
``osv.dev`` API). Tests inject a fake fetcher, so the matching logic is verified
without any network:

.. code-block:: python

findings = scan_components(sbom["components"], None,
fetcher=my_osv_fetcher)

Executor command
----------------

``AC_scan_vulns`` takes ``components`` (a component list, a full SBOM dict, or a
JSON string) and ``advisories`` (a list or JSON string), with an optional
``sarif_path`` to write a SARIF report; it returns ``{findings, count}`` (plus
``sarif_path`` when written). The same operation is exposed as the MCP tool
``ac_scan_vulns`` and as a Script Builder command under **Security**.
1 change: 1 addition & 0 deletions docs/source/Eng/eng_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Comprehensive guides for all AutoControl features.
doc/new_features/v55_features_doc
doc/new_features/v56_features_doc
doc/new_features/v57_features_doc
doc/new_features/v58_features_doc
doc/ocr_backends/ocr_backends_doc
doc/observability/observability_doc
doc/operations_layer/operations_layer_doc
Expand Down
64 changes: 64 additions & 0 deletions docs/source/Zh/doc/new_features/v58_features_doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
相依套件漏洞掃描(OSV)
======================

``build_sbom`` 會*盤點*相依套件,``to_sarif`` 會*匯出*發現項目,但兩者之間從未真正**產生**
漏洞發現項目 —— 完全沒有諮詢比對。本功能補上這個環節:給定 SBOM 的
``(ecosystem, name, version)`` 元件與一份 `OSV <https://osv.dev>`_ 諮詢資料庫,
``scan_components`` 會回報哪些套件受影響,而 ``findings_to_sarif`` 把結果直接橋接到既有的
SARIF 匯出器,供 GitHub / Azure DevOps 程式碼掃描使用。

諮詢資料庫以**純資料注入**(一份 OSV 紀錄清單),因此比對完全離線且具決定性;線上的
``osv.dev`` 查詢則是另一個選用的 ``fetcher`` 接縫。純標準函式庫(``re``);不匯入
``PySide6``。

無頭 API
--------

.. code-block:: python

from je_auto_control import (
build_sbom, scan_components, findings_to_sarif, write_sarif)

advisories = [{
"id": "GHSA-foo", "summary": "RCE in foo",
"database_specific": {"severity": "HIGH"},
"affected": [{
"package": {"ecosystem": "PyPI", "name": "foo"},
"ranges": [{"type": "ECOSYSTEM",
"events": [{"introduced": "0"}, {"fixed": "1.2.0"}]}],
}],
}]

sbom = build_sbom("je_auto_control")
findings = scan_components(sbom["components"], advisories)
# findings: [{id, package, version, summary, severity, fixed, aliases}]
write_sarif(findings_to_sarif(findings), "vulns.sarif",
tool_name="AutoControl-VulnScan")

``is_affected(version, osv_range)`` 透過掃描 ``introduced`` / ``fixed`` /
``last_affected`` 事件來評估單一 OSV 範圍;``match_package`` 以資料庫比對單一套件(明確的
``versions`` **或**範圍);``scan_components`` 跑完整份 SBOM。套件名稱以 PEP-503 正規化後比較,
OSV 嚴重度字詞(``CRITICAL`` / ``HIGH`` / ``MODERATE`` / ``LOW``)對應到 SARIF 的
``error`` / ``warning`` / ``note`` 等級(預設為 ``warning``)。

版本排序採務實的數值比較:release 元件以整數比較,pre-release 後綴(``1.2.0-rc1``)排在最終
release 之前。Git 範圍與完整 CVSS 向量評分不在範圍內。

線上諮詢(選用)
----------------

傳入 ``fetcher`` callable 即可在掃描當下抓取諮詢(例如從 ``osv.dev`` API)。測試注入假的
fetcher,因此比對邏輯不需任何網路即可驗證:

.. code-block:: python

findings = scan_components(sbom["components"], None,
fetcher=my_osv_fetcher)

執行器命令
----------

``AC_scan_vulns`` 接受 ``components``(元件清單、完整 SBOM dict 或 JSON 字串)與
``advisories``(清單或 JSON 字串),並可選用 ``sarif_path`` 寫出 SARIF 報告;回傳
``{findings, count}``(寫檔時另含 ``sarif_path``)。同一操作亦以 MCP 工具 ``ac_scan_vulns``
以及 Script Builder 中 **Security** 分類下的命令提供。
1 change: 1 addition & 0 deletions docs/source/Zh/zh_index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ AutoControl 所有功能的完整使用指南。
doc/new_features/v55_features_doc
doc/new_features/v56_features_doc
doc/new_features/v57_features_doc
doc/new_features/v58_features_doc
doc/ocr_backends/ocr_backends_doc
doc/observability/observability_doc
doc/operations_layer/operations_layer_doc
Expand Down
6 changes: 6 additions & 0 deletions je_auto_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,10 @@
from je_auto_control.utils.json_schema import (
SchemaValidationResult, assert_schema, is_valid, validate_json,
)
# OSV vulnerability matching for SBOM components
from je_auto_control.utils.vuln_scan import (
findings_to_sarif, is_affected, match_package, scan_components, version_key,
)
# Background popup/interrupt watchdog (unattended automation)
from je_auto_control.utils.watchdog import (
PopupWatchdog, WatchdogRule, default_popup_watchdog,
Expand Down Expand Up @@ -772,6 +776,8 @@ def start_autocontrol_gui(*args, **kwargs):
"from_audit_findings", "from_lint_issues", "make_finding", "to_sarif",
"write_sarif",
"SchemaValidationResult", "assert_schema", "is_valid", "validate_json",
"findings_to_sarif", "is_affected", "match_package", "scan_components",
"version_key",
# MCP server
"AuditLogger", "HttpMCPServer", "MCPContent", "MCPPrompt",
"MCPPromptArgument", "MCPResource", "MCPServer", "MCPTool",
Expand Down
13 changes: 13 additions & 0 deletions je_auto_control/gui/script_builder/command_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,19 @@ def _add_misc_specs(specs: List[CommandSpec]) -> None:
),
description="Validate JSON against a JSON Schema; returns {ok, errors}.",
))
specs.append(CommandSpec(
"AC_scan_vulns", "Security", "Scan Dependencies for Vulnerabilities",
fields=(
FieldSpec("components", FieldType.STRING,
placeholder='{"components": [{"name": "foo", '
'"version": "1.0", "purl": "pkg:pypi/foo@1.0"}]}'),
FieldSpec("advisories", FieldType.STRING,
placeholder='[{"id": "GHSA-...", "affected": [...]}]'),
FieldSpec("sarif_path", FieldType.STRING, optional=True,
placeholder="vulns.sarif"),
),
description="Match SBOM components against an OSV advisory database.",
))
specs.append(CommandSpec(
"AC_run_saga", "Flow", "Run Saga (Compensating Rollback)",
fields=(
Expand Down
23 changes: 23 additions & 0 deletions je_auto_control/utils/executor/action_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2863,6 +2863,28 @@ def _scan_secrets(data: Any) -> Dict[str, Any]:
return {"findings": scan_secrets(data)}


def _scan_vulns(components: Any, advisories: Any = None,
sarif_path: Optional[str] = None) -> Dict[str, Any]:
"""Adapter: match SBOM components against an OSV advisory database."""
import json
from je_auto_control.utils.vuln_scan import (
findings_to_sarif, scan_components)
if isinstance(components, str):
components = json.loads(components)
if isinstance(components, dict):
components = components.get("components", [])
if isinstance(advisories, str):
advisories = json.loads(advisories)
findings = scan_components(components, advisories or [])
result: Dict[str, Any] = {"findings": findings, "count": len(findings)}
if sarif_path:
from je_auto_control.utils.sarif import write_sarif
result["sarif_path"] = write_sarif(
findings_to_sarif(findings), sarif_path,
tool_name="AutoControl-VulnScan")
return result


def _generate_sop(actions: List[Any], title: str = "Automation Procedure",
path: Optional[str] = None) -> Dict[str, Any]:
"""Adapter: build (or write) a step-by-step SOP from an action list."""
Expand Down Expand Up @@ -3642,6 +3664,7 @@ def __init__(self):
"AC_clip_history_stop": _clip_history_stop,
"AC_heal_stats": _heal_stats,
"AC_scan_secrets": _scan_secrets,
"AC_scan_vulns": _scan_vulns,
"AC_generate_sop": _generate_sop,
"AC_tween_drag": _tween_drag,
"AC_list_plugins": _list_plugins,
Expand Down
22 changes: 20 additions & 2 deletions je_auto_control/utils/mcp_server/tools/_factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3244,6 +3244,24 @@ def json_schema_tools() -> List[MCPTool]:
]


def vuln_scan_tools() -> List[MCPTool]:
return [
MCPTool(
name="ac_scan_vulns",
description=("Match SBOM 'components' (or a full SBOM dict) against "
"an OSV 'advisories' database. Returns {findings:"
"[{id, package, version, severity, fixed, aliases}], "
"count}. Advisories are supplied as data (offline)."),
input_schema=schema(
{"components": {"type": "object"},
"advisories": {"type": "array"}},
["components"]),
handler=h.scan_vulns,
annotations=READ_ONLY,
),
]


def saga_tools() -> List[MCPTool]:
return [
MCPTool(
Expand Down Expand Up @@ -4438,8 +4456,8 @@ def media_assert_tools() -> List[MCPTool]:
video_report_tools, fuzzy_tools, artifact_store_tools, image_dedup_tools,
locale_tools, voice_tools, coordinate_space_tools, loop_guard_tools,
process_mining_tools, asset_tools, events_tools, notify_channel_tools,
jsonpath_tools, json_schema_tools, saga_tools, decision_table_tools,
locator_repair_tools,
jsonpath_tools, json_schema_tools, vuln_scan_tools, saga_tools,
decision_table_tools, locator_repair_tools,
pii_text_tools, sarif_tools,
screen_record_tools,
process_and_shell_tools, remote_desktop_tools, gamepad_tools,
Expand Down
8 changes: 8 additions & 0 deletions je_auto_control/utils/mcp_server/tools/_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,14 @@ def validate_json(data, schema):
return _v(data, schema).to_dict()


def scan_vulns(components, advisories=None):
from je_auto_control.utils.vuln_scan import scan_components
if isinstance(components, dict):
components = components.get("components", [])
findings = scan_components(components, advisories or [])
return {"findings": findings, "count": len(findings)}


def run_saga(steps):
from je_auto_control.utils.saga import run_saga as _run
result = _run(steps)
Expand Down
9 changes: 9 additions & 0 deletions je_auto_control/utils/vuln_scan/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""OSV vulnerability matching for SBOM components (pure standard library)."""
from je_auto_control.utils.vuln_scan.vuln_scan import (
findings_to_sarif, is_affected, match_package, scan_components, version_key,
)

__all__ = [
"findings_to_sarif", "is_affected", "match_package", "scan_components",
"version_key",
]
Loading
Loading