@i4ctime/q-ring 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -1
- package/dist/{chunk-MLBJCPX2.js → chunk-5LFKBZ3Q.js} +62 -7
- package/dist/chunk-5LFKBZ3Q.js.map +1 -0
- package/dist/{chunk-TPPPTL4J.js → chunk-NCM5GHNW.js} +62 -7
- package/dist/chunk-NCM5GHNW.js.map +1 -0
- package/dist/{dashboard-T2UG23KI.js → dashboard-A3GJQCJX.js} +2 -2
- package/dist/{dashboard-TFWCG23R.js → dashboard-R3FWTFFW.js} +2 -2
- package/dist/index.js +285 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +10 -3
- package/dist/mcp.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-MLBJCPX2.js.map +0 -1
- package/dist/chunk-TPPPTL4J.js.map +0 -1
- /package/dist/{dashboard-T2UG23KI.js.map → dashboard-A3GJQCJX.js.map} +0 -0
- /package/dist/{dashboard-TFWCG23R.js.map → dashboard-R3FWTFFW.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/core/envelope.ts","../src/core/collapse.ts","../src/core/observer.ts","../src/core/backend.ts","../src/utils/file-lock.ts","../src/core/entanglement.ts","../src/utils/registry.ts","../src/core/hooks.ts","../src/utils/http-request.ts","../src/core/ssrf.ts","../src/core/approval.ts","../src/core/policy.ts","../src/utils/hash.ts","../src/core/scope.ts","../src/core/notify.ts","../src/core/canary-alert.ts","../src/core/provision.ts","../src/core/keyring.ts","../src/core/tunnel.ts","../src/core/memory.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Package version from `package.json` next to the compiled bundle (`dist/`).\n * Works when the package is installed from npm (package.json ships with dist).\n */\nfunction readPackageVersion(): string {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(here, \"..\", \"package.json\");\n const raw = readFileSync(pkgPath, \"utf8\");\n const pkg = JSON.parse(raw) as { version?: string };\n return typeof pkg.version === \"string\" ? pkg.version : \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\nexport const PACKAGE_VERSION = readPackageVersion();\n","/**\n * Quantum Envelope: the storage format for all q-ring secrets.\n *\n * Instead of storing raw strings, every secret is wrapped in an envelope\n * that carries quantum metadata: environment states (superposition),\n * TTL/expiry (decay), entanglement links, and access tracking (observer).\n */\n\nimport { z } from \"zod\";\n\nexport type Environment = string; // \"dev\" | \"staging\" | \"prod\" | custom\n\nexport interface EntanglementLink {\n /** Service name of the entangled scope */\n service: string;\n /** Key name in the entangled scope */\n key: string;\n}\n\nexport interface SecretMetadata {\n createdAt: string;\n updatedAt: string;\n /** ISO timestamp when this secret expires (quantum decay) */\n expiresAt?: string;\n /** TTL in seconds from creation/update */\n ttlSeconds?: number;\n /** Human-readable description */\n description?: string;\n /** Tags for organization */\n tags?: string[];\n /** Entanglement links to other secrets */\n entangled?: EntanglementLink[];\n /** Total number of times this secret has been read */\n accessCount: number;\n /** ISO timestamp of last read */\n lastAccessedAt?: string;\n /** Whether this secret is ephemeral (tunneling - not persisted to keyring) */\n ephemeral?: boolean;\n /** Format to use when auto-rotating (e.g. \"api-key\", \"password\", \"uuid\") */\n rotationFormat?: string;\n /** Prefix to use when auto-rotating api-key/token formats */\n rotationPrefix?: string;\n /** Provider name for liveness validation (e.g. \"openai\", \"stripe\", \"github\") */\n provider?: string;\n /** Custom validation URL for generic HTTP provider */\n validationUrl?: string;\n /** Whether reading this secret via MCP requires explicit user approval */\n requiresApproval?: boolean;\n /** Just-In-Time (JIT) provisioning provider name (e.g. \"aws-sts\") */\n jitProvider?: string;\n /** Expiration timestamp for the cached JIT credential */\n jitExpiresAt?: string;\n /** Honeytoken: the value is fake and any read fires a loud alert */\n canary?: boolean;\n /** Format the canary value imitates (e.g. \"aws\", \"github\", \"openai\") */\n canaryFormat?: string;\n}\n\nexport interface QuantumEnvelope {\n /** Schema version for forward compatibility */\n v: 1;\n /** Simple value (when not in superposition) */\n value?: string;\n /** Superposition: environment-keyed values */\n states?: Record<Environment, string>;\n /** Default environment to collapse to when no context is available */\n defaultEnv?: Environment;\n /** Quantum metadata */\n meta: SecretMetadata;\n}\n\nconst EntanglementLinkSchema = z.object({\n service: z.string(),\n key: z.string(),\n});\n\nconst SecretMetadataSchema = z.object({\n createdAt: z.string(),\n updatedAt: z.string(),\n expiresAt: z.string().optional(),\n ttlSeconds: z.number().optional(),\n description: z.string().optional(),\n tags: z.array(z.string()).optional(),\n entangled: z.array(EntanglementLinkSchema).optional(),\n accessCount: z.number(),\n lastAccessedAt: z.string().optional(),\n ephemeral: z.boolean().optional(),\n rotationFormat: z.string().optional(),\n rotationPrefix: z.string().optional(),\n provider: z.string().optional(),\n validationUrl: z.string().optional(),\n requiresApproval: z.boolean().optional(),\n jitProvider: z.string().optional(),\n jitExpiresAt: z.string().optional(),\n canary: z.boolean().optional(),\n canaryFormat: z.string().optional(),\n});\n\n/** Runtime validation for persisted envelopes (forward-compatible unknown meta fields stripped). */\nexport const QuantumEnvelopeSchema = z.object({\n v: z.literal(1),\n value: z.string().optional(),\n states: z.record(z.string(), z.string()).optional(),\n defaultEnv: z.string().optional(),\n meta: SecretMetadataSchema,\n});\n\nexport function createEnvelope(\n value: string,\n opts?: Partial<Pick<QuantumEnvelope, \"states\" | \"defaultEnv\">> & {\n description?: string;\n tags?: string[];\n ttlSeconds?: number;\n expiresAt?: string;\n entangled?: EntanglementLink[];\n rotationFormat?: string;\n rotationPrefix?: string;\n provider?: string;\n requiresApproval?: boolean;\n jitProvider?: string;\n canary?: boolean;\n canaryFormat?: string;\n },\n): QuantumEnvelope {\n const now = new Date().toISOString();\n\n let expiresAt = opts?.expiresAt;\n if (!expiresAt && opts?.ttlSeconds) {\n expiresAt = new Date(Date.now() + opts.ttlSeconds * 1000).toISOString();\n }\n\n return {\n v: 1,\n value: opts?.states ? undefined : value,\n states: opts?.states,\n defaultEnv: opts?.defaultEnv,\n meta: {\n createdAt: now,\n updatedAt: now,\n expiresAt,\n ttlSeconds: opts?.ttlSeconds,\n description: opts?.description,\n tags: opts?.tags,\n entangled: opts?.entangled,\n accessCount: 0,\n rotationFormat: opts?.rotationFormat,\n rotationPrefix: opts?.rotationPrefix,\n provider: opts?.provider,\n requiresApproval: opts?.requiresApproval,\n jitProvider: opts?.jitProvider,\n canary: opts?.canary,\n canaryFormat: opts?.canaryFormat,\n },\n };\n}\n\nexport function parseEnvelope(raw: string): QuantumEnvelope | null {\n try {\n const parsed: unknown = JSON.parse(raw);\n const r = QuantumEnvelopeSchema.safeParse(parsed);\n if (r.success) {\n return r.data as QuantumEnvelope;\n }\n } catch {\n // Not a quantum envelope - legacy raw string\n }\n return null;\n}\n\n/**\n * Wrap a legacy raw string value into a quantum envelope.\n * Used for backward compatibility with secrets stored before the envelope format.\n */\nexport function wrapLegacy(rawValue: string): QuantumEnvelope {\n const now = new Date().toISOString();\n return {\n v: 1,\n value: rawValue,\n meta: {\n createdAt: now,\n updatedAt: now,\n accessCount: 0,\n },\n };\n}\n\nexport function serializeEnvelope(envelope: QuantumEnvelope): string {\n return JSON.stringify(envelope);\n}\n\n/**\n * Resolve the concrete value from a quantum envelope.\n * If in superposition, collapses based on the provided environment.\n */\nexport function collapseValue(\n envelope: QuantumEnvelope,\n env?: Environment,\n): string | null {\n if (envelope.states) {\n const targetEnv = env ?? envelope.defaultEnv;\n if (targetEnv && envelope.states[targetEnv]) {\n return envelope.states[targetEnv];\n }\n // If no env match, try default, then return null\n if (envelope.defaultEnv && envelope.states[envelope.defaultEnv]) {\n return envelope.states[envelope.defaultEnv];\n }\n // Last resort: return the first state\n const keys = Object.keys(envelope.states);\n if (keys.length > 0) {\n return envelope.states[keys[0]];\n }\n return null;\n }\n\n return envelope.value ?? null;\n}\n\nexport interface DecayStatus {\n isExpired: boolean;\n isStale: boolean;\n /** Percentage of lifetime elapsed (0-100+) */\n lifetimePercent: number;\n /** Seconds remaining until expiry, or negative if expired */\n secondsRemaining: number | null;\n /** Human-readable time remaining */\n timeRemaining: string | null;\n}\n\nexport function checkDecay(envelope: QuantumEnvelope): DecayStatus {\n if (!envelope.meta.expiresAt) {\n return {\n isExpired: false,\n isStale: false,\n lifetimePercent: 0,\n secondsRemaining: null,\n timeRemaining: null,\n };\n }\n\n const now = Date.now();\n const expires = new Date(envelope.meta.expiresAt).getTime();\n const created = new Date(envelope.meta.createdAt).getTime();\n\n if (!Number.isFinite(expires) || !Number.isFinite(created)) {\n return {\n isExpired: true,\n isStale: true,\n lifetimePercent: 100,\n secondsRemaining: null,\n timeRemaining: \"invalid date\",\n };\n }\n\n const totalLifetime = expires - created;\n const elapsed = now - created;\n const remaining = expires - now;\n\n const lifetimePercent =\n totalLifetime > 0 ? Math.round((elapsed / totalLifetime) * 100) : 100;\n\n const secondsRemaining = Math.floor(remaining / 1000);\n\n let timeRemaining = \"expired\";\n if (remaining > 0) {\n const days = Math.floor(remaining / 86400000);\n const hours = Math.floor((remaining % 86400000) / 3600000);\n const minutes = Math.floor((remaining % 3600000) / 60000);\n\n if (days > 0) timeRemaining = `${days}d ${hours}h`;\n else if (hours > 0) timeRemaining = `${hours}h ${minutes}m`;\n else timeRemaining = `${minutes}m`;\n }\n\n return {\n isExpired: remaining <= 0,\n isStale: lifetimePercent >= 75,\n lifetimePercent,\n secondsRemaining,\n timeRemaining,\n };\n}\n\n/**\n * Record an access event on the envelope (observer effect).\n * Returns a new envelope with updated access metadata.\n */\nexport function recordAccess(envelope: QuantumEnvelope): QuantumEnvelope {\n return {\n ...envelope,\n meta: {\n ...envelope.meta,\n accessCount: envelope.meta.accessCount + 1,\n lastAccessedAt: new Date().toISOString(),\n },\n };\n}\n","/**\n * Wavefunction Collapse: auto-detect the current environment context.\n *\n * Resolution order (first match wins):\n * 1. Explicit --env flag\n * 2. QRING_ENV environment variable\n * 3. NODE_ENV environment variable\n * 4. Git branch heuristics (main/master → prod, develop → dev, staging → staging)\n * 5. .q-ring.json project config\n * 6. Default environment from the envelope\n */\n\nimport { execSync } from \"node:child_process\";\nimport { readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Environment } from \"./envelope.js\";\n\nconst BRANCH_ENV_MAP: Record<string, Environment> = {\n main: \"prod\",\n master: \"prod\",\n production: \"prod\",\n develop: \"dev\",\n development: \"dev\",\n dev: \"dev\",\n staging: \"staging\",\n stage: \"staging\",\n test: \"test\",\n testing: \"test\",\n};\n\n// getSecret/exportSecrets call collapseEnvironment on every read that omits an\n// explicit env; without caching that shelled out `git rev-parse` (sync, up to a\n// 3s timeout) and re-read .q-ring.json on every call, blocking the MCP event\n// loop. Git branch is cached per-cwd for a short window (a branch switch is\n// picked up within the TTL); the config is cached by mtime (always current).\nconst BRANCH_CACHE_TTL_MS = 2000;\nlet branchCache: { cwd: string; at: number; branch: string | null } | null = null;\n\nfunction detectGitBranch(cwd?: string): string | null {\n const dir = cwd ?? process.cwd();\n const now = Date.now();\n if (branchCache && branchCache.cwd === dir && now - branchCache.at < BRANCH_CACHE_TTL_MS) {\n return branchCache.branch;\n }\n let branch: string | null = null;\n try {\n const out = execSync(\"git rev-parse --abbrev-ref HEAD\", {\n cwd: dir,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n encoding: \"utf8\",\n timeout: 3000,\n }).trim();\n branch = out || null;\n } catch {\n // not a git repo / git absent — branch stays null\n }\n branchCache = { cwd: dir, at: now, branch };\n return branch;\n}\n\n/** Reset the collapse caches (config + git branch). Primarily for tests. */\nexport function clearCollapseCache(): void {\n branchCache = null;\n configCache = null;\n}\n\nexport interface ManifestEntry {\n required?: boolean;\n description?: string;\n /** Expected format for auto-rotation (e.g. \"api-key\", \"password\", \"uuid\") */\n format?: string;\n /** Expected prefix (e.g. \"sk-\") */\n prefix?: string;\n /** Provider name for liveness validation (e.g. \"openai\", \"stripe\", \"github\") */\n provider?: string;\n /** Custom validation URL for generic HTTP provider */\n validationUrl?: string;\n}\n\nexport interface ProjectConfig {\n env?: Environment;\n defaultEnv?: Environment;\n branchMap?: Record<string, Environment>;\n /** Secrets manifest — declares required/expected secrets for this project */\n secrets?: Record<string, ManifestEntry>;\n /** Governance policy for MCP, exec, and secret lifecycle */\n policy?: import(\"./policy.js\").PolicyConfig;\n}\n\nlet configCache: { path: string; mtimeMs: number; config: ProjectConfig | null } | null = null;\n\nexport function readProjectConfig(projectPath?: string): ProjectConfig | null {\n const configPath = join(projectPath ?? process.cwd(), \".q-ring.json\");\n let mtimeMs = 0;\n try {\n mtimeMs = statSync(configPath).mtimeMs;\n } catch {\n // absent — mtimeMs stays 0 as a stable sentinel\n }\n if (configCache && configCache.path === configPath && configCache.mtimeMs === mtimeMs) {\n return configCache.config;\n }\n let config: ProjectConfig | null = null;\n if (mtimeMs > 0) {\n try {\n config = JSON.parse(readFileSync(configPath, \"utf8\")) as ProjectConfig;\n } catch {\n config = null; // invalid config\n }\n }\n configCache = { path: configPath, mtimeMs, config };\n return config;\n}\n\nexport interface CollapseContext {\n /** Explicitly provided environment */\n explicit?: Environment;\n /** Project path for git/config detection */\n projectPath?: string;\n}\n\nexport interface CollapseResult {\n env: Environment;\n source:\n | \"explicit\"\n | \"QRING_ENV\"\n | \"NODE_ENV\"\n | \"git-branch\"\n | \"project-config\"\n | \"default\";\n}\n\nexport function collapseEnvironment(\n ctx: CollapseContext = {},\n): CollapseResult | null {\n if (ctx.explicit) {\n return { env: ctx.explicit, source: \"explicit\" };\n }\n\n const qringEnv = process.env.QRING_ENV;\n if (qringEnv) {\n return { env: qringEnv, source: \"QRING_ENV\" };\n }\n\n const nodeEnv = process.env.NODE_ENV;\n if (nodeEnv) {\n const mapped = mapEnvName(nodeEnv);\n return { env: mapped, source: \"NODE_ENV\" };\n }\n\n const config = readProjectConfig(ctx.projectPath);\n if (config?.env) {\n return { env: config.env, source: \"project-config\" };\n }\n\n const branch = detectGitBranch(ctx.projectPath);\n if (branch) {\n const branchMap = { ...BRANCH_ENV_MAP, ...config?.branchMap };\n const mapped = branchMap[branch] ?? matchGlob(branchMap, branch);\n if (mapped) {\n return { env: mapped, source: \"git-branch\" };\n }\n }\n\n if (config?.defaultEnv) {\n return { env: config.defaultEnv, source: \"project-config\" };\n }\n\n return null;\n}\n\n/**\n * Match a branch name against glob-style patterns in the branchMap.\n * Supports `*` as a wildcard (e.g., `release/*`, `feature/*`).\n */\nconst MAX_BRANCH_GLOB_PATTERN_LEN = 200;\nconst MAX_BRANCH_GLOB_REGEX_SOURCE = 400;\n\nfunction matchGlob(\n branchMap: Record<string, Environment>,\n branch: string,\n): Environment | undefined {\n for (const [pattern, env] of Object.entries(branchMap)) {\n if (!pattern.includes(\"*\")) continue;\n if (pattern.length > MAX_BRANCH_GLOB_PATTERN_LEN) continue;\n const source = \"^\" + pattern.replace(/\\*/g, \".*\") + \"$\";\n if (source.length > MAX_BRANCH_GLOB_REGEX_SOURCE) continue;\n const regex = new RegExp(source);\n if (regex.test(branch)) return env;\n }\n return undefined;\n}\n\nfunction mapEnvName(raw: string): Environment {\n const lower = raw.toLowerCase();\n if (lower === \"production\") return \"prod\";\n if (lower === \"development\") return \"dev\";\n return lower;\n}\n","/**\n * Observer Effect: every secret read/write/delete is logged.\n * Audit trail stored at ~/.config/q-ring/audit.jsonl\n *\n * The act of observation changes the state — each access increments\n * the envelope's access counter and records a timestamp.\n *\n * Hash-chain integrity: each event includes a SHA-256 hash of the\n * previous event, creating a tamper-evident chain. If any event is\n * modified or deleted, the chain breaks and `audit:verify` reports it.\n */\n\nimport {\n existsSync,\n mkdirSync,\n appendFileSync,\n chmodSync,\n readFileSync,\n openSync,\n fstatSync,\n readSync,\n closeSync,\n statSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createHash, createHmac, randomBytes } from \"node:crypto\";\nimport { Entry } from \"./backend.js\";\nimport { withFileLock } from \"../utils/file-lock.js\";\n\n// The audit chain's tamper-evidence root is a keyed anchor — the HMAC of the\n// head line — stored in the OS keyring, OUTSIDE the log file. The per-line\n// SHA-256 chain (below) stays for cheap in-file consistency and backward\n// compatibility, but it's forgeable on its own (no secret). The keyed anchor is\n// what defeats tail-truncation and full-file rewrite: an attacker who can write\n// audit.jsonl still can't produce a head line whose HMAC matches the anchor, nor\n// update the anchor, without OS-keyring access. Fixed key, never rotated.\nconst AUDIT_KEYRING_SERVICE = \"qring-audit-chain\";\nconst AUDIT_KEY_ACCOUNT = \"hmac-key\";\nconst AUDIT_ANCHOR_ACCOUNT = \"chain-head\";\n\nlet warnedNoKeyring = false;\n\n/** Random HMAC key from the OS keyring, or null (with a one-time warning). */\nfunction getAuditKey(): Buffer | null {\n try {\n const entry = new Entry(AUDIT_KEYRING_SERVICE, AUDIT_KEY_ACCOUNT);\n const stored = entry.getPassword();\n if (stored) return Buffer.from(stored, \"base64\");\n const key = randomBytes(32);\n entry.setPassword(key.toString(\"base64\"));\n return key;\n } catch {\n if (!warnedNoKeyring) {\n console.error(\n \"q-ring: WARNING — OS keyring unavailable; the audit chain has no keyed \" +\n \"anchor on this host and is NOT tamper-evident against truncation or \" +\n \"full-file rewrite. (In-file SHA-256 chaining still detects edits.)\",\n );\n warnedNoKeyring = true;\n }\n return null;\n }\n}\n\nfunction headAnchor(line: string, key: Buffer): string {\n return createHmac(\"sha256\", key).update(line).digest(\"hex\");\n}\n\nfunction readStoredAnchor(): string | null {\n try {\n return new Entry(AUDIT_KEYRING_SERVICE, AUDIT_ANCHOR_ACCOUNT).getPassword() ?? null;\n } catch {\n return null;\n }\n}\n\nfunction writeStoredAnchor(hash: string): void {\n try {\n new Entry(AUDIT_KEYRING_SERVICE, AUDIT_ANCHOR_ACCOUNT).setPassword(hash);\n } catch {\n /* ignore — anchor is best-effort when the keyring is unavailable */\n }\n}\n\nexport type AuditAction =\n | \"read\"\n | \"write\"\n | \"delete\"\n | \"list\"\n | \"export\"\n | \"generate\"\n | \"entangle\"\n | \"tunnel\"\n | \"teleport\"\n | \"collapse\"\n | \"approve\"\n | \"revoke\"\n | \"policy_deny\"\n | \"rotate\"\n | \"push\"\n | \"canary\"\n | \"wrap\";\n\nexport interface AuditEvent {\n timestamp: string;\n action: AuditAction;\n key?: string;\n scope?: string;\n env?: string;\n source: \"cli\" | \"mcp\" | \"agent\" | \"api\" | \"hook\" | \"ci\";\n detail?: string;\n pid: number;\n /** SHA-256 hash of the previous event line for chain integrity */\n prevHash?: string;\n /** Correlation ID to group related events across a single operation */\n correlationId?: string;\n /**\n * Client-supplied agent label (MCP clientInfo name@version). Audit metadata\n * ONLY — it is trivially spoofable and must never gate authorization.\n */\n agent?: string;\n}\n\nlet auditAgentLabel: string | null = null;\n\n/**\n * Set the agent label stamped on subsequent audit events from this process.\n * The label comes from the MCP initialize handshake (clientInfo) and is\n * untrusted input: printable ASCII only, capped at 128 chars.\n */\nexport function setAuditAgentLabel(label: string | null): void {\n if (label === null) {\n auditAgentLabel = null;\n return;\n }\n const cleaned = label.replace(/[^\\x20-\\x7e]/g, \"\").trim().slice(0, 128);\n auditAgentLabel = cleaned.length > 0 ? cleaned : null;\n}\n\nexport function getAuditAgentLabel(): string | null {\n return auditAgentLabel;\n}\n\nfunction getAuditDir(): string {\n if (process.env.QRING_AUDIT_DIR) {\n if (!existsSync(process.env.QRING_AUDIT_DIR)) {\n mkdirSync(process.env.QRING_AUDIT_DIR, { recursive: true, mode: 0o700 });\n }\n return process.env.QRING_AUDIT_DIR;\n }\n const dir = join(homedir(), \".config\", \"q-ring\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n return dir;\n}\n\nfunction getAuditPath(): string {\n return join(getAuditDir(), \"audit.jsonl\");\n}\n\nfunction getLastLineHash(): string | undefined {\n const path = getAuditPath();\n if (!existsSync(path)) return undefined;\n\n try {\n const fd = openSync(path, \"r\");\n const stat = fstatSync(fd);\n if (stat.size === 0) {\n closeSync(fd);\n return undefined;\n }\n\n // Read up to the last 8KB to find the last line\n const tailSize = Math.min(stat.size, 8192);\n const buf = Buffer.alloc(tailSize);\n readSync(fd, buf, 0, tailSize, stat.size - tailSize);\n closeSync(fd);\n\n const tail = buf.toString(\"utf8\");\n const lines = tail.split(\"\\n\").filter((l) => l.trim());\n if (lines.length === 0) return undefined;\n\n const lastLine = lines[lines.length - 1];\n return createHash(\"sha256\").update(lastLine).digest(\"hex\");\n } catch {\n return undefined;\n }\n}\n\nexport function logAudit(\n event: Omit<AuditEvent, \"timestamp\" | \"pid\" | \"prevHash\">,\n): void {\n try {\n // Reading the previous head, appending, and updating the keyed anchor must\n // be one atomic critical section — otherwise two concurrent writers (MCP +\n // CLI + dashboard) can compute the same prevHash/anchor and branch the chain.\n // Reuses the same on-disk lock as the JIT path (B1).\n withFileLock(\n \"audit-chain\",\n () => {\n const prevHash = getLastLineHash();\n const full: AuditEvent = {\n ...event,\n timestamp: new Date().toISOString(),\n pid: process.pid,\n prevHash,\n };\n if (full.agent === undefined && auditAgentLabel) {\n full.agent = auditAgentLabel;\n }\n const line = JSON.stringify(full);\n const path = getAuditPath();\n appendFileSync(path, line + \"\\n\", { mode: 0o600 });\n // `mode` only applies when appendFileSync creates the file; chmod fixes\n // the perms of a log created by an older (world-readable) version.\n try {\n chmodSync(path, 0o600);\n } catch {\n /* ignore */\n }\n // Advance the keyed anchor to the HMAC of the new head line.\n const key = getAuditKey();\n if (key) writeStoredAnchor(headAnchor(line, key));\n },\n { timeoutMs: 5000 },\n );\n } catch {\n // audit logging (incl. a lock timeout) must never crash the app\n }\n}\n\nexport interface AuditQuery {\n key?: string;\n action?: AuditAction;\n since?: string;\n limit?: number;\n source?: AuditEvent[\"source\"];\n correlationId?: string;\n agent?: string;\n}\n\n/** Cap bytes read from audit log to avoid loading multi-GB files into memory. */\nconst MAX_AUDIT_BYTES = 12 * 1024 * 1024;\n\nexport function queryAudit(query: AuditQuery = {}): AuditEvent[] {\n const path = getAuditPath();\n if (!existsSync(path)) return [];\n\n try {\n const st = statSync(path);\n const readStart = st.size > MAX_AUDIT_BYTES ? st.size - MAX_AUDIT_BYTES : 0;\n const readLen = st.size > MAX_AUDIT_BYTES ? MAX_AUDIT_BYTES : st.size;\n const buf = Buffer.alloc(readLen);\n const fd = openSync(path, \"r\");\n readSync(fd, buf, 0, readLen, readStart);\n closeSync(fd);\n let text = buf.toString(\"utf8\");\n if (readStart > 0) {\n const firstNl = text.indexOf(\"\\n\");\n if (firstNl !== -1) text = text.slice(firstNl + 1);\n }\n const lines = text.split(\"\\n\").filter((l) => l.trim());\n\n let events: AuditEvent[] = lines\n .map((line) => {\n try {\n return JSON.parse(line) as AuditEvent;\n } catch {\n return null;\n }\n })\n .filter((e): e is AuditEvent => e !== null);\n\n if (query.key) events = events.filter((e) => e.key === query.key);\n if (query.action) events = events.filter((e) => e.action === query.action);\n if (query.source) events = events.filter((e) => e.source === query.source);\n if (query.correlationId) events = events.filter((e) => e.correlationId === query.correlationId);\n if (query.agent) events = events.filter((e) => e.agent === query.agent);\n if (query.since) {\n const since = new Date(query.since).getTime();\n events = events.filter((e) => new Date(e.timestamp).getTime() >= since);\n }\n\n events.sort(\n (a, b) =>\n new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n\n if (query.limit) events = events.slice(0, query.limit);\n\n return events;\n } catch {\n return [];\n }\n}\n\nexport interface VerifyResult {\n totalEvents: number;\n validEvents: number;\n brokenAt?: number;\n brokenEvent?: AuditEvent;\n intact: boolean;\n /** Set when the break is explained by something other than a per-line hash. */\n reason?: string;\n}\n\n/**\n * Verify the hash-chain integrity of the entire audit log.\n * Returns the first break point if the chain has been tampered with.\n */\nexport function verifyAuditChain(): VerifyResult {\n const path = getAuditPath();\n if (!existsSync(path)) {\n return { totalEvents: 0, validEvents: 0, intact: true };\n }\n\n const lines = readFileSync(path, \"utf8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n if (lines.length === 0) {\n return { totalEvents: 0, validEvents: 0, intact: true };\n }\n\n let validEvents = 0;\n\n for (let i = 0; i < lines.length; i++) {\n let event: AuditEvent;\n try {\n event = JSON.parse(lines[i]);\n } catch {\n return {\n totalEvents: lines.length,\n validEvents,\n brokenAt: i,\n intact: false,\n };\n }\n\n if (i === 0) {\n validEvents++;\n continue;\n }\n\n const expectedHash = createHash(\"sha256\")\n .update(lines[i - 1])\n .digest(\"hex\");\n\n if (event.prevHash !== expectedHash) {\n return {\n totalEvents: lines.length,\n validEvents,\n brokenAt: i,\n brokenEvent: event,\n intact: false,\n };\n }\n\n validEvents++;\n }\n\n // Keyed-anchor check: the head line's HMAC must match the anchor stored in the\n // keyring. This is what catches tail truncation (the head line changed) and a\n // full self-consistent rewrite (the attacker can't recompute a matching HMAC\n // without the key). Only enforced when both a key and a stored anchor exist —\n // a keyless host, or a log predating the anchor, degrades to per-line checks.\n const key = getAuditKey();\n const anchor = key ? readStoredAnchor() : null;\n if (key && anchor !== null) {\n const head = headAnchor(lines[lines.length - 1], key);\n if (head !== anchor) {\n return {\n totalEvents: lines.length,\n validEvents,\n brokenAt: lines.length - 1,\n intact: false,\n reason:\n \"audit head does not match the keyed anchor in the OS keyring — the \" +\n \"log was truncated or rewritten\",\n };\n }\n }\n\n return { totalEvents: lines.length, validEvents, intact: true };\n}\n\nexport interface ExportOptions {\n since?: string;\n until?: string;\n format?: \"jsonl\" | \"json\" | \"csv\";\n}\n\n/**\n * Export audit events in a portable format, optionally filtered by time range.\n */\nexport function exportAudit(opts: ExportOptions = {}): string {\n const path = getAuditPath();\n if (!existsSync(path)) return opts.format === \"json\" ? \"[]\" : \"\";\n\n const lines = readFileSync(path, \"utf8\")\n .split(\"\\n\")\n .filter((l) => l.trim());\n\n let events: AuditEvent[] = lines\n .map((l) => {\n try {\n return JSON.parse(l) as AuditEvent;\n } catch {\n return null;\n }\n })\n .filter((e): e is AuditEvent => e !== null);\n\n if (opts.since) {\n const since = new Date(opts.since).getTime();\n events = events.filter((e) => new Date(e.timestamp).getTime() >= since);\n }\n if (opts.until) {\n const until = new Date(opts.until).getTime();\n events = events.filter((e) => new Date(e.timestamp).getTime() <= until);\n }\n\n if (opts.format === \"json\") {\n return JSON.stringify(events, null, 2);\n }\n\n if (opts.format === \"csv\") {\n const header = \"timestamp,action,key,scope,env,source,agent,pid,correlationId,detail\";\n const rows = events.map(\n (e) =>\n `${e.timestamp},${e.action},${e.key ?? \"\"},${e.scope ?? \"\"},${e.env ?? \"\"},${e.source},${(e.agent ?? \"\").replace(/,/g, \";\")},${e.pid},${e.correlationId ?? \"\"},${(e.detail ?? \"\").replace(/,/g, \";\")}`,\n );\n return [header, ...rows].join(\"\\n\");\n }\n\n return events.map((e) => JSON.stringify(e)).join(\"\\n\");\n}\n\nexport interface AccessAnomaly {\n type: \"burst\" | \"unusual-hour\" | \"new-source\" | \"tampered\";\n description: string;\n events: AuditEvent[];\n}\n\nexport function detectAnomalies(key?: string): AccessAnomaly[] {\n const recent = queryAudit({\n key,\n action: \"read\",\n since: new Date(Date.now() - 3600000).toISOString(),\n });\n\n const anomalies: AccessAnomaly[] = [];\n\n if (key && recent.length > 50) {\n anomalies.push({\n type: \"burst\",\n description: `${recent.length} reads of \"${key}\" in the last hour`,\n events: recent.slice(0, 10),\n });\n }\n\n const nightAccess = recent.filter((e) => {\n const hour = new Date(e.timestamp).getHours();\n return hour >= 1 && hour < 5;\n });\n\n if (nightAccess.length > 0) {\n anomalies.push({\n type: \"unusual-hour\",\n description: `${nightAccess.length} access(es) during unusual hours (1am-5am)`,\n events: nightAccess,\n });\n }\n\n const verification = verifyAuditChain();\n if (!verification.intact) {\n anomalies.push({\n type: \"tampered\",\n description: `Audit chain broken at event #${verification.brokenAt}`,\n events: verification.brokenEvent ? [verification.brokenEvent] : [],\n });\n }\n\n return anomalies;\n}\n","/**\n * Keyring Backend Selection\n *\n * Every module that used to talk to `@napi-rs/keyring` directly goes through\n * this shim instead. Two backends:\n *\n * - `keyring` (default): the OS keychain via @napi-rs/keyring — unchanged\n * behavior.\n * - `file` (opt-in, `QRING_BACKEND=file`): an AES-256-GCM-encrypted JSON\n * store for hosts with no Secret Service at all (headless Linux, CI,\n * containers). The key is derived from `QRING_FILE_PASSPHRASE` via PBKDF2;\n * with no passphrase set, every operation fails closed — consistent with\n * the v0.14 rule that q-ring never encrypts under a machine-derivable key.\n *\n * The file backend is deliberately explicit-only: a missing OS keyring does\n * NOT silently fall back to it, because silent fallback would change the\n * at-rest security story without the user choosing it.\n */\n\nimport { Entry as NapiEntry, findCredentials as napiFindCredentials } from \"@napi-rs/keyring\";\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync } from \"node:crypto\";\nimport { withFileLock } from \"../utils/file-lock.js\";\n\nconst PASSPHRASE_ENV = \"QRING_FILE_PASSPHRASE\";\nconst BACKEND_ENV = \"QRING_BACKEND\";\nconst PATH_ENV = \"QRING_FILE_BACKEND_PATH\";\n\nconst PBKDF2_ITERATIONS = 210_000; // OWASP 2023 floor, matches memory.ts/teleport.ts\nconst KEY_LENGTH = 32;\nconst FILE_PREFIX = \"qfile1\"; // qfile1:<saltB64>:<iv>:<tag>:<ciphertext>\n\nexport class BackendUnavailableError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BackendUnavailableError\";\n }\n}\n\nexport type BackendName = \"keyring\" | \"file\";\n\nexport function activeBackend(): BackendName {\n const requested = process.env[BACKEND_ENV];\n if (requested === \"file\") return \"file\";\n if (requested && requested !== \"keyring\") {\n throw new BackendUnavailableError(\n `Unknown ${BACKEND_ENV} \"${requested}\" — expected \"keyring\" or \"file\".`,\n );\n }\n return \"keyring\";\n}\n\n// ─── File backend ───\n\nfunction storePath(): string {\n return (\n process.env[PATH_ENV] ??\n join(homedir(), \".config\", \"q-ring\", \"file-backend.enc\")\n );\n}\n\nfunction passphrase(): string {\n const p = process.env[PASSPHRASE_ENV];\n if (!p) {\n throw new BackendUnavailableError(\n `${BACKEND_ENV}=file requires ${PASSPHRASE_ENV} to be set. q-ring refuses to ` +\n `store secrets under a machine-derivable key — set a strong passphrase, or ` +\n `use the OS keyring backend.`,\n );\n }\n return p;\n}\n\n// PBKDF2 at 210k iterations costs real time; the salt is stable per store\n// file, so cache the derived key for the (salt, passphrase) pair in-process.\nlet keyCache: { salt: string; pass: string; key: Buffer } | null = null;\n\nfunction deriveKey(saltB64: string): Buffer {\n const pass = passphrase();\n if (keyCache && keyCache.salt === saltB64 && keyCache.pass === pass) {\n return keyCache.key;\n }\n const key = pbkdf2Sync(pass, Buffer.from(saltB64, \"base64\"), PBKDF2_ITERATIONS, KEY_LENGTH, \"sha512\");\n keyCache = { salt: saltB64, pass, key };\n return key;\n}\n\ntype StoreMap = Record<string, string>;\n\nfunction loadStore(): { map: StoreMap; salt: string } {\n const path = storePath();\n if (!existsSync(path)) {\n return { map: {}, salt: randomBytes(16).toString(\"base64\") };\n }\n\n const blob = readFileSync(path, \"utf8\").trim();\n const parts = blob.split(\":\");\n if (parts.length !== 5 || parts[0] !== FILE_PREFIX) {\n throw new BackendUnavailableError(\n `${path} is not a valid q-ring file-backend store (expected ${FILE_PREFIX}:...).`,\n );\n }\n const [, salt, ivB64, tagB64, ctB64] = parts;\n\n const decipher = createDecipheriv(\"aes-256-gcm\", deriveKey(salt), Buffer.from(ivB64, \"base64\"));\n decipher.setAuthTag(Buffer.from(tagB64, \"base64\"));\n let plaintext: string;\n try {\n plaintext = decipher.update(Buffer.from(ctB64, \"base64\")) + decipher.final(\"utf8\");\n } catch {\n throw new BackendUnavailableError(\n `Cannot decrypt ${path} — wrong ${PASSPHRASE_ENV}, or the store was tampered with.`,\n );\n }\n return { map: JSON.parse(plaintext) as StoreMap, salt };\n}\n\nfunction saveStore(map: StoreMap, salt: string): void {\n const path = storePath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", deriveKey(salt), iv);\n const ct = Buffer.concat([cipher.update(JSON.stringify(map), \"utf8\"), cipher.final()]);\n const blob = [\n FILE_PREFIX,\n salt,\n iv.toString(\"base64\"),\n cipher.getAuthTag().toString(\"base64\"),\n ct.toString(\"base64\"),\n ].join(\":\");\n\n writeFileSync(path, blob + \"\\n\", { mode: 0o600 });\n try {\n chmodSync(path, 0o600);\n } catch {\n /* best-effort */\n }\n}\n\nconst SEP = \"\\0\";\n\nfunction fileMutate<T>(fn: (map: StoreMap) => T): T {\n return withFileLock(\"file-backend\", () => {\n const { map, salt } = loadStore();\n const result = fn(map);\n saveStore(map, salt);\n return result;\n });\n}\n\n// ─── Uniform interface ───\n\n/**\n * Drop-in for @napi-rs/keyring's Entry, routed to the active backend.\n * Backend choice is evaluated per call, not at import time, so tests and\n * long-lived processes see env changes.\n */\nexport class Entry {\n private napi?: NapiEntry;\n\n constructor(\n private readonly service: string,\n private readonly account: string,\n ) {}\n\n private delegate(): NapiEntry {\n this.napi ??= new NapiEntry(this.service, this.account);\n return this.napi;\n }\n\n private storeKey(): string {\n return `${this.service}${SEP}${this.account}`;\n }\n\n getPassword(): string | null {\n if (activeBackend() === \"file\") {\n return loadStore().map[this.storeKey()] ?? null;\n }\n return this.delegate().getPassword();\n }\n\n setPassword(password: string): void {\n if (activeBackend() === \"file\") {\n fileMutate((map) => {\n map[this.storeKey()] = password;\n });\n return;\n }\n this.delegate().setPassword(password);\n }\n\n deleteCredential(): boolean {\n if (activeBackend() === \"file\") {\n return fileMutate((map) => {\n const existed = this.storeKey() in map;\n delete map[this.storeKey()];\n return existed;\n });\n }\n return this.delegate().deleteCredential();\n }\n\n // @napi-rs/keyring's other delete alias, used by `qring doctor`.\n deletePassword(): boolean {\n return this.deleteCredential();\n }\n}\n\nexport function findCredentials(service: string): { account: string; password: string }[] {\n if (activeBackend() === \"file\") {\n const { map } = loadStore();\n const prefix = `${service}${SEP}`;\n return Object.entries(map)\n .filter(([k]) => k.startsWith(prefix))\n .map(([k, password]) => ({ account: k.slice(prefix.length), password }));\n }\n return napiFindCredentials(service);\n}\n","import {\n mkdirSync,\n writeFileSync,\n unlinkSync,\n readFileSync,\n statSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n/** Non-spinning synchronous sleep — yields the CPU instead of busy-waiting. */\nfunction sleepSync(ms: number): void {\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n}\n\n/** True if a process with this pid exists (EPERM = exists but not ours). */\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code === \"EPERM\";\n }\n}\n\nexport interface FileLockOptions {\n /** Subdirectory under ~/.config/q-ring holding the lock file. */\n dir?: string;\n /** Max time to wait to acquire before throwing (ms). */\n timeoutMs?: number;\n /** Age past which a lock whose holder we can't disprove is stolen (ms). */\n staleMs?: number;\n}\n\n/**\n * Run `fn` while holding an exclusive on-disk lock named `name`.\n *\n * A crash while holding the lock used to deadlock every future caller (the old\n * JIT lock wrote its pid but never read it back, and spun the CPU while\n * waiting). This version steals a lock whose holder process is gone, or that is\n * older than `staleMs`, and sleeps without busy-spinning between attempts.\n * Synchronous by design — callers (secret reads, audit appends) run in sync\n * contexts.\n */\nexport function withFileLock<T>(\n name: string,\n fn: () => T,\n opts: FileLockOptions = {},\n): T {\n const lockDir = join(homedir(), \".config\", \"q-ring\", opts.dir ?? \"locks\");\n mkdirSync(lockDir, { recursive: true, mode: 0o700 });\n const safe = Buffer.from(name, \"utf8\").toString(\"base64url\");\n const lockPath = join(lockDir, `${safe}.lock`);\n const deadline = Date.now() + (opts.timeoutMs ?? 8000);\n const staleMs = opts.staleMs ?? 30_000;\n\n while (Date.now() < deadline) {\n // Acquisition and the critical section are separate try blocks: if they\n // shared one, an exception thrown by fn() would be caught by the retry\n // logic below and resurface 8s later as a bogus \"could not acquire lock\"\n // timeout instead of propagating.\n let acquired = false;\n try {\n writeFileSync(lockPath, `${process.pid}\\n`, { flag: \"wx\", mode: 0o600 });\n acquired = true;\n } catch {\n try {\n const holderPid = parseInt(readFileSync(lockPath, \"utf8\").trim(), 10);\n const ageMs = Date.now() - statSync(lockPath).mtimeMs;\n const stale =\n (Number.isInteger(holderPid) && holderPid > 0 && !isProcessAlive(holderPid)) ||\n ageMs > staleMs;\n if (stale) {\n unlinkSync(lockPath);\n continue;\n }\n } catch {\n // Lock vanished between our failed create and this inspection — retry.\n }\n sleepSync(15);\n }\n\n if (acquired) {\n try {\n return fn();\n } finally {\n try {\n unlinkSync(lockPath);\n } catch {\n /* ignore */\n }\n }\n }\n }\n throw new Error(`Could not acquire lock \"${name}\" (timeout)`);\n}\n","/**\n * Quantum Entanglement: link secrets across projects.\n * When one entangled secret is rotated, all linked copies update.\n *\n * Entanglement is stored as metadata in the envelope. The entanglement\n * registry at ~/.config/q-ring/entanglement.json provides a reverse\n * lookup: given a secret, find all its entangled partners.\n */\n\nimport { existsSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { loadJsonRegistry } from \"../utils/registry.js\";\n\nexport interface EntanglementProvenance {\n /** Audit source that created the link (cli/mcp/...). */\n source?: string;\n /** Pinned policy root in effect when an MCP caller created the link, if any. */\n policyRoot?: string | null;\n}\n\nexport interface EntanglementPair {\n /** Source: service/key */\n source: { service: string; key: string };\n /** Target: service/key */\n target: { service: string; key: string };\n /** When this entanglement was created */\n createdAt: string;\n /** Who created this link. Absent on pre-v0.14 pairs (treat as \"legacy\"). */\n createdBy?: EntanglementProvenance;\n}\n\ninterface EntanglementRegistry {\n /** Schema version. Absent = pre-v0.14. */\n version?: number;\n pairs: EntanglementPair[];\n}\n\nconst REGISTRY_VERSION = 1;\n\nfunction getRegistryPath(): string {\n const dir = join(homedir(), \".config\", \"q-ring\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n return join(dir, \"entanglement.json\");\n}\n\nfunction loadRegistry(): EntanglementRegistry {\n return loadJsonRegistry<EntanglementRegistry>(getRegistryPath(), { pairs: [] });\n}\n\nfunction saveRegistry(registry: EntanglementRegistry): void {\n registry.version = REGISTRY_VERSION;\n writeFileSync(getRegistryPath(), JSON.stringify(registry, null, 2), {\n mode: 0o600,\n });\n}\n\nexport function entangle(\n source: { service: string; key: string },\n target: { service: string; key: string },\n createdBy?: EntanglementProvenance,\n): void {\n const registry = loadRegistry();\n\n const exists = registry.pairs.some(\n (p) =>\n p.source.service === source.service &&\n p.source.key === source.key &&\n p.target.service === target.service &&\n p.target.key === target.key,\n );\n\n if (!exists) {\n const createdAt = new Date().toISOString();\n registry.pairs.push({ source, target, createdAt, createdBy });\n // Bidirectional: add reverse link too\n registry.pairs.push({ source: target, target: source, createdAt, createdBy });\n saveRegistry(registry);\n }\n}\n\nexport function disentangle(\n source: { service: string; key: string },\n target: { service: string; key: string },\n): void {\n const registry = loadRegistry();\n registry.pairs = registry.pairs.filter(\n (p) =>\n !(\n (p.source.service === source.service &&\n p.source.key === source.key &&\n p.target.service === target.service &&\n p.target.key === target.key) ||\n (p.source.service === target.service &&\n p.source.key === target.key &&\n p.target.service === source.service &&\n p.target.key === source.key)\n ),\n );\n saveRegistry(registry);\n}\n\n/**\n * Find all entangled partners for a given secret.\n */\nexport function findEntangled(\n source: { service: string; key: string },\n): { service: string; key: string }[] {\n const registry = loadRegistry();\n return registry.pairs\n .filter(\n (p) =>\n p.source.service === source.service && p.source.key === source.key,\n )\n .map((p) => p.target);\n}\n\n/**\n * List all entanglement pairs.\n */\nexport function listEntanglements(): EntanglementPair[] {\n return loadRegistry().pairs;\n}\n","import { existsSync, readFileSync, renameSync } from \"node:fs\";\n\n/**\n * Load a JSON registry file, distinguishing \"absent\" (a normal first run) from\n * \"present but corrupt\" (a crash mid-write, a full disk, manual mangling).\n *\n * The previous pattern — `try { JSON.parse(...) } catch { return empty }` —\n * treated both cases identically, so a single unparseable read made the caller's\n * next save silently overwrite the file with an empty-plus-one-new-entry\n * registry, permanently destroying every entanglement link / approval grant /\n * hook the user had, with no warning.\n *\n * Here, corruption moves the file aside to `<path>.corrupt-<timestamp>` and\n * warns loudly, so the caller reinitializes from empty while the original bytes\n * survive in the backup. If the file cannot even be moved aside, we throw rather\n * than let a later save overwrite the only (recoverable) copy.\n */\nexport function loadJsonRegistry<T>(path: string, empty: T): T {\n if (!existsSync(path)) return empty;\n\n const raw = readFileSync(path, \"utf8\");\n try {\n return JSON.parse(raw) as T;\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n const stamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const backup = `${path}.corrupt-${stamp}`;\n try {\n renameSync(path, backup);\n } catch {\n throw new Error(\n `q-ring: registry ${path} is corrupt (${reason}) and could not be moved ` +\n `aside — refusing to continue so a later write cannot overwrite it. ` +\n `Inspect or remove the file manually.`,\n );\n }\n console.error(\n `q-ring: WARNING — registry ${path} was corrupt (${reason}); moved it to ` +\n `${backup} and reinitialized from empty. Previous entries are preserved ` +\n `in the backup file.`,\n );\n return empty;\n }\n}\n","/**\n * Hook system: fire callbacks when secrets are created, updated, or deleted.\n * Supports shell commands, HTTP webhooks, and process signals.\n *\n * Registry stored at ~/.config/q-ring/hooks.json\n */\n\nimport { existsSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { execFile, spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { httpRequest } from \"../utils/http-request.js\";\nimport { loadJsonRegistry } from \"../utils/registry.js\";\nimport { logAudit } from \"./observer.js\";\nimport { checkSSRF } from \"./ssrf.js\";\n\nexport type HookType = \"shell\" | \"http\" | \"signal\";\nexport type HookAction = \"write\" | \"delete\" | \"rotate\";\n\nexport interface HookMatch {\n key?: string;\n keyPattern?: string;\n tag?: string;\n scope?: \"global\" | \"project\";\n action?: HookAction[];\n}\n\nexport interface HookEntry {\n id: string;\n type: HookType;\n match: HookMatch;\n command?: string;\n url?: string;\n signal?: { target: string; signal?: string };\n description?: string;\n createdAt: string;\n enabled: boolean;\n}\n\nexport interface HookPayload {\n action: HookAction;\n key: string;\n scope: string;\n timestamp: string;\n source: \"cli\" | \"mcp\" | \"agent\" | \"api\" | \"hook\" | \"ci\";\n}\n\nexport interface HookResult {\n hookId: string;\n success: boolean;\n message: string;\n}\n\ninterface HookRegistry {\n hooks: HookEntry[];\n}\n\nfunction getRegistryPath(): string {\n const dir = join(homedir(), \".config\", \"q-ring\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n return join(dir, \"hooks.json\");\n}\n\nfunction loadRegistry(): HookRegistry {\n return loadJsonRegistry<HookRegistry>(getRegistryPath(), { hooks: [] });\n}\n\nfunction saveRegistry(registry: HookRegistry): void {\n writeFileSync(getRegistryPath(), JSON.stringify(registry, null, 2), {\n mode: 0o600,\n });\n}\n\nexport function registerHook(\n entry: Omit<HookEntry, \"id\" | \"createdAt\">,\n): HookEntry {\n const registry = loadRegistry();\n const hook: HookEntry = {\n ...entry,\n id: randomUUID().slice(0, 8),\n createdAt: new Date().toISOString(),\n };\n registry.hooks.push(hook);\n saveRegistry(registry);\n return hook;\n}\n\nexport function removeHook(id: string): boolean {\n const registry = loadRegistry();\n const before = registry.hooks.length;\n registry.hooks = registry.hooks.filter((h) => h.id !== id);\n if (registry.hooks.length < before) {\n saveRegistry(registry);\n return true;\n }\n return false;\n}\n\nexport function listHooks(): HookEntry[] {\n return loadRegistry().hooks;\n}\n\nexport function enableHook(id: string): boolean {\n const registry = loadRegistry();\n const hook = registry.hooks.find((h) => h.id === id);\n if (!hook) return false;\n hook.enabled = true;\n saveRegistry(registry);\n return true;\n}\n\nexport function disableHook(id: string): boolean {\n const registry = loadRegistry();\n const hook = registry.hooks.find((h) => h.id === id);\n if (!hook) return false;\n hook.enabled = false;\n saveRegistry(registry);\n return true;\n}\n\nfunction matchesHook(\n hook: HookEntry,\n payload: HookPayload,\n tags?: string[],\n): boolean {\n if (!hook.enabled) return false;\n\n const m = hook.match;\n\n if (m.action?.length && !m.action.includes(payload.action)) return false;\n\n if (m.key && m.key !== payload.key) return false;\n\n if (m.keyPattern) {\n const escaped = m.keyPattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n const regex = new RegExp(\"^\" + escaped + \"$\", \"i\");\n if (!regex.test(payload.key)) return false;\n }\n\n if (m.tag && (!tags || !tags.includes(m.tag))) return false;\n\n if (m.scope && m.scope !== payload.scope) return false;\n\n return true;\n}\n\n/** pgrep -f pattern: allow only literals safe from regex/shell metacharacters. */\nconst SAFE_PGREP_NAME = /^[a-zA-Z0-9._:/-]{1,256}$/;\n\nfunction shellRunner(): { file: string; args: string[] } {\n if (process.platform === \"win32\") {\n const comspec = process.env.ComSpec ?? \"cmd.exe\";\n return { file: comspec, args: [\"/d\", \"/s\", \"/c\"] };\n }\n return { file: \"/bin/sh\", args: [\"-c\"] };\n}\n\nfunction executeShell(command: string, payload: HookPayload): Promise<HookResult> {\n return new Promise((resolve) => {\n const env = {\n ...process.env,\n QRING_HOOK_KEY: payload.key,\n QRING_HOOK_ACTION: payload.action,\n QRING_HOOK_SCOPE: payload.scope,\n };\n\n const { file, args } = shellRunner();\n execFile(\n file,\n [...args, command],\n {\n timeout: 30000,\n env,\n windowsHide: true,\n maxBuffer: 4 * 1024 * 1024,\n encoding: \"utf8\",\n },\n (err, stdout) => {\n if (err) {\n resolve({\n hookId: \"\",\n success: false,\n message: `Shell error: ${err.message}`,\n });\n } else {\n resolve({\n hookId: \"\",\n success: true,\n message: (stdout ?? \"\").trim() || \"OK\",\n });\n }\n },\n );\n });\n}\n\nasync function executeHttp(url: string, payload: HookPayload): Promise<HookResult> {\n const ssrfBlock = await checkSSRF(url);\n if (ssrfBlock) {\n logAudit({\n action: \"policy_deny\",\n key: payload.key,\n scope: payload.scope,\n source: payload.source,\n detail: `hook SSRF blocked: ${url}`,\n });\n return { hookId: \"\", success: false, message: ssrfBlock };\n }\n\n try {\n const body = JSON.stringify(payload);\n const res = await httpRequest({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"User-Agent\": \"q-ring-hooks/1.0\",\n },\n body,\n timeoutMs: 10_000,\n });\n return {\n hookId: \"\",\n success: res.statusCode >= 200 && res.statusCode < 300,\n message: `HTTP ${res.statusCode}`,\n };\n } catch (err) {\n return {\n hookId: \"\",\n success: false,\n message: err instanceof Error ? err.message : \"HTTP error\",\n };\n }\n}\n\nfunction executeSignal(\n target: string,\n signal: string = \"SIGHUP\",\n): Promise<HookResult> {\n return new Promise((resolve) => {\n const trimmed = target.trim();\n if (/^\\d+$/.test(trimmed)) {\n const pid = parseInt(trimmed, 10);\n try {\n process.kill(pid, signal as NodeJS.Signals);\n resolve({\n hookId: \"\",\n success: true,\n message: `Signal ${signal} sent to PID ${pid}`,\n });\n } catch (err) {\n resolve({\n hookId: \"\",\n success: false,\n message: `Signal error: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n return;\n }\n\n if (!SAFE_PGREP_NAME.test(trimmed)) {\n resolve({\n hookId: \"\",\n success: false,\n message:\n 'Signal target must be a numeric PID, or a process name matching /^[a-zA-Z0-9._:/-]{1,256}$/ (no spaces or shell metacharacters).',\n });\n return;\n }\n\n const child = spawn(\"pgrep\", [\"-f\", trimmed], {\n timeout: 5000,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n child.stdout.on(\"data\", (d: Buffer) => {\n stdout += d.toString();\n });\n child.on(\"close\", (code) => {\n if (code !== 0 || !stdout.trim()) {\n resolve({\n hookId: \"\",\n success: false,\n message: `Process \"${trimmed}\" not found`,\n });\n return;\n }\n const pids = stdout\n .trim()\n .split(\"\\n\")\n .map((p) => parseInt(p.trim(), 10))\n .filter((p) => !isNaN(p));\n let sent = 0;\n for (const p of pids) {\n try {\n process.kill(p, signal as NodeJS.Signals);\n sent++;\n } catch {\n /* ignore dead PIDs */\n }\n }\n resolve({\n hookId: \"\",\n success: sent > 0,\n message: `Signal ${signal} sent to ${sent} process(es)`,\n });\n });\n child.on(\"error\", () => {\n resolve({\n hookId: \"\",\n success: false,\n message: `Process \"${trimmed}\" not found`,\n });\n });\n });\n}\n\nasync function executeHook(\n hook: HookEntry,\n payload: HookPayload,\n): Promise<HookResult> {\n let result: HookResult;\n\n switch (hook.type) {\n case \"shell\":\n result = hook.command\n ? await executeShell(hook.command, payload)\n : { hookId: hook.id, success: false, message: \"No command specified\" };\n break;\n case \"http\":\n result = hook.url\n ? await executeHttp(hook.url, payload)\n : { hookId: hook.id, success: false, message: \"No URL specified\" };\n break;\n case \"signal\":\n result = hook.signal\n ? await executeSignal(hook.signal.target, hook.signal.signal)\n : { hookId: hook.id, success: false, message: \"No signal target specified\" };\n break;\n default:\n result = { hookId: hook.id, success: false, message: `Unknown hook type: ${hook.type}` };\n }\n\n result.hookId = hook.id;\n return result;\n}\n\n/**\n * Fire all matching hooks for a given payload. Fire-and-forget — never blocks\n * the caller on hook failures.\n */\nexport async function fireHooks(\n payload: HookPayload,\n tags?: string[],\n): Promise<HookResult[]> {\n const hooks = listHooks();\n const matching = hooks.filter((h) => matchesHook(h, payload, tags));\n\n if (matching.length === 0) return [];\n\n const results = await Promise.allSettled(\n matching.map((h) => executeHook(h, payload)),\n );\n\n const hookResults: HookResult[] = [];\n for (const r of results) {\n if (r.status === \"fulfilled\") {\n hookResults.push(r.value);\n } else {\n hookResults.push({\n hookId: \"unknown\",\n success: false,\n message: r.reason?.message ?? \"Hook execution failed\",\n });\n }\n }\n\n for (const r of hookResults) {\n try {\n logAudit({\n action: \"write\",\n key: payload.key,\n scope: payload.scope,\n source: payload.source,\n detail: `hook:${r.hookId} ${r.success ? \"ok\" : \"fail\"} — ${r.message}`,\n });\n } catch { /* never crash on audit logging */ }\n }\n\n return hookResults;\n}\n","/**\n * Shared HTTP request helper with timeout and response body cap.\n * Used by validation providers and webhook hooks.\n */\n\nimport { request as httpsRequest } from \"node:https\";\nimport { request as httpRequestPlain } from \"node:http\";\nimport type { LookupFunction } from \"node:net\";\nimport { guardedLookup } from \"../core/ssrf.js\";\n\nexport interface HttpRequestOptions {\n url: string;\n method?: \"GET\" | \"POST\";\n headers?: Record<string, string>;\n body?: string;\n timeoutMs?: number;\n maxResponseBytes?: number;\n}\n\nexport interface HttpResponse {\n statusCode: number;\n body: string;\n truncated: boolean;\n}\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_RESPONSE_BYTES = 65_536; // 64 KiB\n\n/**\n * Perform an HTTP(S) request with a hard timeout and a cap on the response\n * body size. Always returns a resolved promise unless the network fails or\n * the timeout fires — partial reads are returned with `truncated: true`.\n */\nexport function httpRequest(opts: HttpRequestOptions): Promise<HttpResponse> {\n const {\n url,\n method = \"GET\",\n headers = {},\n body,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n maxResponseBytes = DEFAULT_MAX_RESPONSE_BYTES,\n } = opts;\n\n return new Promise((resolve, reject) => {\n const parsed = new URL(url);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n reject(new Error(`Unsupported URL protocol: ${parsed.protocol}`));\n return;\n }\n const reqFn = parsed.protocol === \"https:\" ? httpsRequest : httpRequestPlain;\n\n const reqHeaders: Record<string, string | number> = { ...headers };\n if (body && !reqHeaders[\"Content-Length\"]) {\n reqHeaders[\"Content-Length\"] = Buffer.byteLength(body);\n }\n\n const req = reqFn(\n url,\n {\n method,\n headers: reqHeaders,\n timeout: timeoutMs,\n // Re-validate the resolved IP at connect time (DNS-rebinding guard).\n lookup: guardedLookup as unknown as LookupFunction,\n },\n (res) => {\n const chunks: Buffer[] = [];\n let totalBytes = 0;\n let truncated = false;\n\n res.on(\"data\", (chunk: Buffer) => {\n totalBytes += chunk.length;\n if (totalBytes > maxResponseBytes) {\n truncated = true;\n res.destroy();\n return;\n }\n chunks.push(chunk);\n });\n\n let settled = false;\n const settle = (result: HttpResponse) => {\n if (!settled) { settled = true; resolve(result); }\n };\n const fail = (err: Error) => {\n if (!settled) { settled = true; reject(err); }\n };\n\n res.on(\"error\", (err) => fail(new Error(`Response error: ${err.message}`)));\n\n res.on(\"end\", () => {\n settle({\n statusCode: res.statusCode ?? 0,\n body: Buffer.concat(chunks).toString(\"utf8\"),\n truncated,\n });\n });\n\n res.on(\"close\", () => {\n settle({\n statusCode: res.statusCode ?? 0,\n body: Buffer.concat(chunks).toString(\"utf8\"),\n truncated,\n });\n });\n },\n );\n\n req.on(\"error\", (err) => reject(new Error(`Network error: ${err.message}`)));\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"Request timed out\"));\n });\n\n if (body) req.write(body);\n req.end();\n });\n}\n","/**\n * SSRF Protection — shared guard for HTTP requests to user-controlled URLs.\n *\n * Blocks requests to private/loopback/link-local addresses unless\n * Q_RING_ALLOW_PRIVATE_HOOKS=1 is set.\n */\n\nimport { lookup } from \"node:dns/promises\";\nimport * as dns from \"node:dns\";\nimport { lookup as dnsLookup, type LookupAddress } from \"node:dns\";\nimport { isIPv4, isIPv6 } from \"node:net\";\nimport ipaddr from \"ipaddr.js\";\n\n/** `lookupSync` exists at runtime (Node 18+); some @types/node versions omit it from typings. */\nfunction lookupAddressesSync(hostname: string): { address: string; family: number }[] {\n const lookupSync = (dns as typeof dns & {\n lookupSync(\n host: string,\n options: { all: true },\n ): { address: string; family: number }[];\n }).lookupSync;\n return lookupSync(hostname, { all: true });\n}\n\nfunction isHostnameIpLiteral(hostname: string): boolean {\n if (isIPv4(hostname)) return true;\n if (hostname.startsWith(\"[\") && hostname.endsWith(\"]\")) {\n return isIPv6(hostname.slice(1, -1));\n }\n return isIPv6(hostname);\n}\n\n/**\n * IPv4 ranges an outbound request must never reach. `reserved` (which includes\n * the TEST-NET documentation blocks) and `multicast` are deliberately omitted to\n * preserve the historical \"public IPs pass\" contract.\n */\nconst BLOCKED_IPV4_RANGES = new Set<string>([\n \"unspecified\",\n \"broadcast\",\n \"linkLocal\",\n \"loopback\",\n \"carrierGradeNat\",\n \"private\",\n]);\n\n/**\n * True if an IP *literal* points somewhere an outbound request must never go:\n * loopback, private, link-local, carrier-grade NAT, unspecified/broadcast, and —\n * for IPv6 — every non-unicast range plus the IPv4-in-IPv6 transition forms that\n * can smuggle those targets past a naive string check.\n *\n * Parsing is delegated to `ipaddr.js` rather than matched with regexes, because\n * the WHATWG URL parser canonicalizes an IPv4-mapped literal like\n * `[::ffff:127.0.0.1]` to the hex-group form `::ffff:7f00:1` (and\n * `[::ffff:169.254.169.254]` → `::ffff:a9fe:a9fe`, i.e. cloud metadata), which a\n * dotted-decimal-only regex silently let through. Structured parsing covers every\n * canonical form of the same address.\n *\n * Returns false for non-IP strings (hostnames); DNS resolution is handled by the\n * callers, which re-run this check against each resolved address.\n */\nexport function isPrivateIP(ip: string): boolean {\n let addr: ipaddr.IPv4 | ipaddr.IPv6;\n try {\n addr = ipaddr.parse(ip);\n } catch {\n return false;\n }\n\n if (addr.kind() === \"ipv6\") {\n const v6 = addr as ipaddr.IPv6;\n // Unwrap IPv4-mapped addresses and judge the embedded IPv4, so both the\n // dotted (`::ffff:127.0.0.1`) and hex-group (`::ffff:7f00:1`) canonical forms\n // resolve to the same verdict.\n if (v6.isIPv4MappedAddress()) {\n return isBlockedIPv4(v6.toIPv4Address());\n }\n // Only genuine global unicast IPv6 is allowed out. Everything else —\n // loopback, link-local, unique-local, unspecified, multicast, reserved, and\n // the IPv4-embedding 6to4/teredo/rfc6052/rfc6145 transition ranges — is a\n // potential internal-target smuggling vector and is blocked.\n return v6.range() !== \"unicast\";\n }\n\n return isBlockedIPv4(addr as ipaddr.IPv4);\n}\n\nfunction isBlockedIPv4(addr: ipaddr.IPv4): boolean {\n return BLOCKED_IPV4_RANGES.has(addr.range());\n}\n\n/**\n * Async SSRF check — resolves DNS and blocks private addresses.\n * Returns null if safe, or a human-readable block message.\n */\nexport async function checkSSRF(url: string): Promise<string | null> {\n if (process.env.Q_RING_ALLOW_PRIVATE_HOOKS === \"1\") return null;\n\n try {\n const parsed = new URL(url);\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, \"\");\n\n if (isPrivateIP(hostname)) {\n return `Blocked: URL resolves to private address (${hostname}). Set Q_RING_ALLOW_PRIVATE_HOOKS=1 to override.`;\n }\n\n const results = await lookup(hostname, { all: true });\n for (const { address } of results) {\n if (isPrivateIP(address)) {\n return `Blocked: URL \"${hostname}\" resolves to private address ${address}. Set Q_RING_ALLOW_PRIVATE_HOOKS=1 to override.`;\n }\n }\n } catch {\n // DNS failure will surface as a request error downstream\n }\n return null;\n}\n\ntype GuardedLookupCallback = (\n err: NodeJS.ErrnoException | null,\n address: string | LookupAddress[],\n family?: number,\n) => void;\n\n/**\n * A `lookup` function for http(s).request that re-validates the resolved\n * address at connection time. This closes the DNS-rebinding TOCTOU window\n * where a hostname passes {@link checkSSRF} but resolves to a private/loopback\n * address moments later when the socket actually connects. Fails closed.\n */\nexport function guardedLookup(\n hostname: string,\n options: dns.LookupOptions,\n callback: GuardedLookupCallback,\n): void {\n if (process.env.Q_RING_ALLOW_PRIVATE_HOOKS === \"1\") {\n (dnsLookup as (h: string, o: dns.LookupOptions, cb: GuardedLookupCallback) => void)(\n hostname,\n options,\n callback,\n );\n return;\n }\n\n (dnsLookup as (h: string, o: dns.LookupOptions, cb: GuardedLookupCallback) => void)(\n hostname,\n options,\n (err, address, family) => {\n if (err) return callback(err, address, family);\n const list = Array.isArray(address)\n ? address\n : [{ address, family: family ?? 0 }];\n for (const a of list) {\n if (isPrivateIP(a.address)) {\n const blocked: NodeJS.ErrnoException = Object.assign(\n new Error(\n `Blocked: \"${hostname}\" resolved to private address ${a.address} at connect time.`,\n ),\n { code: \"EQRINGSSRF\" },\n );\n return callback(blocked, address, family);\n }\n }\n callback(null, address, family);\n },\n );\n}\n\n/**\n * Sync SSRF check — validates IP literals only (no DNS resolution).\n * Suitable for sync contexts where async DNS lookup isn't possible.\n */\nexport function checkSSRFSync(url: string): string | null {\n if (process.env.Q_RING_ALLOW_PRIVATE_HOOKS === \"1\") return null;\n\n try {\n const parsed = new URL(url);\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, \"\");\n\n if (isPrivateIP(hostname)) {\n return `Blocked: URL resolves to private address (${hostname}). Set Q_RING_ALLOW_PRIVATE_HOOKS=1 to override.`;\n }\n } catch {\n // malformed URL — will fail downstream\n }\n return null;\n}\n\n/**\n * JIT HTTP provisioning runs in a sync path and cannot use async DNS.\n * This performs {@link lookupSync} so hostnames cannot bypass {@link checkSSRFSync}\n * by resolving to loopback/private only at request time. Fails closed on DNS errors.\n */\nexport function checkJitHttpProvisionUrl(url: string): string | null {\n if (process.env.Q_RING_ALLOW_PRIVATE_HOOKS === \"1\") return null;\n\n try {\n const parsed = new URL(url);\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return \"Blocked: JIT HTTP provider only allows http: or https: URLs.\";\n }\n const hostname = parsed.hostname.replace(/^\\[|\\]$/g, \"\");\n if (!hostname) {\n return \"Blocked: empty hostname in JIT URL.\";\n }\n\n if (isPrivateIP(hostname)) {\n return `Blocked: URL resolves to private address (${hostname}). Set Q_RING_ALLOW_PRIVATE_HOOKS=1 to override.`;\n }\n\n if (isHostnameIpLiteral(hostname)) {\n return null;\n }\n\n let results: { address: string; family: number }[];\n try {\n results = lookupAddressesSync(hostname);\n } catch {\n return `Blocked: DNS resolution failed for \"${hostname}\" (JIT HTTP provisioning fails closed).`;\n }\n\n if (!results.length) {\n return `Blocked: DNS returned no addresses for \"${hostname}\".`;\n }\n\n for (const { address } of results) {\n if (isPrivateIP(address)) {\n return `Blocked: URL \"${hostname}\" resolves to private address ${address}. Set Q_RING_ALLOW_PRIVATE_HOOKS=1 to override.`;\n }\n }\n } catch {\n return \"Blocked: malformed JIT HTTP URL.\";\n }\n return null;\n}\n","/**\n * Stronger Approval Workflows (Zero-Trust Agent)\n *\n * Manages scoped, reasoned, time-limited approval tokens for accessing\n * protected secrets via MCP. Each token carries:\n * - Reason: why the approval was granted\n * - Workspace / session binding\n * - HMAC verification to prevent tampering\n * - Expiry enforcement\n *\n * Approvals are stored in a file so the CLI can grant them and the MCP\n * server can read and verify them.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { loadJsonRegistry } from \"../utils/registry.js\";\n\nexport interface ApprovalEntry {\n id: string;\n key: string;\n scope: string;\n /**\n * The resolved service identity the approval is bound to (e.g.\n * `q-ring:project:<hashProjectPath>`), not the coarse `scope` label. This is\n * what actually isolates one project from another — the `scope` string is\n * `\"project\"` for *every* project. Absent on pre-v0.14 entries; a check that\n * requires a service will not match those (fail closed) — they must be\n * re-granted.\n */\n service?: string;\n reason: string;\n grantedBy: string;\n grantedAt: string;\n expiresAt: string;\n workspace?: string;\n sessionId?: string;\n hmac: string;\n}\n\ninterface ApprovalRegistry {\n approvals: ApprovalEntry[];\n}\n\nfunction getHmacSecret(): string {\n const dir = join(homedir(), \".config\", \"q-ring\");\n const secretPath = join(dir, \".approval-key\");\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 0o700 });\n\n if (existsSync(secretPath)) {\n return readFileSync(secretPath, \"utf8\").trim();\n }\n const secret = randomBytes(32).toString(\"hex\");\n writeFileSync(secretPath, secret, { mode: 0o600 });\n return secret;\n}\n\nfunction computeHmac(entry: Omit<ApprovalEntry, \"hmac\">): string {\n // Include every persisted field so workspace/sessionId bindings stay\n // tamper-evident even if they are only surfaced informationally today.\n const payload = [\n entry.id,\n entry.key,\n entry.scope,\n entry.service ?? \"\",\n entry.reason,\n entry.grantedBy,\n entry.grantedAt,\n entry.expiresAt,\n entry.workspace ?? \"\",\n entry.sessionId ?? \"\",\n ].join(\"|\");\n return createHmac(\"sha256\", getHmacSecret()).update(payload).digest(\"hex\");\n}\n\nfunction verifyHmac(entry: ApprovalEntry): boolean {\n const expected = computeHmac(entry);\n const a = Buffer.from(expected, \"utf8\");\n const b = Buffer.from(entry.hmac, \"utf8\");\n if (a.length !== b.length) return false;\n try {\n return timingSafeEqual(a, b);\n } catch {\n return false;\n }\n}\n\nfunction getRegistryPath(): string {\n const dir = join(homedir(), \".config\", \"q-ring\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n return join(dir, \"approvals.json\");\n}\n\nfunction loadRegistry(): ApprovalRegistry {\n return loadJsonRegistry<ApprovalRegistry>(getRegistryPath(), { approvals: [] });\n}\n\nfunction saveRegistry(registry: ApprovalRegistry): void {\n writeFileSync(getRegistryPath(), JSON.stringify(registry, null, 2), { mode: 0o600 });\n}\n\nfunction cleanup(registry: ApprovalRegistry): void {\n const now = Date.now();\n registry.approvals = registry.approvals.filter(\n (a) => new Date(a.expiresAt).getTime() > now,\n );\n}\n\nexport interface GrantOptions {\n reason?: string;\n grantedBy?: string;\n workspace?: string;\n sessionId?: string;\n}\n\nexport function grantApproval(\n key: string,\n scope: string,\n service: string,\n ttlSeconds: number = 3600,\n grantOpts: GrantOptions = {},\n): ApprovalEntry {\n const registry = loadRegistry();\n cleanup(registry);\n\n const id = randomBytes(8).toString(\"hex\");\n const grantedAt = new Date().toISOString();\n const expiresAt = new Date(Date.now() + ttlSeconds * 1000).toISOString();\n\n const partial: Omit<ApprovalEntry, \"hmac\"> = {\n id,\n key,\n scope,\n service,\n reason: grantOpts.reason ?? \"no reason provided\",\n grantedBy: grantOpts.grantedBy ?? \"cli-user\",\n grantedAt,\n expiresAt,\n workspace: grantOpts.workspace,\n sessionId: grantOpts.sessionId,\n };\n\n const entry: ApprovalEntry = { ...partial, hmac: computeHmac(partial) };\n\n const existingIdx = registry.approvals.findIndex(\n (a) => a.key === key && a.scope === scope && a.service === service,\n );\n if (existingIdx >= 0) {\n registry.approvals[existingIdx] = entry;\n } else {\n registry.approvals.push(entry);\n }\n\n saveRegistry(registry);\n return entry;\n}\n\nexport function revokeApproval(key: string, scope: string, service: string): boolean {\n const registry = loadRegistry();\n const before = registry.approvals.length;\n registry.approvals = registry.approvals.filter(\n (a) => !(a.key === key && a.scope === scope && a.service === service),\n );\n saveRegistry(registry);\n return registry.approvals.length < before;\n}\n\nexport function hasApproval(key: string, scope: string, service: string): boolean {\n const registry = loadRegistry();\n const entry = registry.approvals.find(\n (a) => a.key === key && a.scope === scope && a.service === service,\n );\n if (!entry) return false;\n if (new Date(entry.expiresAt).getTime() < Date.now()) return false;\n if (!verifyHmac(entry)) return false;\n return true;\n}\n\nexport function getApprovalDetail(\n key: string,\n scope: string,\n service: string,\n): ApprovalEntry | null {\n const registry = loadRegistry();\n const entry = registry.approvals.find(\n (a) => a.key === key && a.scope === scope && a.service === service,\n );\n if (!entry) return null;\n if (new Date(entry.expiresAt).getTime() < Date.now()) return null;\n return entry;\n}\n\n/** Count approvals with no service binding (pre-v0.14) — used by `qring doctor`. */\nexport function countLegacyApprovals(): number {\n return loadRegistry().approvals.filter((a) => a.service === undefined).length;\n}\n\nexport function listApprovals(): (ApprovalEntry & { valid: boolean; tampered: boolean })[] {\n const registry = loadRegistry();\n const now = Date.now();\n return registry.approvals.map((a) => ({\n ...a,\n valid: new Date(a.expiresAt).getTime() > now,\n tampered: !verifyHmac(a),\n }));\n}\n","/**\n * Governance-As-Code Policy Engine\n *\n * Evaluates project-level policies declared in `.q-ring.json` under the\n * `policy` key. Enforces MCP tool gating, key/tag access restrictions,\n * exec allowlists, and mandatory metadata requirements.\n */\n\nimport { statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { z } from \"zod\";\nimport { readProjectConfig } from \"./collapse.js\";\n\n/**\n * Strict schema for the `.q-ring.json` `policy` object. `.strict()` at every\n * level is the point of B3: an unknown key (a typo like `denytools` for\n * `denyTools`) is a hard error rather than a silently-ignored no-op. Because\n * this object is a deny-by-default security control, a misspelled deny rule that\n * is silently dropped fails *open* — the tool/key the user meant to block stays\n * allowed. Validating strictly and failing closed (see loadPolicy) closes that.\n */\nconst stringArray = z.array(z.string());\nconst mcpPolicySchema = z\n .object({\n allowTools: stringArray.optional(),\n denyTools: stringArray.optional(),\n readableKeys: stringArray.optional(),\n deniedKeys: stringArray.optional(),\n deniedTags: stringArray.optional(),\n })\n .strict();\nconst execPolicySchema = z\n .object({\n allowCommands: stringArray.optional(),\n denyCommands: stringArray.optional(),\n maxRuntimeSeconds: z.number().optional(),\n allowNetwork: z.boolean().optional(),\n })\n .strict();\nconst secretsPolicySchema = z\n .object({\n requireApprovalForTags: stringArray.optional(),\n requireRotationFormatForTags: stringArray.optional(),\n maxTtlSeconds: z.number().optional(),\n })\n .strict();\nconst policySchema = z\n .object({\n mcp: mcpPolicySchema.optional(),\n exec: execPolicySchema.optional(),\n secrets: secretsPolicySchema.optional(),\n })\n .strict();\n\nexport type PolicyConfig = z.infer<typeof policySchema>;\n\n/** Thrown when `.q-ring.json` has a `policy` object that fails validation. */\nexport class PolicyConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PolicyConfigError\";\n }\n}\n\nexport interface PolicyDecision {\n allowed: boolean;\n reason?: string;\n policySource: string;\n}\n\nlet cachedPolicy:\n | { path: string; mtimeMs: number; policy: PolicyConfig; error?: undefined }\n | { path: string; mtimeMs: number; error: PolicyConfigError; policy?: undefined }\n | null = null;\n\n/**\n * Trusted policy root. When set (by the MCP server at startup), all policy\n * resolution is anchored here and ignores caller-supplied projectPath. This\n * prevents an MCP agent from escaping project governance by pointing\n * projectPath at a directory that has no (or a weaker) `.q-ring.json`.\n */\nlet policyRoot: string | null = null;\n\nexport function setPolicyRoot(root: string): void {\n policyRoot = root;\n cachedPolicy = null;\n}\n\n/** The pinned policy root, if the MCP server set one (else null). */\nexport function getPolicyRoot(): string | null {\n return policyRoot;\n}\n\nfunction resolvePolicyPath(projectPath?: string): string {\n return policyRoot ?? projectPath ?? process.cwd();\n}\n\nfunction configMtime(pp: string): number {\n try {\n return statSync(join(pp, \".q-ring.json\")).mtimeMs;\n } catch {\n return 0; // file absent — stable sentinel\n }\n}\n\nexport function loadPolicy(projectPath?: string): PolicyConfig {\n const pp = resolvePolicyPath(projectPath);\n const mtimeMs = configMtime(pp);\n if (cachedPolicy && cachedPolicy.path === pp && cachedPolicy.mtimeMs === mtimeMs) {\n if (cachedPolicy.error) throw cachedPolicy.error;\n return cachedPolicy.policy;\n }\n\n const config = readProjectConfig(pp) as { policy?: unknown } | null;\n const rawPolicy = config?.policy;\n\n if (rawPolicy === undefined || rawPolicy === null) {\n const policy: PolicyConfig = {};\n cachedPolicy = { path: pp, mtimeMs, policy };\n return policy;\n }\n\n const parsed = policySchema.safeParse(rawPolicy);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => `policy${i.path.length ? \".\" + i.path.join(\".\") : \"\"}: ${i.message}`)\n .join(\"; \");\n const error = new PolicyConfigError(\n `Invalid policy in ${join(pp, \".q-ring.json\")} — refusing to run under an ` +\n `unparseable security policy (fail closed). Fix these and retry: ${issues}`,\n );\n // Loud, and cached by mtime so it surfaces on every call until the file is\n // corrected (a dropped deny rule must never silently allow access).\n console.error(`q-ring: ${error.message}`);\n cachedPolicy = { path: pp, mtimeMs, error };\n throw error;\n }\n\n cachedPolicy = { path: pp, mtimeMs, policy: parsed.data };\n return parsed.data;\n}\n\nexport function clearPolicyCache(): void {\n cachedPolicy = null;\n}\n\nexport function checkToolPolicy(toolName: string, projectPath?: string): PolicyDecision {\n const policy = loadPolicy(projectPath);\n if (!policy.mcp) return { allowed: true, policySource: \"no-policy\" };\n\n if (policy.mcp.denyTools?.includes(toolName)) {\n return {\n allowed: false,\n reason: `Tool \"${toolName}\" is denied by project policy`,\n policySource: \".q-ring.json policy.mcp.denyTools\",\n };\n }\n\n if (policy.mcp.allowTools && !policy.mcp.allowTools.includes(toolName)) {\n return {\n allowed: false,\n reason: `Tool \"${toolName}\" is not in the allowlist`,\n policySource: \".q-ring.json policy.mcp.allowTools\",\n };\n }\n\n return { allowed: true, policySource: \".q-ring.json\" };\n}\n\n/** Enforce `policy.secrets` from `.q-ring.json` on writes. */\nexport function checkSecretLifecyclePolicy(\n input: {\n tags?: string[];\n ttlSeconds?: number;\n rotationFormat?: string;\n requiresApproval?: boolean;\n },\n projectPath?: string,\n): PolicyDecision {\n const policy = loadPolicy(projectPath);\n if (!policy.secrets) return { allowed: true, policySource: \"no-policy\" };\n const s = policy.secrets;\n\n if (s.maxTtlSeconds != null && input.ttlSeconds != null && input.ttlSeconds > s.maxTtlSeconds) {\n return {\n allowed: false,\n reason: `TTL ${input.ttlSeconds}s exceeds policy maximum ${s.maxTtlSeconds}s`,\n policySource: \".q-ring.json policy.secrets.maxTtlSeconds\",\n };\n }\n\n if (s.requireApprovalForTags?.length && input.tags?.length) {\n const hit = input.tags.find((t) => s.requireApprovalForTags!.includes(t));\n if (hit && !input.requiresApproval) {\n return {\n allowed: false,\n reason: `Tag \"${hit}\" requires explicit approval metadata (set requiresApproval / --requires-approval)`,\n policySource: \".q-ring.json policy.secrets.requireApprovalForTags\",\n };\n }\n }\n\n if (s.requireRotationFormatForTags?.length && input.tags?.length) {\n const hit = input.tags.find((t) => s.requireRotationFormatForTags!.includes(t));\n if (hit && !input.rotationFormat) {\n return {\n allowed: false,\n reason: `Tag \"${hit}\" requires a rotationFormat to be set`,\n policySource: \".q-ring.json policy.secrets.requireRotationFormatForTags\",\n };\n }\n }\n\n return { allowed: true, policySource: \".q-ring.json\" };\n}\n\nexport function checkKeyReadPolicy(key: string, tags: string[] | undefined, projectPath?: string): PolicyDecision {\n const policy = loadPolicy(projectPath);\n if (!policy.mcp) return { allowed: true, policySource: \"no-policy\" };\n\n if (policy.mcp.deniedKeys?.includes(key)) {\n return {\n allowed: false,\n reason: `Key \"${key}\" is denied by project policy`,\n policySource: \".q-ring.json policy.mcp.deniedKeys\",\n };\n }\n\n if (policy.mcp.readableKeys && !policy.mcp.readableKeys.includes(key)) {\n return {\n allowed: false,\n reason: `Key \"${key}\" is not in the readable keys allowlist`,\n policySource: \".q-ring.json policy.mcp.readableKeys\",\n };\n }\n\n if (tags && policy.mcp.deniedTags) {\n const blocked = tags.find((t) => policy.mcp!.deniedTags!.includes(t));\n if (blocked) {\n return {\n allowed: false,\n reason: `Tag \"${blocked}\" is denied by project policy`,\n policySource: \".q-ring.json policy.mcp.deniedTags\",\n };\n }\n }\n\n return { allowed: true, policySource: \".q-ring.json\" };\n}\n\nexport function checkExecPolicy(command: string, projectPath?: string): PolicyDecision {\n const policy = loadPolicy(projectPath);\n if (!policy.exec) return { allowed: true, policySource: \"no-policy\" };\n\n if (policy.exec.denyCommands) {\n // Match on token/path boundaries so denying \"rm\" does not also block\n // \"charm\" or \"npm\", while still catching \"/usr/bin/rm\" and \"rm -rf\".\n const denied = policy.exec.denyCommands.find((d) => {\n const pattern = new RegExp(\n `(^|[\\\\s/])${d.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}(\\\\s|$)`,\n \"i\",\n );\n return pattern.test(command);\n });\n if (denied) {\n return {\n allowed: false,\n reason: `Command containing \"${denied}\" is denied by project policy`,\n policySource: \".q-ring.json policy.exec.denyCommands\",\n };\n }\n }\n\n if (policy.exec.allowCommands) {\n const normalized = command.trimStart();\n const allowed = policy.exec.allowCommands.some((a) => normalized.startsWith(a));\n if (!allowed) {\n return {\n allowed: false,\n reason: `Command \"${command}\" is not in the exec allowlist`,\n policySource: \".q-ring.json policy.exec.allowCommands\",\n };\n }\n }\n\n return { allowed: true, policySource: \".q-ring.json\" };\n}\n\nexport function getExecMaxRuntime(projectPath?: string): number | undefined {\n return loadPolicy(projectPath).exec?.maxRuntimeSeconds;\n}\n\nexport function getPolicySummary(projectPath?: string): {\n hasMcpPolicy: boolean;\n hasExecPolicy: boolean;\n hasSecretPolicy: boolean;\n details: PolicyConfig;\n} {\n const policy = loadPolicy(projectPath);\n return {\n hasMcpPolicy: !!policy.mcp,\n hasExecPolicy: !!policy.exec,\n hasSecretPolicy: !!policy.secrets,\n details: policy,\n };\n}\n","import { createHash } from \"node:crypto\";\n\nexport function hashProjectPath(projectPath: string): string {\n return createHash(\"sha256\").update(projectPath).digest(\"hex\").slice(0, 12);\n}\n","import { hashProjectPath } from \"../utils/hash.js\";\n\nconst SERVICE_PREFIX = \"q-ring\";\n\nexport type Scope = \"global\" | \"project\" | \"team\" | \"org\";\n\nexport interface ResolvedScope {\n scope: Scope;\n service: string;\n projectPath?: string;\n teamId?: string;\n orgId?: string;\n}\n\nexport function globalService(): string {\n return `${SERVICE_PREFIX}:global`;\n}\n\nexport function projectService(projectPath: string): string {\n const hash = hashProjectPath(projectPath);\n return `${SERVICE_PREFIX}:project:${hash}`;\n}\n\nexport function teamService(teamId: string): string {\n return `${SERVICE_PREFIX}:team:${teamId}`;\n}\n\nexport function orgService(orgId: string): string {\n return `${SERVICE_PREFIX}:org:${orgId}`;\n}\n\nexport interface ScopeOpts {\n scope?: Scope;\n projectPath?: string;\n teamId?: string;\n orgId?: string;\n}\n\n/**\n * Resolution order (most specific first):\n * project → team → org → global\n *\n * When a scope is explicitly requested, only that scope is returned.\n * When no scope is specified, the full resolution chain is built so\n * project-level secrets override team, which override org, which\n * override global.\n */\nexport function resolveScope(opts: ScopeOpts): ResolvedScope[] {\n const { scope, projectPath, teamId, orgId } = opts;\n\n if (scope === \"global\") {\n return [{ scope: \"global\", service: globalService() }];\n }\n\n if (scope === \"project\") {\n if (!projectPath) throw new Error(\"Project path is required for project scope\");\n return [{ scope: \"project\", service: projectService(projectPath), projectPath }];\n }\n\n if (scope === \"team\") {\n if (!teamId) throw new Error(\"Team ID is required for team scope\");\n return [{ scope: \"team\", service: teamService(teamId), teamId }];\n }\n\n if (scope === \"org\") {\n if (!orgId) throw new Error(\"Org ID is required for org scope\");\n return [{ scope: \"org\", service: orgService(orgId), orgId }];\n }\n\n const chain: ResolvedScope[] = [];\n\n if (projectPath) {\n chain.push({ scope: \"project\", service: projectService(projectPath), projectPath });\n }\n if (teamId) {\n chain.push({ scope: \"team\", service: teamService(teamId), teamId });\n }\n if (orgId) {\n chain.push({ scope: \"org\", service: orgService(orgId), orgId });\n }\n\n chain.push({ scope: \"global\", service: globalService() });\n return chain;\n}\n\n/**\n * The single service string for one specific scope, given resolution opts.\n * Unlike resolveScope (which builds the precedence chain when scope is omitted),\n * this always returns exactly one service — used to bind an approval to the\n * concrete project/team/org identity rather than the coarse scope label.\n */\nexport function serviceForScope(\n scope: Scope,\n opts: Omit<ScopeOpts, \"scope\"> = {},\n): string {\n return resolveScope({ ...opts, scope })[0].service;\n}\n\nexport function parseServiceName(service: string): ResolvedScope {\n if (service === globalService()) {\n return { scope: \"global\", service };\n }\n if (service.startsWith(`${SERVICE_PREFIX}:project:`)) {\n return { scope: \"project\", service };\n }\n if (service.startsWith(`${SERVICE_PREFIX}:team:`)) {\n const teamId = service.slice(`${SERVICE_PREFIX}:team:`.length);\n return { scope: \"team\", service, teamId };\n }\n if (service.startsWith(`${SERVICE_PREFIX}:org:`)) {\n const orgId = service.slice(`${SERVICE_PREFIX}:org:`.length);\n return { scope: \"org\", service, orgId };\n }\n return { scope: \"global\", service };\n}\n","/**\n * Approval Notifications\n *\n * When an MCP agent is blocked on a secret that requires user approval, the\n * denial reaches the agent — but the human it is asking for is looking at a\n * different window. This module raises a best-effort desktop notification\n * (`notify-send` on Linux, `osascript` on macOS) telling the user which key\n * is waiting and what to run.\n *\n * Strictly best-effort: notification failure must never affect the deny\n * itself, and repeated agent retries are throttled per key so a retry loop\n * cannot spam the desktop. Disable entirely with QRING_NOTIFY=off.\n */\n\nimport { spawn } from \"node:child_process\";\n\nconst DISABLE_ENV = \"QRING_NOTIFY\";\nconst THROTTLE_MS = 5 * 60 * 1000;\n\n// Per-key last-notified timestamps. In-memory is enough: the MCP server that\n// hits approval denials is a long-lived process.\nconst lastNotified = new Map<string, number>();\n\n/** Reset throttle state (tests). */\nexport function resetNotifyThrottle(): void {\n lastNotified.clear();\n}\n\nexport function notificationsEnabled(): boolean {\n const value = process.env[DISABLE_ENV];\n return value !== \"off\" && value !== \"0\" && value !== \"false\";\n}\n\n/**\n * Fire a desktop notification, detached and fire-and-forget. Returns whether\n * a notifier was launched (false on unsupported platforms or errors).\n */\nexport function notifyUser(title: string, body: string): boolean {\n try {\n let command: string;\n let args: string[];\n\n if (process.platform === \"linux\") {\n command = \"notify-send\";\n args = [\"--app-name=q-ring\", \"--urgency=critical\", title, body];\n } else if (process.platform === \"darwin\") {\n command = \"osascript\";\n // Args are passed as argv (no shell); quotes in the payload are\n // stripped rather than escaped to keep the AppleScript literal inert.\n const clean = (s: string) => s.replace(/[\"\\\\]/g, \"\");\n args = [\"-e\", `display notification \"${clean(body)}\" with title \"${clean(title)}\"`];\n } else {\n return false;\n }\n\n const child = spawn(command, args, { detached: true, stdio: \"ignore\" });\n child.on(\"error\", () => {\n /* notifier missing — best-effort */\n });\n child.unref();\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Notify the user that an agent is waiting on approval for `key`.\n * Throttled to once per key per 5 minutes.\n */\nexport function notifyApprovalRequested(key: string, source: string): void {\n if (!notificationsEnabled()) return;\n\n const now = Date.now();\n const last = lastNotified.get(key);\n if (last !== undefined && now - last < THROTTLE_MS) return;\n lastNotified.set(key, now);\n\n notifyUser(\n \"q-ring: approval requested\",\n `An ${source} agent wants to read \"${key}\". Allow with: qring approve ${key}`,\n );\n}\n","/**\n * Canary trip alerting.\n *\n * Kept separate from canary.ts so keyring.ts can import the trip hook without\n * a keyring <-> canary import cycle (canary.ts plants through setSecret).\n *\n * A trip is deliberately LOUD: it lands in the tamper-evident audit chain as\n * its own \"canary\" action and raises a desktop notification with a shorter\n * throttle than approval notices — a burst of reads is itself the signal.\n */\n\nimport { logAudit, getAuditAgentLabel } from \"./observer.js\";\nimport { notificationsEnabled, notifyUser } from \"./notify.js\";\n\nconst TRIP_THROTTLE_MS = 30 * 1000;\n\nconst lastAlerted = new Map<string, number>();\n\n/** Reset throttle state (tests). */\nexport function resetCanaryAlertThrottle(): void {\n lastAlerted.clear();\n}\n\nexport interface CanaryTrip {\n key: string;\n scope: string;\n env?: string;\n source: \"cli\" | \"mcp\" | \"agent\" | \"api\" | \"hook\" | \"ci\";\n}\n\n/**\n * Record a canary read: audit event first (never throttled), then a\n * best-effort desktop alert throttled per key.\n */\nexport function recordCanaryTrip(trip: CanaryTrip): void {\n const agent = getAuditAgentLabel();\n logAudit({\n action: \"canary\",\n key: trip.key,\n scope: trip.scope,\n env: trip.env,\n source: trip.source,\n detail: `CANARY TRIPPED: honeytoken read via ${trip.source}`,\n });\n\n if (!notificationsEnabled()) return;\n const now = Date.now();\n const last = lastAlerted.get(trip.key);\n if (last !== undefined && now - last < TRIP_THROTTLE_MS) return;\n lastAlerted.set(trip.key, now);\n\n const who = agent ? `${trip.source} (${agent})` : trip.source;\n notifyUser(\n \"q-ring: CANARY TRIPPED\",\n `Honeytoken \"${trip.key}\" was read by ${who}. This credential is fake — but something reached for it. Investigate: qring audit --action canary`,\n );\n}\n","/**\n * Just-In-Time (JIT) Credential Provisioning\n *\n * Dynamically generates short-lived credentials when requested, caching them\n * until they expire.\n */\n\nimport { execFileSync, spawnSync } from \"node:child_process\";\nimport { z } from \"zod\";\nimport { checkJitHttpProvisionUrl } from \"./ssrf.js\";\n\nconst AwsStsConfigSchema = z.object({\n roleArn: z.string(),\n sessionName: z.string().optional(),\n durationSeconds: z.number().optional(),\n});\n\nconst HttpJitConfigSchema = z.object({\n url: z.string(),\n method: z.string().optional(),\n valuePath: z.string().optional(),\n expiresInSeconds: z.number().optional(),\n headers: z.record(z.string(), z.string()).optional(),\n body: z.unknown().optional(),\n});\n\nexport interface ProvisionResult {\n value: string;\n expiresAt: string;\n}\n\nexport interface JitProvider {\n name: string;\n description: string;\n provision(configRaw: string): ProvisionResult;\n}\n\nexport class ProvisionRegistry {\n private providers = new Map<string, JitProvider>();\n\n register(provider: JitProvider): void {\n this.providers.set(provider.name, provider);\n }\n\n get(name: string): JitProvider | undefined {\n return this.providers.get(name);\n }\n\n listProviders(): JitProvider[] {\n return [...this.providers.values()];\n }\n}\n\n// Built-in Providers\n\nconst awsStsProvider: JitProvider = {\n name: \"aws-sts\",\n description: \"AWS STS AssumeRole (requires existing local AWS CLI credentials)\",\n provision(configRaw: string): ProvisionResult {\n let raw: unknown;\n try {\n raw = JSON.parse(configRaw);\n } catch {\n throw new Error(\"aws-sts requires valid JSON config (e.g. {\\\"roleArn\\\":\\\"arn:aws:...\\\"})\");\n }\n const parsed = AwsStsConfigSchema.safeParse(raw);\n if (!parsed.success) {\n throw new Error(`aws-sts invalid config: ${parsed.error.message}`);\n }\n const config = parsed.data;\n\n const roleArn = config.roleArn;\n const sessionName = config.sessionName || \"q-ring-agent\";\n const duration = config.durationSeconds || 3600;\n\n try {\n const output = execFileSync(\"aws\", [\n \"sts\", \"assume-role\",\n \"--role-arn\", roleArn,\n \"--role-session-name\", sessionName,\n \"--duration-seconds\", String(duration),\n \"--output\", \"json\",\n ], { encoding: \"utf8\" });\n const parsed = JSON.parse(output);\n const creds = parsed.Credentials;\n \n const value = JSON.stringify({\n AWS_ACCESS_KEY_ID: creds.AccessKeyId,\n AWS_SECRET_ACCESS_KEY: creds.SecretAccessKey,\n AWS_SESSION_TOKEN: creds.SessionToken,\n });\n \n return {\n value,\n expiresAt: creds.Expiration\n };\n } catch (err) {\n throw new Error(`AWS STS provision failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n }\n }\n};\n\nconst httpProvider: JitProvider = {\n name: \"http\",\n description: \"Generic HTTP token endpoint using Node.js http/https\",\n provision(configRaw: string): ProvisionResult {\n let raw: unknown;\n try {\n raw = JSON.parse(configRaw);\n } catch {\n throw new Error(\"http provider requires valid JSON config\");\n }\n const parsed = HttpJitConfigSchema.safeParse(raw);\n if (!parsed.success) {\n throw new Error(`http provider invalid config: ${parsed.error.message}`);\n }\n const config = parsed.data;\n\n const url = config.url;\n const method = config.method || \"POST\";\n const valuePath = config.valuePath || \"token\"; // dot notation path to value\n const expiresInSeconds = config.expiresInSeconds || 3600;\n\n if (!url) throw new Error(\"http provider requires url in config\");\n\n const ssrfBlock = checkJitHttpProvisionUrl(url);\n if (ssrfBlock) throw new Error(`SSRF blocked: ${ssrfBlock}`);\n\n const headers: Record<string, string> = {\n \"User-Agent\": \"q-ring-jit/1.0\",\n ...(config.headers ?? {}),\n };\n let bodyStr: string | undefined;\n if (config.body) {\n headers[\"Content-Type\"] = \"application/json\";\n bodyStr = JSON.stringify(config.body);\n }\n\n // Pass config via environment variable to avoid code interpolation\n const scriptConfig = JSON.stringify({ url, method, headers, bodyStr });\n\n // Static script that reads config from env var\n const script = `\nconst cfg = JSON.parse(process.env.__QRING_HTTP_CFG);\nconst parsedUrl = new URL(cfg.url);\nconst http = require(parsedUrl.protocol === \"https:\" ? \"node:https\" : \"node:http\");\nconst req = http.request(cfg.url, { method: cfg.method, headers: cfg.headers, timeout: 30000 }, (res) => {\n let body = \"\";\n res.on(\"data\", (chunk) => body += chunk);\n res.on(\"end\", () => process.stdout.write(body));\n});\nreq.on(\"error\", (e) => { process.stderr.write(e.message); process.exit(1); });\nif (cfg.bodyStr) req.write(cfg.bodyStr);\nreq.end();\n`;\n\n try {\n const result = spawnSync(\"node\", [\"-e\", script], {\n encoding: \"utf8\",\n timeout: 35000,\n env: { ...process.env, __QRING_HTTP_CFG: scriptConfig },\n });\n\n if (result.status !== 0) {\n throw new Error(result.stderr || \"HTTP request failed\");\n }\n\n const parsed = JSON.parse(result.stdout);\n let val = parsed;\n for (const key of valuePath.split(\".\")) {\n val = val[key];\n }\n return {\n value: String(val),\n expiresAt: new Date(Date.now() + expiresInSeconds * 1000).toISOString()\n };\n } catch (err) {\n throw new Error(`HTTP provision failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });\n }\n }\n};\n\nexport const registry = new ProvisionRegistry();\nregistry.register(awsStsProvider);\nregistry.register(httpProvider);\n","import { withFileLock } from \"../utils/file-lock.js\";\nimport { Entry, findCredentials } from \"./backend.js\";\nimport {\n resolveScope,\n serviceForScope,\n globalService,\n projectService,\n teamService,\n orgService,\n type Scope,\n} from \"./scope.js\";\nimport {\n type QuantumEnvelope,\n type Environment,\n createEnvelope,\n parseEnvelope,\n wrapLegacy,\n serializeEnvelope,\n collapseValue,\n checkDecay,\n recordAccess,\n type DecayStatus,\n} from \"./envelope.js\";\nimport { collapseEnvironment } from \"./collapse.js\";\nimport { logAudit } from \"./observer.js\";\nimport { findEntangled, entangle as entangleLink, disentangle as disentangleLink } from \"./entanglement.js\";\nimport { fireHooks } from \"./hooks.js\";\nimport { hasApproval } from \"./approval.js\";\nimport { notifyApprovalRequested } from \"./notify.js\";\nimport { recordCanaryTrip } from \"./canary-alert.js\";\nimport { registry as jitRegistry } from \"./provision.js\";\nimport { checkKeyReadPolicy, checkSecretLifecyclePolicy, getPolicyRoot } from \"./policy.js\";\n\nfunction withJitEnvelopeLock<T>(service: string, key: string, fn: () => T): T {\n return withFileLock(`${service}\\0${key}`, fn, { dir: \"jit-locks\" });\n}\n\nexport interface SecretEntry {\n key: string;\n scope: Scope;\n value?: string;\n envelope?: QuantumEnvelope;\n decay?: DecayStatus;\n}\n\nexport interface KeyringOptions {\n scope?: Scope;\n projectPath?: string;\n /** Team identifier for team-scoped secrets */\n teamId?: string;\n /** Org identifier for org-scoped secrets */\n orgId?: string;\n /** Environment for superposition collapse */\n env?: Environment;\n /** Audit source */\n source?: \"cli\" | \"mcp\" | \"agent\" | \"api\" | \"hook\" | \"ci\";\n /** Skip audit logging (for internal polling like the dashboard) */\n silent?: boolean;\n}\n\nexport interface SetSecretOptions extends KeyringOptions {\n /** Environment states for superposition */\n states?: Record<Environment, string>;\n /** Default environment */\n defaultEnv?: Environment;\n /** TTL in seconds (quantum decay) */\n ttlSeconds?: number;\n /** Expiry timestamp */\n expiresAt?: string;\n /** Description */\n description?: string;\n /** Tags */\n tags?: string[];\n /** Format for auto-rotation (e.g. \"api-key\", \"password\", \"uuid\") */\n rotationFormat?: string;\n /** Prefix for auto-rotation (e.g. \"sk-\") */\n rotationPrefix?: string;\n /** Provider for liveness validation (e.g. \"openai\", \"stripe\") */\n provider?: string;\n /** Whether reading this secret via MCP requires explicit user approval */\n requiresApproval?: boolean;\n /** Just-In-Time (JIT) provisioning provider name (e.g. \"aws-sts\") */\n jitProvider?: string;\n /** Honeytoken: any read fires a loud canary alert */\n canary?: boolean;\n /** Provider token shape the canary value imitates */\n canaryFormat?: string;\n}\n\nfunction readEnvelope(service: string, key: string): QuantumEnvelope | null {\n const entry = new Entry(service, key);\n const raw = entry.getPassword();\n if (raw === null) return null;\n\n const envelope = parseEnvelope(raw);\n return envelope ?? wrapLegacy(raw);\n}\n\nfunction writeEnvelope(\n service: string,\n key: string,\n envelope: QuantumEnvelope,\n): void {\n const entry = new Entry(service, key);\n entry.setPassword(serializeEnvelope(envelope));\n}\n\nfunction resolveEnv(opts: KeyringOptions): Environment | undefined {\n if (opts.env) return opts.env;\n const result = collapseEnvironment({ projectPath: opts.projectPath });\n return result?.env;\n}\n\nfunction resolveTemplates(value: string, opts: KeyringOptions & { _seen?: Set<string> }, seen: Set<string>): string {\n if (!value.includes(\"{{\") || !value.includes(\"}}\")) return value;\n \n return value.replace(/\\{\\{([^}]+)\\}\\}/g, (_match, refKeyRaw) => {\n const refKey = refKeyRaw.trim();\n const refValue = getSecret(refKey, { ...opts, _seen: seen });\n if (refValue === null) {\n throw new Error(`Template resolution failed: referenced secret \"${refKey}\" not found`);\n }\n return refValue;\n });\n}\n\nexport function resolveTemplatesOffline(value: string, rawValues: Map<string, string>, seen: Set<string>): string {\n if (!value.includes(\"{{\") || !value.includes(\"}}\")) return value;\n \n return value.replace(/\\{\\{([^}]+)\\}\\}/g, (_match, refKeyRaw) => {\n const refKey = refKeyRaw.trim();\n if (seen.has(refKey)) {\n throw new Error(`Circular dependency detected: ${[...seen].join(\" -> \")} -> ${refKey}`);\n }\n const rawRef = rawValues.get(refKey);\n if (rawRef === undefined) {\n throw new Error(`Template resolution failed: referenced secret \"${refKey}\" not found`);\n }\n const nextSeen = new Set(seen);\n nextSeen.add(refKey);\n return resolveTemplatesOffline(rawRef, rawValues, nextSeen);\n });\n}\n\n/**\n * Retrieve a secret by key, with scope resolution and superposition collapse.\n * Records the access in the audit log (observer effect).\n */\nexport function getSecret(\n key: string,\n opts: KeyringOptions & { _seen?: Set<string> } = {},\n): string | null {\n const scopes = resolveScope(opts);\n const env = resolveEnv(opts);\n const source = opts.source ?? \"cli\";\n const seen = opts._seen ?? new Set<string>();\n\n if (source === \"mcp\") {\n const policyDecision = checkKeyReadPolicy(key, undefined, opts.projectPath);\n if (!policyDecision.allowed) {\n throw new Error(`Policy Denied: ${policyDecision.reason}`);\n }\n }\n\n if (seen.has(key)) {\n throw new Error(`Circular dependency detected: ${[...seen].join(\" -> \")} -> ${key}`);\n }\n const nextSeen = new Set(seen);\n nextSeen.add(key);\n\n for (const { service, scope } of scopes) {\n const envelope = readEnvelope(service, key);\n if (!envelope) continue;\n\n // Check decay\n const decay = checkDecay(envelope);\n if (decay.isExpired) {\n if (!opts.silent) {\n logAudit({\n action: \"read\",\n key,\n scope,\n source,\n detail: \"blocked: secret expired (quantum decay)\",\n });\n }\n continue;\n }\n\n // Check approvals for MCP\n if (envelope.meta.requiresApproval && source === \"mcp\") {\n if (!hasApproval(key, scope, service)) {\n if (!opts.silent) {\n logAudit({\n action: \"read\",\n key,\n scope,\n source,\n detail: \"blocked: requires user approval\",\n });\n notifyApprovalRequested(key, source);\n }\n throw new Error(`Access Denied: This secret requires user approval. Please ask the user to run 'qring approve ${key}'`);\n }\n }\n\n // Collapse superposition\n let value = collapseValue(envelope, env);\n if (value === null) continue;\n\n // Just-In-Time Provisioning\n if (envelope.meta.jitProvider) {\n const provider = jitRegistry.get(envelope.meta.jitProvider);\n if (provider) {\n let isExpired = true;\n if (envelope.states && envelope.states[\"jit\"] && envelope.meta.jitExpiresAt) {\n isExpired = new Date(envelope.meta.jitExpiresAt).getTime() <= Date.now();\n }\n\n if (isExpired) {\n const jitConfigSource = value;\n withJitEnvelopeLock(service, key, () => {\n const latest = readEnvelope(service, key);\n if (!latest?.meta.jitProvider) return;\n let innerExpired = true;\n if (\n latest.states &&\n latest.states[\"jit\"] &&\n latest.meta.jitExpiresAt\n ) {\n innerExpired =\n new Date(latest.meta.jitExpiresAt).getTime() <= Date.now();\n }\n if (!innerExpired) {\n envelope.states = latest.states;\n envelope.meta.jitExpiresAt = latest.meta.jitExpiresAt;\n return;\n }\n const result = provider.provision(jitConfigSource);\n latest.states = latest.states ?? {};\n latest.states[\"jit\"] = result.value;\n latest.meta.jitExpiresAt = result.expiresAt;\n writeEnvelope(service, key, latest);\n envelope.states = latest.states;\n envelope.meta.jitExpiresAt = latest.meta.jitExpiresAt;\n });\n }\n value = envelope.states![\"jit\"];\n }\n }\n\n // Resolve templates\n value = resolveTemplates(value, { ...opts, _seen: nextSeen }, nextSeen);\n\n // Observer effect: record access and persist. Re-read the current envelope\n // first so a value written concurrently between our read above and this\n // write-back is preserved — the access counter is deliberately\n // last-write-wins, but the secret value must never be clobbered (B4).\n if (!opts.silent) {\n const latest = readEnvelope(service, key) ?? envelope;\n writeEnvelope(service, key, recordAccess(latest));\n logAudit({ action: \"read\", key, scope, env, source });\n // Honeytoken trip: still return the (fake) value so the reader has no\n // tell — the alarm is the side effect, not a denial. Silent reads\n // (dashboard polling) deliberately don't trip.\n if (envelope.meta.canary) {\n recordCanaryTrip({ key, scope, env, source });\n }\n }\n\n return value;\n }\n\n return null;\n}\n\n/**\n * Get the full envelope for a secret (for inspection, no value extraction).\n */\nexport function getEnvelope(\n key: string,\n opts: KeyringOptions = {},\n): { envelope: QuantumEnvelope; scope: Scope } | null {\n const source = opts.source ?? \"cli\";\n\n if (source === \"mcp\") {\n const policyDecision = checkKeyReadPolicy(key, undefined, opts.projectPath);\n if (!policyDecision.allowed) {\n throw new Error(`Policy Denied: ${policyDecision.reason}`);\n }\n }\n\n const scopes = resolveScope(opts);\n\n for (const { service, scope } of scopes) {\n const envelope = readEnvelope(service, key);\n if (envelope) return { envelope, scope };\n }\n\n return null;\n}\n\n/**\n * Store a secret with quantum metadata.\n */\nexport function setSecret(\n key: string,\n value: string,\n opts: SetSecretOptions = {},\n): void {\n const scope = opts.scope ?? \"global\";\n const scopes = resolveScope({ ...opts, scope });\n const { service } = scopes[0];\n const source = opts.source ?? \"cli\";\n\n // Check if there's an existing envelope to preserve metadata\n const existing = readEnvelope(service, key);\n\n let envelope: QuantumEnvelope;\n\n const rotFmt = opts.rotationFormat ?? existing?.meta.rotationFormat;\n const rotPfx = opts.rotationPrefix ?? existing?.meta.rotationPrefix;\n const prov = opts.provider ?? existing?.meta.provider;\n const reqApp = opts.requiresApproval ?? existing?.meta.requiresApproval;\n const jitProv = opts.jitProvider ?? existing?.meta.jitProvider;\n const canaryFlag = opts.canary ?? existing?.meta.canary;\n const canaryFmt = opts.canaryFormat ?? existing?.meta.canaryFormat;\n\n const mergedTags = opts.tags ?? existing?.meta.tags;\n const ttlForPolicy = opts.ttlSeconds ?? existing?.meta.ttlSeconds;\n const life = checkSecretLifecyclePolicy(\n {\n tags: mergedTags,\n ttlSeconds: ttlForPolicy,\n rotationFormat: rotFmt,\n requiresApproval: !!reqApp,\n },\n opts.projectPath,\n );\n if (!life.allowed) {\n throw new Error(life.reason ?? \"Secret lifecycle policy denied\");\n }\n\n if (opts.states) {\n envelope = createEnvelope(\"\", {\n states: opts.states,\n defaultEnv: opts.defaultEnv,\n description: opts.description,\n tags: opts.tags,\n ttlSeconds: opts.ttlSeconds,\n expiresAt: opts.expiresAt,\n entangled: existing?.meta.entangled,\n rotationFormat: rotFmt,\n rotationPrefix: rotPfx,\n provider: prov,\n requiresApproval: reqApp,\n jitProvider: jitProv,\n canary: canaryFlag,\n canaryFormat: canaryFmt,\n });\n } else {\n envelope = createEnvelope(value, {\n description: opts.description,\n tags: opts.tags,\n ttlSeconds: opts.ttlSeconds,\n expiresAt: opts.expiresAt,\n entangled: existing?.meta.entangled,\n rotationFormat: rotFmt,\n rotationPrefix: rotPfx,\n provider: prov,\n requiresApproval: reqApp,\n jitProvider: jitProv,\n canary: canaryFlag,\n canaryFormat: canaryFmt,\n });\n }\n\n // Preserve access count from existing\n if (existing) {\n envelope.meta.createdAt = existing.meta.createdAt;\n envelope.meta.accessCount = existing.meta.accessCount;\n }\n\n writeEnvelope(service, key, envelope);\n logAudit({ action: \"write\", key, scope, source });\n\n // Propagate to entangled secrets\n const entangled = findEntangled({ service, key });\n for (const target of entangled) {\n try {\n // An MCP-sourced write must not silently propagate into a key the\n // caller's policy forbids — otherwise entanglement is a write primitive\n // that bypasses deniedKeys/deniedTags (A2). CLI writes are unrestricted\n // by design (the local operator already has full access).\n if (source === \"mcp\") {\n const decision = checkKeyReadPolicy(target.key, undefined, opts.projectPath);\n if (!decision.allowed) {\n logAudit({\n action: \"entangle\",\n key: target.key,\n scope: \"global\",\n source,\n detail: `blocked propagation from ${key}: ${decision.reason}`,\n });\n continue;\n }\n }\n const targetEnvelope = readEnvelope(target.service, target.key);\n if (targetEnvelope) {\n if (opts.states) {\n targetEnvelope.states = opts.states;\n } else {\n targetEnvelope.value = value;\n }\n targetEnvelope.meta.updatedAt = new Date().toISOString();\n writeEnvelope(target.service, target.key, targetEnvelope);\n logAudit({\n action: \"entangle\",\n key: target.key,\n scope: \"global\",\n source,\n detail: `propagated from ${key}`,\n });\n }\n } catch {\n // entangled target may not exist\n }\n }\n\n fireHooks({\n action: \"write\",\n key,\n scope,\n timestamp: new Date().toISOString(),\n source,\n }, envelope.meta.tags).catch(() => {});\n}\n\n/**\n * Delete a secret from the specified scope (or both if unscoped).\n */\nexport function deleteSecret(\n key: string,\n opts: KeyringOptions = {},\n): boolean {\n const scopes = resolveScope(opts);\n const source = opts.source ?? \"cli\";\n\n if (source === \"mcp\") {\n const policyDecision = checkKeyReadPolicy(key, undefined, opts.projectPath);\n if (!policyDecision.allowed) {\n throw new Error(`Policy Denied: ${policyDecision.reason}`);\n }\n }\n\n let deleted = false;\n\n for (const { service, scope } of scopes) {\n const entry = new Entry(service, key);\n try {\n if (entry.deleteCredential()) {\n deleted = true;\n logAudit({ action: \"delete\", key, scope, source });\n fireHooks({\n action: \"delete\",\n key,\n scope,\n timestamp: new Date().toISOString(),\n source,\n }).catch(() => {});\n }\n } catch {\n // not found\n }\n }\n\n return deleted;\n}\n\n/**\n * Check whether a secret exists in any applicable scope.\n */\nexport function hasSecret(\n key: string,\n opts: KeyringOptions = {},\n): boolean {\n const source = opts.source ?? \"cli\";\n\n if (source === \"mcp\") {\n const policyDecision = checkKeyReadPolicy(key, undefined, opts.projectPath);\n if (!policyDecision.allowed) return false;\n }\n\n const scopes = resolveScope(opts);\n\n for (const { service } of scopes) {\n const envelope = readEnvelope(service, key);\n if (envelope) {\n const decay = checkDecay(envelope);\n if (!decay.isExpired) return true;\n }\n }\n\n return false;\n}\n\n/**\n * List all secrets across applicable scopes with quantum metadata.\n */\nexport function listSecrets(opts: KeyringOptions = {}): SecretEntry[] {\n const source = opts.source ?? \"cli\";\n const services: { service: string; scope: Scope }[] = [];\n\n if (!opts.scope || opts.scope === \"global\") {\n services.push({ service: globalService(), scope: \"global\" });\n }\n\n if ((!opts.scope || opts.scope === \"project\") && opts.projectPath) {\n services.push({\n service: projectService(opts.projectPath),\n scope: \"project\",\n });\n }\n\n if ((!opts.scope || opts.scope === \"team\") && opts.teamId) {\n services.push({ service: teamService(opts.teamId), scope: \"team\" });\n }\n\n if ((!opts.scope || opts.scope === \"org\") && opts.orgId) {\n services.push({ service: orgService(opts.orgId), scope: \"org\" });\n }\n\n const results: SecretEntry[] = [];\n const seen = new Set<string>();\n\n for (const { service, scope } of services) {\n try {\n const credentials = findCredentials(service);\n for (const cred of credentials) {\n const id = `${scope}:${cred.account}`;\n if (seen.has(id)) continue;\n seen.add(id);\n\n const envelope = parseEnvelope(cred.password) ?? wrapLegacy(cred.password);\n const decay = checkDecay(envelope);\n\n results.push({\n key: cred.account,\n scope,\n envelope,\n decay,\n });\n }\n } catch {\n // keyring unavailable\n }\n }\n\n if (!opts.silent) {\n logAudit({ action: \"list\", source });\n }\n\n const sorted = results.sort((a, b) => a.key.localeCompare(b.key));\n\n if (source === \"mcp\") {\n return sorted.filter((e) => {\n const decision = checkKeyReadPolicy(e.key, undefined, opts.projectPath);\n return decision.allowed;\n });\n }\n\n return sorted;\n}\n\n/**\n * Export all secrets with their values (for .env or JSON export).\n * Collapses superposition based on detected environment.\n */\nexport function exportSecrets(\n opts: KeyringOptions & { format?: \"env\" | \"json\"; keys?: string[]; tags?: string[] } = {},\n): string {\n const format = opts.format ?? \"env\";\n const env = resolveEnv(opts);\n let entries = listSecrets(opts);\n const source = opts.source ?? \"cli\";\n\n if (opts.keys?.length) {\n const keySet = new Set(opts.keys);\n entries = entries.filter((e) => keySet.has(e.key));\n }\n\n if (opts.tags?.length) {\n entries = entries.filter((e) =>\n opts.tags!.some((t) => e.envelope?.meta.tags?.includes(t)),\n );\n }\n\n const rawValues = new Map<string, string>();\n\n // Process in precedence order: global < org < team < project\n const globalEntries = entries.filter((e) => e.scope === \"global\");\n const orgEntries = entries.filter((e) => e.scope === \"org\");\n const teamEntries = entries.filter((e) => e.scope === \"team\");\n const projectEntries = entries.filter((e) => e.scope === \"project\");\n\n for (const entry of [...globalEntries, ...orgEntries, ...teamEntries, ...projectEntries]) {\n if (entry.envelope) {\n const decay = checkDecay(entry.envelope);\n if (decay.isExpired) continue;\n\n // Honor the approval gate on bulk reads too — otherwise export_secrets\n // would surface approval-protected values to an MCP agent that getSecret\n // would have denied. Silently skip (consistent with policy filtering).\n if (\n source === \"mcp\" &&\n entry.envelope.meta.requiresApproval &&\n !hasApproval(entry.key, entry.scope, serviceForScope(entry.scope, opts))\n ) {\n logAudit({\n action: \"read\",\n key: entry.key,\n scope: entry.scope,\n source,\n detail: \"blocked: requires user approval (export)\",\n });\n continue;\n }\n\n const value = collapseValue(entry.envelope, env);\n if (value !== null) {\n rawValues.set(entry.key, value);\n }\n }\n }\n\n const merged = new Map<string, string>();\n for (const [key, value] of rawValues) {\n try {\n const resolved = resolveTemplatesOffline(value, rawValues, new Set([key]));\n merged.set(key, resolved);\n } catch (err) {\n // In export, if a template fails, we just don't export it\n console.warn(`Warning: skipped exporting ${key} due to template error: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n logAudit({ action: \"export\", source, detail: `format=${format}` });\n\n if (format === \"json\") {\n const obj: Record<string, string> = {};\n for (const [key, value] of merged) {\n obj[key] = value;\n }\n return JSON.stringify(obj, null, 2);\n }\n\n const lines: string[] = [];\n for (const [key, value] of merged) {\n const escaped = value\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\");\n lines.push(`${key}=\"${escaped}\"`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Create an entanglement between two secrets.\n */\nexport function entangleSecrets(\n sourceKey: string,\n sourceOpts: KeyringOptions,\n targetKey: string,\n targetOpts: KeyringOptions,\n): void {\n const sourceScopes = resolveScope({ ...sourceOpts, scope: sourceOpts.scope ?? \"global\" });\n const targetScopes = resolveScope({ ...targetOpts, scope: targetOpts.scope ?? \"global\" });\n\n const source = { service: sourceScopes[0].service, key: sourceKey };\n const target = { service: targetScopes[0].service, key: targetKey };\n\n entangleLink(source, target, {\n source: sourceOpts.source ?? \"cli\",\n policyRoot: getPolicyRoot(),\n });\n logAudit({\n action: \"entangle\",\n key: sourceKey,\n source: sourceOpts.source ?? \"cli\",\n detail: `entangled with ${targetKey}`,\n });\n}\n\n/**\n * Remove an entanglement between two secrets.\n */\nexport function disentangleSecrets(\n sourceKey: string,\n sourceOpts: KeyringOptions,\n targetKey: string,\n targetOpts: KeyringOptions,\n): void {\n const sourceScopes = resolveScope({ ...sourceOpts, scope: sourceOpts.scope ?? \"global\" });\n const targetScopes = resolveScope({ ...targetOpts, scope: targetOpts.scope ?? \"global\" });\n\n const source = { service: sourceScopes[0].service, key: sourceKey };\n const target = { service: targetScopes[0].service, key: targetKey };\n\n disentangleLink(source, target);\n logAudit({\n action: \"entangle\",\n key: sourceKey,\n source: sourceOpts.source ?? \"cli\",\n detail: `disentangled from ${targetKey}`,\n });\n}\n","/**\n * Quantum Tunneling: ephemeral secrets that exist only in memory.\n *\n * Tunneled secrets are never persisted to the OS keyring. They live\n * in a process-scoped in-memory store with optional auto-expiry.\n * Useful for passing secrets between agents without touching disk.\n */\n\nimport { randomBytes } from \"node:crypto\";\n\ninterface TunnelEntry {\n value: string;\n createdAt: number;\n expiresAt?: number;\n accessCount: number;\n /** Max number of reads before auto-destruct */\n maxReads?: number;\n}\n\nconst tunnelStore = new Map<string, TunnelEntry>();\n\nlet cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\nfunction ensureCleanup(): void {\n if (cleanupInterval) return;\n cleanupInterval = setInterval(() => {\n const now = Date.now();\n for (const [id, entry] of tunnelStore) {\n if (entry.expiresAt && now >= entry.expiresAt) {\n tunnelStore.delete(id);\n }\n }\n if (tunnelStore.size === 0 && cleanupInterval) {\n clearInterval(cleanupInterval);\n cleanupInterval = null;\n }\n }, 5000);\n\n // Don't prevent process exit\n if (cleanupInterval && typeof cleanupInterval === \"object\" && \"unref\" in cleanupInterval) {\n cleanupInterval.unref();\n }\n}\n\nexport interface TunnelOptions {\n /** TTL in seconds */\n ttlSeconds?: number;\n /** Self-destruct after N reads */\n maxReads?: number;\n}\n\n/**\n * Create a tunneled (ephemeral) secret. Returns a tunnel ID.\n */\nexport function tunnelCreate(\n value: string,\n opts: TunnelOptions = {},\n): string {\n const id = `tun_${Date.now().toString(36)}_${randomBytes(6).toString(\"base64url\")}`;\n const now = Date.now();\n\n tunnelStore.set(id, {\n value,\n createdAt: now,\n expiresAt: opts.ttlSeconds ? now + opts.ttlSeconds * 1000 : undefined,\n accessCount: 0,\n maxReads: opts.maxReads,\n });\n\n ensureCleanup();\n return id;\n}\n\n/**\n * Read a tunneled secret by ID. Returns null if expired or not found.\n * Each read increments the access counter; auto-destructs after maxReads.\n */\nexport function tunnelRead(id: string): string | null {\n const entry = tunnelStore.get(id);\n if (!entry) return null;\n\n if (entry.expiresAt && Date.now() >= entry.expiresAt) {\n tunnelStore.delete(id);\n return null;\n }\n\n entry.accessCount++;\n\n if (entry.maxReads && entry.accessCount >= entry.maxReads) {\n const value = entry.value;\n tunnelStore.delete(id);\n return value;\n }\n\n return entry.value;\n}\n\n/**\n * Destroy a tunneled secret immediately.\n */\nexport function tunnelDestroy(id: string): boolean {\n return tunnelStore.delete(id);\n}\n\n/**\n * List all active tunnel IDs (never exposes values).\n */\nexport function tunnelList(): {\n id: string;\n createdAt: number;\n expiresAt?: number;\n accessCount: number;\n maxReads?: number;\n}[] {\n const now = Date.now();\n const result: ReturnType<typeof tunnelList> = [];\n\n for (const [id, entry] of tunnelStore) {\n if (entry.expiresAt && now >= entry.expiresAt) {\n tunnelStore.delete(id);\n continue;\n }\n result.push({\n id,\n createdAt: entry.createdAt,\n expiresAt: entry.expiresAt,\n accessCount: entry.accessCount,\n maxReads: entry.maxReads,\n });\n }\n\n return result;\n}\n","/**\n * Agent Memory — Persistent State Across Sessions\n *\n * Stores key-value pairs in an encrypted JSON file so the AI agent\n * can remember decisions, rotations performed, and project-specific\n * context between conversations.\n *\n * Data is encrypted with AES-256-GCM. The key is a random 32-byte key stored in\n * the OS keyring. Where no keyring is available (headless Linux, most\n * containers/CI), a key is derived from QRING_MEMORY_PASSPHRASE (PBKDF2); if\n * neither is present, writes fail closed rather than fall back to a\n * machine-derivable key that any local process could recompute (A4). The old\n * hostname+username-derived key is retained for *reading* pre-existing stores.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir, hostname, userInfo } from \"node:os\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n randomBytes,\n pbkdf2Sync,\n} from \"node:crypto\";\nimport { Entry } from \"./backend.js\";\n\nconst MEMORY_FILE = \"agent-memory.enc\";\nconst KEYRING_SERVICE = \"qring-memory-key\";\nconst KEYRING_ACCOUNT = \"encryption-key\";\n\nfunction getMemoryDir(): string {\n const dir = join(homedir(), \".config\", \"q-ring\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n return dir;\n}\n\n/**\n * Persist the encrypted memory blob with owner-only permissions. `mode` on\n * writeFileSync only applies when creating the file, so chmod additionally fixes\n * a store written world-readable by an older version. Best-effort chmod.\n */\nfunction writeMemoryFile(path: string, data: string): void {\n writeFileSync(path, data, { mode: 0o600 });\n try {\n chmodSync(path, 0o600);\n } catch {\n /* ignore */\n }\n}\n\nfunction getMemoryPath(): string {\n return join(getMemoryDir(), MEMORY_FILE);\n}\n\nconst PBKDF2_ITERATIONS = 210_000; // OWASP 2023 floor, matches teleport.ts\nconst KEY_LENGTH = 32;\nconst PASSPHRASE_ENV = \"QRING_MEMORY_PASSPHRASE\";\nconst V2_PREFIX = \"qmem2\"; // passphrase-encrypted blob: qmem2:<salt>:<iv:tag:ct>\n\n/** Thrown when no secure key is available to encrypt (or decrypt) memory. */\nexport class MemoryKeyUnavailableError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MemoryKeyUnavailableError\";\n }\n}\n\n/**\n * The pre-A4 fallback key: SHA-256 of hostname+username. NOT secret — any local\n * process can recompute it. Retained ONLY to read stores written by older\n * versions; never used to encrypt new data.\n */\nfunction deriveLegacyKey(): Buffer {\n const fingerprint = `qring-memory:${hostname()}:${userInfo().username}`;\n return createHash(\"sha256\").update(fingerprint).digest();\n}\n\nfunction passphrase(): string | undefined {\n const p = process.env[PASSPHRASE_ENV];\n return p && p.length > 0 ? p : undefined;\n}\n\nfunction derivePassphraseKey(salt: Buffer): Buffer {\n return pbkdf2Sync(passphrase()!, salt, PBKDF2_ITERATIONS, KEY_LENGTH, \"sha512\");\n}\n\n/**\n * The random key from the OS keyring (created on first use), or null if no\n * keyring backend is available on this host.\n */\nfunction keyringKey(): Buffer | null {\n try {\n const entry = new Entry(KEYRING_SERVICE, KEYRING_ACCOUNT);\n const stored = entry.getPassword();\n if (stored) return Buffer.from(stored, \"base64\");\n const key = randomBytes(KEY_LENGTH);\n entry.setPassword(key.toString(\"base64\"));\n return key;\n } catch {\n return null;\n }\n}\n\nfunction encryptWith(data: string, key: Buffer): string {\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const encrypted = Buffer.concat([cipher.update(data, \"utf8\"), cipher.final()]);\n const tag = cipher.getAuthTag();\n return `${iv.toString(\"base64\")}:${tag.toString(\"base64\")}:${encrypted.toString(\"base64\")}`;\n}\n\nfunction decryptWith(blob: string, key: Buffer): string {\n const parts = blob.split(\":\");\n if (parts.length !== 3) throw new Error(\"Invalid encrypted format\");\n const iv = Buffer.from(parts[0], \"base64\");\n const tag = Buffer.from(parts[1], \"base64\");\n const encrypted = Buffer.from(parts[2], \"base64\");\n\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(tag);\n return decipher.update(encrypted) + decipher.final(\"utf8\");\n}\n\nfunction encrypt(data: string): string {\n const kk = keyringKey();\n if (kk) return encryptWith(data, kk);\n\n if (passphrase()) {\n const salt = randomBytes(16);\n const key = derivePassphraseKey(salt);\n return `${V2_PREFIX}:${salt.toString(\"base64\")}:${encryptWith(data, key)}`;\n }\n\n throw new MemoryKeyUnavailableError(\n `Cannot persist agent memory: the OS keyring is unavailable and ${PASSPHRASE_ENV} ` +\n `is not set. Refusing to encrypt with a machine-derivable key (any local process ` +\n `could recompute it and read your memory). Set ${PASSPHRASE_ENV} to a strong ` +\n `passphrase, or run on a host with an OS keyring.`,\n );\n}\n\nfunction decrypt(blob: string): string {\n // Passphrase-encrypted (v2): salt is embedded; needs QRING_MEMORY_PASSPHRASE.\n if (blob.startsWith(`${V2_PREFIX}:`)) {\n if (!passphrase()) {\n throw new MemoryKeyUnavailableError(\n `Agent memory was encrypted with ${PASSPHRASE_ENV} but it is not set — cannot decrypt.`,\n );\n }\n const rest = blob.slice(V2_PREFIX.length + 1);\n const sep = rest.indexOf(\":\");\n const salt = Buffer.from(rest.slice(0, sep), \"base64\");\n return decryptWith(rest.slice(sep + 1), derivePassphraseKey(salt));\n }\n\n // Legacy 3-part format: try the keyring key first, then the machine-derived\n // key for read-only migration of pre-A4 stores.\n const kk = keyringKey();\n if (kk) {\n try {\n return decryptWith(blob, kk);\n } catch {\n /* fall through to legacy machine key */\n }\n }\n\n const plain = decryptWith(blob, deriveLegacyKey());\n // Re-encrypt under the keyring key if one is now available — but never persist\n // under the derivable legacy key. Without a secure key, read but don't rewrite.\n if (kk) {\n try {\n writeMemoryFile(getMemoryPath(), encryptWith(plain, kk));\n } catch {\n /* best-effort migration */\n }\n }\n return plain;\n}\n\ninterface MemoryStore {\n entries: Record<string, { value: string; updatedAt: string }>;\n}\n\nfunction loadStore(): MemoryStore {\n const path = getMemoryPath();\n if (!existsSync(path)) {\n return { entries: {} };\n }\n try {\n const raw = readFileSync(path, \"utf8\");\n const decrypted = decrypt(raw);\n return JSON.parse(decrypted);\n } catch (err) {\n // A store that exists but can't be decrypted because the key is unavailable\n // is surfaced loudly (so \"empty memory\" isn't mistaken for \"no memory\"),\n // but reads still degrade to empty rather than crashing the caller.\n if (err instanceof MemoryKeyUnavailableError) {\n console.error(`q-ring: ${err.message}`);\n }\n return { entries: {} };\n }\n}\n\nfunction saveStore(store: MemoryStore): void {\n const json = JSON.stringify(store);\n const encrypted = encrypt(json);\n writeMemoryFile(getMemoryPath(), encrypted);\n}\n\n/**\n * Store a value in agent memory.\n */\nexport function remember(key: string, value: string): void {\n const store = loadStore();\n store.entries[key] = {\n value,\n updatedAt: new Date().toISOString(),\n };\n saveStore(store);\n}\n\n/**\n * Retrieve a value from agent memory.\n */\nexport function recall(key: string): string | null {\n const store = loadStore();\n return store.entries[key]?.value ?? null;\n}\n\n/**\n * List all keys in agent memory.\n */\nexport function listMemory(): Array<{ key: string; updatedAt: string }> {\n const store = loadStore();\n return Object.entries(store.entries).map(([key, entry]) => ({\n key,\n updatedAt: entry.updatedAt,\n }));\n}\n\n/**\n * Delete a key from agent memory.\n */\nexport function forget(key: string): boolean {\n const store = loadStore();\n if (key in store.entries) {\n delete store.entries[key];\n saveStore(store);\n return true;\n }\n return false;\n}\n\n/**\n * Clear all agent memory.\n */\nexport function clearMemory(): void {\n saveStore({ entries: {} });\n}\n"],"mappings":"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","names":["readFileSync","join","join","readFileSync","existsSync","mkdirSync","chmodSync","readFileSync","statSync","join","homedir","randomBytes","readFileSync","writeFileSync","mkdirSync","dirname","join","homedir","readFileSync","statSync","join","join","homedir","readFileSync","mkdirSync","dirname","writeFileSync","randomBytes","existsSync","mkdirSync","join","homedir","chmodSync","statSync","readFileSync","existsSync","writeFileSync","mkdirSync","join","homedir","existsSync","readFileSync","join","homedir","existsSync","mkdirSync","registry","writeFileSync","existsSync","writeFileSync","mkdirSync","join","homedir","hostname","lookupSync","hostname","getRegistryPath","join","homedir","existsSync","mkdirSync","loadRegistry","saveRegistry","registry","writeFileSync","existsSync","readFileSync","writeFileSync","mkdirSync","join","homedir","createHmac","randomBytes","join","homedir","existsSync","mkdirSync","readFileSync","randomBytes","writeFileSync","createHmac","getRegistryPath","loadRegistry","registry","loadRegistry","registry","loadRegistry","statSync","join","z","z","statSync","join","createHash","spawn","spawn","z","z","parsed","randomBytes","existsSync","readFileSync","writeFileSync","mkdirSync","chmodSync","join","homedir","createCipheriv","createDecipheriv","createHash","randomBytes","pbkdf2Sync","join","homedir","existsSync","mkdirSync","writeFileSync","chmodSync","PBKDF2_ITERATIONS","KEY_LENGTH","PASSPHRASE_ENV","createHash","passphrase","pbkdf2Sync","randomBytes","createCipheriv","createDecipheriv","loadStore","readFileSync","saveStore"]}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
readProjectConfig,
|
|
15
15
|
tunnelList,
|
|
16
16
|
verifyAuditChain
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-5LFKBZ3Q.js";
|
|
18
18
|
|
|
19
19
|
// src/core/dashboard.ts
|
|
20
20
|
import { createServer } from "http";
|
|
@@ -655,4 +655,4 @@ export {
|
|
|
655
655
|
collectSnapshot,
|
|
656
656
|
startDashboardServer
|
|
657
657
|
};
|
|
658
|
-
//# sourceMappingURL=dashboard-
|
|
658
|
+
//# sourceMappingURL=dashboard-A3GJQCJX.js.map
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
readProjectConfig,
|
|
15
15
|
tunnelList,
|
|
16
16
|
verifyAuditChain
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NCM5GHNW.js";
|
|
18
18
|
|
|
19
19
|
// src/core/dashboard.ts
|
|
20
20
|
import { createServer } from "http";
|
|
@@ -655,4 +655,4 @@ export {
|
|
|
655
655
|
collectSnapshot,
|
|
656
656
|
startDashboardServer
|
|
657
657
|
};
|
|
658
|
-
//# sourceMappingURL=dashboard-
|
|
658
|
+
//# sourceMappingURL=dashboard-R3FWTFFW.js.map
|