Skip to content
Closed
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
27 changes: 27 additions & 0 deletions .github/workflows/github-hourly-review-repair.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Central GitHub Hourly Review Repair

on:
schedule:
# Keep the control-plane queue moving without colliding with minute-zero jobs.
- cron: "21 * * * *"

concurrency:
group: github-hourly-review-repair
cancel-in-progress: false

permissions:
contents: read

jobs:
dispatch-review-repair:
uses: ./.github/workflows/pr-review-fix-scheduler.yml
with:
target_repository: ContextualWisdomLab/.github
base_branch: main
max_prs: "50"
max_dispatches: "1"
resolve_unreviewed_conflicts: true
retry_hours: "1"
secrets:
PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}
OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }}
14 changes: 14 additions & 0 deletions .github/workflows/hourly-nvidia-nim-review-repair.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ on:
- .github/workflows/clearfolio-hourly-review-repair.yml
- .github/workflows/disksage-hourly-review-repair.yml
- .github/workflows/fast-mlsirm-hourly-review-repair.yml
- .github/workflows/github-hourly-review-repair.yml
- .github/workflows/governance-risk-compliance-hourly-review-repair.yml
- .github/workflows/hourly-nvidia-nim-review-repair.yml
- .github/workflows/nonnest2-hourly-review-repair.yml
- .github/workflows/originweave-hourly-review-repair.yml
- scripts/ci/pr_review_conflict_scope.py
- scripts/ci/pr_review_autofix_context.py
- tests/test_bandscope_hourly_review_caller.py
- tests/test_disksage_hourly_review_caller.py
- tests/test_fast_mlsirm_hourly_review_caller.py
- tests/test_github_hourly_conflict_repair.py
- tests/test_governance_risk_compliance_hourly_review_caller.py
- tests/test_hourly_scheduler_runtime_budget.py
- tests/test_nonnest2_hourly_review_caller.py
- tests/test_originweave_hourly_review_caller.py
- tests/test_hourly_autofix_context_quality_gate.py
- tests/test_pr_review_conflict_scope.py
Expand All @@ -39,8 +43,10 @@ on:
- docs/doctoring/conflict-control-evidence-isolation.md
- docs/doctoring/disksage-hourly-review-caller.md
- docs/doctoring/fast-mlsirm-hourly-review-caller.md
- docs/doctoring/github-hourly-conflict-repair.md
- docs/doctoring/governance-risk-compliance-hourly-review-caller.md
- docs/doctoring/hourly-nvidia-nim-autofix.md
- docs/doctoring/nonnest2-hourly-review-caller.md
- docs/doctoring/originweave-hourly-review-caller.md
push:
paths:
Expand All @@ -51,16 +57,20 @@ on:
- .github/workflows/clearfolio-hourly-review-repair.yml
- .github/workflows/disksage-hourly-review-repair.yml
- .github/workflows/fast-mlsirm-hourly-review-repair.yml
- .github/workflows/github-hourly-review-repair.yml
- .github/workflows/governance-risk-compliance-hourly-review-repair.yml
- .github/workflows/hourly-nvidia-nim-review-repair.yml
- .github/workflows/nonnest2-hourly-review-repair.yml
- .github/workflows/originweave-hourly-review-repair.yml
- scripts/ci/pr_review_conflict_scope.py
- scripts/ci/pr_review_autofix_context.py
- tests/test_bandscope_hourly_review_caller.py
- tests/test_disksage_hourly_review_caller.py
- tests/test_fast_mlsirm_hourly_review_caller.py
- tests/test_github_hourly_conflict_repair.py
- tests/test_governance_risk_compliance_hourly_review_caller.py
- tests/test_hourly_scheduler_runtime_budget.py
- tests/test_nonnest2_hourly_review_caller.py
- tests/test_originweave_hourly_review_caller.py
- tests/test_hourly_autofix_context_quality_gate.py
- tests/test_pr_review_conflict_scope.py
Expand All @@ -80,8 +90,10 @@ on:
- docs/doctoring/conflict-control-evidence-isolation.md
- docs/doctoring/disksage-hourly-review-caller.md
- docs/doctoring/fast-mlsirm-hourly-review-caller.md
- docs/doctoring/github-hourly-conflict-repair.md
- docs/doctoring/governance-risk-compliance-hourly-review-caller.md
- docs/doctoring/hourly-nvidia-nim-autofix.md
- docs/doctoring/nonnest2-hourly-review-caller.md
- docs/doctoring/originweave-hourly-review-caller.md

permissions:
Expand Down Expand Up @@ -133,8 +145,10 @@ jobs:
tests/test_bandscope_hourly_review_caller.py \
tests/test_disksage_hourly_review_caller.py \
tests/test_fast_mlsirm_hourly_review_caller.py \
tests/test_github_hourly_conflict_repair.py \
tests/test_governance_risk_compliance_hourly_review_caller.py \
tests/test_hourly_scheduler_runtime_budget.py \
tests/test_nonnest2_hourly_review_caller.py \
tests/test_originweave_hourly_review_caller.py \
tests/test_pr_review_conflict_scope_control_files.py \
tests/test_hourly_autofix_context_quality_gate.py \
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/nonnest2-hourly-review-repair.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: nonnest2 Hourly Review Repair

on:
schedule:
# Minute 16 avoids pg-llm-batch (1), aFIPC (2), kaefa (3), LineageWeave (4),
# codec-carver (5), life-os (6), Wardnet (7), mightyETL (8),
# psychometrics-commons (9), OriginWeave (10), naruon (11),
# DiagramWeave (12), pg-erd-cloud (13), mhtml-etl-gateway (14),
# html4tree (15), orchestrator (17), noema (19), Clearfolio (23),
# Keyverse (29), Scopeweave (31), DiskSage (37), Appguardrail (41),
# newsdom-api (43), Inkspan (47), fast-mlsirm (49), BandScope (53),
# and semantic-data-portal (59).
- cron: "16 * * * *"

concurrency:
group: nonnest2-hourly-review-repair
# A later heartbeat must not cancel an in-flight Vuong or fit RCA.
cancel-in-progress: false

permissions:
contents: read

jobs:
dispatch-review-repair:
permissions:
contents: read
id-token: write
uses: ./.github/workflows/pr-review-fix-scheduler.yml
with:
target_repository: ContextualWisdomLab/nonnest2
base_branch: master
max_prs: "50"
max_dispatches: "1"
retry_hours: "2"
secrets:
PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}
OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }}
39 changes: 27 additions & 12 deletions .github/workflows/pr-review-fix-scheduler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ on:
required: false
default: ""
type: string
resolve_unreviewed_conflicts:
description: Dispatch bounded conflict repair before the original head is reviewed
required: false
default: true
type: boolean
retry_hours:
description: Minimum hours before redispatching autofix for the same head
required: false
Expand Down Expand Up @@ -83,6 +88,7 @@ jobs:
DRY_RUN: ${{ github.event.client_payload.dry_run == true || github.event.client_payload.dry_run == 'true' || inputs.dry_run == true }}
MAX_PRS: ${{ github.event.client_payload.max_prs || inputs.max_prs || '50' }}
MAX_DISPATCHES: ${{ github.event.client_payload.max_dispatches || inputs.max_dispatches || '1' }}
RESOLVE_UNREVIEWED_CONFLICTS: ${{ github.event.client_payload.resolve_unreviewed_conflicts == true || github.event.client_payload.resolve_unreviewed_conflicts == 'true' || inputs.resolve_unreviewed_conflicts == true }}
RETRY_HOURS: ${{ github.event.client_payload.retry_hours || inputs.retry_hours || '1' }}
AUTOFIX_WORKFLOW: pr-review-autofix.yml
AUTOFIX_REPOSITORY: ContextualWisdomLab/.github
Expand All @@ -104,20 +110,26 @@ jobs:
"${TARGET_REPOSITORY:-<empty>}"
exit 1
fi
if [ -z "$ALLOWED_TARGET_REPOSITORIES" ]; then
echo "::error::Scheduler target repository allowlist is not configured."
exit 1
fi

