upgrade access controls to use biome 2

This commit is contained in:
Nate Kelley 2025-10-09 10:19:04 -06:00
parent 30b7d30753
commit a62664184a
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
19 changed files with 97 additions and 102 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@ -1,7 +1,7 @@
{ {
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "$schema": "https://biomejs.dev/schemas/2.2.5/schema.json",
"extends": ["../../biome.json"], "extends": ["../../biome2.json"],
"files": { "files": {
"include": ["src/**/*"] "includes": ["src/**/*"]
} }
} }

View File

@ -32,7 +32,8 @@
"@buster/env-utils": "workspace:*", "@buster/env-utils": "workspace:*",
"@buster/typescript-config": "workspace:*", "@buster/typescript-config": "workspace:*",
"@buster/vitest-config": "workspace:*", "@buster/vitest-config": "workspace:*",
"lru-cache": "^11.1.0", "@biomejs/biome": "2.2.5",
"lru-cache": "^11.2.2",
"node-sql-parser": "^5.3.12", "node-sql-parser": "^5.3.12",
"yaml": "^2.8.1", "yaml": "^2.8.1",
"zod": "catalog:", "zod": "catalog:",

View File

@ -464,11 +464,8 @@ export async function hasAllDatasetsAccess(userId: string, datasetIds: string[])
// --- Step 3: Check specific permissions for each dataset --- // --- Step 3: Check specific permissions for each dataset ---
for (const datasetId of input.datasetIds) { for (const datasetId of input.datasetIds) {
const datasetOrgId = datasetInfos.find( const datasetOrgId = datasetInfos.find(
(info: { (info: { id: string; organizationId: string; deletedAt: string | null }) =>
id: string; info.id === datasetId
organizationId: string;
deletedAt: string | null;
}) => info.id === datasetId
)?.organizationId; )?.organizationId;
if (!datasetOrgId) { if (!datasetOrgId) {

View File

@ -1,9 +1,9 @@
import { beforeEach, describe, expect, it } from 'vitest'; import { beforeEach, describe, expect, it } from 'vitest';
import { import {
clearAllCaches, clearAllCaches,
getCacheStats,
getCachedCascadingPermission, getCachedCascadingPermission,
getCachedPermission, getCachedPermission,
getCacheStats,
invalidateAsset, invalidateAsset,
invalidateOnPermissionChange, invalidateOnPermissionChange,
invalidateUser, invalidateUser,

View File

@ -1,10 +1,10 @@
import type { User } from '@buster/database/queries';
import { import {
checkChatsContainingAsset, checkChatsContainingAsset,
checkCollectionsContainingAsset, checkCollectionsContainingAsset,
checkDashboardsContainingMetric, checkDashboardsContainingMetric,
checkReportsContainingMetric, checkReportsContainingMetric,
} from '@buster/database/queries'; } from '@buster/database/queries';
import type { User } from '@buster/database/queries';
import type { AssetType } from '@buster/database/schema-types'; import type { AssetType } from '@buster/database/schema-types';
import type { AssetPermissionRole, WorkspaceSharing } from '../types/asset-permissions'; import type { AssetPermissionRole, WorkspaceSharing } from '../types/asset-permissions';
import { AccessControlError } from '../types/errors'; import { AccessControlError } from '../types/errors';

View File

@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'; import { beforeEach, describe, expect, it, vi } from 'vitest';
import { checkPermission, computeEffectivePermission } from './checks';
import type { AssetPermissionResult } from './checks'; import type { AssetPermissionResult } from './checks';
import { checkPermission, computeEffectivePermission } from './checks';
// Mock database queries // Mock database queries
vi.mock('@buster/database/queries', () => ({ vi.mock('@buster/database/queries', () => ({

View File

@ -1,9 +1,9 @@
import type { User } from '@buster/database/queries';
import { import {
type CheckAssetPermissionParams, type CheckAssetPermissionParams,
checkAssetPermission as checkDbAssetPermission, checkAssetPermission as checkDbAssetPermission,
getUserOrganizationsByUserId, getUserOrganizationsByUserId,
} from '@buster/database/queries'; } from '@buster/database/queries';
import type { User } from '@buster/database/queries';
import type { AssetType } from '@buster/database/schema-types'; import type { AssetType } from '@buster/database/schema-types';
import type { AssetPermissionRole, OrganizationMembership, WorkspaceSharing } from '../types'; import type { AssetPermissionRole, OrganizationMembership, WorkspaceSharing } from '../types';
import { getHighestPermission, isPermissionSufficient } from '../types/asset-permissions'; import { getHighestPermission, isPermissionSufficient } from '../types/asset-permissions';

View File

@ -1,6 +1,6 @@
// Asset permissions module exports // Asset permissions module exports
export * from './permissions';
export * from './checks';
export * from './cascading-permissions';
export * from './cache'; export * from './cache';
export * from './cascading-permissions';
export * from './checks';
export * from './permissions';

View File

@ -1,5 +1,5 @@
import { checkPermission } from './checks';
import type { AssetPermissionCheck } from './checks'; import type { AssetPermissionCheck } from './checks';
import { checkPermission } from './checks';
/** /**
* Cached version of hasAssetPermission * Cached version of hasAssetPermission

View File

@ -1,10 +1,10 @@
import { import {
type ListAssetPermissionsParams,
type RemoveAssetPermissionParams,
bulkCreateAssetPermissions, bulkCreateAssetPermissions,
createAssetPermission, createAssetPermission,
findUserByEmail, findUserByEmail,
type ListAssetPermissionsParams,
listAssetPermissions, listAssetPermissions,
type RemoveAssetPermissionParams,
removeAssetPermission, removeAssetPermission,
} from '@buster/database/queries'; } from '@buster/database/queries';
import type { AssetType } from '@buster/database/schema-types'; import type { AssetType } from '@buster/database/schema-types';

View File

@ -2,9 +2,9 @@ import { beforeEach, describe, expect, it } from 'vitest';
import type { PermissionedDataset } from '../types/dataset-permissions'; import type { PermissionedDataset } from '../types/dataset-permissions';
import { import {
clearAllCaches, clearAllCaches,
getCacheStats,
getCachedDatasetAccess, getCachedDatasetAccess,
getCachedPermissionedDatasets, getCachedPermissionedDatasets,
getCacheStats,
invalidateDataset, invalidateDataset,
invalidateOnPermissionChange, invalidateOnPermissionChange,
invalidateUser, invalidateUser,

View File

@ -1,4 +1,4 @@
// Dataset permissions module exports // Dataset permissions module exports
export * from './permissions';
export * from './cache'; export * from './cache';
export * from './permissions';

View File

@ -1,89 +1,80 @@
// Export all types // Export all types
export * from './types';
// Export asset permissions (excluding cache functions to avoid conflicts)
export {
// From permissions.ts
hasAssetPermission,
createPermission,
createPermissionByEmail,
removePermission,
removePermissionByEmail,
listPermissions,
// From checks.ts
checkPermission,
computeEffectivePermission,
type AssetPermissionCheck,
type AssetPermissionResult,
// From cascading-permissions.ts
checkCascadingPermissions,
checkMetricDashboardAccess,
checkMetricChatAccess,
checkMetricCollectionAccess,
checkMetricReportAccess,
checkDashboardChatAccess,
checkDashboardCollectionAccess,
} from './assets';
// Export dataset permissions
export * from './datasets';
// Export user utilities
export * from './users';
// Export SQL permissions
export * from './sql-permissions';
// Export cache functions separately
export {
clearAllCaches,
invalidateUser,
invalidateOnPermissionChange,
getCacheStats as getAssetCacheStats,
} from './assets/cache';
// Export legacy access control functionality (for backward compatibility)
export {
AccessControlsError,
type Permission,
type Role,
type AccessControlOptions,
} from './types';
// Export legacy access control functions // Export legacy access control functions
export { export {
checkPermission as legacyCheckPermission, checkPermission as legacyCheckPermission,
hasRole,
validateAccess,
getPermissionedDatasets as legacyGetPermissionedDatasets, getPermissionedDatasets as legacyGetPermissionedDatasets,
hasDatasetAccess as legacyHasDatasetAccess,
hasAllDatasetsAccess as legacyHasAllDatasetsAccess, hasAllDatasetsAccess as legacyHasAllDatasetsAccess,
hasDatasetAccess as legacyHasDatasetAccess,
hasRole,
type PermissionedDataset as LegacyPermissionedDataset, type PermissionedDataset as LegacyPermissionedDataset,
validateAccess,
} from './access-controls'; } from './access-controls';
// Export asset permissions (excluding cache functions to avoid conflicts)
export {
type AssetPermissionCheck,
type AssetPermissionResult,
// From cascading-permissions.ts
checkCascadingPermissions,
checkDashboardChatAccess,
checkDashboardCollectionAccess,
checkMetricChatAccess,
checkMetricCollectionAccess,
checkMetricDashboardAccess,
checkMetricReportAccess,
// From checks.ts
checkPermission,
computeEffectivePermission,
createPermission,
createPermissionByEmail,
// From permissions.ts
hasAssetPermission,
listPermissions,
removePermission,
removePermissionByEmail,
} from './assets';
// Export cache functions separately
export {
clearAllCaches,
getCacheStats as getAssetCacheStats,
invalidateOnPermissionChange,
invalidateUser,
} from './assets/cache';
export { canUserAccessChat } from './chats'; export { canUserAccessChat } from './chats';
// Export cached version and cache management functions // Export cached version and cache management functions
export { export {
canUserAccessChatCached, canUserAccessChatCached,
getCacheStats,
resetCacheStats,
clearCache, clearCache,
getCacheStats,
invalidateAccess, invalidateAccess,
invalidateUserAccess,
invalidateChatAccess, invalidateChatAccess,
invalidateUserAccess,
resetCacheStats,
} from './chats-cached'; } from './chats-cached';
// Export dataset permissions
// Export utility functions export * from './datasets';
export { formatPermissionName, buildAccessQuery } from './utils'; // Export SQL permissions
export * from './sql-permissions';
export * from './types';
// Export legacy access control functionality (for backward compatibility)
export {
type AccessControlOptions,
AccessControlsError,
type Permission,
type Role,
} from './types';
// Export user organization functions // Export user organization functions
export { export {
checkUserInOrganization,
getUserOrganizations,
checkEmailDomainForOrganization, checkEmailDomainForOrganization,
getOrganizationWithDefaults, checkUserInOrganization,
createUserInOrganization, createUserInOrganization,
type UserOrganizationInfo, getOrganizationWithDefaults,
getUserOrganizations,
type OrganizationWithDefaults, type OrganizationWithDefaults,
type UserOrganizationInfo,
} from './user-organizations'; } from './user-organizations';
// Export user utilities
export * from './users';
// Export utility functions
export { buildAccessQuery, formatPermissionName } from './utils';

View File

@ -1,3 +1,3 @@
export * from './execute-with-permission-check';
export * from './parser-helpers'; export * from './parser-helpers';
export * from './validator'; export * from './validator';
export * from './execute-with-permission-check';

View File

@ -1,10 +1,13 @@
import pkg from 'node-sql-parser'; import pkg from 'node-sql-parser';
const { Parser } = pkg; const { Parser } = pkg;
import type { BaseFrom, ColumnRefItem, Join, Select } from 'node-sql-parser'; import type { BaseFrom, ColumnRefItem, Join, Select } from 'node-sql-parser';
import * as yaml from 'yaml'; import * as yaml from 'yaml';
export type { QueryTypeCheckResult } from '@buster/data-source';
// Import checkQueryIsReadOnly from data-source package // Import checkQueryIsReadOnly from data-source package
export { checkQueryIsReadOnly } from '@buster/data-source'; export { checkQueryIsReadOnly } from '@buster/data-source';
export type { QueryTypeCheckResult } from '@buster/data-source';
export interface ParsedTable { export interface ParsedTable {
database?: string; database?: string;
@ -155,7 +158,7 @@ export function extractPhysicalTables(sql: string, dataSourceSyntax?: string): P
*/ */
export function parseTableReference(tableRef: string): ParsedTable { export function parseTableReference(tableRef: string): ParsedTable {
// Remove any quotes and trim // Remove any quotes and trim
let cleanRef = tableRef.replace(/["'`\[\]]/g, '').trim(); let cleanRef = tableRef.replace(/["'`[\]]/g, '').trim();
// Handle node-sql-parser format: "type::database::table" or "type::table" // Handle node-sql-parser format: "type::database::table" or "type::table"
if (cleanRef.includes('::')) { if (cleanRef.includes('::')) {

View File

@ -1,12 +1,12 @@
import { getPermissionedDatasets } from '../datasets/permissions'; import { getPermissionedDatasets } from '../datasets/permissions';
import { import {
type ParsedDataset,
type ParsedTable,
checkQueryIsReadOnly, checkQueryIsReadOnly,
extractColumnReferences, extractColumnReferences,
extractDatasetsFromYml, extractDatasetsFromYml,
extractPhysicalTables, extractPhysicalTables,
extractTablesFromYml, extractTablesFromYml,
type ParsedDataset,
type ParsedTable,
tablesMatch, tablesMatch,
validateWildcardUsage, validateWildcardUsage,
} from './parser-helpers'; } from './parser-helpers';

View File

@ -2,8 +2,8 @@ import { z } from 'zod';
// Re-export all internal types // Re-export all internal types
export * from './types/asset-permissions'; export * from './types/asset-permissions';
export * from './types/dataset-permissions';
export * from './types/cascading-permissions'; export * from './types/cascading-permissions';
export * from './types/dataset-permissions';
export * from './types/errors'; export * from './types/errors';
// Custom error class for access control operations (legacy - use AccessControlError instead) // Custom error class for access control operations (legacy - use AccessControlError instead)

View File

@ -1016,6 +1016,9 @@ importers:
packages/access-controls: packages/access-controls:
dependencies: dependencies:
'@biomejs/biome':
specifier: 2.2.5
version: 2.2.5
'@buster/data-source': '@buster/data-source':
specifier: workspace:* specifier: workspace:*
version: link:../data-source version: link:../data-source
@ -1035,8 +1038,8 @@ importers:
specifier: 'catalog:' specifier: 'catalog:'
version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7) version: 0.44.5(@opentelemetry/api@1.9.0)(@types/pg@8.15.4)(bun-types@1.2.23(@types/react@19.1.13))(mysql2@3.14.1)(pg@8.16.3)(postgres@3.4.7)
lru-cache: lru-cache:
specifier: ^11.1.0 specifier: ^11.2.2
version: 11.1.0 version: 11.2.2
node-sql-parser: node-sql-parser:
specifier: ^5.3.12 specifier: ^5.3.12
version: 5.3.12 version: 5.3.12
@ -9568,14 +9571,14 @@ packages:
lru-cache@10.4.3: lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-cache@11.1.0:
resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==}
engines: {node: 20 || >=22}
lru-cache@11.2.1: lru-cache@11.2.1:
resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==} resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==}
engines: {node: 20 || >=22} engines: {node: 20 || >=22}
lru-cache@11.2.2:
resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==}
engines: {node: 20 || >=22}
lru-cache@5.1.1: lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@ -13215,7 +13218,7 @@ snapshots:
'@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
'@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
'@csstools/css-tokenizer': 3.0.4 '@csstools/css-tokenizer': 3.0.4
lru-cache: 11.2.1 lru-cache: 11.2.2
'@asamuzakjp/dom-selector@6.5.4': '@asamuzakjp/dom-selector@6.5.4':
dependencies: dependencies:
@ -22925,10 +22928,10 @@ snapshots:
lru-cache@10.4.3: {} lru-cache@10.4.3: {}
lru-cache@11.1.0: {}
lru-cache@11.2.1: {} lru-cache@11.2.1: {}
lru-cache@11.2.2: {}
lru-cache@5.1.1: lru-cache@5.1.1:
dependencies: dependencies:
yallist: 3.1.1 yallist: 3.1.1
@ -24378,7 +24381,7 @@ snapshots:
path-scurry@2.0.0: path-scurry@2.0.0:
dependencies: dependencies:
lru-cache: 11.2.1 lru-cache: 11.2.2
minipass: 7.1.2 minipass: 7.1.2
path-to-regexp@0.1.12: {} path-to-regexp@0.1.12: {}