#### Description
- `POST /api/v1/resetPassword` was the last password endpoint with no v2
equivalent. Adds `POST /api/v2/factor_password/reset`, next to the
existing `/factor_password/forgot`, so the whole recovery flow lives
under one namespace.
- v1 keeps working and is now marked deprecated. Both routes share the
same handler, so behaviour is identical.
- A malformed request body now returns a structured 400 instead of a
500. This applies to v1 too, since the handler is shared.
#### Issues closed by this PR
Contributes to SigNoz/platform-pod#2667
#### Additional Information
- The generated frontend client is included because CI re-runs `pnpm
generate:api` and fails on drift. The UI still calls v1; moving it to
the new `useResetPassword` hook is a separate PR to keep review
ownership split.
- Not fixed here: a reset doesn't revoke existing sessions, though a
voluntary password change does. Worth its own ticket.
#### Description
- Removes `GET`, `PUT` and `DELETE /api/v1/user/{id}` — all deprecated
and superseded by `/api/v2/users/{id}`, which the frontend already uses.
- Drops the dead code this leaves behind: the `SelfAccess` middleware
and `Claims.IsSelfAccess` (no callers left), the deprecated update
setters, and three `DeprecatedUser` helpers.
- Points the integration tests that deleted users at `DELETE
/api/v2/users/{id}`.
#### Issues closed by this PR
Contributes to SigNoz/platform-pod#2667
#### Additional Information
- Behaviour change: the removed `GET`/`PUT` were `SelfAccess`, the v2
equivalents are `AdminAccess`. Self-serve reads and updates go through
`/api/v2/users/me`, which is what the UI already calls — but worth a
second pair of eyes.
- `DELETE /api/v1/user/{id}` was the most widely reached of the three.
Please confirm nothing external (zeus) still calls it before merging.
- OpenAPI spec and the generated frontend client are regenerated, not
hand-edited.
#### Description
- Removes `POST /api/v1/invite/bulk` — already deprecated, superseded by
`POST /api/v1/invite`, and no callers left.
- `Setter.CreateBulkInvite` stays; `CreateInvite` still delegates to it
for the single-invite case.
#### Issues closed by this PR
Contributes to SigNoz/platform-pod#2667
#### Additional Information
- OpenAPI spec and the generated frontend client are regenerated, not
hand-edited.
- The `integrationci / fmtlint` failure here is not from this PR — `make
py-lint` is broken on `main`. Fixed separately in #12475; this PR needs
that merged (or a rebase on it) to go green.
- First of three PRs splitting a v1 user-API cleanup. The other two also
regenerate the spec and generated client, so whichever merges second
needs the generators re-run.
## Pull Request
---
### 📄 Summary
Adds a `filterByPodStatus` secondary filter to the v2 infra-monitoring
list APIs (pods, nodes, namespaces, clusters, deployments, statefulsets,
jobs, daemonsets).
Pod status is a derived kubectl-style value (`k8s.pod.phase` + status
reasons, resolved via `argMax`), not a real label, so it can't go
through the normal query-builder filter. This PR resolves the full-scope
status keyset up-front and intersects it with the metadata + ranked
groups, keeping `total` and pagination correct.
- Multi-select: the field is an array, pushed down as `WHERE
lower(display_status) IN (...)` (OR within status, AND with the
attribute filter).
- When the optional status metrics were never ingested, the endpoint
returns a non-blocking warning + empty page instead of silently
filtering everything out.
#### Screenshots / Screen Recordings (if applicable)
N/A — backend + generated FE API types only; the UI is a separate
change.
#### Issues closed by this PR
Part of SigNoz/engineering-pod#5778.
---
### ✅ Change Type
- [x] ✨ Feature
- [ ] 🐛 Bug fix
- [x] ♻️ Refactor
- [ ] 🛠️ Infra / Tooling
- [ ] 🧪 Test-only
---
### 🐛 Bug Context
N/A — not a bug fix.
---
### 🧪 Testing Strategy
- Tests added/updated:
- Unit test for the status push-down (`applyPodStatusFilter`, built with
go-sqlbuilder).
- Integration tests across all 8 entity APIs: list mode, grouped mode,
validation, missing-metric warning, and multi-select union.
- Manual verification: smoke-tested against staging data (single, multi,
and grouped filters).
- Edge cases covered: missing status metric → warning + empty; grouped
mode keeps a group if ≥1 pod matches; multi-select returns the union of
the selected statuses.
---
### ⚠️ Risk & Impact Assessment
- Blast radius: v2 infra-monitoring list endpoints only.
- Potential regressions: none when the filter is unset (empty = off,
fully additive). When set, an extra status query runs; it is gated
behind the filter being present.
- Rollback plan: revert the PR — no schema or data migrations involved.
---
### 📝 Changelog
| Field | Value |
|------|-------|
| Deployment Type | OSS, Cloud, Enterprise |
| Change Type | Feature |
| Description | v2 infra-monitoring lists can now be filtered by pod
status (multi-select). |
---
### 📋 Checklist
- [x] Tests added or explicitly not required
- [x] Manually tested
- [x] Breaking changes documented
- [x] Backward compatibility considered
---
## 👀 Notes for Reviewers
- `filterByPodStatus` is optional and additive — no change to existing
responses when omitted.
- The status keyset is resolved once at full scope, then intersected —
this is what keeps `total`/pagination correct despite status being a
post-aggregation value.
- OpenAPI spec + FE API types are regenerated (scalar → array); no
hand-written FE.
## Summary
- Saved views now persist a versioned, typed spec (`schemaVersion` +
`spec{compositeQuery, selectedFields, display}`) instead of a bare
composite-query blob plus an opaque, frontend-owned `extraData` string
-- mirroring the pattern dashboards already use for their v2/perses
schema.
- `/api/v1/explorer/views` keeps working exactly as before: a thin
conversion layer translates to/from the legacy wire format, including
folding `extraData`'s ad hoc JSON into the typed spec and back for
backward compatibility.
- A one-time migration rewrites existing rows into the new shape and
drops the now-unused `extra_data`/`category`/`tags` columns.
### Scaffolding decisions
- Using v2 for new handlers instead of renaming old handlers to
something else for these reasons - keep the diff minimum for easier
reviews, avoiding any git history or last updated at change in old route
registration.
- Keeping the conversion to old saved view type in handler itself rather
than `savedviewtypes` package to keep it un-exported and not let them be
available anywhere else to be used. It also enables `savedviewtypes` to
be independent on query-service models.
- Modified the existing handler and it's interface to include the v2
methods instead of adding another handlerV2 since apiserver already had
handler wired in, so don't want to pass on 2 version simultaneously.
### Breaking change
- Any unknown key in the `ExtraData` will be rejected and dropped
silently in the old APIs and give error in new version.
- If there was any way to add tag or category in saved view earlier,
that data will be lost.
- Old APIs will not support the old QB request payload, only v5 format
is supported.
---
ClosesSigNoz/engineering-pod#4651
Alternative discarded https://github.com/SigNoz/signoz/pull/12208
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* feat: enable FGA for dashboards and their public config
* test: add integration test for dashboard FGA
* fix: fix permissions for public dashboards, pinning, views
* fix: allow viewers to manage views
* fix: remove edits to the public dashboard line
* chore: add api to retry migration for a dashboard
* feat(dashboard): add retry migration action for legacy dashboards
The legacy-dashboard dialog only offered the dashboard ID and a link to
support. Now that the v1->v2 migration can be re-run on demand, let an
editor trigger it from there and fall back to support only if it still
fails.
Retrying needs edit access (the endpoint is EDITOR-gated), so viewers
keep the ID-and-support dialog unchanged.
---------
Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
* fix(ruletypes): expose above_or_equal and below_or_equal in CompareOperator enum
The operators are accepted by Validate(), normalized, evaluated and
returned by the rules API, but were commented out of Enum(), so the
generated OpenAPI spec (and clients generated from it, e.g.
terraform-provider-signoz) rejected rules the server itself creates.
* fix(alerts): support above_or_equal and below_or_equal operators in CreateAlertV2
Adds the two inclusive operators to the v2 alert form: selectable in the
threshold operator dropdown, normalized from all backend aliases
(5/6, above_or_eq/below_or_eq, >=/<=), rendered with their symbols in
threshold rows and match-type tooltips, and prefilled losslessly from
dashboard panel thresholds instead of collapsing onto the strict
variants. The v1 form is left untouched.
* feat: adding gcp memorystore redis service
* refactor: updating dashboard title
* refactor: extending width of uptime gauge panel
* refactor: updating cpu utilization panel
* refactor: updating dashboard panel to use rate function instead of hack
* feat: adding compute engine service
* refactor: updating dashboard panels to use rate aggregation
* fix: correct typo and unit in compute engine dashboard
* refactor: migrating dashboard to v6
* feat(rulestatehistory): populate related logs/traces links in v2 history APIs
The v2 rule history timeline dropped the relatedLogsLink/relatedTracesLink
that v1 (getRuleStateHistory) returned per entry, which the alert history
page uses to jump from a state change to the explorer with the rule's
filter and the entry's labels. Load the rule from the rule store in the
module and build the links with contextlinks, scoped to the entry's
evaluation window like v1.
Extract the builder-query filter/group-by selection that the v1 handler
and threshold rule notifications each inlined into
contextlinks.BuilderQueryForSignal and reuse it from both the module and
ThresholdRule.
Also populate the links for top contributors, which both v1 (since #10760)
and v2 returned as always-empty fields even though the UI renders them;
contributor links span the queried range since the counts aggregate it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(contextlinks): remove unused v3 link helpers
PrepareLinksToTraces, PrepareLinksToLogs and PrepareFilters lost their
last callers when the deprecated v3/v4 rule support was removed in #10760;
the v5 equivalents (PrepareParamsFor*V5 and PrepareFilterExpression) are
what all remaining callers use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore: end doc comments with a period to satisfy godot
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(alerts): cover v2 rule history related links for logs and traces
Each test fires a rule with a filter and a service.name group-by, then
asserts the recorded firing entry and top contributor carry a related
explorer link for the rule's signal only, with the label-rewritten filter
expression, the evaluation window on timeline entries and the queried
range on contributors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(contextlinks): shrink explorer links to the minimal payload
The explorer pages read only the data source and filter expression from a
shared link and fill in the rest of the query shape with defaults, so stop
shipping the v3 builder-query ceremony (queryName, aggregateOperator,
aggregateAttribute, stepInterval, paging fields) and the timeRange and
options params nothing reads. Links shrink from ~1.2k to ~450 chars and
contextlinks no longer depends on the v3 model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(rulestatehistory): derive link windows from the evaluation envelope
Rules created through the current UI store the window in the v2alpha1
evaluation envelope with no top-level evalWindow, so the previous 5m
fallback produced wrong link windows for any non-default rolling window
and could not represent cumulative windows at all. Use the envelope's
NextWindowFor like the rule engine does, keeping the top-level
evalWindow (default 5m) as the fallback for rules without an envelope.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* chore(contextlinks): simplify double-encoding comment
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(alerts): use literal matchType/op in fixtures and drop link unit tests
Replace the numeric matchType/op codes in all alert scenario fixtures
with their literal forms (at_least_once, above, ...) which the API
normalizes to the same canonical values, and remove the rule history
link unit tests since the integration tests cover the behavior
end-to-end.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(alerts): move rule history helpers into the shared alerts fixtures
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* chore: fix schema based on migration errors
* test: add rejection based integration tests for new validations
* fix: remove datasource field from schema
* fix: remove requirement for links to be always present
* fix: make links use defined type
* test: add integration test for link omission roundtrip
* test: change not in to None for links in panel
---------
Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
* fix(dashboards-v2): make panel/dashboard links required and non-nullable
* fix: validate links on read from db as well
* fix: allow all as value for signal
* fix: dont allow empty string for signal
* fix(dashboards-v2): dedicated `all` dynamic-variable signal (frontend + client)
* test: add empty links to new payloads in integration tests
---------
Co-authored-by: Naman Verma <naman.verma@signoz.io>
* feat: adding gcp memorystore redis service
* refactor: updating dashboard title
* refactor: extending width of uptime gauge panel
* refactor: updating cpu utilization panel
* refactor: updating dashboard panel to use rate function instead of hack
* fix(querybuildertypesv5): omit unset stepInterval on the wire
Step is a struct (struct{ time.Duration }), so omitempty had no effect — an
unset stepInterval serialized as 0 instead of being omitted, so a typed
client reading a query back saw a 0 it never sent (create -> GET drift).
Tag stepInterval with ,omitzero so an unset value is dropped while a set
value still serializes (as seconds), on all three sites: builder query,
trace-operator, and secondary aggregation. Schema-invisible (no OpenAPI /
client change). source and the metric enums were already handled in #12164.
* fix(telemetrytypes): round-trip empty fieldContext/fieldDataType on field keys
A TelemetryFieldKey can deliberately leave fieldContext/fieldDataType empty
to match across any context / data type, but ,omitzero dropped that empty
value on serialize, so a typed client that sent "" read it back as absent
(create -> GET drift).
Make both fields always serialize and add the empty member to their Enum()s
so "" is a valid schema value that round-trips verbatim — the same approach
#12164 used for source. Signal keeps ,omitzero: its empty value is invalid
for the query/variable signal contexts that share the enum (adding "" there
breaks those consumers), and a field key's signal is not deliberately empty.
Regenerate the OpenAPI spec + client (fieldContext/fieldDataType enums gain
"") and update the ScalarData marshal test (column keys now echo the fields).
* fix(telemetrytypes): round-trip empty signal on field keys
Extend the field-key round-trip fix to Signal: add the empty member to
Signal.Enum() and make TelemetryFieldKey.Signal always serialize, so an
empty ("any") field-key signal round-trips as a valid value instead of
being dropped — matching the fieldContext/fieldDataType treatment.
The Signal enum is shared with query/variable signals, where "" is invalid.
Narrow the frontend's TelemetrySignal type to logs/traces/metrics (so the
variable/panel signal selectors stay exhaustive), label the empty member in
the panel type switcher's map, and fold an empty drilldown signal into "all".
Regenerate the OpenAPI spec + client (Signal enum gains ""), and update the
ScalarData marshal test and the querierlogs aggregation label assertions to
include the now-serialized empty signal.
* fix(dashboardtypes): round-trip zero-valued variable/display fields
omitempty dropped explicit zero values from the create -> GET response, so
a typed client (Terraform/SDK) that sent them read back null and reported
drift. Remove the tag so these always serialize:
- Display.Description ("" round-trips; applies to dashboard/panel/variable
displays)
- TextVariableSpec.Constant (constant: false, like the disabled fix)
- ListVariableSpec.CustomAllValue / CapturingRegexp ("" round-trips)
Scalars carry no nullability, so the OpenAPI spec and generated client are
unchanged. Sort stays omitzero: its "no sort" value is "none", not "", so
omitzero only omits the invalid unset state.
* fix(dashboardtypes): round-trip panel and dashboard links
`links` used omitempty (dropped an explicit []) and its element type was the
imported perses dashboard.Link, whose own fields tag name/tooltip/
renderVariables/targetBlank omitempty — so a link's false/"" were dropped
too, and a typed client read them back as null.
- Replicate dashboard.Link as a SigNoz Link type (same pattern as
ListVariableSpec/TextVariableSpec) with every field always serialized.
- Use ,omitzero on PanelSpec.Links and DashboardSpec.Links so an explicit
[] round-trips while an unset list stays omitted (never null).
Regenerate the OpenAPI spec and frontend client: the element schema is now
DashboardtypesLink (was the perses DashboardLink) and links is nullable.
Update the frontend consumers to the renamed type and coalesce the now
type-nullable spec.links (never null on the wire) at its two boundaries.
* test(dashboard): cover variable/display/link round-trip cases
Extend the v2 dashboard round-trip test with the spec-wide zero values this
PR fixes: a display description "", a text variable's constant false, a list
variable's customAllValue/capturingRegexp "", an explicit [] of panel links
that round-trips, a link whose own zero-valued fields (name/tooltip "",
renderVariables/targetBlank false) echo back, and a linkless panel whose
links stay omitted (never null).
* test(dashboard): accept null-or-absent for unset panel links
A panel with no links round-trips as "links": null rather than being
omitted (the panel serialization path differs from the query slices, which
omit). Both mean "no links" and neither drifts for a typed client, so assert
the value is None (null or absent) instead of strictly absent. The explicit
[] case still asserts a verbatim round-trip, which is the guarantee the fix
provides.
* fix(dashboardtypes): round-trip remaining zero-valued spec fields
Complete the dashboards-v2 create -> GET round-trip audit:
- DashboardSpec.Datasources: ,omitempty -> ,omitzero so an explicit {}
round-trips (omitempty dropped it) while an unset map stays omitted.
- DashboardV2 Image, DashboardSpec.Duration/RefreshInterval: drop ,omitempty
so an explicit "" round-trips (same class as Display.Description). The
server accepts "": DurationString.validate() returns nil for len 0, and
Image/Duration/RefreshInterval have no create-time validation, so a
GET-then-PUT of "" is not rejected.
Scalars carry no nullability (no spec change); the datasources map is now
nullable: true in the regenerated OpenAPI spec and client.
* test(dashboard): cover datasources/image/duration/refreshInterval round-trip
Extend the round-trip test with the spec-wide zero values just fixed: a
dashboard-level image "", spec duration/refreshInterval "", and an explicit
empty datasources {} that must echo back as {} (omitzero) rather than being
dropped.
* fix(querybuildertypesv5): omit unset metric enum fields on the wire
A metric builder query serialized empty strings for its enum fields
because omitempty has no effect on struct-backed valuer types:
"source":"", "aggregations":[{"temporality":"","timeAggregation":"","spaceAggregation":""}]
Those "" values are not members of the corresponding OpenAPI enums
(source=[meter], temporality=[delta,cumulative,unspecified], etc.), so a
typed client reading a rule back rejected it (create -> GET round-trip
drift; terraform-provider-signoz generate-config failed schema validation).
Tag Source/Temporality/TimeAggregation/SpaceAggregation with ,omitzero so
an unset value is dropped instead of emitted as an invalid "", matching the
existing convention (dashboardtypes Sort, telemetrytypes field keys). Valid
values still serialize. The OpenAPI spec regenerates byte-identical, which
confirms the enums were already correct.
* test(querybuildertypesv5): cover client-sent empty enum values
A client (e.g. terraform) may send explicit source:"" / temporality:"" for
an unset enum. Assert unmarshaling accepts them, normalizes to the zero
value, and re-marshaling drops them so the round-trip never echoes an
invalid "" back.
* fix(querybuildertypesv5): allow empty metric enum values in the spec
The server accepts and echoes back an unset source, temporality, and
timeAggregation for a metric query (a create -> GET returns "" for them), but
their OpenAPI enums omitted "". A typed client (terraform-provider-signoz
generate-config) therefore rejected the config generated for an imported rule.
Add "" as a valid member of the Source, Temporality, and TimeAggregation enums
so the spec matches what the server actually accepts and returns. spaceAggregation
is left unchanged: an empty value is rejected with 400 at creation (IsValid), so
it is never stored or echoed and "" must stay out of its enum.
Drop the earlier ,omitzero tags: these fields already always-serialize, so an
accepted "" round-trips faithfully instead of being silently dropped (silent
mutation is itself drift). source loses its no-op omitempty for the same reason.
Regenerate the OpenAPI spec and frontend client (both git-diff gated).
* test(querybuildertypesv5): assert accepted empty enums round-trip
Empty source/temporality/timeAggregation are echoed back (not dropped) and are
stable across marshal -> unmarshal -> marshal; spaceAggregation carries a valid
value since an empty one is 400'd at creation.
* test(querybuildertypesv5): merge and rename metric enum round-trip test
Fold the unmarshal-echo case into the table-driven marshal round-trip test
(its marshal -> unmarshal -> marshal check already covers the client-sends-""
path) and rename to TestQueryBuilderQuery_MetricAggregation_MarshalJSONEnumRoundTrip.
* style(metrictypes): drop explanatory comments on enum changes
Remove the comments added to Temporality/TimeAggregation Enum() and the metric
enum round-trip test case.
* style(telemetrytypes): drop explanatory comment on Source enum change
Remove the comment added to Source.Enum(), keeping the pre-existing doc/TODO.
* fix(dashboardtypes): accept threshold value of 0 on create
A NumberPanel/TimeSeries/Table threshold with `value: 0` (a legitimate
value the SigNoz UI emits by default) was rejected on create with
`dashboard_invalid_input` "Field validation for 'Value' failed on the
'required' tag".
go-playground/validator's `required` treats a numeric field equal to its
zero value as "missing", so `validate:"required"` on the float `Value`
wrongly rejected 0. Drop `validate:"required"` from `Value` on
ThresholdWithLabel and ComparisonThreshold; keep `required:"true"` since
the field is always present in the schema (0 is a valid present value, not
an absent one), so the OpenAPI/generated client are unaffected. `Color`
keeps both tags — an empty colour is genuinely invalid.
Drop the two "missing value" cases from TestValidateRequiredFields, which
asserted the removed invariant.
* fix(querybuildertypesv5): round-trip zero-valued query spec fields
A dashboard/alert query that sets a zero-valued field — `disabled: false`,
`legend: ""`, or an explicit empty `groupBy`/`order`/`selectFields`/etc. —
created fine but the GET response omitted it, so a typed client that echoes
what it sent (Terraform, SDKs, PUT-after-GET) read back `null`/absent and
reported drift. `,omitempty` dropped these zero values on the way out.
Fix the create -> GET asymmetry:
- Slice fields use `,omitzero` instead of `,omitempty`. `omitzero` omits a
nil slice (field never set stays absent) but keeps an explicit non-nil
`[]`, so an empty array round-trips as `[]` and there is no `null`
regression. Applied to groupBy, order, selectFields, aggregations,
functions, secondaryAggregations and function args across the builder,
formula, trace-operator and join specs, plus ListPanelSpec.selectFields.
- Scalars `disabled` (bool) and `legend` (string) drop the tag entirely;
`omitzero`/`omitempty` both suppress false/"", so the only way to
round-trip them is to always serialize.
Result types in resp.go keep `,omitempty` — they are server-computed and
never round-tripped. Regenerate docs/api/openapi.yml and the frontend
client: the omitzero slices are now `nullable: true` in the schema (never
null on the wire, but the generated types gain `| null`, which existing
consumers already handle via `?? []`).
* test(dashboard): round-trip serialization for zero-valued fields
Add a v2 dashboards integration test that creates one minimal dashboard
(stripped from SigNoz/dashboards cicd-perses.json) and asserts the
create -> GET round-trip preserves every zero-valued field the fix targets:
- threshold value 0 (ComparisonThreshold + ThresholdWithLabel) is accepted
on create and echoed back
- builder slices set to an explicit [] (groupBy/order/selectFields/functions)
round-trip as [], while a bare builder's unset slices stay absent (never
null) on read
- scalars disabled/legend always echo false/""
Table-driven: one equality table for round-tripped values and one absence
table for omitted slices.
* test(dashboard): fold round-trip test into 03_v2_dashboard
Move test_dashboard_v2_roundtrip_preserves_zero_values alongside the other
v2 dashboard tests (test_create_rejects_*, lifecycle, ...) instead of a
standalone file, with the dashboard payload inlined per this suite's style.
* feat(authz): enable FGA for telemetry resources on v5 query_range
Authorize /api/v5/query_range and /preview at the telemetry-resource level,
derived from the request body:
- coretypes: ResourceWithID + ResourceExtractor as the resource-level analogue
of the id extractors; NewResolvedResourceWithID/NewResolvedResourceWithError;
telemetryresource selector regex widened to query-type selectors with up to
two hashed segments (metric name, where clause) or wildcards
- telemetrytypes: QueryRangeResources maps each query to its telemetry
resource (signal/source aware: audit-logs, meter-metrics) with a hierarchical
selector id (query_type/<hash(metric)>/<hash(where)>); PrefixSelector expands
the id into the grant ladder [exact, prefix/*..., *]
- handler: generic TelemetryResourceDef fans out an injected ResourceExtractor;
fails closed when extraction errors or resolves nothing
- audit: log and skip resolved resources that carry a resolution error
- querier routes: ViewAccess -> CheckResources with telemetry read scopes;
substitute_vars stays ViewAccess (no telemetry access)
- sqlmigration 099: backfill telemetry read tuples for existing orgs
(admin: logs/traces/metrics/audit-logs/meter-metrics; editor/viewer:
logs/traces/metrics)
* feat(authz): widen telemetry selector segments to 128 bits
64-bit truncation permits chosen-collision attacks at ~2^32 work; 128 bits
pushes this to 2^64. No hashed selector is persisted yet, so the change is
free.
* chore(docs): regenerate openapi spec with telemetry read scopes
* feat(telemetry): add where clause visitor
* refactor(telemetry): restructure normalizer file and quote bare values
* feat(authz): gate v5 query_range on service.name telemetry selectors
* feat(authz): encode telemetry grants as query-type qualified atom selectors
* feat(authz): move telemetry grant key to plaintext selector segment
* feat(authz): use escaped plaintext telemetry selectors with mechanical ladder
* revert(authz): restore transaction group diff in role update
* test(authz): add querierauthz integration suite for telemetry query_range gating
* test(authz): seed logs so service.name resolves in allowed querierauthz cases
* feat(authz): backfill telemetry read tuples for existing orgs
* chore(authz): reword empty composite query error message
* feat(authz): add meter metrics and audit logs to clickhouse sql
* Revert "feat(authz): add meter metrics and audit logs to clickhouse sql"
This reverts commit c9d870e0ee.
* feat(authz): grant meter-metrics to editor/viewer, keep clickhouse admin-only
* feat(authz): remove the audit logs from clickhouse check altogether until it's introduced
* fix(ruletypes): always serialize notificationSettings.usePolicy
usePolicy is a plain bool tagged omitempty, so a false value is dropped
from the GET response. Clients that pin usePolicy to false read it back as
absent/null. Drop omitempty (matching Renotify.Enabled) so false always
serializes and round-trips.
* test(ruletypes): assert usePolicy round-trips in minimal read shape
usePolicy now always serializes, so the minimal read shape includes it with a false value rather than omitting it.
* fix(ruletypes): always serialize notificationSettings.groupBy
Like usePolicy, groupBy dropped its omitempty so an explicitly-set empty value round-trips instead of reading back as absent. A nil groupBy now serializes as null.
* fix(ruletypes): use omitzero for notificationSettings.groupBy
omitzero omits groupBy only when nil (unset) while preserving an explicitly-set empty array as [], so unset and empty stay distinguishable instead of every response carrying groupBy: null. Matches the sibling newGroupEvalDelay tag.
* fix(ruletypes): use omitzero for renotify.alertStates
Symmetric to groupBy: omitzero omits alertStates only when nil (unset renotify configs stay absent, no regression) while echoing an explicitly-set empty array as [].
* chore(ruletypes): regenerate openapi spec and api client
groupBy and renotify.alertStates switched to omitzero, so the generated spec marks both slices nullable and the orval client types them as [] | null.
* fix: set correct opapi response model for span mapper list
* fix: change group_id to groupId in response
* fix: format properly
* fix: update fixtures
* chore: added types and open api spec changes
* chore: added method to calculate reason
* chore: per group pod status counts with req metric checks method added
* chore: wired up pod status counts
* chore: pod restarts type added
* chore: added restart counts for the group
* chore: bug in query fix
* chore: onboarding API changes
* chore: integration tests added
* chore: added podcountsbyphase in other entities
* chore: added pod status counts for other entities
* chore: added integration tests for other entities
* chore: added checks api changes for other entities
* chore: rearrangement
* chore: removed succeeded status and mark it as completed
* chore: query beautified
* chore: corrected metrics list for metadata lookup
* chore: removed dead constants
* chore: goroutines for ListHosts
* chore: goroutines for ListPods
* chore: goroutines for ListNodes
* chore: goroutines for ListNamespaces
* chore: goroutines for ListClusters
* chore: goroutines for ListDeployments
* chore: goroutines for ListStatefulsets
* chore: added goroutines for ListStatefulsets, ListJobs and ListDaemonsets
* chore: added function
* chore: added struct changes
* chore: added count attr keys
* chore: wired counts to the response fields
* chore: regenerated API spec
* chore: merged main, resolved conflicts
* chore: nodes count surfacing
* chore: integration tests added
* fix: use tuple mapping to uniquely identify attrs:
* chore: integration tests update
* feat(authz): store role transaction groups as document of record
Persist a role's transaction groups as JSON on the role row so the role
details page is reconstructed deterministically from SQL instead of being
rebuilt from OpenFGA tuples (which will soon carry opaque hashed telemetry
selectors):
- authtypes: TransactionGroups gains Value/Scan (validated via
NewTransactionGroups) and MarshalJSON (nil renders as []); NewRole takes
transactionGroups; NewManagedRoles fills managed docs from the registry;
RoleWithTransactionGroups removed - Role carries the wire field and the
AuthZ interface, handler, and OpenAPI responses use *Role; GettableRole
(without transactionGroups) is the list response
- sqlmigration 099: add role.transaction_groups, backfill custom roles from
their permission tuples (dual dialect) and managed roles from the registry
- sqlmigration 059: pin insert columns so the live Role model addition does
not break fresh installs (059 runs before 099)
- ee provider: writes persist the doc alongside FGA tuples (FGA first, SQL
second, as before); GetWithTransactionGroups reads the doc; the per-type
ReadTuples fan-out (readAllTuplesForRole) is removed
- audit middleware: log and skip resolved resources carrying a resolution
error
- frontend: regenerated OpenAPI spec and API types; role list consumers
retyped to GettableRole; role GET keeps transactionGroups
* fix(authz): reconcile role tuples from openfga state, decouple migration 059
- Update and Delete derive their diff/deletion base from the tuples openfga
actually holds for the role (readAllTuplesForRole) instead of the stored
JSON record, so every mutation sweeps drift and residue; the record stays
a display-only artifact written after the tuple write
- ReadTuples restored on the AuthZ interface with plain passthroughs in both
providers and the ee server
- TransactionGroups.Value marshals unconditionally (nil renders as [] via
MarshalJSON) instead of returning a nil driver.Value
- migration 059 uses a migration-local role struct and constructor so live
Role model changes cannot alter its insert; migration 099 drops the manual
column-exists guard (AddColumn emits IF NOT EXISTS)
* refactor(authz): split role into domain Role and StorableRole
Replace the Scan/Value/MarshalJSON codecs on TransactionGroups with the
storable pattern: StorableRole is the bun model carrying transaction groups
as raw JSON text, Role is the pure domain/wire type, and
NewStorableRoleFromRole/NewRoleFromStorableRole convert at the store
boundary (nil groups persist as [], reads parse through the validating
constructor). RoleStore and sqlauthzstore speak StorableRole; both
providers convert; handlers and the wire contract are unchanged.
* revert(authz): restore TransactionGroups codecs over the storable split
Role is a bun relation target (UserRole.Role, ServiceAccountRole.Role), so
splitting it into StorableRole/Role cascaded: relations must point at the
bun model, which broke the user-roles join and leaked the storable shape
into user and service account responses. Keep the single Role model with
Scan/Value/MarshalJSON on TransactionGroups; the storable split fits leaf
models only.
This reverts commit 73aa7d32b1 and keeps transaction_test.go deleted.
* refactor(authz): use bun models in migration 099, wire oss role get
- migration 099 follows the migration-local row struct pattern: bun
NewSelect/NewUpdate for the role table reads and backfill writes; the
openfga store and tuple lookups stay raw like 081/083
- oss provider Get reads the role from the store instead of returning
unsupported
* refactor(authz): org-scoped backfill in migration 099, empty groups on null scan
- migration 099 iterates organizations: per org it backfills custom roles
from their permission tuples (readRoleTuples helper) and managed roles
from the registry (JSON precomputed per role name)
- TransactionGroups scans SQL NULL as an empty slice so the api always
renders transactionGroups as []; nullzero keeps writing NULL for nil
* fix(authz): pass unique constraints to add column in migration 099
* fix: don't return error in v2 list dashboard api if there is a v1 dashboard
* chore: generate api specs
* feat(dashboard-v2): surface legacy dashboards in the v2 list (#12024)
* feat(dashboard-v2): add legacy dashboard dialog
Surfaces a copyable dashboard ID and a Contact Support action for a
pre-v2 (legacy) dashboard that has no v2 spec to render.
* feat(dashboard-v2): hide v2-only actions for legacy dashboards
A legacy dashboard has no v2 spec, so view/open/copy-link/rename/
duplicate/lock don't apply. Gate them behind !isLegacy, leaving only
Delete (and dropping its now-orphan leading divider).
* feat(dashboard-v2): surface legacy dashboards in the v2 list
Flag legacy rows with a badge, block navigation, and open the legacy
dialog on click instead. Disable the pin action with an explanatory
tooltip and gate the row's actions menu to legacy-safe items.
---------
Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
* fix(ruletypes): tag rule threshold targets as format: double
BasicRuleThreshold.{TargetValue,RecoveryTarget} and RuleCondition.Target are
*float64 but emitted a bare 'type: number' (swaggest sets format: double only for
non-pointer floats). Bare number makes oapi-codegen clients generate float32, so a
value like 0.8 loses precision on round-trip. Tag them format:double to match
non-pointer float64 fields (e.g. MetrictypesComparisonSpaceAggregationParam).
* chore(frontend): regenerate API client for rule threshold format: double
Reflects the format: double schema change on the rule threshold/condition
targets in the orval-generated client (oxfmt + oxlint applied).
* feat(public-dashboard): detect v1 vs v2 schema for the public viewer
Anonymous public viewers have no feature flags, so the schema can't be read from
use_dashboard_v2. Probe the v2 model endpoint first and fall back to v1 only on the
'dashboard_invalid_data' (HTTP 501) schema-mismatch signal. Probing v2 first also stops
the v1 endpoint from serving v2 dashboards with un-redacted queries.
* feat(public-dashboard): fetch v2 public panel data by key
Adds a by-key fetcher over the anonymous /api/v2/public/dashboards/{id}/panels/{key}/query_range
endpoint (the generated client omits the startTime/endTime params) and a store-free
usePublicPanelQuery that mirrors usePanelQuery's PanelQueryData shape. No variables and no
pagination — the public endpoint supports neither.
* feat(public-dashboard): render v2 public dashboards read-only
Adds a read-only v2 viewer that reuses the authenticated V2 panel renderers
(PanelHeader with hideActions, PanelBody, panel registry) and the pure layoutsToSections
util, with a forked read-only grid. The public page branches on the resolved schema:
v1 keeps the existing container, v2 renders the new viewer. Dashboard variables are not
rendered — the public endpoint does not substitute them.
* feat(public-dashboard): match the standard auto-refresh control
Replace the hand-rolled 'Off' select (which was styled inconsistently and clipped its
options) with a PublicAutoRefresh that mirrors the app's DateTimeSelectionV2 refresh cluster:
a grouped refresh button + auto-refresh popover (Auto Refresh checkbox + full interval list),
portal-rendered so nothing clips. It's prop-driven — the public viewer keeps managing its own
time window — so the container now tracks enabled + interval and exposes a manual refresh.
Also nudge the header-right gap 8→12px.
* feat(public-dashboard): declare v2 query_range params, drop the wrapper, address review
Declare startTime/endTime as query params on the v2 public query_range endpoint via
RequestQuery and regenerate the OpenAPI spec + orval client, so the generated
getPublicDashboardPanelQueryRangeV2 carries them. usePublicPanelQuery now calls the
generated fetcher directly and the hand-written wrapper is removed.
Also from review: drop the defensive panelDefinition guard so an unsupported kind
surfaces loudly, use lodash noop, and trim excessive comments across the v2 files.
* fix: bind query params from PublicWidgetQueryRangeParams
---------
Co-authored-by: Naman Verma <naman.verma@signoz.io>
* chore: added types for containers
* chore: added querier query and constants
* chore: added helper queries
* chore: added wiring
* chore: added open api spec
* chore: endpoint and variable rename
* chore: use recency for container status.reason as well
* chore: pass orgID to getMetadata for containers (adapt to rebased main)
* chore: add metrics to the containers list for metadata and earliest time
* chore: corrected metrics list for metadata lookup
* chore: added changes to the checks API for new kube containers section
* chore: containers query modified
* chore: added integration tests
* chore: integration tests
* chore: goroutines in container monitoring
* chore: constants deduplication
* chore: inlined requests.Post call for this PR instead of wrapping in a function
* chore: added types and open api spec changes
* chore: added method to calculate reason
* chore: per group pod status counts with req metric checks method added
* chore: wired up pod status counts
* chore: pod restarts type added
* chore: added restart counts for the group
* chore: bug in query fix
* chore: onboarding API changes
* chore: integration tests added
* chore: added podcountsbyphase in other entities
* chore: added pod status counts for other entities
* chore: added integration tests for other entities
* chore: added checks api changes for other entities
* chore: rearrangement
* chore: removed succeeded status and mark it as completed
* chore: query beautified
* chore: corrected metrics list for metadata lookup
* chore: removed dead constants
* feat(authz): add serviceaccount and user role handlers
* feat(authz): add support for role and service account extractors
* feat(authz): make the user apis v2
* feat(authz): return the existing service account role id
* feat: add first draft of v2 public dashboard apis
* fix: remove duplicate call to GetDashboardByPublicIDV2 in GetPublicWidgetQueryRangeV2
* fix: fill fields that were in the data blob in v1
* chore: trim comments
* fix: remove fields that v1 also removes when redacting
* chore: rename method name
* test: unit tests for GetPanelQuery
* fix: add fill gaps to query
* fix: generate api specs
* test: add integration tests for new v2 public apis
* fix: add query validation and aggregation validation
* fix: remove unneeded tags db call from public query range api
* fix: redact variable queries as well
* fix: move regex out of method so that it is only compiled once per package load
* chore: remove empty line
* fix: use pointer to specs during redaction
* fix: move single expression validation to dashboard package, use chparser for it
* test: add integration test for variable query redaction
* test: add integration test for expression with many parens
* test: use valid query in integration test
* test: use realistic query in variable
* fix: return list of all tags sorted alphabetically
* chore: return reserved keys in list api response for easy filtering
* fix: add length limit to dashboard display name
* test: check error message as well
* chore: increase the length limits
* chore: add copy suffix on cloning dashboards
* fix: increase limit to 64 for dashboard view name
* fix: send user friendly err message on length check fail
* fix: add path to error message
* fix: include path in main error message directly
* fix: move regex out so that it only compiles once per init
* fix: format integration test properly
The reflector saw Source's unexported valuer.String field and emitted
type: object. Add a JSONSchema exposer that pins type: string, deriving
the enum values from the existing Enum() method so the list of sources
lives in exactly one place.
* chore(authz): delete the deprecated authz apis
* test(authz): rework role integration tests onto the new CRUD APIs
Migrate the role integration suite off the deprecated PATCH endpoints and
onto the current declarative role CRUD APIs (Create/Get/List/Update/Delete
with full transactionGroups).
- role/01_register.py: verify managed roles via GetRole's transactionGroups
against a golden matrix in testdata/role/managed_role_grants.json (no more
DB tuple assertions).
- role/02_crud.py (new): custom-role CRUD lifecycle, declarative update,
validation (naming, invalid verb/type/kind/selector, duplicate, managed
immutability, delete-with-assignee), and license gating.
- role/03_fga.py: resource FGA allow/deny via declarative grant sets.
- role/02_user.py: deleted; user role-membership is covered by the
passwordauthn suite.
- serviceaccount/06_fga.py: migrated to declarative grant PUTs.
- fixtures/role.py: pure data helpers + find_role_id fixture; tests make
their HTTP calls directly.
* test(authz): scope role/SA FGA tests to fine-grained selectors
- role FGA: grant read/update/delete on a specific role name (not "*") and
assert allowed-on-granted vs forbidden-on-other; create is collection-scoped;
list on "*" returns every role.
- serviceaccount FGA: grant on a specific SA id (with a second SA to prove
cross-instance denial); dual attach/detach scoped to SA id + role name.
- add create_role fixture (alongside find_role_id) for happy-path role creation;
validation/failure cases stay inline.
- underscore-prefix file-local constants in both FGA modules.
* test(authz): rename grants terminology to transactions in role tests
* chore(metrics): review follow ups for volume control
* chore: the reduced metrics show up in summary page
* chore: 1h; 6h window changes
* chore: address some gaps
* chore: asset warning gap
* chore: address lint
* chore: regenerate api
* fix: change schema properties based on UI integration review
* fix: check that panels referred in layouts exist
* chore: extract out validate panels method
* test: add test for missing spec prefix in layout
* fix: reject dashbaords that have vars with the same name
* fix: add additional error info on patch application error
* fix: add validations to list variable that text variable has
* fix: replicate text variable spec in signoz to make name required
* chore: replicate variable.sort into signoz
* chore: remove unsupported enum values (causing errors right now)
* chore: fix variable sort type errors
* fix: add back enum values
* fix: reject single-element list default when allowMultiple is false in list variables
* fix: remove unused import
* fix: make display required
* chore: make queries non-nullable
* fix: properly define default value and datasource plugin spec's api specs
* fix: promote variable defaultValue to a named oneOf component
The list variable defaultValue was an inline string | []string oneOf,
which downstream codegen can't canonicalize: tfplugingen-openapi rejects
the inline scalar-or-array multi-type, and oapi-codegen has no named type
to attach the union's Marshal/UnmarshalJSON to.
Shape the vendored variable.DefaultValue as the named VariableDefaultValue
oneOf via a reflector InterceptSchema hook and let defaultValue $ref it,
instead of overriding the property inline. Regenerate the OpenAPI spec and
frontend client accordingly.
* refactor: move VariableDefaultValue oneOf into dashboardtypes
Define VariableDefaultValue in dashboardtypes as a subclass of the perses
variable.DefaultValue and attach the string | []string oneOf via its own
PrepareJSONSchema, instead of shaping the perses type from an openapi.go
InterceptSchema hook. This keeps the union's schema next to its type.
The named component is now DashboardtypesVariableDefaultValue; regenerate
the OpenAPI spec and frontend client accordingly.
---------
Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
Co-authored-by: grandwizard28 <vibhupandey28@gmail.com>
* feat: add api to fetch v2 dashboards for a metric name
* chore: switch to query param
* chore: generate API specs
* chore: use proper struct in return type of GetByMetricNamesV2
* chore: add method for escaping like patterns in sqlstore formatter
* fix: use only one db call in GetByMetricNamesV2
* chore: dont use type alias for list of references
* chore: mark required and nullable in json tag, renamed methods, and added more functionality
* fix: unit test
* fix: cast clickhouse exceptions
* fix: go mod tidy
* fix: telemetrystore now returns explicit base errors
* fix: typo
* fix: added all changes
* fix: added nil check
* fix: update test files
* fix: addressed comments
* fix: change errors and suggestions to be non-nullable