Compare commits

..

1 Commits

Author SHA1 Message Date
Stéphane Lesimple fd7caec415 Merge remote-tracking branch 'origin/source-build' 2026-06-02 18:17:06 +02:00
4 changed files with 279 additions and 31 deletions
+41
View File
@@ -0,0 +1,41 @@
name: autoupdate
on:
workflow_dispatch:
schedule:
- cron: '42 9 * * *'
permissions:
pull-requests: write
contents: write
jobs:
autoupdate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: source
- name: Install prerequisites
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends iucode-tool sqlite3 unzip shfmt
- name: Update microcode versions
run: ./scripts/update_mcedb.sh
- name: Update Intel models
run: ./scripts/update_intel_models.sh
- name: Check git diff
id: diff
run: |
echo change="$(git diff | awk '/MCEDB/ { if(V) { print V" to "$4; exit } else { V=$4 } }')" >> "$GITHUB_OUTPUT"
echo nbdiff="$(git diff | grep -cE -- '^\+# [AI],')" >> "$GITHUB_OUTPUT"
git diff
cat "$GITHUB_OUTPUT"
- name: Create Pull Request if needed
if: steps.diff.outputs.nbdiff != '0'
uses: peter-evans/create-pull-request@v7
with:
branch: autoupdate-fwdb
commit-message: "update: fwdb from ${{ steps.diff.outputs.change }}, ${{ steps.diff.outputs.nbdiff }} microcode changes"
title: "[Auto] Update fwdb from ${{ steps.diff.outputs.change }}"
body: |
Automated PR to update fwdb from ${{ steps.diff.outputs.change }}
Detected ${{ steps.diff.outputs.nbdiff }} microcode changes
+33
View File
@@ -0,0 +1,33 @@
name: 'Manage stale issues and PRs'
on:
schedule:
- cron: '37 7 * * *'
workflow_dispatch:
inputs:
action:
description: "dry-run"
required: true
default: "dryrun"
type: choice
options:
- dryrun
- apply
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v10
with:
any-of-labels: 'needs-more-info,answered'
labels-to-remove-when-unstale: 'needs-more-info,answered'
days-before-stale: 30
days-before-close: 7
stale-issue-label: stale
remove-stale-when-updated: true
debug-only: ${{ case(inputs.action == 'dryrun', true, false) }}
+190
View File
@@ -0,0 +1,190 @@
name: Online search for vulns
on:
schedule:
- cron: '42 8 * * *'
workflow_dispatch:
inputs:
model:
description: 'Claude model to use (cron runs default to Sonnet)'
required: false
type: choice
default: claude-sonnet-4-6
options:
- claude-sonnet-4-6
- claude-opus-4-7
- claude-haiku-4-5-20251001
window_hours:
description: 'Lookback window in hours (cron runs use 25)'
required: false
type: string
default: '25'
reconsider_age_days:
description: 'Only reconsider backlog entries last reviewed ≥ N days ago (0 = all, default 7)'
required: false
type: string
default: '7'
permissions:
contents: read
actions: read # needed to list/download previous run artifacts
id-token: write # needed by claude-code-action for OIDC auth
concurrency:
group: vuln-watch
cancel-in-progress: true
jobs:
watch:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
# The scripts driving this workflow live on the `vuln-watch` branch so
# they don't clutter master (which is what ships to production). The
# workflow file itself MUST stay on the default branch, as GitHub only
# honors `schedule:` triggers on the default branch.
- name: Checkout vuln-watch branch (scripts + prompt)
uses: actions/checkout@v5
with:
ref: vuln-watch
fetch-depth: 1
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Python dependencies
run: python -m pip install --quiet feedparser
# ---- Load previous state ---------------------------------------------
# Find the most recent successful run of THIS workflow (other than the
# current one) and pull its `vuln-watch-state` artifact. On the very
# first run there will be none — that's fine, we start empty.
- name: Find previous successful run id
id: prev
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
run_id=$(gh run list \
--workflow="${{ github.workflow }}" \
--status=success \
--limit 1 \
--json databaseId \
--jq '.[0].databaseId // empty')
echo "run_id=${run_id}" >> "$GITHUB_OUTPUT"
if [ -n "$run_id" ]; then
echo "Found previous successful run: $run_id"
else
echo "No previous successful run — starting from empty state."
fi
- name: Download previous state artifact
if: steps.prev.outputs.run_id != ''
uses: actions/download-artifact@v5
continue-on-error: true # tolerate retention expiry
with:
name: vuln-watch-state
path: state/
run-id: ${{ steps.prev.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
# ---- Fetch + diff (token-free; runs every time) ---------------------
# Performs conditional GETs (ETag / If-Modified-Since) against every
# source, parses RSS/Atom/HTML, dedups against state.seen + state.aliases,
# applies the time-window filter, and emits new_items.json.
# Updates state.sources (HTTP cache metadata + per-source high-water
# marks) in place so the cache survives even when Claude doesn't run.
- name: Fetch + diff all sources
id: diff
env:
SCAN_DATE: ${{ github.run_started_at }}
# Cron runs have no `inputs` context, so the fallback kicks in.
WINDOW_HOURS: ${{ inputs.window_hours || '25' }}
RECONSIDER_AGE_DAYS: ${{ inputs.reconsider_age_days || '7' }}
run: python -m scripts.vuln_watch.fetch_and_diff
# ---- Fetch checker code so Claude can grep it for coverage ---------
# The orphan vuln-watch branch has none of the actual checker code,
# so we pull the `test` branch (the dev branch where coded-but-
# unreleased CVE checks live) into ./checker/. The prompt tells
# Claude this is the canonical source of truth for "is CVE-X already
# implemented?". Only fetched on days with something to classify.
- name: Checkout checker code (test branch) for coverage grep
if: steps.diff.outputs.new_count != '0' || steps.diff.outputs.reconsider_count != '0'
uses: actions/checkout@v5
with:
ref: test
path: checker
fetch-depth: 1
persist-credentials: false
# ---- Classify new items with Claude (skipped when nothing is new) ---
# Model selection: a manual workflow_dispatch run picks from a dropdown
# (defaulting to Sonnet). Scheduled cron runs have no `inputs` context,
# so the `|| 'claude-sonnet-4-6'` fallback kicks in — cron always uses
# Sonnet to keep the daily cost floor low.
- name: Run classifier with Claude
id: classify
if: steps.diff.outputs.new_count != '0' || steps.diff.outputs.reconsider_count != '0'
uses: anthropics/claude-code-action@v1
env:
SCAN_DATE: ${{ github.run_started_at }}
with:
prompt: |
Read the full task instructions from scripts/daily_vuln_watch_prompt.md
and execute them end-to-end. Your input is new_items.json (already
deduped, windowed, and pre-filtered — do NOT re-fetch sources).
Write the three watch_${TODAY}_*.md files and classifications.json.
Use $SCAN_DATE as the canonical timestamp.
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# model + tool allowlist pass through claude_args (v1 dropped the
# dedicated `model:` and `allowed_tools:` inputs). Job-level
# `timeout-minutes: 20` above bounds total runtime.
claude_args: |
--model ${{ inputs.model || 'claude-sonnet-4-6' }}
--allowedTools "Read,Write,Edit,Bash,Grep,Glob,WebFetch"
- name: Upload Claude execution log
if: ${{ always() && steps.classify.outputs.execution_file != '' }}
uses: actions/upload-artifact@v5
with:
name: claude-execution-log-${{ github.run_id }}
path: ${{ steps.classify.outputs.execution_file }}
retention-days: 30
if-no-files-found: warn
# ---- Merge classifications back into state --------------------------
# Also writes stub watch_*.md files if the classify step was skipped, so
# the report artifact is consistent across runs.
- name: Merge classifications into state
if: always()
env:
SCAN_DATE: ${{ github.run_started_at }}
run: python -m scripts.vuln_watch.merge_state
- name: Upload new state artifact
if: always()
uses: actions/upload-artifact@v5
with:
name: vuln-watch-state
path: state/seen.json
retention-days: 90
if-no-files-found: error
- name: Upload daily report
if: always()
uses: actions/upload-artifact@v5
with:
name: vuln-watch-report-${{ github.run_id }}
path: |
watch_*.md
current_toimplement.md
current_tocheck.md
new_items.json
classifications.json
retention-days: 90
if-no-files-found: warn
+15 -31
View File
@@ -13,7 +13,7 @@
#
# Stephane Lesimple
#
VERSION='26.36.0603505'
VERSION='26.36.0601873'
# --- Common paths and basedirs ---
readonly VULN_SYSFS_BASE="/sys/devices/system/cpu/vulnerabilities"
@@ -3936,18 +3936,11 @@ parse_cpu_details() {
# cpu_variant_list and cpu_revision_list are consumed by ARM64 errata affection checks
# that need to match a specific revision range.
if grep -q 'CPU implementer' "$g_procfs/cpuinfo"; then
# keep these single-line (space-separated) so consumers and outputs (JSON, prometheus)
# don't end up with embedded newlines; per-core order is preserved for the errata checks
cpu_impl_list=$(awk '/CPU implementer/ {print $4}' "$g_procfs/cpuinfo" | tr '\n' ' ')
cpu_impl_list=${cpu_impl_list% }
cpu_part_list=$(awk '/CPU part/ {print $4}' "$g_procfs/cpuinfo" | tr '\n' ' ')
cpu_part_list=${cpu_part_list% }
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' "$g_procfs/cpuinfo" | tr '\n' ' ')
cpu_arch_list=${cpu_arch_list% }
cpu_variant_list=$(awk '/CPU variant/ {print $4}' "$g_procfs/cpuinfo" | tr '\n' ' ')
cpu_variant_list=${cpu_variant_list% }
cpu_revision_list=$(awk '/CPU revision/ {print $4}' "$g_procfs/cpuinfo" | tr '\n' ' ')
cpu_revision_list=${cpu_revision_list% }
cpu_impl_list=$(awk '/CPU implementer/ {print $4}' "$g_procfs/cpuinfo")
cpu_part_list=$(awk '/CPU part/ {print $4}' "$g_procfs/cpuinfo")
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' "$g_procfs/cpuinfo")
cpu_variant_list=$(awk '/CPU variant/ {print $4}' "$g_procfs/cpuinfo")
cpu_revision_list=$(awk '/CPU revision/ {print $4}' "$g_procfs/cpuinfo")
fi
# Map first-seen implementer to cpu_vendor; note that heterogeneous systems
# (e.g. DynamIQ with ARM+Kryo cores) would all map to one vendor here, but
@@ -5058,12 +5051,6 @@ check_kernel_info() {
fi
}
# Collapse a whitespace-separated list to its unique values, preserving first-seen order.
# Used to prettify the per-core ARM lists for display (e.g. "0x41 0x41 0x41 0x41" -> "0x41").
_uniq_list() {
echo "$1" | awk '{ for (i = 1; i <= NF; i++) if (!seen[$i]++) printf "%s%s", (n++ ? " " : ""), $i }'
}
# Display hardware-level CPU mitigation support (microcode features, ARCH_CAPABILITIES, etc.)
check_cpu() {
local capabilities ret spec_ctrl_msr codename ucode_str
@@ -5073,13 +5060,13 @@ check_cpu() {
pr_info " * Vendor: $cpu_vendor"
pr_info " * Model name: $cpu_friendly_name"
if [ -n "${cpu_impl_list:-}" ]; then
pr_info " * Implementer(s): $(_uniq_list "$cpu_impl_list")"
pr_info " * Implementer(s): $cpu_impl_list"
fi
if [ -n "${cpu_part_list:-}" ]; then
pr_info " * Part(s): $(_uniq_list "$cpu_part_list")"
pr_info " * Part(s): $cpu_part_list"
fi
if [ -n "${cpu_arch_list:-}" ]; then
pr_info " * Architecture(s): $(_uniq_list "$cpu_arch_list")"
pr_info " * Architecture(s): $cpu_arch_list"
fi
if has_runtime; then
pr_info_nol " * Running as VM guest: "
@@ -13133,7 +13120,7 @@ exit 0 # ok
# with X being either I for Intel, or A for AMD
# When the date is unknown it defaults to 20000101
# %%% MCEDB v350+i20260512+1cce
# %%% MCEDB v349+i20260512+1cce
# I,0x00000611,0xFF,0x00000B27,19961218
# I,0x00000612,0xFF,0x000000C6,19961210
# I,0x00000616,0xFF,0x000000C6,19961210
@@ -13552,7 +13539,6 @@ exit 0 # ok
# I,0x000A06D0,0xFF,0x10000680,20240818
# I,0x000A06D1,0x20,0x0A000142,20260129
# I,0x000A06D1,0x95,0x01000423,20260129
# I,0x000A06E0,0xFF,0x80000953,20240902
# I,0x000A06E1,0x97,0x01000307,20260226
# I,0x000A06F0,0xFF,0x80000360,20240130
# I,0x000A06F3,0x01,0x030003A3,20260130
@@ -13582,10 +13568,8 @@ exit 0 # ok
# I,0x000C06C3,0x90,0x0000011B,20260324
# I,0x000C06F1,0x87,0x210002E0,20251217
# I,0x000C06F2,0x87,0x210002E0,20251217
# I,0x000D0650,0xFF,0x00000008,20260208
# I,0x000D0651,0xFF,0x00000008,20260208
# I,0x000D0670,0xFF,0x00000137,20260218
# I,0x000D06D0,0xFF,0x80000370,20250917
# I,0x000D0670,0xFF,0x00000003,20250825
# I,0x000D06D0,0xFF,0x00000340,20250807
# I,0x00FF0671,0xFF,0x0000010E,20220907
# I,0x00FF0672,0xFF,0x0000000D,20210816
# I,0x00FF0675,0xFF,0x0000000D,20210816
@@ -13682,7 +13666,7 @@ exit 0 # ok
# A,0x00880F40,0xFF,0x08804005,20210312
# A,0x00890F00,0xFF,0x08900007,20200921
# A,0x00890F01,0xFF,0x08900103,20201105
# A,0x00890F02,0xFF,0x08900208,20241219
# A,0x00890F02,0xFF,0x08900203,20230915
# A,0x00890F10,0xFF,0x08901003,20230919
# A,0x008A0F00,0xFF,0x08A0000B,20241125
# A,0x00A00F00,0xFF,0x0A000033,20200413
@@ -13727,11 +13711,11 @@ exit 0 # ok
# A,0x00B00F00,0xFF,0x0B00004D,20240318
# A,0x00B00F10,0xFF,0x0B001016,20240318
# A,0x00B00F20,0xFF,0x0B002032,20241003
# A,0x00B00F21,0xFF,0x0B002162,20251105
# A,0x00B00F21,0xFF,0x0B002161,20251105
# A,0x00B00F80,0xFF,0x0B008011,20241211
# A,0x00B00F81,0xFF,0x0B008121,20251020
# A,0x00B10F00,0xFF,0x0B10000F,20240320
# A,0x00B10F10,0xFF,0x0B101059,20251105
# A,0x00B10F10,0xFF,0x0B101058,20251105
# A,0x00B20F40,0xFF,0x0B204037,20251019
# A,0x00B40F00,0xFF,0x0B400034,20240318
# A,0x00B40F40,0xFF,0x0B404035,20251020