Skip to content

feat: Migrate API keys from .env file to 1Password #10

Description

@krishagel

Summary

Migrate all API keys and secrets from the iCloud-stored .env file to 1Password for improved security, audit trails, and centralized secret management.

Current State

Secrets stored in: ~/Library/Mobile Documents/com~apple~CloudDocs/Geoffrey/secrets/.env

9 secrets identified across 4 skills:

Secret Used By
FRESHSERVICE_DOMAIN freshservice-manager (10 scripts)
FRESHSERVICE_API_KEY freshservice-manager (10 scripts)
PERPLEXITY_API_KEY research, multi-model-research
GEMINI_API_KEY research, multi-model-research, image-gen (3 scripts)
OPENAI_API_KEY research, multi-model-research
XAI_API_KEY multi-model-research
GOOGLE_CLIENT_ID google-workspace
GOOGLE_CLIENT_SECRET google-workspace
ELEVENLABS_API_KEY elevenlabs-tts (2 scripts)
OBSIDIAN_API_KEY MCP server (external)

Current security concerns:

  • Plain text file on iCloud (synced to cloud)
  • No access audit trail
  • No rotation management
  • All-or-nothing access (no granular permissions)

Proposed Solution

Use 1Password CLI (op) with secret references to load secrets at runtime.

Secret Reference Format

op://Geoffrey/Freshservice/api-key
op://Geoffrey/OpenAI/api-key

Implementation Patterns

Pattern A: Wrapper script (Recommended)

Create scripts/load-secrets.sh:

#!/bin/bash
export FRESHSERVICE_API_KEY="op://Geoffrey/Freshservice/api-key"
export OPENAI_API_KEY="op://Geoffrey/OpenAI/api-key"
# ... etc
op run -- "$@"

Scripts call: ./load-secrets.sh bun myscript.js

Pattern B: Per-script integration

Each script loads its own secrets:

const { execSync } = require('child_process');
const apiKey = execSync('op read "op://Geoffrey/Freshservice/api-key"').toString().trim();

Pattern C: Template .env with op inject

Create .env.tpl:

FRESHSERVICE_API_KEY={{ op://Geoffrey/Freshservice/api-key }}

Generate at runtime: op inject -i .env.tpl -o .env

Requirements

Prerequisites

  • Install 1Password CLI: brew install --cask 1password-cli
  • Enable CLI integration in 1Password desktop app
  • Create "Geoffrey" vault in 1Password

1Password Vault Structure

Create items in "Geoffrey" vault:

Geoffrey/
├── Freshservice
│   ├── domain: psd401.freshservice.com
│   └── api-key: ***
├── OpenAI
│   └── api-key: ***
├── Perplexity
│   └── api-key: ***
├── Gemini
│   └── api-key: ***
├── XAI
│   └── api-key: ***
├── Google-Workspace
│   ├── client-id: ***
│   └── client-secret: ***
├── ElevenLabs
│   └── api-key: ***
└── Obsidian-MCP
    └── api-key: ***

Acceptance Criteria

  • All 9 secrets migrated to 1Password "Geoffrey" vault
  • All skill scripts updated to use 1Password CLI
  • Old .env file deleted from iCloud
  • Documentation updated (CLAUDE.md, skill SKILL.md files)
  • Scripts fail gracefully if 1Password CLI not available

Implementation Plan

Phase 1: Setup (Prerequisites)

  1. Install 1Password CLI
  2. Create Geoffrey vault
  3. Add all 9 secrets to vault

Phase 2: Create Helper (Central Loader)

  1. Create scripts/op-run.sh wrapper
  2. Add fallback for missing op command (error message)

Phase 3: Update Scripts (Skill by Skill)

freshservice-manager (10 scripts):

  • add_note.js, create_ticket.js, get_agent.js, get_approvals.js
  • get_daily_summary.js, get_service_request.js, get_ticket.js
  • get_weekly_summary.js, get_workspaces.js, list_agents.js
  • list_tickets.js, search_tickets.js, update_ticket.js

research (orchestrator.js, agent .md files)

multi-model-research (llm_client.py)

image-gen (compose.py, edit.py, generate.py)

elevenlabs-tts (generate_audio.py, list_voices.py)

google-workspace (oauth_setup.js, token_manager.js)

Phase 4: Documentation

  1. Update CLAUDE.md secret references
  2. Update each skill's SKILL.md
  3. Remove old .env file

Technical Considerations

Backward Compatibility

  • Keep checking for .env as fallback during transition
  • Clear deprecation warnings if .env found

Performance

  • op read adds ~100-200ms per secret fetch
  • Consider caching for scripts with multiple secrets
  • op run loads all secrets once upfront (preferred)

Error Handling

  • Detect missing op CLI with clear error message
  • Detect locked 1Password with unlock prompt
  • Graceful degradation if secrets unavailable

Testing Plan

  • Verify each skill works with 1Password secrets
  • Test on fresh machine without .env file
  • Test error messages when 1Password locked/missing

References

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions