## What
Adds a *Script and process execution design principles (do not regress)*
section to `.github/instructions/instructions.md` codifying three
invariants for script and PHP Script Server execution:
1. One read attempt per command, no looping to EOF.
2. Never block the polling thread in `waitpid()` — single non-blocking
WNOHANG attempt, then hand off to the async abandoned-pid sweep.
3. Script timeouts must go through `nft_popen()`/`nft_pchild()`
(pid-tracked), not a native `popen()`/`pclose()` fallback.
## Why
While investigating a reported poller slowdown, these three invariants
were each found violated: #614 turned `nft_pclose()` into a
bounded-but-blocking spin/sleep/SIGTERM/SIGKILL sequence on the polling
hot path, and 1.2.x's `nft_pclose()` has an unbounded blocking
`waitpid()` there. Writing this down so future AI-assisted changes don't
reintroduce either. Tracked in #632.
## What was tested
Docs-only change; no build/test impact.
Signed-off-by: TheWitness <thewitness@cacti.net>
## Summary
A batch of small, independent, unaddressed bugs from the open-issue
backlog. None of these overlapped with any currently open PR's actual
diff (verified by inspecting each candidate PR's changes directly, not
just its declared `Closes` list).
## Fixes
- **`poll_host()` skips `mysql_thread_end()` when the device row is
missing** — the early `return` on `num_rows != 1` released both DB
connections and freed six allocations, but never called
`mysql_thread_end()`, unlike the other two exit paths. Added the missing
call.
- **SNMPv3 passphrase scrubbing flag never set** — `zero_sensitive` was
a function-local initialized to 0 and never assigned, so every guarded
`memset()` was dead code. Made scrubbing of this module's own heap
copies (`Apsz`/`Xpsz`) unconditional, and moved the wipe to immediately
precede each free (including both `generate_Ku()` error paths) after
review found the first pass still scrubbed before assignment. Left the
caller's `snmp_password`/`snmp_priv_passphrase` alone rather than also
scrubbing those in place — those are `host_t`-owned and get reused for
later session rebuilds against the same host, so zeroing them would have
broken subsequent polls.
- **`php_readpipe()` FD_SET without an FD_SETSIZE check** — `FD_SET()`
doesn't range-check, so a read descriptor at or above `FD_SETSIZE` (1024
on glibc) wrote past the end of the on-stack `fd_set`. Added a bounds
check; on an out-of-range descriptor it marks the result undefined and
closes the slot (a review finding caught the first version recursing
without bound through `php_init()` → `php_readpipe()` under sustained
descriptor exhaustion, so it no longer restarts synchronously from
here).
- **Signal handler never re-arms, so the second SIGPIPE kills the
poller** — every fatal signal reset itself to `SIG_DFL` and never
re-armed. That's the right idiom for a real fault (SIGSEGV and friends
re-execute and die with a core), but SIGPIPE is a routine, recurring
condition — a second one previously killed the whole poller. A review
finding pointed out that re-arming only at the end still left a window
(signal dispositions are process-wide) where another thread's SIGPIPE
could hit `SIG_DFL`; fixed by never resetting SIGPIPE's disposition in
the first place.
- **spine fails to link on Fedora: undefined reference to
`usmDESPrivProtocol`** — some distributions ship a `net-snmp-config.h`
that advertises DES as the default privacy protocol while the shipped
`libnetsnmp` doesn't export the symbol. Added an `AC_LINK_IFELSE` probe
for the actual symbol and guarded the fallback to use
`usmAESPrivProtocol` when it's absent.
- **Poller results ≥1024 bytes silently truncated to 1022** —
`db_escape()` capped its internal trim buffer at a fixed `DBL_BUFSIZE`
regardless of the caller's `max_size`, so raising
`--with-results-buffer` never helped. The trim buffer now scales with
`max_size` (a review finding caught the trim-size formula going
negative/zero for `max_size` 1-3), and `escaped_result` in `poll_host()`
is sized to `RESULTS_BUFFER * 2 + 1` instead of the fixed `DBL_BUFSIZE`.
(A very large escaped result can still hit the separate, already-tracked
row-size limit in #598/#618 — this fix only addresses the escaping-stage
truncation.)
## Also included
- **Seed `spine.conf` from `spine.conf.dist` on first install** — `make
install` only ever installed `spine.conf.dist`; nothing produced a live
`spine.conf`. Added an `install-data-hook` that copies it over only when
`spine.conf` doesn't already exist, plus a matching `uninstall-hook`
that only removes it again when it's still byte-identical to the `.dist`
(so a real uninstall never discards a customized config, while `make
distcheck`'s install/uninstall symmetry check still passes).
## Dropped from this PR
- A custom `codeql.yml` workflow (originally added for #580) was removed
— the repo already has GitHub's default CodeQL setup enabled and running
(`gh api repos/Cacti/spine/code-scanning/default-setup` → `state:
configured`), and a custom "advanced configuration" workflow cannot
coexist with it; GitHub rejected the SARIF upload and failed CI. #580's
underlying gap was already resolved out of band, so this PR no longer
claims to close it.
## Testing
Full build via WSL (`./bootstrap && ./configure --enable-warnings &&
make`) succeeds with no new warnings in `poller.c`, `snmp.c`, `php.c`,
`error.c`, or `sql.c` beyond two pre-existing, unrelated
`-Wformat-truncation` warnings in `php_init()`. Confirmed the
`usmDESPrivProtocol` configure probe correctly detects the missing
symbol in this build environment and takes the AES fallback path without
a link error. `make distcheck` passes end to end.
Closes#594Closes#600Closes#605Closes#607Closes#575Closes#583
Fixes#438
Four targeted content fixes:
1. **spine.c**: replace `[WHERE?]` placeholder in doxygen comment and
expand `--help` output to list the actual spine.conf search order:
current directory, /etc/, /etc/cacti/, ../etc/.
2. **configure.ac**: raise AC_PREREQ from 2.63 to 2.69; remove obsolete
macros no longer needed in C99 builds (AC_C_CONST, AC_HEADER_TIME,
AC_STRUCT_TM, RETSIGTYPE block).
3. **spine.conf.dist**: document SNMP_Clientaddr, DB_SSL_Verify, and
RDB_SSL_Verify in the header comment block and add them as commented
example lines in the settings section.
4. **.github/instructions/instructions.md**: replace generic blueprint
template with spine-specific Copilot instructions (C99/POSIX, pthreads,
net-snmp, libmariadb, autotools, CI, commit conventions).
No behaviour changes. man page content improves automatically via
help2man.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Co-authored-by: netniV <netniv@hotmail.com>
This pull request introduces a new blueprint generator for creating
comprehensive `copilot-instructions.md` files, aimed at guiding GitHub
Copilot to generate code that strictly follows project-specific
standards, architecture, and technology versions. The blueprint is
technology-agnostic and ensures that generated instructions are based
solely on actual patterns found in the codebase, avoiding any
assumptions.
Key additions and improvements:
**Blueprint Generator and Configuration:**
- Added `.github/instructions/instructions.md`, which provides a
detailed, configurable template for generating `copilot-instructions.md`
files. The template supports variables for project type, architecture
style, code quality focus, documentation level, testing requirements,
and versioning approach.
**Instruction Structure and Guidance:**
- Outlined a core instruction structure that enforces strict adherence
to detected technology versions, project architecture, and codebase
patterns, with explicit prioritization of context files and code quality
standards.
- Included technology-specific sections for .NET, Java,
JavaScript/TypeScript, React, Angular, and Python, each with guidelines
to match exact versions and code patterns found in the codebase.
**Codebase Analysis and Implementation:**
- Provided detailed steps for analyzing the codebase to extract
technology versions, architectural style, code patterns, and quality
standards, ensuring the generated instructions are fully aligned with
the existing code. (F7dd6