更新: 21 个文件 - 2026-03-17 00:00:00
这个提交包含在:
@@ -4,6 +4,7 @@ import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from urllib.parse import quote
|
||||
|
||||
import requests
|
||||
|
||||
@@ -13,16 +14,24 @@ from intel.utils import read_json, run
|
||||
|
||||
PR_PATHS = [
|
||||
"README.md",
|
||||
"00-environments",
|
||||
"01-sql-injection",
|
||||
"02-xss",
|
||||
"03-authentication",
|
||||
"04-server-security",
|
||||
"05-defense/secure-code",
|
||||
"06-case-studies/generated-runs",
|
||||
"07-framework-security",
|
||||
"08-threat-intel",
|
||||
"requirements-intel.txt",
|
||||
"scripts/intel",
|
||||
"scripts/lab",
|
||||
"scripts/tool_contract.py",
|
||||
]
|
||||
|
||||
|
||||
def create_branch_name() -> str:
|
||||
return "codex/intel-" + datetime.now().strftime("%Y%m%d-%H%M")
|
||||
return "codex/intel-" + datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
|
||||
def _parse_origin() -> Optional[dict]:
|
||||
@@ -42,6 +51,17 @@ def _changed_paths() -> list[str]:
|
||||
return lines
|
||||
|
||||
|
||||
def _current_branch() -> str:
|
||||
result = run(["git", "-C", str(ROOT), "branch", "--show-current"], check=False)
|
||||
return result.stdout.strip()
|
||||
|
||||
|
||||
def _push_remote(origin: dict, token: str | None) -> str:
|
||||
if token and origin["url"].startswith("https://"):
|
||||
return f"https://{quote(origin['owner'], safe='')}:{quote(token, safe='')}@{origin['host']}/{origin['owner']}/{origin['repo']}.git"
|
||||
return "origin"
|
||||
|
||||
|
||||
def open_pr(base_branch: str = "main", dry_run: bool = False) -> str:
|
||||
origin = _parse_origin()
|
||||
if not origin:
|
||||
@@ -51,27 +71,36 @@ def open_pr(base_branch: str = "main", dry_run: bool = False) -> str:
|
||||
if not changed:
|
||||
return "No intel-related changes to submit"
|
||||
|
||||
branch = create_branch_name()
|
||||
branch = _current_branch()
|
||||
if not branch.startswith("codex/"):
|
||||
branch = create_branch_name()
|
||||
if dry_run:
|
||||
preview = "\n".join(f"- {line}" for line in changed[:40])
|
||||
return f"Dry run only; would create branch {branch} with these paths:\n{preview}"
|
||||
|
||||
run(["git", "-C", str(ROOT), "checkout", "-b", branch])
|
||||
if _current_branch() != branch:
|
||||
run(["git", "-C", str(ROOT), "checkout", "-b", branch])
|
||||
run(["git", "-C", str(ROOT), "add", "--", *PR_PATHS])
|
||||
run(["git", "-C", str(ROOT), "commit", "-m", f"intel: automated advisory ingest {branch}"])
|
||||
run(["git", "-C", str(ROOT), "push", "-u", "origin", branch])
|
||||
run(["git", "-C", str(ROOT), "commit", "-m", f"lab: automated intel and verification sync {branch}"])
|
||||
|
||||
token = os.environ.get("GITEA_TOKEN")
|
||||
run(["git", "-C", str(ROOT), "push", "-u", _push_remote(origin, token), branch])
|
||||
if not token:
|
||||
return f"Pushed branch {branch}, but GITEA_TOKEN is not set; PR not created"
|
||||
|
||||
summary = read_json(GENERATED_DIR / "run-summary.json", default={}) or {}
|
||||
dashboard = read_json(GENERATED_DIR / "dashboard" / "summary.json", default={}) or {}
|
||||
body_lines = [
|
||||
"Automated advisory ingest update.",
|
||||
"Automated advisory ingest and local verification update.",
|
||||
"",
|
||||
f"- New advisories: {summary.get('new_count', 0)}",
|
||||
f"- Updated advisories: {summary.get('updated_count', 0)}",
|
||||
f"- Triage count: {summary.get('triage_count', 0)}",
|
||||
f"- Run bundles: {summary.get('run_bundle_count', 0)}",
|
||||
f"- verified-real: {dashboard.get('statuses', {}).get('verified-real', 0)}",
|
||||
f"- verified-synthetic: {dashboard.get('statuses', {}).get('verified-synthetic', 0)}",
|
||||
f"- blocked-artifact: {dashboard.get('statuses', {}).get('blocked-artifact', 0)}",
|
||||
f"- triage-manual: {dashboard.get('statuses', {}).get('triage-manual', 0)}",
|
||||
f"- Failure count: {len(summary.get('failures', []))}",
|
||||
]
|
||||
if summary.get("systems_touched"):
|
||||
@@ -80,6 +109,10 @@ def open_pr(base_branch: str = "main", dry_run: bool = False) -> str:
|
||||
body_lines.extend(["", "Failed source adapters:"])
|
||||
for failure in summary["failures"]:
|
||||
body_lines.append(f"- {failure}")
|
||||
if dashboard.get("recent_failures"):
|
||||
body_lines.extend(["", "Recent repro blockers:"])
|
||||
for failure in dashboard["recent_failures"][:10]:
|
||||
body_lines.append(f"- {failure['run_id']} :: {failure['status']} :: {failure.get('blocked_reason') or '-'}")
|
||||
|
||||
payload = {
|
||||
"title": f"Intel ingest {branch}",
|
||||
|
||||
@@ -7,5 +7,19 @@ mkdir -p "$LOG_DIR"
|
||||
STAMP="$(date '+%Y%m%d-%H%M%S')"
|
||||
exec >> "$LOG_DIR/hourly-$STAMP.log" 2>&1
|
||||
|
||||
run_pr() {
|
||||
if [[ "${WEBSAFE_PR_MODE:-auto}" == "skip" ]]; then
|
||||
echo "[hourly] PR skipped by WEBSAFE_PR_MODE=skip"
|
||||
elif [[ "${WEBSAFE_PR_MODE:-auto}" == "dry-run" || -z "${GITEA_TOKEN:-}" ]]; then
|
||||
python3 /Users/x/websafe/scripts/intel/main.py open-pr --dry-run
|
||||
else
|
||||
python3 /Users/x/websafe/scripts/intel/main.py open-pr
|
||||
fi
|
||||
}
|
||||
|
||||
echo "[hourly] $(date -u '+%Y-%m-%dT%H:%M:%SZ') starting"
|
||||
python3 /Users/x/websafe/scripts/intel/main.py hotlane
|
||||
python3 /Users/x/websafe/scripts/lab/main.py run-batch --only-hotlane --limit "${WEBSAFE_HOTLANE_LIMIT:-10}"
|
||||
python3 /Users/x/websafe/scripts/intel/main.py render
|
||||
python3 /Users/x/websafe/scripts/intel/main.py validate
|
||||
run_pr
|
||||
|
||||
@@ -7,5 +7,19 @@ mkdir -p "$LOG_DIR"
|
||||
STAMP="$(date '+%Y%m%d-%H%M%S')"
|
||||
exec >> "$LOG_DIR/nightly-$STAMP.log" 2>&1
|
||||
|
||||
run_pr() {
|
||||
if [[ "${WEBSAFE_PR_MODE:-auto}" == "skip" ]]; then
|
||||
echo "[nightly] PR skipped by WEBSAFE_PR_MODE=skip"
|
||||
elif [[ "${WEBSAFE_PR_MODE:-auto}" == "dry-run" || -z "${GITEA_TOKEN:-}" ]]; then
|
||||
python3 /Users/x/websafe/scripts/intel/main.py open-pr --dry-run
|
||||
else
|
||||
python3 /Users/x/websafe/scripts/intel/main.py open-pr
|
||||
fi
|
||||
}
|
||||
|
||||
echo "[nightly] $(date -u '+%Y-%m-%dT%H:%M:%SZ') starting"
|
||||
python3 /Users/x/websafe/scripts/intel/main.py ingest --since last-success
|
||||
python3 /Users/x/websafe/scripts/lab/main.py run-batch --limit "${WEBSAFE_NIGHTLY_LIMIT:-25}"
|
||||
python3 /Users/x/websafe/scripts/intel/main.py render
|
||||
python3 /Users/x/websafe/scripts/intel/main.py validate
|
||||
run_pr
|
||||
|
||||
@@ -7,5 +7,20 @@ mkdir -p "$LOG_DIR"
|
||||
STAMP="$(date '+%Y%m%d-%H%M%S')"
|
||||
exec >> "$LOG_DIR/weekly-$STAMP.log" 2>&1
|
||||
|
||||
run_pr() {
|
||||
if [[ "${WEBSAFE_PR_MODE:-auto}" == "skip" ]]; then
|
||||
echo "[weekly] PR skipped by WEBSAFE_PR_MODE=skip"
|
||||
elif [[ "${WEBSAFE_PR_MODE:-auto}" == "dry-run" || -z "${GITEA_TOKEN:-}" ]]; then
|
||||
python3 /Users/x/websafe/scripts/intel/main.py open-pr --dry-run
|
||||
else
|
||||
python3 /Users/x/websafe/scripts/intel/main.py open-pr
|
||||
fi
|
||||
}
|
||||
|
||||
echo "[weekly] $(date -u '+%Y-%m-%dT%H:%M:%SZ') starting"
|
||||
python3 /Users/x/websafe/scripts/intel/main.py reconcile
|
||||
python3 /Users/x/websafe/scripts/lab/main.py retry-failures --limit "${WEBSAFE_RETRY_LIMIT:-100}"
|
||||
python3 /Users/x/websafe/scripts/lab/main.py run-batch --from-queue --limit "${WEBSAFE_WEEKLY_LIMIT:-50}"
|
||||
python3 /Users/x/websafe/scripts/intel/main.py render
|
||||
python3 /Users/x/websafe/scripts/intel/main.py validate
|
||||
run_pr
|
||||
|
||||
@@ -83,6 +83,7 @@ def validate(source_map: Dict[str, Any]) -> List[str]:
|
||||
GENERATED_DIR / "run-summary.json",
|
||||
GENERATED_DIR / "dashboard" / "index.html",
|
||||
GENERATED_DIR / "dashboard" / "summary.json",
|
||||
GENERATED_DIR / "dashboard" / "systems.json",
|
||||
ROOT / "08-threat-intel" / "registry" / "source-confidence.md",
|
||||
]:
|
||||
if not path.exists():
|
||||
|
||||
在新工单中引用
屏蔽一个用户