Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Releases: runcycles/cycles-server-admin

v0.1.25.41 — drop tomcat override (SB 3.5.14 BOM-managed) + Jedis fleet alignment

26 Apr 13:31
@amavashev amavashev
7fec471
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

Dependency hygiene release. No application-level code or wire-format changes — pom-only patch.

Changed

  • Spring Boot 3.5.13 → 3.5.14. Patch upgrade picking up upstream security hardening (constant-time DevTools secret comparison, RandomValuePropertySource SecureRandom, consistent SSL hostname verification, ApplicationPidFileWriter/ApplicationTemp symlink fixes).
  • Drop <tomcat.version>10.1.54</tomcat.version> override. SB 3.5.14's BOM now manages Tomcat 10.1.54 directly (verified against spring-boot-dependencies-3.5.14.pom). The explicit pin from v0.1.25.33 (closing CVE-2026-34483 / CVE-2026-34487) is now redundant.
  • Jedis 5.2.0 → 6.2.0 (major). Aligns with cycles-server-events (6.2.0) and cycles-server (6.2.0) on a single Redis-client major across the fleet. Jedis 6.1.0 explicitly restored binary compatibility for SetParams (#4225 upstream); all 782 tests pass on 6.2.0.
  • commons-lang3 3.18.0 override retained — SB 3.5.14's BOM still manages 3.17.0 (CVE-2025-48924 unfixed there). Comment updated to reference SB 3.5.14.

See CHANGELOG.md for the full entry.

Fleet alignment

Matching releases: cycles-server-events v0.1.25.12, cycles-server v0.1.25.18.

Assets 2
Loading

v0.1.25.40 — webhook lifecycle emit post-review polish

23 Apr 16:31
@amavashev amavashev
2fcd496
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.40 — webhook lifecycle emit post-review polish

Post-review correctness pass on v0.1.25.39 webhook lifecycle Events. No new spec surface, no wire-format changes — strictly better output for listEvents consumers.

Fixed

  • B1 — Actor parity on single-op lifecycle emits. createWebhookSubscription, updateWebhookSubscription, and deleteWebhookSubscription now populate Actor.keyId from authenticated_key_id, matching the bulk-action path. Audit consumers see consistent API-key attribution across all webhook lifecycle Events regardless of code path.
  • B2/B3 — changed_fields is now a real diff. updateWebhookSubscription previously listed any field present in the PATCH body even when the value matched the subscription's current value. Each request-provided field is now compared against the prior snapshot; only genuine mutations land in changed_fields. A full-identity PATCH (every field resent with existing value, no status flip) is a true no-op and emits nothing — aligns with spec v0.1.25.33 §6281. signing_secret keeps presence-based detection (stored value is encrypted; not safely comparable to plaintext request value).
  • B4 — Correlation-id uniqueness. The "no-req" literal fallback in webhook_update:<sub_id>:<request_id> and webhook_bulk_action:<action>:<request_id> is replaced with req_<uuid> fallback. Guarantees uniqueness across concurrent requests if RequestIdFilter ever fails to populate the attribute.

Compatibility

Internal-only fixes. No EventType / schema / endpoint / wire-format changes. Pairs with cycles-server-events v0.1.25.11 dispatcher-side webhook.disabled emit (unchanged).

Loading

v0.1.25.39 — admin webhook lifecycle Events

23 Apr 14:20
@amavashev amavashev
2dc2366
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.39 — admin webhook lifecycle Events

Operator-driven emits for webhook.{created,updated,paused,resumed,deleted} wired into single-op + bulk webhook endpoints per cycles-protocol v0.1.25.33 contract, with EventCategory.webhook (spec v0.1.25.34).

Emits

Operation EventType correlation_id
POST /v1/admin/webhooks webhook.created webhook_create:<subscription_id>
PATCH /v1/admin/webhooks/{id} (fields) webhook.updated webhook_update:<subscription_id>:<request_id>
PATCH /v1/admin/webhooks/{id} (status flip) webhook.paused / webhook.resumed same
DELETE /v1/admin/webhooks/{id} webhook.deleted webhook_delete:<subscription_id>
POST /v1/admin/webhooks/bulk-action webhook.paused / webhook.resumed / webhook.deleted webhook_bulk_action:<action>:<request_id>
  • Only fires on actual state transition; skipped/failed rows produce no Event.
  • Payload conforms to EventDataWebhookLifecycle.
  • Best-effort emit; failures logged, not propagated.

Not here

  • webhook.disabled — dispatcher-side (already live in cycles-server-events v0.1.25.11).

Compatibility

Additive. No wire breaks. Pairs with dispatcher emit already running; together closes the v0.1.25.33 webhook audit-trail gap.

Loading

v0.1.25.38 — bulk-action event parity

22 Apr 12:04
@amavashev amavashev
2adfa75
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.38 — bulk-action event parity (spec v0.1.25.32)

Added

  • Per-row Event emission on POST /v1/admin/budgets/bulk-action — one
    budget.funded / budget.debited / budget.reset / budget.reset_spent /
    budget.debt_repaid per successfully-mutated row, stamped
    correlation_id = budget_bulk_action:<action>:<request_id>.
  • Per-row Event emission on POST /v1/admin/tenants/bulk-action — one
    tenant.suspended / tenant.reactivated / tenant.closed per
    successfully-mutated row, stamped
    correlation_id = tenant_bulk_action:<action>:<request_id>. Cascade
    fan-out retains its own tenant_close_cascade:<tenant_id>:<request_id>
    (complementary, unchanged).

Unchanged

  • Aggregate AuditLogEntry per bulk-action invocation (spec v0.1.25.26 rule).
  • EventType enum — reuses existing per-op kinds.
  • TenantCloseCascadeService semantics.

Notes

  • Skipped and failed rows emit no Event. Event-emission failures are logged
    but never abort the bulk op.
  • Aligns with cycles-protocol spec v0.1.25.32.

See CHANGELOG.md and AUDIT.md for details.

Loading

v0.1.25.37 — Rule 1(c) bounded-convergence wired into close paths

21 Apr 10:37
@amavashev amavashev
17ec7c9
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.37 — Rule 1(c) bounded-convergence wired into close paths

Closes a spec-conformance gap: the server's OPERATIONS.md §"Tenant-close cascade" documented operator-issued re-close as the recovery path for an interrupted cascade, but the controller code silently short-circuited on already-CLOSED tenants before ever re-invoking the cascade service. Spec v0.1.25.31 Rule 1(c) requires Mode B implementations to both document and implement a bounded convergence mechanism; this release makes the code match the doc.

Fixed

  • PATCH /v1/admin/tenants/{id} with status=CLOSED — cascade now runs on every request regardless of prior status. On a retry against an already-CLOSED tenant, the parent event falls through to tenant.updated (no duplicate tenant.closed); straggler children still emit their own *_via_tenant_cascade events via the cascade service.
  • POST /v1/admin/tenants/bulk-action with action=CLOSE — skips the redundant repo.update on already-CLOSED rows but still runs the cascade. Bucketed succeeded if any child transitioned, skipped (reason=ALREADY_IN_TARGET_STATE) if cascade was a full no-op — keeping the bulk-action response honest about whether state changed.

Operator-visible effect

An operator seeing a budget in FROZEN under a CLOSED tenant can now re-issue PATCH /v1/admin/tenants/{id} { "status": "CLOSED" } (or bulk-action CLOSE) and the straggler will transition, with the cascade emitting its own audit + *_via_tenant_cascade events for the picked-up child under a fresh correlation_id (new request_id). The OPERATIONS.md triage recipe now works as documented.

Unchanged

  • No wire / OpenAPI / DTO contract change.
  • ErrorCode, EventType, and the cascade service's public contract unchanged.
  • Spec-coverage report: declared=46 covered=46 missing=0.

Verification

  • mvn verify: 749 tests, 0 failures, 0 errors, BUILD SUCCESS (jacoco 95% line-coverage gate enforced at verify phase).
  • OpenApiContractDiffTest + SpecCoverageReportTest both green.
  • CI: all 8 checks passed (Unit & Contract, Integration with contract validation, CodeQL java-kotlin + actions, Trivy, PR Container Scan).

Spec & docs

  • Target spec: cycles-governance-admin-v0.1.25.yaml info.version 0.1.25.31 (CASCADE SEMANTICS — Mode B flip-first-with-guarded-cascade, Rule 1(c) bounded-convergence MUST).
  • See AUDIT.md v0.1.25.37 entry for before/after, spec citation, and test coverage.
  • See CHANGELOG.md for the downstream-facing summary.
Loading

v0.1.25.36 — Rule 2 mutation guard coverage completed

20 Apr 18:31
@amavashev amavashev
fddb9f5
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

Rolls up four CHANGELOG entries (0.1.25.33 → 0.1.25.36). Headline: spec v0.1.25.29 Rule 1 + Rule 2 are fully implemented, plus two security patches for CVE coverage. No wire break; additive to the existing error_code, EventType, and audit-payload surfaces.

0.1.25.36 — Rule 2 mutation guard coverage completed

Closes the conformance gap flagged in the v0.1.25.35 AUDIT entry. Every mutating admin-plane operation now returns 409 TENANT_CLOSED when the owning tenant is CLOSED, per spec v0.1.25.29 Rule 2 (MUST).

New TerminalOwnerMutationGuard callsites:

  • POST /v1/admin/policies, PATCH /v1/admin/policies/{id}
  • POST /v1/admin/api-keys, PATCH /v1/admin/api-keys/{id}, DELETE /v1/admin/api-keys/{id}
  • POST /v1/admin/webhooks, PATCH /v1/admin/webhooks/{id}, DELETE /v1/admin/webhooks/{id}, POST /v1/admin/webhooks/{id}/test, POST /v1/admin/webhooks/{id}/replay
  • DELETE /v1/webhooks/{id}, POST /v1/webhooks/{id}/test
  • Per-row in POST /v1/admin/budgets/bulk-action and POST /v1/admin/webhooks/bulk-action — closed-owner rows land in failed[] with error_code: "TENANT_CLOSED"; sibling rows still proceed.

Paired with cycles-protocol spec revisions v0.1.25.30 (PRs #70 + #71), which enumerate 409 TENANT_CLOSED on all 10 ops in the spec's response catalog.

0.1.25.35 — Tenant-close cascade (Rule 1) + initial Rule 2 guard

Rule 1 cascade — when a tenant transitions to CLOSED, owned objects transition atomically in the same request:

  • BudgetLedgerCLOSED (stamps closed_at; releases any outstanding reserved)
  • WebhookSubscriptionDISABLED
  • ApiKeyREVOKED (reason tenant_closed)
  • Budgets with reserved > 0 emit an aggregate reservation.released_via_tenant_cascade event with the total released amount

Every audit + event in the cascade shares the originating request_id + trace_id plus correlation_id = tenant_close_cascade:<tenant_id>:<request_id>. Triggered by both PATCH /admin/tenants/{id} with status=CLOSED and the tenants:bulk-action CLOSE path; idempotent on already-closed tenants.

Initial Rule 2 guard (pre-.36) — budget + webhook-admin-create/update mutations.

Four new event kinds on EventType: BUDGET_CLOSED_VIA_TENANT_CASCADE, RESERVATION_RELEASED_VIA_TENANT_CASCADE, WEBHOOK_DISABLED_VIA_TENANT_CASCADE, API_KEY_REVOKED_VIA_TENANT_CASCADE. New WEBHOOK event category.

Tenant close payload gains cascade_summary (budgets_closed, webhooks_disabled, api_keys_revoked, reservations_released) so downstream consumers read the outcome without a follow-up query.

0.1.25.34 — Security: commons-lang3 3.18.0 pin

CVE-2025-48924 follow-up — Trivy HIGH finding not covered by Spring Boot 3.5.13's managed BOM. Added <commons-lang3.version>3.18.0</commons-lang3.version> override alongside the Tomcat override. Removable when SB ships 3.18.0+ managed. No API surface change.

0.1.25.33 — Security: Spring Boot 3.5.13 + Tomcat 10.1.54 pin

Closes 4 HIGH/CRITICAL CVEs against tomcat-embed-core 10.1.52 (CVE-2026-29145 CRITICAL, CVE-2026-29129 HIGH, CVE-2026-34483 HIGH, CVE-2026-34487 HIGH). SB 3.5.13 → Tomcat 10.1.53 transitively; <tomcat.version>10.1.54</tomcat.version> override picks up the remaining two. Patch-level bump within 3.5.x — no API surface change.


Conformance target

  • Protocol: cycles-protocol v0.1.25
  • Admin spec: cycles-governance-admin v0.1.25.30 (full 10-op 409 TENANT_CLOSED coverage)

Tests / CI

  • 747 tests green; spec coverage declared=46 covered=46 missing=0
  • OpenApiContractDiffTest + DtoConstraintContractTest green against spec v0.1.25.30

Image

  • ghcr.io/runcycles/cycles-server-admin:0.1.25.36
  • ghcr.io/runcycles/cycles-server-admin:latest
Loading

v0.1.25.32 — lenient deserialization on cross-plane read schemas

18 Apr 23:39
@amavashev amavashev
e9405d0
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

Cross-plane read tolerance hardening — closes the second of two items from the post-v0.1.25.31 alignment audit against runtime v0.1.25.14 (paired with runcycles/cycles-server#108 which closed the first). No spec change, no wire change — read-side tolerance adjustment in admin only.


Changed

  • Lenient deserialization on cross-plane read schemas. Event and WebhookDelivery now declare @JsonIgnoreProperties(ignoreUnknown = true) at the class level. Runtime (cycles-server) is the authoritative writer of event:* and delivery:* Redis records; admin only reads them. Previously the admin POJOs were ignoreUnknown = false — so any additive field runtime shipped in a patch release would break admin's listEvents / listWebhookDeliveries with UnrecognizedPropertyException until admin lockstep-updated the POJO. This violated the "additive fields are safe" invariant the admin/runtime split is built on. Runtime can now ship additive fields in any patch without forcing an admin release.
  • Hygiene: removed a dead @JsonIgnoreProperties(ignoreUnknown = false) from ErrorResponse. That annotation was never reachable at runtime (admin writes ErrorResponse to the wire; no reader path exists inside admin), so it was inert.

Unchanged (scope discipline)

  • Strict mode preserved on admin-owned schemas: WebhookSubscription, Tenant, Budget, Policy, ApiKey, every EventData* subtype, every Bulk*Request / Bulk*Filter, every *CreateRequest / *UpdateRequest. Admin writes these — a typo there is an admin-internal bug and must fail loudly. The lenient tolerance is scoped to schemas runtime writes.

Internal

  • No wire contract change. No spec edits (cycles-governance-admin-v0.1.25.yaml still at info.version=0.1.25.28).
  • Two test cases pin the invariant: EventModelTest#event_tolerantOfUnknownFieldAddedByRuntime and WebhookModelTest#webhookDelivery_tolerantOfUnknownFieldAddedByRuntime. A future regression — someone re-adding ignoreUnknown = false — would fail these tests immediately.

Compatibility

  • No client-visible behavior change. Admin-written request/response payloads still validate strictly.
  • No DB migration.
  • No upgrade ordering with runtime — that's the whole point of the change.
Loading

v0.1.25.31 — W3C Trace Context cross-surface correlation

18 Apr 21:16
@amavashev amavashev
ceae762
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.31 — W3C Trace Context cross-surface correlation

Server implementation of cycles-protocol admin spec v0.1.25.28 (PRs #56 + #58). Adds a third correlation tier on top of the existing request_id / correlation_id that spans an HTTP request, every event it emits, the audit entry it produces, and any outbound webhook delivery. Operators now have a first-class JOIN key for bulk-action fan-outs, multi-request operator sessions, and upstream distributed traces.

Contract: cycles-governance-admin-v0.1.25.yaml info.version 0.1.25.28 — declares trace_id on Event / AuditLogEntry / ErrorResponse / WebhookDelivery, the X-Cycles-Trace-Id response header, and trace_id / request_id query params on listAuditLogs / listEvents. Fully additive.

Added

  • trace_id (optional, ^[0-9a-f]{32}$) on response bodies:

    • ErrorResponse.trace_id — populated on every error response.
    • AuditLogEntry.trace_id — populated on every audit entry written for an HTTP-originated operation.
    • Event.trace_id — populated on every event emitted inside a servlet request (auto-propagated from RequestContextHolder so none of the 13 existing emit(...) call sites changed signature).
    • WebhookDelivery.trace_id + trace_flags + traceparent_inbound_valid — captured at dispatch time for the cycles-server-events sidecar to construct a conformant outbound traceparent with inbound-flags preservation.
  • X-Cycles-Trace-Id response header — emitted on every response (2xx / 4xx / 5xx). Clients ignore unknown response headers per HTTP contract, so non-breaking.

  • Inbound precedence — the server extracts trace_id from the first rule that matches:

    1. traceparent header (W3C Trace Context §3.2, version 00, non-all-zero trace-id + span-id).
    2. X-Cycles-Trace-Id header (32 lowercase hex, non-all-zero).
    3. Server-generated (16 random bytes → 32 lowercase hex; all-zero re-rolled per W3C §3.2.2.3).

    A malformed correlation header is treated as absent (falls through to the next rule); the server never rejects a request on a bad correlation header. Valid inbound trace-flags are preserved for outbound webhook delivery so an upstream sampled=0 opt-out is respected rather than silently re-enabled.

  • New list-endpoint filterslistAuditLogs and listEvents gain trace_id + request_id query params. Exact-match, post-hydration predicate, null-safe (null-field entries never match a supplied filter value so historical pre-upgrade rows aren't silently returned).

  • TraceContextFilter — new servlet filter @Order(2) running immediately after RequestIdFilter @Order(1). Extracts trace_id, stamps request attributes (traceId / traceFlags / traceparentInboundValid), and writes the X-Cycles-Trace-Id response header.

Non-breaking by design

  • All new wire fields are optional; historical rows persisted before this upgrade continue to round-trip through strict Jackson (JsonIgnoreProperties(ignoreUnknown = false) is satisfied because the fields ARE declared, just @JsonInclude(NON_NULL)).
  • Inbound headers are additive; old clients don't send them.
  • Outbound X-Cycles-Trace-Id is additive; clients accepting unknown response headers (all of them, per HTTP contract) are unaffected.
  • Query-param additions follow the spec's additive-parameter guarantee — older servers that don't implement them MUST ignore; this server implements them.

What this enables

  • JOIN an audit entry with the events it caused (same trace_id).
  • JOIN N related API calls from one user intent (same client-supplied traceparent).
  • Propagate Cycles operations into the subscriber's distributed trace (standard OTel traceparent on outbound webhook).
  • Bulk-action fan-out triage — one request_id + one trace_id → N events + 1 audit entry, all joinable.
  • Dashboard filter "show all events/audits for trace X" becomes one query across both list endpoints.

Spec gap closure (v0.1.25.27 → v0.1.25.28)

The cross-surface correlation feature originally shipped against admin spec v0.1.25.27 (cycles-protocol#56). PR #116 review surfaced a gap: the WebhookDelivery schema declared additionalProperties: false but did not include the three trace-metadata fields this server persists on every delivery row. Rather than ship a workaround, the spec was patched via cycles-protocol#58 to declare trace_id / trace_flags / traceparent_inbound_valid on WebhookDelivery. This server conforms cleanly against v0.1.25.28.

Coverage

  • 719 / 719 api-module unit tests green (14 dedicated TraceContextFilterTest cases covering precedence, all-zero re-roll, uppercase rejection, flag preservation, uniqueness).
  • 480 / 480 data-module unit tests green.
  • Integration + contract tests green.
  • JaCoCo ≥95% per module.
  • SpecCoverageReportTest clean against cycles-governance-admin-v0.1.25.yaml (46/46 operations).

Upgrade

  • Docker image: ghcr.io/runcycles/cycles-server-admin:0.1.25.31
  • No config changes required.
  • Client regen recommended if you consume the admin OpenAPI — the new trace_id field appears on Event, AuditLogEntry, ErrorResponse, and WebhookDelivery, and new query params appear on listAuditLogs / listEvents. Old generated clients continue to work (additive), but won't surface trace_id to your application code until regenerated.

Operator runbook

See OPERATIONS.md § Cross-surface correlation (trace_id) for the full trace-id runbook, including worked curl examples for capturing X-Cycles-Trace-Id and JOIN-ing via listAuditLogs / listEvents.

Downstream follow-ups

  • cycles-server-events sidecar: construct outbound traceparent from the new WebhookDelivery.trace_id + trace_flags + traceparent_inbound_valid triple on HTTP delivery (preserves inbound flags when valid; defaults to 01 otherwise).
  • cycles-dashboard: surface trace_id as a first-class filter on audit + events pages; add a "JOIN on trace" link from any row.
Loading

v0.1.25.30 — bulk-action audit metadata enrichment

18 Apr 13:59
@amavashev amavashev
9951830
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.30 — bulk-action audit metadata enrichment for triage

Triage enrichment for all three bulk-action endpoints (bulkActionTenants, bulkActionWebhooks, bulkActionBudgets). Before v0.1.25.30 the single AuditLogEntry emitted per bulk-op carried only bucket counts + idempotency_key in its metadata — post-incident triage required the operator's own copy of the response envelope or re-running the op (not acceptable for destructive actions like DELETE or DEBIT). Now the audit log entry alone is sufficient.

Contract: cycles-governance-admin-v0.1.25.yaml info.version 0.1.25.26no spec bump required. AuditLogEntry.metadata is already typed object with additionalProperties: true, so key additions are spec-compatible.

Added metadata keys

Emitted on GET /v1/admin/audit/logs entries where operation ∈ { bulkActionTenants, bulkActionWebhooks, bulkActionBudgets }:

Key Type Purpose
succeeded_ids string[] Per-row ids of successful operations — paper trail for compliance.
failed_rows BulkActionRowOutcome[] Full id + error_code + message per failure — replaces "re-run to see what broke".
skipped_rows BulkActionRowOutcome[] Full id + reason per skip — distinguishes ALREADY_IN_TARGET_STATE from ALREADY_DELETED.
filter object Normalized filter echoed as-is — reconstructs operator intent from audit alone.
duration_ms int64 Handler-entry → audit-emit wall-clock for SLO triage without needing trace sampling.

Changed

  • Consolidated the three previously-inline auditMeta.put(...) blocks into a single BulkActionAuditMetadataBuilder.build(...) helper so future bulk-action endpoints cannot drift on key set or ordering. LinkedHashMap pins the documented field order.
  • Each controller (TenantController, WebhookAdminController, BudgetController) now captures System.nanoTime() as the first statement of its bulk-action handler so duration_ms measures match + apply end-to-end.

Unchanged

  • Response shape and HTTP semantics of all three bulk-action endpoints. The synchronous envelope returned to callers is byte-identical to v0.1.25.29.
  • Existing metadata keys (action, total_matched, succeeded, failed, skipped, idempotency_key). No rename, no removal.
  • Auth model, idempotency semantics, safety gates (500-row cap, expected_count, 15-min replay).

Migration notes

  • Worst-case audit row size ~40 KB (500-row bulk-action cap ×ばつ ~80 B per outcome + filter echo + fixed keys). Within Redis value-size comfort range; no new limits required. Audit-tooling that caps on entry-level JSON size should review.
  • Dashboards parsing bulk-action audit entries gain five fields they may or may not display — fully backward compatible for consumers that ignore unknown keys.

Coverage

  • 705/705 unit + contract tests green, JaCoCo ≥95% per module.
  • OpenApiContractDiffTest + SpecCoverageReportTest clean against spec v0.1.25.26 on cycles-protocol/main (46/46 operations).

Triage recipe (new)

See OPERATIONS.md § Bulk-action audit triage for the full runbook:

  1. Find the entry: listAuditLogs?operation=bulkAction*&tenant_id=...
  2. Compare total_matched vs succeeded + failed + skipped.
  3. Classify each failed_rows[i] by error_code.
  4. Narrow the filter to the failing ids, re-run with a new idempotency_key.

Upgrade

  • Docker image: ghcr.io/runcycles/cycles-server-admin:0.1.25.30
  • No config changes required.
  • No client regen required (spec version unchanged).
Loading

v0.1.25.29 — Budget bulk-action endpoint

18 Apr 11:06
@amavashev amavashev
fce3712
This commit was created on GitHub.com and signed with GitHub’s verified signature.
GPG key ID: B5690EEEBB952194
Verified
Learn about vigilant mode.

Choose a tag to compare

v0.1.25.29 — Budget bulk-action endpoint

Closes #99. Operators rolling over a billing period no longer need to iterate listBudgets + per-row fundBudget — one filtered bulk request applies any FundingOperation across up to 500 ledgers with an atomic count-gate. Fifth bulk-action endpoint; same envelope as tenants / webhooks / api-keys / policies.

Contract: cycles-governance-admin-v0.1.25.yaml info.version 0.1.25.26.

Added

  • POST /v1/admin/budgets/bulk-action — AdminKeyAuth only. Apply CREDIT / DEBIT / RESET / REPAY_DEBT / RESET_SPENT (reuses existing FundingOperation enum) to every budget matching a BudgetBulkFilter. Returns 200 with succeeded[] / failed[] / skipped[] envelope carrying per-row ledger_id + error_code.
  • BudgetBulkFilter — mirrors listBudgets query params (scope_prefix, unit, status, over_limit, has_debt, utilization_min/max, search). tenant_id is required for cross-tenant safety. Matcher is shared with listBudgets via BudgetListFilters.fromBulkFilter(...) so operator preview and bulk apply can never diverge.

Safety gates

  • 500-row hard cap → 400 LIMIT_EXCEEDED (fail-fast before any writes).
  • expected_count gate → 409 COUNT_MISMATCH when server-observed match count differs from the caller's preview count (no writes performed).
  • 15-min idempotency replay via IdempotencyStore — same idempotency_key returns the cached envelope verbatim, partial failures and all.
  • Per-row derived idempotency (bulkKey:scope:unit fed to the existing Lua fund idempotency) — retry-the-failed-set after the envelope TTL cannot double-apply CREDIT/DEBIT/etc. to previously-succeeded rows.
  • Row-level known codes: BUDGET_EXCEEDED, INVALID_TRANSITION, NOT_FOUND, PERMISSION_DENIED, INTERNAL_ERROR. Skipped rows carry reason=ALREADY_IN_TARGET_STATE (REPAY_DEBT on zero debt).
  • AdminKeyAuth enforcedAuthInterceptor explicitly routes /v1/admin/budgets/bulk-action to admin-key auth; tenant keys → 401.

Audit

  • One AuditLogEntry per bulk-op (not per row) with operation=bulkActionBudgets, resourceId=bulk-action, and metadata counts (action / total_matched / succeeded / failed / skipped / idempotency_key). Per-row detail lives in the synchronous response envelope returned to the caller.

Also in this release (bundled 2026年04月18日)

  • v0.1.25.28.1 test fixAuditFailureSoakIntegrationTest AS4 tier-sum invariant now includes the __admin__ sentinel delta (PR #113). v0.1.25.28 split the pre-auth sentinel into __unauth__ / __admin__, but the soak-test invariant still summed only the old pair, causing the 2026年04月18日 nightly to go red on a legitimate 400-wave. Production audit-write path was always correct — test-only gap.

Coverage

  • 698/698 unit + contract tests green, JaCoCo ≥95% per module.
  • OpenApiContractDiffTest + SpecCoverageReportTest clean against spec v0.1.25.26 on cycles-protocol/main (46/46 operations).

Upgrade notes

  • No breaking changes. New endpoint is additive; existing fundBudget remains the canonical per-row path.
  • Clients that want to take advantage of bulk-action should regenerate against admin spec v0.1.25.26.
Loading
Previous 1 3 4
Previous

AltStyle によって変換されたページ (->オリジナル) /