Skip to content

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.

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.

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.

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.

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.

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.

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 }

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.

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 variable

A 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.