@openape/openclaw-plugin-grants 0.2.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/adapters/loader.ts","../src/adapters/toml.ts","../src/store/grant-store.ts","../src/store/grant-cache.ts","../src/store/audit-log.ts","../src/local/local-jwt.ts","../src/approval/channel-approval.ts","../src/adapters/parser.ts","../src/execution/executor.ts","../src/idp/idp-grants.ts","../src/idp/discovery.ts","../src/tools/grant-exec.ts","../src/idp/auth.ts","../src/execution/apes.ts","../src/index.ts"],"sourcesContent":["import type { GrantType, ScopeRiskLevel } from '@openape/core'\n\n// --- Plugin Configuration ---\n\nexport interface PluginConfig {\n mode: 'local' | 'idp'\n audience: string\n defaultApproval: GrantType\n adapterPaths?: string[]\n\n // IdP mode\n agentEmail?: string\n agentKeyPath?: string\n idpUrl?: string\n\n // apes\n apes?: {\n enabled: boolean\n binaryPath?: string\n }\n\n // Polling (IdP mode)\n pollIntervalMs?: number\n pollTimeoutMs?: number\n}\n\nexport const DEFAULT_CONFIG: PluginConfig = {\n mode: 'local',\n audience: 'openclaw',\n defaultApproval: 'once',\n pollIntervalMs: 3000,\n pollTimeoutMs: 300000,\n}\n\n// --- OpenClaw Plugin API (type stubs) ---\n\nexport interface ToolDefinition {\n name: string\n description: string\n inputSchema: Record<string, unknown>\n handler: (input: ToolInput) => Promise<ToolResult>\n}\n\nexport interface ToolInput {\n command: string\n reason?: string\n privileged?: boolean\n}\n\nexport interface ToolResult {\n success: boolean\n output?: string\n error?: string\n}\n\nexport interface HookHandler {\n (context: HookContext): Promise<HookResult>\n}\n\nexport interface HookContext {\n toolName: string\n toolInput: Record<string, unknown>\n}\n\nexport interface HookResult {\n allow: boolean\n message?: string\n}\n\nexport interface HttpRouteDefinition {\n path: string\n method: 'GET' | 'POST'\n handler: (req: HttpRequest) => Promise<HttpResponse>\n}\n\nexport interface HttpRequest {\n method: string\n path: string\n headers: Record<string, string>\n body?: unknown\n}\n\nexport interface HttpResponse {\n status: number\n headers?: Record<string, string>\n body: unknown\n}\n\nexport interface CliCommandDefinition {\n name: string\n description: string\n subcommands?: CliSubcommand[]\n handler: (args: string[]) => Promise<void>\n}\n\nexport interface CliSubcommand {\n name: string\n description: string\n handler: (args: string[]) => Promise<void>\n}\n\nexport interface ChannelMessage {\n text: string\n actions?: ChannelAction[]\n}\n\nexport interface ChannelAction {\n label: string\n value: string\n}\n\nexport interface PluginApi {\n registerTool(tool: ToolDefinition): void\n on(event: 'before_tool_call', handler: HookHandler, options?: { priority?: number }): void\n registerHttpRoute(route: HttpRouteDefinition): void\n registerCli(command: CliCommandDefinition): void\n\n // Channel communication\n sendChannelMessage(message: ChannelMessage): Promise<string | undefined>\n onChannelCommand(command: string, handler: (args: string[], responderId?: string) => Promise<void>): void\n\n // Runtime\n runtime: {\n system: {\n runCommandWithTimeout(command: string, args: string[], options?: {\n timeout?: number\n cwd?: string\n env?: Record<string, string>\n }): Promise<{ stdout: string, stderr: string, exitCode: number }>\n }\n config: {\n getStateDir(): string\n getWorkspaceDir(): string\n }\n }\n\n // Logging\n log: {\n info(message: string, ...args: unknown[]): void\n warn(message: string, ...args: unknown[]): void\n error(message: string, ...args: unknown[]): void\n debug(message: string, ...args: unknown[]): void\n }\n}\n\n// --- Grant Types (plugin-internal) ---\n\nexport type GrantApproval = 'once' | 'timed' | 'always'\n\nexport interface GrantRecord {\n id: string\n permission: string\n approval: GrantApproval\n status: 'pending' | 'approved' | 'denied' | 'used' | 'expired' | 'revoked'\n command: string\n reason?: string\n risk: ScopeRiskLevel\n display: string\n jwt?: string\n createdAt: string\n decidedAt?: string\n expiresAt?: string\n usedAt?: string\n}\n\nexport interface AuditEntry {\n ts: string\n event: 'grant_requested' | 'grant_approved' | 'grant_denied' | 'grant_used' | 'grant_revoked' | 'grant_expired' | 'exec_success' | 'exec_failed' | 'exec_blocked'\n grantId?: string\n permission?: string\n command?: string\n detail?: string\n}\n","import { createHash } from 'node:crypto'\nimport { existsSync, readFileSync, readdirSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { LoadedAdapter } from './types.js'\nimport { parseAdapterToml } from './toml.js'\n\nconst PACKAGE_DIR = dirname(fileURLToPath(import.meta.url))\n\nfunction digest(content: string): string {\n return `SHA-256:${createHash('sha256').update(content).digest('hex')}`\n}\n\nfunction bundledAdapterDir(): string {\n // In dist/, adapters/ is at package root (sibling of dist/)\n return join(PACKAGE_DIR, '..', '..', 'adapters')\n}\n\nexport interface AdapterSearchPaths {\n explicit?: string[]\n workspaceDir?: string\n}\n\nfunction getSearchDirs(options?: AdapterSearchPaths): string[] {\n const dirs: string[] = []\n\n if (options?.explicit) {\n dirs.push(...options.explicit)\n }\n\n if (options?.workspaceDir) {\n dirs.push(join(options.workspaceDir, '.openclaw', 'adapters'))\n }\n\n dirs.push(join(homedir(), '.openclaw', 'adapters'))\n dirs.push(bundledAdapterDir())\n\n return dirs\n}\n\nexport function loadAdapterFromFile(filePath: string): LoadedAdapter {\n const content = readFileSync(filePath, 'utf-8')\n const adapter = parseAdapterToml(content)\n return {\n adapter,\n source: filePath,\n digest: digest(content),\n }\n}\n\nexport function loadAdapter(cliId: string, options?: AdapterSearchPaths): LoadedAdapter {\n const dirs = getSearchDirs(options)\n\n for (const dir of dirs) {\n const filePath = join(dir, `${cliId}.toml`)\n if (existsSync(filePath)) {\n return loadAdapterFromFile(filePath)\n }\n }\n\n throw new Error(`No adapter found for CLI: ${cliId}`)\n}\n\nexport function discoverAdapters(options?: AdapterSearchPaths): LoadedAdapter[] {\n const dirs = getSearchDirs(options)\n const seen = new Set<string>()\n const adapters: LoadedAdapter[] = []\n\n for (const dir of dirs) {\n if (!existsSync(dir))\n continue\n\n let entries: string[]\n try {\n entries = readdirSync(dir)\n }\n catch {\n continue\n }\n\n for (const entry of entries) {\n if (!entry.endsWith('.toml'))\n continue\n\n const cliId = entry.slice(0, -5) // strip .toml\n if (seen.has(cliId))\n continue // higher-priority path already loaded this adapter\n\n try {\n const loaded = loadAdapterFromFile(join(dir, entry))\n seen.add(cliId)\n adapters.push(loaded)\n }\n catch {\n // Skip invalid adapters\n }\n }\n }\n\n return adapters\n}\n","import type { AdapterDefinition, AdapterOperation } from './types.js'\n\ninterface AdapterTomlFile {\n schema?: string\n cli?: AdapterDefinition['cli']\n operation?: AdapterOperation[]\n}\n\nfunction parseKeyValue(line: string): { key: string, value: string } | null {\n const eqIndex = line.indexOf('=')\n if (eqIndex === -1)\n return null\n const key = line.slice(0, eqIndex).trim()\n const value = line.slice(eqIndex + 1).trim()\n if (!key || !value)\n return null\n return { key, value }\n}\n\nfunction splitTomlArray(inner: string): string[] {\n const elements: string[] = []\n let current = ''\n let inQuote = false\n\n for (let i = 0; i < inner.length; i++) {\n const char = inner[i]!\n if (char === '\"') {\n inQuote = !inQuote\n current += char\n }\n else if (char === ',' && !inQuote) {\n elements.push(current)\n current = ''\n }\n else {\n current += char\n }\n }\n\n if (current.trim())\n elements.push(current)\n\n return elements\n}\n\nfunction parseTomlValue(raw: string): unknown {\n const trimmed = raw.trim()\n\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"'))\n return trimmed.slice(1, -1)\n if (trimmed === 'true')\n return true\n if (trimmed === 'false')\n return false\n if (trimmed.startsWith('[') && trimmed.endsWith(']')) {\n const inner = trimmed.slice(1, -1).trim()\n if (!inner)\n return []\n return splitTomlArray(inner).map(value => value.trim().replace(/^\"|\"$/g, ''))\n }\n\n return trimmed\n}\n\nexport function parseAdapterToml(content: string): AdapterDefinition {\n const result: AdapterTomlFile = {}\n const operations: AdapterOperation[] = []\n let currentSection: 'root' | 'cli' | 'operation' = 'root'\n let currentEntry: Record<string, unknown> = {}\n\n const flushOperation = () => {\n if (currentSection === 'operation' && Object.keys(currentEntry).length > 0) {\n operations.push(currentEntry as unknown as AdapterOperation)\n currentEntry = {}\n }\n }\n\n for (const rawLine of content.split('\\n')) {\n const line = rawLine.trim()\n if (!line || line.startsWith('#'))\n continue\n\n if (line === '[cli]') {\n flushOperation()\n currentSection = 'cli'\n result.cli = {} as AdapterDefinition['cli']\n continue\n }\n\n if (line === '[[operation]]') {\n flushOperation()\n currentSection = 'operation'\n currentEntry = {}\n continue\n }\n\n const kv = parseKeyValue(line)\n if (!kv)\n continue\n\n const value = parseTomlValue(kv.value)\n if (currentSection === 'root') {\n ;(result as Record<string, unknown>)[kv.key] = value\n }\n else if (currentSection === 'cli') {\n ;(result.cli as Record<string, unknown>)[kv.key] = value\n }\n else {\n currentEntry[kv.key] = value\n }\n }\n\n flushOperation()\n result.operation = operations\n\n if (result.schema !== 'openape-shapes/v1') {\n throw new Error(`Unsupported adapter schema: ${result.schema ?? 'missing'}`)\n }\n if (!result.cli?.id || !result.cli.executable) {\n throw new Error('Adapter is missing cli.id or cli.executable')\n }\n if (!result.operation?.length) {\n throw new Error('Adapter must define at least one [[operation]] entry')\n }\n\n return {\n schema: result.schema,\n cli: {\n id: String(result.cli.id),\n executable: String(result.cli.executable),\n ...(result.cli.audience ? { audience: String(result.cli.audience) } : {}),\n ...(result.cli.version ? { version: String(result.cli.version) } : {}),\n },\n operations: result.operation.map((operation) => {\n if (!Array.isArray(operation.command) || operation.command.some(token => typeof token !== 'string')) {\n throw new Error(`Operation ${String(operation.id ?? '<unknown>')} is missing command[]`)\n }\n if (!Array.isArray(operation.resource_chain) || operation.resource_chain.some(token => typeof token !== 'string')) {\n throw new Error(`Operation ${String(operation.id ?? '<unknown>')} is missing resource_chain[]`)\n }\n if (typeof operation.id !== 'string' || typeof operation.display !== 'string' || typeof operation.action !== 'string') {\n throw new TypeError('Operation must define id, display, and action')\n }\n return {\n id: operation.id,\n command: operation.command as string[],\n ...(Array.isArray(operation.positionals) ? { positionals: operation.positionals as string[] } : {}),\n ...(Array.isArray(operation.required_options) ? { required_options: operation.required_options as string[] } : {}),\n display: operation.display,\n action: operation.action,\n risk: (operation.risk as AdapterOperation['risk']) || 'low',\n resource_chain: operation.resource_chain as string[],\n ...(operation.exact_command !== undefined ? { exact_command: Boolean(operation.exact_command) } : {}),\n }\n }),\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport type { GrantApproval, GrantRecord } from '../types.js'\nimport type { ScopeRiskLevel } from '@openape/core'\n\nexport interface CreateGrantInput {\n permission: string\n command: string\n reason?: string\n risk: ScopeRiskLevel\n display: string\n}\n\nexport class GrantStore {\n private grants = new Map<string, GrantRecord>()\n private filePath: string | null\n\n constructor(stateDir?: string) {\n this.filePath = stateDir ? join(stateDir, 'grants', 'store.json') : null\n this.load()\n }\n\n createGrant(input: CreateGrantInput): GrantRecord {\n const grant: GrantRecord = {\n id: randomUUID().slice(0, 8),\n permission: input.permission,\n approval: 'once',\n status: 'pending',\n command: input.command,\n reason: input.reason,\n risk: input.risk,\n display: input.display,\n createdAt: new Date().toISOString(),\n }\n this.grants.set(grant.id, grant)\n this.save()\n return grant\n }\n\n approveGrant(id: string, approval: GrantApproval, expiresAt?: string): GrantRecord | null {\n const grant = this.grants.get(id)\n if (!grant || grant.status !== 'pending')\n return null\n\n grant.status = 'approved'\n grant.approval = approval\n grant.decidedAt = new Date().toISOString()\n if (expiresAt)\n grant.expiresAt = expiresAt\n\n this.save()\n return grant\n }\n\n denyGrant(id: string): GrantRecord | null {\n const grant = this.grants.get(id)\n if (!grant || grant.status !== 'pending')\n return null\n\n grant.status = 'denied'\n grant.decidedAt = new Date().toISOString()\n this.save()\n return grant\n }\n\n consumeGrant(id: string): boolean {\n const grant = this.grants.get(id)\n if (!grant || grant.status !== 'approved')\n return false\n\n if (grant.approval === 'once') {\n grant.status = 'used'\n grant.usedAt = new Date().toISOString()\n this.save()\n }\n\n return true\n }\n\n revokeGrant(id: string): boolean {\n const grant = this.grants.get(id)\n if (!grant || (grant.status !== 'approved' && grant.status !== 'pending'))\n return false\n\n grant.status = 'revoked'\n this.save()\n return true\n }\n\n getGrant(id: string): GrantRecord | undefined {\n return this.grants.get(id)\n }\n\n listGrants(filter?: { status?: GrantRecord['status'] }): GrantRecord[] {\n const grants = Array.from(this.grants.values())\n if (filter?.status)\n return grants.filter(g => g.status === filter.status)\n return grants\n }\n\n getActiveGrantCount(): number {\n return Array.from(this.grants.values()).filter(g => g.status === 'approved' || g.status === 'pending').length\n }\n\n private load(): void {\n if (!this.filePath || !existsSync(this.filePath))\n return\n\n try {\n const data = JSON.parse(readFileSync(this.filePath, 'utf-8'))\n if (Array.isArray(data)) {\n for (const grant of data) {\n this.grants.set(grant.id, grant)\n }\n }\n }\n catch {\n // Start fresh if file is corrupt\n }\n }\n\n private save(): void {\n if (!this.filePath)\n return\n\n const dir = dirname(this.filePath)\n if (!existsSync(dir))\n mkdirSync(dir, { recursive: true })\n\n writeFileSync(this.filePath, JSON.stringify(Array.from(this.grants.values()), null, 2))\n }\n}\n","import { cliAuthorizationDetailCovers } from '@openape/core'\nimport type { OpenApeCliAuthorizationDetail } from '@openape/core'\nimport type { GrantRecord } from '../types.js'\n\ninterface CacheEntry {\n grant: GrantRecord\n detail: OpenApeCliAuthorizationDetail\n expiresAt: number | null\n}\n\nexport class GrantCache {\n private entries = new Map<string, CacheEntry>()\n\n put(grant: GrantRecord, detail: OpenApeCliAuthorizationDetail): void {\n if (grant.approval === 'once')\n return // never cache once-grants\n\n const expiresAt = grant.expiresAt ? new Date(grant.expiresAt).getTime() : null\n\n this.entries.set(grant.permission, {\n grant,\n detail,\n expiresAt,\n })\n }\n\n lookup(permission: string, detail: OpenApeCliAuthorizationDetail): GrantRecord | null {\n // Direct match first\n const direct = this.entries.get(permission)\n if (direct) {\n if (this.isExpired(direct)) {\n this.entries.delete(permission)\n return null\n }\n return direct.grant\n }\n\n // Coverage match: check if any cached grant covers this permission\n for (const [key, entry] of this.entries) {\n if (this.isExpired(entry)) {\n this.entries.delete(key)\n continue\n }\n if (cliAuthorizationDetailCovers(entry.detail, detail)) {\n return entry.grant\n }\n }\n\n return null\n }\n\n remove(permission: string): boolean {\n return this.entries.delete(permission)\n }\n\n clear(): void {\n this.entries.clear()\n }\n\n size(): number {\n return this.entries.size\n }\n\n private isExpired(entry: CacheEntry): boolean {\n if (!entry.expiresAt)\n return false\n return Date.now() > entry.expiresAt\n }\n}\n","import { appendFileSync, existsSync, mkdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport type { AuditEntry } from '../types.js'\n\nexport class AuditLog {\n private filePath: string | null\n\n constructor(stateDir?: string) {\n this.filePath = stateDir ? join(stateDir, 'grants', 'audit.jsonl') : null\n if (this.filePath) {\n const dir = dirname(this.filePath)\n if (!existsSync(dir))\n mkdirSync(dir, { recursive: true })\n }\n }\n\n write(entry: Omit<AuditEntry, 'ts'>): void {\n const full: AuditEntry = {\n ts: new Date().toISOString(),\n ...entry,\n }\n\n if (this.filePath) {\n appendFileSync(this.filePath, JSON.stringify(full) + '\\n')\n }\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { randomUUID } from 'node:crypto'\nimport * as jose from 'jose'\nimport type { GrantRecord } from '../types.js'\nimport type { OpenApeCliAuthorizationDetail, OpenApeExecutionContext } from '@openape/core'\n\nconst LOCAL_ISSUER = 'local://openclaw-grants'\nconst KEY_ALGORITHM = 'EdDSA'\n\nexport class LocalJwtSigner {\n private privateKey: jose.KeyLike | null = null\n private publicKey: jose.KeyLike | null = null\n private kid: string = ''\n private stateDir: string\n\n constructor(stateDir: string) {\n this.stateDir = stateDir\n }\n\n async init(): Promise<void> {\n const keyDir = join(this.stateDir, 'grants', 'keys')\n const privatePath = join(keyDir, 'private.jwk')\n const publicPath = join(keyDir, 'public.jwk')\n\n if (existsSync(privatePath) && existsSync(publicPath)) {\n const privData = JSON.parse(readFileSync(privatePath, 'utf-8'))\n const pubData = JSON.parse(readFileSync(publicPath, 'utf-8'))\n this.privateKey = await jose.importJWK(privData, KEY_ALGORITHM) as jose.KeyLike\n this.publicKey = await jose.importJWK(pubData, KEY_ALGORITHM) as jose.KeyLike\n this.kid = privData.kid ?? 'local-1'\n }\n else {\n const { privateKey, publicKey } = await jose.generateKeyPair(KEY_ALGORITHM, { crv: 'Ed25519' })\n this.privateKey = privateKey\n this.publicKey = publicKey\n this.kid = `local-${Date.now()}`\n\n if (!existsSync(keyDir))\n mkdirSync(keyDir, { recursive: true })\n\n const privJwk = await jose.exportJWK(privateKey)\n privJwk.kid = this.kid\n privJwk.alg = KEY_ALGORITHM\n writeFileSync(privatePath, JSON.stringify(privJwk, null, 2))\n\n const pubJwk = await jose.exportJWK(publicKey)\n pubJwk.kid = this.kid\n pubJwk.alg = KEY_ALGORITHM\n pubJwk.use = 'sig'\n writeFileSync(publicPath, JSON.stringify(pubJwk, null, 2))\n }\n }\n\n async signGrant(options: {\n grant: GrantRecord\n audience: string\n detail: OpenApeCliAuthorizationDetail\n executionContext: OpenApeExecutionContext\n }): Promise<string> {\n if (!this.privateKey)\n throw new Error('LocalJwtSigner not initialized')\n\n const { grant, audience, detail, executionContext } = options\n\n const expirationTime = this.getExpiration(grant)\n\n const jwt = await new jose.SignJWT({\n grant_id: grant.id,\n grant_type: grant.approval,\n permissions: [grant.permission],\n authorization_details: [detail],\n cmd_hash: executionContext.argv_hash,\n command: grant.command,\n execution_context: executionContext,\n })\n .setProtectedHeader({ alg: KEY_ALGORITHM, kid: this.kid })\n .setIssuedAt()\n .setIssuer(LOCAL_ISSUER)\n .setSubject('local-agent')\n .setAudience(audience)\n .setExpirationTime(expirationTime)\n .setJti(randomUUID())\n .sign(this.privateKey)\n\n return jwt\n }\n\n async getJwks(): Promise<jose.JSONWebKeySet> {\n if (!this.publicKey)\n throw new Error('LocalJwtSigner not initialized')\n\n const jwk = await jose.exportJWK(this.publicKey)\n jwk.kid = this.kid\n jwk.alg = KEY_ALGORITHM\n jwk.use = 'sig'\n\n return { keys: [jwk] }\n }\n\n getIssuer(): string {\n return LOCAL_ISSUER\n }\n\n private getExpiration(grant: GrantRecord): string | number {\n switch (grant.approval) {\n case 'once':\n return '5m'\n case 'timed':\n if (grant.expiresAt) {\n const secondsFromNow = Math.max(0, Math.floor((new Date(grant.expiresAt).getTime() - Date.now()) / 1000))\n return `${secondsFromNow}s`\n }\n return '1h'\n case 'always':\n return '1h'\n default:\n return '5m'\n }\n }\n}\n","import type { PluginApi } from '../types.js'\nimport type { GrantRecord } from '../types.js'\nimport type { GrantStore } from '../store/grant-store.js'\n\nconst RISK_EMOJI: Record<string, string> = {\n low: '\\u{1F7E2}', // green circle\n medium: '\\u{1F7E1}', // yellow circle\n high: '\\u{1F534}', // red circle\n critical: '\\u{26D4}', // no entry\n}\n\nexport class ChannelApproval {\n private pending = new Map<string, {\n resolve: (result: { approved: boolean, approval?: 'once' | 'timed' | 'always' }) => void\n timeout: ReturnType<typeof setTimeout>\n }>()\n\n constructor(\n private api: PluginApi,\n private store: GrantStore,\n private timeoutMs: number = 300000,\n ) {\n this.registerCommands()\n }\n\n async requestApproval(grant: GrantRecord): Promise<{ approved: boolean, approval?: 'once' | 'timed' | 'always' }> {\n const emoji = RISK_EMOJI[grant.risk] ?? '\\u{1F50D}'\n const message = [\n `\\u{1F510} Grant Request ${emoji} [${grant.risk} risk]`,\n `Operation: ${grant.display}`,\n `Permission: ${grant.permission}`,\n grant.reason ? `Reason: ${grant.reason}` : '',\n `ID: ${grant.id}`,\n '',\n 'Reply: /grant-approve <id> [once|1h|4h|always] or /grant-deny <id>',\n ].filter(Boolean).join('\\n')\n\n await this.api.sendChannelMessage({\n text: message,\n actions: [\n { label: 'Once', value: `grant-approve ${grant.id} once` },\n { label: '1h', value: `grant-approve ${grant.id} 1h` },\n { label: '4h', value: `grant-approve ${grant.id} 4h` },\n { label: 'Always', value: `grant-approve ${grant.id} always` },\n { label: 'Deny', value: `grant-deny ${grant.id}` },\n ],\n })\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.pending.delete(grant.id)\n resolve({ approved: false })\n }, this.timeoutMs)\n\n this.pending.set(grant.id, { resolve, timeout })\n })\n }\n\n private registerCommands(): void {\n this.api.onChannelCommand('grant-approve', async (args: string[]) => {\n const [id, durationOrType] = args\n if (!id)\n return\n\n let approval: 'once' | 'timed' | 'always' = 'once'\n let expiresAt: string | undefined\n\n if (durationOrType === 'always') {\n approval = 'always'\n }\n else if (durationOrType === '1h' || durationOrType === '4h') {\n approval = 'timed'\n const hours = durationOrType === '1h' ? 1 : 4\n expiresAt = new Date(Date.now() + hours * 3600_000).toISOString()\n }\n else if (durationOrType === 'once' || !durationOrType) {\n approval = 'once'\n }\n\n const grant = this.store.approveGrant(id, approval, expiresAt)\n if (!grant) {\n this.api.log.warn(`[grants] Cannot approve grant ${id}: not found or not pending`)\n return\n }\n\n const pending = this.pending.get(id)\n if (pending) {\n clearTimeout(pending.timeout)\n this.pending.delete(id)\n pending.resolve({ approved: true, approval })\n }\n })\n\n this.api.onChannelCommand('grant-deny', async (args: string[]) => {\n const [id] = args\n if (!id)\n return\n\n this.store.denyGrant(id)\n\n const pending = this.pending.get(id)\n if (pending) {\n clearTimeout(pending.timeout)\n this.pending.delete(id)\n pending.resolve({ approved: false })\n }\n })\n }\n}\n","import { canonicalizeCliPermission, computeArgvHash } from '@openape/core'\nimport type { OpenApeCliAuthorizationDetail, OpenApeCliResourceRef } from '@openape/core'\nimport type { AdapterOperation, CommandResolutionResult, FallbackCommand, LoadedAdapter, ResolvedCommand } from './types.js'\n\nfunction parseOptionArgs(tokens: string[]): { options: Record<string, string>, positionals: string[] } {\n const options: Record<string, string> = {}\n const positionals: string[] = []\n\n for (let index = 0; index < tokens.length; index += 1) {\n const token = tokens[index]!\n if (!token.startsWith('--')) {\n positionals.push(token)\n continue\n }\n\n const stripped = token.slice(2)\n const eqIndex = stripped.indexOf('=')\n if (eqIndex >= 0) {\n options[stripped.slice(0, eqIndex)] = stripped.slice(eqIndex + 1)\n continue\n }\n\n const next = tokens[index + 1]\n if (next && !next.startsWith('--')) {\n options[stripped] = next\n index += 1\n continue\n }\n\n options[stripped] = 'true'\n }\n\n return { options, positionals }\n}\n\nfunction resolveBindingToken(binding: string, bindings: Record<string, string>): string {\n const match = binding.match(/^\\{([^}|]+)(?:\\|([^}]+))?\\}$/)\n if (!match)\n return binding\n\n const [, name, transform] = match\n const value = bindings[name!]\n if (!value)\n throw new Error(`Missing binding: ${name}`)\n if (!transform)\n return value\n\n if (transform === 'owner' || transform === 'name') {\n const [owner, repo] = value.split('/')\n if (!owner || !repo)\n throw new Error(`Binding ${name} must be in owner/name form`)\n return transform === 'owner' ? owner : repo\n }\n\n throw new Error(`Unsupported binding transform: ${transform}`)\n}\n\nfunction renderTemplate(template: string, bindings: Record<string, string>): string {\n return template.replace(/\\{([^}]+)\\}/g, (_, expression: string) => resolveBindingToken(`{${expression}}`, bindings))\n}\n\nfunction parseResourceChain(chain: string[], bindings: Record<string, string>): OpenApeCliResourceRef[] {\n return chain.map((entry) => {\n const [resource, selectorSpec = '*'] = entry.split(':', 2)\n if (!resource)\n throw new Error(`Invalid resource chain entry: ${entry}`)\n\n if (selectorSpec === '*') {\n return { resource }\n }\n\n const selector = Object.fromEntries(\n selectorSpec.split(',').map((segment) => {\n const [key, rawValue] = segment.split('=', 2)\n if (!key || !rawValue)\n throw new Error(`Invalid selector segment: ${segment}`)\n return [key, renderTemplate(rawValue, bindings)]\n }),\n )\n\n return { resource, selector }\n })\n}\n\nfunction matchOperation(operation: AdapterOperation, argv: string[]): Record<string, string> | null {\n if (argv.length < operation.command.length)\n return null\n\n const prefix = argv.slice(0, operation.command.length)\n if (prefix.join('\\0') !== operation.command.join('\\0'))\n return null\n\n const remainder = argv.slice(operation.command.length)\n const { options, positionals } = parseOptionArgs(remainder)\n\n const expectedPositionals = operation.positionals ?? []\n if (positionals.length !== expectedPositionals.length)\n return null\n\n for (const option of operation.required_options ?? []) {\n if (!options[option])\n return null\n }\n\n const bindings: Record<string, string> = { ...options }\n expectedPositionals.forEach((name, index) => {\n bindings[name] = positionals[index]!\n })\n return bindings\n}\n\nexport async function resolveCommand(loaded: LoadedAdapter, fullArgv: string[]): Promise<ResolvedCommand> {\n const [executable, ...commandArgv] = fullArgv\n if (!executable) {\n throw new Error('Missing wrapped command')\n }\n if (executable !== loaded.adapter.cli.executable) {\n throw new Error(`Adapter ${loaded.adapter.cli.id} expects executable ${loaded.adapter.cli.executable}, got ${executable}`)\n }\n\n const matches = loaded.adapter.operations.flatMap((operation) => {\n try {\n const bindings = matchOperation(operation, commandArgv)\n return bindings ? [{ operation, bindings }] : []\n }\n catch {\n return []\n }\n })\n\n if (matches.length === 0) {\n throw new Error(`No adapter operation matched: ${fullArgv.join(' ')}`)\n }\n\n // Disambiguate: prefer operations with more constraints (required_options, positionals, exact_command)\n if (matches.length > 1) {\n matches.sort((a, b) => {\n const scoreA = (a.operation.required_options?.length ?? 0) + (a.operation.positionals?.length ?? 0) + (a.operation.exact_command ? 1 : 0)\n const scoreB = (b.operation.required_options?.length ?? 0) + (b.operation.positionals?.length ?? 0) + (b.operation.exact_command ? 1 : 0)\n return scoreB - scoreA\n })\n }\n\n const { operation, bindings } = matches[0]!\n const resource_chain = parseResourceChain(operation.resource_chain, bindings)\n const detail: OpenApeCliAuthorizationDetail = {\n type: 'openape_cli',\n cli_id: loaded.adapter.cli.id,\n operation_id: operation.id,\n resource_chain,\n action: operation.action,\n permission: '',\n display: renderTemplate(operation.display, bindings),\n risk: operation.risk,\n ...(operation.exact_command ? { constraints: { exact_command: true } } : {}),\n }\n detail.permission = canonicalizeCliPermission(detail)\n\n return {\n adapter: loaded.adapter,\n source: loaded.source,\n digest: loaded.digest,\n executable,\n commandArgv,\n bindings,\n detail,\n executionContext: {\n argv: fullArgv,\n argv_hash: await computeArgvHash(fullArgv),\n adapter_id: loaded.adapter.cli.id,\n adapter_version: loaded.adapter.cli.version ?? loaded.adapter.schema,\n adapter_digest: loaded.digest,\n resolved_executable: executable,\n context_bindings: bindings,\n },\n permission: detail.permission,\n }\n}\n\nexport async function createFallbackCommand(commandString: string): Promise<FallbackCommand> {\n const argv = parseCommandString(commandString)\n const hash = await computeArgvHash(argv)\n return {\n command: commandString,\n argv,\n hash,\n permission: `unknown.command[hash=${hash.slice(7, 19)}]#execute`,\n display: `Execute: ${commandString.length > 60 ? `${commandString.slice(0, 57)}...` : commandString}`,\n risk: 'high',\n }\n}\n\nexport function parseCommandString(command: string): string[] {\n const argv: string[] = []\n let current = ''\n let inQuote: '\\'' | '\"' | null = null\n\n for (let i = 0; i < command.length; i++) {\n const char = command[i]!\n\n if (inQuote) {\n if (char === inQuote) {\n inQuote = null\n }\n else {\n current += char\n }\n }\n else if (char === '\\'' || char === '\"') {\n inQuote = char\n }\n else if (char === ' ' || char === '\\t') {\n if (current) {\n argv.push(current)\n current = ''\n }\n }\n else {\n current += char\n }\n }\n\n if (current)\n argv.push(current)\n\n return argv\n}\n\nexport async function resolveCommandFromAdapters(\n adapters: LoadedAdapter[],\n commandString: string,\n): Promise<CommandResolutionResult> {\n const argv = parseCommandString(commandString)\n if (argv.length === 0) {\n throw new Error('Empty command')\n }\n\n const executable = argv[0]!\n\n for (const loaded of adapters) {\n if (loaded.adapter.cli.executable !== executable)\n continue\n\n try {\n const resolved = await resolveCommand(loaded, argv)\n return { resolved, fallback: null }\n }\n catch {\n // This adapter matched executable but no operation — continue to next or fallback\n }\n }\n\n const fallback = await createFallbackCommand(commandString)\n return { resolved: null, fallback }\n}\n","import type { PluginApi, ToolResult } from '../types.js'\n\nexport interface ExecuteOptions {\n command: string\n args: string[]\n jwt?: string\n privileged?: boolean\n apesBinaryPath?: string\n timeout?: number\n}\n\nexport async function executeCommand(api: PluginApi, options: ExecuteOptions): Promise<ToolResult> {\n const { command, args, jwt, privileged, apesBinaryPath, timeout } = options\n\n if (privileged && jwt && apesBinaryPath) {\n return executeWithApes(api, { command, args, jwt, binaryPath: apesBinaryPath, timeout })\n }\n\n return executeDirectly(api, { command, args, timeout })\n}\n\nasync function executeDirectly(api: PluginApi, options: { command: string, args: string[], timeout?: number }): Promise<ToolResult> {\n try {\n const result = await api.runtime.system.runCommandWithTimeout(\n options.command,\n options.args,\n { timeout: options.timeout ?? 30000 },\n )\n\n if (result.exitCode !== 0) {\n return {\n success: false,\n output: result.stdout || undefined,\n error: result.stderr || `Command exited with code ${result.exitCode}`,\n }\n }\n\n return {\n success: true,\n output: result.stdout,\n }\n }\n catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n\nasync function executeWithApes(api: PluginApi, options: {\n command: string\n args: string[]\n jwt: string\n binaryPath: string\n timeout?: number\n}): Promise<ToolResult> {\n try {\n const result = await api.runtime.system.runCommandWithTimeout(\n options.binaryPath,\n ['--grant', options.jwt, '--', options.command, ...options.args],\n { timeout: options.timeout ?? 30000 },\n )\n\n if (result.exitCode !== 0) {\n return {\n success: false,\n output: result.stdout || undefined,\n error: result.stderr || `apes exited with code ${result.exitCode}`,\n }\n }\n\n return {\n success: true,\n output: result.stdout,\n }\n }\n catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n}\n","import { hostname } from 'node:os'\nimport { verifyAuthzJWT } from '@openape/grants'\nimport { cliAuthorizationDetailCovers } from '@openape/core'\nimport type { OpenApeCliAuthorizationDetail } from '@openape/core'\nimport type { PluginConfig, ToolResult } from '../types.js'\nimport type { ResolvedCommand, FallbackCommand } from '../adapters/types.js'\nimport type { GrantStore } from '../store/grant-store.js'\nimport type { GrantCache } from '../store/grant-cache.js'\nimport type { AuditLog } from '../store/audit-log.js'\nimport type { PluginApi } from '../types.js'\nimport type { AgentAuthState } from './auth.js'\nimport { getGrantsEndpoint, getJwksUri } from './discovery.js'\nimport { executeCommand } from '../execution/executor.js'\n\nexport interface IdpGrantContext {\n config: PluginConfig\n api: PluginApi\n authState: AgentAuthState\n store: GrantStore\n cache: GrantCache\n audit: AuditLog\n}\n\nexport async function handleIdpGrantExec(\n ctx: IdpGrantContext,\n options: {\n resolved: ResolvedCommand | null\n fallback: FallbackCommand | null\n command: string\n reason?: string\n privileged?: boolean\n },\n): Promise<ToolResult> {\n const { config, api, authState, store, cache, audit } = ctx\n const { resolved, fallback, command, reason, privileged } = options\n\n let permission: string\n let display: string\n let risk: string\n let detail: OpenApeCliAuthorizationDetail | null = null\n let argv: string[]\n\n if (resolved) {\n permission = resolved.permission\n display = resolved.detail.display\n risk = resolved.detail.risk\n detail = resolved.detail\n argv = [resolved.executable, ...resolved.commandArgv]\n }\n else if (fallback) {\n permission = fallback.permission\n display = fallback.display\n risk = fallback.risk\n argv = fallback.argv\n }\n else {\n return { success: false, error: 'Command resolution failed' }\n }\n\n // Cache check\n if (detail) {\n const cached = cache.lookup(permission, detail)\n if (cached) {\n api.log.info(`[grants] IdP cache hit for ${permission}`)\n audit.write({ event: 'grant_used', grantId: cached.id, permission, command, detail: 'idp cache hit' })\n return doExecute(api, config, argv, cached.jwt, privileged)\n }\n }\n\n // Create grant at IdP\n const grantsEndpoint = await getGrantsEndpoint(authState.idpUrl)\n const grantBody: Record<string, unknown> = {\n requester: authState.email,\n target_host: hostname(),\n audience: config.audience,\n grant_type: config.defaultApproval,\n command: argv,\n reason: reason ?? display,\n permissions: [permission],\n }\n\n if (resolved) {\n grantBody.authorization_details = [resolved.detail]\n grantBody.execution_context = resolved.executionContext\n }\n\n const createResp = await fetch(grantsEndpoint, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${authState.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(grantBody),\n })\n\n if (!createResp.ok) {\n const text = await createResp.text()\n return { success: false, error: `IdP grant creation failed: ${createResp.status} ${text}` }\n }\n\n const { id: grantId } = await createResp.json() as { id: string, status: string }\n audit.write({ event: 'grant_requested', grantId, permission, command })\n\n // Store locally\n const localGrant = store.createGrant({ permission, command, reason, risk: risk as 'low' | 'medium' | 'high' | 'critical', display })\n\n // Poll for approval\n const pollInterval = config.pollIntervalMs ?? 3000\n const pollTimeout = config.pollTimeoutMs ?? 300000\n const deadline = Date.now() + pollTimeout\n\n while (Date.now() < deadline) {\n const statusResp = await fetch(`${grantsEndpoint}/${grantId}`, {\n headers: { Authorization: `Bearer ${authState.token}` },\n })\n\n if (statusResp.ok) {\n const { status } = await statusResp.json() as { status: string }\n if (status === 'approved')\n break\n if (status === 'denied' || status === 'revoked') {\n audit.write({ event: 'grant_denied', grantId, permission })\n store.denyGrant(localGrant.id)\n return { success: false, error: `Grant ${status}: ${display}` }\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, pollInterval))\n }\n\n if (Date.now() >= deadline) {\n return { success: false, error: `Grant approval timed out for: ${display}` }\n }\n\n // Fetch authorization JWT\n const tokenResp = await fetch(`${grantsEndpoint}/${grantId}/token`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${authState.token}` },\n })\n\n if (!tokenResp.ok) {\n return { success: false, error: `Failed to fetch grant token: ${tokenResp.status}` }\n }\n\n const { authz_jwt: jwt } = await tokenResp.json() as { authz_jwt: string }\n\n // Verify JWT\n if (resolved) {\n const jwksUri = await getJwksUri(authState.idpUrl)\n const verifyResult = await verifyAuthzJWT(jwt, {\n expectedIss: authState.idpUrl,\n expectedAud: config.audience,\n jwksUri,\n })\n\n if (!verifyResult.valid) {\n return { success: false, error: `Grant JWT verification failed: ${verifyResult.error}` }\n }\n\n // Verify coverage\n const claims = verifyResult.claims!\n const grantedDetails = extractCliDetails(claims as unknown as Record<string, unknown>)\n if (grantedDetails.length > 0 && !grantedDetails.some(d => cliAuthorizationDetailCovers(d, resolved.detail))) {\n return { success: false, error: `Grant does not cover required permission: ${permission}` }\n }\n }\n\n // Update local state\n const approval = config.defaultApproval\n store.approveGrant(localGrant.id, approval)\n if (detail && approval !== 'once') {\n const updatedGrant = store.getGrant(localGrant.id)!\n updatedGrant.jwt = jwt\n cache.put(updatedGrant, detail)\n }\n store.consumeGrant(localGrant.id)\n\n audit.write({ event: 'grant_approved', grantId, permission, command })\n\n return doExecute(api, config, argv, jwt, privileged)\n}\n\nfunction extractCliDetails(claims: Record<string, unknown>): OpenApeCliAuthorizationDetail[] {\n const details = claims.authorization_details\n if (!Array.isArray(details))\n return []\n return details.filter((d): d is OpenApeCliAuthorizationDetail =>\n typeof d === 'object' && d !== null && (d as Record<string, unknown>).type === 'openape_cli',\n )\n}\n\nasync function doExecute(api: PluginApi, config: PluginConfig, argv: string[], jwt?: string, privileged?: boolean): Promise<ToolResult> {\n const [command, ...args] = argv\n if (!command)\n return { success: false, error: 'Empty command' }\n\n return executeCommand(api, {\n command,\n args,\n jwt,\n privileged: privileged && config.apes?.enabled,\n apesBinaryPath: config.apes?.binaryPath ?? 'apes',\n })\n}\n","import { resolveIdP } from '@openape/core'\n\nconst _discoveryCache: Record<string, Record<string, unknown>> = {}\n\nexport function extractDomain(email: string): string {\n const parts = email.split('@')\n if (parts.length !== 2 || !parts[1])\n throw new Error(`Invalid email: ${email}`)\n return parts[1]\n}\n\nexport async function discoverIdpUrl(email: string, pinnedUrl?: string): Promise<string> {\n if (pinnedUrl)\n return pinnedUrl\n\n const domain = extractDomain(email)\n const idpUrl = await resolveIdP(domain)\n if (!idpUrl)\n throw new Error(`No DDISA record found for domain: ${domain}`)\n\n return idpUrl\n}\n\nexport async function discoverEndpoints(idpUrl: string): Promise<Record<string, unknown>> {\n if (_discoveryCache[idpUrl])\n return _discoveryCache[idpUrl]!\n\n try {\n const response = await fetch(`${idpUrl}/.well-known/openid-configuration`)\n if (response.ok) {\n const data = await response.json() as Record<string, unknown>\n _discoveryCache[idpUrl] = data\n return data\n }\n }\n catch {}\n\n _discoveryCache[idpUrl] = {}\n return {}\n}\n\nexport async function getGrantsEndpoint(idpUrl: string): Promise<string> {\n const disco = await discoverEndpoints(idpUrl)\n return (disco.openape_grants_endpoint as string) || `${idpUrl}/api/grants`\n}\n\nexport async function getAgentChallengeEndpoint(idpUrl: string): Promise<string> {\n const disco = await discoverEndpoints(idpUrl)\n return (disco.ddisa_agent_challenge_endpoint as string) || `${idpUrl}/api/agent/challenge`\n}\n\nexport async function getAgentAuthenticateEndpoint(idpUrl: string): Promise<string> {\n const disco = await discoverEndpoints(idpUrl)\n return (disco.ddisa_agent_authenticate_endpoint as string) || `${idpUrl}/api/agent/authenticate`\n}\n\nexport async function getJwksUri(idpUrl: string): Promise<string> {\n const disco = await discoverEndpoints(idpUrl)\n return (disco.jwks_uri as string) || `${idpUrl}/.well-known/jwks.json`\n}\n\nexport function clearDiscoveryCache(): void {\n for (const key of Object.keys(_discoveryCache))\n delete _discoveryCache[key]\n}\n","import type { PluginApi, PluginConfig, ToolInput, ToolResult } from '../types.js'\nimport type { LoadedAdapter, ResolvedCommand } from '../adapters/types.js'\nimport { resolveCommandFromAdapters } from '../adapters/parser.js'\nimport type { GrantStore } from '../store/grant-store.js'\nimport type { GrantCache } from '../store/grant-cache.js'\nimport type { AuditLog } from '../store/audit-log.js'\nimport type { LocalJwtSigner } from '../local/local-jwt.js'\nimport type { ChannelApproval } from '../approval/channel-approval.js'\nimport { executeCommand } from '../execution/executor.js'\nimport { handleIdpGrantExec } from '../idp/idp-grants.js'\nimport type { AgentAuthState } from '../idp/auth.js'\nimport type { OpenApeCliAuthorizationDetail, OpenApeExecutionContext } from '@openape/core'\n\nexport interface GrantExecContext {\n config: PluginConfig\n api: PluginApi\n adapters: LoadedAdapter[]\n store: GrantStore\n cache: GrantCache\n audit: AuditLog\n localJwt: LocalJwtSigner | null\n channelApproval: ChannelApproval | null\n idpAuthState: AgentAuthState | null\n}\n\nexport async function handleGrantExec(\n ctx: GrantExecContext,\n input: ToolInput,\n): Promise<ToolResult> {\n const { config, api, adapters, store, cache, audit } = ctx\n\n // 1. Resolve command against adapters\n const resolution = await resolveCommandFromAdapters(adapters, input.command)\n\n let permission: string\n let display: string\n let risk: string\n let detail: OpenApeCliAuthorizationDetail | null = null\n let executionContext: OpenApeExecutionContext | null = null\n let argv: string[]\n\n if (resolution.resolved) {\n const r = resolution.resolved\n permission = r.permission\n display = r.detail.display\n risk = r.detail.risk\n detail = r.detail\n executionContext = r.executionContext\n argv = [r.executable, ...r.commandArgv]\n }\n else if (resolution.fallback) {\n const f = resolution.fallback\n permission = f.permission\n display = f.display\n risk = f.risk\n argv = f.argv\n }\n else {\n return { success: false, error: 'Command resolution failed' }\n }\n\n // 2. Check cache\n if (detail) {\n const cached = cache.lookup(permission, detail)\n if (cached) {\n api.log.info(`[grants] Cache hit for ${permission}`)\n audit.write({ event: 'grant_used', grantId: cached.id, permission, command: input.command, detail: 'cache hit' })\n return doExecute(ctx, argv, input, cached.jwt)\n }\n }\n\n // 3. Create grant and request approval\n const grant = store.createGrant({\n permission,\n command: input.command,\n reason: input.reason,\n risk: risk as 'low' | 'medium' | 'high' | 'critical',\n display,\n })\n\n audit.write({ event: 'grant_requested', grantId: grant.id, permission, command: input.command })\n\n // 4. Approval flow (local mode)\n if (config.mode === 'local') {\n if (!ctx.channelApproval) {\n return { success: false, error: 'Channel approval not available' }\n }\n\n const result = await ctx.channelApproval.requestApproval(grant)\n if (!result.approved) {\n audit.write({ event: 'grant_denied', grantId: grant.id, permission })\n return { success: false, error: `Grant denied for: ${display}` }\n }\n\n // Re-read the grant (approval updates it)\n const approvedGrant = store.getGrant(grant.id)\n if (!approvedGrant || approvedGrant.status !== 'approved') {\n return { success: false, error: 'Grant not in approved state' }\n }\n\n // 5. Sign local JWT\n let jwt: string | undefined\n if (ctx.localJwt && detail && executionContext) {\n jwt = await ctx.localJwt.signGrant({\n grant: approvedGrant,\n audience: config.audience,\n detail,\n executionContext,\n })\n approvedGrant.jwt = jwt\n }\n\n // 6. Cache if not once\n if (detail && approvedGrant.approval !== 'once') {\n cache.put(approvedGrant, detail)\n }\n\n // 7. Execute\n store.consumeGrant(approvedGrant.id)\n audit.write({ event: 'grant_approved', grantId: approvedGrant.id, permission, command: input.command })\n return doExecute(ctx, argv, input, jwt)\n }\n\n // IdP mode\n if (config.mode === 'idp') {\n if (!ctx.idpAuthState) {\n return { success: false, error: 'IdP authentication not available. Check agentEmail and agentKeyPath config.' }\n }\n\n return handleIdpGrantExec(\n { config, api, authState: ctx.idpAuthState, store, cache, audit },\n { resolved: resolution.resolved, fallback: resolution.fallback, command: input.command, reason: input.reason, privileged: input.privileged },\n )\n }\n\n return { success: false, error: `Unknown mode: ${config.mode}` }\n}\n\nasync function doExecute(\n ctx: GrantExecContext,\n argv: string[],\n input: ToolInput,\n jwt?: string,\n): Promise<ToolResult> {\n const { config, api, audit } = ctx\n const [command, ...args] = argv\n\n if (!command) {\n return { success: false, error: 'Empty command' }\n }\n\n const privileged = input.privileged && config.apes?.enabled\n const result = await executeCommand(api, {\n command,\n args,\n jwt,\n privileged,\n apesBinaryPath: config.apes?.binaryPath ?? 'apes',\n })\n\n audit.write({\n event: result.success ? 'exec_success' : 'exec_failed',\n command: input.command,\n detail: result.error,\n })\n\n return result\n}\n","import { readFileSync } from 'node:fs'\nimport { sign } from 'node:crypto'\nimport { getAgentAuthenticateEndpoint, getAgentChallengeEndpoint } from './discovery.js'\n\nexport interface AgentAuthState {\n idpUrl: string\n token: string\n email: string\n expiresAt: number\n}\n\nexport async function authenticateAgent(options: {\n idpUrl: string\n email: string\n keyPath: string\n}): Promise<AgentAuthState> {\n const { idpUrl, email, keyPath } = options\n\n // Load Ed25519 private key\n const keyContent = readFileSync(keyPath, 'utf-8')\n const privateKey = loadEd25519PrivateKey(keyContent)\n\n // Challenge\n const challengeUrl = await getAgentChallengeEndpoint(idpUrl)\n const challengeResp = await fetch(challengeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ agent_id: email }),\n })\n\n if (!challengeResp.ok)\n throw new Error(`Agent challenge failed: ${challengeResp.status} ${await challengeResp.text()}`)\n\n const { challenge } = await challengeResp.json() as { challenge: string }\n\n // Sign\n const signature = sign(null, Buffer.from(challenge), privateKey).toString('base64')\n\n // Authenticate\n const authenticateUrl = await getAgentAuthenticateEndpoint(idpUrl)\n const authResp = await fetch(authenticateUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ agent_id: email, challenge, signature }),\n })\n\n if (!authResp.ok)\n throw new Error(`Agent authentication failed: ${authResp.status} ${await authResp.text()}`)\n\n const { token, expires_in } = await authResp.json() as { token: string, expires_in: number }\n\n return {\n idpUrl,\n token,\n email,\n expiresAt: Math.floor(Date.now() / 1000) + (expires_in || 3600),\n }\n}\n\nexport function isTokenExpired(state: AgentAuthState): boolean {\n return Math.floor(Date.now() / 1000) > state.expiresAt - 30\n}\n\nfunction loadEd25519PrivateKey(content: string): string | Buffer {\n // PKCS8 PEM\n if (content.includes('BEGIN PRIVATE KEY'))\n return content\n\n // OpenSSH format — extract the raw key\n if (content.includes('BEGIN OPENSSH PRIVATE KEY'))\n return content\n\n throw new Error('Unsupported key format. Expected PKCS8 PEM or OpenSSH format.')\n}\n","import { existsSync } from 'node:fs'\nimport { execFileSync } from 'node:child_process'\n\nexport interface ApesConfig {\n enabled: boolean\n binaryPath: string\n}\n\nexport function detectApes(binaryPath: string = 'apes'): { available: boolean, path: string, version?: string } {\n // Check explicit path first\n if (binaryPath !== 'apes' && existsSync(binaryPath)) {\n return { available: true, path: binaryPath, version: getApesVersion(binaryPath) }\n }\n\n // Check PATH\n try {\n const result = execFileSync('which', [binaryPath], { encoding: 'utf-8', timeout: 5000 }).trim()\n if (result) {\n return { available: true, path: result, version: getApesVersion(result) }\n }\n }\n catch {\n // not found in PATH\n }\n\n return { available: false, path: binaryPath }\n}\n\nfunction getApesVersion(binaryPath: string): string | undefined {\n try {\n return execFileSync(binaryPath, ['--version'], { encoding: 'utf-8', timeout: 5000 }).trim()\n }\n catch {\n return undefined\n }\n}\n\nexport function buildApesArgs(jwt: string, command: string, args: string[]): string[] {\n return ['--grant', jwt, '--', command, ...args]\n}\n","import type {\n HookContext,\n HookResult,\n PluginApi,\n PluginConfig,\n ToolInput,\n ToolResult,\n} from './types.js'\nimport { DEFAULT_CONFIG } from './types.js'\nimport { discoverAdapters } from './adapters/loader.js'\nimport type { LoadedAdapter } from './adapters/types.js'\nimport { GrantStore } from './store/grant-store.js'\nimport { GrantCache } from './store/grant-cache.js'\nimport { AuditLog } from './store/audit-log.js'\nimport { LocalJwtSigner } from './local/local-jwt.js'\nimport { ChannelApproval } from './approval/channel-approval.js'\nimport { handleGrantExec } from './tools/grant-exec.js'\nimport { authenticateAgent, isTokenExpired } from './idp/auth.js'\nimport type { AgentAuthState } from './idp/auth.js'\nimport { discoverIdpUrl } from './idp/discovery.js'\n\nexport type { PluginApi, PluginConfig } from './types.js'\nexport {\n parseAdapterToml,\n resolveCommand,\n resolveCommandFromAdapters,\n createFallbackCommand,\n parseCommandString,\n loadAdapter,\n loadAdapterFromFile,\n discoverAdapters,\n} from './adapters/index.js'\nexport type {\n AdapterDefinition,\n AdapterOperation,\n CommandResolutionResult,\n FallbackCommand,\n LoadedAdapter,\n ResolvedCommand,\n AdapterSearchPaths,\n} from './adapters/index.js'\nexport { GrantStore } from './store/grant-store.js'\nexport { GrantCache } from './store/grant-cache.js'\nexport { AuditLog } from './store/audit-log.js'\nexport { LocalJwtSigner } from './local/local-jwt.js'\nexport { ChannelApproval } from './approval/channel-approval.js'\nexport { executeCommand } from './execution/executor.js'\nexport { detectApes, buildApesArgs } from './execution/apes.js'\nexport { handleGrantExec } from './tools/grant-exec.js'\nexport { authenticateAgent, isTokenExpired } from './idp/auth.js'\nexport type { AgentAuthState } from './idp/auth.js'\nexport { discoverIdpUrl, discoverEndpoints, getGrantsEndpoint, clearDiscoveryCache } from './idp/discovery.js'\nexport { handleIdpGrantExec } from './idp/idp-grants.js'\n\nconst BLOCKED_TOOLS = new Set(['exec', 'bash', 'shell', 'run_command'])\n\nexport function register(api: PluginApi, userConfig?: Partial<PluginConfig>): void {\n const config: PluginConfig = { ...DEFAULT_CONFIG, ...userConfig }\n\n api.log.info(`[grants] Initializing in ${config.mode} mode`)\n\n // --- State ---\n const stateDir = api.runtime.config.getStateDir()\n const workspaceDir = api.runtime.config.getWorkspaceDir()\n\n const store = new GrantStore(stateDir)\n const cache = new GrantCache()\n const audit = new AuditLog(stateDir)\n\n // --- Adapters ---\n const adapters: LoadedAdapter[] = discoverAdapters({\n explicit: config.adapterPaths,\n workspaceDir,\n })\n api.log.info(`[grants] Loaded ${adapters.length} adapters: ${adapters.map(a => a.adapter.cli.id).join(', ')}`)\n\n // --- Local Mode Setup ---\n let localJwt: LocalJwtSigner | null = null\n let channelApproval: ChannelApproval | null = null\n\n if (config.mode === 'local') {\n localJwt = new LocalJwtSigner(stateDir)\n channelApproval = new ChannelApproval(api, store, config.pollTimeoutMs)\n\n // Init key pair asynchronously\n localJwt.init().catch((error) => {\n api.log.error(`[grants] Failed to init local JWT: ${error}`)\n })\n }\n\n // --- IdP Mode Setup ---\n let idpAuthState: AgentAuthState | null = null\n\n if (config.mode === 'idp') {\n if (!config.agentEmail || !config.agentKeyPath) {\n api.log.error('[grants] IdP mode requires agentEmail and agentKeyPath')\n }\n else {\n // Init auth asynchronously\n discoverIdpUrl(config.agentEmail, config.idpUrl)\n .then(idpUrl => authenticateAgent({\n idpUrl,\n email: config.agentEmail!,\n keyPath: config.agentKeyPath!,\n }))\n .then((state) => {\n idpAuthState = state\n api.log.info(`[grants] IdP auth OK: ${state.email} @ ${state.idpUrl}`)\n })\n .catch((error) => {\n api.log.error(`[grants] IdP auth failed: ${error}`)\n })\n }\n }\n\n // --- Tool: grant_exec ---\n api.registerTool({\n name: 'grant_exec',\n description: [\n 'Execute a CLI command with grant-based authorization.',\n 'Commands are resolved against adapters for granular permissions.',\n 'The owner must approve the grant before execution proceeds.',\n ].join(' '),\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'The full CLI command to execute (e.g. \"gh pr merge 42 --repo openape/core\")',\n },\n reason: {\n type: 'string',\n description: 'Why this command needs to be executed',\n },\n privileged: {\n type: 'boolean',\n description: 'Whether this command requires elevated privileges (via apes)',\n },\n },\n required: ['command'],\n },\n handler: async (input: ToolInput): Promise<ToolResult> => {\n api.log.info(`[grants] grant_exec called: ${input.command}`)\n return handleGrantExec(\n { config, api, adapters, store, cache, audit, localJwt, channelApproval, idpAuthState },\n input,\n )\n },\n })\n\n // --- Hook: before_tool_call → block exec/bash ---\n api.on('before_tool_call', async (context: HookContext): Promise<HookResult> => {\n if (BLOCKED_TOOLS.has(context.toolName)) {\n api.log.warn(`[grants] Blocked tool: ${context.toolName} — use grant_exec instead`)\n audit.write({ event: 'exec_blocked', command: String(context.toolInput.command ?? context.toolName) })\n return {\n allow: false,\n message: `Direct command execution via \"${context.toolName}\" is disabled. Use grant_exec instead for authorized command execution.`,\n }\n }\n return { allow: true }\n }, { priority: 100 })\n\n // --- HTTP Route: JWKS ---\n api.registerHttpRoute({\n path: '/grants/.well-known/jwks.json',\n method: 'GET',\n handler: async (): Promise<{ status: number, headers: Record<string, string>, body: unknown }> => {\n if (!localJwt) {\n return {\n status: 404,\n headers: { 'Content-Type': 'application/json' },\n body: { error: 'JWKS not available in IdP mode' },\n }\n }\n\n try {\n const jwks = await localJwt.getJwks()\n return {\n status: 200,\n headers: { 'Content-Type': 'application/json', 'Cache-Control': 'public, max-age=3600' },\n body: jwks,\n }\n }\n catch {\n return {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n body: { error: 'JWKS not ready' },\n }\n }\n },\n })\n\n // --- CLI: openclaw grants ---\n api.registerCli({\n name: 'grants',\n description: 'Manage grant-based command execution',\n subcommands: [\n {\n name: 'status',\n description: 'Show grant system status (mode, auth, active grants)',\n handler: async () => {\n console.log(`Mode: ${config.mode}`)\n console.log(`Adapters: ${adapters.length} loaded`)\n console.log(`Active grants: ${store.getActiveGrantCount()}`)\n console.log(`Cache entries: ${cache.size()}`)\n },\n },\n {\n name: 'list',\n description: 'List all grants',\n handler: async () => {\n const grants = store.listGrants()\n if (grants.length === 0) {\n console.log('No grants')\n return\n }\n for (const g of grants) {\n console.log(`${g.id} [${g.status}] ${g.permission} (${g.approval})`)\n }\n },\n },\n {\n name: 'revoke',\n description: 'Revoke a grant by ID',\n handler: async (args: string[]) => {\n const id = args[0]\n if (!id) {\n console.error('Usage: openclaw grants revoke <grant-id>')\n return\n }\n const success = store.revokeGrant(id)\n if (success) {\n cache.remove(store.getGrant(id)?.permission ?? '')\n audit.write({ event: 'grant_revoked', grantId: id })\n console.log(`Grant ${id} revoked`)\n }\n else {\n console.error(`Grant ${id} not found or cannot be revoked`)\n }\n },\n },\n {\n name: 'adapters',\n description: 'List loaded adapters and their operations',\n handler: async () => {\n if (adapters.length === 0) {\n console.log('No adapters loaded')\n return\n }\n for (const a of adapters) {\n console.log(`\\n${a.adapter.cli.id} (${a.adapter.cli.executable})`)\n for (const op of a.adapter.operations) {\n console.log(` ${op.id}: ${op.display} [${op.risk}]`)\n }\n }\n },\n },\n ],\n handler: async (args: string[]) => {\n console.log(`Unknown subcommand: ${args.join(' ')}`)\n console.log('Available: status, list, revoke, adapters')\n },\n })\n\n api.log.info('[grants] Plugin registered successfully')\n}\n"],"mappings":"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","names":["existsSync","readFileSync","dirname","join","existsSync","mkdirSync","dirname","join","existsSync","mkdirSync","readFileSync","writeFileSync","join","randomUUID","operation","bindings","cliAuthorizationDetailCovers","cliAuthorizationDetailCovers","doExecute","readFileSync","readFileSync","existsSync"]}
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "openclaw-plugin-grants",
3
+ "version": "0.1.0",
4
+ "description": "Grant-based command execution with granular adapter permissions",
5
+ "entry": "dist/index.js",
6
+ "capabilities": {
7
+ "tools": ["grant_exec"],
8
+ "hooks": ["before_tool_call"],
9
+ "httpRoutes": ["/grants/.well-known/jwks.json"],
10
+ "cli": ["grants"]
11
+ },
12
+ "config": {
13
+ "mode": {
14
+ "type": "string",
15
+ "enum": ["local", "idp"],
16
+ "default": "local",
17
+ "description": "Grant approval mode: local (channel-approval) or idp (federation)"
18
+ },
19
+ "audience": {
20
+ "type": "string",
21
+ "default": "openclaw",
22
+ "description": "JWT audience claim"
23
+ },
24
+ "defaultApproval": {
25
+ "type": "string",
26
+ "enum": ["once", "timed", "always"],
27
+ "default": "once",
28
+ "description": "Default grant approval type"
29
+ },
30
+ "adapterPaths": {
31
+ "type": "array",
32
+ "items": { "type": "string" },
33
+ "description": "Additional adapter search directories"
34
+ },
35
+ "agentEmail": {
36
+ "type": "string",
37
+ "description": "Agent email for IdP mode (DNS discovery)"
38
+ },
39
+ "agentKeyPath": {
40
+ "type": "string",
41
+ "description": "Path to Ed25519 private key for IdP mode"
42
+ },
43
+ "idpUrl": {
44
+ "type": "string",
45
+ "description": "Pin IdP URL (skip DNS discovery)"
46
+ },
47
+ "apes": {
48
+ "type": "object",
49
+ "properties": {
50
+ "enabled": { "type": "boolean", "default": false },
51
+ "binaryPath": { "type": "string", "default": "apes" }
52
+ }
53
+ },
54
+ "pollIntervalMs": {
55
+ "type": "number",
56
+ "default": 3000
57
+ },
58
+ "pollTimeoutMs": {
59
+ "type": "number",
60
+ "default": 300000
61
+ }
62
+ }
63
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@openape/openclaw-plugin-grants",
3
+ "type": "module",
4
+ "version": "0.2.0",
5
+ "description": "OpenClaw plugin for grant-based command execution with granular permissions",
6
+ "license": "MIT",
7
+ "author": "Patrick Hofmann <patrick@delta-mind.at>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/openape-ai/openape.git",
11
+ "directory": "packages/openclaw-plugin-grants"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "dist",
24
+ "adapters",
25
+ "openclaw.plugin.json"
26
+ ],
27
+ "dependencies": {
28
+ "jose": "^5.9.0",
29
+ "consola": "^3.4.2",
30
+ "@openape/core": "0.8.0",
31
+ "@openape/grants": "0.5.2"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^22.19.13",
35
+ "typescript": "^5.9.3",
36
+ "tsup": "^8.5.1",
37
+ "vitest": "^3.2.4",
38
+ "eslint": "^9.35.0",
39
+ "@antfu/eslint-config": "^7.6.1"
40
+ },
41
+ "engines": {
42
+ "node": ">=22"
43
+ },
44
+ "openclaw": {
45
+ "extensions": [
46
+ "./dist/index.js"
47
+ ]
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "test": "vitest run",
55
+ "typecheck": "tsc --noEmit",
56
+ "lint": "eslint ."
57
+ }
58
+ }