Using Secrets in Simulation
This guide explains how to use secrets during local development and simulation. When you're simulating a workflow on your local machine with cre workflow simulate, secrets are provided via environment variables or a .env file.
At a high level, the process follows a simple, three-step pattern:
- Declare: You declare the logical names of your secrets in a
secrets.yamlfile. - Provide: You provide the actual secret values in a
.envfile or as environment variables. - Use: You access the secrets in your workflow code using the SDK's secret management API.
This separation of concerns ensures that your workflow code is portable and your secrets are never hard-coded.
Step-by-step guide
Step 1: Declare your secrets (secrets.yaml)
The first step is to create a secrets.yaml file in the root of your project. This file acts as a manifest, defining the "logical names" or "IDs" for the secrets your workflow will use.
In this file, you map a logical name (which you'll use in your workflow code) to one environment variable name that will hold the actual secret value.
Example secrets.yaml:
# in project-root/secrets.yaml
secretsNames:
# This is the logical ID you will use in your workflow code
SECRET_ADDRESS:
# This is the environment variable the CLI will look for
- SECRET_ADDRESS_ALL
Step 2: Provide the secret values
Next, you need to provide the actual values for the secrets. The cre CLI can read these values in two primary ways.
Method 1: Using shell environment variables (Recommended)
You can provide secrets as standard environment variables directly in your shell.
For example, in your terminal:
export SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678"
When you run the cre workflow simulate command in the same terminal session, the CLI will have access to this variable.
Method 2: Using a .env file
Create a .env file in your project's root directory. The cre CLI automatically finds this file and loads the variables defined within it into the environment for your simulation. The variable names here must match those you declared in secrets.yaml.
Example .env file:
# in project-root/.env
# The variable name matches the one in secrets.yaml
SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678"
Step 3: Use the secret in your workflow
Now you can access the secret in your workflow code. The SDK provides a method to retrieve secrets using the logical ID you defined in secrets.yaml.
The following code shows a complete, runnable workflow that triggers on a schedule, fetches a secret, and logs its value.
Example workflow:
| 1 | import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" |
| 2 | โ |
| 3 | // Config can be an empty object if you don't need any parameters from config.json |
| 4 | type Config = Record<string, never> |
| 5 | โ |
| 6 | // Define the logical name of the secret as a constant for clarity |
| 7 | const SECRET_NAME = "SECRET_ADDRESS" |
| 8 | โ |
| 9 | // onCronTrigger is the callback function that gets executed when the cron trigger fires |
| 10 | // This is where you use the secret |
| 11 | const onCronTrigger = (runtime: Runtime<Config>): string => { |
| 12 | // Call runtime.getSecret with the secret's logical ID |
| 13 | const secret = runtime.getSecret({ id: SECRET_NAME }).result() |
| 14 | โ |
| 15 | // Use the secret's value |
| 16 | const secretAddress = secret.value |
| 17 | runtime.log(`Successfully fetched a secret! Address: ${secretAddress}`) |
| 18 | โ |
| 19 | // ... now you can use the secretAddress in your logic ... |
| 20 | return "Success" |
| 21 | } |
| 22 | โ |
| 23 | // initWorkflow is the entry point for the workflow |
| 24 | const initWorkflow = () => { |
| 25 | const cron = new cre.capabilities.CronCapability() |
| 26 | โ |
| 27 | return [cre.handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] |
| 28 | } |
| 29 | โ |
| 30 | // main is the entry point for the WASM binary |
| 31 | export async function main() { |
| 32 | const runner = await Runner.newRunner<Config>() |
| 33 | await runner.run(initWorkflow) |
| 34 | } |
| 35 | โ |
| 36 | main() |
| 37 | โ |
Step 4: Configure secrets path in workflow.yaml
Before simulating, you need to tell the CLI where to find your secrets file. This is configured in your workflow.yaml file under workflow-artifacts.secrets-path.
Open your workflow.yaml file and set the secrets-path:
local-simulation:
user-workflow:
workflow-name: "my-workflow"
workflow-artifacts:
workflow-path: "./main.ts"
config-path: "./config.json"
secrets-path: "../secrets.yaml" # Path to your secrets file
Notice the path ../secrets.yaml. Because the workflow artifacts are relative to the workflow directory, you need to point to the secrets.yaml file located one level up in the project root.
Step 5: Run the simulation
Now you can simulate your workflow:
cre workflow simulate my-workflow --target staging-settings
The CLI will automatically read the secrets-path from your workflow.yaml and load the secrets from your .env file or environment variables you provided in your terminal session.
Fetching multiple secrets
You can fetch multiple secrets by calling the secret retrieval method multiple times within your workflow.
The following example builds on the previous one. First, update your secrets.yaml to declare two secrets:
secretsNames:
SECRET_ADDRESS:
- SECRET_ADDRESS_ALL
API_KEY:
- API_KEY_ALL
Then provide the values in your .env file or export them as environment variables in your terminal session:
export SECRET_ADDRESS_ALL="0x1234567890abcdef1234567890abcdef12345678"
export API_KEY_ALL="your-api-key-here"
Now you can fetch both secrets in your workflow code:
| 1 | import { cre, Runner, type Runtime } from "@chainlink/cre-sdk" |
| 2 | โ |
| 3 | // Config can be an empty object if you don't need any parameters from config.json |
| 4 | type Config = Record<string, never> |
| 5 | โ |
| 6 | const SECRET_ADDRESS_NAME = "SECRET_ADDRESS" |
| 7 | const API_KEY_NAME = "API_KEY" |
| 8 | โ |
| 9 | const onCronTrigger = (runtime: Runtime<Config>): string => { |
| 10 | // 1. Request the first secret |
| 11 | const secretAddress = runtime.getSecret({ id: SECRET_ADDRESS_NAME }).result() |
| 12 | โ |
| 13 | // 2. Request the second secret |
| 14 | const apiKey = runtime.getSecret({ id: API_KEY_NAME }).result() |
| 15 | โ |
| 16 | // 3. Use your secrets |
| 17 | runtime.log(`Successfully fetched secrets! Address: ${secretAddress.value}, API Key: ${apiKey.value}`) |
| 18 | โ |
| 19 | return "Success" |
| 20 | } |
| 21 | โ |
| 22 | // initWorkflow is the entry point for the workflow |
| 23 | const initWorkflow = () => { |
| 24 | const cron = new cre.capabilities.CronCapability() |
| 25 | โ |
| 26 | return [cre.handler(cron.trigger({ schedule: "0 */10 * * * *" }), onCronTrigger)] |
| 27 | } |
| 28 | โ |
| 29 | // main is the entry point for the WASM binary |
| 30 | export async function main() { |
| 31 | const runner = await Runner.newRunner<Config>() |
| 32 | await runner.run(initWorkflow) |
| 33 | } |
| 34 | โ |
| 35 | main() |
| 36 | โ |