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

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.

@jemjam
Copy link
Author

jemjam commented Oct 20, 2025

I figured out how to get op run working properly for myself, I was making a silly error initially. It doesn't seem like there's interest in this approach, so I'll just close this for now.

@mungodewar
Copy link

I figured out how to get op run working properly for myself, I was making a silly error initially. It doesn't seem like there's interest in this approach, so I'll just close this for now.

👋 I'm interested in what the fix was if you have it handy to share. I think I'm running up against the same tui issue...

@jemjam
Copy link
Author

jemjam commented Dec 18, 2025

If you're using op, by default it will take over (wrap/redirect) shell output to try to mask any logged secrets. That breaks the TUI output, but you can disable it with --no-masking. That solved my TUI problems.

Otherwise, I just launch opencode with a shell alias:

# ~/.config/opencode/.env  
# You can put the 1pass env file wherever you want ofc

# Environment/api keys while working in Opencode
ANTHROPIC_API_KEY="op://..."
OPENAI_API_KEY="op://..."
OPENCODE_API_KEY="op://..."
alias opncd='op run --env-file=$HOME/.config/opencode/.env --no-masking -- opencode'

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.

2 participants