Authority Effective Write Contract
Contract ID: CONTRACT-AUTHORITY-EFFECTIVE-WRITE-008 Version: 1.0 Status: Published Last Updated: 2025-12-05
Implementation note (reconciled against source). Although the routes are namespaced under
/api/v1/authority/..., the endpoints, services, and data models for this contract are implemented in the Policy Engine (src/Policy/StellaOps.Policy.Engine+src/Policy/StellaOps.Policy.RiskProfile), not in the Authority service. The Authority OpenAPI spec only declares theeffective:writescope; it does not host these endpoints. Storage is an in-memory store (ConcurrentDictionaryinsideEffectivePolicyService) — there is currently no PostgreSQL persistence or migration backing this contract. See Implementation References below.
Overview
This contract defines the effective:write scope and the associated APIs for managing effective policies and authority scope attachments in Stella Ops. An effective policy binds a policy pack revision to a subject pattern with a priority rank, controlling which policy governs releases for matching subjects. The APIs are served by the Policy Engine under the /api/v1/authority/... route prefix.
Audience: integrators and operators wiring policy attachment into release control, and service authors that consume the effective:write / policy:read scopes.
Implementation References
- Endpoints:
src/Policy/StellaOps.Policy.Engine/Endpoints/EffectivePolicyEndpoints.cs - Service + data models:
src/Policy/StellaOps.Policy.RiskProfile/Scope/EffectivePolicyService.cs,src/Policy/StellaOps.Policy.RiskProfile/Scope/ScopeAttachmentModels.cs - Audit emitter:
src/Policy/StellaOps.Policy.Engine/Services/EffectivePolicyAuditor.cs - Scope constant:
StellaOps.Auth.Abstractions.StellaOpsScopes.EffectiveWrite(src/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOpsScopes.cs) - Scope declaration (Authority):
src/Authority/StellaOps.Api.OpenApi/authority/openapi.yaml(scope description only — not the endpoint surface) - Tests:
src/Policy/__Tests/StellaOps.Policy.Engine.Tests/Scope/EffectivePolicyServiceTests.cs
Not to be confused with the Risk Profile scope attachments surface (
/api/risk/scopes/..., also inScopeAttachmentEndpoints.cs), which binds risk profiles to organizational scopes (organization/project/environment/component) and is gated bypolicy:edit/policy:read. That is a separate model (ScopeAttachment) and is not part of this contract. This contract concerns theAuthorityScopeAttachmentmodel under/api/v1/authority/scope-attachments.
Scope Definition
effective:write
The canonical purpose of effective:write (StellaOpsScopes.EffectiveWrite = "effective:write") is: “Scope granted to the Policy Engine service identity for writing effective findings.” The Authority OpenAPI spec describes it as “Write effective findings (Policy Engine service identity only).”
Within this contract the same scope additionally gates the write operations on effective policies and authority scope attachments:
- Create, update, and delete effective policies
- Attach and detach authority scopes on effective policies
Backward-compatibility fallback: the write endpoints first check for effective:write; if absent they fall back to policy:edit (StellaOpsScopes.PolicyEdit) during the migration period (see RequireEffectiveWriteScope; TODO tracked under POLICY-AOC-19-002).
Read operations require policy:read(StellaOpsScopes.PolicyRead), not effective:write. This applies to get-by-id, list, get-scope-attachments, and resolve.
Tenant context is mandatory. Every endpoint group is registered with RequireTenantContext(); the tenant is taken from the authenticated tenant context / claims, not from a query-string parameter (POL-TEN-03).
Data Models
EffectivePolicy
Source: EffectivePolicy record in ScopeAttachmentModels.cs. JSON property names are snake_case (explicit [JsonPropertyName] attributes).
{
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"tenant_id": "default",
"policy_id": "security-policy-v1",
"policy_version": "1.0.0",
"subject_pattern": "pkg:npm/*",
"priority": 100,
"enabled": true,
"expires_at": "2025-12-31T23:59:59Z",
"scopes": ["scan:read", "scan:write"],
"created_at": "2025-12-05T10:00:00Z",
"created_by": "admin@example.com",
"updated_at": "2025-12-05T10:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
effective_policy_id | string | Auto | Generated as eff- + first 16 hex chars of SHA256(tenant_id|policy_id|subject_pattern|timestamp) |
tenant_id | string | Yes | Tenant scope |
policy_id | string | Yes | Referenced policy pack |
policy_version | string | null | No | Specific version (null if omitted) |
subject_pattern | string | Yes | Subject matching pattern (validated, see below) |
priority | integer | Yes | Priority rank (higher = wins) |
enabled | boolean | No | Whether policy is active (default: true) |
expires_at | datetime | null | No | Optional expiration (RFC 3339 / ISO 8601) |
scopes | array<string> | null | No | Attached authorization scopes carried on the policy |
created_at | datetime | Auto | Creation timestamp |
created_by | string | null | Auto | Actor id resolved (in order) from the NameIdentifier claim, then upn, then sub; falls back to the X-StellaOps-Actor header (see ResolveActorId in EffectivePolicyEndpoints.cs) |
updated_at | datetime | Auto | Last-update timestamp |
AuthorityScopeAttachment
Source: AuthorityScopeAttachment record in ScopeAttachmentModels.cs.
{
"attachment_id": "att-9f8e7d6c5b4a3021",
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"scope": "scan:write",
"conditions": {
"environment": "production"
},
"created_at": "2025-12-05T10:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
attachment_id | string | Auto | Generated as att- + first 16 hex chars of SHA256(effective_policy_id|scope|timestamp) |
effective_policy_id | string | Yes | Owning effective policy (must already exist) |
scope | string | Yes | Authorization scope to attach |
conditions | object<string,string> | null | No | Free-form string-to-string conditions map |
created_at | datetime | Auto | Creation timestamp |
Subject Patterns
Subject patterns use glob-style matching and are validated by EffectivePolicyService.IsValidSubjectPattern. A pattern is valid only if it is the universal wildcard *, or starts with pkg: or oci://, and does not contain a double wildcard **.
| Pattern | Valid | Matches |
|---|---|---|
* | Yes | All subjects |
pkg:* | Yes | All packages |
pkg:npm/* | Yes | All npm packages |
pkg:npm/@org/* | Yes | npm packages in the @org scope |
pkg:maven/com.example/* | Yes | Maven packages in com.example |
oci://registry.example.com/* | Yes | All images in registry |
invalid | No | Rejected with ERR_AUTH_001 |
pkg:** | No | Double wildcard rejected with ERR_AUTH_001 |
Glob matching semantics (MatchesPattern / GlobToRegex): a trailing * matches everything remaining (including /); a non-trailing * matches a single path segment ([^/]*). Matching is case-insensitive.
API Endpoints
All routes are served by the Policy Engine. All endpoints require authentication and a resolved tenant context (RequireTenantContext).
Effective Policies
Create Effective Policy
Requires effective:write (or policy:edit fallback). Audited as policy / create_effective_policy.
POST /api/v1/authority/effective-policies
Content-Type: application/json
Authorization: Bearer <token with effective:write scope>
{
"tenant_id": "default",
"policy_id": "security-policy-v1",
"subject_pattern": "pkg:npm/*",
"priority": 100,
"scopes": ["scan:read", "scan:write"]
}
Response: 201 Created
Location: /api/v1/authority/effective-policies/eff-0a1b2c3d4e5f6071
{
"effectivePolicy": {
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"tenant_id": "default",
"policy_id": "security-policy-v1",
"policy_version": null,
"subject_pattern": "pkg:npm/*",
"priority": 100,
"enabled": true,
"expires_at": null,
"scopes": ["scan:read", "scan:write"],
"created_at": "2025-12-05T10:00:00Z",
"created_by": "admin@example.com",
"updated_at": "2025-12-05T10:00:00Z"
}
}
The response is wrapped in an
effectivePolicyenvelope (EffectivePolicyResponse). Invalid patterns / missing fields return400 Bad Requestwitherror_codeERR_AUTH_001.
Get Effective Policy
Requires policy:read.
GET /api/v1/authority/effective-policies/{effectivePolicyId}
Authorization: Bearer <token with policy:read scope>
Response: 200 OK
{ "effectivePolicy": { ... } }
Response: 404 Not Found (error_code: ERR_AUTH_002)
Update Effective Policy
Requires effective:write (or policy:edit fallback). Audited as policy / update_effective_policy. Only priority, enabled, expires_at, and scopes are mutable; subject_pattern, policy_id, and tenant_id cannot be changed.
PUT /api/v1/authority/effective-policies/{effectivePolicyId}
Content-Type: application/json
Authorization: Bearer <token with effective:write scope>
{
"priority": 150,
"enabled": false,
"expires_at": "2025-12-31T23:59:59Z",
"scopes": ["scan:read"]
}
Response: 200 OK
{ "effectivePolicy": { ... } }
Response: 404 Not Found (error_code: ERR_AUTH_002)
Delete Effective Policy
Requires effective:write (or policy:edit fallback). Audited as policy / delete_effective_policy. Deleting a policy also removes its associated scope attachments.
DELETE /api/v1/authority/effective-policies/{effectivePolicyId}
Authorization: Bearer <token with effective:write scope>
Response: 204 No Content
Response: 404 Not Found (error_code: ERR_AUTH_002)
List Effective Policies
Requires policy:read. The tenant is taken from the tenant context, not a query parameter. Results are ordered by priority descending, then updated_at descending.
GET /api/v1/authority/effective-policies?policyId=security-policy-v1&enabledOnly=true&includeExpired=false&limit=100
Authorization: Bearer <token with policy:read scope>
Response: 200 OK
{
"items": [
{
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"tenant_id": "default",
"policy_id": "security-policy-v1",
"policy_version": null,
"subject_pattern": "pkg:npm/*",
"priority": 100,
"enabled": true,
"expires_at": null,
"scopes": ["scan:read", "scan:write"],
"created_at": "2025-12-05T10:00:00Z",
"created_by": "admin@example.com",
"updated_at": "2025-12-05T10:00:00Z"
}
],
"total": 1
}
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
policyId | string | (none) | Filter by referenced policy id |
enabledOnly | boolean | false | Only return enabled policies |
includeExpired | boolean | false | Include policies past expires_at |
limit | integer | 100 | Max items (values <= 0 default to 100) |
Scope Attachments
Attach Scope
Requires effective:write (or policy:edit fallback). Audited as policy / grant_scope.
POST /api/v1/authority/scope-attachments
Content-Type: application/json
Authorization: Bearer <token with effective:write scope>
{
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"scope": "scan:write",
"conditions": {
"environment": "production"
}
}
Response: 201 Created
Location: /api/v1/authority/scope-attachments/att-9f8e7d6c5b4a3021
{
"attachment": {
"attachment_id": "att-9f8e7d6c5b4a3021",
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"scope": "scan:write",
"conditions": { "environment": "production" },
"created_at": "2025-12-05T10:00:00Z"
}
}
The response is wrapped in an
attachmentenvelope (AuthorityScopeAttachmentResponse). Attaching to a non-existent policy returns400 Bad Requestwitherror_codeERR_AUTH_002; other validation failures returnERR_AUTH_004.
Detach Scope
Requires effective:write (or policy:edit fallback). Audited as policy / revoke_scope.
DELETE /api/v1/authority/scope-attachments/{attachmentId}
Authorization: Bearer <token with effective:write scope>
Response: 204 No Content
Response: 404 Not Found
List Scope Attachments for a Policy
Requires policy:read.
GET /api/v1/authority/scope-attachments/policy/{effectivePolicyId}
Authorization: Bearer <token with policy:read scope>
Response: 200 OK
{
"attachments": [
{
"attachment_id": "att-9f8e7d6c5b4a3021",
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"scope": "scan:write",
"conditions": { "environment": "production" },
"created_at": "2025-12-05T10:00:00Z"
}
]
}
Policy Resolution
Resolve Effective Policy for Subject
Requires policy:read. The tenant is taken from the tenant context. A blank subject returns 400 Bad Request.
GET /api/v1/authority/resolve?subject=pkg:npm/lodash@4.17.20
Authorization: Bearer <token with policy:read scope>
Response: 200 OK
{
"result": {
"subject": "pkg:npm/lodash@4.17.20",
"effective_policy": {
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"tenant_id": "default",
"policy_id": "security-policy-v1",
"policy_version": null,
"subject_pattern": "pkg:npm/*",
"priority": 100,
"enabled": true,
"expires_at": null,
"scopes": ["scan:read", "scan:write"],
"created_at": "2025-12-05T10:00:00Z",
"created_by": "admin@example.com",
"updated_at": "2025-12-05T10:00:00Z"
},
"granted_scopes": ["scan:read", "scan:write"],
"matched_pattern": "pkg:npm/*",
"resolution_time_ms": 0.42
}
}
The response is wrapped in a
resultenvelope (EffectivePolicyResolutionResponse). When no policy matches,effective_policyandmatched_patternarenullandgranted_scopesis an empty array.granted_scopesis the union of the winning policy’sscopesplus any attached scopes.
Priority Resolution
When multiple enabled, non-expired effective policies match a subject within the resolved tenant (EffectivePolicyService.Resolve):
- Higher
priorityvalue wins. - If equal priority, the more specific pattern wins (
GetPatternSpecificity=literalChars * 10 + segmentCount * 5; the universal*scores 0). - If equal specificity, the most recently updated (
updated_at) wins.
Example:
Pattern: pkg:npm/* Priority: 100 → Matches
Pattern: pkg:npm/@org/* Priority: 100 → Matches (more specific)
Pattern: pkg:* Priority: 100 → Matches
Winner (for subject pkg:npm/@org/utils@1.0.0): pkg:npm/@org/*
(most specific among equal-priority matches)
Audit Trail
All effective:write operations are recorded two ways:
- Structured log scope emitted by
EffectivePolicyAuditor(EffectivePolicyEndpointscallsRecordCreated/RecordUpdated/RecordDeleted/RecordScopeAttached/RecordScopeDetached). - Audit pipeline via the
.Audited(AuditModules.Policy, ...)endpoint filter (AuditActions.Policy.CreateEffectivePolicyetc.).
The structured log scope shape (example for a creation event):
{
"event": "effective_policy.created",
"timestamp": "2025-12-05T10:00:00.0000000Z",
"actor": "admin@example.com",
"effective_policy_id": "eff-0a1b2c3d4e5f6071",
"tenant_id": "default",
"policy_id": "security-policy-v1",
"subject_pattern": "pkg:npm/*",
"priority": 100,
"scopes": ["scan:read", "scan:write"]
}
Event types: effective_policy.created, effective_policy.updated, effective_policy.deleted, scope_attachment.created, scope_attachment.deleted. Audit action ids (audit pipeline): create_effective_policy, update_effective_policy, delete_effective_policy, grant_scope, revoke_scope.
Error Codes
These error codes are emitted as the error_code extension on the RFC 7807 ProblemDetails body.
| Code | Where used | Message |
|---|---|---|
ERR_AUTH_001 | Create policy — invalid subject pattern | Invalid subject pattern |
ERR_AUTH_002 | Get/Update/Delete policy not found; attach to non-existent policy | Policy not found |
ERR_AUTH_004 | Attach scope — other validation failure | Invalid scope |
Not implemented (documented for completeness):
ERR_AUTH_003(Duplicate attachment) andERR_AUTH_005(Priority conflict) appear in earlier drafts of this contract but are not produced by the current implementation. Attaching a duplicate scope or creating policies with conflicting priorities does not raise a dedicated error today.
Unblocks
This contract unblocks the following tasks:
- POLICY-AOC-19-002 (also tracks removal of the
policy:editwrite fallback) - POLICY-AOC-19-003
- POLICY-AOC-19-004
Related Contracts
- Policy Studio Contract - Policy creation
- Verification Policy Contract - Attestation policies
