IssuerDirectory — HOST RETIRED 2026-09-11, surface folded into Authority
The standalone
issuer-directoryservice no longer runs. The issuer surface does.SPRINT_20260722_016AUTH-9 folded the issuer directory into Authority on 2026-09-08 and AUTH-10 retired the deployable on 2026-09-11. The host project is frozen undersrc/__Obsoleted/Authority/StellaOps.IssuerDirectory.WebService/; the compose key, the publish key and theissuerdirectory.stella-ops.localalias are gone.What serves the surface now.
stellaops-authoritymaps the same endpoint groups from the librarysrc/Authority/__Libraries/StellaOps.IssuerDirectory.Api/throughIssuerDirectoryFold, and the gateway routes/issuer-directorytoauthorityby a static ReverseProxy rule. Theissuerschema moved intostellaops_authorityat the fold window; the schema NAME is unchanged (D-AUTH3-1).Paths, scopes and payloads are UNCHANGED, which is why this dossier is still useful rather than merely historical:
api-reference.mdandopenapi/v1.jsonremain accurate about the API. What is out of date anywhere below is the deployment framing — a separate container, its own base URL, its own host project and, since AUTH-10, theStellaOps.IssuerDirectory.WebService.*namespace, which is nowStellaOps.IssuerDirectory.Api.*.Canonical current dossier:
../authority/architecture.md(issuer sections 21.2 and 21.4).
IssuerDirectory is the Stella Ops trust registry for CSAF publishers and VEX statement issuers — it stores issuer metadata, signing keys, and per-tenant trust weights that Concelier/Excititor and VexLens consult when verifying signed advisory and VEX content.
Status: Implemented; served by the authority deployable since 2026-09-08 (AUTH-9 fold) Surface source: src/Authority/__Libraries/StellaOps.IssuerDirectory.Api/ (endpoints, contracts, resolvers) Domain + persistence: src/Authority/StellaOps.IssuerDirectory/, src/Authority/__Libraries/StellaOps.IssuerDirectory.Persistence/ Retired host: src/__Obsoleted/Authority/StellaOps.IssuerDirectory.WebService/ (frozen, AUTH-10) Database: stellaops_authority, schema issuer Owner: Authority domain (Identity & Trust)
Latest updates (2026-04-16)
- IssuerDirectory web runtime no longer silently falls back to in-memory persistence outside
Testing; non-testing hosts now require PostgreSQL wiring (IssuerDirectory:Persistence:Provider=Postgres). Startup throwsIssuerDirectory requires Persistence:Provider=Postgres outside Testing.otherwise. - Canonical configuration now lives under
IssuerDirectory:Persistence:*, while legacyIssuerDirectory:Postgres:*settings remain supported for compatibility (LegacyPostgresOptions; the effective value is resolved byGetEffectivePostgres*helpers, with the canonical keys winning). - Anonymous mode (
IssuerDirectory:Authority:Enabled=false) is a local/test-only path.IssuerDirectoryAnonymousModeGuard.Enforceblocks anonymous startup outsideTesting. - Focused runtime coverage moved with the fold (AUTH-10, 2026-09-11). The retired host’s suite is frozen at
src/__Obsoleted/Authority/StellaOps.IssuerDirectory.WebService.Tests. What guards the LIVE surface isAuthorityIssuerFoldHostingTestsandAuthorityIssuerFoldGlobalTenantTestsinStellaOps.Authority.Tests— they boot the real folded Authority host against a real PostgreSQL with tokens Authority minted itself — plusStellaOps.IssuerDirectory.Persistence.Tests.
Purpose
IssuerDirectory maintains a trust registry of CSAF publishers and VEX statement issuers. It stores issuer metadata, issuer signing keys (with rotation/revocation lifecycle), and per-tenant trust overrides (weights) for upstream vulnerability advisories and VEX statements. Consumers (notably Concelier/Excititor and VexLens) read issuer keys and trust weights when verifying signed advisory/VEX content.
Domain ownership
As of Sprint 216, IssuerDirectory source is owned by the Authority domain. The runtime service identity, container, and database schema remain independent. Schema isolation from AuthorityDbContext is a deliberate security feature (blast-radius containment between issuer-metadata handling and authentication internals).
See ../authority/architecture.md(sections 21.1–21.4) for schema ownership and the no-merge rationale.
Components
The module is split across the Authority tree:
Endpoint surface (src/Authority/__Libraries/StellaOps.IssuerDirectory.Api/):
StellaOps.IssuerDirectory.Api- endpoint mapping, contracts, options, security policies and tenant/actor resolution, composed into the Authority host byIssuerDirectoryFold(namespaceStellaOps.IssuerDirectory.Api.*since AUTH-10).- the Minimal-API host (StellaOps.IssuerDirectory.WebServiceProgram.cs, Router integration,/healthz,/readyz, its own OpenAPI document) is RETIRED tosrc/__Obsoleted/Authority/. Those host concerns are Authority’s now; the surface kept its paths.StellaOps.IssuerDirectory.Core- Domain model (IssuerRecord,IssuerKeyRecord,IssuerTrustOverrideRecord), services (IssuerDirectoryService,IssuerKeyService,IssuerTrustService), key validation, and metrics (IssuerDirectoryMetrics).StellaOps.IssuerDirectory.Infrastructure- In-memory repositories (Testing only) and the CSAF publisher seed loader.
Libraries (src/Authority/__Libraries/):
StellaOps.IssuerDirectory.Persistence- PostgreSQL repositories,IssuerDirectoryDbContext, the startup migration (Migrations/001_initial_schema.sql), and DI registration (AddIssuerDirectoryPersistence).StellaOps.IssuerDirectory.Client- Typed HTTP client (IIssuerDirectoryClient/IssuerDirectoryClient) with caching, consumed by other services for issuer keys and trust lookups.
HTTP API
All routes are under the /issuer-directory/issuers group and require an Authority token carrying the policy scope below (X-StellaOps-TenantId header selects the tenant; an optional X-StellaOps-Reason header is recorded in the audit trail). Most read routes accept ?includeGlobal=true (default true on issuer reads) to fold in global/system-seed issuers.
| Method & path | Operation | Required policy / scope |
|---|---|---|
GET /issuer-directory/issuers | List issuers | Reader / issuer-directory:read |
GET /issuer-directory/issuers/{id} | Get issuer | Reader / issuer-directory:read |
POST /issuer-directory/issuers | Create issuer | Writer / issuer-directory:write |
PUT /issuer-directory/issuers/{id} | Update issuer | Writer / issuer-directory:write |
DELETE /issuer-directory/issuers/{id} | Delete issuer | Admin / issuer-directory:admin |
GET /issuer-directory/issuers/{issuerId}/keys | List issuer keys | Reader / issuer-directory:read |
POST /issuer-directory/issuers/{issuerId}/keys | Add key | Writer / issuer-directory:write |
POST /issuer-directory/issuers/{issuerId}/keys/{keyId}/rotate | Rotate key | Writer / issuer-directory:write |
DELETE /issuer-directory/issuers/{issuerId}/keys/{keyId} | Revoke key | Admin / issuer-directory:admin |
GET /issuer-directory/issuers/{issuerId}/trust | Get effective trust | Reader / issuer-directory:read |
PUT /issuer-directory/issuers/{issuerId}/trust | Set tenant trust override | Writer / issuer-directory:write |
DELETE /issuer-directory/issuers/{issuerId}/trust | Delete trust override | Admin / issuer-directory:admin |
Health/diagnostics: GET /healthz (liveness), GET /readyz (readiness), and a build-info endpoint are mapped anonymously. OpenAPI is exposed via MapOpenApi.
Authorization
Endpoints bind to three named policies (IssuerDirectoryPolicies): IssuerDirectory.Reader, IssuerDirectory.Writer, IssuerDirectory.Admin. When IssuerDirectory:Authority:Enabled=true (default), each policy is registered via AddStellaOpsScopePolicy against the configured ReadScope / WriteScope / AdminScope (defaults issuer-directory:read, issuer-directory:write, issuer-directory:admin — see StellaOpsScopes.IssuerDirectoryRead/Write/Admin). The framework handler honours configured BypassNetworks (e.g. ISSUERDIRECTORY__AUTHORITY__BYPASSNETWORKS__0). When Authority is disabled (local/test), all three policies allow anonymous access.
Key types
Issuer key requests carry a type string parsed into the IssuerKeyType enum:
Ed25519PublicKeyX509CertificateDssePublicKey
(The startup-migration SQL key_type CHECK constraint lists a broader value set — ed25519, x509, dsse, kms, hsm, fido2 — but only the three enum members above are accepted by the WebService today.) Trust override weights are constrained to the range [-10, 10].
Configuration
See etc/issuer-directory.yaml.sample for the full sample. The binding section is IssuerDirectory and the environment prefix is ISSUERDIRECTORY_ (double-underscore for nesting, e.g. ISSUERDIRECTORY__PERSISTENCE__POSTGRESCONNECTIONSTRING).
Key settings:
IssuerDirectory:Persistence:Provider(Postgresdefault;InMemoryonly honoured in theTestingenvironment)IssuerDirectory:Persistence:PostgresConnectionStringIssuerDirectory:Persistence:SchemaName(defaults toissuerviaIssuerDirectoryDataSource.DefaultSchemaName)IssuerDirectory:Postgres:*— legacy compatibility keys (ConnectionString,Schema,CommandTimeoutSeconds)IssuerDirectory:Authority:Enabled/Issuer/Audiences/RequireHttpsMetadataIssuerDirectory:Authority:ReadScope/WriteScope/AdminScope/BypassNetworksIssuerDirectory:TenantHeader(defaults toX-StellaOps-TenantId)IssuerDirectory:SeedCsafPublishers(defaults totrue) andIssuerDirectory:CsafSeedPath(defaults tocsaf-publishers.json) — bootstraps system-seed CSAF publishers on startup viaCsafPublisherSeedLoaderIssuerDirectory:Telemetry:MinimumLogLevel
Persistence
PostgreSQL schema (default issuer), auto-migrated on startup via AddStartupMigrations (module IssuerDirectory.Persistence, embedded Migrations/001_initial_schema.sql). Tables:
issuers- issuer metadata (tenant-scoped or global), endpoints/contact/metadata JSONB, tags, status,is_system_seed;UNIQUE (tenant_id, name)issuer_keys- signing keys with lifecycle (active/retired/revoked), fingerprint dedupe, rotation chain (replaces_key_id)trust_overrides- per-consumer-tenant weight overrides (NUMERIC(5,2), range[-10,10]);UNIQUE (issuer_id, tenant_id)audit- issuer-domain audit log (actions:create_issuer,update_issuer,delete_issuer,add_key,rotate_key,revoke_key,set_trust,delete_trust,seed_csaf)schema_migrations- migration tracking
In-memory repositories exist for the Testing environment only. Unified audit events are also emitted to Timeline via AddAuditEmission.
Observability
Meter StellaOps.IssuerDirectory exposes:
issuer_directory_changes_total- issuer create/update/delete eventsissuer_directory_key_operations_total- key create/rotate/revoke operationsissuer_directory_key_validation_failures_total- key validation/verification failures
Dependencies
- PostgreSQL (default schema:
issuer; configurable viaIssuerDirectory:Persistence:SchemaName) - Authority (token authentication; resource-server validation)
- Stella Router (service registration / messaging transport)
- Timeline (unified audit emission)
Consumers:
- Concelier / Excititor - verify signed VEX/advisory content using issuer keys (
StellaOps.IssuerDirectory.Clientis referenced byStellaOps.Excititor.WebServiceandStellaOps.Excititor.Worker). - VexLens - trust-scoring/signature verification via its own
IIssuerDirectoryabstraction andAuthorityIssuerDirectoryAdapterover the directory client.
Related Documentation
- API reference — endpoint and DTO detail.
- Architecture:
../authority/architecture.md(sections 21.1–21.4). - Archived original:
docs-archive/modules/issuer-directory/. - Concelier — consumes issuer keys to verify signed advisories/VEX.
- VexLens — trust scoring and signature verification.
