Skip to content
Registry StackDocsv0.46.0

Registry Render configuration reference

View as Markdown

This grammar is not frozen.

manifest.yaml declares the bundle’s document types: each one’s template, data schema, label locales, version, and PDF standard. Each labels/<locale>.yaml holds one label table, and every table must carry the same keys. runtime.yaml is what registry-render serve reads: listener, package, secret providers, API key, limits, and audit.

The JSON Schema a document type names for its data is yours to write; Render applies it to every request and has no schema of its own for it. A schema-valid file still needs registry-render check, because rules across files, such as a label key the template reads, are not in these tables. Configuration files describes the YAML rules and environment substitution that apply when serve reads runtime.yaml.

Two rules are written as exclusions the tables do not show: each document’s entryFile and schemaFile is relative to the bundle root and contains no .., and package.root has no . or .. segment.

documents[] means an array item; labels.* means a map entry whose name you choose. Required fields inside an optional object apply when that object is present. Conditional fields depend on another value, such as audit.path on audit.destination. audit.rotateBytes defaults to 100 MiB and audit.retentionDays to 90.

manifest.yaml

Source preview, pre-1.0

Generated from products/render/schemas/bundle.schema.json. 13 key paths. Explained in docs/site/src/content/docs/reference/render-configuration.mdx.

Key pathTypeRequiredAccepted valuesConstraints
apiVersionstringYes
  • id.registrystack.org/formats/render/bundle/v1alpha1
None specified
bundleVersionAuthor-defined bundle version, monotonic per bundle.integerYesNot specified
  • format: uint32
  • maximum: 4294967295
  • minimum: 1
documentsThe document types, each with an id unique in the bundle.arrayNoNot specifiedNone specified
documents[]Array itemOne document type as manifest.yaml writes it.objectNoNot specifiedNone specified
documents[].entryFileEntry point relative to the bundle root: a .typ file inside the bundle.stringYesNot specified
  • pattern: \.typ$
documents[].idStable document identifier used in requests and routes.stringYesNot specified
  • pattern: ^[a-z][a-z0-9_-]{0,63}$
documents[].labelsLabel tables the template receives, by locale: each names labels/<locale>.yaml.arrayNoNot specifiedSchema default, where declared: []
  • uniqueItems: true
documents[].labels[]Array itemA local identifier: a lowercase letter, then up to 63 lowercase letters, digits, _, or -.stringNoNot specified
  • pattern: ^[a-z][a-z0-9_-]{0,63}$
documents[].pdfStandardPDF standard for this document; plain PDF when absent.stringNo
  • 1.4
  • 1.5
  • 1.6
  • 1.7
  • 2.0
  • a-1a
  • a-1b
  • a-2a
  • a-2b
  • a-2u
  • a-3a
  • a-3b
  • a-3u
  • a-4
  • a-4e
  • a-4f
  • ua-1
None specified
documents[].schemaFileJSON Schema (draft 2020-12) for the request data, relative to the bundle root: a .json file inside the bundle.stringNoNot specified
  • pattern: \.json$
documents[].sealThe seal this document type is issued under: a local identifier that the serving runtime's signing.seals binds to key material. Omit it and the document type cannot be sealed. The bundle never holds a key, a certificate, or a client list.stringNoNot specified
  • pattern: ^[a-z][a-z0-9_-]{0,63}$
documents[].versionThe document's own version; printed on paper by templates that wish to.integerYesNot specified
  • format: uint32
  • maximum: 4294967295
  • minimum: 1
kindstringYes
  • RenderBundle
None specified

