Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@

[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.

## Feature docs

- Security penetration tests integration:
- `src/security-penetration-tests/README.md`

## Project setup

```bash
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { AssistantChatModule } from './assistant-chat/assistant-chat.module';
import { OrgChartModule } from './org-chart/org-chart.module';
import { TrainingModule } from './training/training.module';
import { EvidenceFormsModule } from './evidence-forms/evidence-forms.module';
import { SecurityPenetrationTestsModule } from './security-penetration-tests/security-penetration-tests.module';

@Module({
imports: [
Expand Down Expand Up @@ -84,6 +85,7 @@ import { EvidenceFormsModule } from './evidence-forms/evidence-forms.module';
TrainingModule,
OrgChartModule,
EvidenceFormsModule,
SecurityPenetrationTestsModule,
],
controllers: [AppController],
providers: [
Expand Down
40 changes: 40 additions & 0 deletions apps/api/src/security-penetration-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Security Penetration Tests (Maced Integration)

This module exposes Comp API endpoints under `/v1/security-penetration-tests` and orchestrates report generation with Maced (`/v1/pentests`).

## Endpoints

- `GET /v1/security-penetration-tests`
- `POST /v1/security-penetration-tests`
- `GET /v1/security-penetration-tests/:id`
- `GET /v1/security-penetration-tests/:id/progress`
- `GET /v1/security-penetration-tests/:id/report`
- `GET /v1/security-penetration-tests/:id/pdf`
- `POST /v1/security-penetration-tests/webhook`

## Required environment variables

- `MACED_API_KEY`: Maced API key used by Nest API when calling provider endpoints.

## Optional environment variables

- `MACED_API_BASE_URL`: Defaults to `https://api.maced.ai`.
- `SECURITY_PENETRATION_TESTS_WEBHOOK_URL`: Base callback URL for Comp webhook endpoint.

## Webhook handshake model

1. On create (`POST /v1/security-penetration-tests`), Maced issues a per-job `webhookToken` and returns it in the create response.
2. Comp does not send a user-provided `webhookToken` upstream; the value is reserved for provider issuance.
3. If callback target resolves to Comp webhook route and Maced returns `webhookToken`, Comp persists a handshake record in `secrets` using name:
- `security_penetration_test_webhook_<reportId>`
4. On webhook receive, Comp:
- resolves org context (`X-Organization-Id` or `orgId`/`organizationId` query),
- resolves token (`webhookToken` query or `X-Webhook-Token` header),
- requires a persisted per-job handshake and verifies token hash match,
- tracks idempotency (`X-Webhook-Id`/`X-Request-Id`, plus payload hash fallback),
- returns `duplicate: true` for replayed webhook events.

## Notes

- Frontend should call Nest API only (no Next.js proxy routes for this feature).
- Provider callbacks to non-Comp webhook URLs are passed through and are not forced to include Comp-specific webhook tokens.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { IsBoolean, IsOptional, IsString, IsUrl } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class CreatePenetrationTestDto {
@ApiProperty({
description: 'Target URL for the penetration test scan',
example: 'https://app.example.com',
})
@IsUrl()
targetUrl!: string;

@ApiProperty({
description: 'Repository URL containing the target application code',
example: 'https://github.com/org/repo',
required: false,
})
@IsOptional()
@IsUrl()
repoUrl?: string;

@ApiPropertyOptional({
description: 'GitHub token used for cloning private repositories',
required: false,
})
@IsOptional()
@IsString()
githubToken?: string;

@ApiPropertyOptional({
description: 'Optional YAML configuration for the pentest run',
required: false,
})
@IsOptional()
@IsString()
configYaml?: string;

@ApiPropertyOptional({
description: 'Whether to enable pipeline testing mode',
required: false,
default: false,
})
@IsOptional()
@IsBoolean()
pipelineTesting?: boolean;

@ApiPropertyOptional({
description: 'Workspace identifier used by the pentest engine',
required: false,
})
@IsOptional()
@IsString()
workspace?: string;

@ApiPropertyOptional({
description:
'Set false to reject non-mocked checkout flows for strict behavior',
required: false,
default: true,
})
@IsOptional()
@IsBoolean()
mockCheckout?: boolean;

@ApiPropertyOptional({
description: 'Optional webhook URL to notify when report generation completes',
required: false,
})
@IsOptional()
@IsUrl()
webhookUrl?: string;

@ApiPropertyOptional({
description: 'Whether to run the pentest in simulation mode',
required: false,
default: false,
})
@IsOptional()
@IsBoolean()
testMode?: boolean;
}
Loading
Loading