Compare commits

..

2 Commits

Author SHA1 Message Date
Vinícius Lourenço
76b78220a4 chore(frontend): add no-antd-barrel lint rule 2026-09-17 15:47:53 -03:00
Vinícius Lourenço
323ffcad7c perf(frontend): drop antd, sentry and store/actions barrels from the test import graph 2026-09-17 15:47:38 -03:00
43 changed files with 211 additions and 345 deletions

View File

@@ -11012,9 +11012,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration:list
- ADMIN
- tokenizer:
- cloud-integration:list
- ADMIN
summary: List accounts
tags:
- cloudintegration
@@ -11069,9 +11069,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration:create
- ADMIN
- tokenizer:
- cloud-integration:create
- ADMIN
summary: Create account
tags:
- cloudintegration
@@ -11114,9 +11114,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration:delete
- ADMIN
- tokenizer:
- cloud-integration:delete
- ADMIN
summary: Disconnect account
tags:
- cloudintegration
@@ -11182,9 +11182,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration:read
- ADMIN
- tokenizer:
- cloud-integration:read
- ADMIN
summary: Get account
tags:
- cloudintegration
@@ -11231,9 +11231,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration:update
- ADMIN
- tokenizer:
- cloud-integration:update
- ADMIN
summary: Update account
tags:
- cloudintegration
@@ -11289,9 +11289,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration-service:list
- ADMIN
- tokenizer:
- cloud-integration-service:list
- ADMIN
summary: List account services metadata
tags:
- cloudintegration
@@ -11364,9 +11364,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration-service:read
- ADMIN
- tokenizer:
- cloud-integration-service:read
- ADMIN
summary: Get service for account
tags:
- cloudintegration
@@ -11418,9 +11418,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration-service:update
- ADMIN
- tokenizer:
- cloud-integration-service:update
- ADMIN
summary: Update service
tags:
- cloudintegration
@@ -11528,9 +11528,9 @@ paths:
description: Internal Server Error
security:
- api_key:
- cloud-integration:create
- ADMIN
- tokenizer:
- cloud-integration:create
- ADMIN
summary: Get connection credentials
tags:
- cloudintegration
@@ -11580,8 +11580,10 @@ paths:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key: []
- tokenizer: []
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: List services metadata
tags:
- cloudintegration
@@ -11636,8 +11638,10 @@ paths:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key: []
- tokenizer: []
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Get service
tags:
- cloudintegration

View File

@@ -291,6 +291,11 @@
// Prevents the usage of specific antd components in favor of our lib
"signoz/no-signozhq-ui-barrel": "error",
// Forces subpath imports (@signozhq/ui/<component>) instead of the eagerly-loaded barrel
"signoz/no-antd-barrel": "off",
// Off until someone runs `oxlint --fix --rules signoz/no-antd-barrel` over
// src: 626 files still import the barrel and the autofix has not been
// reviewed against the production bundle. Same rationale as
// no-signozhq-ui-barrel above; the barrel is ~536 modules.
"signoz/no-css-module-bracket-access": "warn",
// Prevents bracket access on CSS modules (styles['kebab-case']) which fails with camelCaseOnly config
"signoz/no-dashboard-fetch-outside-root": "error",

View File

@@ -13,6 +13,9 @@ const config: Config.InitialOptions = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
modulePathIgnorePatterns: ['dist'],
moduleNameMapper: {
'^antd/es/(.*)$': 'antd/lib/$1',
'^lodash-es$': 'lodash',
'^lodash-es/(.*)$': 'lodash/$1',
'\\.(png|jpg|jpeg|gif|svg|webp|avif|ico|bmp|tiff)$':
'<rootDir>/__mocks__/fileMock.ts',
// The icon glob module uses `import.meta.glob` (Vite-only); jest can't parse

View File

@@ -0,0 +1,98 @@
/**
* Rule: no-antd-barrel
*
* Forbids importing from the `antd` barrel and requires the matching
* `antd/es/<component>` subpath instead.
*
* This rule catches:
* import { Tooltip } from 'antd'
* import { Button, Modal } from 'antd'
* import { theme as antdTheme } from 'antd'
*
* And expects:
* import Tooltip from 'antd/es/tooltip'
* import Button from 'antd/es/button'
* import antdTheme from 'antd/es/theme'
*
* Why: `antd/es/index.js` re-exports every component, and a re-export cannot be
* erased by type elision the way an unused named import can, so one `Tooltip`
* import loads all ~536 antd modules. Measured on the jest suite, five files on
* the `tests/test-utils` path were responsible for the whole antd subtree;
* converting just those cut per-file import cost 33%.
*
* Type-only imports are exempt: `import type { ThemeConfig } from 'antd'` is
* erased before the module is ever requested.
*/
const SUBPATH_OVERRIDES = {
theme: 'theme',
message: 'message',
notification: 'notification',
ConfigProvider: 'config-provider',
FloatButton: 'float-button',
AutoComplete: 'auto-complete',
BackTop: 'back-top',
ColorPicker: 'color-picker',
DatePicker: 'date-picker',
InputNumber: 'input-number',
TimePicker: 'time-picker',
TreeSelect: 'tree-select',
QRCode: 'qr-code',
};
function toSubpath(name) {
if (SUBPATH_OVERRIDES[name]) return SUBPATH_OVERRIDES[name];
// Components are PascalCase and live at the kebab-case path.
if (!/^[A-Z]/.test(name)) return null;
return name
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
.toLowerCase();
}
function buildReplacement(node) {
const quote = node.source.raw?.[0] === '"' ? '"' : "'";
const lines = [];
for (const spec of node.specifiers) {
if (spec.type !== 'ImportSpecifier') return null;
if (spec.imported?.type !== 'Identifier') return null;
const subpath = toSubpath(spec.imported.name);
if (!subpath) return null;
// An inline `type` specifier keeps its name; it is erased either way.
const keyword = spec.importKind === 'type' ? 'import type' : 'import';
lines.push(
`${keyword} ${spec.local.name} from ${quote}antd/es/${subpath}${quote};`,
);
}
return lines.length ? lines.join('\n') : null;
}
export default {
meta: {
fixable: 'code',
},
create(context) {
return {
ImportDeclaration(node) {
if (node.source.value !== 'antd') return;
if (node.importKind === 'type') return;
if (node.specifiers.length === 0) return;
const replacement = buildReplacement(node);
const report = {
node: node.source,
message:
"Do not import from the 'antd' barrel. Use the matching subpath instead (e.g. 'antd/es/tooltip', 'antd/es/button'). The barrel re-exports every component, so one named import loads all ~536 antd modules and slows every test that reaches this file.",
};
if (replacement) {
report.fix = (fixer) => fixer.replaceText(node, replacement);
}
context.report(report);
},
};
},
};

View File

@@ -11,6 +11,7 @@ import noUnsupportedAssetPattern from './rules/no-unsupported-asset-pattern.mjs'
import noRawAbsolutePath from './rules/no-raw-absolute-path.mjs';
import noAntdComponents from './rules/no-antd-components.mjs';
import noSignozhqUiBarrel from './rules/no-signozhq-ui-barrel.mjs';
import noAntdBarrel from './rules/no-antd-barrel.mjs';
import noCssModuleBracketAccess from './rules/no-css-module-bracket-access.mjs';
import noDashboardFetchOutsideRoot from './rules/no-dashboard-fetch-outside-root.mjs';
import noConditionalTextNodesWithSiblings from './rules/no-conditional-text-nodes-with-siblings.mjs';
@@ -27,6 +28,7 @@ export default {
'no-raw-absolute-path': noRawAbsolutePath,
'no-antd-components': noAntdComponents,
'no-signozhq-ui-barrel': noSignozhqUiBarrel,
'no-antd-barrel': noAntdBarrel,
'no-css-module-bracket-access': noCssModuleBracketAccess,
'no-dashboard-fetch-outside-root': noDashboardFetchOutsideRoot,
'no-conditional-text-nodes-with-siblings': noConditionalTextNodesWithSiblings,

View File

@@ -12,7 +12,7 @@ import { useIsDarkMode } from 'hooks/useDarkMode';
import useUrlQuery from 'hooks/useUrlQuery';
import { isEmpty } from 'lodash-es';
import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { Widgets } from 'types/api/widgets/widget';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -12,7 +12,7 @@ import { useIsDarkMode } from 'hooks/useDarkMode';
import useUrlQuery from 'hooks/useUrlQuery';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { Widgets } from 'types/api/widgets/widget';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';

View File

@@ -15,7 +15,7 @@ import { useIsDarkMode } from 'hooks/useDarkMode';
import useUrlQuery from 'hooks/useUrlQuery';
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
import { getStartAndEndTimesInMilliseconds } from 'pages/MessagingQueues/MessagingQueuesUtils';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { DataSource } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -1,6 +1,7 @@
import React from 'react';
import { Color } from '@signozhq/design-tokens';
import { Button, Modal } from 'antd';
import Button from 'antd/es/button';
import Modal from 'antd/es/modal';
import { CircleAlert, X } from '@signozhq/icons';
import KeyValueLabel from 'periscope/components/KeyValueLabel';
import { useAppContext } from 'providers/App/App';

View File

@@ -1,6 +1,6 @@
import { ReactNode } from 'react';
import { Color } from '@signozhq/design-tokens';
import { Button } from 'antd';
import Button from 'antd/es/button';
import ErrorIcon from 'assets/Error';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import { BookOpenText, ChevronsDown } from '@signozhq/icons';

View File

@@ -12,7 +12,7 @@ import heatmapPlugin from 'lib/uPlotLib/plugins/heatmapPlugin';
import timelinePlugin from 'lib/uPlotLib/plugins/timelinePlugin';
import { uPlotXAxisValuesFormat } from 'lib/uPlotLib/utils/constants';
import { useTimezone } from 'providers/Timezone';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AlertRuleTimelineGraphResponse } from 'types/api/alerts/def';
import uPlot, { AlignedData } from 'uplot';

View File

@@ -34,7 +34,7 @@ import { LegendPosition } from 'lib/uPlotV2/components/types';
import { isEmpty } from 'lodash-es';
import { useAppContext } from 'providers/App/App';
import { useTimezone } from 'providers/Timezone';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { Warning } from 'types/api';
import { AlertDef } from 'types/api/alerts/def';

View File

@@ -12,7 +12,7 @@ import GetMinMax from 'lib/getMinMax';
import { LegendPosition } from 'lib/uPlotV2/components/types';
import { StackMode } from 'lib/uPlotV2/config/types';
import { useTimezone } from 'providers/Timezone';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -33,8 +33,8 @@ let mockGlobalTimeState: {
} | null = null;
// Mock UpdateTimeInterval to update the mock state that useSelector will use
jest.mock('store/actions', () => {
const originalModule = jest.requireActual('store/actions');
jest.mock('store/actions/global', () => {
const originalModule = jest.requireActual('store/actions/global');
const GetMinMax = jest.requireActual('lib/getMinMax').default;
return {

View File

@@ -16,7 +16,7 @@ import dayjs from 'dayjs';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
import useUrlQuery from 'hooks/useUrlQuery';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { Widgets } from 'types/api/widgets/widget';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -11,7 +11,7 @@ import useUrlQuery from 'hooks/useUrlQuery';
import GetMinMax from 'lib/getMinMax';
import getTimeString from 'lib/getTimeString';
import history from 'lib/history';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { getTimeRange } from 'utils/getTimeRange';
interface UseTimeSeriesTimeManagementProps {

View File

@@ -23,7 +23,7 @@ import useUrlQuery from 'hooks/useUrlQuery';
import getStep from 'lib/getStep';
import history from 'lib/history';
import store from 'store';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid';

View File

@@ -25,7 +25,7 @@ import useUrlQuery from 'hooks/useUrlQuery';
import getStep from 'lib/getStep';
import history from 'lib/history';
import store from 'store';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { EQueryType } from 'types/common/dashboard';
import { v4 as uuid } from 'uuid';

View File

@@ -26,7 +26,7 @@ import history from 'lib/history';
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
import { defaultTo } from 'lodash-es';
import { useAppContext } from 'providers/App/App';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';

View File

@@ -36,7 +36,7 @@ import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
import { isEmpty } from 'lodash-es';
import { useTimezone } from 'providers/Timezone';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { SuccessResponse, Warning } from 'types/api';
import { LegendPosition } from 'types/api/widgets/widget';

View File

@@ -28,7 +28,7 @@ import { useTimezone } from 'providers/Timezone';
// eslint-disable-next-line no-restricted-imports
import { bindActionCreators, Dispatch } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import { GlobalTimeLoading, UpdateTimeInterval } from 'store/actions';
import { GlobalTimeLoading, UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -14,7 +14,7 @@ import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import getTimeString from 'lib/getTimeString';
import { isEqual } from 'lodash-es';
import isEmpty from 'lodash-es/isEmpty';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import APIError from 'types/api/error';
import { DataSource } from 'types/common/queryBuilder';

View File

@@ -1,7 +1,7 @@
import { renderHook } from '@testing-library/react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { useSyncTimeOnStagedQueryChange } from '../useSyncTimeOnStagedQueryChange';
@@ -12,7 +12,7 @@ jest.mock('react-redux', () => ({
useSelector: jest.fn(),
}));
jest.mock('store/actions', () => ({
jest.mock('store/actions/global', () => ({
UpdateTimeInterval: jest.fn((time: string) => ({
type: 'UPDATE_TIME_INTERVAL_THUNK',
payload: time,

View File

@@ -1,7 +1,7 @@
import { useEffect, useRef } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useDispatch, useSelector } from 'react-redux';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -11,7 +11,8 @@ import {
useMemo,
useState,
} from 'react';
import { theme as antdTheme, ThemeConfig } from 'antd';
import type { ThemeConfig } from 'antd/es/config-provider';
import antdTheme from 'antd/es/theme';
import get from 'api/browser/localstorage/get';
import set from 'api/browser/localstorage/set';
import { LOCALSTORAGE } from 'constants/localStorage';

View File

@@ -6,7 +6,7 @@ import { QueryParams } from 'constants/query';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import { getNextZoomOutRange } from 'lib/zoomOutUtils';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
import { persistTimeDurationForRoute } from 'utils/metricsTimeStorageUtils';

View File

@@ -12,7 +12,8 @@ import useResourceAttribute from 'hooks/useResourceAttribute';
import { whilelistedKeys } from 'hooks/useResourceAttribute/config';
import { IResourceAttribute } from 'hooks/useResourceAttribute/types';
import { filterServiceMapSupportedQueries } from 'hooks/useResourceAttribute/utils';
import { getDetailedServiceMapItems, ServiceMapStore } from 'store/actions';
import { getDetailedServiceMapItems } from 'store/actions/serviceMap';
import type { ServiceMapStore } from 'store/actions/serviceMap';
import { AppState } from 'store/reducers';
import styled from 'styled-components';
import { GlobalTime } from 'types/actions/globalTime';

View File

@@ -7,7 +7,9 @@ import { withRouter } from 'react-router-dom';
import { Select, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import Graph from 'components/Graph';
import { GetService, getUsageData, UsageDataItem } from 'store/actions';
import { GetService } from 'store/actions/metrics';
import { getUsageData } from 'store/actions/usage';
import type { UsageDataItem } from 'store/actions/usage';
import { AppState } from 'store/reducers';
import { GlobalTime } from 'types/actions/globalTime';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -14,7 +14,7 @@ import { Button } from 'container/MetricsApplication/Tabs/styles';
import { useGraphClickHandler } from 'container/MetricsApplication/Tabs/util';
import useUrlQuery from 'hooks/useUrlQuery';
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { AppState } from 'store/reducers';
import { Widgets } from 'types/api/widgets/widget';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';

View File

@@ -11,7 +11,7 @@ import { useSafeNavigate } from 'hooks/useSafeNavigate';
import useUrlQuery from 'hooks/useUrlQuery';
import logEvent from 'api/common/logEvent';
import { DashboardDetailEvents } from 'pages/DashboardPage/constants/events';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
export interface PanelInteractions {
/** Drag-select a chart range → write it to the URL + global time so every panel re-fetches the same range. */

View File

@@ -9,7 +9,7 @@ import GridCard from 'container/WidgetCard/Card';
import { Card } from 'container/WidgetCard/styles';
import { useIsDarkMode } from 'hooks/useDarkMode';
import useUrlQuery from 'hooks/useUrlQuery';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import { Widgets } from 'types/api/widgets/widget';
import './MetricPage.styles.scss';

View File

@@ -11,7 +11,7 @@ import { Card } from 'container/WidgetCard/styles';
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
import { useIsDarkMode } from 'hooks/useDarkMode';
import useUrlQuery from 'hooks/useUrlQuery';
import { UpdateTimeInterval } from 'store/actions';
import { UpdateTimeInterval } from 'store/actions/global';
import {
getFiltersFromConfigOptions,

View File

@@ -1,4 +1,4 @@
import { Tooltip } from 'antd';
import Tooltip from 'antd/es/tooltip';
import TrimmedText from '../TrimmedText/TrimmedText';

View File

@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
import { Tooltip } from 'antd';
import Tooltip from 'antd/es/tooltip';
function TrimmedText({
text,

View File

@@ -1,5 +0,0 @@
export * from './global';
export * from './metrics';
export * from './serviceMap';
export * from './types';
export * from './usage';

View File

@@ -1,4 +1,5 @@
import { Action, ActionTypes, ServiceMapStore } from 'store/actions';
import { Action, ActionTypes } from 'store/actions/types';
import type { ServiceMapStore } from 'store/actions/serviceMap';
const initialState: ServiceMapStore = {
items: [],

View File

@@ -1,5 +1,6 @@
/* eslint-disable sonarjs/no-small-switch */
import { Action, ActionTypes, UsageDataItem } from 'store/actions';
import { Action, ActionTypes } from 'store/actions/types';
import type { UsageDataItem } from 'store/actions/usage';
export const usageDataReducer = (
state: UsageDataItem[] = [{ timestamp: 0, count: 0 }],

View File

@@ -1,4 +1,3 @@
import * as Sentry from '@sentry/react';
import {
IBuilderQuery,
OrderByPayload,
@@ -23,11 +22,15 @@ export function sanitizeOrderByForExplorer(
const hasInvalidOrderBy = current.some((o) => !allowed.has(o.columnName));
if (hasInvalidOrderBy) {
Sentry.captureEvent({
message: `Invalid orderBy: current: ${JSON.stringify(
current,
)} - allowed: ${JSON.stringify(Array.from(allowed))}`,
level: 'warning',
// Loaded on demand: a static import puts all of @sentry/react (~273
// modules) in the graph of every module that reaches this file.
void import('@sentry/react').then((Sentry) => {
Sentry.captureEvent({
message: `Invalid orderBy: current: ${JSON.stringify(
current,
)} - allowed: ${JSON.stringify(Array.from(allowed))}`,
level: 'warning',
});
});
}
return current.filter((o) => allowed.has(o.columnName));

View File

@@ -5,15 +5,13 @@ import (
"github.com/SigNoz/signoz/pkg/http/handler"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/authtypes"
citypes "github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
"github.com/SigNoz/signoz/pkg/types/coretypes"
"github.com/gorilla/mux"
)
func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/credentials", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.GetConnectionCredentials, authtypes.SigNozAdminRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.GetConnectionCredentials),
handler.OpenAPIDef{
ID: "GetConnectionCredentials",
Tags: []string{"cloudintegration"},
@@ -26,20 +24,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegration.Scope(coretypes.VerbCreate)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegration,
Verb: coretypes.VerbCreate, // get or create the credentials, so we use create verb here
Category: coretypes.ActionCategoryConfigurationChange,
Selector: coretypes.WildcardSelector,
}),
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.CreateAccount, authtypes.SigNozAdminRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.CreateAccount),
handler.OpenAPIDef{
ID: "CreateAccount",
Tags: []string{"cloudintegration"},
@@ -52,21 +44,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusCreated,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegration.Scope(coretypes.VerbCreate)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegration,
Verb: coretypes.VerbCreate,
Category: coretypes.ActionCategoryConfigurationChange,
ID: coretypes.ResponseJSONPath("data.id"),
Selector: coretypes.WildcardSelector,
}),
)).Methods(http.MethodPost).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.ListAccounts, authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName, authtypes.SigNozViewerRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.ListAccounts),
handler.OpenAPIDef{
ID: "ListAccounts",
Tags: []string{"cloudintegration"},
@@ -79,20 +64,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegration.Scope(coretypes.VerbList)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegration,
Verb: coretypes.VerbList,
Category: coretypes.ActionCategoryDataAccess,
Selector: coretypes.WildcardSelector,
}),
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.GetAccount, authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName, authtypes.SigNozViewerRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.GetAccount),
handler.OpenAPIDef{
ID: "GetAccount",
Tags: []string{"cloudintegration"},
@@ -105,21 +84,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegration.Scope(coretypes.VerbRead)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegration,
Verb: coretypes.VerbRead,
Category: coretypes.ActionCategoryDataAccess,
ID: coretypes.PathParam("id"),
Selector: coretypes.IDSelector,
}),
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.UpdateAccount, authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.UpdateAccount),
handler.OpenAPIDef{
ID: "UpdateAccount",
Tags: []string{"cloudintegration"},
@@ -132,21 +104,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegration.Scope(coretypes.VerbUpdate)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegration,
Verb: coretypes.VerbUpdate,
Category: coretypes.ActionCategoryConfigurationChange,
ID: coretypes.PathParam("id"),
Selector: coretypes.IDSelector,
}),
)).Methods(http.MethodPut).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.DisconnectAccount, authtypes.SigNozAdminRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.DisconnectAccount),
handler.OpenAPIDef{
ID: "DisconnectAccount",
Tags: []string{"cloudintegration"},
@@ -159,21 +124,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegration.Scope(coretypes.VerbDelete)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegration,
Verb: coretypes.VerbDelete,
Category: coretypes.ActionCategoryConfigurationChange,
ID: coretypes.PathParam("id"),
Selector: coretypes.IDSelector,
}),
)).Methods(http.MethodDelete).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/services", handler.New(
provider.authzMiddleware.OpenAccess(provider.cloudIntegrationHandler.ListServicesMetadata),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.ListServicesMetadata),
handler.OpenAPIDef{
ID: "ListServicesMetadata",
Tags: []string{"cloudintegration"},
@@ -186,14 +144,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes(nil),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.ListAccountServicesMetadata, authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName, authtypes.SigNozViewerRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.ListAccountServicesMetadata),
handler.OpenAPIDef{
ID: "ListAccountServicesMetadata",
Tags: []string{"cloudintegration"},
@@ -206,20 +164,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegrationService.Scope(coretypes.VerbList)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegrationService,
Verb: coretypes.VerbList,
Category: coretypes.ActionCategoryDataAccess,
Selector: coretypes.WildcardSelector,
}),
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/services/{service_id}", handler.New(
provider.authzMiddleware.OpenAccess(provider.cloudIntegrationHandler.GetService),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.GetService),
handler.OpenAPIDef{
ID: "GetService",
Tags: []string{"cloudintegration"},
@@ -232,14 +184,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes(nil),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services/{service_id}", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.UpdateService, authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.UpdateService),
handler.OpenAPIDef{
ID: "UpdateService",
Tags: []string{"cloudintegration"},
@@ -252,21 +204,14 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusNoContent,
ErrorStatusCodes: []int{},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegrationService.Scope(coretypes.VerbUpdate)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegrationService,
Verb: coretypes.VerbUpdate,
Category: coretypes.ActionCategoryConfigurationChange,
ID: coretypes.PathParam("service_id"),
Selector: coretypes.WildcardSelector,
}),
)).Methods(http.MethodPut).GetError(); err != nil {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services/{service_id}", handler.New(
provider.authzMiddleware.CheckResources(provider.cloudIntegrationHandler.GetAccountService, authtypes.SigNozAdminRoleName, authtypes.SigNozEditorRoleName, authtypes.SigNozViewerRoleName),
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.GetAccountService),
handler.OpenAPIDef{
ID: "GetAccountService",
Tags: []string{"cloudintegration"},
@@ -279,15 +224,8 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
SuccessStatusCode: http.StatusOK,
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusNotFound},
Deprecated: false,
SecuritySchemes: newScopedSecuritySchemes([]string{coretypes.ResourceMetaResourceCloudIntegrationService.Scope(coretypes.VerbRead)}),
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
},
handler.WithResourceDefs(handler.BasicResourceDef{
Resource: coretypes.ResourceMetaResourceCloudIntegrationService,
Verb: coretypes.VerbRead,
Category: coretypes.ActionCategoryDataAccess,
ID: coretypes.PathParam("service_id"),
Selector: coretypes.WildcardSelector,
}),
)).Methods(http.MethodGet).GetError(); err != nil {
return err
}
@@ -314,7 +252,6 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
return err
}
// TODO: figure out authz permission model for this endppoint without breaking existing deployed agents.
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/check_in", handler.New(
provider.authzMiddleware.ViewAccess(provider.cloudIntegrationHandler.AgentCheckIn),
handler.OpenAPIDef{

View File

@@ -254,7 +254,6 @@ func NewSQLMigrationProviderFactories(
sqlmigration.NewAddIngestionTuplesFactory(sqlstore),
sqlmigration.NewAddSubscriptionTuplesFactory(sqlstore),
sqlmigration.NewNormalizeQuickFilterFieldsFactory(sqlstore),
sqlmigration.NewAddCloudIntegrationTuplesFactory(sqlstore),
)
}

View File

@@ -1,175 +0,0 @@
package sqlmigration
import (
"context"
"database/sql"
"encoding/json"
"time"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/coretypes"
"github.com/oklog/ulid/v2"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect"
"github.com/uptrace/bun/migrate"
)
type addCloudIntegrationTuples struct {
sqlstore sqlstore.SQLStore
}
func NewAddCloudIntegrationTuplesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_cloud_integration_tuples"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return &addCloudIntegrationTuples{sqlstore: sqlstore}, nil
})
}
func (migration *addCloudIntegrationTuples) Register(migrations *migrate.Migrations) error {
return migrations.Register(migration.Up, migration.Down)
}
func (migration *addCloudIntegrationTuples) Up(ctx context.Context, db *bun.DB) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer func() { _ = tx.Rollback() }()
var storeID string
err = tx.QueryRowContext(ctx, `SELECT id FROM store WHERE name = ? LIMIT 1`, "signoz").Scan(&storeID)
if err != nil {
return err
}
var orgIDs []string
err = tx.NewSelect().
Table("organizations").
Column("id").
Scan(ctx, &orgIDs)
if err != nil && err != sql.ErrNoRows {
return err
}
isPG := migration.sqlstore.BunDB().Dialect().Name() == dialect.PG
// cloud-integration and cloud-integration-service moved from legacy role
// gates to CheckResources. Existing organizations need the same tuples that
// new organizations receive from the managed-role registry at bootstrap.
tuples := []migrationTuple{
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration", "create"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration", "read"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration", "update"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration", "delete"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration", "list"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration-service", "read"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration-service", "update"},
{authtypes.SigNozAdminRoleName, "metaresource", "cloud-integration-service", "list"},
{authtypes.SigNozEditorRoleName, "metaresource", "cloud-integration", "read"},
{authtypes.SigNozEditorRoleName, "metaresource", "cloud-integration", "update"},
{authtypes.SigNozEditorRoleName, "metaresource", "cloud-integration", "list"},
{authtypes.SigNozEditorRoleName, "metaresource", "cloud-integration-service", "read"},
{authtypes.SigNozEditorRoleName, "metaresource", "cloud-integration-service", "update"},
{authtypes.SigNozEditorRoleName, "metaresource", "cloud-integration-service", "list"},
{authtypes.SigNozViewerRoleName, "metaresource", "cloud-integration", "read"},
{authtypes.SigNozViewerRoleName, "metaresource", "cloud-integration", "list"},
{authtypes.SigNozViewerRoleName, "metaresource", "cloud-integration-service", "read"},
{authtypes.SigNozViewerRoleName, "metaresource", "cloud-integration-service", "list"},
}
for _, orgID := range orgIDs {
for _, tuple := range tuples {
entropy := ulid.DefaultEntropy()
now := time.Now().UTC()
tupleID := ulid.MustNew(ulid.Timestamp(now), entropy).String()
objectID := "organization/" + orgID + "/" + tuple.objectName + "/*"
roleSubject := "organization/" + orgID + "/role/" + tuple.roleName
if isPG {
user := "role:" + roleSubject + "#assignee"
result, err := tx.ExecContext(ctx, `
INSERT INTO tuple (store, object_type, object_id, relation, _user, user_type, ulid, inserted_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (store, object_type, object_id, relation, _user) DO NOTHING`,
storeID, tuple.objectType, objectID, tuple.relation, user, "userset", tupleID, now,
)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
continue
}
_, err = tx.ExecContext(ctx, `
INSERT INTO changelog (store, object_type, object_id, relation, _user, operation, ulid, inserted_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (store, ulid, object_type) DO NOTHING`,
storeID, tuple.objectType, objectID, tuple.relation, user, 0, tupleID, now,
)
if err != nil {
return err
}
} else {
result, err := tx.ExecContext(ctx, `
INSERT INTO tuple (store, object_type, object_id, relation, user_object_type, user_object_id, user_relation, user_type, ulid, inserted_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (store, object_type, object_id, relation, user_object_type, user_object_id, user_relation) DO NOTHING`,
storeID, tuple.objectType, objectID, tuple.relation, "role", roleSubject, "assignee", "userset", tupleID, now,
)
if err != nil {
return err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
continue
}
_, err = tx.ExecContext(ctx, `
INSERT INTO changelog (store, object_type, object_id, relation, user_object_type, user_object_id, user_relation, operation, ulid, inserted_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT (store, ulid, object_type) DO NOTHING`,
storeID, tuple.objectType, objectID, tuple.relation, "role", roleSubject, "assignee", 0, tupleID, now,
)
if err != nil {
return err
}
}
}
}
managedRoleGroups := make(map[string]string, len(coretypes.ManagedRoleToTransactions))
for roleName, transactions := range coretypes.ManagedRoleToTransactions {
data, err := json.Marshal(authtypes.NewTransactionGroupsFromTransactions(transactions))
if err != nil {
return err
}
managedRoleGroups[roleName] = string(data)
}
for _, orgID := range orgIDs {
for roleName, data := range managedRoleGroups {
if _, err := tx.NewUpdate().
Model(new(roles)).
Set("transaction_groups = ?", data).
Where("org_id = ?", orgID).
Where("type = ?", authtypes.RoleTypeManaged.StringValue()).
Where("name = ?", roleName).
Exec(ctx); err != nil {
return err
}
}
}
return tx.Commit()
}
func (migration *addCloudIntegrationTuples) Down(context.Context, *bun.DB) error {
return nil
}

View File

@@ -35,15 +35,17 @@ var ManagedRoleToTransactions = map[string][]Transaction{
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindAuthDomain}, WildCardSelectorString)},
{Verb: VerbAttach, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindAuthDomain}, WildCardSelectorString)},
{Verb: VerbDetach, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindAuthDomain}, WildCardSelectorString)},
// cloud-integration — admin can fully manage accounts
// cloud-integration — admin only
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbUpdate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbDelete, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbCreate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
// cloud-integration-service — admin can read and update account services
// cloud-integration-service — admin only
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbUpdate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbDelete, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbCreate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
// integration — viewer/editor/admin (install/uninstall via ViewAccess)
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindIntegration}, WildCardSelectorString)},
@@ -214,14 +216,6 @@ var ManagedRoleToTransactions = map[string][]Transaction{
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindTracesField}, WildCardSelectorString)},
},
SigNozEditorRoleName: {
// cloud-integration — editor can read and update existing accounts
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbUpdate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
// cloud-integration-service — editor can read and update account services
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbUpdate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
// dashboard — full CRUD
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindDashboard}, WildCardSelectorString)},
{Verb: VerbUpdate, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindDashboard}, WildCardSelectorString)},
@@ -314,12 +308,6 @@ var ManagedRoleToTransactions = map[string][]Transaction{
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindTracesField}, WildCardSelectorString)},
},
SigNozViewerRoleName: {
// cloud-integration — viewer can read accounts
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegration}, WildCardSelectorString)},
// cloud-integration-service — viewer can read account services
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindCloudIntegrationService}, WildCardSelectorString)},
// dashboard — read only
{Verb: VerbRead, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindDashboard}, WildCardSelectorString)},
{Verb: VerbList, Object: *MustNewObject(ResourceRef{Type: TypeMetaResource, Kind: KindDashboard}, WildCardSelectorString)},

View File

@@ -52,8 +52,8 @@ var (
ResourceMetaResourceApdexSetting = NewResourceMetaResource(KindApdexSetting)
ResourceMetaResourceAuthDomain = NewResourceMetaResource(KindAuthDomain)
ResourceMetaResourceSession = NewResourceMetaResource(KindSession)
ResourceMetaResourceCloudIntegration = NewResourceMetaResource(KindCloudIntegration, VerbCreate, VerbList, VerbRead, VerbUpdate, VerbDelete)
ResourceMetaResourceCloudIntegrationService = NewResourceMetaResource(KindCloudIntegrationService, VerbList, VerbRead, VerbUpdate)
ResourceMetaResourceCloudIntegration = NewResourceMetaResource(KindCloudIntegration)
ResourceMetaResourceCloudIntegrationService = NewResourceMetaResource(KindCloudIntegrationService)
ResourceMetaResourceIntegration = NewResourceMetaResource(KindIntegration)
ResourceMetaResourceDashboard = NewResourceMetaResource(KindDashboard, VerbCreate, VerbList, VerbRead, VerbUpdate, VerbDelete)
ResourceMetaResourcePublicDashboard = NewResourceMetaResource(KindPublicDashboard)