Skip to content

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 granted

The 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 |

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.

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.