steev/credbridge.sh
Svrnty 2db2d26250 feat(profile): §7 conformance build-out — credbridge, distribution.yaml, cron, manifest
Closes the largest set of PROFILE-DISTRIBUTION-PROTOCOL §7 readiness gaps
surfaced in the 2026-05-23 audit. Profile goes from 4/8 to expected 8/8
once skills/proton-tools/ is committed.

New files:

  credbridge.sh           Personal-assistant variant of the shared-core
                          credbridge pattern. Three credentials in scope:
                          google-workspace (Gmail/Calendar/Contacts),
                          proton-bridge (himalaya IMAP/SMTP), perplexity
                          (raw WebSearch). Plan B marketing platforms
                          explicitly OUT OF SCOPE per CLAUDE.md hard rule.

  validate_access.sh      Emits PASS/BLOCKED/FAIL JSON line per credential.
                          Sourceable from install.sh and standalone. Exit
                          code always 0; status is in the JSON.

  distribution.yaml       Native Hermes install contract (`hermes profile
                          install` reads this). Mirrors cmo/ceo pattern.
                          Documents personal/agnostic naming exception
                          per FRAMEWORK §6.1 — no org suffix because there
                          is exactly one principal.

  cron/steev-daily-briefing.json.template
                          06:30 daily briefing skeleton, ships disabled.
                          Aggregates calendar + flagged emails + due tasks
                          + carried items + brief news scan into a single
                          digest in JP's voice. NEVER auto-sends, NEVER
                          touches business comms (CEO → CMO surface).

manifest.yaml fully rewritten:

  - Added `contract: CONTRACT.md` pointer (was missing)
  - Added inline comment explaining intentional `org:` omission
  - Declared skills/proton-tools (on disk via JP's untracked WIP; declared
    here so manifest matches disk truth once JP commits it)
  - Added `lib:` block (credbridge.sh + validate_access.sh)
  - Added `expected_external_skills:` informational list (google-workspace,
    apple-*, obsidian, himalaya, imessage, perplexity) — these come from
    Hermes' global skills tree per CLAUDE.md "reuse existing core skills"
  - Added `optional_tools:` block (4 MCP servers: proton-calendar/-email/
    -contacts, perplexity)
  - Added `credentials:` block listing the 3 creds + resolution path
  - Promoted `cron:` from empty list to a single steev-daily-briefing
    entry (disabled_on_install: true)
  - Added `sovereignty:` block (qwen3.6-35b-a3b on DGX Spark)

CONTRACT.md frontmatter migrated from legacy `tier: S` to T1 per
FRONTMATTER-SPEC. Added required fields (name, last_reviewed,
description, depends_on).

skills/proton-tools/ left untracked — that's JP's WIP, not mine to
commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 19:01:55 -04:00

95 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# credbridge.sh — resolve credctl credentials into env vars for steev's
# personal-flow tools, then exec the CLI. Secrets NEVER echoed, logged, or
# written to disk.
#
# Usage: credbridge.sh <tool> [args...]
# tools: google-workspace | proton-bridge | perplexity
#
# Per PROFILE-DISTRIBUTION-PROTOCOL §3 (shared core, "credbridge" row) and §6
# (Conventions → Secrets), every profile distribution exposes credentials via
# this verb chain: credctl set → credenv → exec, with secrets per-call only.
#
# This is the personal-assistant variant of the credbridge pattern. Steev's
# cred surface is narrow by design:
#
# - google-workspace: Gmail + Calendar + Contacts (OAuth blob from credctl)
# - proton-bridge: IMAP/SMTP password for the local Proton Bridge T6
# sidecar — gives Steev access to JP's Proton mail via
# himalaya (cleartext on 127.0.0.1 only)
# - perplexity: Perplexity API key for WebSearch toolset (lightweight
# — most Steev work uses the perplexity MCP instead)
#
# Plan B marketing platforms (WooCommerce, Mailchimp, Meta, GA4, etc.) are OUT
# OF SCOPE here — that's cmo-planb's credbridge. Steev MUST NEVER resolve a
# marketing platform credential. The CLAUDE.md "no access to Plan B marketing
# platform credentials" rule is enforced by omission from this case statement.
#
# Design notes (same as cmo/credbridge.sh — shared core):
# - credctl values read into local vars, exported straight to the child env
# - JSON-valued creds (google-workspace OAuth) parsed via `node -e` reading
# from stdin so the value never lands on argv / process list
# - No `echo $secret`. set +x stays off.
set -euo pipefail
# Paths env-overridable for portability; defaults match the JP install.
CREDCTL="${CREDCTL:-/home/svrnty/workspaces/cortex/L6-svrnty.core-credentials/credctl}"
STEEV_LIB="${STEEV_LIB:-/home/svrnty/.hermes/steev}"
die() { printf '{"error":"%s"}\n' "$1" >&2; exit 1; }
[ $# -ge 1 ] || die "usage: credbridge.sh <google-workspace|proton-bridge|perplexity> [args...]"
TOOL="$1"; shift
[ -x "$CREDCTL" ] || die "credctl not found/executable at $CREDCTL"
# cred_raw <name> — print unmasked credential value to stdout. Caller captures
# into a var; value never displayed. Strips the "Value:" header from credctl.
cred_raw() {
"$CREDCTL" get "$1" --unmask 2>/dev/null \
| sed -n '/^Value:/,$p' | sed '1s/^Value:[[:space:]]*//'
}
# json_field <json> <key> — extract a string field via node; value never on argv.
json_field() {
printf '%s' "$1" | node -e '
let s="";process.stdin.on("data",d=>s+=d);
process.stdin.on("end",()=>{try{const o=JSON.parse(s);
const v=o[process.argv[1]];process.stdout.write(v==null?"":String(v));
}catch(e){process.stdout.write("");}});' "$2"
}
case "$TOOL" in
google-workspace)
# Gmail Data API + Calendar API + People API all expect a bearer token
# minted from this service-account / OAuth blob. The blob is JSON; we
# export the whole document so the child CLI can introspect scope.
GW_JSON="$(cred_raw google-workspace)"
[ -n "$GW_JSON" ] || die "credctl: google-workspace not set"
export GOOGLE_WORKSPACE_CREDENTIALS_JSON="$GW_JSON"
exec "$@"
;;
proton-bridge)
# Steev reads JP's Proton inbox via the local Proton Bridge IMAP daemon
# (T6 sidecar — see PROFILE-DISTRIBUTION-PROTOCOL §4.T6). credctl stores
# the bridge password (rotates when JP rotates the bridge).
PB_PASS="$(cred_raw proton-bridge-imap)"
[ -n "$PB_PASS" ] || die "credctl: proton-bridge-imap not set"
export PROTON_BRIDGE_IMAP_PASSWORD="$PB_PASS"
exec "$@"
;;
perplexity)
# Lightweight WebSearch path. Most Steev research goes through the
# perplexity MCP server (which holds its own key); this credbridge entry
# exists for scripts that need a raw key (rare).
PPL_KEY="$(cred_raw perplexity-api)"
[ -n "$PPL_KEY" ] || die "credctl: perplexity-api not set"
export PERPLEXITY_API_KEY="$PPL_KEY"
exec "$@"
;;
*)
die "unknown tool: $TOOL (allowed: google-workspace|proton-bridge|perplexity)"
;;
esac