Add unit tests for RabbitMq and Udp transport servers and clients
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling. - Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options. - Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation. - Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios. - Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling. - Included tests for UdpTransportOptions to verify default values and modification capabilities. - Enhanced service registration tests for Udp transport services in the dependency injection container.
This commit is contained in:
324
docs/contracts/export-bundle.md
Normal file
324
docs/contracts/export-bundle.md
Normal file
@@ -0,0 +1,324 @@
|
||||
# Export Bundle Scheduler Contract
|
||||
|
||||
**Contract ID:** `CONTRACT-EXPORT-BUNDLE-009`
|
||||
**Version:** 1.0
|
||||
**Status:** Published
|
||||
**Last Updated:** 2025-12-05
|
||||
|
||||
## Overview
|
||||
|
||||
This contract defines the export bundle job scheduling and manifest format used by the Export Center. It covers job definitions, scheduling, output formats, and attestation integration.
|
||||
|
||||
## Implementation References
|
||||
|
||||
- **Export Center:** `src/ExportCenter/`
|
||||
- **API Spec:** `src/Api/StellaOps.Api.OpenApi/export-center/openapi.yaml`
|
||||
|
||||
## Data Models
|
||||
|
||||
### ExportBundleJob
|
||||
|
||||
Job definition for scheduled exports.
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "job-001",
|
||||
"tenant_id": "default",
|
||||
"name": "daily-vex-export",
|
||||
"description": "Daily VEX advisory export",
|
||||
"query": {
|
||||
"type": "vex",
|
||||
"filters": {
|
||||
"severity": ["critical", "high"],
|
||||
"providers": ["github", "redhat"]
|
||||
}
|
||||
},
|
||||
"format": "openvex",
|
||||
"schedule": "0 0 * * *",
|
||||
"destination": {
|
||||
"type": "s3",
|
||||
"config": {
|
||||
"bucket": "exports",
|
||||
"prefix": "vex/daily/"
|
||||
}
|
||||
},
|
||||
"signing": {
|
||||
"enabled": true,
|
||||
"predicate_type": "stella.ops/vex@v1"
|
||||
},
|
||||
"enabled": true,
|
||||
"created_at": "2025-12-05T10:00:00Z",
|
||||
"last_run_at": "2025-12-05T00:00:00Z",
|
||||
"next_run_at": "2025-12-06T00:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Export Formats
|
||||
|
||||
| Format | Description | MIME Type |
|
||||
|--------|-------------|-----------|
|
||||
| `openvex` | OpenVEX JSON | application/json |
|
||||
| `csaf` | CSAF VEX | application/json |
|
||||
| `cyclonedx` | CycloneDX VEX | application/json |
|
||||
| `spdx` | SPDX document | application/json |
|
||||
| `ndjson` | Newline-delimited JSON | application/x-ndjson |
|
||||
| `json` | Standard JSON array | application/json |
|
||||
|
||||
### Schedule Format
|
||||
|
||||
Cron expressions (5 fields):
|
||||
```
|
||||
┌───────────── minute (0-59)
|
||||
│ ┌───────────── hour (0-23)
|
||||
│ │ ┌───────────── day of month (1-31)
|
||||
│ │ │ ┌───────────── month (1-12)
|
||||
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
|
||||
│ │ │ │ │
|
||||
* * * * *
|
||||
```
|
||||
|
||||
Examples:
|
||||
| Schedule | Description |
|
||||
|----------|-------------|
|
||||
| `0 0 * * *` | Daily at midnight |
|
||||
| `0 */6 * * *` | Every 6 hours |
|
||||
| `0 0 * * 0` | Weekly on Sunday |
|
||||
| `0 0 1 * *` | Monthly on the 1st |
|
||||
|
||||
### Destination Types
|
||||
|
||||
#### S3 Destination
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "s3",
|
||||
"config": {
|
||||
"bucket": "my-exports",
|
||||
"prefix": "vex/",
|
||||
"region": "us-east-1",
|
||||
"endpoint": "https://s3.amazonaws.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### File Destination
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "file",
|
||||
"config": {
|
||||
"path": "/exports/vex/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Webhook Destination
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "webhook",
|
||||
"config": {
|
||||
"url": "https://example.com/webhook",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${SECRET}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ExportBundleManifest
|
||||
|
||||
Manifest for completed export.
|
||||
|
||||
```json
|
||||
{
|
||||
"bundle_id": "bundle-001",
|
||||
"job_id": "job-001",
|
||||
"tenant_id": "default",
|
||||
"created_at": "2025-12-05T00:00:00Z",
|
||||
"format": "openvex",
|
||||
"artifact_digest": "sha256:abc123...",
|
||||
"artifact_size_bytes": 1048576,
|
||||
"query_signature": "sha256:def456...",
|
||||
"item_count": 150,
|
||||
"policy_digest": "sha256:...",
|
||||
"consensus_digest": "sha256:...",
|
||||
"score_digest": "sha256:...",
|
||||
"attestation": {
|
||||
"predicate_type": "stella.ops/vex@v1",
|
||||
"rekor_uuid": "24296fb24b8ad77a...",
|
||||
"rekor_index": 12345,
|
||||
"signed_at": "2025-12-05T00:00:01Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Job Management
|
||||
|
||||
#### Create Export Job
|
||||
|
||||
```
|
||||
POST /api/v1/export/jobs
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer <token>
|
||||
|
||||
{
|
||||
"name": "daily-vex-export",
|
||||
"query": {...},
|
||||
"format": "openvex",
|
||||
"schedule": "0 0 * * *",
|
||||
"destination": {...}
|
||||
}
|
||||
|
||||
Response: 201 Created
|
||||
{
|
||||
"job_id": "job-001",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Job
|
||||
|
||||
```
|
||||
PUT /api/v1/export/jobs/{job_id}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"schedule": "0 */12 * * *",
|
||||
"enabled": true
|
||||
}
|
||||
|
||||
Response: 200 OK
|
||||
```
|
||||
|
||||
#### Delete Job
|
||||
|
||||
```
|
||||
DELETE /api/v1/export/jobs/{job_id}
|
||||
|
||||
Response: 204 No Content
|
||||
```
|
||||
|
||||
#### List Jobs
|
||||
|
||||
```
|
||||
GET /api/v1/export/jobs?tenant_id=default
|
||||
|
||||
Response: 200 OK
|
||||
{
|
||||
"items": [...],
|
||||
"total": 5
|
||||
}
|
||||
```
|
||||
|
||||
### Manual Execution
|
||||
|
||||
#### Trigger Job
|
||||
|
||||
```
|
||||
POST /api/v1/export/jobs/{job_id}/run
|
||||
|
||||
Response: 202 Accepted
|
||||
{
|
||||
"execution_id": "exec-001",
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Execution Status
|
||||
|
||||
```
|
||||
GET /api/v1/export/jobs/{job_id}/executions/{execution_id}
|
||||
|
||||
Response: 200 OK
|
||||
{
|
||||
"execution_id": "exec-001",
|
||||
"status": "completed",
|
||||
"bundle_id": "bundle-001",
|
||||
"started_at": "2025-12-05T00:00:00Z",
|
||||
"completed_at": "2025-12-05T00:00:05Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Bundle Retrieval
|
||||
|
||||
#### Get Bundle Manifest
|
||||
|
||||
```
|
||||
GET /api/v1/export/bundles/{bundle_id}
|
||||
|
||||
Response: 200 OK
|
||||
{
|
||||
"bundle_id": "bundle-001",
|
||||
"artifact_digest": "sha256:...",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
#### Download Bundle
|
||||
|
||||
```
|
||||
GET /api/v1/export/bundles/{bundle_id}/download
|
||||
|
||||
Response: 200 OK
|
||||
Content-Type: application/json
|
||||
Content-Disposition: attachment; filename="vex-export-2025-12-05.json"
|
||||
|
||||
[bundle content]
|
||||
```
|
||||
|
||||
## Signing Configuration
|
||||
|
||||
### Enable Signing
|
||||
|
||||
```json
|
||||
{
|
||||
"signing": {
|
||||
"enabled": true,
|
||||
"predicate_type": "stella.ops/vex@v1",
|
||||
"key_id": "signing-key-001",
|
||||
"include_rekor": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Predicate Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `stella.ops/vex@v1` | VEX export attestation |
|
||||
| `stella.ops/sbom@v1` | SBOM export attestation |
|
||||
| `stella.ops/policy@v1` | Policy result export |
|
||||
|
||||
## Job Status
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| `idle` | Job is waiting for next scheduled run |
|
||||
| `running` | Job is currently executing |
|
||||
| `completed` | Last run completed successfully |
|
||||
| `failed` | Last run failed |
|
||||
| `disabled` | Job is disabled |
|
||||
|
||||
## Error Codes
|
||||
|
||||
| Code | Message |
|
||||
|------|---------|
|
||||
| `ERR_EXP_001` | Invalid schedule expression |
|
||||
| `ERR_EXP_002` | Invalid destination config |
|
||||
| `ERR_EXP_003` | Export failed |
|
||||
| `ERR_EXP_004` | Signing failed |
|
||||
| `ERR_EXP_005` | Job not found |
|
||||
|
||||
## Unblocks
|
||||
|
||||
This contract unblocks the following tasks:
|
||||
|
||||
- EXPORT-CONSOLE-23-001
|
||||
|
||||
## Related Contracts
|
||||
|
||||
- [Mirror Bundle Contract](./mirror-bundle.md) - Bundle format for air-gap
|
||||
- [Risk Scoring Contract](./risk-scoring.md) - Score digest in exports
|
||||
Reference in New Issue
Block a user