Merge pull request #1272 from buster-so/nate/upgrade-access-controls-biome2

upgrade access controls to use biome 2
This commit is contained in:
Nate Kelley 2025-10-09 10:50:02 -06:00 committed by GitHub
commit 2dfb3d6e5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 89 additions and 100 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",
"extends": ["../../biome.json"],
"$schema": "https://biomejs.dev/schemas/2.2.5/schema.json",
"extends": ["../../biome2.json"],
"files": {
"include": ["src/**/*"]
"includes": ["src/**/*"]
}
}

View File

@ -32,7 +32,8 @@
"@buster/env-utils": "workspace:*",
"@buster/typescript-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",
"yaml": "^2.8.1",
"zod": "catalog:",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
// Asset permissions module exports
export * from './permissions';
export * from './checks';
export * from './cascading-permissions';
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 { checkPermission } from './checks';
/**
* Cached version of hasAssetPermission

View File

@ -1,10 +1,10 @@
import {
type ListAssetPermissionsParams,
type RemoveAssetPermissionParams,
bulkCreateAssetPermissions,
createAssetPermission,
findUserByEmail,
type ListAssetPermissionsParams,
listAssetPermissions,
type RemoveAssetPermissionParams,
removeAssetPermission,
} from '@buster/database/queries';
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 {
clearAllCaches,
getCacheStats,
getCachedDatasetAccess,
getCachedPermissionedDatasets,
getCacheStats,
invalidateDataset,
invalidateOnPermissionChange,
invalidateUser,

View File

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

View File

@ -1,89 +1,80 @@
// 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 {
checkPermission as legacyCheckPermission,
hasRole,
validateAccess,
getPermissionedDatasets as legacyGetPermissionedDatasets,
hasDatasetAccess as legacyHasDatasetAccess,
hasAllDatasetsAccess as legacyHasAllDatasetsAccess,
hasDatasetAccess as legacyHasDatasetAccess,
hasRole,
type PermissionedDataset as LegacyPermissionedDataset,
validateAccess,
} 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 cached version and cache management functions
export {
canUserAccessChatCached,
getCacheStats,
resetCacheStats,
clearCache,
getCacheStats,
invalidateAccess,
invalidateUserAccess,
invalidateChatAccess,
invalidateUserAccess,
resetCacheStats,
} from './chats-cached';
// Export utility functions
export { formatPermissionName, buildAccessQuery } from './utils';
// Export dataset permissions
export * from './datasets';
// 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 {
checkUserInOrganization,
getUserOrganizations,
checkEmailDomainForOrganization,
getOrganizationWithDefaults,
checkUserInOrganization,
createUserInOrganization,
type UserOrganizationInfo,
getOrganizationWithDefaults,
getUserOrganizations,
type OrganizationWithDefaults,
type UserOrganizationInfo,
} 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 './validator';
export * from './execute-with-permission-check';

View File

@ -1,10 +1,13 @@
import pkg from 'node-sql-parser';
const { Parser } = pkg;
import type { BaseFrom, ColumnRefItem, Join, Select } from 'node-sql-parser';
import * as yaml from 'yaml';
export type { QueryTypeCheckResult } from '@buster/data-source';
// Import checkQueryIsReadOnly from data-source package
export { checkQueryIsReadOnly } from '@buster/data-source';
export type { QueryTypeCheckResult } from '@buster/data-source';
export interface ParsedTable {
database?: string;
@ -155,7 +158,7 @@ export function extractPhysicalTables(sql: string, dataSourceSyntax?: string): P
*/
export function parseTableReference(tableRef: string): ParsedTable {
// 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"
if (cleanRef.includes('::')) {

View File

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

View File

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

View File

@ -1016,6 +1016,9 @@ importers:
packages/access-controls:
dependencies:
'@biomejs/biome':
specifier: 2.2.5
version: 2.2.5
'@buster/data-source':
specifier: workspace:*
version: link:../data-source
@ -1035,8 +1038,8 @@ importers:
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)
lru-cache:
specifier: ^11.1.0
version: 11.1.0
specifier: ^11.2.2
version: 11.2.2
node-sql-parser:
specifier: ^5.3.12
version: 5.3.12
@ -9419,10 +9422,6 @@ packages:
lru-cache@10.4.3:
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.2:
resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==}
engines: {node: 20 || >=22}
@ -22666,8 +22665,6 @@ snapshots:
lru-cache@10.4.3: {}
lru-cache@11.1.0: {}
lru-cache@11.2.2: {}
lru-cache@5.1.1: