Ignore history rows without initialized daily or monthly state so deleted and quarantined services cannot panic dashboard startup. Cover startup and statistics preservation with regression tests.
Thanks to Zachariah Mithani (@zachariah-mithani, AploSec) for privately reporting the retained service history startup panic.
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
* fix: prevent unbounded transfer history growth
* fix: preserve transfer history on alert load errors
* test: close transfer cleanup database
---------
Co-authored-by: naiba <hi@nai.ba>
* test: TDD regression tests for GHSA-jx78-55p5-rwv5 stream quota enforcement
* Apply remaining changes
* fix: update action SHA allowlist and test assertions to match dependabot bump
* fix: close GHSA-jx78-55p5-rwv5 incomplete fix of GHSA-qjpp-gffx-2wm9
Finding 1 (Moderate): nil-guard reporterServer in delayCheck and notifyCheck.
ServerShared has its own lock independent of serviceResponseDataStoreLock, so
m := ServerShared.GetList() taken inside the worker can return a nil entry for
the reporter if the server was concurrently deleted. Previously this caused an
unrecovered SIGSEGV in the worker goroutine (and in the gRPC layer with no
recovery interceptor), taking down the whole instance.
Finding 2 (Low): nil-guard ss.services[id] in ServiceSentinel.Delete().
A caller-supplied id that is absent from the registry caused
ss.services[id].CronJobID to panic, aborting the Delete loop and leaving every
subsequent valid id as a zombie service (DB row deleted, in-memory entry kept,
cron probe still running).
Regression tests added for both findings following the existing
servicesentinel_lifecycle_test.go patterns.
* Apply remaining changes
* chore: replace commit hashes with version tags in test.yml
* fix(server): serialize authoritative lifecycle changes
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix(service): bind reports to reporter lifecycle
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix(rpc): reject results from stale task streams
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix(agentcompat): allow version-tagged actions
* fix(agentcompat): allow literal checkout refs
* refactor(agentcompat): remove SHA resolver policy
* test(agentcompat): remove resolver SHA fixtures
* test(agentcompat): remove mutable ref fixtures
* test(agentcompat): use tagged actions in secure fixtures
* test(agentcompat): update credential fixtures for tags
* test(agentcompat): update reusable action fixtures
* test(agentcompat): update artifact redaction fixtures
* test(agentcompat): finish artifact fixture tag migration
* test(agentcompat): update workflow validation fixtures
* test(agentcompat): update dependency workflow fixture
* ci(agentcompat): stop pinning cross-repository revisions
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: naiba <hi@nai.ba>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
GET /api/v1/ddns and /api/v1/notification returned full objects with
plaintext credentials (Cloudflare/TencentCloud secrets, webhook URLs
with embedded bot tokens, Authorization headers). Redact these fields
in the list responses.
Since the frontend edit form repopulates from the list endpoint, the
update handlers now treat an empty submitted credential as "no change"
and preserve the stored value, preventing accidental secret wipes.
Ref: GHSA-ww5p-j6cj-6mqq
The v2.2.2 Release workflow failed: fetch-frontends.sh fetched user-dist
from hamster1963/nezha-dash-v2 at v2.1.1, but upstream went v2.1.0 -> v2.1.2
and never tagged v2.1.1, so the dist.zip download 404'd and unzip aborted the
build. Point at the existing v2.1.2 asset.
Add TestCheckStatus_SampleMemoryBounded asserting that, across 100k ticks,
the per-(alert,server) sample slice length and capacity stay bounded by the
rule's retention window and never grow with elapsed time.
Trim alert samples using AlertRule.RetentionWindow() (max rule duration)
instead of Check()'s verdict max, which is 0 while a rule's window is still
filling. The old max<=0 trim wiped history every tick, so Duration>=2 general
rules never accumulated enough samples and never fired a notification.
Add model + end-to-end singleton regression tests covering sample
accumulation, the retention-window contract, and the actual notify path.