feat(status-dashboard): apply security guards to controllers
Apply defense-in-depth security to all sensitive endpoints:
HostsController:
- Add FlexibleAuthGuard with @AuthMethods('jwt')
- Add AuditLoggingInterceptor for request tracking
StatusController:
- Add FlexibleAuthGuard with @AuthMethods('jwt')
- Add AuditLoggingInterceptor for request tracking
- Apply DTOs for input validation (ContainerNameDto, LogsQueryDto, EventsQueryDto)
All /api/hosts/* and /api/health/* endpoints now require JWT
authentication and log all access attempts.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2ce3b295f4
commit
e794353eef
3 changed files with 33 additions and 14 deletions
|
|
@ -4,3 +4,6 @@ export * from './docker-event.dto';
|
|||
export * from './platform-status.dto';
|
||||
export * from './dependency-graph.dto';
|
||||
export * from './endpoint-status.dto';
|
||||
export * from './logs-query.dto';
|
||||
export * from './container-name.dto';
|
||||
export * from './events-query.dto';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
import { Controller, Get, Param } from '@nestjs/common';
|
||||
import { Controller, Get, Param, UseGuards, UseInterceptors } from '@nestjs/common';
|
||||
import { MetricsStorageService } from '../storage/metrics-storage.service';
|
||||
import { AlertDetectionService } from '../alerts/alert-detection.service';
|
||||
import { FlexibleAuthGuard, AuthMethods } from '../auth';
|
||||
import { HOSTS } from '../config/hosts.config';
|
||||
import { AuditLoggingInterceptor } from '../logging';
|
||||
|
||||
@Controller('api/hosts')
|
||||
@UseGuards(FlexibleAuthGuard)
|
||||
@AuthMethods('jwt')
|
||||
@UseInterceptors(AuditLoggingInterceptor)
|
||||
export class HostsController {
|
||||
constructor(
|
||||
private readonly metricsStorage: MetricsStorageService,
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@ import {
|
|||
HttpException,
|
||||
HttpStatus,
|
||||
Logger,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
import { execFileSync } from 'child_process';
|
||||
import { VPSAgentService, DockerContainer } from '../vps/vps-agent.service';
|
||||
import { EndpointCheckerService, EndpointStatus } from '../endpoints';
|
||||
import { FlexibleAuthGuard, AuthMethods } from '../auth';
|
||||
import {
|
||||
PlatformStatusDto,
|
||||
PlatformStatus,
|
||||
|
|
@ -19,10 +22,17 @@ import {
|
|||
DockerEventDto,
|
||||
DependencyGraphDto,
|
||||
EndpointStatusDto,
|
||||
LogsQueryDto,
|
||||
ContainerNameDto,
|
||||
EventsQueryDto,
|
||||
} from './dto';
|
||||
import { AuditLoggingInterceptor } from '../logging';
|
||||
|
||||
@ApiTags('health')
|
||||
@Controller('api/health')
|
||||
@UseGuards(FlexibleAuthGuard)
|
||||
@AuthMethods('jwt')
|
||||
@UseInterceptors(AuditLoggingInterceptor)
|
||||
export class StatusController {
|
||||
private readonly logger = new Logger(StatusController.name);
|
||||
|
||||
|
|
@ -155,15 +165,15 @@ export class StatusController {
|
|||
status: 404,
|
||||
description: 'Service not found',
|
||||
})
|
||||
async getServiceDetail(@Param('name') name: string): Promise<DockerContainerDto> {
|
||||
async getServiceDetail(@Param() params: ContainerNameDto): Promise<DockerContainerDto> {
|
||||
try {
|
||||
this.logger.log(`Fetching details for service: ${name}`);
|
||||
this.logger.log(`Fetching details for service: ${params.name}`);
|
||||
|
||||
const containers = await this.vpsAgent.getDockerContainers();
|
||||
const container = containers.find((c) => c.name === name);
|
||||
const container = containers.find((c) => c.name === params.name);
|
||||
|
||||
if (!container) {
|
||||
throw new HttpException(`Service '${name}' not found`, HttpStatus.NOT_FOUND);
|
||||
throw new HttpException(`Service '${params.name}' not found`, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
return container as DockerContainerDto;
|
||||
|
|
@ -172,7 +182,7 @@ export class StatusController {
|
|||
throw error;
|
||||
}
|
||||
|
||||
this.logger.error(`Failed to get service details for ${name}`, error);
|
||||
this.logger.error(`Failed to get service details for ${params.name}`, error);
|
||||
throw new HttpException(
|
||||
'Failed to retrieve service details',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
|
|
@ -222,10 +232,10 @@ export class StatusController {
|
|||
description: 'Docker events retrieved successfully',
|
||||
type: [DockerEventDto],
|
||||
})
|
||||
async getEvents(@Query('since') since = '1h'): Promise<DockerEventDto[]> {
|
||||
async getEvents(@Query() query: EventsQueryDto): Promise<DockerEventDto[]> {
|
||||
try {
|
||||
this.logger.log(`Fetching Docker events since ${since}...`);
|
||||
const events = await this.vpsAgent.getDockerEvents(since);
|
||||
this.logger.log(`Fetching Docker events since ${query.since}...`);
|
||||
const events = await this.vpsAgent.getDockerEvents(query.since || '1h');
|
||||
return events as DockerEventDto[];
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to get Docker events', error);
|
||||
|
|
@ -280,17 +290,18 @@ export class StatusController {
|
|||
schema: { type: 'object', properties: { logs: { type: 'string' } } },
|
||||
})
|
||||
async getContainerLogs(
|
||||
@Param('name') name: string,
|
||||
@Query('lines') lines = 100,
|
||||
@Param() params: ContainerNameDto,
|
||||
@Query() query: LogsQueryDto,
|
||||
): Promise<{ logs: string }> {
|
||||
try {
|
||||
this.logger.log(`Fetching logs for service: ${name} (${lines} lines)`);
|
||||
const lines = query.lines || 100;
|
||||
this.logger.log(`Fetching logs for service: ${params.name} (${lines} lines)`);
|
||||
|
||||
const logs = await this.vpsAgent.getContainerLogs(name, Number(lines));
|
||||
const logs = await this.vpsAgent.getContainerLogs(params.name, lines);
|
||||
|
||||
return { logs };
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to get logs for ${name}`, error);
|
||||
this.logger.error(`Failed to get logs for ${params.name}`, error);
|
||||
throw new HttpException(
|
||||
'Failed to retrieve container logs',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue