E12050: service requires 'open' or 'constrain by' security posture declaration
What went wrong
Every service operation must have a security posture, either inherited from its parent service or declared on the operation itself. The compiler found a service operation with no posture. If the service declares 'open' or 'constrain by X', all operations inherit automatically. If the service has no posture, each operation must declare its own 'open' or 'constrain by'.
Worked examples
The [EXAMPLE] section below shows a service with no security posture, then the posture given at the service level - 'open', or 'constrain by' a security gate and/or a CORS policy, which every operation inherits - and at the operation level, when the service declares none (good_operation.ek9: one operation 'open', another 'constrain by ApiGate').
Rationale
Security posture must be a conscious, visible decision. A service that silently defaults to 'open' creates a class of bugs where developers forget to add authentication. Requiring explicit declaration means the security posture is always auditable in the source code.
This follows the EK9 principle: if the compiler cannot verify it, it does not compile. There is no 'default open' escape hatch.
How to fix it
Add a security posture to the service or to each operation. A service with no posture anywhere is this error. At the service level, 'open' or 'constrain by' a gate (and/or a CORS policy) is inherited by every operation; when the service declares none, each operation declares its own ('open', or 'constrain by ApiGate').
See also
- Constraint type resolution: E12060
- Constraint type validation: E12062
- Duplicate constraint role: E12064
- SecurityGate abstract function: ek9 -h SecurityGate
- CORSPolicy abstract function: ek9 -h CORSPolicy
- Compilable examples: ek9 -q 1292 (How does service security posture work with 'open' and ...) ek9 -q 1293 (What happens when a constrain by reference cannot be re...) ek9 -q 1294 (What types are valid in a constrain by clause?) ek9 -q 1295 (Why does constrain by X and Y fail when both extend Sec...)
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E12050: service requires 'open' or 'constrain by' security posture declaration
#!ek9 defines module error.e12050.bad defines service NoPostureService for :/api health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ?
Fixed: Declare the posture: 'open', or 'constrain by' a gate
#!ek9 defines module error.e12050.good defines service PostureService for :/api open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ?
Fixed: Or declare the posture on each operation
#!ek9 defines module error.e12050.good.operation defines function ApiGate is SecurityGate -> context as HTTPContext <- rtn as HTTPContext: context defines service PostureService for :/api health() as GET for :/status open <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? report() as GET for :/report constrain by ApiGate <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("report") override contentType() as pure <- rtn as String: "text/plain" default operator ?
Questions and answers
These Q&A entries show E12050 and its fix: