feat: Add native binary analyzer test utilities and implement SM2 signing tests
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Manifest Integrity / Audit SHA256SUMS Files (push) Has been cancelled
Manifest Integrity / Validate Schema Integrity (push) Has been cancelled
Manifest Integrity / Validate Contract Documents (push) Has been cancelled
Manifest Integrity / Validate Pack Fixtures (push) Has been cancelled
Manifest Integrity / Verify Merkle Roots (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled

- Introduced `NativeTestBase` class for ELF, PE, and Mach-O binary parsing helpers and assertions.
- Created `TestCryptoFactory` for SM2 cryptographic provider setup and key generation.
- Implemented `Sm2SigningTests` to validate signing functionality with environment gate checks.
- Developed console export service and store with comprehensive unit tests for export status management.
This commit is contained in:
StellaOps Bot
2025-12-07 13:12:41 +02:00
parent d907729778
commit e53a282fbe
387 changed files with 21941 additions and 1518 deletions

View File

@@ -0,0 +1,72 @@
# Authority Routing Decision
**Decision ID:** DECISION-AUTH-001
**Status:** DEFAULT-APPROVED
**Effective Date:** 2025-12-06
**48h Window Started:** 2025-12-06T00:00:00Z
## Decision
Authority claim routing uses **RBAC-standard routing** patterns aligned with existing `docs/security/scopes-and-roles.md`.
## Rationale
1. RBAC patterns are well-established and auditable
2. Consistent with Authority module implementation
3. Supports multi-tenancy requirements
4. Compatible with external IdP integration (OIDC, SAML)
## Routing Matrix
| Claim | Source | Routing | Scope |
|-------|--------|---------|-------|
| `tenant_id` | Token/Session | Per-request | All endpoints |
| `project_id` | Token/Header | Per-request | Project-scoped |
| `user_id` | Token | Per-request | User-scoped |
| `role` | Token claims | Authorization | Role-based access |
| `scope` | Token claims | Authorization | Fine-grained access |
## Claim Priority
When claims conflict:
1. Explicit header overrides token claim (if authorized)
2. Token claim is authoritative for identity
3. Session context provides defaults
## Implementation Pattern
```csharp
// Authority claim resolution
public class ClaimResolver : IClaimResolver
{
public AuthorityContext Resolve(HttpContext context)
{
var tenantId = context.Request.Headers["X-Tenant-Id"]
?? context.User.FindFirst("tenant_id")?.Value;
var projectId = context.Request.Headers["X-Project-Id"]
?? context.User.FindFirst("project_id")?.Value;
return new AuthorityContext(tenantId, projectId);
}
}
```
## Impact
- Tasks unblocked: ~5
- Sprint files affected: SPRINT_0303
## Reversibility
To change routing patterns:
1. Update `docs/security/scopes-and-roles.md`
2. Get Authority Guild + Security Guild sign-off
3. Update `AuthorityClaimsProvider` implementations
4. Migration path for existing integrations
## References
- [Scopes and Roles](../security/scopes-and-roles.md)
- [Auth Scopes](../security/auth-scopes.md)
- [Tenancy Overview](../security/tenancy-overview.md)

View File

@@ -0,0 +1,56 @@
# Dossier Sequencing Decision
**Decision ID:** DECISION-DOCS-001
**Status:** DEFAULT-APPROVED
**Effective Date:** 2025-12-06
**48h Window Started:** 2025-12-06T00:00:00Z
## Decision
Module dossiers (Md.II through Md.X) are **sequenced after Md.I completion**, following the dependency chain in `docs/implplan/SPRINT_0300_*.md` files.
## Rationale
1. Md.I establishes baseline architecture documentation structure
2. Subsequent modules depend on patterns defined in Md.I
3. Sequential ordering prevents documentation conflicts
4. Allows parallel work within each dossier batch
## Sequencing Order
| Phase | Dossiers | Dependencies | Sprint |
|-------|----------|--------------|--------|
| Md.I | Concelier, Scanner, Authority | None | 0300 |
| Md.II | Attestor, Signer, Evidence | Md.I complete | 0301 |
| Md.III | VEX Lens, Excititor | Md.II complete | 0302 |
| Md.IV | Policy, Risk | Md.II complete | 0303 |
| Md.V | Scheduler, TaskRunner | Md.IV complete | 0304 |
| Md.VI | Notify, Telemetry | Md.V complete | 0305 |
| Md.VII | CLI, Web | Md.VI complete | 0306 |
| Md.VIII | AirGap, Mirror | Md.VII complete | 0307 |
| Md.IX | Zastava, Signals | Md.VIII complete | 0308 |
| Md.X | Integration, E2E | All above | 0309 |
## Parallelism Rules
Within each phase, dossiers MAY be worked in parallel if:
1. No cross-dependencies within the phase
2. Shared components are stable
3. Different owners/guilds assigned
## Impact
- Tasks unblocked: ~10
- Sprint files affected: SPRINT_0300, SPRINT_0301, SPRINT_0302
## Reversibility
To change sequencing:
1. Propose new order in `docs/process/dossier-sequencing.md`
2. Get Docs Guild sign-off
3. Update all affected SPRINT_03xx files
## References
- [SPRINT_0300 Documentation](../implplan/SPRINT_0300_0001_0001_documentation_i.md)
- [Module Dossier Template](../modules/template/)

View File

@@ -0,0 +1,263 @@
# Rate Limit Design Contract
**Contract ID:** CONTRACT-RATE-LIMIT-001
**Status:** APPROVED
**Effective Date:** 2025-12-07
**Owners:** Platform Reliability Guild, Gateway Guild
## Overview
This contract defines the rate limiting design for StellaOps API endpoints, ensuring fair resource allocation, protection against abuse, and consistent client experience across all services.
## Rate Limiting Strategy
### Tiered Rate Limits
| Tier | Requests/Minute | Requests/Hour | Burst Limit | Typical Use Case |
|------|-----------------|---------------|-------------|------------------|
| **Free** | 60 | 1,000 | 10 | Evaluation, small projects |
| **Standard** | 300 | 10,000 | 50 | Production workloads |
| **Enterprise** | 1,000 | 50,000 | 200 | Large-scale deployments |
| **Unlimited** | No limit | No limit | No limit | Internal services, VIP |
### Per-Endpoint Rate Limits
Some endpoints have additional rate limits based on resource intensity:
| Endpoint Category | Rate Limit | Rationale |
|-------------------|------------|-----------|
| `/api/risk/simulation/*` | 30/min | CPU-intensive simulation |
| `/api/risk/simulation/studio/*` | 10/min | Full breakdown analysis |
| `/system/airgap/seal` | 5/hour | Critical state change |
| `/policy/decisions` | 100/min | Lightweight evaluation |
| `/api/policy/packs/*/bundle` | 10/min | Bundle compilation |
| Export endpoints | 20/min | I/O-intensive operations |
## Implementation
### Algorithm
Use **Token Bucket** algorithm with the following configuration:
```yaml
rate_limit:
algorithm: token_bucket
bucket_size: ${BURST_LIMIT}
refill_rate: ${REQUESTS_PER_MINUTE} / 60
refill_interval: 1s
```
### Rate Limit Headers
All responses include standard rate limit headers:
```http
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 295
X-RateLimit-Reset: 1701936000
X-RateLimit-Policy: standard
Retry-After: 30
```
### Rate Limit Response
When rate limit is exceeded, return:
```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 30
```
## Rate Limit Keys
### Primary Key: Tenant ID + Client ID
```
rate_limit_key = "${tenant_id}:${client_id}"
```
### Fallback Keys
1. Authenticated: `tenant:${tenant_id}:user:${user_id}`
2. API Key: `apikey:${api_key_hash}`
3. Anonymous: `ip:${client_ip}`
## Exemptions
### Exempt Endpoints
The following endpoints are exempt from rate limiting:
- `GET /health`
- `GET /ready`
- `GET /metrics`
- `GET /.well-known/*`
### Exempt Clients
- Internal service mesh traffic (mTLS authenticated)
- Localhost connections in development mode
- Clients with `unlimited` tier
## Quota Management
### Tenant Quota Tracking
```yaml
quota:
tracking:
storage: redis
key_prefix: "stellaops:quota:"
ttl: 3600 # 1 hour rolling window
dimensions:
- tenant_id
- endpoint_category
- time_bucket
```
### Quota Alerts
| Threshold | Action |
|-----------|--------|
| 80% consumed | Emit `quota.warning` event |
| 95% consumed | Emit `quota.critical` event |
| 100% consumed | Block requests, emit `quota.exceeded` event |
## Configuration
### Gateway Configuration
```yaml
# gateway/rate-limits.yaml
rateLimiting:
enabled: true
defaultTier: standard
tiers:
free:
requestsPerMinute: 60
requestsPerHour: 1000
burstLimit: 10
standard:
requestsPerMinute: 300
requestsPerHour: 10000
burstLimit: 50
enterprise:
requestsPerMinute: 1000
requestsPerHour: 50000
burstLimit: 200
endpoints:
- pattern: "/api/risk/simulation/*"
limit: 30
window: 60s
- pattern: "/api/risk/simulation/studio/*"
limit: 10
window: 60s
- pattern: "/system/airgap/seal"
limit: 5
window: 3600s
```
### Policy Engine Configuration
```csharp
// PolicyEngineRateLimitOptions.cs
public static class PolicyEngineRateLimitOptions
{
public const string PolicyName = "PolicyEngineRateLimit";
public static void Configure(RateLimiterOptions options)
{
options.AddTokenBucketLimiter(PolicyName, opt =>
{
opt.TokenLimit = 50;
opt.QueueLimit = 10;
opt.ReplenishmentPeriod = TimeSpan.FromSeconds(10);
opt.TokensPerPeriod = 5;
opt.AutoReplenishment = true;
});
}
}
```
## Monitoring
### Metrics
| Metric | Type | Labels |
|--------|------|--------|
| `stellaops_rate_limit_requests_total` | Counter | tier, endpoint, status |
| `stellaops_rate_limit_exceeded_total` | Counter | tier, endpoint |
| `stellaops_rate_limit_remaining` | Gauge | tenant_id, tier |
| `stellaops_rate_limit_queue_size` | Gauge | endpoint |
### Alerts
```yaml
# prometheus/rules/rate-limiting.yaml
groups:
- name: rate_limiting
rules:
- alert: HighRateLimitExceeded
expr: rate(stellaops_rate_limit_exceeded_total[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "High rate of rate limit exceeded events"
```
## Integration with Web UI
### Client SDK Configuration
```typescript
// stellaops-sdk/rate-limit-handler.ts
interface RateLimitConfig {
retryOnRateLimit: boolean;
maxRetries: number;
backoffMultiplier: number;
maxBackoffSeconds: number;
}
const defaultConfig: RateLimitConfig = {
retryOnRateLimit: true,
maxRetries: 3,
backoffMultiplier: 2,
maxBackoffSeconds: 60
};
```
### UI Rate Limit Display
The Web UI displays rate limit status in the console header with:
- Current remaining requests
- Time until reset
- Visual indicator when approaching limit (< 20% remaining)
## Changelog
| Date | Version | Change |
|------|---------|--------|
| 2025-12-07 | 1.0.0 | Initial contract definition |
## References
- [API Governance Baseline](./api-governance-baseline.md)
- [Web Gateway Architecture](../modules/gateway/architecture.md)
- [Policy Engine Rate Limiting](../modules/policy/design/rate-limiting.md)
## Changelog
| Date | Version | Change |
|------|---------|--------|
| 2025-12-07 | 1.0.0 | Initial contract definition |
## References
- [API Governance Baseline](./api-governance-baseline.md)
- [Web Gateway Architecture](../modules/gateway/architecture.md)
- [Policy Engine Rate Limiting](../modules/policy/design/rate-limiting.md)

View File

@@ -0,0 +1,67 @@
# Redaction Defaults Decision
**Decision ID:** DECISION-SECURITY-001
**Status:** DEFAULT-APPROVED
**Effective Date:** 2025-12-06
**48h Window Started:** 2025-12-06T00:00:00Z
## Decision
Notification and export pipelines use **restrictive redaction defaults** that redact PII, secrets, and cryptographic keys.
## Rationale
1. Security-first approach minimizes data exposure risk
2. Users can opt-in to less restrictive settings via configuration
3. Aligns with GDPR and data minimization principles
4. Consistent with existing Evidence Locker redaction patterns
## Default Redaction Rules
### Always Redacted (HIGH)
- Private keys (RSA, ECDSA, Ed25519)
- API keys and tokens
- Passwords and secrets
- Database connection strings
- JWT tokens
### Redacted by Default (MEDIUM) - Opt-out available
- Email addresses
- IP addresses (external)
- File paths containing usernames
- Environment variable values (not names)
### Not Redacted (LOW)
- Package names and versions
- CVE identifiers
- Severity scores
- Public key fingerprints
## Configuration
```yaml
# etc/notify.yaml
redaction:
level: restrictive # Options: permissive, standard, restrictive
custom_patterns:
- pattern: "INTERNAL_.*"
action: redact
```
## Impact
- Tasks unblocked: ~5
- Sprint files affected: SPRINT_0170, SPRINT_0171
## Reversibility
To change redaction defaults:
1. Update `docs/security/redaction-and-privacy.md`
2. Get Security Guild sign-off
3. Update configuration schemas
4. Ensure backward compatibility
## References
- [Redaction and Privacy](../security/redaction-and-privacy.md)
- [SPRINT_0170 Notifications](../implplan/SPRINT_0170_0001_0001_notifications_telemetry.md)

View File

@@ -0,0 +1,467 @@
# Web Gateway Tenant RBAC Contract
**Contract ID:** CONTRACT-GATEWAY-RBAC-001
**Status:** APPROVED
**Effective Date:** 2025-12-07
**Owners:** Gateway Guild, Authority Guild, Web UI Guild
## Overview
This contract defines the tenant isolation and role-based access control (RBAC) model for the StellaOps Web Gateway, ensuring consistent authorization across all API endpoints and UI components.
## Tenant Model
### Tenant Hierarchy
```
Organization (Org)
├── Tenant A
│ ├── Project 1
│ │ └── Resources...
│ └── Project 2
│ └── Resources...
└── Tenant B
└── Project 3
└── Resources...
```
### Tenant Identification
Tenants are identified through:
1. **JWT Claims:** `tenant_id` or `stellaops:tenant` claim
2. **Header:** `X-Tenant-Id` header (for service-to-service)
3. **Path Parameter:** `/tenants/{tenantId}/...` routes
### Tenant Resolution Priority
```
1. Path parameter (explicit)
2. JWT claim (authenticated user context)
3. X-Tenant-Id header (service-to-service)
4. Default tenant (configuration fallback)
```
## Role Definitions
### Built-in Roles
| Role | Description | Scope |
|------|-------------|-------|
| `org:admin` | Organization administrator | Org-wide |
| `org:reader` | Organization read-only access | Org-wide |
| `tenant:admin` | Tenant administrator | Single tenant |
| `tenant:operator` | Can modify resources within tenant | Single tenant |
| `tenant:viewer` | Read-only access to tenant | Single tenant |
| `project:admin` | Project administrator | Single project |
| `project:contributor` | Can modify project resources | Single project |
| `project:viewer` | Read-only project access | Single project |
| `policy:admin` | Policy management | Tenant-wide |
| `scanner:operator` | Scanner operations | Tenant-wide |
| `airgap:admin` | Air-gap operations | Tenant-wide |
### Role Hierarchy
```
org:admin
├── org:reader
├── tenant:admin
│ ├── tenant:operator
│ │ └── tenant:viewer
│ ├── policy:admin
│ ├── scanner:operator
│ └── airgap:admin
└── project:admin
├── project:contributor
└── project:viewer
```
## Scopes
### OAuth 2.0 Scopes
| Scope | Description | Required Role |
|-------|-------------|---------------|
| `policy:read` | Read policies and profiles | `tenant:viewer` |
| `policy:edit` | Create/modify policies | `policy:admin` |
| `policy:activate` | Activate policies | `policy:admin` |
| `scanner:read` | View scan results | `tenant:viewer` |
| `scanner:execute` | Execute scans | `scanner:operator` |
| `airgap:seal` | Seal/unseal environment | `airgap:admin` |
| `airgap:status:read` | Read sealed mode status | `tenant:viewer` |
| `airgap:verify` | Verify bundles | `tenant:operator` |
| `export:read` | Read exports | `tenant:viewer` |
| `export:create` | Create exports | `tenant:operator` |
| `admin:users` | Manage users | `tenant:admin` |
| `admin:settings` | Manage settings | `tenant:admin` |
### Scope Inheritance
Child scopes are automatically granted when parent scope is present:
```yaml
scope_inheritance:
"policy:edit": ["policy:read"]
"policy:activate": ["policy:read", "policy:edit"]
"scanner:execute": ["scanner:read"]
"export:create": ["export:read"]
"admin:users": ["admin:settings"]
```
## Resource Authorization
### Resource Types
| Resource Type | Tenant Scoped | Project Scoped | Description |
|--------------|---------------|----------------|-------------|
| `risk_profile` | Yes | No | Risk scoring profiles |
| `policy_pack` | Yes | No | Policy bundles |
| `scan_result` | Yes | Yes | Scan outputs |
| `export` | Yes | Yes | Export jobs |
| `finding` | Yes | Yes | Vulnerability findings |
| `vex_document` | Yes | Yes | VEX statements |
| `sealed_mode` | Yes | No | Air-gap state |
| `user` | Yes | No | Tenant users |
| `project` | Yes | No | Projects |
### Authorization Rules
```yaml
# authorization-rules.yaml
rules:
- resource: risk_profile
actions:
read:
required_scopes: [policy:read]
tenant_isolation: strict
create:
required_scopes: [policy:edit]
tenant_isolation: strict
update:
required_scopes: [policy:edit]
tenant_isolation: strict
activate:
required_scopes: [policy:activate]
tenant_isolation: strict
delete:
required_scopes: [policy:edit]
tenant_isolation: strict
require_role: policy:admin
- resource: scan_result
actions:
read:
required_scopes: [scanner:read]
tenant_isolation: strict
project_isolation: optional
create:
required_scopes: [scanner:execute]
tenant_isolation: strict
delete:
required_scopes: [scanner:execute]
tenant_isolation: strict
require_role: scanner:operator
- resource: sealed_mode
actions:
read:
required_scopes: [airgap:status:read]
tenant_isolation: strict
seal:
required_scopes: [airgap:seal]
tenant_isolation: strict
require_role: airgap:admin
audit: required
unseal:
required_scopes: [airgap:seal]
tenant_isolation: strict
require_role: airgap:admin
audit: required
```
## Tenant Isolation
### Strict Isolation
All data access is tenant-scoped by default:
```sql
-- Example: All queries include tenant filter
SELECT * FROM findings
WHERE tenant_id = @current_tenant_id
AND deleted_at IS NULL;
```
### Cross-Tenant Access
Cross-tenant access is prohibited except:
1. **Organization admins** can access all tenants in their org
2. **Internal services** with explicit `cross_tenant` scope
3. **Aggregation endpoints** with `org:reader` role
### Isolation Enforcement Points
| Layer | Enforcement |
|-------|-------------|
| Gateway | Validates tenant claim, injects X-Tenant-Id |
| Service | Applies tenant filter to all queries |
| Database | Row-level security (RLS) policies |
| Cache | Tenant-prefixed cache keys |
## JWT Claims
### Required Claims
```json
{
"sub": "user-uuid",
"aud": ["stellaops-api"],
"iss": "https://auth.stellaops.io",
"exp": 1701936000,
"iat": 1701932400,
"stellaops:tenant": "tenant-uuid",
"stellaops:org": "org-uuid",
"stellaops:roles": ["tenant:operator", "policy:admin"],
"scope": "policy:read policy:edit scanner:read"
}
```
### Custom Claims
| Claim | Type | Description |
|-------|------|-------------|
| `stellaops:tenant` | string | Current tenant UUID |
| `stellaops:org` | string | Organization UUID |
| `stellaops:roles` | string[] | Assigned roles |
| `stellaops:projects` | string[] | Accessible projects |
| `stellaops:tier` | string | Rate limit tier |
## Gateway Implementation
### Authorization Middleware
```csharp
// AuthorizationMiddleware.cs
public class TenantAuthorizationMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
// 1. Extract tenant from JWT/header/path
var tenantId = ResolveTenantId(context);
// 2. Validate tenant access
if (!await ValidateTenantAccess(context.User, tenantId))
{
context.Response.StatusCode = 403;
return;
}
// 3. Set tenant context for downstream
context.Items["TenantId"] = tenantId;
context.Request.Headers["X-Tenant-Id"] = tenantId;
await next(context);
}
}
```
### Scope Authorization
```csharp
// ScopeAuthorization.cs
public static class ScopeAuthorization
{
public static IResult? RequireScope(HttpContext context, string requiredScope)
{
var scopes = context.User.FindFirst("scope")?.Value?.Split(' ') ?? [];
if (!scopes.Contains(requiredScope) && !HasInheritedScope(scopes, requiredScope))
{
return Results.Problem(
title: "Forbidden",
detail: $"Missing required scope: {requiredScope}",
statusCode: 403);
}
return null; // Access granted
}
}
```
## Web UI Integration
### Route Guards
```typescript
// route-guards.ts
export const TenantGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthService);
const requiredRoles = route.data['roles'] as string[];
if (!auth.hasAnyRole(requiredRoles)) {
return inject(Router).createUrlTree(['/unauthorized']);
}
return true;
};
// Usage in routes
{
path: 'policy/studio',
component: PolicyStudioComponent,
canActivate: [TenantGuard],
data: { roles: ['policy:admin', 'tenant:admin'] }
}
```
### Scope-Based UI Elements
```typescript
// rbac.directive.ts
@Directive({ selector: '[requireScope]' })
export class RequireScopeDirective {
@Input() set requireScope(scope: string) {
this.updateVisibility(scope);
}
private updateVisibility(scope: string): void {
const hasScope = this.auth.hasScope(scope);
this.viewContainer.clear();
if (hasScope) {
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
}
// Usage in templates
<button *requireScope="'policy:activate'">Activate Policy</button>
```
## Audit Trail
### Audited Operations
All write operations are logged with:
```json
{
"timestamp": "2025-12-07T10:30:00Z",
"actor": {
"userId": "user-uuid",
"tenantId": "tenant-uuid",
"roles": ["policy:admin"],
"ipAddress": "192.168.1.100"
},
"action": "policy.activate",
"resource": {
"type": "policy_pack",
"id": "pack-123",
"version": 5
},
"outcome": "success",
"details": {
"previousStatus": "approved",
"newStatus": "active"
}
}
```
### Sensitive Operations
These operations require enhanced audit logging:
- `sealed_mode.seal` / `sealed_mode.unseal`
- `policy.activate`
- `export.create` (with PII)
- `user.role.assign`
- `tenant.settings.modify`
## Configuration
### Gateway RBAC Configuration
```yaml
# gateway/rbac.yaml
rbac:
enabled: true
strictTenantIsolation: true
allowCrossTenantForOrgAdmin: true
defaultRole: tenant:viewer
defaultScopes:
- policy:read
- scanner:read
roleBindings:
tenant:admin:
scopes:
- policy:read
- policy:edit
- policy:activate
- scanner:read
- scanner:execute
- airgap:status:read
- export:read
- export:create
- admin:users
- admin:settings
policy:admin:
scopes:
- policy:read
- policy:edit
- policy:activate
```
## Error Responses
### 401 Unauthorized
```json
{
"type": "https://stellaops.org/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Authentication required."
}
```
### 403 Forbidden
```json
{
"type": "https://stellaops.org/problems/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "You do not have permission to access this resource.",
"requiredScope": "policy:activate",
"currentScopes": ["policy:read"]
}
```
### 404 Not Found (Tenant Isolation)
```json
{
"type": "https://stellaops.org/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "Resource not found."
}
```
Note: 404 is returned instead of 403 for resources in other tenants to prevent enumeration attacks.
## Changelog
| Date | Version | Change |
|------|---------|--------|
| 2025-12-07 | 1.0.0 | Initial contract definition |
## References
- [Auth Scopes Documentation](../security/auth-scopes.md)
- [RBAC Documentation](../security/scopes-and-roles.md)
- [Tenancy Overview](../security/tenancy-overview.md)
- [Rate Limit Design](./rate-limit-design.md)