2

Consider the following.

node file1.js && react-scripts start

I am trying to make an API call to the GCP Secret Manager in file1.js. After the request is received, I want to set them as environment variables under process.env. After that, I want to access them in the frontend. The browser can't make a call to that Secret Manager without OAuth. Is there any way I can share process.env between these two scripts?

File1 code

const {SecretManagerServiceClient} =  require('@google-cloud/secret-manager');

// Instantiates a client
const client = new SecretManagerServiceClient();

const firebaseKeysResourceId = 'URL'
const  getFireBaseKeys=async()=> {
  const [version] = await client.accessSecretVersion({
    name: firebaseKeysResourceId,
  });

  // Extract the payload as a string.
  const payload = JSON.parse(version?.payload?.data?.toString() || '');
  process.env.TEST= payload.TEST
  return payload
}

getFireBaseKeys()
Unity Hour
  • 550
  • 2
  • 7
  • 22
  • 1
    It's not possible to share data directly via the shell like this. You could: 1. Have `file1.js` print exportable values, then you can `source` or `eval` it like `source $(node file1.js); react-scripts start` 2. Have `file1.js` write to disk and source from disk. 3. Make `file1.js` exec react-scripts from within its own subprocess where it can spawn the environment. – sethvargo Jun 30 '21 at 16:12
  • Environment variables can populate down but not up. As sethvargo says your best option is probably to spawn `react-scripts` from `file1.js`, the child process will by default inherit the environment of the parent. Another option would be to have `file1.js` print *only* the OAUTH key and run it like this to pass in env variable named OAUTH: `OAUTH=$(node file1.js) ./react-scripts start` – leitning Jun 30 '21 at 16:19
  • @leitning Can you expand more on child process? Since the file is async, I don't think your second option will work. Added the code. – Unity Hour Jun 30 '21 at 16:24
  • Spawning processes is always async, the second option will work as bash will wait for the process inside of `$(...)` to complete before moving on. Docs on `child_process.spawn` are here https://nodejs.org/docs/latest-v14.x/api/child_process.html#child_process_child_process_spawn_command_args_options – leitning Jun 30 '21 at 16:29
  • @leitning In the second option, there will be like 5-6 env variable. Will I need to set each of them individually? – Unity Hour Jun 30 '21 at 16:32
  • That will be a pain, then you'd need to print your env variables in valid bash export syntax and use `source` as sethvargo said, but you'll be populating your secrets into the shell as well as passing them on to your script. You're better off spawning from `file1.js`. Alternatively you can compile all your "env" variables into one real env variable and then parse in your script. i.e. ALLENV=$(node file1.js) ./react-script start. where you would print something like `JSON.stringify(mySecrets)` – leitning Jun 30 '21 at 16:34

1 Answers1

1

Expanding on my comment

Method 1 - kind of neat but unneccessary

Supposing you had these vars you wanted in the environment:

const passAlong = {
  FOO: 'bar',
  OAUTH: 'easy-crack',
  N: 'eat'
}

Then at the end of file1.js you would do this

console.log(JSON.stringify(passAlong));

Note you cannot print anything else in file1.js

Then you would call your script like this

PASSALONG=$(node file1.js) react-script start

And at the beginning of react-script you would do this to populate the passed along variables into the environment.

const passAlong = JSON.parse(process.env.PASSALONG);
Object.assign(process.env,passAlong);

Method 2 - what I would do

Using the spawn method would involve just setting process.env how you like in file1.js and then adding something like this at the end of file1.js

// somewhere along the way
process.env.FOO = 'bar';
process.env.OAUTH = 'easy-crack';
process.env.N = 'eat';

// at the end of the script
require('child_process').spawnSync(
  'node', // Calling a node script is really calling node
  [       //   with the script path as the first argument
   '/path/to/react-script', // Using relative path will be relative
   'start'                  //   to where you call this from
  ],                        
  { stdio: 'inherit' }
);
leitning
  • 1,081
  • 1
  • 6
  • 10
  • In method 1, it says. PASSALONG is not recognized as an internal or externalcommand. – Unity Hour Jun 30 '21 at 16:59
  • Bash doesn't allow spaces in var assignment. Make sure it's `PASSALONG=$...` not `PASSALONG = $...` – leitning Jun 30 '21 at 17:01
  • Yup, it is like that. The issue seems to be with $() syntax. – Unity Hour Jun 30 '21 at 17:08
  • What OS are you on? If it's a linux distro what do you get from `echo $SHELL` – leitning Jun 30 '21 at 17:08
  • I am on windows. – Unity Hour Jun 30 '21 at 17:09
  • Aha. You'd have to look up how to (a) pass env variables into a windows process and (b) assign a processes stdout to a variable, I only do linux stuff. Method 2 will still work. *Edit*: or run it in WSL – leitning Jun 30 '21 at 17:11
  • Method 2 immediately exits on windows. child_process.exec commands work. But it does not do a live updates on file change. I used node_modules/react-scripts/bin/react-scripts.js as path – Unity Hour Jun 30 '21 at 17:16
  • Did you put after your async call? `getFireBaseKeys().then(()=>{ /*spawn here*/ })`. Also if your react script is a javascript file then you're really calling node, with the script as an argument. command should be `node` and arguments should be [`require('path').join(__dirname,'node_modules','react-scripts','bin','react-script.js'),'start'] – leitning Jun 30 '21 at 17:25
  • Edited method 2 – leitning Jun 30 '21 at 17:34
  • Thanks a lot. The only issue is it does not do page refresh on file changes that webpack normally does. Any idea ? – Unity Hour Jun 30 '21 at 17:37
  • I'm not sure what that means – leitning Jun 30 '21 at 17:41
  • Suppose I change a file called Component1.js. Then webpack will refresh the chrome browser. I think proper term is hot reloading. – Unity Hour Jun 30 '21 at 17:41
  • I don't know, that's a react thing I assume which is out of my element. – leitning Jun 30 '21 at 17:42
  • This post https://stackoverflow.com/questions/68086920/what-exactly-is-a-webpack-module-in-webpacks-terminology leads me to believe that `webpack` is a separate process than `node`, in which case you may need to change the command from `node` to whatever the webpack executable is called. Check the top of the script for a shebang. If it says something like `#!/usr/bin/webpack-exec` than your executable is probably called `webpack-exec` – leitning Jun 30 '21 at 18:24