Skip to content

v0.15 bridges: qring:// refs, run, setup, push, file backend, AI-stack providers, approval notifications - #94

Merged
I4cTime merged 11 commits into
mainfrom
feat/0.15-bridges
Aug 5, 2026
Merged

v0.15 bridges: qring:// refs, run, setup, push, file backend, AI-stack providers, approval notifications#94
I4cTime merged 11 commits into
mainfrom
feat/0.15-bridges

Conversation

@I4cTime

@I4cTime I4cTime commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Summary

The v0.15 "bridges" feature set, per the council roadmap sequencing — q-ring now reaches outward into .env files, editors, and deployment platforms without a secret value ever leaving the ring unencrypted or unaudited:

  • qring:// secret references (core/refs.ts) — committable pointers for .env files: qring://project/KEY, qring:///KEY (auto scope project→global), ?env= pin. Key lives in the path, never the host (WHATWG parsers lowercase hosts); the key-in-host mistake is rejected with a corrective error, and malformed refs fail loudly.
  • qring run -- <cmd> (core/run.ts) — least-privilege sibling of exec: injects only declared secrets (.q-ring.json manifest + .env refs), fails fast on missing required keys, shares the redaction transform, --dry-run shows the plan.
  • qring setup cursor|kiro|claude (core/setup.ts) — non-destructive MCP-config merge matching the bundled plugins; kiro carries the read-only autoApprove list; claude --global defers to claude mcp add.
  • qring push github|vercel|cloudflare (core/push.ts) — via each platform's own authenticated CLI (gh/vercel/wrangler); values over stdin, never argv; new push audit action.
  • AI-stack liveness providers — anthropic, openrouter, google-ai, groq, huggingface + explicit-only elevenlabs/vercel; keys only ever in headers.
  • Encrypted file backend (core/backend.ts) — QRING_BACKEND=file + QRING_FILE_PASSPHRASE, AES-256-GCM/PBKDF2(210k), explicit-only and fail-closed; secrets, audit anchor, and memory key all route through the shim.
  • Approval notifications (core/notify.ts) — desktop notification on a blocked requiresApproval MCP read, throttled per key, QRING_NOTIFY=off.

Also fixes two latent bugs found en route: withFileLock converted exceptions thrown inside the critical section into bogus 8s lock timeouts, and sk-ant-/sk-or- keys misdetected as OpenAI (bare sk- registered first).

Zero new MCP tools (deliberate — 44 is tool-selection saturation; bridges are CLI-only). 36 new tests; suite is 289.

Type

  • Feature
  • Fix

Checklist

  • pnpm run typecheck passes
  • pnpm run lint passes
  • pnpm run build passes
  • pnpm run test:ci passes
  • CHANGELOG.md updated under [Unreleased] (for user-facing changes)
  • Docs / README updated if behavior changed
  • CLI ↔ MCP parity kept (if a command or tool was added/changed) — new commands are deliberately CLI-only per the roadmap's tool-budget rule

Breaking changes

None. Default backend, exec paths, and MCP surface are unchanged; all new behavior is opt-in.

🤖 Generated with Claude Code

I4cTime and others added 11 commits August 5, 2026 11:28
…ing setup <editor>`

The v0.15 bridge lead: .env files can now hold committable qring://
references instead of values, and one command wires the MCP server into
an editor.

- core/refs.ts: qring://<scope>/KEY[?env=] grammar — key lives in the
  PATH (WHATWG parsers lowercase hosts, which would corrupt env-var
  keys); the key-in-host mistake is rejected with a corrective error.
  Auto-scope (qring:///KEY) resolves project → global.
- core/run.ts: `qring run -- cmd` injects only declared secrets
  (.q-ring.json manifest + refs found in .env), unlike `exec` which
  injects the whole scope. Missing required keys fail fast; output is
  redacted via the shared RedactionTransform. --dry-run shows the plan.
- core/setup.ts: `qring setup cursor|kiro|claude` merges the same
  server entry the bundled plugins ship into the editor's MCP config,
  non-destructively (--force to replace a diverging entry); claude
  --global points at `claude mcp add` instead of touching
  ~/.claude.json.
- exec.ts: extracted enforceExecPolicy + spawnRedacted so run composes
  the same policy/profile/redaction path. CLI-only — no new MCP tools.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…loudflare

Pushes keyring secrets to GitHub Actions, Vercel envs, or Cloudflare
Workers through each platform's own authenticated CLI (gh / vercel /
wrangler) — q-ring never holds platform tokens, and values travel over
the child's stdin, never argv. Default key set is the .q-ring.json
manifest (--keys overrides); missing keys are reported non-fatally,
per-key CLI failures are collected, and every real push lands in the
audit chain as a new "push" action. CLI-only, no new MCP tools.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…google-ai, groq, huggingface, elevenlabs, vercel

New providers use a shared liveness factory (one authenticated GET, the
standard 200/401/403/429 mapping) and only ever send the key in headers,
never the URL. Registration order now puts anthropic (sk-ant-) and
openrouter (sk-or-) ahead of openai, whose bare "sk-" prefix was
shadowing them in auto-detection. ElevenLabs and Vercel have no safe
public prefix and are explicit-only via the secret/manifest provider
field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QRING_BACKEND=file routes every keyring operation (secrets, audit
anchor, agent-memory key) through an AES-256-GCM-encrypted store at
~/.config/q-ring/file-backend.enc (0600), keyed by PBKDF2(210k) from
QRING_FILE_PASSPHRASE. No passphrase → every operation fails closed;
a missing OS keyring never falls back to it silently, consistent with
the v0.14 no-derivable-keys rule. All consumers now import the Entry/
findCredentials shim from core/backend.ts; the default path is the OS
keyring, unchanged.

Also fixes a latent withFileLock bug this surfaced: an exception thrown
inside the critical section was caught by the acquisition retry loop
and resurfaced 8s later as a bogus "could not acquire lock" timeout
instead of propagating (affected throwing JIT/audit callbacks too).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oval

An MCP read denied by requiresApproval now raises a best-effort desktop
notification (notify-send on Linux, osascript on macOS) telling the
user which key is waiting and the exact `qring approve <KEY>` to run —
the human being asked is rarely looking at the agent's window. Strictly
fire-and-forget (a missing notifier never affects the deny), throttled
to once per key per 5 minutes so agent retry loops can't spam, and
disabled with QRING_NOTIFY=off.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd, providers, approval notifications

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New `smithery` job in publish.yml, downstream of the npm/MCP publish
(needs: publish) so a Smithery outage can never block the critical
path: wait for npm to serve the new version (same tolerance pattern as
update-homebrew), build the cross-platform MCPB via
scripts/build-mcpb.mjs, attach qring-<ver>.mcpb to the GitHub release,
publish to i4ctime/q-ring with the pinned smithery CLI, and best-effort
re-apply the listing metadata + icon that bundle publishes reset
(learned 2026-08-04). Auth comes from the SMITHERY_API_KEY repo secret
— set via `qring push github`, dogfooding this branch's new command.
Adds the `build:mcpb` npm script for the manual path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… risk

Adds docs/threat-model.md: assets, trust boundaries, the five attackers
considered, per-surface mitigations (incl. the v0.15 file backend, qring
run, and push bridges), where plaintext can appear, an honest answer to
the agent-exfiltration question, explicit non-goals, and production-key
hardening recommendations. Linked from the README Security section and
SECURITY.md scope; changelog entry under Unreleased.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rvers.org

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…assertion

notify.test.ts assumed a linux host (win32's notifyUser no-ops by
design, so spawn was never called); process.platform is now pinned to
linux for the suite. The file-backend 0600 assertion is skipped on
win32, which has no POSIX mode bits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@I4cTime
I4cTime merged commit 8fe495e into main Aug 5, 2026
9 checks passed
@I4cTime
I4cTime deleted the feat/0.15-bridges branch August 6, 2026 00:56
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