home / skills / plurigrid / asi / keychain-secure

keychain-secure skill

/skills/keychain-secure

This skill securely manages macOS Keychain credentials using GF(3) balanced operations to create, retrieve, and validate secrets.

npx playbooks add skill plurigrid/asi --skill keychain-secure

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
5.7 KB
---
name: keychain-secure
description: macOS Keychain credential management with GF(3) balanced operations
---

# Keychain Secure Skill: GF(3) Balanced Credential Management

**Status**: ✅ Production Ready
**Trit**: -1 (MINUS - validator/security)
**Color**: #2626D8 (Blue)
**Principle**: Store(+1) + Retrieve(0) + Validate(-1) = 0
**Frame**: Never env vars, always Keychain

---

## Overview

**Keychain Secure** provides secure credential storage on macOS with GF(3) conservation. Every credential lifecycle is balanced:

```
Create (+1) → Transport (0) → Consume/Verify (-1) = 0 ✓
```

## GF(3) Triads

```
keychain-secure (-1) ⊗ mdm-cobordism (0) ⊗ gay-mcp (+1) = 0 ✓  [Credential Chain]
keychain-secure (-1) ⊗ unworld (0) ⊗ oapply-colimit (+1) = 0 ✓  [Derivation]
keychain-secure (-1) ⊗ acsets (0) ⊗ koopman-generator (+1) = 0 ✓  [Pattern]
```

## Why Not Environment Variables?

| Storage | Security | Problem |
|---------|----------|---------|
| `export API_KEY=...` | ❌ None | Visible in `ps`, logs, shell history |
| `.env` file | ❌ Minimal | Readable, often committed to git |
| Keychain | ✅ Encrypted | Hardware-backed, ACL-protected |

**Rule**: Secrets belong in Keychain, never in environment.

## Commands

### Store Credential (+1 Generator)

```bash
# Interactive (prompts for password)
security add-generic-password \
    -s "service-name" \
    -a "$USER" \
    -w

# Non-interactive (⚠️ visible in process list briefly)
security add-generic-password \
    -s "service-name" \
    -a "$USER" \
    -w "secret-value" \
    -U  # Update if exists
```

### Retrieve Credential (0 Coordinator)

```bash
# Get password value
security find-generic-password \
    -s "service-name" \
    -a "$USER" \
    -w

# Use in command substitution
export API_KEY=$(security find-generic-password -s "openai" -a "$USER" -w)
```

### Delete Credential (-1 Validator)

```bash
security delete-generic-password \
    -s "service-name" \
    -a "$USER"
```

### Verify Credential (-1 Validator)

```bash
# Check if credential exists and is retrievable
security find-generic-password -s "service-name" -a "$USER" -w >/dev/null 2>&1 \
    && echo "valid" || echo "invalid"
```

## GF(3) Balanced Operations

### Pattern 1: Store-Retrieve-Validate

```bash
# +1: Store
security add-generic-password -s "test" -a "$USER" -w "secret123" -U

# 0: Retrieve  
RETRIEVED=$(security find-generic-password -s "test" -a "$USER" -w)

# -1: Validate
[ "$RETRIEVED" = "secret123" ] && echo "GF(3) = 0 ✓"
```

### Pattern 2: Create-Use-Rotate

```bash
# +1: Create new credential
security add-generic-password -s "api-key-v2" -a "$USER" -w "$NEW_KEY"

# 0: Use credential (transport)
curl -H "Authorization: Bearer $(security find-generic-password -s 'api-key-v2' -a '$USER' -w)" ...

# -1: Delete old credential
security delete-generic-password -s "api-key-v1" -a "$USER"
```

## Python API

```python
from mdm_mcp_server import Keychain, Trit, verify_gf3

# Store (+1)
ok, trit = Keychain.store("openai", "api-key", "sk-...")
assert trit == Trit.PLUS

# Retrieve (0)
secret, trit = Keychain.retrieve("openai", "api-key")
assert trit == Trit.ERGODIC

# Delete (-1)
ok, trit = Keychain.delete("openai", "api-key")
assert trit == Trit.MINUS

# GF(3) balanced operation
ok, trits = Keychain.store_then_verify("service", "account", "secret")
assert verify_gf3(trits)  # [+1, 0, -1] = 0 ✓
```

## Ruby API

```ruby
require 'keychain_secure'

# Store with GF(3) tracking
KeychainSecure.store(
  service: 'openai',
  account: ENV['USER'],
  secret: 'sk-...',
  trit: :plus  # +1
)

# Balanced lifecycle
KeychainSecure.balanced_lifecycle(
  service: 'api-key',
  account: ENV['USER']
) do |secret|
  # Use secret here (trit: 0)
  make_api_call(secret)
end
# Automatic validation on block exit (trit: -1)
```

## Access Control

### Restrict to Specific Apps

```bash
security add-generic-password \
    -s "my-service" \
    -a "$USER" \
    -w "secret" \
    -T "/usr/bin/security" \
    -T "/Applications/MyApp.app"
```

### Require User Confirmation

```bash
# Set ACL to require confirmation
security set-generic-password-partition-list \
    -s "my-service" \
    -a "$USER" \
    -S "apple:"
```

## Integration with MDM

```python
# MDM enrollment with Keychain-backed credentials
from mdm_mcp_server import W1_GENERATE_KEY, Keychain

# Store MDM push certificate
Keychain.store("mdm-push-cert", "apns", push_cert_pem)

# Retrieve for APNS connection
push_cert, _ = Keychain.retrieve("mdm-push-cert", "apns")
```

## Common Services

| Service | Account | Description |
|---------|---------|-------------|
| `openai` | `api-key` | OpenAI API key |
| `anthropic` | `api-key` | Claude API key |
| `github` | `pat` | Personal access token |
| `mdm-push-cert` | `apns` | MDM push certificate |
| `scep-challenge` | `enrollment` | SCEP challenge password |

## Security Best Practices

1. **Use Access Groups** for app-to-app sharing
2. **Set ACLs** to require user presence for sensitive items
3. **Rotate credentials** periodically (create new, delete old)
4. **Never log secrets** — even to debug logs
5. **Verify GF(3)** — ensures complete credential lifecycle

## Anti-Patterns

```bash
# ❌ BAD: Secret in command line (visible in ps)
curl -H "Authorization: Bearer sk-abc123" ...

# ✅ GOOD: Secret from Keychain
curl -H "Authorization: Bearer $(security find-generic-password -s 'openai' -a '$USER' -w)" ...

# ❌ BAD: Secret in environment
export OPENAI_API_KEY="sk-abc123"

# ✅ GOOD: Retrieve when needed
OPENAI_API_KEY=$(security find-generic-password -s 'openai' -a "$USER" -w)
```

---

**Skill Name**: keychain-secure
**Type**: Credential Management / Security
**Trit**: -1 (MINUS)
**Color**: #2626D8 (Blue)
**GF(3)**: Store(+1) + Retrieve(0) + Validate(-1) = 0
**Env Vars**: Never for secrets

Overview

This skill implements macOS Keychain credential management with GF(3) balanced operations to ensure every secret sees a complete lifecycle: create, use/transport, and validate/delete. It enforces never storing secrets in environment variables and provides CLI and language APIs to store, retrieve, and validate credentials securely. The workflow emphasizes hardware-backed encryption, ACLs, and minimal exposure during transport.

How this skill works

The skill uses the macOS security CLI and language bindings to add, find, and delete generic passwords in Keychain while annotating each action with a GF(3) trit (+1 store, 0 retrieve, -1 validate/delete). It supports app-specific ACLs, user-confirmation requirements, and short-lived retrieval patterns so secrets are only exposed when needed. Higher-level helpers implement balanced lifecycles that create new credentials, use them, and then validate or remove older entries to maintain a zero-sum GF(3) state.

When to use it

  • Store API keys, certificates, and tokens on macOS instead of env vars or .env files
  • Provide secrets to local apps with app-scoped ACLs or require user confirmation
  • Rotate credentials safely by creating new entries then deleting old ones
  • Retrieve secrets at runtime for ephemeral use in commands or scripts
  • Validate existence and correctness of secrets during deployment or enrollment flows

Best practices

  • Never place long-term secrets in environment variables or text files
  • Use access groups and explicit -T entries to restrict which apps can access an item
  • Require user presence for highly sensitive keys via ACL/partition lists
  • Rotate credentials: create new (+1), use (0), then delete old (-1) to preserve GF(3) balance
  • Avoid passing secrets on command lines; use secure command substitution or language APIs

Example use cases

  • Store an OpenAI API key in Keychain and retrieve it when launching a local CLI tool
  • MDM enrollment flow: store push certificates and retrieve them only for APNS connections
  • Credential rotation: create api-key-v2, switch services to it, then delete api-key-v1
  • CI step that validates a service credential exists and is retrievable before proceeding
  • A Ruby or Python app that executes a balanced_lifecycle block to automatically validate and clean up secrets

FAQ

Why not use environment variables for secrets?

Environment variables are easily exposed in process lists, logs, and shell history; Keychain offers encrypted, ACL-protected storage with hardware backing.

How do I restrict an item to a specific app?

When adding an item, specify -T entries for allowed binaries or app bundle paths so only those processes can access the secret.

Can I require user confirmation before access?

Yes: set ACLs or partition lists to require user presence for retrieval; this prevents silent programmatic access.