ADR-015 and the doctrine blueprint now point at the assembled section 3.3 text. Accepted v0.8 still governs. Assistant: grok Assistant-Session: 01a1609f-72b8-7222-9dff-fae300115e42
166 lines
7.9 KiB
Markdown
166 lines
7.9 KiB
Markdown
# ADR-015 — Engine as processor and operator use-privilege
|
|
|
|
**Repository:** gate-house
|
|
**Status:** accepted
|
|
**Date:** 2026-10-22
|
|
**Accepted:** 2026-10-22
|
|
**Revision:** 2026-10-22 — a store may serve several engines; an engine enables a capability and is not an access-control mechanism.
|
|
|
|
## Context
|
|
|
|
The security-layer standard defines an Engine as a deterministic API for a
|
|
modeled concept. It types that layer into PDP, PIP, Evidence, and Lifecycle.
|
|
It does not say whether an engine is a library, a command, or a service, or
|
|
where the records of the concept live.
|
|
|
|
Repository intents filled that gap in incompatible ways. Some engines describe
|
|
themselves as the store of their facts. `secrets-engine` describes itself as a
|
|
processor over OpenBao: the vault holds the credential records, and the engine
|
|
turns an already-rendered access decision into a scoped change and a one-shot
|
|
delivery. The same estate also needs a rule for who may start that process.
|
|
The process holds credentials the calling operator must not hold. Without a
|
|
separate use-privilege, "the operator uses the engine" collapses into "the
|
|
operator receives the engine's credentials," or into the engine deciding for
|
|
itself who may call it.
|
|
|
|
A first draft of this ADR also made each engine the only client of its store.
|
|
That rule is withdrawn. One store can back several capabilities, and each
|
|
capability can be an engine. Exclusive clientship would turn every engine into
|
|
a gate on the records.
|
|
|
|
## Decision
|
|
|
|
An engine is a tool of automation for one capability. It encapsulates the
|
|
complexity of that capability in a consistent, often simpler interface than
|
|
doing the work by hand. The same inputs yield the same result. That
|
|
determinism is what reduces failure modes and what makes the work more
|
|
reliable and more efficient.
|
|
|
|
An engine implements its capability from the domain canon. It does not hold
|
|
the domain's records. Tooling holds the records. Several engines may use one
|
|
store. Each engine provides a different capability over those records. Being
|
|
an engine does not make a process the store's only client, and it does not
|
|
make the engine an access-control mechanism. An engine enables the capability.
|
|
Restricting who may act remains the domain of `access-engine`, not a property
|
|
of engines in general.
|
|
|
|
The implementation has three manifestations of one library:
|
|
|
|
1. **Library.** The capability: validate, explain, plan, and compute the next
|
|
state. A caller may use these operations without receiving a store
|
|
credential.
|
|
2. **CLI.** The library in a process. At start, the process is injected with
|
|
the credential for one scoped environment. That credential lets the process
|
|
reach the inputs and outputs of its capability. It is not returned to the
|
|
caller.
|
|
3. **Service.** The same process, kept running for a scoped environment that
|
|
needs a standing processor. A service is not a second implementation and
|
|
does not receive the credentials of any other environment.
|
|
|
|
`secrets-engine` is the reference shape. OpenBao is the store. The engine
|
|
enables credential lifecycle as a reliable operation. Another engine may use
|
|
OpenBao for a different capability. Build, test, and production are different
|
|
scoped environments and different processes.
|
|
|
|
### Authentication and the operator
|
|
|
|
An **operator** is a Staff actor, human or agent, who starts or calls an
|
|
engine. Authentication, by key-cape, establishes who the operator is. It does
|
|
not grant use of an engine.
|
|
|
|
Two privileges stay distinct.
|
|
|
|
- The **encapsulated privilege** is the credential injected into one engine
|
|
instance at start. It enables that instance to perform its capability. The
|
|
operator does not possess it, see it, or reuse it outside the process.
|
|
Holding it inside the process does not turn the engine into a restriction
|
|
on the store.
|
|
- The **use-privilege** is permission to start and call one named engine
|
|
instance, or a named set of instances. `access-engine` renders that
|
|
permission. The engine does not decide it and does not become the access
|
|
control for its store. A use-privilege is not a grant of the encapsulated
|
|
credential. It is permission to use the enabling interface.
|
|
|
|
Starting an instance and calling it both require a use-privilege for that
|
|
instance. The operator who starts it is the operator under whose use the
|
|
process is injected. One process is injected for one scoped environment.
|
|
|
|
### Delegation between operators
|
|
|
|
An operator who is allowed to delegate tasks may assign a task to another
|
|
operator who holds a use-privilege the delegator does not hold. The delegate
|
|
uses the engine. The delegator does not gain the use-privilege and does not
|
|
gain the encapsulated credential.
|
|
|
|
Delegation assigns work. It does not transfer either privilege. The delegate
|
|
must already hold the use-privilege. Engines stay deterministic, so the
|
|
enabled operation stays consistent. Operators stay flexible and are expected
|
|
to be reliable in the work they choose and assign. That reliability is a
|
|
Staff expectation. It is not a second restriction inside the engine.
|
|
|
|
## Consequences
|
|
|
|
- An engine intent that says the running service is the store of record is
|
|
aligned later: the database, the vault, or the log is Tooling. The engine
|
|
is a client of that store for its capability. Other engines may be clients
|
|
of the same store for other capabilities.
|
|
- `user-engine`, `tenant-engine`, `approval-engine`, and the access decision
|
|
log are enabling processors over records in Tooling. Another engine may use
|
|
the same records for a different capability. Approval consumption remains
|
|
the approval capability's own transaction. It is not an exclusive lock on
|
|
the store.
|
|
- `audit-core` enables append and verification. The tamper-evident store is
|
|
Tooling.
|
|
- A Deployment exists when a scoped environment keeps the process running. A
|
|
one-task environment manifests the same binary as a CLI. Absence of a
|
|
Deployment does not make the engine incomplete.
|
|
- This ADR selects no database, framework, or hosting technology, and it
|
|
creates no Gate House runtime surface.
|
|
- Accepted on 2026-10-22. The engine section is assembled into proposed
|
|
`security-layer-model_v0.9` §3.3
|
|
(`docs/amendments/adr-015-engine-section.md`). Accepted v0.8 still governs.
|
|
|
|
## Alternatives rejected
|
|
|
|
### The engine holds the records
|
|
|
|
Rejected because the layer cut already gives persistence to Tooling. Putting
|
|
the store inside the engine makes the process the system of record.
|
|
|
|
### Exactly one engine is the client of a store
|
|
|
|
Rejected because one store can back several capabilities. Each capability is
|
|
an engine. Exclusive clientship would block a second engine from offering a
|
|
different interface over the same records, and it would make the first engine
|
|
a gate.
|
|
|
|
### The engine is the access control for its store
|
|
|
|
Rejected because an engine enables a capability. It encapsulates complexity
|
|
so the operation is consistent, reliable, and efficient. Restricting who may
|
|
act is `access-engine`'s domain. An injected credential does not create a
|
|
second restriction mechanism.
|
|
|
|
### The operator receives the encapsulated credential
|
|
|
|
Rejected because the operator would then perform the complex operation by
|
|
hand. The engine exists so that work goes through the reliable interface.
|
|
The use-privilege names who may invoke that interface. It does not hand over
|
|
the store credential.
|
|
|
|
### The engine decides who may use it
|
|
|
|
Rejected because that decision is an access rule. An engine that renders it
|
|
takes on an access-control role this ADR withholds from engines in general.
|
|
|
|
### Delegation transfers the delegate's privileges to the delegator
|
|
|
|
Rejected because assigning a task would then widen the delegator. The
|
|
delegate already holds the use-privilege. The delegator remains without it.
|
|
|
|
### Library only, or service only
|
|
|
|
Rejected because the capability, the process boundary, and the standing
|
|
manifestation are one implementation. Collapsing them either gives callers
|
|
the store credential inside a library, or forces a Deployment for a one-task
|
|
environment.
|