continuedev / continue

⏩ Continue is the leading open-source AI code assistant. You can connect any models and any context to build custom autocomplete and chat experiences inside VS Code and JetBrains
https://docs.continue.dev/
Apache License 2.0
19.59k stars 1.71k forks source link

storing api keys in plain text #1729

Open bachittle opened 4 months ago

bachittle commented 4 months ago

Validations

Problem

I don't like that all the API keys are stored in plain text in a JSON file at the user root. I know that this is required for VSCode, and every other plugin that uses API has to do this. It just doesn't sit right with me.

Solution

At the very least, put a .gitignore at the root of .continue to make sure config.json doesn't get indexed. It may also be possible to write external scripts that encrypt the config.json if the user wants to be security-conscious.

noamross commented 2 months ago

Ideally one should be able to use environment variables for API keys and keep them out of the config entirely.

rashabarbar commented 2 months ago

Another vote. Support for environment variables or alternative secure storage would be a significant improvement.

Astlaan commented 1 month ago

I too would support the idea of retrieving the API keys from the environment variables.

boennemann commented 3 weeks ago

I also feel like .continuerc.json is pretty much impossible to use, if I can't pull in secrets. Otherwise I can't commit this, when the whole point of the file is to share setup with the team? Or is that not the point? Should I gitignore this and let everybody else copy/paste this?

ctwardy commented 2 weeks ago

Putting this into config.ts worked for us, allowing us to write things like ${USERNAME} and ${OPENAI_API_KEY} into our config.json and project-specific .continuerc.json files.

 /**
   * Recursively replace environment variable placeholders in an object.
   * 
   * This function traverses through the provided object and looks for strings 
   * containing placeholders in the format `${VAR_NAME}`. It then replaces 
   * these placeholders with the corresponding values from `process.env`. 
   * If the environment variable is not found, it replaces the placeholder with an empty string.
   * 
   * @param obj - The object in which placeholders should be replaced. This can be a deeply nested object.
   */
  const replaceEnvVars = (obj: any) => {
    for (const key in obj) {
      if (typeof obj[key] === 'string') {
      // Replace placeholders in the format ${VAR_NAME} with the value from process.env
        obj[key] = obj[key].replace(/\$\{(.+?)\}/g, (_: any, varName: string | number) => process.env[varName] || '');
      } else if (typeof obj[key] === 'object' && obj[key] !== null) {
      // Recursively call replaceEnvVars for nested objects
        replaceEnvVars(obj[key]);
      }
    }
  };

  const newConfig = JSON.parse(JSON.stringify(config)); // Create a deep copy of the config object
  replaceEnvVars(newConfig);
  return newConfig;

➛ A good bit of that was written by Continue/GPT as I don't normally typescript. :-)

Probably this should be pulled into the codebase, not required of everyone's custom config. But I'm not sure where.

Note: Continue handles comments in config.json, but not .continuerc.json. I'll make a quick ticket for that.

RomneyDa commented 2 weeks ago

@bachittle @noamross @rashabarbar @boennemann @ctwardy thoughts on this implementation?

RomneyDa commented 2 weeks ago

Would note that this issue is solved way more robustly for teams by Continue for Teams (in beta) since in this case would still need to share config files around and stuff. But this would be good for

ctwardy commented 2 weeks ago

@bachittle @noamross @rashabarbar @boennemann @ctwardy thoughts on this implementation?

Those look good - I'd neglected to support .env but it really should. envFiles is a great idea too, and moustache-format (mumbo-format?) would be a sensible change.

In addition to URLs and API keys, I'd suggest:

Anything we do now can be done with those. And simple is good as extensions are boundless. But they suggest two common cases:

We're tracking the team version and will be interested when we can run the server behind our firewall. Totally understand that's not your first priority. But add a vote for the backlog.

Joilence commented 6 days ago

@RomneyDa , the solution looks great. Only:

by default, the IDE checks .env files at the root of the directory

If directory meaning "current workspace / working directory", there might be a risk.

It seems like a trend that coding assistance tools, including Continue, would build a map of the repo and inject files as context as LLM sees fit (smart context), and it's a risk that .env file could be sent to some remote model provider when the user ask something like "introduce me the structure of this project". Let the tool ignore dot files is sometimes a good practice, but can't promise every tool will do this.

RomneyDa commented 3 days ago

@Joilence good callout, I think to answer your question, for indexing and all directory walking including repo map generation, these files are ignored by default including .env files and anything in .gitignores and .continueignores: https://github.com/continuedev/continue/blob/2c597764cac076a6342625273e43f203b74f2da6/core/indexing/ignore.ts also check out the walkDir function

.env would only be checked when parsing config in that solution

@ctwardy Only supporting CONTINUE_ env variables with mustache templating could be a pretty solid solution. And maybe a select few others like HOME_DIR etc., agree