Dependencies
Everything a task requires from your environment is declared in a single list, with a type:
dependencies: source: "." # directory gcpCredential: ./keys/service-account.json # file gitToken: ${env.OREN_GIT_TOKEN} # sensitive value docker: true # access grantedThe key is defined by the contract — you do not choose the name, only how to satisfy it. Each type determines how the value reaches the worker.
| Form | You provide | The worker receives |
|---|---|---|
directory |
a host path | a mounted directory |
file |
a host path | a mounted file, mode 0400 |
string |
a value or ${env.OREN_VAR} |
an environment variable |
endpoint/tcp |
an address, host:<port>, or a provider |
<ENV>, <ENV>_HOST, <ENV>_PORT — see Providers and endpoints |
| socket | true | a mounted socket |
Privilege
Section titled “Privilege”The level has a floor, computed from the form and the flags, and the floor is not negotiable:
| Declaration | Floor |
|---|---|
form: directory |
low |
form: directory, mutable: true |
medium — writing to your working directory costs more than reading it |
any sensitive: true |
medium |
form: capability (network) |
medium |
form: socket |
critical — socket access is equivalent to root on the host |
Whoever writes the contract may declare privilege above the floor, never
below. Below is a validation error, not a preference.
The asymmetry exists because privilege is the one field in the spec that its author benefits from understating: it is what ranks implementations in the catalogue. The floor puts the catastrophic part out of any author’s reach — there is no way to advertise a socket as cheap.
Declaring above is the legitimate case, and it is worth it when the scope is
worse than the form reveals: a token reaching an entire team rather than one
resource. That is what techlite/coolify-deploy does:
coolifyToken: form: string sensitive: true privilege: high description: >- API token with deploy permission. The token's scope is the TEAM, not the application: there is no way to issue one reaching only this resource.The level describes what the credential can do, not what you intend to use it for.
It is also created if it does not exist. A mutable directory is where the
worker writes, and requiring it to already be there would break every first run
in a clean copy — the .oren/artefatos of a CI that has just cloned does not
exist, and git does not version empty directories.
A read directory that does not exist is the opposite: it is a wrong path, and Oren refuses, naming the step and the dependency. Creating it would silently mount an empty directory, and the step would fail later, far from the cause.
Credentials without registering anything
Section titled “Credentials without registering anything”You do not need to store secrets anywhere new. If your organisation already uses Vault or Secret Manager, fetching the secret is just one more task:
- id: creds task: acme/fetch-vault-secrets@^1.0.0 implementation: acme/fetch-vault-secrets-sh inputs: paths: [secret/data/gcp/prod] dependencies: vaultToken: ${env.OREN_VAULT_TOKEN}
- id: push task: techlite/push-docker-image@^1.0.0 implementation: techlite/push-docker-image-skopeo dependencies: registryCredential: ${outputs['creds'].gcpServiceAccount}Values marked as secret never appear in logs, never reach the lockfile and never touch the disk — the CLI materialises the content straight into the container.
The mark is contagious: an ordinary field that interpolates a secret value starts being treated as secret.