target_allowed=false
IFS=',' read -r -a allowed_targets <<<"$ALLOWED_TARGET_REPOSITORIES"
for candidate in "${allowed_targets[@]}"; do
candidate="${candidate//[[:space:]]/}"
if [ -n "$candidate" ] && [ "$candidate" = "$TARGET_REPOSITORY" ]; then
target_allowed=true
break
if [ -n "${GITHUB_REPOSITORY:-}" ] &&
[ "$TARGET_REPOSITORY" = "$GITHUB_REPOSITORY" ]; then
echo "Self-targeted scheduler invocation uses the protected caller repository."
target_allowed=true
else
if [ -z "$ALLOWED_TARGET_REPOSITORIES" ]; then
echo "::error::Scheduler target repository allowlist is not configured."
exit 1
fi
done
IFS=',' read -r -a allowed_targets <<<"$ALLOWED_TARGET_REPOSITORIES"
for candidate in "${allowed_targets[@]}"; do
candidate="${candidate//[[:space:]]/}"
if [ -n "$candidate" ] && [ "$candidate" = "$TARGET_REPOSITORY" ]; then
target_allowed=true
break
fi
done
fi
if [ "$target_allowed" != "true" ]; then
printf '::error::Scheduler target repository is not allowlisted: %s.\n' \
"$TARGET_REPOSITORY"
Expand All @@ -127,7 +139,7 @@ jobs:
# A reusable workflow receives its caller's original event payload,
# so the hourly callers arrive as `schedule`, not `workflow_call`.
# Only the direct repository_dispatch surface needs sender binding;
# every invocation still passes the target allowlist above.
# cross-repository invocations still pass the configured allowlist.
if [ "$EVENT_NAME" = "repository_dispatch" ]; then
if [ -z "$ALLOWED_DISPATCH_ACTOR" ] ||
[ "$DISPATCH_ACTOR" != "$ALLOWED_DISPATCH_ACTOR" ] ||
Expand Down Expand Up @@ -308,6 +320,9 @@ jobs:
--autofix-workflow "$AUTOFIX_WORKFLOW"
--autofix-repository "$AUTOFIX_REPOSITORY"
)
if [ "$RESOLVE_UNREVIEWED_CONFLICTS" = "true" ]; then
args+=(--resolve-unreviewed-conflicts)
fi
if [ "$DRY_RUN" = "true" ]; then
args+=(--dry-run)
fi
Expand Down
34 changes: 31 additions & 3 deletions .github/workflows/python-security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,37 @@ jobs:

# Audit every discovered requirements file.
while IFS= read -r req; do
echo "::group::pip-audit -r ${req}"
pip-audit --strict --desc=on -r "${req}" || status=1
echo "::endgroup::"
# A matching requirements-<tool>-ci-overrides.txt (a `uv pip compile --override`
# input, e.g. requirements-strix-ci-overrides.txt) means the *-hashes.txt this
# override applies to pins a version whose declared metadata range intentionally
# conflicts with another pin in the same file (verified safe at override time, not a
# resolution mistake). pip's own dependency resolver -- which pip-audit's default
# `-r` mode still calls even for fully hash-pinned files -- fails on that same
# declared-range conflict regardless of --require-hashes, and plain --no-deps does
# not suppress it (confirmed: --no-deps only skips fetching undeclared transitive
# packages, pip's resolver still cross-checks the packages that *are* listed
# together). --disable-pip bypasses pip's resolver entirely and audits the exact
# pins directly, but it requires every requirement to be an exact version (raises on
# any bare range) -- true for the compiled *-hashes.txt, not necessarily true for the
# hand-maintained raw input (e.g. requirements-strix-ci.txt intentionally leaves
# protobuf as a range). So: hashed output files with an override get
# --disable-pip --no-deps; their raw, non-hash input counterpart is skipped here
# (it is never itself a `pip install --require-hashes` target -- only its compiled
# *-hashes.txt is installed -- and that compiled file is the one audited with full
# transitive coverage).
base="${req%.txt}"
unhashed_base="${base%-hashes}"
if [ "$base" != "$unhashed_base" ] && [ -f "${unhashed_base}-overrides.txt" ]; then
echo "::group::pip-audit -r ${req} (--disable-pip --no-deps: overridden lock)"
pip-audit --strict --desc=on --no-deps --disable-pip -r "${req}" || status=1
echo "::endgroup::"
elif [ "$base" = "$unhashed_base" ] && [ -f "${unhashed_base}-overrides.txt" ]; then
echo "::notice::Skipping pip-audit for ${req}: it is the raw input to an overridden lock (${unhashed_base}-hashes.txt), never itself a pip install --require-hashes target, and its compiled hashes file is audited separately with full resolution."
else
echo "::group::pip-audit -r ${req}"
pip-audit --strict --desc=on -r "${req}" || status=1
echo "::endgroup::"
fi
done < <(find . -type f -name 'requirements*.txt' -not -path './.git/*')

