Files
cloud-server/src/repositories/regions.ts
kappa 3a8dd705e6 refactor: comprehensive code review fixes (security, performance, QA)
## Security Improvements
- Fix timing attack in verifyApiKey with fixed 256-byte buffer
- Fix sortOrder SQL injection with whitelist validation
- Fix rate limiting bypass for non-Cloudflare traffic (fail-closed)
- Remove stack trace exposure in error responses
- Add request_id for audit trail (X-Request-ID header)
- Sanitize origin header to prevent log injection
- Add content-length validation for /sync endpoint (10KB limit)
- Replace Math.random() with crypto.randomUUID() for sync IDs
- Expand sensitive data masking patterns (8 → 18)

## Performance Improvements
- Reduce rate limiter KV reads from 3 to 1 per request (66% reduction)
- Increase sync batch size from 100 to 500 (80% fewer batches)
- Fix health check N+1 query with efficient JOINs
- Fix COUNT(*) Cartesian product with COUNT(DISTINCT)
- Implement shared logger cache pattern across repositories
- Add CacheService singleton pattern in recommend.ts
- Add composite index for recommendation queries
- Implement Anvil pricing query batching (100 per chunk)

## QA Improvements
- Add BATCH_SIZE bounds validation (1-1000)
- Add pagination bounds (page >= 1, MAX_OFFSET = 100000)
- Add min/max range consistency validation
- Add DB reference validation for singleton services
- Add type guards for database result validation
- Add timeout mechanism for external API calls (10-60s)
- Use SUPPORTED_PROVIDERS constant instead of hardcoded list

## Removed
- Remove Vault integration (using Wrangler secrets)
- Remove 6-hour pricing cron (daily sync only)

## Configuration
- Add idx_instance_types_specs_filter composite index
- Add CORS Access-Control-Expose-Headers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 23:50:37 +09:00

196 lines
5.1 KiB
TypeScript

/**
* Regions Repository
* Handles CRUD operations for provider regions
*/
import { BaseRepository } from './base';
import { Region, RegionInput, RepositoryError, ErrorCodes } from '../types';
export class RegionsRepository extends BaseRepository<Region> {
protected tableName = 'regions';
protected allowedColumns = [
'provider_id',
'region_code',
'region_name',
'country_code',
'latitude',
'longitude',
'available',
];
/**
* Find all regions for a specific provider
*/
async findByProvider(providerId: number): Promise<Region[]> {
try {
const result = await this.db
.prepare('SELECT * FROM regions WHERE provider_id = ?')
.bind(providerId)
.all<Region>();
return result.results;
} catch (error) {
this.logger.error('findByProvider failed', {
providerId,
error: error instanceof Error ? error.message : 'Unknown error'
});
throw new RepositoryError(
`Failed to find regions for provider: ${providerId}`,
ErrorCodes.DATABASE_ERROR,
error
);
}
}
/**
* Find a region by provider ID and region code
*/
async findByCode(providerId: number, code: string): Promise<Region | null> {
try {
const result = await this.db
.prepare('SELECT * FROM regions WHERE provider_id = ? AND region_code = ?')
.bind(providerId, code)
.first<Region>();
return result || null;
} catch (error) {
this.logger.error('findByCode failed', {
providerId,
code,
error: error instanceof Error ? error.message : 'Unknown error'
});
throw new RepositoryError(
`Failed to find region by code: ${code}`,
ErrorCodes.DATABASE_ERROR,
error
);
}
}
/**
* Bulk upsert regions for a provider
* Uses batch operations for efficiency
*/
async upsertMany(providerId: number, regions: RegionInput[]): Promise<number> {
if (regions.length === 0) {
return 0;
}
try {
// Build upsert statements for each region
const statements = regions.map((region) => {
return this.db.prepare(
`INSERT INTO regions (
provider_id, region_code, region_name, country_code,
latitude, longitude, available
) VALUES (?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(provider_id, region_code)
DO UPDATE SET
region_name = excluded.region_name,
country_code = excluded.country_code,
latitude = excluded.latitude,
longitude = excluded.longitude,
available = excluded.available`
).bind(
providerId,
region.region_code,
region.region_name,
region.country_code || null,
region.latitude || null,
region.longitude || null,
region.available
);
});
// Count successful operations
const successCount = await this.executeBatchCount(statements);
this.logger.info('Upserted regions', {
providerId,
count: successCount
});
return successCount;
} catch (error) {
this.logger.error('upsertMany failed', {
providerId,
count: regions.length,
error: error instanceof Error ? error.message : 'Unknown error'
});
throw new RepositoryError(
`Failed to upsert regions for provider: ${providerId}`,
ErrorCodes.TRANSACTION_FAILED,
error
);
}
}
/**
* Get available regions only
*/
async findAvailable(providerId?: number): Promise<Region[]> {
try {
let query = 'SELECT * FROM regions WHERE available = 1';
const params: (string | number | boolean | null)[] = [];
if (providerId !== undefined) {
query += ' AND provider_id = ?';
params.push(providerId);
}
const result = await this.db
.prepare(query)
.bind(...params)
.all<Region>();
return result.results;
} catch (error) {
this.logger.error('findAvailable failed', {
providerId,
error: error instanceof Error ? error.message : 'Unknown error'
});
throw new RepositoryError(
'Failed to find available regions',
ErrorCodes.DATABASE_ERROR,
error
);
}
}
/**
* Update region availability status
*/
async updateAvailability(id: number, available: boolean): Promise<Region> {
try {
const result = await this.db
.prepare('UPDATE regions SET available = ? WHERE id = ? RETURNING *')
.bind(available ? 1 : 0, id)
.first<Region>();
if (!result) {
throw new RepositoryError(
`Region not found: ${id}`,
ErrorCodes.NOT_FOUND
);
}
return result;
} catch (error) {
this.logger.error('updateAvailability failed', {
id,
available,
error: error instanceof Error ? error.message : 'Unknown error'
});
if (error instanceof RepositoryError) {
throw error;
}
throw new RepositoryError(
`Failed to update region availability: ${id}`,
ErrorCodes.DATABASE_ERROR,
error
);
}
}
}