- Introduced AGENTS.md, README.md, TASKS.md, and implementation_plan.md for Vexer, detailing mission, responsibilities, key components, and operational notes. - Established similar documentation structure for Vulnerability Explorer and Zastava modules, including their respective workflows, integrations, and observability notes. - Created risk scoring profiles documentation outlining the core workflow, factor model, governance, and deliverables. - Ensured all modules adhere to the Aggregation-Only Contract and maintain determinism and provenance in outputs.
		
			
				
	
	
	
		
			8.2 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	architecture_excititor_mirrors.md — Excititor Mirror Distribution
Status: Draft (Sprint 7). Complements
docs/modules/excititor/architecture.mdby describing the mirror export surface exposed byExcititor.WebServiceand the configuration hooks used by operators and downstream mirrors.
0) Purpose
Excititor publishes canonical VEX consensus data. Operators (or StellaOps-managed mirrors) need a deterministic way to sync those exports into downstream environments. Mirror distribution provides:
- A declarative map of export bundles (json,jsonl,openvex,csaf) reachable via signed HTTP endpoints under/excititor/mirror.
- Thin quota/authentication controls on top of the existing export cache so mirrors cannot starve the web service.
- Stable payload shapes that downstream automation can monitor (index → fetch updates → download artifact → verify signature).
Mirror endpoints are intentionally read-only. Write paths (export generation, attestation, cache) remain the responsibility of the export pipeline.
1) Configuration model
The web service reads mirror configuration from Excititor:Mirror (YAML/JSON/appsettings). Each domain groups a set of exports that share rate limits and authentication rules.
Excititor:
  Mirror:
    Domains:
      - id: primary
        displayName: Primary Mirror
        requireAuthentication: false
        maxIndexRequestsPerHour: 600
        maxDownloadRequestsPerHour: 1200
        exports:
          - key: consensus
            format: json
            filters:
              vulnId: CVE-2025-0001
              productKey: pkg:test/demo
            sort:
              createdAt: false     # descending
            limit: 1000
          - key: consensus-openvex
            format: openvex
            filters:
              vulnId: CVE-2025-0001
Root settings
| Field | Required | Description | 
|---|---|---|
| outputRoot | – | Filesystem root where mirror artefacts are written. Defaults to the Excititor file-system artifact store root when omitted. | 
| directoryName | – | Optional subdirectory created under outputRoot; defaults tomirror. | 
| targetRepository | – | Hint propagated to manifests/index files indicating the operator-visible location (for example s3://mirror/excititor). | 
| signing | – | Bundle signing configuration. When enabled, the exporter emits a detached JWS ( bundle.json.jws) alongside each domain bundle. | 
signing supports the following fields:
| Field | Required | Description | 
|---|---|---|
| enabled | – | Toggles detached signing for domain bundles. | 
| algorithm | – | Signing algorithm identifier (default ES256). | 
| keyId | ✅ (when enabled) | Signing key identifier resolved via the configured crypto provider registry. | 
| provider | – | Optional provider hint when multiple registries are available. | 
| keyPath | – | Optional PEM path used to seed the provider when the key is not already loaded. | 
Domain field reference
| Field | Required | Description | 
|---|---|---|
| id | ✅ | Stable identifier. Appears in URLs ( /excititor/mirror/domains/{id}) and download filenames. | 
| displayName | – | Human-friendly label surfaced in the /domainslisting. Falls back toid. | 
| requireAuthentication | – | When truethe service enforces that the caller is authenticated (Authority token). | 
| maxIndexRequestsPerHour | – | Per-domain quota for index endpoints. 0/negative disables the guard. | 
| maxDownloadRequestsPerHour | – | Per-domain quota for artifact downloads. | 
| exports | ✅ | Collection of export projections. | 
Export-level fields:
| Field | Required | Description | 
|---|---|---|
| key | ✅ | Unique key within the domain. Used in URLs ( /exports/{key}) and filenames/bundle entries. | 
| format | ✅ | One of json,jsonl,openvex,csaf. Maps toVexExportFormat. | 
| filters | – | Key/value pairs executed via VexQueryFilter. Keys must match export data source columns (e.g.,vulnId,productKey). | 
| sort | – | Key/boolean map (false = descending). | 
| limit,offset,view | – | Optional query bounds passed through to the export query. | 
⚠️ Misconfiguration: invalid formats or missing keys cause exports to be flagged with status in the index response; they are not exposed downstream.
2) HTTP surface
Routes are grouped under /excititor/mirror.
| Method | Path | Description | 
|---|---|---|
| GET | /domains | Returns configured domains with quota metadata. | 
| GET | /domains/{domainId} | Domain detail (auth/quota + export keys). 404for unknown domains. | 
| GET | /domains/{domainId}/index | Lists exports with exportId, query signature, format, artifact digest, attestation metadata, and size. Applies index quota. | 
| GET | /domains/{domainId}/exports/{exportKey} | Returns manifest metadata (single export). 404if unknown/missing. | 
| GET | /domains/{domainId}/exports/{exportKey}/download | Streams export content from the artifact store. Applies download quota. | 
Responses are serialized via VexCanonicalJsonSerializer ensuring stable ordering. Download responses include a content-disposition header naming the file <domain>-<export>.<ext>.
Error handling
- 401– authentication required (- requireAuthentication=true).
- 404– domain/export not found or manifest not persisted.
- 429– per-domain quota exceeded (- Retry-Afterheader set in seconds).
- 503– export misconfiguration (invalid format/query).
3) Rate limiting
MirrorRateLimiter implements a simple rolling 1-hour window using IMemoryCache. Each domain has two quotas:
- indexscope →- maxIndexRequestsPerHour
- downloadscope →- maxDownloadRequestsPerHour
0 or negative limits disable enforcement. Quotas are best-effort (per-instance). For HA deployments, configure sticky routing at the ingress or replace the limiter with a distributed implementation.
4) Interaction with export pipeline
Mirror endpoints consume manifests produced by the export engine (MongoVexExportStore). They do not trigger new exports. Operators must configure connectors/exporters to keep targeted exports fresh (see EXCITITOR-EXPORT-01-005/006/007).
Recommended workflow:
- Define export plans at the export layer (JSON/OpenVEX/CSAF).
- Configure mirror domains mapping to those plans.
- Downstream mirror automation:
- GET /domains/{id}/index
- Compare exportId/consensusRevision
- GET /downloadwhen new
- Verify digest + attestation
 
When the export engine runs, it materializes the following artefacts under outputRoot/<directoryName>:
- index.json– canonical index listing each configured domain, manifest/bundle descriptors (with SHA-256 digests), and available export keys.
- <domain>/manifest.json– per-domain summary with export metadata (query signature, consensus/score digests, source providers) and a descriptor pointing at the bundle.
- <domain>/bundle.json– canonical payload containing serialized consensus, score envelopes, and normalized VEX claims for the matching export definitions.
- <domain>/bundle.json.jws– optional detached JWS when signing is enabled.
Downstream automation reads manifest.json/bundle.json directly, while /excititor/mirror endpoints stream the same artefacts through authenticated HTTP.
5) Operational guidance
- Track quota utilisation via HTTP 429 metrics (configure structured logging or OTEL counters when rate limiting triggers).
- Mirror domains can be deployed per tenant (e.g., tenant-a,tenant-b) with different auth requirements.
- Ensure the underlying artifact stores (FileSystem,S3, offline bundle) retain artefacts long enough for mirrors to sync.
- For air-gapped mirrors, combine mirror endpoints with the Offline Kit (see docs/24_OFFLINE_KIT.md).
6) Future alignment
- Replace manual export definitions with generated mirror bundle manifests once EXCITITOR-EXPORT-01-007ships.
- Extend /indexpayload with quiet-provenance whenEXCITITOR-EXPORT-01-006adds that metadata.
- Integrate domain manifests with DevOps mirror profiles (DEVOPS-MIRROR-08-001) so helm/compose overlays can enable or disable domains declaratively.