labels/*.yaml

Source preview, pre-1.0

Generated from products/render/schemas/labels.schema.json. 4 key paths. Explained in docs/site/src/content/docs/reference/render-configuration.mdx.

Key pathTypeRequiredAccepted valuesConstraints
apiVersionstringYes
  • id.registrystack.org/formats/render/labels/v1alpha1
None specified
kindstringYes
  • RenderLabels
None specified
labelsThe text of each label, by key. Every locale of a document defines the same keys.objectYesNot specifiedNone specified
labels.*Map valueHuman-readable display text. Bidirectional embedding, override, and isolate controls, byte-order marks, line and paragraph separators, and Unicode noncharacters are refused; multilingual joiners and direction marks remain valid.stringNoNot specified
  • propertyNames.pattern: ^[a-z][a-z0-9_-]{0,63}$

runtime.yaml

Source preview, pre-1.0

Generated from products/render/schemas/runtime.schema.json. 58 key paths. Explained in docs/site/src/content/docs/reference/render-configuration.mdx.

Key pathTypeRequiredAccepted valuesConstraints
apiVersionstringYes
  • id.registrystack.org/formats/render/runtime/v1alpha1
None specified
assuranceProfileThe assurance boundary of this deployment's seals, the same member and values Evidence declares. Required when signing declares a seal, and unused otherwise. local signs with a local-jwk key file and marks every seal a test seal; production signs through transit only, so a production key never leaves Transit.stringConditional
  • local
  • production
None specified
auditThe audit block every Registry Stack product shares: a file (the default) or stdout destination, with rotation and retention for a file.objectYesNot specifiedNone specified
audit.destinationWhere audit lines go: file or stdout.stringNo
  • file
  • stdout
Schema default, where declared: "file"
None specified
audit.pathThe absolute path of the active audit file, for a file destination.stringConditionalNot specified
  • pattern: ^/+(?:(?:[^/.][^/]*|\.(?:[^/.][^/]*|\.[^/]+)?)/+)*(?:[^/.][^/]*|\.(?:[^/.][^/]*|\.[^/]+))$
audit.retentionDaysDays a rotated file is kept, for a file destination. Default: 90.integerNoNot specified
  • format: uint32
  • maximum: 36500
  • minimum: 1
audit.rotateBytesSize at which the active file rotates, in bytes, for a file destination. Default: 100 MiB.integerNoNot specified
  • format: uint64
  • maximum: 4294967295
  • minimum: 1048576
authenticationobjectYesNot specifiedNone specified
authentication.apiKeyRefSecret reference to the caller API key, under a declared provider. Omit when OIDC authentication is configured.stringConditionalNot specified
  • pattern: ^(?:secret:env/[A-Z][A-Z0-9_]{0,127}|secret:file/[a-z][a-z0-9._-]{0,127})$
authentication.oidcServing-adapter OIDC configuration. The pure rendering library never reads it.objectConditionalNot specifiedNone specified
authentication.oidc.allowInsecureHttpPermit plain HTTP beyond loopback to the configured issuer and to a JWKS URI declared in configuration. TLS remains required unless the operator explicitly accepts this transport risk.booleanNoNot specifiedSchema default, where declared: falseNone specified
authentication.oidc.allowedClientsThe OAuth clients whose access tokens are admitted: unrestricted to admit a token from every client the issuer verifies, or a list of at least one distinct client. A runtime decides whether unrestricted is acceptable in production.array | stringYes
  • unrestricted

No bound

or

  • minItems: 1
  • uniqueItems: true
authentication.oidc.allowedClients[]Array itemstringConditionalNot specifiedNone specified
authentication.oidc.assertionIssuersAssertion authorities each client may exchange a subject token from, keyed by client identifier. Omitted, no assertion-issuer rule applies; written, it lists at least one client, each with at least one authority. Once a client is listed, a token it exchanged is accepted only for one of that client's declared authorities, and a client that is not listed may exchange from no authority.objectNoNot specified
  • maxProperties: 64
  • minProperties: 1
authentication.oidc.assertionIssuers.*Map valuearrayNoNot specified
  • maxItems: 16
  • minItems: 1
  • propertyNames.maxLength: 128
  • propertyNames.minLength: 1
  • propertyNames.pattern: ^[^\u0000-\u001F\u007F-\u009F]+$
  • uniqueItems: true
authentication.oidc.assertionIssuers.*[]Array itemstringNoNot specified
  • maxLength: 512
  • minLength: 1
authentication.oidc.audienceThe audience every accepted access token must carry in aud.stringYesNot specified
  • maxLength: 512
  • minLength: 1
authentication.oidc.issuerExact issuer accepted in access-token iss claims, an absolute https URL, or a plain http URL when allowInsecureHttp is set.stringYesNot specified
  • format: uri
  • maxLength: 2048
  • pattern: ^[Hh][Tt][Tt][Pp][Ss]?://[^/?#@\u005C\u0000-\u0020\u007F-\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+([/?#][^\u005C\u0000-\u0020\u007F-\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]*)?$
authentication.oidc.jwksSourceWhere the issuer's signing keys come from. Absent reads the issuer's OpenID Connect discovery document.objectNoNot specifiedSchema default, where declared: {"type":"discovery"}None specified
authentication.oidc.jwksSource.documentRefAn exact secret reference: secret:file/name, resolved under secretProviders.file.root, or secret:env/NAME, resolved only when secretProviders.environment is declared.stringConditionalNot specified
  • pattern: ^(?:secret:env/[A-Z][A-Z0-9_]{0,127}|secret:file/[a-z][a-z0-9._-]{0,127})$
authentication.oidc.jwksSource.typestringYes
  • discovery
  • static
  • uri
None specified
authentication.oidc.jwksSource.uriAn absolute http or https URL with a host preserved as written, no user information, and no backslash, whitespace or control character. DNS case and equivalent IPv6 literals are permitted.stringConditionalNot specified
  • format: uri
  • maxLength: 2048
  • pattern: ^[Hh][Tt][Tt][Pp][Ss]?://[^/?#@\u005C\u0000-\u0020\u007F-\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+([/?#][^\u005C\u0000-\u0020\u007F-\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]*)?$
kindstringYes
  • RenderRuntimeConfig
None specified
limitsobjectNoNot specifiedNone specified
limits.maximumConcurrentRendersMost renders in flight at once. Default: the CPU count, at most 8.integerNoNot specified
  • format: uint64
  • maximum: 64
  • minimum: 1
limits.maximumOutputBytesLargest PDF a render may produce, in bytes.integerNoNot specifiedSchema default, where declared: 8388608
  • format: uint64
  • maximum: 8388608
  • minimum: 1
limits.maximumRequestBytesLargest request body (data and base64 assets), in bytes. The httpsec default is 1 MiB; renders with photos need a conscious, bounded raise.integerNoNot specifiedSchema default, where declared: 8388608
  • format: uint64
  • maximum: 67108864
  • minimum: 1
limits.renderTimeoutSecondsWall-clock budget per render, in seconds; the worker is killed at this bound.integerNoNot specifiedSchema default, where declared: 20
  • format: uint64
  • maximum: 3600
  • minimum: 1
listenerobjectYesNot specifiedNone specified
listener.bindLoopback, private, or link-local address to listen on. A public or all-interfaces bind is refused when the file is read. TLS is the proxy's job, not Render's.stringYesNot specified
  • maxLength: 128
  • minLength: 1
  • pattern: :0*(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
  • pattern: ^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?|0)\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?|0):[0-9]+$

or

  • maxLength: 128
  • minLength: 1
  • pattern: :0*(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
  • pattern: ^\[(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,7}:|(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,5}(?::[0-9A-Fa-f]{1,4}){1,2}|(?:[0-9A-Fa-f]{1,4}:){1,4}(?::[0-9A-Fa-f]{1,4}){1,3}|(?:[0-9A-Fa-f]{1,4}:){1,3}(?::[0-9A-Fa-f]{1,4}){1,4}|(?:[0-9A-Fa-f]{1,4}:){1,2}(?::[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:(?:(?::[0-9A-Fa-f]{1,4}){1,6})|:(?:(?::[0-9A-Fa-f]{1,4}){1,7}|:))\]:[0-9]+$

or

  • maxLength: 128
  • minLength: 1
  • pattern: :0*(?:[0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$
  • pattern: ^\[(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?|0)\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?|0)\]:[0-9]+$
listener.networkExposureThe operator-declared private network placement of an HTTP listener.stringNo
  • container-private
  • private-address
Schema default, where declared: "private-address"
None specified
listener.shutdownGraceMillisecondsTime allowed for renders and seals in flight to finish at shutdown, in milliseconds. Open connections get the same again.integerNoNot specifiedSchema default, where declared: 30000
  • format: uint64
  • maximum: 3600000
  • minimum: 1000
packageThe verified bundle package Render serves.objectYesNot specifiedNone specified
package.expectedDigestsha256: label of the package digest, the digest of the package's SHA256SUMS file. When set, the runtime refuses to start on any other package.stringNoNot specified
  • pattern: ^sha256:[0-9a-f]{64}$
package.rootAbsolute path of the package directory.stringYesNot specified
  • pattern: ^/
secretProvidersProviders for secret references. Omit when the authentication mode uses no secret references.objectNoNot specifiedNone specified
secretProviders.environmentEnables secret:env/NAME references, read from the process environment. Declared as an empty mapping: environment: {}.objectConditionalNot specifiedNone specified
secretProviders.fileEnables secret:file/name references, read from files under root.objectConditionalNot specifiedNone specified
secretProviders.file.rootAbsolute directory holding one file per secret. Each file must be a regular file owned by the runtime user, mode 0400 or 0600, with exactly one hard link.stringConditionalNot specified
  • pattern: ^/
signingOptional document sealing. Omit it and Render loads no signer, makes no timestamp call, and cannot seal any document.objectNoNot specifiedNone specified
signing.sealsThe seals, keyed by the local identifier the bundle manifest's seal names. At least one seal is required: omit signing to turn sealing off.objectYesNot specified
  • minProperties: 1
signing.seals.*Map valueOne seal: the signer, the certificate chain, the timestamp policy, and the clients allowed to use it.objectNoNot specified
  • propertyNames.pattern: ^[a-z][a-z0-9_-]{0,63}$
signing.seals.*.allowedClientsThe OIDC clients allowed to seal with this seal: a list of at least one client, each also admitted by authentication.oidc.allowedClients. There is no unrestricted form and no wildcard: a seal issues documents in the institution's name, so every seal-capable client is named. Keep these clients separate from any citizen-facing client.arrayYesNot specified
  • minItems: 1
  • uniqueItems: true
signing.seals.*.allowedClients[]Array itemAn identifier another system issues, written exactly as its issuer gives it.stringNoNot specified
  • maxLength: 512
  • minLength: 1
  • pattern: ^[^\u0000-\u001F\u007F-\u009F]+$
signing.seals.*.certificateChainFileAbsolute path of the PEM certificate chain file, the seal's own certificate first, then each issuer. It is absolute like Render's other runtime paths, so a runtime file names deployment locations, not locations relative to wherever the file was copied.stringYesNot specified
  • pattern: ^/(?:[^/]+/)*[^/]+$
signing.seals.*.signerBinds the seal to the private-key transport that produces its signature. Selects the signer transport for this seal: local-jwk resolves a file-provider secret directly, transit calls a workload-local Transit signing proxy over a Unix socket. Under assuranceProfile: production a seal signs through transit only; under local it signs with a local-jwk key file only.objectYesNot specifiedNone specified
signing.seals.*.signer.attemptTimeoutMillisecondsBounds how long the runtime waits on each call to the Transit signing proxy; because a transit signer keeps no local fallback key, a call that exceeds this bound fails the seal request rather than blocking it indefinitely.integerConditionalNot specified
  • format: uint64
  • maximum: 30000
  • minimum: 1
signing.seals.*.signer.keyNameNames the specific key within signer.mount this signer calls; combined with signer.mount and signer.keyVersion, it reaches exactly one pinned Transit key.stringConditionalNot specified
  • pattern: ^[a-z][a-z0-9_-]{0,63}$
signing.seals.*.signer.keyVersionPins signing to one exact Transit key version rather than a latest alias, so a provider-side rotation cannot silently replace the key bytes behind an unchanged seal certificate.integerConditionalNot specified
  • format: uint32
  • maximum: 4294967295
  • minimum: 1
signing.seals.*.signer.mountNames the Transit secrets-engine mount this signer calls; it is a path segment in the local Transit-proxy request URL, not a filesystem location.stringConditionalNot specified
  • pattern: ^[a-z][a-z0-9_-]{0,63}$
signing.seals.*.signer.privateKeyRefNames the file-provider secret holding the local signing private key material, read only when signer.type is local-jwk; the value is a reference, and configuration never carries the key bytes themselves. The secret is one private JSON Web Key, the form registry-render keygen writes.stringConditionalNot specified
  • pattern: ^(?:secret:env/[A-Z][A-Z0-9_]{0,127}|secret:file/[a-z][a-z0-9._-]{0,127})$
signing.seals.*.signer.typestringYes
  • local-jwk
  • transit
A rule elsewhere fixes this value in some cases.
None specified
signing.seals.*.signer.unixSocketPathAbsolute Unix socket path used to reach the workload-local Transit signing proxy; the runtime supplies no provider token over this connection, because token custody and renewal stay with the proxy.stringConditionalNot specified
  • pattern: ^/(?:[^/]+/)*[^/]+$
signing.seals.*.timestampAuthorityThe RFC 3161 timestamp authority that timestamps each seal (PAdES B-T), so the seal keeps validating after its certificate expires. Exactly one of timestampAuthority and withoutTimestamp is required.objectConditionalNot specifiedNone specified
signing.seals.*.timestampAuthority.attemptTimeoutMillisecondsTime allowed for one request to the authority, in milliseconds.integerNoNot specifiedSchema default, where declared: 10000
  • format: uint64
  • maximum: 60000
  • minimum: 1000
signing.seals.*.timestampAuthority.caBundleRefPEM CA bundle for the authority. Omitted, the platform's trusted roots verify it.stringNoNot specified
  • pattern: ^(?:secret:env/[A-Z][A-Z0-9_]{0,127}|secret:file/[a-z][a-z0-9._-]{0,127})$
signing.seals.*.timestampAuthority.urlAbsolute https URL of the authority. http is accepted only for a loopback host (localhost, 127.0.0.0/8, [::1]), for a test authority on the same machine.stringYesNot specified
  • format: uri
  • maxLength: 2048
  • pattern: ^(?:[Hh][Tt][Tt][Pp][Ss]://|[Hh][Tt][Tt][Pp]://(?:[Ll][Oo][Cc][Aa][Ll][Hh][Oo][Ss][Tt]|127(?:\.[0-9]{1,3}){3}|\[::1\])(?:[:/?#]|$))
  • pattern: ^[Hh][Tt][Tt][Pp][Ss]?://[^/?#@\u005C\u0000-\u0020\u007F-\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]+([/?#][^\u005C\u0000-\u0020\u007F-\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]*)?$
signing.seals.*.withoutTimestampSeal without a timestamp (PAdES B-B). The only value states the consequence the operator accepts: a seal without a timestamp stops validating when its certificate expires, which is usually before the document stops mattering. Exactly one of timestampAuthority and withoutTimestamp is required.stringConditional
  • seal-stops-validating-when-certificate-expires
None specified

The tables above list the signing.seals.<id> keys and the manifest’s per-document seal. These rules are not in the tables.

  • Omit signing to leave sealing off. With it, at least one seal is required, and serve mounts POST /v1/seal/{type}. Without it, that path is an unknown route and /ready has no signing member.
  • signing needs authentication.oidc. Each seal has exactly one of timestampAuthority (B-T) and withoutTimestamp: seal-stops-validating-when-certificate-expires (B-B).
  • timestampAuthority.url is https; http is accepted only for localhost, 127.0.0.0/8, and [::1]. attemptTimeoutMilliseconds is 1000 to 60000 and defaults to 10000.
  • timestampAuthority.caBundleRef is a secret reference to a PEM CA bundle that verifies the authority’s TLS certificate in place of the platform’s trusted roots. Omitted, the platform’s trusted roots verify it.
  • The timestamp authority must answer in DER, as RFC 3161 specifies; a BER answer, such as one with indefinite lengths, is refused as malformed-response. Its token must be signed with RSA PKCS#1 v1.5 or ECDSA over SHA-256, SHA-384, or SHA-512; RSA-PSS and SHA-1 are refused as token-signature-invalid. Its signer must carry an ESS signing-certificate attribute (v1 or v2, RFC 5816) naming the authority’s certificate, or the token is refused as tsa-certificate-not-named-by-token. Seal one test document through each authority before you rely on it for B-T.
  • certificateChainFile is an absolute path with no . or .. segment. The file is PEM, the seal certificate first.
  • assuranceProfile is a top-level runtime member, local or production, the same member and values Evidence uses. It is required when signing.seals declares a seal, and unused otherwise. Under production every seal signs through a transit signer; under local every seal signs with a local-jwk key file. A seal with the other signer is refused as render.runtime.signer-assurance-mismatch, at its signer.type. A runtime without seals needs no assuranceProfile.
  • signer names how the seal key signs. type: transit signs through a Vault or OpenBao Transit signing proxy on the Render host: unixSocketPath is the proxy’s socket, an absolute path with no . or .. segment; mount and keyName are local identifiers naming the key; keyVersion pins one version of it; and attemptTimeoutMilliseconds (1 to 30000, required) bounds each call. The key is ECDSA P-256, so the seal signs ES256, and it must be non-exportable, not derived, and without plaintext backup. The proxy holds the Transit token; Render sends none.
  • type: local-jwk is for assuranceProfile: local: privateKeyRef is a file-provider secret reference (secret:file/<name>) to one ES256, ES384, RS256, or RS384 private JWK, and EdDSA is refused. An environment reference is refused as render.runtime.seal-key-requires-file-provider.
  • registry-render keygen --key <file> --csr <file> --common-name <name> writes a seal key in the local-jwk form, owner-only, and a PKCS #10 certificate request for it. --organization and --country add to the request’s subject, and --algorithm picks es256 (the default), es384, rs256, or rs384. --from-pem <file> converts an unencrypted PKCS #8 key instead of generating one; encrypted PKCS #8, SEC 1, PKCS #1, and PKCS #12 keys are refused with the openssl command that converts each. In place of --key, --transit-unix-socket-path <socket> --transit-mount <mount> --transit-key-name <key> --transit-key-version <version> names a Transit key, as a transit signer does: keygen reads its public key, has Transit sign the request, and writes the request alone. Keygen never overwrites a file and never prints a key.
  • allowedClients is a list of at least one named client. unrestricted and any item containing * are refused. When authentication.oidc.allowedClients lists clients, each seal client must be in it.
  • assuranceProfile: local sets signing.testOnly in the template payload, and every answer about the seal says so: testOnly: true in the JSON seal member, the /ready entry, and each audit entry of the call, and X-Registry-Seal-Test-Only: true on the PDF answer. serve logs one test-only seal warning per such seal at startup. Under assuranceProfile: production a seal carries none of these.
  • A document type’s seal must name a seal in signing.seals. A package that names an unbound seal is refused at serve; check reports it, and warns about a runtime seal no document type names.
  • The seal is a certification signature (DocMDP permission 2) in an invisible field named RegistrySeal. The space it reserves is the certificate chain, twice the seal certificate’s issuer name and serial number, and 2112 bytes of structure and signature allowance, plus 16 KiB when timestamped. A chain that needs more than 256 KiB is refused.

Serve and check report these as runtime problems at the position of the key.

CodeMeaning
render.runtime.signing-requires-oidcsigning is declared with the legacy API key.
render.runtime.no-sealssigning.seals is empty.
render.runtime.relative-pathcertificateChainFile, or a transit signer’s unixSocketPath, is relative or has a . or .. segment.
render.runtime.seal-timestamp-undecidedNeither timestampAuthority nor withoutTimestamp is declared.
render.runtime.seal-timestamp-conflictBoth are declared.
render.runtime.insecure-timestamp-urlThe timestamp URL is http and not loopback.
render.runtime.seal-clients-not-listedallowedClients is missing, empty, or not a list.
render.runtime.seal-client-wildcardA client is unrestricted or contains a wildcard.
render.runtime.seal-client-not-admittedA seal client is not in authentication.oidc.allowedClients.
render.runtime.seal-key-requires-file-providersigner.privateKeyRef names the environment provider; a seal key is read through the file provider only.
render.runtime.signer-assurance-mismatchA seal’s signer does not suit assuranceProfile: local signs with local-jwk, production signs through transit.
render.runtime.seal-not-boundA document type names a seal signing.seals does not bind (error).
render.runtime.seal-unusedA runtime seal is named by no document type (warning).
render.runtime.seals-not-servedDocument types name seals and the runtime has no signing block: they render unsealed (warning).

check --environment and serve read the chain file and report:

CodeSeverityMeaning
render.runtime.seal-chain-unreadableerrorThe chain file cannot be read.
render.runtime.seal-chain-invaliderrorThe file is not a usable certificate chain: its certificates do not link in order, or its first certificate, taken as the seal certificate, is a CA certificate (basicConstraints CA:TRUE), which validators refuse as a document’s signer. Seal with a leaf issued with CA:FALSE; for a test seal, a test root of your own issues it.
render.runtime.seal-certificate-usageerrorThe seal certificate has neither the digitalSignature nor the nonRepudiation key usage.
render.runtime.seal-chain-too-largeerrorThe chain exceeds the signature space a seal may reserve.
render.runtime.seal-certificate-expiredwarningThe certificate is expired; the seal is unavailable.
render.runtime.seal-certificate-not-yet-validwarningThe certificate is not yet valid; the seal is unavailable.
render.runtime.seal-certificate-expiringwarningThe certificate expires within 30 days.
render.runtime.seal-certificate-purposewarningThe certificate’s extended key usage names none of document signing (RFC 9336 or Microsoft’s), Adobe Authentic Documents, email protection or anyExtendedKeyUsage; validators such as Acrobat flag its seals. serve logs it at startup too.

Each sealed document type is checked against its pdfStandard, at its seal member in manifest.yaml:

CodeSeverityMeaning
render.bundle.seal-space-exceeds-standarderrorThe seal reserves more signature space than the standard’s string limit holds: 65535 bytes under PDF/A-1, 32767 under PDF/A-2 and PDF/A-3. check --environment reports it, and serve refuses to start.

Without --environment, check reads no chain file and says so: the human output ends with seal chains not read: pass --environment to check them, and the JSON report has "sealChains": "not-read".

serve alone also reads the key and the timestamp authority’s CA bundle, and reports render.runtime.seal-key-unreadable (with the secret provider’s reason; a key file must be a regular file owned by the serving user, with mode 0600 or 0400 and one link), render.runtime.seal-key-invalid, render.runtime.seal-key-unsupported, render.runtime.seal-key-mismatch (the key file, or the Transit key version, is not the key the certificate certifies), render.runtime.seal-transit-unavailable (the Transit proxy does not answer, refuses the key read, or names a key that is not a non-exportable, non-derived ecdsa-p256 key without plaintext backup, or a version outside its live versions; checked by reading the key and signing once), render.runtime.seal-timestamp-ca-bundle-unreadable (with the secret provider’s reason), render.runtime.seal-timestamp-ca-bundle-invalid (the bundle is not PEM, holds no certificate, or is too large), and render.runtime.seal-timestamp-client (the timestamp client cannot be built from the URL).

A seal that cannot load refuses serve at startup as runtime-invalid (exit code 20), whichever piece failed, with each error at its member’s line in the runtime file, or, for render.bundle.seal-space-exceeds-standard, at the document type’s seal member in the package’s manifest.yaml. seal-certificate-invalid (27) and signing-unavailable (26) answer seal requests only.

POST /v1/seal/{type} takes the render route’s request body and returns the document sealed. It requires the render:seal scope, which render:render does not imply, from a client the seal’s allowedClients names. The legacy API key never seals. The signing time is the server’s clock, truncated to seconds. GET /v1/documents names the seal of each document type this route takes as seal; a document type without it is refused here with document-not-sealable.

The default answer is application/pdf with these headers. Every digest is labelled, sha256:<hex>:

HeaderValue
X-Registry-Document-DigestSHA-256 of the first revision, the document Render rendered.
X-Registry-Signed-File-DigestSHA-256 of the whole signed file.
X-Registry-Data-DigestSHA-256 of the canonical request data.
X-Registry-Document-VersionDocument type and version.
X-Registry-Package-DigestThe package digest, in the form package.expectedDigest takes.
X-Registry-Warning-CountNumber of render warnings.
X-Registry-Seal-IdThe seal id.
X-Registry-Seal-LevelB-T or B-B, the baseline level names of ETSI EN 319 142-1.
X-Registry-Certificate-DigestSHA-256 of the seal certificate’s DER.
X-Registry-Timestamped-AtThe timestamp authority’s genTime, RFC 3339 at the authority’s precision; B-T only.
X-Registry-Seal-Test-Onlytrue; only for a seal under assuranceProfile: local.

With Accept: application/json the body is pdfBase64, documentDigest, signedFileDigest, dataDigest, documentVersion, packageDigest, warnings, and seal (id, level, certificateDigest, timestampedAt for B-T, and testOnly: true for a test-only seal). A client granted only render:seal pins the package from packageDigest without reading /v1/documents. There is no pdfDigest. Because the payload carries the signing member, a sealed render’s dataDigest differs from a plain render of the same request.

The problems specific to this route, from a closed vocabulary shared with the render route:

ProblemHTTPExit codeMeaning
forbidden40323The credential lacks render:seal, or is the legacy API key.
seal-client-not-allowed40330The verified client is not in the seal’s allowedClients.
document-not-sealable40029The document type names no seal.
signing-unavailable50326The seal’s key provider is not ready.
seal-certificate-invalid50327The seal certificate is expired, not yet valid, or cannot sign.
timestamp-failed50228The timestamp authority gave no usable token. No file is returned and no retry is made.
rate-limited42918As many seals as limits.maximumConcurrentRenders are already in flight. The call is refused, not queued.

/ready adds signing, one member per seal: {"status": "ready"} or {"status": "not-ready", "reason": ...} with certificate-expired, certificate-not-yet-valid, or signer-not-ready, plus "testOnly": true for a test-only seal. It never changes the status code. A transit seal turns signer-not-ready when a signature fails; /ready calls and seal requests then start probes that have Transit sign one probe message, and the seal can sign again once a probe succeeds, with no restart. A seal has at most one probe in flight, and after a failed probe the next starts no sooner than one second after it ended. /ready starts the probe and never waits for it, so a recovery shows on a later call; a seal request waits for the probe it starts. At startup, serve logs a seal unavailable warning with seal_id and the same reason for each seal that cannot sign, and a seal certificate expiring warning for one whose certificate expires within 30 days.

Each seal call adds sealId to its audit entries, and testOnly: true when the seal is test-only. The response entry adds documentDigest, signedFileDigest, certificateDigest, and, for B-T, timestampTokenDigest, each labelled sha256:<hex>.

A timestamp-failed response entry adds reason, the failing check, and the log has one seal refused warning with the same reason. Neither carries a value from the exchange.

reasonPiece
connection-failed, timed-outThe authority could not be reached within the attempt timeout.
http-status, not-grantedThe authority answered with an HTTP error, or a status that grants no token.
not-a-timestamp-reply, malformed-response, missing-token, not-tst-info, malformed-tst-infoThe answer is not a DER timestamp reply carrying a token.
message-imprint-mismatch, nonce-mismatchThe token does not answer this request.
token-signature-invalid, tsa-certificate-not-named-by-token, tsa-certificate-not-for-timestamping, tsa-certificate-not-valid-at-gen-timeThe token does not verify under a timestamping certificate it names and that is valid at its time.
token-not-embeddable, gen-time-not-rfc3339The token cannot be added to the signature.
invalid-tokenAny other refusal of the token.
response-too-large, token-too-largeThe answer exceeds 64 KiB, or the token does not fit the space the seal reserves.

The key tables above are generated from the runtime schema by docs/site/scripts/generate-render-configuration.mjs; this section is hand-written.

Format and filesCheck command
Render bundle manifest
  • manifest.yaml
registry-render check --bundle <project>
Render label catalogue
  • labels/*.yaml
registry-render check --bundle <project>
Render runtime configuration
  • runtime.yaml
registry-render check --runtime-config <file>
Render document data schema
  • schemas/*.schema.json
None