Regression: Environment Variables Values Not Working Since v1.18.0
I have checked the following:
- [X] I use the newest version of bruno.
- [X] I've searched existing issues and found nothing related to my issue.
Describe the bug
Since updating to version 1.18.0, environment variables used within the values of other environment variables no longer work as expected. This feature was available and worked correctly since version 1.17.0.
Setup
Let's take a GET request at https://catfact.ninja/fact that retrieves random cat facts via text message every day :
You can see that the URL is a variable, which comes from the environment variables as shown here :
As you can see,
url is also made up of another environment variable Cat.
.bru file to reproduce the bug
environements/Local.bru
vars {
Cat: https://catfact.ninja
url: {{Cat}}/fact
}
cat.bru
meta {
name: cat
type: http
seq: 3
}
get {
url: {{url}}
body: none
auth: none
}
Screenshots/Live demo link
Versions before v1.17.0
I would get an error :
Version v1.17.0
I would get a 200 OK with the wanted response :
Version 1.18.0
But since the 1.18.0 update, I get the same error as I did before version 1.17.0:
@Peperomain
The fix in v1.17.0 was incidental and not a proper one.
For example:
The above scenario doesn't work in v1.17.0 either.
To properly solve this, multi-level interpolation needs to be done.
I do plan on working on this if time permits and based on my other task priorities.
This issue can be overcome through scripting. Do let me know if you need any help with it.
Hi @lohxt1,
Thanks a lot for the quick response and for explaining the situation. I really appreciate it!
About the scripting workaround you mentioned, could you share some tips or examples on how to do this? It'd be super helpful to understand how to handle environment variable interpolation with scripts.
Thanks again for your help!
Cheers, Peperomain
Hey @Peperomain
sure, here's a simple script that'l create a equivalent collection var with the interpolated env var value.
const patternRegex = /\{\{([^}]+)\}\}/g;
const vars = bru.envVariables;
console.log("before:");
console.log(vars);
console.log("-----------------");
const interpolate = (str) => {
return str && str.replaceAll(patternRegex, (match, placeholder) => {
const replacement = vars[placeholder];
return replacement !== undefined
? patternRegex.test(replacement)
? interpolate(replacement)
: replacement
: match;
});
};
let interpolatedVars = {};
Object.entries(vars).map(([key, value]) => {
interpolatedVars[key] = interpolate(value);
bru.setVar(key, interpolate(value));
});
console.log("after:");
console.log(interpolatedVars);
console.log("-----------------");
vars {
host: http://example.com
path: foo
urlWithPath: {{url}}{{path}}/bar
url: https://example.com/
bigUrl: {{urlWithPath}}/baz
}
You can add this in the collection level pre-request script. And since the collection variables hold higher precedence over env vars, interpolated values will be used.
https://github.com/usebruno/bruno/assets/159901171/a781c6ac-1b81-413d-980d-ddb38ab5001b
The above script does not place the value of a a process.env.* variable into Bruno environment variables. Version 1.17.0 does it, but only without the above script.
Given, e.g.:
| Name | Value |
|---|---|
bearer_token |
{{client_id}}:{{client_secret}} |
client_id |
{{process.env.STG_ID}} |
client_secret |
{{process.env.STG_SECRET}} |
where I've defined STG_ID and STG_SECRET in my dotenv file
and using {{bearer_token}} for Auth at the Collection level:
Before the script in v1.18.0+, Bruno sends this as Auth:
...
> Authorization: Bearer {{client_id}}:{{client_secret}}
...
After the script in v1.17.0+, Bruno sends this as Auth:
...
> Authorization: Bearer {{process.env.STG_ID}}:{{process.env.STG_SECRET}}
...
Since this sets the collection vars, the quickest way to undo everything this script does is, unfortunately, to restart Bruno.
Since we sometimes need a temporary Bearer token and other times can use a client ID and secret, it's far easier for us to manage our authorization in our secrets file (as opposed to copy-pasting every time we switch environments).
What's the "right" way to incorporate process.env.* variables into your script?
How can I add my vote to (or help with) getting a "proper" fix in -- one that doesn't need an extra pre-script that sets the collection vars?
From the example above, using v1.17.0+ with the script:
But with v1.17.0 without the script, it grabs the {{process.env.JEFF}} value buzz, but (as you pointed out) cannot get the {{path}} value:
you can modify the script to include process env vars like below
pre-request script
const patternRegex = /\{\{([^}]+)\}\}/g;
const processEnvVars = Object.entries(bru.processEnvVars)?.reduce((acc, [key, value])=>{
acc[`process.env.${key}`] = value;
return acc;
}, {})
const vars = {
...bru.envVariables,
...processEnvVars
};
console.log("before:");
console.log(vars);
console.log("-----------------");
const interpolate = (str) => {
return str && str.replaceAll(patternRegex, (match, placeholder) => {
const replacement = vars[placeholder];
return replacement !== undefined
? patternRegex.test(replacement)
? interpolate(replacement)
: replacement
: match;
});
};
let interpolatedVarKeys = []
let interpolatedVars = {};
Object.entries(vars).map(([key, value]) => {
interpolatedVars[key] = interpolate(value);
bru.setVar(key, interpolate(value));
interpolatedVarKeys.push(key);
});
bru.setVar('temp', JSON.stringify(interpolatedVarKeys));
console.log("after:");
console.log(interpolatedVars);
console.log("-----------------");
and to clear/null the temporarily created collection vars
add the below code to the post-response script
post-response script
const interpolatedVarKeys = [...JSON.parse(bru.getVar('temp')), 'temp'];
interpolatedVarKeys.forEach(key=>bru.setVar(key, null));
https://github.com/usebruno/bruno/assets/25679466/cb6c8997-9d4a-412d-af98-3b913b8c492b
this is in v1.18.0
Environment variables set in pre-requests scripts using bru.setVar are not shown in Collection variables tab at all. Thus, they are also impossible to use in Auth tab, e.g. Bearer token. I can read the variable after I set it in the pre-request script itself, but I cannot access it in either Auth or Variables tab.
Bruno in 1.18.1
Just noticed this post here as I was preparing to report another bug post on this. This is definitely a problem in our enterprise. We will all now have to downgrade to v17.0 to have our scripts working again.
The extra scripting seems to work, but I cannot ask all of our enterprise teams to do this. We will wait for the next fixed version before we upgrade from v1.17.0.
@technodrome you could add your script in the collection pre-request script and use the token in your requests
i have attached a sample bruno collection json this is in v1.18.0
@james-yin could you share a sample bru file or a collection showing what you are doing with the url value in the pre-request script, it would help us understand your use-case better
@lohxt1
I'm attaching my test collection script along with 2 screenshots between v1.17 & v1.19. The issue is how the environment variable is evaluated between 17 and 19. In 17, during 'Pre' script, the env variable was evaluated correct. But in 19, it does not evaluate correctly as you can see from my screenshots.
v1.17 - evaluates env var correctly:
v1.19 - evaluates env var incorrectly:
Here's my simple Bruno collection: bruno-test.zip
Fixed in 1.20.0
this issue is not fixed in v20. if you execute the collection i posted, the problem still exists. i've just created a new bug issue.
this issue is not fixed in v20. if you execute the collection i posted, the problem still exists. i've just created a new bug issue.
Thank you for your feedback, James. In my use case, the issue seems to be resolved in version 20, which is why I closed the issue. It's concerning that it still persists for you. Hopefully, the new bug issue you've created will be resolved soon.
@technodrome you could add your script in the collection pre-request script and use the token in your requests
i have attached a sample bruno collection json this is in v1.18.0
Does not work with 1.20.1. On top of that, declaring something as collection var just to make it work (if it actually did) is not the right approach IMO. Even when I move the script to collection pre-request script section, I see my token using getVar in the dev console but Collection variables do not show this programmatically defined variable and it is also unavailable (red font) in the auth bearer token input field using {{auth_token}}. Broken.
I'll have to stick with Insomnia which even has nice built-in dialogue for these response variables. I do not mind defining things programmatically but it seems completely broken to me.