mirror of
https://github.com/rsyslog/rsyslog.git
synced 2026-06-04 22:13:12 +02:00
devtools: fold local review experiment into planner
Why: The old AI local-review workflow was experimental, duplicated newer validation guidance, and still carried stale review behavior on main. Impact: Local validation keeps useful checks in the maintained planner and removes the obsolete experiment while retaining shared prompt assets. Before/After: Before, local review policy lived partly in an unused AI script and a deleted workflow entry point. After, the planner and skills own the reusable checks and prompt guidance. Technical Overview: Remove ai/local-review-workflow.sh and .agent/workflows/audit.md. Teach devtools/local-validation-plan.sh to derive its default base from RSYSLOG_LOCAL_VALIDATION_BASE, rsyslog.localValidationBase, or the worktree HEAD reflog baseline. Use the same base for local Cubic review so committed branch changes are reviewed against the worktree creation point. Add advisory raw allocation and test antipattern scans, and run fast mock distcheck for distribution-risk test/build changes. Fold the old audit prompt guidance into the local container testing skill as late manual prompt audits without launching another AI CLI. Document ai/ as the central shared prompt-asset library and remove stale references to deleted workflow paths. With the help of AI-Agents: OpenAI Codex
This commit is contained in:
parent
372e6e8a8c
commit
ed91aebc42
@ -41,7 +41,10 @@ This skill standardizes the final step of the development workflow: committing a
|
||||
- **Validation**: Ensure the relevant build/test path passed. For PR-ready
|
||||
implementation work, prefer the local container-testing skill's change-gated
|
||||
validation over unconditional full-suite local runs.
|
||||
- **Multi-Pass AI Audit**: Run the `/audit` workflow for a rigorous, persona-based review (Memory, Concurrency, Standards) using the project's canned prompts.
|
||||
- **Late Prompt Audits**: For non-trivial C/H, concurrency, or test/build
|
||||
plumbing changes, follow the local container-testing skill's late
|
||||
prompt-audit stage. Read and apply the project's canned prompts directly;
|
||||
do not launch another AI CLI from repository scripts.
|
||||
- **Local Cubic**: Run local Cubic review for code changes when `cubic` is
|
||||
installed and reachable. Skip Cubic for documentation-only changes. For
|
||||
tests, workflows, build tooling, and mixed changes, use Cubic when the
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: rsyslog_local_container_testing
|
||||
description: Mirror rsyslog run_checks.yml container validation locally, including Cubic review where applicable, the clang static analyzer job, the change-gated Ubuntu 26.04 run-ci.sh check run, service-skip validation, clean-tree rules, and container path caveats.
|
||||
description: Mirror rsyslog run_checks.yml container validation locally, including the change-gated Ubuntu 26.04 run-ci.sh check run, the clang static analyzer job, late prompt-based audit passes, Cubic review where applicable, service-skip validation, clean-tree rules, and container path caveats.
|
||||
---
|
||||
|
||||
# rsyslog_local_container_testing
|
||||
@ -54,6 +54,14 @@ Optional local linters still remain tool-presence guarded, so missing optional
|
||||
developer tools do not turn a documentation or tooling-only change into a
|
||||
container validation failure.
|
||||
|
||||
By default the helper compares committed branch changes against the worktree's
|
||||
creation baseline: `RSYSLOG_LOCAL_VALIDATION_BASE` when set, otherwise
|
||||
`rsyslog.localValidationBase` from git config when present, otherwise the
|
||||
oldest `HEAD` reflog entry for the worktree. This keeps local Cubic and local
|
||||
diff classification tied to the commit that was `HEAD` when the dedicated
|
||||
worktree was created, even after `origin/main` moves. Use `--base REF` for an
|
||||
intentional one-off override.
|
||||
|
||||
Before starting any heavy local validation, run the relevant cheap local checks
|
||||
that are available in the environment. These checks should be diff-scoped and
|
||||
tool-presence guarded:
|
||||
@ -77,6 +85,14 @@ tool-presence guarded:
|
||||
fuller local environment to cover the gap. CI will not pass with improperly
|
||||
formatted C/H code. Use `devtools/format-code.sh --git-changed` separately
|
||||
when you intentionally want to rewrite local files.
|
||||
- changed C sources or headers also get an advisory raw-allocation scan in
|
||||
`devtools/local-validation-plan.sh --run`. Treat matches for `malloc`,
|
||||
`calloc`, `realloc`, `strdup`, and `strndup` as review prompts; prefer
|
||||
rsyslog allocation helpers where practical, but inspect low-level exceptions
|
||||
before changing code.
|
||||
- changed shell tests should run `devtools/check-test-antipatterns.sh` through
|
||||
the helper. Its findings are advisory prompts for flake-prone constructs such
|
||||
as fixed sleeps, port preselection, fixed ports, and ad-hoc assertions.
|
||||
|
||||
Do not run `cppcheck` routinely unless a maintainer explicitly asks for it; it
|
||||
is too noisy for routine rsyslog PR validation.
|
||||
@ -98,11 +114,12 @@ is too noisy for routine rsyslog PR validation.
|
||||
edits. Internal docs that are not rendered into the user manual, such as
|
||||
`doc/ai/**`, repository agent guides, and skill files, do not require this
|
||||
docs build unless they also change rendered Sphinx inputs.
|
||||
- **Tier 1: default PR-ready gate for code or testbench changes**. Run the
|
||||
local Cubic review when applicable, the existing static-analyzer pass, and a
|
||||
change-gated Ubuntu 26.04 `devtools/run-ci.sh` check. This is the normal
|
||||
local confidence gate for C, parser, module, runtime, `tests/*.sh`,
|
||||
`diag.sh`, `Makefile.am`, `configure.ac`, and `run_checks.yml` changes.
|
||||
- **Tier 1: default PR-ready gate for code or testbench changes**. Run a
|
||||
change-gated Ubuntu 26.04 `devtools/run-ci.sh` check first, then the existing
|
||||
static-analyzer pass, then late prompt-based audit passes and local Cubic
|
||||
review when applicable. This is the normal local confidence gate for C,
|
||||
parser, module, runtime, `tests/*.sh`, `diag.sh`, `Makefile.am`,
|
||||
`configure.ac`, and `run_checks.yml` changes.
|
||||
- **Tier 2: compile portability gate for non-trivial C/header changes**. Add
|
||||
the two build-only compile lanes from `run_checks.yml`:
|
||||
`clang21-ndebug` and `gcc15-gnu23-debug`. Use this when a change touches
|
||||
@ -147,11 +164,48 @@ It should be set by the user or machine profile, for example in `.bashrc`.
|
||||
Deflake and overload experiments are prompt-driven and must use explicit
|
||||
one-off `-jN` values instead of changing this normal validation knob.
|
||||
|
||||
## Late Prompt Audits
|
||||
|
||||
Run prompt-based audits late in the process, after cheap deterministic checks,
|
||||
mock distcheck when needed, the change-gated Ubuntu 26.04 container run, and
|
||||
the static analyzer have either passed or the implementation is otherwise
|
||||
stable enough that no major rewrite is expected. This keeps review tokens spent
|
||||
on the candidate that is likely to ship instead of on intermediate churn.
|
||||
|
||||
Do not launch `codex`, `copilot`, or another AI CLI from repository scripts.
|
||||
The active agent must read the canned prompt and apply it to the current diff,
|
||||
changed functions, and nearby lifecycle paths. When a separate reviewer session
|
||||
or subagent is explicitly available, it may be used, but local validation must
|
||||
not depend on unknown local AI tooling, authentication, or model availability.
|
||||
|
||||
Use these prompt passes when they match the change:
|
||||
|
||||
- changed C sources or headers: read
|
||||
`ai/rsyslog_memory_auditor/base_prompt.txt` and audit changed functions plus
|
||||
nearby allocation, ownership, and cleanup paths. For focused allocation
|
||||
changes, also consult `audit_leaks.txt`, `audit_lifecycle.txt`, and
|
||||
`audit_null_checks.txt` as needed.
|
||||
- lock, queue, worker, thread, timer, atomic, shutdown, retry, or resource
|
||||
ownership changes: read `ai/rsyslog_bug_finder/base_prompt.txt` and perform a
|
||||
path-sensitive resource and concurrency audit, including lock ordering and
|
||||
branch-specific counterexamples for any non-clean findings.
|
||||
- testbench, build, or distribution plumbing changes: perform a project
|
||||
standards audit: check `tests/Makefile.am` registration, `EXTRA_DIST`,
|
||||
"define at top, distribute unconditionally, register conditionally" patterns,
|
||||
RainerScript syntax in touched tests, and mock distcheck coverage.
|
||||
|
||||
Report the prompt audits in the validation summary: which prompts were applied,
|
||||
which findings were fixed, which findings were dismissed with rationale, or
|
||||
that the audit was clean. Skip prompt audits for documentation-only and
|
||||
instruction-only changes unless the edited instructions themselves change audit
|
||||
or validation behavior.
|
||||
|
||||
## Cubic Review
|
||||
|
||||
Run the local `cubic` CLI as an AI review gate when it applies. Cubic is a small
|
||||
local shim that forwards the review request to the configured cloud AI service,
|
||||
so it can normally run in parallel with the local static analyzer.
|
||||
so it should run late on the stabilized candidate. It is a broad review pass,
|
||||
not a fast compile detector.
|
||||
|
||||
- **Docs-only changes**: do not run Cubic.
|
||||
- **Code changes (`*.c`, `*.h`, grammar/parser/runtime/module logic)**: always
|
||||
@ -190,7 +244,10 @@ change-gated Ubuntu 26.04 check would not expose. Do not add lanes by habit.
|
||||
- **Distribution checks (`ubuntu_22_distcheck`, mock distcheck, or
|
||||
`kafka_distcheck_CI`)**: run when adding, renaming, or deleting files/tests,
|
||||
changing `Makefile.am`, `configure.ac`, `m4`, packaging lists, generated
|
||||
artifacts, or Kafka build/test plumbing.
|
||||
artifacts, or Kafka build/test plumbing. The local validation helper runs the
|
||||
fast `make distcheck TEST_RUN_TYPE=MOCK-OK` variant for changed, added,
|
||||
renamed, or deleted test and build-manifest distribution risks before
|
||||
escalating to heavier container lanes.
|
||||
- **Service-specific lanes**: run only when directly relevant to the touched
|
||||
module, tests, helpers, build plumbing, or relevance logic. This includes
|
||||
Kafka, Elasticsearch, VictoriaLogs/omhttp, MySQL/libdbi, imfile, and similar
|
||||
|
||||
@ -126,7 +126,10 @@ Certain modules (Kafka, Elasticsearch, Journald) have heavy integration tests re
|
||||
|
||||
### 8. Memory Lifecycle Validation (Mental Audit)
|
||||
Before committing C changes, agents SHOULD perform a self-audit of memory ownership and lifecycle.
|
||||
- **Rule**: Run the `/audit` workflow. It orchestrates multiple specialized passes (Memory Guardian, Concurrency Architect) using the [Canned Prompts](../../../ai/).
|
||||
- **Rule**: Follow the late prompt-audit stage in
|
||||
[`rsyslog_local_container_testing`](../rsyslog_local_container_testing/SKILL.md).
|
||||
Read and apply the relevant canned prompts under [`ai/`](../../../ai/)
|
||||
directly; do not depend on another local AI CLI being installed.
|
||||
- **Critical Patterns**:
|
||||
- **NULL Checks**: `es_str2cstr()` can return `NULL`. Every call MUST be followed by a `NULL` check.
|
||||
- **Macro Usage**: Prefer `CHKmalloc()` for allocations as it automatically handles the `NULL` check and jumps to `finalize_it`.
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
---
|
||||
description: Perform a comprehensive, multi-pass AI-driven review of current code changes.
|
||||
---
|
||||
|
||||
// turbo-all
|
||||
|
||||
1. **Gather Changes**: Run `git diff` to identify all uncommitted changes.
|
||||
2. **Specialized Persona Audits**:
|
||||
- **Pass 1: The Memory Guardian (Ownership & Leaks)**:
|
||||
- Persona: Senior C Security Auditor.
|
||||
- Canned Prompt: `ai/rsyslog_memory_auditor/base_prompt.txt`
|
||||
- Focus: `RS_RET` paths, `es_str2cstr()` NULL checks, `strdup/free` balance, `CHKmalloc` usage.
|
||||
- **Pass 2: The Concurrency Architect (Races & Lock Logic)**:
|
||||
- Persona: Systems Architect.
|
||||
- Canned Prompt: `ai/rsyslog_bug_finder/base_prompt.txt`
|
||||
- Focus: Data races, lock balance, structured path analysis, counterexamples for non-OK findings.
|
||||
- **Pass 3: The Project Standards Guard (Build & Distribution)**:
|
||||
- Persona: rsyslog Maintainer.
|
||||
- Focus:
|
||||
- `tests/Makefile.am`: "Define at Top, Distribute Unconditionally, Register Conditionally" pattern.
|
||||
- `EXTRA_DIST` completeness.
|
||||
- RainerScript syntax correctness (rsyslog Assistant mode from `ai/support_gpt/base_prompt-gpt4.txt`).
|
||||
- **Pass 4: The Structural & Formatting Auditor**:
|
||||
- Persona: Documentation & Quality Engineer.
|
||||
- Focus:
|
||||
- Check for duplicate section numbering (e.g., two "### 6.").
|
||||
- Check for redundant or duplicate guidance lines (e.g., identical `- Focus:` bullets).
|
||||
- Verify all file links and internal cross-references are valid.
|
||||
3. **Adversarial Pass (Simulation)**:
|
||||
- Persona: Adversarial Tester.
|
||||
- Final Pass: Assume a different set of constraints (e.g., "Review this as if you are a strict static analysis tool like Clang Tidy or Coverity") to find any lingering edge cases.
|
||||
4. **Consolidated Report**:
|
||||
- **CRITICAL**: Functional bugs, leaks, or failing distribution rules (VPATH failures).
|
||||
- **ADVISORY**: Pattern improvements, macro suggestions (`CHKmalloc`), or style nits.
|
||||
- **CLEAN**: Verification of correctly implemented rsyslog patterns.
|
||||
13
AGENTS.md
13
AGENTS.md
@ -16,7 +16,7 @@ To ensure consistency and high-quality contributions, AI agents SHOULD use the f
|
||||
|-------|---------|
|
||||
| [`rsyslog_build`](.agent/skills/rsyslog_build/SKILL.md) | Environment setup and incremental parallel builds. |
|
||||
| [`rsyslog_test`](.agent/skills/rsyslog_test/SKILL.md) | Standardized validation and debugging via `diag.sh`. |
|
||||
| [`rsyslog_local_container_testing`](.agent/skills/rsyslog_local_container_testing/SKILL.md) | CI-style local dev-container validation, analyzer-first flow, service-skip checks, and clean-tree rules. |
|
||||
| [`rsyslog_local_container_testing`](.agent/skills/rsyslog_local_container_testing/SKILL.md) | CI-style local dev-container validation, change-gated Ubuntu 26.04 first, late prompt audits, service-skip checks, and clean-tree rules. |
|
||||
| [`rsyslog_pr_babysitting`](.agent/skills/rsyslog_pr_babysitting/SKILL.md) | Post-push PR monitoring, including CI failures, reruns, and unresolved review-thread checks. |
|
||||
| [`rsyslog_changelog`](.agent/skills/rsyslog_changelog/SKILL.md) | Selective ChangeLog maintenance that follows release-note style and avoids low-signal churn. |
|
||||
| [`rsyslog_doc`](.agent/skills/rsyslog_doc/SKILL.md) | Structured, RAG-optimized documentation and metadata. |
|
||||
@ -103,11 +103,12 @@ validation as the final validation gate when container tooling is available.
|
||||
[`rsyslog_local_container_testing`](.agent/skills/rsyslog_local_container_testing/SKILL.md)
|
||||
skill's PR-ready local validation before reporting the task complete.
|
||||
- PR-ready local container validation means the skill's ordered
|
||||
change-gated sequence: local Cubic where applicable, the Ubuntu 26.04 static
|
||||
analyzer, and the Ubuntu 26.04 `run-ci.sh` check run using the same relevance
|
||||
gates as regular PR CI. Focused container tests are useful targeted evidence,
|
||||
but they are not the final gate unless the skill explicitly allows the
|
||||
reduced lane for the touched area.
|
||||
change-gated sequence: the Ubuntu 26.04 `run-ci.sh` check run using the same
|
||||
relevance gates as regular PR CI, the Ubuntu 26.04 static analyzer where
|
||||
applicable, late prompt-based audit passes where applicable, and local Cubic
|
||||
where applicable. Focused container tests are useful targeted evidence, but
|
||||
they are not the final gate unless the skill explicitly allows the reduced
|
||||
lane for the touched area.
|
||||
- Use the skill's configured CI-equivalent dev image, including Docker Hub dev
|
||||
images when appropriate. Use a locally built image only when validating that
|
||||
local image or the runtime container produced by the task.
|
||||
|
||||
43
ai/README.md
43
ai/README.md
@ -1,30 +1,29 @@
|
||||
# AI and Machine Learning Tooling for rsyslog
|
||||
# AI Prompt Assets for rsyslog
|
||||
|
||||
This directory contains AI and Machine Learning (ML) tools that
|
||||
This directory contains maintained prompt assets that agents may read during
|
||||
rsyslog development, review, documentation, and support workflows.
|
||||
|
||||
---
|
||||
## Purpose
|
||||
|
||||
The `ai` directory is designated for a new generation of tooling that will
|
||||
interface with rsyslog. It will house external AI and ML models and
|
||||
applications. This approach ensures the rsyslog core remains lean and
|
||||
robust while allowing for flexible and powerful extensions.
|
||||
The `ai` directory keeps reusable AI-facing context outside the rsyslog core.
|
||||
These files are not executable validation scripts and should not launch local
|
||||
AI tooling by themselves. Active agents read the relevant prompt text and apply
|
||||
it to the current diff or task.
|
||||
|
||||
---
|
||||
## Current Status
|
||||
## Current Assets
|
||||
|
||||
**No tools exist yet.**
|
||||
- `rsyslog_memory_auditor/`: memory ownership, cleanup, leak, and NULL-check
|
||||
review prompts for C changes.
|
||||
- `rsyslog_bug_finder/`: resource, concurrency, lock-order, and lifecycle
|
||||
review prompt.
|
||||
- `rsyslog_commit_assistant/`: commit message guidance.
|
||||
- `rsyslog_doc_assistant/` and `rsyslog_code_doc_builder/`: documentation
|
||||
prompt assets.
|
||||
- `rsyslog_issue_assistant/` and `support_gpt/`: issue and support prompt
|
||||
assets.
|
||||
|
||||
This directory and its `README.md` have been created to provide a
|
||||
consistent and official location for this work as it progresses.
|
||||
Active development is ongoing, and tools will be added here once they
|
||||
reach a stable state.
|
||||
## Workflow
|
||||
|
||||
---
|
||||
## Vision
|
||||
|
||||
Future tools in this directory will leverage artificial intelligence and
|
||||
machine learning for tasks like advanced log analysis, anomaly detection,
|
||||
and intelligent system monitoring. The goal is to enhance rsyslog's
|
||||
capabilities without integrating complex models directly into the core
|
||||
daemon.
|
||||
Prompt-based audits are intentionally manual from repository tooling. See
|
||||
`.agent/skills/rsyslog_local_container_testing/SKILL.md` for when agents should
|
||||
apply these prompts as late validation passes.
|
||||
|
||||
@ -1,407 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# copilot-policy-alloc.sh
|
||||
#
|
||||
# Purpose:
|
||||
# Multi-stage rsyslog policy check pipeline using GitHub Copilot CLI.
|
||||
# Runs checks from least to most costly, stopping at first issue.
|
||||
#
|
||||
# Validation role:
|
||||
# This script runs local review stages, including local Cubic when available.
|
||||
# Hosted Cubic/Gemini PR comments are useful follow-up review feedback, but
|
||||
# they do not substitute for this local Cubic stage. Likewise, local Cubic
|
||||
# does not substitute for the full local container validation sequence in
|
||||
# .agent/skills/rsyslog_local_container_testing/SKILL.md.
|
||||
#
|
||||
# Default diff:
|
||||
# main...HEAD
|
||||
#
|
||||
# Overrides:
|
||||
# ./copilot-policy-alloc.sh origin/main...HEAD
|
||||
# ./copilot-policy-alloc.sh --cached
|
||||
#
|
||||
# Output:
|
||||
# JSON only (machine-consumable)
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 all checks passed (or no changes)
|
||||
# 1 policy violations found
|
||||
# 3 tool/setup error
|
||||
|
||||
# Configuration
|
||||
POLICY_CHECK_MODEL="gpt-5.1-codex-mini"
|
||||
CUBIC_BASE_BRANCH="main"
|
||||
DEBUG=false
|
||||
SKIP_STAGES=()
|
||||
FORCE_SUBCLI=""
|
||||
|
||||
die() {
|
||||
echo "error: $*" >&2
|
||||
exit 3
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat <<'HELP'
|
||||
Usage: copilot-policy-alloc.sh [OPTIONS] [DIFF_SPEC]
|
||||
|
||||
Multi-stage rsyslog policy check pipeline using AI code review tools.
|
||||
Runs checks from least to most costly, stopping at first issue.
|
||||
|
||||
OPTIONS:
|
||||
--debug Enable debug output to stderr
|
||||
--skip <stage> Skip a pipeline stage (repeatable)
|
||||
Values: alloc-policy, mock-distcheck, cubic
|
||||
--subcli <tool> Force specific CLI tool
|
||||
Values: copilot, codex
|
||||
--cached Use staged changes instead of commits
|
||||
-h, --help Show this help message
|
||||
|
||||
DIFF_SPEC:
|
||||
Default: main...HEAD
|
||||
Examples: origin/main...HEAD, HEAD~1..HEAD
|
||||
|
||||
PIPELINE STAGES:
|
||||
1. alloc-policy - Scans .c/.h files for raw malloc/calloc/realloc/strdup calls
|
||||
2. mock-distcheck - Runs 'make distcheck TEST_RUN_TYPE=MOCK-OK' for packaging validation
|
||||
3. cubic - Runs local cubic code review (final stage)
|
||||
|
||||
NOTE: Agent should build/test working tree BEFORE running this script. For
|
||||
implementation PRs, also run the rsyslog_local_container_testing skill's
|
||||
full ordered container gate when container tooling is available. A focused
|
||||
run-ci.sh invocation is targeted container testing, not full validation,
|
||||
unless that skill explicitly permits the reduced lane.
|
||||
|
||||
EXIT CODES:
|
||||
0 All checks passed (or no changes/skipped)
|
||||
1 Policy violations found
|
||||
3 Tool/setup error
|
||||
|
||||
EXAMPLES:
|
||||
copilot-policy-alloc.sh --debug
|
||||
copilot-policy-alloc.sh --skip cubic
|
||||
copilot-policy-alloc.sh --skip alloc-policy --skip cubic
|
||||
copilot-policy-alloc.sh --skip mock-distcheck
|
||||
copilot-policy-alloc.sh --subcli copilot --debug
|
||||
copilot-policy-alloc.sh --subcli codex origin/main...HEAD
|
||||
HELP
|
||||
exit 0
|
||||
}
|
||||
|
||||
debug() {
|
||||
if $DEBUG; then
|
||||
echo "[DEBUG] $*" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
should_skip() {
|
||||
local stage="$1"
|
||||
for skip in "${SKIP_STAGES[@]}"; do
|
||||
if [[ "$skip" == "$stage" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || die "missing required command: $1"
|
||||
}
|
||||
|
||||
need_cmd git
|
||||
# Either codex or copilot required (check later)
|
||||
|
||||
has_issues() {
|
||||
local output="$1"
|
||||
# Try JSON first (cubic, codex output)
|
||||
if has_issues_array "$output"; then
|
||||
return 0
|
||||
fi
|
||||
# For text streams, check if output is non-empty (skip common "success" patterns)
|
||||
if [[ -n "$output" ]] && ! echo "$output" | grep -qE '^(\s*|\{\s*"issues"\s*:\s*\[\s*\]\s*\})$'; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
has_issues_array() {
|
||||
local json="$1"
|
||||
# Check if issues array has elements: "issues":[...] with content
|
||||
echo "$json" | grep -q '"issues"\s*:\s*\[[^]]\+\]'
|
||||
}
|
||||
|
||||
check_allocation_policy() {
|
||||
local diff_file="$1"
|
||||
|
||||
# Read diff content
|
||||
local diff_content
|
||||
diff_content=$(<"$diff_file")
|
||||
|
||||
# Compact, CLI-safe policy prompt
|
||||
local PROMPT=$'IMPORTANT: Do NOT read AGENTS.md, DEVELOPING.md, or other repo guidance files. This is a simple pattern-matching task.\n\n'
|
||||
PROMPT+=$'Workflow: rsyslog policy-alloc\n\n'
|
||||
PROMPT+=$'Task: Scan ONLY added/modified lines in the diff for raw allocation calls:\n'
|
||||
PROMPT+=$'malloc(, calloc(, realloc(, strdup(, strndup(\n'
|
||||
PROMPT+=$'Regex: \\b(malloc|calloc|realloc|strdup|strndup)\\s*\\(\n\n'
|
||||
PROMPT+=$'A match is a violation unless the same statement/expression clearly uses an approved project wrapper/macro '
|
||||
PROMPT+=$'(e.g. CHKmalloc/CHKrealloc or project strdup wrapper). '
|
||||
PROMPT+=$'If uncertain, report as warning with lower confidence.\n\n'
|
||||
PROMPT+=$'Output JSON ONLY (no prose). Match this exact format:\n'
|
||||
PROMPT+=$'{\n'
|
||||
PROMPT+=$' "issues": [\n'
|
||||
PROMPT+=$' {\n'
|
||||
PROMPT+=$' "file": "<path>",\n'
|
||||
PROMPT+=$' "line": <int>,\n'
|
||||
PROMPT+=$' "severity": "error|warning|info",\n'
|
||||
PROMPT+=$' "code": "ALLOC_RAW_CALL",\n'
|
||||
PROMPT+=$' "message": "<description>",\n'
|
||||
PROMPT+=$' "suggestion": "<recommended fix>"\n'
|
||||
PROMPT+=$' }\n'
|
||||
PROMPT+=$' ]\n'
|
||||
PROMPT+=$'}\n\n'
|
||||
PROMPT+=$'If no issues found, return: {"issues":[]}\n\n'
|
||||
PROMPT+=$'Analyze this diff:\n\n'
|
||||
PROMPT+="$diff_content"
|
||||
|
||||
if $DEBUG; then
|
||||
debug "=== Prompt content (first 500 chars) ==="
|
||||
echo "${PROMPT:0:500}..." >&2
|
||||
debug "=== Diff file size: $(wc -l < "$diff_file") lines ==="
|
||||
debug "=== Diff file content preview (first 20 lines) ==="
|
||||
head -20 "$diff_file" >&2
|
||||
fi
|
||||
|
||||
# Prefer codex (faster), fall back to copilot, or force via --subcli
|
||||
if [[ "$FORCE_SUBCLI" == "codex" ]] || { [[ -z "$FORCE_SUBCLI" ]] && command -v codex >/dev/null 2>&1; }; then
|
||||
if [[ "$FORCE_SUBCLI" == "codex" ]] && ! command -v codex >/dev/null 2>&1; then
|
||||
die "Forced --subcli codex but codex not found"
|
||||
fi
|
||||
debug "Using codex for policy check"
|
||||
debug "Command: codex exec --model $POLICY_CHECK_MODEL --dangerously-bypass-approvals-and-sandbox <PROMPT>"
|
||||
if $DEBUG; then
|
||||
codex exec \
|
||||
--model "$POLICY_CHECK_MODEL" \
|
||||
--dangerously-bypass-approvals-and-sandbox \
|
||||
"$PROMPT"
|
||||
else
|
||||
# Suppress codex's verbose output (stderr) when not in debug mode
|
||||
codex exec \
|
||||
--model "$POLICY_CHECK_MODEL" \
|
||||
--dangerously-bypass-approvals-and-sandbox \
|
||||
"$PROMPT" 2>/dev/null
|
||||
fi
|
||||
elif [[ "$FORCE_SUBCLI" == "copilot" ]] || { [[ -z "$FORCE_SUBCLI" ]] && command -v copilot >/dev/null 2>&1; }; then
|
||||
if [[ "$FORCE_SUBCLI" == "copilot" ]] && ! command -v copilot >/dev/null 2>&1; then
|
||||
die "Forced --subcli copilot but copilot not found"
|
||||
fi
|
||||
debug "Using copilot for policy check"
|
||||
debug "Command: copilot --model $POLICY_CHECK_MODEL --add-dir /tmp --allow-all-tools --prompt <PROMPT>"
|
||||
copilot \
|
||||
--model "$POLICY_CHECK_MODEL" \
|
||||
--add-dir /tmp \
|
||||
--allow-all-tools \
|
||||
--prompt "$PROMPT"
|
||||
else
|
||||
debug "Neither codex nor copilot CLI found, skipping check"
|
||||
# Return valid empty JSON matching cubic format
|
||||
echo '{"issues":[]}'
|
||||
fi
|
||||
}
|
||||
|
||||
run_cubic_review() {
|
||||
if ! command -v cubic >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
debug "Command: cubic review --base $CUBIC_BASE_BRANCH --json"
|
||||
cubic review --base "$CUBIC_BASE_BRANCH" --json 2>&1 || true
|
||||
}
|
||||
|
||||
run_mock_distcheck() {
|
||||
debug "Mock distcheck: Running make distcheck TEST_RUN_TYPE=MOCK-OK..."
|
||||
|
||||
# Run distcheck - let output stream directly (don't capture)
|
||||
# Return exit code for caller to check
|
||||
if ! make distcheck TEST_RUN_TYPE=MOCK-OK -j$(nproc) 2>&1; then
|
||||
return 1 # Signal failure
|
||||
fi
|
||||
return 0 # Success
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
DIFF_ARGS=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
show_help
|
||||
;;
|
||||
--debug)
|
||||
DEBUG=true
|
||||
shift
|
||||
;;
|
||||
--skip)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
die "--skip requires an argument (alloc-policy|mock-distcheck|cubic)"
|
||||
fi
|
||||
SKIP_STAGES+=("$2")
|
||||
shift 2
|
||||
;;
|
||||
--subcli)
|
||||
if [[ $# -lt 2 ]]; then
|
||||
die "--subcli requires an argument (copilot|codex)"
|
||||
fi
|
||||
FORCE_SUBCLI="$2"
|
||||
shift 2
|
||||
;;
|
||||
--cached)
|
||||
DIFF_ARGS+=(--cached)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
DIFF_ARGS+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Default diff target if none specified
|
||||
if [[ ${#DIFF_ARGS[@]} -eq 0 ]]; then
|
||||
DIFF_ARGS+=("main...HEAD")
|
||||
fi
|
||||
|
||||
debug "Debug mode enabled"
|
||||
debug "Diff args: ${DIFF_ARGS[*]}"
|
||||
if [[ ${#SKIP_STAGES[@]} -gt 0 ]]; then
|
||||
debug "Skipping stages: ${SKIP_STAGES[*]}"
|
||||
fi
|
||||
if [[ -n "$FORCE_SUBCLI" ]]; then
|
||||
debug "Forcing subcli: $FORCE_SUBCLI"
|
||||
fi
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || die "not a git repo?"
|
||||
cd "$REPO_ROOT"
|
||||
debug "Repository root: $REPO_ROOT"
|
||||
|
||||
TMP_DIFF="$(mktemp -p /tmp copilot_policy_alloc.XXXXXX.diff)"
|
||||
cleanup() {
|
||||
rm -f "$TMP_DIFF"
|
||||
# distcheck leaves read-only directories - restore write perms before removing
|
||||
if compgen -G "rsyslog-*.daily" > /dev/null 2>&1; then
|
||||
chmod -R u+w rsyslog-*.daily 2>/dev/null || true
|
||||
rm -rf rsyslog-*.daily
|
||||
fi
|
||||
rm -f rsyslog-*.tar.gz 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
debug "Temp diff file: $TMP_DIFF"
|
||||
|
||||
# Generate minimal diff (unified=0 keeps token usage low)
|
||||
debug "Generating diff..."
|
||||
debug "Command: git diff --unified=0 --no-color ${DIFF_ARGS[*]}"
|
||||
git diff --unified=0 --no-color "${DIFF_ARGS[@]}" >"$TMP_DIFF" || true
|
||||
|
||||
# Also include unstaged changes in working directory
|
||||
if [[ "${DIFF_ARGS[*]}" != *"--cached"* ]]; then
|
||||
debug "Command: git diff --unified=0 --no-color (unstaged)"
|
||||
git diff --unified=0 --no-color >>"$TMP_DIFF" || true
|
||||
fi
|
||||
|
||||
# Check for untracked files
|
||||
debug "Command: git ls-files --others --exclude-standard"
|
||||
UNTRACKED_FILES=$(git ls-files --others --exclude-standard)
|
||||
if [[ -n "$UNTRACKED_FILES" ]]; then
|
||||
debug "Found untracked files:"
|
||||
$DEBUG && echo "$UNTRACKED_FILES" >&2
|
||||
|
||||
# Add untracked file contents to diff as proper unified diffs
|
||||
# Skip: the script itself, build artifacts, and generated tarballs
|
||||
while IFS= read -r file; do
|
||||
if [[ -f "$file" && "$file" != "ai/copilot-policy-alloc.sh" && "$file" != rsyslog-*.daily/* && "$file" != *.tar.gz ]]; then
|
||||
line_count=$(wc -l < "$file")
|
||||
# Limit file size to prevent argument list too long
|
||||
if [[ $line_count -lt 10000 ]]; then
|
||||
echo "diff --git a/$file b/$file" >>"$TMP_DIFF"
|
||||
echo "new file mode 100644" >>"$TMP_DIFF"
|
||||
echo "index 0000000..0000000" >>"$TMP_DIFF"
|
||||
echo "--- /dev/null" >>"$TMP_DIFF"
|
||||
echo "+++ b/$file" >>"$TMP_DIFF"
|
||||
echo "@@ -0,0 +1,$line_count @@" >>"$TMP_DIFF"
|
||||
# Add all lines as additions with proper + prefix (no space)
|
||||
sed 's/^/+/' "$file" >>"$TMP_DIFF"
|
||||
else
|
||||
debug "Skipping large untracked file: $file ($line_count lines)"
|
||||
fi
|
||||
fi
|
||||
done <<< "$UNTRACKED_FILES"
|
||||
fi
|
||||
|
||||
DIFF_IS_EMPTY=false
|
||||
if [[ ! -s "$TMP_DIFF" ]]; then
|
||||
debug "No changes detected: no diff and no untracked files"
|
||||
echo '{"issues":[]}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Pipeline: Run checks from least to most costly
|
||||
debug "Starting pipeline checks..."
|
||||
|
||||
# Stage 1: Allocation policy check (only for .c/.h files)
|
||||
if should_skip "alloc-policy"; then
|
||||
debug "Stage 1: Skipped via --skip alloc-policy"
|
||||
RESULT='{"issues":[]}'
|
||||
elif grep -q '^[+].*\.\(c\|h\)' "$TMP_DIFF" || git diff --name-only "${DIFF_ARGS[@]}" 2>/dev/null | grep -q '\.\(c\|h\)$'; then
|
||||
debug "Stage 1: Running allocation policy check (C/H files detected)..."
|
||||
RESULT=$(check_allocation_policy "$TMP_DIFF")
|
||||
debug "Stage 1 result:"
|
||||
$DEBUG && echo "$RESULT" | head -20 >&2
|
||||
if has_issues "$RESULT"; then
|
||||
debug "Issues found in Stage 1, stopping pipeline"
|
||||
echo "$RESULT"
|
||||
exit 1
|
||||
fi
|
||||
debug "Stage 1 passed"
|
||||
else
|
||||
debug "Stage 1: Skipped (no .c or .h files modified)"
|
||||
RESULT='{"issues":[]}'
|
||||
fi
|
||||
|
||||
# Stage 2: Add more checks here (in cost order)
|
||||
# ...
|
||||
|
||||
# Stage 2: Mock distcheck
|
||||
if should_skip "mock-distcheck"; then
|
||||
debug "Stage 2: Skipped via --skip mock-distcheck"
|
||||
else
|
||||
debug "Stage 2: Running mock distcheck..."
|
||||
if ! run_mock_distcheck; then
|
||||
debug "Issues found in Stage 2, stopping pipeline"
|
||||
exit 1
|
||||
fi
|
||||
debug "Stage 2 passed"
|
||||
fi
|
||||
|
||||
# Final stage: Run cubic if available
|
||||
debug "Final stage: Checking for cubic..."
|
||||
if should_skip "cubic"; then
|
||||
debug "Cubic: Skipped via --skip cubic"
|
||||
else
|
||||
CUBIC_OUTPUT=$(run_cubic_review)
|
||||
if [[ -n "$CUBIC_OUTPUT" ]]; then
|
||||
debug "Cubic output received:"
|
||||
$DEBUG && echo "$CUBIC_OUTPUT" | head -20 >&2
|
||||
# Check if cubic JSON has non-empty issues array
|
||||
if has_issues_array "$CUBIC_OUTPUT"; then
|
||||
debug "Cubic detected issues"
|
||||
echo "$CUBIC_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
debug "Cubic ran but found no issues"
|
||||
else
|
||||
debug "Cubic not installed or no output"
|
||||
fi
|
||||
fi
|
||||
|
||||
# All checks passed
|
||||
debug "All pipeline checks passed"
|
||||
echo "$RESULT"
|
||||
exit 0
|
||||
@ -22,7 +22,11 @@
|
||||
set -eu
|
||||
|
||||
mode=plan
|
||||
base_ref="${RSYSLOG_LOCAL_VALIDATION_BASE:-origin/main}"
|
||||
base_ref="${RSYSLOG_LOCAL_VALIDATION_BASE:-}"
|
||||
base_ref_source=environment
|
||||
if [ -z "$base_ref" ]; then
|
||||
base_ref_source=auto
|
||||
fi
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
@ -34,11 +38,17 @@ unstaged tracked changes, and untracked files. Generated build products should
|
||||
be cleaned before using this helper.
|
||||
|
||||
Environment knobs:
|
||||
RSYSLOG_LOCAL_VALIDATION_BASE Base ref for committed branch changes (default: origin/main)
|
||||
RSYSLOG_LOCAL_VALIDATION_BASE Base ref for committed branch changes
|
||||
RSYSLOG_LOCAL_BUILD_JOBS Local build concurrency (default: 10)
|
||||
RSYSLOG_LOCAL_CHECK_JOBS Local make check concurrency (default: 10)
|
||||
RSYSLOG_LOCAL_DOC_JOBS Local Sphinx doc build jobs (default: nproc)
|
||||
|
||||
Without --base or RSYSLOG_LOCAL_VALIDATION_BASE, the helper uses
|
||||
rsyslog.localValidationBase from git config when set, then the oldest HEAD
|
||||
reflog entry for this worktree, then origin/main as a fallback. In normal
|
||||
dedicated worktrees this makes local review compare against the commit that was
|
||||
HEAD when the worktree was created, even after origin/main moves.
|
||||
|
||||
The --run mode exits on the first validation finding from a tool that actually
|
||||
runs. Missing local tools produce warnings, not failures; hosted CI or a fuller
|
||||
local environment must cover the skipped plumbing.
|
||||
@ -57,6 +67,7 @@ while [ "$#" -gt 0 ]; do
|
||||
exit 2
|
||||
fi
|
||||
base_ref="$2"
|
||||
base_ref_source=cli
|
||||
shift 2
|
||||
;;
|
||||
-h | --help)
|
||||
@ -74,12 +85,33 @@ done
|
||||
repo_root="$(git rev-parse --show-toplevel)"
|
||||
cd "$repo_root"
|
||||
|
||||
resolve_default_base_ref() {
|
||||
configured_base="$(git config --get rsyslog.localValidationBase 2>/dev/null || true)"
|
||||
if [ -n "$configured_base" ]; then
|
||||
printf '%s\n' "$configured_base"
|
||||
return
|
||||
fi
|
||||
|
||||
reflog_base="$(git reflog --format=%H HEAD 2>/dev/null | tail -n 1 || true)"
|
||||
if [ -n "$reflog_base" ] && git rev-parse --verify "$reflog_base^{commit}" >/dev/null 2>&1; then
|
||||
printf '%s\n' "$reflog_base"
|
||||
return
|
||||
fi
|
||||
|
||||
printf '%s\n' origin/main
|
||||
}
|
||||
|
||||
if [ -z "$base_ref" ]; then
|
||||
base_ref="$(resolve_default_base_ref)"
|
||||
fi
|
||||
|
||||
tmp_changed="$(mktemp)"
|
||||
tmp_status="$(mktemp)"
|
||||
tmp_shell="$(mktemp)"
|
||||
tmp_python="$(mktemp)"
|
||||
tmp_c="$(mktemp)"
|
||||
cleanup() {
|
||||
rm -f "$tmp_changed" "$tmp_shell" "$tmp_python" "$tmp_c"
|
||||
rm -f "$tmp_changed" "$tmp_status" "$tmp_shell" "$tmp_python" "$tmp_c"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
@ -89,8 +121,14 @@ if ! git rev-parse --verify "$base_ref" >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
{
|
||||
git diff --name-only --diff-filter=d "$base_ref"...HEAD
|
||||
git diff --name-only --diff-filter=d HEAD
|
||||
git diff --name-status --diff-filter=ACMRD "$base_ref"...HEAD
|
||||
git diff --name-status --diff-filter=ACMRD HEAD
|
||||
git ls-files --others --exclude-standard | sed 's/^/A /'
|
||||
} | sort -u > "$tmp_status"
|
||||
|
||||
{
|
||||
git diff --name-only "$base_ref"...HEAD
|
||||
git diff --name-only HEAD
|
||||
git ls-files --others --exclude-standard
|
||||
} | sort -u > "$tmp_changed"
|
||||
|
||||
@ -116,6 +154,7 @@ has_testbench_plumbing=0
|
||||
has_test_shell_only=0
|
||||
has_c=0
|
||||
has_runtime_ci=0
|
||||
has_dist_risk=0
|
||||
|
||||
if matches_any '^(doc/source/|doc/Makefile\.am$|doc/tools/|doc/requirements\.txt$|doc/source/conf\.py$)'; then
|
||||
has_rendered_docs=1
|
||||
@ -139,6 +178,22 @@ fi
|
||||
if matches_any '^((runtime|grammar|tools|plugins|contrib|compat)/|tests/|[^/]+\.(c|h)$|configure\.ac$|Makefile\.am$|m4/|\.github/workflows/run_checks\.yml$)'; then
|
||||
has_runtime_ci=1
|
||||
fi
|
||||
if awk '
|
||||
BEGIN { FS = "\t" }
|
||||
/^[ACDMR]/ {
|
||||
for (i = 2; i <= NF; i++) {
|
||||
if ($i ~ /^tests\/[^/]+\.sh$/ ||
|
||||
$i ~ /(^|\/)Makefile\.am$/ ||
|
||||
$i == "configure.ac" ||
|
||||
$i ~ /^m4\//) {
|
||||
found = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
END { exit found ? 0 : 1 }
|
||||
' "$tmp_status"; then
|
||||
has_dist_risk=1
|
||||
fi
|
||||
|
||||
agent_docs_only=0
|
||||
if matches_only '(^|/)AGENTS(\.local)?\.md$|^\.agent/skills/|^\.codex/skills/'; then
|
||||
@ -155,9 +210,17 @@ if [ "$has_rendered_docs" -eq 0 ] && matches_only '(^|/)AGENTS(\.local)?\.md$|^\
|
||||
validation_tooling_only=1
|
||||
fi
|
||||
|
||||
grep -E '\.sh$' "$tmp_changed" > "$tmp_shell" || true
|
||||
grep -E '\.py$' "$tmp_changed" > "$tmp_python" || true
|
||||
grep -E '\.(c|h)$' "$tmp_changed" > "$tmp_c" || true
|
||||
: > "$tmp_shell"
|
||||
: > "$tmp_python"
|
||||
: > "$tmp_c"
|
||||
while IFS= read -r file; do
|
||||
[ -f "$file" ] || continue
|
||||
case "$file" in
|
||||
*.sh) printf '%s\n' "$file" >> "$tmp_shell" ;;
|
||||
*.py) printf '%s\n' "$file" >> "$tmp_python" ;;
|
||||
*.c | *.h) printf '%s\n' "$file" >> "$tmp_c" ;;
|
||||
esac
|
||||
done < "$tmp_changed"
|
||||
|
||||
classification=general
|
||||
if [ "$agent_docs_only" -eq 1 ]; then
|
||||
@ -190,7 +253,7 @@ check_jobs="${RSYSLOG_LOCAL_CHECK_JOBS:-10}"
|
||||
|
||||
print_plan() {
|
||||
echo "Local validation classification: $classification"
|
||||
echo "Base ref: $base_ref"
|
||||
echo "Base ref: $base_ref ($base_ref_source)"
|
||||
echo
|
||||
echo "Changed files:"
|
||||
sed 's/^/ /' "$tmp_changed"
|
||||
@ -212,16 +275,23 @@ print_plan() {
|
||||
;;
|
||||
test-shell-only)
|
||||
echo " - shellcheck changed tests if shellcheck is installed."
|
||||
echo " - devtools/check-test-antipatterns.sh on changed tests."
|
||||
echo " - Focused container test with CI_MAKE_CHECK_TESTS set to changed tests."
|
||||
echo " - Add broad Ubuntu 26.04 run if the test changes timing, ports, process lifecycle, or shared behavior."
|
||||
;;
|
||||
testbench-plumbing | code-or-ci | general)
|
||||
echo " - Available cheap diff-scoped linters."
|
||||
echo " - Cubic where applicable."
|
||||
echo " - Ubuntu 26.04 static analyzer for C/testbench/code changes."
|
||||
echo " - Advisory raw allocation scan for changed C/H files."
|
||||
echo " - devtools/check-test-antipatterns.sh on changed tests."
|
||||
echo " - Change-gated Ubuntu 26.04 run-ci.sh check."
|
||||
echo " - Ubuntu 26.04 static analyzer for C/testbench/code changes."
|
||||
echo " - Late prompt-based audit passes for applicable C/H, concurrency, test, or build changes."
|
||||
echo " - Cubic where applicable."
|
||||
;;
|
||||
esac
|
||||
if [ "$has_dist_risk" -eq 1 ]; then
|
||||
echo " - make distcheck TEST_RUN_TYPE=MOCK-OK -j<jobs> for distribution-risk changes."
|
||||
fi
|
||||
}
|
||||
|
||||
run_shellcheck() {
|
||||
@ -273,6 +343,82 @@ run_format_code_check() {
|
||||
fi
|
||||
}
|
||||
|
||||
run_raw_alloc_scan() {
|
||||
if [ ! -s "$tmp_c" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
findings="$(
|
||||
{
|
||||
git diff --unified=0 --no-color "$base_ref"...HEAD -- '*.c' '*.h'
|
||||
git diff --unified=0 --no-color HEAD -- '*.c' '*.h'
|
||||
while IFS= read -r file; do
|
||||
case "$file" in
|
||||
*.c | *.h)
|
||||
if git ls-files --others --exclude-standard -- "$file" | grep -q .; then
|
||||
printf '+++ b/%s\n' "$file"
|
||||
awk '{ print "+" $0 }' "$file"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done < "$tmp_c"
|
||||
} | awk '
|
||||
/^\+\+\+ / {
|
||||
file = substr($0, 7)
|
||||
sub(/^b\//, "", file)
|
||||
next
|
||||
}
|
||||
/^\+[^+]/ {
|
||||
line = substr($0, 2)
|
||||
if (line ~ /(^|[^A-Za-z0-9_])(malloc|calloc|realloc|strdup|strndup)[[:space:]]*\(/ &&
|
||||
line !~ /(^|[^A-Za-z0-9_])CHK(malloc|realloc)[[:space:]]*\(/) {
|
||||
if (file == "") {
|
||||
file = "(untracked C/H file)"
|
||||
}
|
||||
print file ": " line
|
||||
}
|
||||
}
|
||||
'
|
||||
)"
|
||||
|
||||
if [ -n "$findings" ]; then
|
||||
echo "warning: raw allocation calls found in changed C/H lines; prefer rsyslog allocation helpers where practical" >&2
|
||||
printf '%s\n' "$findings" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
run_test_antipattern_scan() {
|
||||
found_tests=0
|
||||
while IFS= read -r file; do
|
||||
case "$file" in
|
||||
tests/*/*.sh)
|
||||
;;
|
||||
tests/*.sh)
|
||||
[ -f "$file" ] || continue
|
||||
found_tests=1
|
||||
;;
|
||||
esac
|
||||
done < "$tmp_changed"
|
||||
if [ "$found_tests" -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ -x devtools/check-test-antipatterns.sh ]; then
|
||||
# This helper is advisory and exits successfully even with findings.
|
||||
while IFS= read -r file; do
|
||||
case "$file" in
|
||||
tests/*/*.sh)
|
||||
;;
|
||||
tests/*.sh)
|
||||
[ -f "$file" ] || continue
|
||||
devtools/check-test-antipatterns.sh "$file"
|
||||
;;
|
||||
esac
|
||||
done < "$tmp_changed"
|
||||
else
|
||||
echo "warning: devtools/check-test-antipatterns.sh missing or not executable; skipping test antipattern scan" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
run_docs_build() {
|
||||
if [ ! -x ./doc/tools/build-doc-linux.sh ]; then
|
||||
echo "warning: doc/tools/build-doc-linux.sh missing or not executable; skipping docs build" >&2
|
||||
@ -324,12 +470,36 @@ run_cubic_if_available() {
|
||||
;;
|
||||
esac
|
||||
if command -v cubic >/dev/null 2>&1; then
|
||||
cubic review --print-logs --base HEAD
|
||||
cubic review --print-logs --base "$base_ref"
|
||||
else
|
||||
echo "warning: cubic not installed; skipping local Cubic review" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
run_mock_distcheck_if_needed() {
|
||||
if [ "$has_dist_risk" -ne 1 ]; then
|
||||
return 0
|
||||
fi
|
||||
if ! command -v make >/dev/null 2>&1; then
|
||||
echo "warning: make not installed; skipping mock distcheck" >&2
|
||||
return 0
|
||||
fi
|
||||
make distcheck TEST_RUN_TYPE=MOCK-OK -j"$(nproc_jobs)"
|
||||
}
|
||||
|
||||
run_prompt_audit_reminder() {
|
||||
case "$classification" in
|
||||
agent-doc-only | internal-doc-only | rendered-docs | local-validation-tooling)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
echo "Prompt audit reminder: after deterministic checks, apply relevant canned prompts manually." >&2
|
||||
echo " - C/H memory lifecycle: ai/rsyslog_memory_auditor/base_prompt.txt" >&2
|
||||
echo " - Locks/queues/threads/resources: ai/rsyslog_bug_finder/base_prompt.txt" >&2
|
||||
echo " - Test/build plumbing: project standards audit from rsyslog_local_container_testing skill" >&2
|
||||
echo "Do not launch another AI CLI from this helper." >&2
|
||||
}
|
||||
|
||||
run_static_analyzer() {
|
||||
have_container_tooling || return 0
|
||||
have_devcontainer_script || return 0
|
||||
@ -370,7 +540,17 @@ run_change_gated_ubuntu26() {
|
||||
}
|
||||
|
||||
run_focused_test_shell() {
|
||||
tests="$(grep -E '^tests/[^/]+\.sh$' "$tmp_changed" | sed 's#^tests/##' | tr '\n' ' ')"
|
||||
tests="$(awk '
|
||||
BEGIN { FS = "\t" }
|
||||
$1 !~ /^D/ {
|
||||
for (i = 2; i <= NF; i++) {
|
||||
if ($i ~ /^tests\/[^/]+\.sh$/) {
|
||||
sub(/^tests\//, "", $i)
|
||||
printf "%s ", $i
|
||||
}
|
||||
}
|
||||
}
|
||||
' "$tmp_status")"
|
||||
if [ -z "$tests" ]; then
|
||||
return 0
|
||||
fi
|
||||
@ -400,6 +580,8 @@ echo "Executing local validation plan..."
|
||||
run_shellcheck
|
||||
run_python_style
|
||||
run_format_code_check
|
||||
run_raw_alloc_scan
|
||||
run_test_antipattern_scan
|
||||
git diff --check "$base_ref"...HEAD
|
||||
git diff --cached --check
|
||||
git diff --check
|
||||
@ -415,11 +597,14 @@ rendered-docs)
|
||||
run_docs_build
|
||||
;;
|
||||
test-shell-only)
|
||||
run_mock_distcheck_if_needed
|
||||
run_focused_test_shell
|
||||
;;
|
||||
testbench-plumbing | code-or-ci | general)
|
||||
run_cubic_if_available
|
||||
run_static_analyzer
|
||||
run_mock_distcheck_if_needed
|
||||
run_change_gated_ubuntu26
|
||||
run_static_analyzer
|
||||
run_prompt_audit_reminder
|
||||
run_cubic_if_available
|
||||
;;
|
||||
esac
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user