# Audit the project itself when a PEP 621 / lock manifest exists.
Expand Down
55 changes: 17 additions & 38 deletions .github/workflows/strix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ jobs:
test -f "$trusted_strix_source/scripts/ci/strix_quick_gate.sh"
test -f "$trusted_strix_source/scripts/ci/test_strix_quick_gate.sh"
test -f "$trusted_strix_source/scripts/ci/strix_required_workflow_smoke.sh"
test -f "$trusted_strix_source/scripts/ci/strix_report_semantics.py"
test -f "$trusted_strix_source/scripts/ci/validate_strix_runtime_compatibility.py"
{
echo "TRUSTED_STRIX_SOURCE=$trusted_strix_source"
echo "TRUSTED_STRIX_GATE=$trusted_strix_source/scripts/ci/strix_quick_gate.sh"
Expand Down Expand Up @@ -543,7 +545,13 @@ jobs:
# private install umask before creating the credential-bearing Strix
# entry point; the runtime gate still rejects any later relaxation.
umask 022
python3 -m pip install --disable-pip-version-check --no-cache-dir --require-hashes -r requirements-strix-ci-hashes.txt
# --no-deps: strix-agent declares cryptography<49, conflicting with this repo's
# cryptography==50.0.0 pin (CVE-2026-39892 fix, see requirements-strix-ci-overrides.txt).
# --require-hashes already pins every package (including transitive deps) to an exact,
# hash-verified version, so skipping pip's redundant declared-range resolution here is
# safe -- verified locally with --dry-run against this exact file before pushing.
python3 -m pip install --disable-pip-version-check --no-cache-dir --require-hashes --no-deps -r requirements-strix-ci-hashes.txt
python3 -I scripts/ci/validate_strix_runtime_compatibility.py requirements-strix-ci-hashes.txt
strix_executable="$(command -v strix || true)"
if [ -z "$strix_executable" ] || [[ "$strix_executable" != /* ]] \
|| [ ! -f "$strix_executable" ] || [ -L "$strix_executable" ] \
Expand Down Expand Up @@ -835,50 +843,21 @@ jobs:
export "STRIX_PROCESS_${budget_suffix}_SECONDS=$process_budget_seconds"
export "STRIX_TOTAL_${budget_suffix}_SECONDS=5700"

# Capture the gate exit code plus its console output. The gate returns
# exit 1 both for genuine blocking vulnerabilities AND for
# LLM-backend-unavailable outcomes (GitHub Models "Too many requests"
# rate limits, OpenAI quota starvation, 413 tokens_limit_reached
# token-cap, connection/warm-up failures) that could not complete a scan. A backend outage is CI
# infrastructure noise, not a security finding, so it must not fail
# the required check and block merges.
# Preserve the gate exit code and console output. An incomplete backend
# run is not security evidence, so every non-zero gate result remains
# fail-closed while the following always() steps preserve diagnostics.
strix_run_log="$RUNNER_TEMP/strix_gate_console.log"
strix_rc=0
set +e
bash "$TRUSTED_STRIX_GATE" 2>&1 | tee "$strix_run_log"
strix_rc="${PIPESTATUS[0]}"
set -e

if [ "$strix_rc" -eq 0 ]; then
exit 0
fi

# Preserve configuration failures (exit 2) and any unexpected exit
# code as hard failures — only the scan-failure code (1) can be an
# infrastructure/backend-unavailability outcome.
if [ "$strix_rc" -ne 1 ]; then
exit "$strix_rc"
if [ "$strix_rc" -ne 0 ]; then
# Provider-specific catalog failures such as Nvidia_nimException
# remain classified inside the trusted gate; this wrapper never
# converts an incomplete scan into success.
echo "Strix did not produce complete passing security evidence; failing the required check (gate exit ${strix_rc})." >&2
fi

# Recognized signals that the LLM backend was unavailable / starved.
backend_unavailable_signal='RateLimitError|Too many requests\. For more on scraping GitHub|exceeded your current quota|insufficient_quota|billing details|"status"[[:space:]]*:[[:space:]]*"RESOURCE_EXHAUSTED"|tokens_limit_reached|Request body too large|Max size:[[:space:]]*[0-9]+[[:space:]]+tokens|Error code:[[:space:]]*413|LLM CONNECTION FAILED|Could not establish connection to the language model|LLM warm-up failed|Configured model and fallback models were unavailable|Configured Vertex model and fallback models were unavailable|emitted provider infrastructure or failure-signal output|before provider infrastructure failure|litellm(\.exceptions)?\.NotFoundError[^[:cntrl:]]*Nvidia_nimException[^[:cntrl:]]*Error code:[[:space:]]*404'
# Any evidence that a vulnerability was actually reported. Its presence
# forces a hard failure so real findings are NEVER downgraded. Keep the
# severity branch anchored away from identifiers so environment lines
# such as STRIX_FAIL_ON_MIN_SEVERITY do not look like findings.
reported_vulnerability_signal='Vulnerabilities[[:space:]]+[1-9]|(^|[^A-Za-z0-9_])severity[[:space:]]*:'

# Neutral skip only when ALL hold: a backend-unavailability signal is
# present and no vulnerability was reported anywhere. This preserves
# real security gating while keeping uncontrollable provider outages
# from blocking current-head merge progress.
if grep -Eiq "$backend_unavailable_signal" "$strix_run_log" \
&& ! grep -Eiq "$reported_vulnerability_signal" "$strix_run_log"; then
echo "::warning title=Strix backend unavailable::Strix could not complete because its LLM backend was unavailable (rate limit / token cap / connection or warm-up failure) before producing a vulnerability report. Treating as a neutral skip so an infrastructure outage does not block merges; genuine findings still fail the check. See the strix-reports artifact and the run log."
exit 0
fi

echo "Strix reported security findings or failed for a non-backend reason; failing the required check (gate exit ${strix_rc})." >&2
exit "$strix_rc"

- name: Collect Strix reports for artifact upload
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include (no `.`/`..`); a lone `--require-hashes` directive is not trust evidence. See [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md).
Conflict-scope roots fail closed when the immediate parent directory is a symbolic link.
OriginWeave hourly NVIDIA NIM repair is a thin caller at minute 10. See [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md).
nonnest2 hourly NVIDIA NIM repair is a thin caller at minute 16. See [`docs/doctoring/nonnest2-hourly-review-caller.md`](docs/doctoring/nonnest2-hourly-review-caller.md).
7 changes: 7 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ flowchart LR
only established scheduler credentials, and grants job-scoped
`id-token: write`. The reusable engine stays product-neutral.

## nonnest2 hourly caller

`nonnest2-hourly-review-repair.yml` is a thin, read-only caller at minute
16. It names `ContextualWisdomLab/nonnest2` and protected `master`, maps
only established scheduler credentials, and grants job-scoped
`id-token: write`. The reusable engine stays product-neutral.

## Hourly NVIDIA NIM repair gate

```mermaid
Expand Down
Loading
Loading