Declaring dependencies
dependencies: source: type: git-repository description: Repository to analyse. mutable: false gcpCredential: form: file sensitive: true privilege: high description: >- Service account key. The real scope depends on the account's roles and is rarely minimal.Two ways to declare, and exactly one per dependency.
Inline, the common case
Section titled “Inline, the common case”form says what the engine materialises — directory, file, string, socket,
capability — and that is what it can enforce. Add sensitive: true when it is a
credential, and description to say what it is.
It registers nothing, works offline, and is what you will write most of the time.
Named, when the name buys something
Section titled “Named, when the name buys something”type references the core vocabulary. It is closed — an unknown type is a
validation error — and deliberately small: only what enforces something beyond
the form belongs there.
| Type | Form | Privilege | What it enforces beyond the form |
|---|---|---|---|
directory |
directory | low | — |
git-repository |
directory | low | requires .git at the path, before any container starts |
file |
file | low | — |
string |
string | low | — |
secret |
string | medium | marks it sensitive: redacted in logs, kept out of the lockfile |
secret-file |
file | medium | sensitive content mounted as a file — never written to the host |
socket |
socket | critical | a channel into whatever daemon is listening |
engine/docker |
socket | critical | knows the socket’s conventional path |
network |
capability | medium | — (declarable, not yet enforced) |
endpoint/tcp |
endpoint | medium | a live address the worker reaches — see Providers and endpoints |
endpoint/postgres, endpoint/redis |
endpoint | medium | extend endpoint/tcp: a claim of protocol, matched but never verified — see below |
A name also buys identity: two documents citing the same type are known to mean the same thing. That is what catalogue search and credential auto-wiring — which does not exist yet — depend on.
What a name does not buy is a guarantee. What the engine enforces is the form, and the form is present either way.
What each column decides
Section titled “What each column decides”Three things, and they are orthogonal.
Form is how the value crosses into the container, and the runtime does
different work for each:
| Form | What the worker gets |
|---|---|
directory |
a mounted directory, at the mountPath the implementation declares |
file |
a single file, mounted as a secret when the value is content rather than a path |
string |
an environment variable, marked secret when the type is sensitive |
socket |
a Unix socket bound into the container |
capability |
nothing in the filesystem — the grant is the absence of a restriction |
Privilege is what it costs to grant, and it is what the consent gate reads.
Below medium it is granted without asking, because there is nothing to decide
about reading a directory. mutable: true raises it one step: writing into
someone’s directory costs more than reading it.
extends is inheritance. git-repository is a directory, and serves
where a contract asks for one — the reverse does not hold.
Why the vocabulary is closed
Section titled “Why the vocabulary is closed”An unknown type is an error, on both sides: the CLI refuses to resolve it, and the portal refuses to publish it.
That is deliberate. This is the one part of the spec that the CLI and the portal
have to interpret identically. If it came from a database or from a file in
your project, two portals would have different vocabularies and the same
oren.yaml would mean different things in each.
Admitting an unknown type would also force assuming a privilege for it — and a privilege assumed downwards is exactly what makes the consent gate stay quiet about something expensive.
Asking for a new type
Section titled “Asking for a new type”A new type is a change to the spec, with a release — not configuration. Before asking, check whether you need one at all:
You probably do not. A credential for any cloud is
form: file, sensitive: true, privilege: high declared inline, and that says
everything the engine needs to know. What a name buys is identity —
catalogue search, auto-wiring — not a guarantee.
Seven vendor types used to live in the core and were removed for exactly that
reason: none of them enforced anything beyond the form. Their semantics live
better in the contract’s description, where they are read.
You probably do when the form is new: something that is neither a directory, nor a file, nor a variable, nor a socket, nor a bare capability. That has not happened yet.
What a proposal needs: the name, the form, the privilege and — the part that
matters — why that privilege. engine/docker is critical because the
Docker socket is root on the host; if you cannot write a sentence like that, the
privilege is a guess, and a guessed privilege is worse than no type.
Cardinality
Section titled “Cardinality”The key is the identity; type is an attribute. Declaring several of the
same type is normal:
dependencies: source: { type: git-repository, mutable: true } artifacts: { type: directory, mutable: true } gcpProd: { form: file, sensitive: true, privilege: high } gcpStaging: { form: file, sensitive: true, privilege: high }mutable
Section titled “mutable”Without it, whatever the worker writes is discarded with the container. With it, the change comes back to the host and later steps see it.
It has to be explicit: it is the difference between a task that reads the repository and one that rewrites the working directory of whoever ran it. And it raises the privilege one level.
In the implementation
Section titled “In the implementation”The contract names; the implementation positions:
dependencies: source: mountPath: /source gcpCredential: mountPath: /secrets/gcp-key.json gitToken: env: GIT_TOKEN # the string form arrives as a variableA key that does not exist in the contract is an additional dependency of the
implementation, and must declare type. That is the delta the catalogue
compares.