test fixes and new product advisories work
This commit is contained in:
@@ -191,6 +191,85 @@ stellaops alert bundle verify --file ./bundles/alert-123.stella.bundle.tgz
|
||||
stellaops alert bundle import --file ./bundles/alert-123.stella.bundle.tgz
|
||||
```
|
||||
|
||||
## OCI Referrer Artifacts
|
||||
|
||||
Mirror bundles automatically include OCI referrer artifacts (SBOMs, attestations, signatures) discovered from container registries. These artifacts are stored under a dedicated `referrers/` directory keyed by subject image digest.
|
||||
|
||||
### Referrer Directory Structure
|
||||
|
||||
```
|
||||
bundle.stella.bundle.tgz
|
||||
├── ...existing structure...
|
||||
├── referrers/
|
||||
│ └── sha256-abc123.../ # Subject image digest
|
||||
│ ├── sha256-def456.json # CycloneDX SBOM
|
||||
│ ├── sha256-ghi789.json # in-toto attestation
|
||||
│ └── sha256-jkl012.json # VEX statement
|
||||
└── indexes/
|
||||
├── referrers.index.json # Referrer artifact index
|
||||
└── attestations.index.json # Attestation cross-reference
|
||||
```
|
||||
|
||||
### Manifest Referrers Section
|
||||
|
||||
The bundle manifest includes a `referrers` section documenting all discovered artifacts:
|
||||
|
||||
```yaml
|
||||
referrers:
|
||||
subjects:
|
||||
- subject: "sha256:abc123..."
|
||||
artifacts:
|
||||
- digest: "sha256:def456..."
|
||||
artifactType: "application/vnd.cyclonedx+json"
|
||||
mediaType: "application/vnd.oci.image.manifest.v1+json"
|
||||
size: 12345
|
||||
path: "referrers/sha256-abc123.../sha256-def456.json"
|
||||
sha256: "def456789..."
|
||||
category: "sbom"
|
||||
annotations:
|
||||
org.opencontainers.image.created: "2026-01-27T10:00:00Z"
|
||||
- digest: "sha256:ghi789..."
|
||||
artifactType: "application/vnd.in-toto+json"
|
||||
mediaType: "application/vnd.oci.image.manifest.v1+json"
|
||||
size: 8192
|
||||
path: "referrers/sha256-abc123.../sha256-ghi789.json"
|
||||
sha256: "ghi789abc..."
|
||||
category: "attestation"
|
||||
```
|
||||
|
||||
### Referrer Validation
|
||||
|
||||
The `ImportValidator` verifies referrer artifacts during bundle import:
|
||||
|
||||
| Validation | Severity | Description |
|
||||
|------------|----------|-------------|
|
||||
| `ReferrerMissing` | Error | Declared artifact not found in bundle |
|
||||
| `ReferrerChecksumMismatch` | Error | SHA-256 doesn't match declared value |
|
||||
| `ReferrerSizeMismatch` | Error | Size doesn't match declared value |
|
||||
| `OrphanedReferrer` | Warning | File exists in `referrers/` but not declared |
|
||||
|
||||
### Artifact Types
|
||||
|
||||
| Artifact Type | Category | Description |
|
||||
|---------------|----------|-------------|
|
||||
| `application/vnd.cyclonedx+json` | `sbom` | CycloneDX SBOM |
|
||||
| `application/vnd.spdx+json` | `sbom` | SPDX SBOM |
|
||||
| `application/vnd.openvex+json` | `vex` | OpenVEX statement |
|
||||
| `application/vnd.csaf+json` | `vex` | CSAF advisory |
|
||||
| `application/vnd.in-toto+json` | `attestation` | in-toto attestation |
|
||||
| `application/vnd.dsse.envelope+json` | `attestation` | DSSE envelope |
|
||||
| `application/vnd.slsa.provenance+json` | `attestation` | SLSA provenance |
|
||||
| `application/vnd.stella.rva+json` | `attestation` | RVA attestation |
|
||||
|
||||
### Registry Compatibility
|
||||
|
||||
Referrer discovery supports both OCI 1.1 native API and fallback tag-based discovery:
|
||||
|
||||
- **OCI 1.1+**: Uses native `/v2/{repo}/referrers/{digest}` endpoint
|
||||
- **OCI 1.0 (fallback)**: Discovers via `sha256-{digest}.*` tag pattern
|
||||
|
||||
See [Registry Compatibility Matrix](../../export-center/registry-compatibility.md) for per-registry details.
|
||||
|
||||
## Function Map Artifacts
|
||||
|
||||
Bundles can include runtime linkage verification artifacts. These are stored in dedicated subdirectories:
|
||||
|
||||
308
docs/modules/doctor/architecture.md
Normal file
308
docs/modules/doctor/architecture.md
Normal file
@@ -0,0 +1,308 @@
|
||||
# Doctor Architecture
|
||||
|
||||
> Module: Doctor
|
||||
> Sprint: SPRINT_0127_001_0002_oci_registry_compatibility
|
||||
|
||||
Stella Doctor is a diagnostic framework for validating system health, configuration, and integration connectivity across the StellaOps platform.
|
||||
|
||||
## 1) Overview
|
||||
|
||||
Doctor provides a plugin-based diagnostic system that enables:
|
||||
- **Health checks** for all platform components
|
||||
- **Integration validation** for external systems (registries, SCM, CI, secrets)
|
||||
- **Configuration verification** before deployment
|
||||
- **Capability probing** for feature compatibility
|
||||
- **Evidence collection** for troubleshooting and compliance
|
||||
|
||||
## 2) Plugin Architecture
|
||||
|
||||
### Core Interfaces
|
||||
|
||||
```csharp
|
||||
public interface IDoctorPlugin
|
||||
{
|
||||
string PluginId { get; }
|
||||
string DisplayName { get; }
|
||||
string Category { get; }
|
||||
Version Version { get; }
|
||||
|
||||
IEnumerable<IDoctorCheck> GetChecks();
|
||||
Task InitializeAsync(DoctorPluginContext context, CancellationToken ct);
|
||||
}
|
||||
|
||||
public interface IDoctorCheck
|
||||
{
|
||||
string CheckId { get; }
|
||||
string Name { get; }
|
||||
string Description { get; }
|
||||
DoctorSeverity DefaultSeverity { get; }
|
||||
IReadOnlyList<string> Tags { get; }
|
||||
TimeSpan EstimatedDuration { get; }
|
||||
|
||||
bool CanRun(DoctorPluginContext context);
|
||||
Task<CheckResult> RunAsync(DoctorPluginContext context, CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
### Plugin Context
|
||||
|
||||
```csharp
|
||||
public sealed class DoctorPluginContext
|
||||
{
|
||||
public IServiceProvider Services { get; }
|
||||
public IConfiguration Configuration { get; }
|
||||
public TimeProvider TimeProvider { get; }
|
||||
public ILogger Logger { get; }
|
||||
public string EnvironmentName { get; }
|
||||
public IReadOnlyDictionary<string, object> PluginConfig { get; }
|
||||
}
|
||||
```
|
||||
|
||||
### Check Results
|
||||
|
||||
```csharp
|
||||
public sealed record CheckResult
|
||||
{
|
||||
public DoctorSeverity Severity { get; init; }
|
||||
public string Diagnosis { get; init; }
|
||||
public Evidence Evidence { get; init; }
|
||||
public IReadOnlyList<string> LikelyCauses { get; init; }
|
||||
public Remediation? Remediation { get; init; }
|
||||
public string? VerificationCommand { get; init; }
|
||||
}
|
||||
|
||||
public enum DoctorSeverity
|
||||
{
|
||||
Pass, // Check succeeded
|
||||
Info, // Informational (no action needed)
|
||||
Warn, // Warning (degraded but functional)
|
||||
Fail, // Failure (requires action)
|
||||
Skip // Check skipped (preconditions not met)
|
||||
}
|
||||
```
|
||||
|
||||
## 3) Built-in Plugins
|
||||
|
||||
### IntegrationPlugin
|
||||
|
||||
Validates external system connectivity and capabilities.
|
||||
|
||||
**Check Catalog:**
|
||||
|
||||
| Check ID | Name | Severity | Description |
|
||||
|----------|------|----------|-------------|
|
||||
| `check.integration.oci.credentials` | OCI Registry Credentials | Fail | Validate registry authentication |
|
||||
| `check.integration.oci.pull` | OCI Registry Pull Authorization | Fail | Verify pull permissions |
|
||||
| `check.integration.oci.push` | OCI Registry Push Authorization | Fail | Verify push permissions |
|
||||
| `check.integration.oci.referrers` | OCI Registry Referrers API | Warn | Check OCI 1.1 referrers support |
|
||||
| `check.integration.oci.capabilities` | OCI Registry Capability Matrix | Info | Probe all registry capabilities |
|
||||
|
||||
See [Registry Diagnostic Checks](./registry-checks.md) for detailed documentation.
|
||||
|
||||
### ConfigurationPlugin
|
||||
|
||||
Validates platform configuration.
|
||||
|
||||
| Check ID | Name | Severity | Description |
|
||||
|----------|------|----------|-------------|
|
||||
| `check.config.database` | Database Connection | Fail | Verify database connectivity |
|
||||
| `check.config.secrets` | Secrets Provider | Fail | Verify secrets access |
|
||||
| `check.config.tls` | TLS Configuration | Warn | Validate TLS certificates |
|
||||
|
||||
### HealthPlugin
|
||||
|
||||
Validates platform component health.
|
||||
|
||||
| Check ID | Name | Severity | Description |
|
||||
|----------|------|----------|-------------|
|
||||
| `check.health.api` | API Health | Fail | Verify API endpoints |
|
||||
| `check.health.worker` | Worker Health | Fail | Verify background workers |
|
||||
| `check.health.storage` | Storage Health | Fail | Verify storage backends |
|
||||
|
||||
## 4) Check Patterns
|
||||
|
||||
### Non-Destructive Probing
|
||||
|
||||
Registry checks use non-destructive operations:
|
||||
|
||||
```csharp
|
||||
// Pull check: HEAD request only (no data transfer)
|
||||
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, manifestUrl), ct);
|
||||
|
||||
// Push check: Start upload then immediately cancel
|
||||
var uploadResponse = await client.PostAsync(uploadsUrl, null, ct);
|
||||
if (uploadResponse.StatusCode == HttpStatusCode.Accepted)
|
||||
{
|
||||
var location = uploadResponse.Headers.Location;
|
||||
await client.DeleteAsync(location, ct); // Cancel upload
|
||||
}
|
||||
```
|
||||
|
||||
### Capability Detection
|
||||
|
||||
Registry capability probing sequence:
|
||||
|
||||
```
|
||||
1. GET /v2/ → Extract OCI-Distribution-API-Version header
|
||||
2. GET /v2/{repo}/referrers/{digest} → Check referrers API support
|
||||
3. POST /v2/{repo}/blobs/uploads/ → Check chunked upload support
|
||||
└─ DELETE {location} → Cancel upload session
|
||||
4. POST /v2/{repo}/blobs/uploads/?mount=...&from=... → Check cross-repo mount
|
||||
5. OPTIONS /v2/{repo}/manifests/{ref} → Check delete support (Allow header)
|
||||
6. OPTIONS /v2/{repo}/blobs/{digest} → Check blob delete support
|
||||
```
|
||||
|
||||
### Evidence Collection
|
||||
|
||||
All checks collect structured evidence:
|
||||
|
||||
```csharp
|
||||
var result = CheckResultBuilder.Create(check)
|
||||
.Pass("Registry authentication successful")
|
||||
.WithEvidence(eb => eb
|
||||
.Add("registry_url", registryUrl)
|
||||
.Add("auth_method", "bearer")
|
||||
.Add("response_time_ms", elapsed.TotalMilliseconds.ToString("F0"))
|
||||
.AddSensitive("token_preview", RedactToken(token)))
|
||||
.Build();
|
||||
```
|
||||
|
||||
### Credential Redaction
|
||||
|
||||
Sensitive values are automatically redacted:
|
||||
|
||||
```csharp
|
||||
// Redact to first 2 + last 2 characters
|
||||
private static string Redact(string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value) || value.Length <= 4)
|
||||
return "****";
|
||||
return $"{value[..2]}...{value[^2..]}";
|
||||
}
|
||||
// "mysecretpassword" → "my...rd"
|
||||
```
|
||||
|
||||
## 5) CLI Integration
|
||||
|
||||
```bash
|
||||
# Run all checks
|
||||
stella doctor
|
||||
|
||||
# Run checks by tag
|
||||
stella doctor --tag registry
|
||||
stella doctor --tag configuration
|
||||
|
||||
# Run specific check
|
||||
stella doctor --check check.integration.oci.referrers
|
||||
|
||||
# Output formats
|
||||
stella doctor --format table # Default: human-readable
|
||||
stella doctor --format json # Machine-readable
|
||||
stella doctor --format sarif # SARIF for CI integration
|
||||
|
||||
# Verbosity
|
||||
stella doctor --verbose # Include evidence details
|
||||
stella doctor --quiet # Only show failures
|
||||
|
||||
# Filtering by severity
|
||||
stella doctor --min-severity warn # Skip info/pass
|
||||
```
|
||||
|
||||
## 6) Extensibility
|
||||
|
||||
### Creating a Custom Check
|
||||
|
||||
```csharp
|
||||
public sealed class MyCustomCheck : IDoctorCheck
|
||||
{
|
||||
public string CheckId => "check.custom.mycheck";
|
||||
public string Name => "My Custom Check";
|
||||
public string Description => "Validates custom integration";
|
||||
public DoctorSeverity DefaultSeverity => DoctorSeverity.Fail;
|
||||
public IReadOnlyList<string> Tags => ["custom", "integration"];
|
||||
public TimeSpan EstimatedDuration => TimeSpan.FromSeconds(5);
|
||||
|
||||
public bool CanRun(DoctorPluginContext context)
|
||||
{
|
||||
// Return false if preconditions not met
|
||||
return context.Configuration["Custom:Enabled"] == "true";
|
||||
}
|
||||
|
||||
public async Task<CheckResult> RunAsync(DoctorPluginContext context, CancellationToken ct)
|
||||
{
|
||||
var builder = CheckResultBuilder.Create(this);
|
||||
|
||||
try
|
||||
{
|
||||
// Perform check logic
|
||||
var result = await ValidateAsync(context, ct);
|
||||
|
||||
if (result.Success)
|
||||
{
|
||||
return builder
|
||||
.Pass("Custom validation successful")
|
||||
.WithEvidence(eb => eb.Add("detail", result.Detail))
|
||||
.Build();
|
||||
}
|
||||
|
||||
return builder
|
||||
.Fail("Custom validation failed")
|
||||
.WithLikelyCause("Configuration is invalid")
|
||||
.WithRemediation(rb => rb
|
||||
.AddManualStep(1, "Check configuration", "Verify Custom:Setting is correct")
|
||||
.WithRunbookUrl("https://docs.stella-ops.org/runbooks/custom-check"))
|
||||
.Build();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return builder
|
||||
.Fail($"Check failed with error: {ex.Message}")
|
||||
.WithEvidence(eb => eb.Add("exception_type", ex.GetType().Name))
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Creating a Custom Plugin
|
||||
|
||||
```csharp
|
||||
public sealed class MyCustomPlugin : IDoctorPlugin
|
||||
{
|
||||
public string PluginId => "custom";
|
||||
public string DisplayName => "Custom Checks";
|
||||
public string Category => "Integration";
|
||||
public Version Version => new(1, 0, 0);
|
||||
|
||||
public IEnumerable<IDoctorCheck> GetChecks()
|
||||
{
|
||||
yield return new MyCustomCheck();
|
||||
yield return new AnotherCustomCheck();
|
||||
}
|
||||
|
||||
public Task InitializeAsync(DoctorPluginContext context, CancellationToken ct)
|
||||
{
|
||||
// Optional initialization
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7) Telemetry
|
||||
|
||||
Doctor emits metrics and traces for observability:
|
||||
|
||||
**Metrics:**
|
||||
- `doctor_check_duration_seconds{check_id, severity}` - Check execution time
|
||||
- `doctor_check_results_total{check_id, severity}` - Result counts
|
||||
- `doctor_plugin_load_duration_seconds{plugin_id}` - Plugin initialization time
|
||||
|
||||
**Traces:**
|
||||
- `doctor.run` - Full doctor run span
|
||||
- `doctor.check.{check_id}` - Individual check spans with evidence as attributes
|
||||
|
||||
## 8) Related Documentation
|
||||
|
||||
- [Registry Diagnostic Checks](./registry-checks.md)
|
||||
- [Registry Compatibility Runbook](../../runbooks/registry-compatibility.md)
|
||||
- [Registry Referrer Troubleshooting](../../runbooks/registry-referrer-troubleshooting.md)
|
||||
366
docs/modules/doctor/registry-checks.md
Normal file
366
docs/modules/doctor/registry-checks.md
Normal file
@@ -0,0 +1,366 @@
|
||||
# Registry Diagnostic Checks
|
||||
|
||||
> Module: Doctor
|
||||
> Plugin: IntegrationPlugin
|
||||
> Sprint: SPRINT_0127_001_0002_oci_registry_compatibility
|
||||
|
||||
This document covers the OCI registry diagnostic checks available in Stella Doctor for validating registry connectivity, capabilities, and authorization.
|
||||
|
||||
## Overview
|
||||
|
||||
StellaOps Doctor includes comprehensive registry diagnostics to verify that configured OCI registries are properly accessible and support the features required for secure software supply chain operations. These checks are part of the `IntegrationPlugin` and can be run individually or as a group using the `registry` tag.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Run all registry checks
|
||||
stella doctor --tag registry
|
||||
|
||||
# Run a specific check
|
||||
stella doctor --check check.integration.oci.referrers
|
||||
|
||||
# Export results as JSON
|
||||
stella doctor --tag registry --format json --output registry-health.json
|
||||
|
||||
# Run with verbose output
|
||||
stella doctor --tag registry --verbose
|
||||
```
|
||||
|
||||
## Available Checks
|
||||
|
||||
### check.integration.oci.credentials
|
||||
|
||||
**Purpose:** Validate registry credential configuration and authentication.
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Name | OCI Registry Credentials |
|
||||
| Default Severity | Fail |
|
||||
| Tags | `registry`, `oci`, `credentials`, `secrets`, `auth` |
|
||||
| Estimated Duration | 5 seconds |
|
||||
|
||||
**What it checks:**
|
||||
1. Credential configuration (username/password, bearer token, or anonymous)
|
||||
2. Authentication against the `/v2/` endpoint
|
||||
3. OAuth2 token exchange for registries requiring it
|
||||
4. Credential validity and format
|
||||
|
||||
**Evidence collected:**
|
||||
- `registry_url` - Target registry URL
|
||||
- `auth_method` - Authentication method (basic, bearer, anonymous)
|
||||
- `username` - Username (if configured)
|
||||
- `credentials_valid` - Whether authentication succeeded
|
||||
- `auth_challenge` - WWW-Authenticate header if present
|
||||
|
||||
**Pass criteria:**
|
||||
- Credentials are properly configured
|
||||
- Authentication succeeds against `/v2/` endpoint
|
||||
|
||||
**Fail scenarios:**
|
||||
- Missing required credentials (username without password)
|
||||
- Invalid credentials (401 Unauthorized)
|
||||
- Network or TLS errors
|
||||
|
||||
---
|
||||
|
||||
### check.integration.oci.pull
|
||||
|
||||
**Purpose:** Verify pull authorization for the configured test repository.
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Name | OCI Registry Pull Authorization |
|
||||
| Default Severity | Fail |
|
||||
| Tags | `registry`, `oci`, `pull`, `authorization` |
|
||||
| Estimated Duration | 5 seconds |
|
||||
|
||||
**What it checks:**
|
||||
1. HEAD request to manifest endpoint (non-destructive)
|
||||
2. Authorization for pull operations
|
||||
3. Image/tag existence
|
||||
|
||||
**Evidence collected:**
|
||||
- `registry_url` - Target registry URL
|
||||
- `test_repository` - Repository used for testing
|
||||
- `test_tag` - Tag used for testing
|
||||
- `pull_authorized` - Whether pull is authorized
|
||||
- `manifest_digest` - Manifest digest if successful
|
||||
- `http_status` - HTTP status code
|
||||
|
||||
**Pass criteria:**
|
||||
- HEAD request to manifest returns 200 OK
|
||||
- Manifest digest is returned
|
||||
|
||||
**Fail scenarios:**
|
||||
- 401 Unauthorized: Invalid credentials
|
||||
- 403 Forbidden: Valid credentials but no pull permission
|
||||
- Info (not fail) for 404: Test image not found (can't verify)
|
||||
|
||||
---
|
||||
|
||||
### check.integration.oci.push
|
||||
|
||||
**Purpose:** Verify push authorization for the configured test repository.
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Name | OCI Registry Push Authorization |
|
||||
| Default Severity | Fail |
|
||||
| Tags | `registry`, `oci`, `push`, `authorization` |
|
||||
| Estimated Duration | 10 seconds |
|
||||
|
||||
**What it checks:**
|
||||
1. Initiates blob upload via POST (non-destructive)
|
||||
2. Immediately cancels the upload session
|
||||
3. Verifies push authorization
|
||||
|
||||
**Evidence collected:**
|
||||
- `registry_url` - Target registry URL
|
||||
- `test_repository` - Repository used for testing
|
||||
- `push_authorized` - Whether push is authorized
|
||||
- `upload_session_cancelled` - Whether cleanup succeeded
|
||||
- `http_status` - HTTP status code
|
||||
- `credentials_valid` - Whether credentials are valid (for 403)
|
||||
|
||||
**Pass criteria:**
|
||||
- POST to blob uploads returns 202 Accepted
|
||||
- Upload session is successfully cancelled
|
||||
|
||||
**Fail scenarios:**
|
||||
- 401 Unauthorized: Invalid credentials
|
||||
- 403 Forbidden: Valid credentials but no push permission
|
||||
|
||||
**Non-destructive design:**
|
||||
This check initiates a blob upload session but immediately cancels it via DELETE. No data is actually pushed to the registry.
|
||||
|
||||
---
|
||||
|
||||
### check.integration.oci.referrers
|
||||
|
||||
**Purpose:** Verify OCI 1.1 referrers API support for artifact linking.
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Name | OCI Registry Referrers API Support |
|
||||
| Default Severity | Warn |
|
||||
| Tags | `registry`, `oci`, `referrers`, `oci-1.1` |
|
||||
| Estimated Duration | 10 seconds |
|
||||
|
||||
**What it checks:**
|
||||
1. Resolves manifest digest for test image
|
||||
2. Probes the referrers API endpoint
|
||||
3. Determines if native API or fallback is required
|
||||
|
||||
**Evidence collected:**
|
||||
- `registry_url` - Target registry URL
|
||||
- `referrers_supported` - Whether referrers API is supported
|
||||
- `fallback_required` - Whether tag-based fallback is needed
|
||||
- `oci_version` - OCI-Distribution-API-Version header
|
||||
- `referrers_count` - Number of referrers found (if any)
|
||||
|
||||
**Pass criteria:**
|
||||
- Referrers endpoint returns 200 OK with OCI index
|
||||
- Or returns 404 with OCI index content (empty referrers)
|
||||
|
||||
**Warn scenarios (not Fail):**
|
||||
- 404 without OCI index: API not supported, fallback required
|
||||
- 405 Method Not Allowed: API not implemented
|
||||
|
||||
The severity is Warn (not Fail) because StellaOps automatically uses tag-based fallback discovery when the referrers API is unavailable.
|
||||
|
||||
---
|
||||
|
||||
### check.integration.oci.capabilities
|
||||
|
||||
**Purpose:** Comprehensive registry capability matrix detection.
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Name | OCI Registry Capability Matrix |
|
||||
| Default Severity | Info |
|
||||
| Tags | `registry`, `oci`, `capabilities`, `compatibility` |
|
||||
| Estimated Duration | 30 seconds |
|
||||
|
||||
**What it checks:**
|
||||
1. OCI Distribution version (via headers)
|
||||
2. Referrers API support
|
||||
3. Chunked upload support
|
||||
4. Cross-repository blob mounting
|
||||
5. Manifest delete support
|
||||
6. Blob delete support
|
||||
|
||||
**Evidence collected:**
|
||||
- `registry_url` - Target registry URL
|
||||
- `distribution_version` - OCI/Docker distribution version
|
||||
- `supports_referrers_api` - true/false/unknown
|
||||
- `supports_chunked_upload` - true/false/unknown
|
||||
- `supports_cross_repo_mount` - true/false/unknown
|
||||
- `supports_manifest_delete` - true/false/unknown
|
||||
- `supports_blob_delete` - true/false/unknown
|
||||
- `capability_score` - Summary (e.g., "5/6")
|
||||
|
||||
**Severity logic:**
|
||||
- Pass: All capabilities supported
|
||||
- Info: Some non-critical capabilities missing
|
||||
- Warn: Referrers API not supported (critical for StellaOps)
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Registry checks use the following configuration keys:
|
||||
|
||||
```yaml
|
||||
OCI:
|
||||
RegistryUrl: "https://registry.example.com"
|
||||
Username: "service-account"
|
||||
Password: "secret" # Or use PasswordSecretRef
|
||||
Token: "bearer-token" # Alternative to username/password
|
||||
TestRepository: "stellaops/test" # Default: library/alpine
|
||||
TestTag: "latest" # Default: latest
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
export OCI__RegistryUrl="https://registry.example.com"
|
||||
export OCI__Username="service-account"
|
||||
export OCI__Password="secret"
|
||||
export OCI__TestRepository="stellaops/test"
|
||||
export OCI__TestTag="latest"
|
||||
```
|
||||
|
||||
## Registry Compatibility Matrix
|
||||
|
||||
| Registry | Version | Referrers API | Chunked Upload | Cross-Mount | Delete | Recommended |
|
||||
|----------|---------|---------------|----------------|-------------|--------|-------------|
|
||||
| **ACR** | Any | Native | Yes | Yes | Yes | Yes |
|
||||
| **ECR** | Any | Native | Yes | Yes | Yes | Yes |
|
||||
| **GCR/Artifact Registry** | Any | Native | Yes | Yes | Yes | Yes |
|
||||
| **Harbor** | 2.6+ | Native | Yes | Yes | Yes | Yes |
|
||||
| **Quay** | 3.12+ | Native | Yes | Yes | Yes | Yes |
|
||||
| **JFrog Artifactory** | 7.x+ | Native | Yes | Yes | Yes | Yes |
|
||||
| **GHCR** | Any | Fallback | Yes | Yes | Yes | With fallback |
|
||||
| **Docker Hub** | Any | Fallback | Yes | Limited | Limited | With fallback |
|
||||
| **registry:2** | 2.8+ | Fallback | Yes | Yes | Yes | For testing |
|
||||
| **Zot** | Any | Native | Yes | Yes | Yes | Yes |
|
||||
| **Distribution** | Edge | Partial | Yes | Yes | Yes | Yes |
|
||||
|
||||
### Legend
|
||||
- **Native**: Full OCI 1.1 referrers API support
|
||||
- **Fallback**: Requires tag-based discovery (`sha256-{digest}.*` tags)
|
||||
- **Partial**: Support varies by configuration
|
||||
|
||||
## Known Issues & Workarounds
|
||||
|
||||
### GHCR (GitHub Container Registry)
|
||||
|
||||
**Issue:** Referrers API not implemented (returns 404 without OCI index)
|
||||
|
||||
**Impact:** Slower artifact discovery, requires tag-based fallback
|
||||
|
||||
**Workaround:** StellaOps automatically detects this and uses fallback discovery. No action required.
|
||||
|
||||
**Tracking:** GitHub feature request pending
|
||||
|
||||
### Docker Hub
|
||||
|
||||
**Issue:** Rate limiting can affect capability probes
|
||||
|
||||
**Impact:** Probes may timeout or return 429
|
||||
|
||||
**Workaround:**
|
||||
- Use authenticated requests to increase rate limits
|
||||
- Configure retry with exponential backoff
|
||||
- Consider using a pull-through cache
|
||||
|
||||
### Harbor < 2.6
|
||||
|
||||
**Issue:** Referrers API not available in older versions
|
||||
|
||||
**Impact:** Requires tag-based fallback
|
||||
|
||||
**Workaround:** Upgrade to Harbor 2.6+ for native referrers API support
|
||||
|
||||
### ACR with CMK Encryption
|
||||
|
||||
**Issue:** Customer-managed key encrypted registries may use tag fallback
|
||||
|
||||
**Impact:** Slightly slower referrer discovery
|
||||
|
||||
**Workaround:** Automatic fallback detection handles this transparently
|
||||
|
||||
**Reference:** [Azure Container Registry CMK Documentation](https://learn.microsoft.com/azure/container-registry/)
|
||||
|
||||
## Interpreting Results
|
||||
|
||||
### Healthy Registry Output
|
||||
|
||||
```
|
||||
Registry Checks Summary
|
||||
=======================
|
||||
|
||||
check.integration.oci.credentials PASS Credentials valid for registry.example.com
|
||||
check.integration.oci.pull PASS Pull authorized (sha256:abc123...)
|
||||
check.integration.oci.push PASS Push authorization verified
|
||||
check.integration.oci.referrers PASS Referrers API supported (OCI 1.1)
|
||||
check.integration.oci.capabilities PASS Full capability support (6/6)
|
||||
|
||||
Overall: 5 passed, 0 warnings, 0 failures
|
||||
```
|
||||
|
||||
### Registry with Fallback Required
|
||||
|
||||
```
|
||||
Registry Checks Summary
|
||||
=======================
|
||||
|
||||
check.integration.oci.credentials PASS Credentials valid for ghcr.io
|
||||
check.integration.oci.pull PASS Pull authorized (sha256:def456...)
|
||||
check.integration.oci.push PASS Push authorization verified
|
||||
check.integration.oci.referrers WARN Referrers API not supported (using fallback)
|
||||
check.integration.oci.capabilities INFO Partial capability support (4/6)
|
||||
|
||||
Overall: 3 passed, 1 warning, 1 info, 0 failures
|
||||
|
||||
Recommendations:
|
||||
- Referrers API: StellaOps will use tag-based fallback automatically
|
||||
- Consider upgrading to a registry with OCI 1.1 support for better performance
|
||||
```
|
||||
|
||||
## Remediation Steps
|
||||
|
||||
### Invalid Credentials (401)
|
||||
|
||||
1. Verify username and password are correct
|
||||
2. Check if credentials have expired
|
||||
3. For OAuth2 registries, ensure token refresh is working
|
||||
4. Test with docker CLI: `docker login <registry>`
|
||||
|
||||
### No Permission (403)
|
||||
|
||||
1. Verify the service account has required permissions
|
||||
2. For pull: Reader/Viewer role is typically sufficient
|
||||
3. For push: Contributor/Writer role is required
|
||||
4. Check repository-level permissions (some registries have repo-specific ACLs)
|
||||
|
||||
### Referrers API Not Supported
|
||||
|
||||
1. Check registry version against compatibility matrix
|
||||
2. Upgrade registry if possible (Harbor 2.6+, Quay 3.12+)
|
||||
3. If upgrade not possible, StellaOps will use fallback automatically
|
||||
4. Monitor for performance impact with large artifact counts
|
||||
|
||||
### Network/TLS Errors
|
||||
|
||||
1. Verify network connectivity: `curl -v https://<registry>/v2/`
|
||||
2. Check TLS certificate validity
|
||||
3. For self-signed certs, configure trust or use `--insecure` (not recommended for production)
|
||||
4. Check firewall rules and proxy configuration
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Registry Compatibility Quick Reference](../../runbooks/registry-compatibility.md)
|
||||
- [Registry Referrer Troubleshooting](../../runbooks/registry-referrer-troubleshooting.md)
|
||||
- [Export Center Registry Compatibility](../export-center/registry-compatibility.md)
|
||||
- [Doctor Architecture](./architecture.md)
|
||||
@@ -82,8 +82,8 @@ All endpoints require Authority-issued JWT + DPoP tokens with scopes `export:run
|
||||
|
||||
Audit bundles are a specialized Export Center output: a deterministic, immutable evidence pack for a single subject (and optional time window) suitable for audits and incident response.
|
||||
|
||||
- **Schema**: `docs/modules/evidence-locker/schemas/audit-bundle-index.schema.json` (bundle index/manifest with integrity hashes and referenced artefacts).
|
||||
- The index must list Rekor entry ids and RFC3161 timestamp tokens when present; offline bundles record skip reasons in predicates.
|
||||
- **Schema**: `docs/modules/evidence-locker/schemas/audit-bundle-index.schema.json` (bundle index/manifest with integrity hashes and referenced artefacts).
|
||||
- The index must list Rekor entry ids and RFC3161 timestamp tokens when present; offline bundles record skip reasons in predicates.
|
||||
- **Core APIs**:
|
||||
- `POST /v1/audit-bundles` - Create a new bundle (async generation).
|
||||
- `GET /v1/audit-bundles` - List previously created bundles.
|
||||
@@ -117,6 +117,78 @@ Adapters expose structured telemetry events (`adapter.start`, `adapter.chunk`, `
|
||||
- **Attestation.** Cosign SLSA Level 2 template by default; optional SLSA Level 3 when supply chain attestations are enabled. Detached signatures stored alongside manifests; CLI/Console encourage `cosign verify --key <tenant-key>` workflow.
|
||||
- **Audit trail.** Each run stores success/failure status, signature identifiers, and verification hints for downstream automation (CI pipelines, offline verification scripts).
|
||||
|
||||
## OCI Referrer Discovery
|
||||
|
||||
Mirror bundles automatically discover and include OCI referrer artifacts (SBOMs, attestations, signatures, VEX statements) linked to container images via the OCI 1.1 referrers API.
|
||||
|
||||
### Discovery Flow
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌───────────────────────┐ ┌─────────────────┐
|
||||
│ MirrorAdapter │────▶│ IReferrerDiscovery │────▶│ OCI Registry │
|
||||
│ │ │ Service │ │ │
|
||||
│ 1. Detect │ │ 2. Probe registry │ │ 3. Query │
|
||||
│ images │ │ capabilities │ │ referrers │
|
||||
│ │ │ │ │ API │
|
||||
└─────────────────┘ └───────────────────────┘ └─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
│ Fallback: Tag-based │
|
||||
│ discovery for older │
|
||||
│ registries (GHCR) │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
### Capability Probing
|
||||
|
||||
Before starting referrer discovery, the export flow probes each unique registry to determine capabilities:
|
||||
|
||||
- **OCI 1.1+ registries**: Native referrers API (`/v2/{repo}/referrers/{digest}`)
|
||||
- **OCI 1.0 registries**: Fallback to tag-based discovery (`sha256-{digest}.*` tags)
|
||||
|
||||
Capabilities are cached per registry host with a 1-hour TTL.
|
||||
|
||||
**Logging at export start:**
|
||||
```
|
||||
[INFO] Probing 3 registries for OCI referrer capabilities before export
|
||||
[INFO] Registry registry.example.com: OCI 1.1 (referrers API supported, version=OCI-Distribution/2.1, probe_ms=42)
|
||||
[WARN] Registry ghcr.io: OCI 1.0 (using fallback tag discovery, version=registry/2.0, probe_ms=85)
|
||||
```
|
||||
|
||||
### Telemetry Metrics
|
||||
|
||||
| Metric | Description | Tags |
|
||||
|--------|-------------|------|
|
||||
| `export_registry_capabilities_probed_total` | Registry capability probe operations | `registry`, `api_supported` |
|
||||
| `export_referrer_discovery_method_total` | Discovery operations by method | `registry`, `method` (native/fallback) |
|
||||
| `export_referrers_discovered_total` | Referrers discovered | `registry`, `artifact_type` |
|
||||
| `export_referrer_discovery_failures_total` | Discovery failures | `registry`, `error_type` |
|
||||
|
||||
### Artifact Type Mapping
|
||||
|
||||
| OCI Artifact Type | Bundle Category | Example |
|
||||
|-------------------|-----------------|---------|
|
||||
| `application/vnd.cyclonedx+json` | `sbom` | CycloneDX SBOM |
|
||||
| `application/vnd.spdx+json` | `sbom` | SPDX SBOM |
|
||||
| `application/vnd.openvex+json` | `vex` | OpenVEX statement |
|
||||
| `application/vnd.csaf+json` | `vex` | CSAF document |
|
||||
| `application/vnd.in-toto+json` | `attestation` | in-toto attestation |
|
||||
| `application/vnd.dsse.envelope+json` | `attestation` | DSSE envelope |
|
||||
| `application/vnd.slsa.provenance+json` | `attestation` | SLSA provenance |
|
||||
|
||||
### Error Handling
|
||||
|
||||
- If referrer discovery fails for a single image, the export logs a warning and continues with other images
|
||||
- Network failures do not block the entire export
|
||||
- Missing referrer artifacts are validated during bundle import (see [ImportValidator](../airgap/guides/offline-bundle-format.md))
|
||||
|
||||
### Related Documentation
|
||||
|
||||
- [Registry Compatibility Matrix](registry-compatibility.md)
|
||||
- [Offline Bundle Format](../airgap/guides/offline-bundle-format.md#oci-referrer-artifacts)
|
||||
- [Registry Referrer Troubleshooting](../../runbooks/registry-referrer-troubleshooting.md)
|
||||
|
||||
## Distribution flows
|
||||
- **HTTP download.** Console and CLI stream bundles via chunked transfer; supports range requests and resumable downloads. Response includes `X-Export-Digest`, `X-Export-Length`, and optional encryption metadata.
|
||||
- **OCI push.** Worker uses ORAS to publish bundles as OCI artefacts with annotations describing profile, tenant, manifest digest, and provenance reference. Supports multi-tenant registries with `repository-per-tenant` naming.
|
||||
|
||||
152
docs/modules/export-center/registry-compatibility.md
Normal file
152
docs/modules/export-center/registry-compatibility.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Registry Compatibility Matrix
|
||||
|
||||
> Sprint: SPRINT_0127_001_0001_oci_referrer_bundle_export
|
||||
> Module: ExportCenter
|
||||
|
||||
This document provides detailed compatibility information for OCI referrer discovery across container registries.
|
||||
|
||||
## OCI 1.1 Referrers API Support
|
||||
|
||||
The OCI Distribution Spec v1.1 introduced the native referrers API (), which enables efficient discovery of artifacts linked to container images. Not all registries support this API yet.
|
||||
|
||||
### Support Matrix
|
||||
|
||||
| Registry | OCI 1.1 API | Fallback Tags | Artifact Type Filter | Notes |
|
||||
|----------|-------------|---------------|---------------------|-------|
|
||||
| **Docker Hub** | Partial | Yes | Limited | Rate limits may affect discovery; partial OCI 1.1 support |
|
||||
| **GitHub Container Registry (GHCR)** | No | Yes | N/A | Uses tag-based discovery |
|
||||
| **Google Container Registry (GCR)** | Yes | Yes | Yes | Full OCI 1.1 support |
|
||||
| **Google Artifact Registry** | Yes | Yes | Yes | Full OCI 1.1 support |
|
||||
| **Amazon ECR** | Yes | Yes | Yes | Requires proper IAM permissions for referrer operations |
|
||||
| **Azure Container Registry (ACR)** | Yes | Yes | Yes | Full OCI 1.1 support |
|
||||
| **Harbor 2.0+** | Yes | Yes | Yes | Full OCI 1.1 support; older versions require fallback |
|
||||
| **Harbor 1.x** | No | Yes | N/A | Fallback only |
|
||||
| **Quay.io** | Partial | Yes | Limited | Support varies by version and configuration |
|
||||
| **JFrog Artifactory** | Partial | Yes | Limited | Requires OCI layout repository type |
|
||||
| **Zot** | Yes | Yes | Yes | Full OCI 1.1 support |
|
||||
| **Distribution (registry:2)** | No | Yes | N/A | Reference implementation without referrers API |
|
||||
|
||||
### Legend
|
||||
|
||||
- **OCI 1.1 API**: Native support for endpoint
|
||||
- **Fallback Tags**: Support for tag-schema discovery pattern ()
|
||||
- **Artifact Type Filter**: Support for query parameter
|
||||
|
||||
## Per-Registry Details
|
||||
|
||||
### Docker Hub
|
||||
|
||||
- **API Support**: Partial OCI 1.1 support
|
||||
- **Fallback**: Yes, via tag-based discovery
|
||||
- **Authentication**: Bearer token via Docker Hub auth service
|
||||
- **Rate Limits**: 100 pulls/6 hours (anonymous), 200 pulls/6 hours (authenticated)
|
||||
- **Known Issues**:
|
||||
- Rate limiting can affect large bundle exports
|
||||
- Some artifact types may not be discoverable via native API
|
||||
|
||||
### GitHub Container Registry (GHCR)
|
||||
|
||||
- **API Support**: No native referrers API
|
||||
- **Fallback**: Yes, required for all referrer discovery
|
||||
- **Authentication**: GitHub PAT or GITHUB_TOKEN with scope
|
||||
- **Rate Limits**: GitHub API rate limits apply
|
||||
- **Known Issues**:
|
||||
- Referrers must be pushed using tag-schema pattern
|
||||
- Artifact types embedded in tag suffix (e.g., , , )
|
||||
|
||||
### Google Container Registry / Artifact Registry
|
||||
|
||||
- **API Support**: Full OCI 1.1 support
|
||||
- **Fallback**: Yes, as backup
|
||||
- **Authentication**: Google Cloud service account or gcloud auth
|
||||
- **Rate Limits**: Generous; project quotas apply
|
||||
- **Known Issues**: None significant
|
||||
|
||||
### Amazon Elastic Container Registry (ECR)
|
||||
|
||||
- **API Support**: Full OCI 1.1 support
|
||||
- **Fallback**: Yes, as backup
|
||||
- **Authentication**: IAM role or access keys via
|
||||
- **Rate Limits**: 1000 requests/second per region
|
||||
- **Known Issues**:
|
||||
- Requires IAM permissions for OCI operations
|
||||
- Cross-account referrer discovery needs proper IAM policies
|
||||
|
||||
### Azure Container Registry (ACR)
|
||||
|
||||
- **API Support**: Full OCI 1.1 support
|
||||
- **Fallback**: Yes, as backup
|
||||
- **Authentication**: Azure AD service principal or managed identity
|
||||
- **Rate Limits**: Tier-dependent (Basic: 1000 reads/min, Standard: 3000, Premium: 10000)
|
||||
- **Known Issues**: None significant
|
||||
|
||||
### Harbor
|
||||
|
||||
- **API Support**: Full OCI 1.1 support in Harbor 2.0+
|
||||
- **Fallback**: Yes
|
||||
- **Authentication**: Harbor user credentials or robot account
|
||||
- **Rate Limits**: Configurable at server level
|
||||
- **Known Issues**:
|
||||
- Harbor 1.x does not support referrers API
|
||||
- Project-level permissions required
|
||||
|
||||
### Quay.io / Red Hat Quay
|
||||
|
||||
- **API Support**: Partial (version-dependent)
|
||||
- **Fallback**: Yes
|
||||
- **Authentication**: Robot account or OAuth token
|
||||
- **Rate Limits**: Account tier dependent
|
||||
- **Known Issues**:
|
||||
- Support varies significantly by version
|
||||
- Some deployments may have referrers API disabled
|
||||
|
||||
### JFrog Artifactory
|
||||
|
||||
- **API Support**: Partial (requires OCI layout)
|
||||
- **Fallback**: Yes
|
||||
- **Authentication**: API key or access token
|
||||
- **Rate Limits**: License-dependent
|
||||
- **Known Issues**:
|
||||
- Repository must be configured as Docker with OCI layout
|
||||
- Referrers API requires Artifactory 7.x+
|
||||
|
||||
## Discovery Methods
|
||||
|
||||
### Native Referrers API (OCI 1.1)
|
||||
|
||||
The preferred method queries the registry referrers endpoint directly:
|
||||
|
||||
|
||||
|
||||
### Fallback Tag-Schema Discovery
|
||||
|
||||
For registries without OCI 1.1 support, tags following the pattern are enumerated:
|
||||
|
||||
|
||||
|
||||
Each matching tag is then resolved to get artifact metadata.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
| Issue | Registry | Solution |
|
||||
|-------|----------|----------|
|
||||
| 404 on referrers endpoint | GHCR, Distribution | Use fallback tag discovery |
|
||||
| Rate limit exceeded | Docker Hub | Authenticate or reduce concurrency |
|
||||
| Permission denied | ECR, ACR | Check IAM/RBAC permissions |
|
||||
| No referrers found | All | Verify artifacts were pushed with referrer relationship |
|
||||
| Timeout | All | Increase timeout_seconds, check network |
|
||||
|
||||
### Diagnostic Commands
|
||||
|
||||
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Export Center Architecture](architecture.md#oci-referrer-discovery)
|
||||
- [Offline Bundle Format](../airgap/guides/offline-bundle-format.md#oci-referrer-artifacts)
|
||||
- [Registry Referrer Troubleshooting Runbook](../../runbooks/registry-referrer-troubleshooting.md)
|
||||
- [OCI Distribution Spec v1.1](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers)
|
||||
|
||||
> **Imposed rule:** Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.
|
||||
Reference in New Issue
Block a user