Skip to content

Conversation

jemjam
Copy link

@jemjam jemjam commented Sep 3, 2025

Heyo, hopefully you don't consider this new functionality, but feel free to reject if you have another plan. Still, I'm filing this under either "fixes for env specific quirks" (this enables environments that load secrets differently) or "missing standard behavior" (some tools that also use api keys already provide this (or similar methods) for loading secrets).

The big thing this partially/kinda helps protect against is rogue users skimming keys. For security reasons, many users avoid leaving secrets in plain text or even environment variables. Some tooling will allow reading secrets from a command instead. For example, gp.nvim's instructions for password managers, or CodeCompanion's "cmd:" prefix

The main change here is to allow api keys to (also) be loaded from the output of a command. auth.json would allow for a new "type" of apikey: cmd, with the value saved as an array (command plus args). The opencode auth login command is also updated to now let you users pick whether to paste just a key, or use the new command format.

Here's what it looks like:

  • Configure opencode provider (opencode auth login and when it's time for the key, choose to enter a command instead.
  • The 1password command I use is op read "op://some vault/some key/password". See their docs.
  • The value saved for the provider in ~/.local/share/opencode/auth.json is saved as an array: ['op', 'read', "op://some vault/some key/password"] (with type "cmd")
  • When I start opencode, if 1password is currently locked I'm prompted to unlock. Once unlocked, if my 1password has access to that key path, then the key is handed to opencode for that session.
  • If I shut down and lock my system, then I'll have to re-auth again the next time I try to load that value

@@ -10,6 +10,39 @@ import { Global } from "../../global"
import { Plugin } from "../../plugin"
import { Instance } from "../../project/instance"

// Simple command parser that handles quoted strings
function parseCommand(input: string): string[] {
Copy link
Author

@jemjam jemjam Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is admittedly a bit "sloppy", I'm open to other approaches. Initially I just wanted to enable the command format in config. Adding the prompts to auth login required parsing user input though (that would invariably include some type of quote).

@jemjam
Copy link
Author

jemjam commented Sep 4, 2025

I'd heard there was a recent supply chain attack involving nx, though I wasn't aware of the details before this morning.

It sounds like the malicious package would scan for credentials to upload, putting .env or auth.json style files at risk of exposure. Luckily there is a kind of mitigation for this type of attack. Secret management! Have your config point at a placeholder value that is resolved just in time. Then if some rogue user or process gets access to the .env they only actually see placeholders.

1password's own instructions will have you replace the key in configuration with a 1password ref. Then when it comes time to run a command that requires the secret, you just wrap it in an op run -- yourCommand. The wrapper should check you're allowed to read the value, and if authorized, then swap all the references for the real values, before passing control on to the command.

FWIW I did try this; simply configured an env variable as a 1pass reference and tried to op run -- opencode. This should have allowed me to swap that env reference without needing to modify any opencode internals. For simpler builds and deploys, this is usually fine. Unfortunately, 1password's wrapper (which translates that ref) seems to completely break the opencode tui in the process.

Anyways, in light of the attack elsewhere, I just thought I'd come back and reiterate how enabling a change like this could help users protect themselves in similar situations. Let me know if you want any changes or whatever, hopefully it's helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant