From 12491b04a0201c4e6662bfa325808702b8316341 Mon Sep 17 00:00:00 2001 From: SentienceDEV Date: Fri, 20 Feb 2026 19:45:39 -0800 Subject: [PATCH 1/2] updated readme; non-web state_hash --- README.md | 34 ++++-- examples/README.md | 50 ++++++++ examples/non-web-evidence-demo.ts | 184 ++++++++++++++++++++++++++++ package.json | 2 +- src/non-web-evidence.ts | 43 +++++-- tests/non-web-evidence.test.ts | 194 +++++++++++++++++++++++------- 6 files changed, 446 insertions(+), 61 deletions(-) create mode 100644 examples/non-web-evidence-demo.ts diff --git a/README.md b/README.md index 482e0e2..6524967 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# openclaw-predicate-provider +# predicate-claw > **Stop prompt injection before it executes.** @@ -17,8 +17,8 @@ Policy: DENY (sensitive_path + untrusted_source) Result: ActionDeniedError — SSH key never read ``` -[![npm version](https://img.shields.io/npm/v/openclaw-predicate-provider.svg)](https://www.npmjs.com/package/openclaw-predicate-provider) -[![CI](https://github.com/PredicateSystems/openclaw-predicate-provider/actions/workflows/tests.yml/badge.svg)](https://github.com/PredicateSystems/openclaw-predicate-provider/actions) +[![npm version](https://img.shields.io/npm/v/predicate-claw.svg)](https://www.npmjs.com/package/predicate-claw) +[![CI](https://github.com/PredicateSystems/predicate-claw/actions/workflows/tests.yml/badge.svg)](https://github.com/PredicateSystems/predicate-claw/actions) [![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE) --- @@ -45,6 +45,8 @@ a document, or a webpage can hijack your agent. Predicate Authority intercepts every tool call and authorizes it **before execution**. +*Identity providers give your agent a passport. Predicate gives it a work visa.* We don't just know who the agent is; we cryptographically verify exactly what it is allowed to do, right when it tries to do it. + | Without Protection | With Predicate Authority | |-------------------|-------------------------| | Agent reads ~/.ssh/id_rsa | **BLOCKED** - sensitive path | @@ -57,21 +59,37 @@ Predicate Authority intercepts every tool call and authorizes it **before execut - 🔒 **Deterministic** — No probabilistic filtering, reproducible decisions - 🚫 **Fail-closed** — Errors block execution, never allow - 📋 **Auditable** — Every decision logged with full context +- 🛡️ **Zero-egress** — Sidecar runs locally; no data leaves your infrastructure --- ## Quick Start +### 0. Prerequisites + +This SDK requires the Predicate Authority sidecar to evaluate policies locally. + +```bash +# macOS (Homebrew) +brew install predicatesystems/tap/predicate-authorityd + +# Or via install script +curl -sSL https://predicate.systems/install.sh | bash + +# Or Docker +docker run -d -p 8787:8787 predicatesystems/authorityd:latest +``` + ### 1. Install ```bash -npm install openclaw-predicate-provider +npm install predicate-claw ``` ### 2. Protect your agent ```typescript -import { GuardedProvider } from "openclaw-predicate-provider"; +import { GuardedProvider } from "predicate-claw"; const provider = new GuardedProvider({ principal: "agent:my-agent", @@ -92,8 +110,8 @@ const content = await fs.readFile(path); // Only runs if authorized ### 3. See it in action ```bash -git clone https://github.com/PredicateSystems/openclaw-predicate-provider -cd openclaw-predicate-provider +git clone https://github.com/PredicateSystems/predicate-claw +cd predicate-claw npm install npm run test:demo ``` @@ -386,5 +404,5 @@ MIT OR Apache-2.0

Don't let prompt injection own your agent.
- npm install openclaw-predicate-provider + npm install predicate-claw

diff --git a/examples/README.md b/examples/README.md index 18aafe8..ded175b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -112,6 +112,56 @@ sidecar runs. 3. Show deny result and user-facing blocked message. 4. Show test command and green output as reproducible evidence. +## Non-Web Evidence Provider Demo + +Demonstrates terminal and desktop accessibility evidence providers with canonical +hashing for reproducible `state_hash` computation. + +### Run the Demo + +```bash +npx tsx examples/non-web-evidence-demo.ts +``` + +### What It Shows + +1. **Terminal Evidence** - Captures command-line state with: + - Path normalization (`/workspace/./src/../src` → `/workspace/src`) + - Whitespace collapsing (`git status` → `git status`) + - ANSI code stripping (removes color codes) + - Timestamp normalization (`[12:34:56]` → `[TIMESTAMP]`) + - Secret redaction (environment variables like `AWS_SECRET_KEY`) + +2. **Desktop Evidence** - Captures accessibility tree state with: + - App name normalization + - UI tree text normalization + - Whitespace handling + +3. **Hash Stability** - Proves that minor variations produce identical hashes + when canonicalization is enabled. + +### API Usage + +```typescript +import { + OpenClawTerminalEvidenceProvider, + buildTerminalEvidenceFromProvider, +} from "predicate-claw"; + +const provider = new OpenClawTerminalEvidenceProvider(() => ({ + sessionId: "my-session", + cwd: process.cwd(), + command: "npm test", + transcript: "...", +})); + +const evidence = await buildTerminalEvidenceFromProvider(provider, { + useCanonicalHash: true, // default +}); + +console.log(evidence.state_hash); // sha256:... +``` + ## Other Examples - `openclaw_integration_example.py` - Python integration example diff --git a/examples/non-web-evidence-demo.ts b/examples/non-web-evidence-demo.ts new file mode 100644 index 0000000..a38f31e --- /dev/null +++ b/examples/non-web-evidence-demo.ts @@ -0,0 +1,184 @@ +/** + * Non-Web Evidence Provider Demo + * + * This example demonstrates how to use the terminal and desktop accessibility + * evidence providers with canonical hashing for reproducible state_hash computation. + * + * The canonicalization ensures that minor variations (ANSI codes, timestamps, + * whitespace) don't break hash verification. + * + * Run with: npx tsx examples/non-web-evidence-demo.ts + */ + +import { + OpenClawTerminalEvidenceProvider, + OpenClawDesktopAccessibilityEvidenceProvider, + buildTerminalEvidenceFromProvider, + buildDesktopEvidenceFromProvider, + type TerminalRuntimeContext, + type DesktopRuntimeContext, +} from "../src/index.js"; + +// ============================================================================ +// Terminal Evidence Demo +// ============================================================================ + +async function demoTerminalEvidence(): Promise { + console.log("=".repeat(60)); + console.log("Terminal Evidence Provider Demo"); + console.log("=".repeat(60)); + + // Simulated terminal runtime context (in real usage, capture from actual terminal) + const terminalContext: TerminalRuntimeContext = { + sessionId: "demo-session-001", + terminalId: "term-1", + cwd: "/workspace/./src/../src", // Will be normalized to /workspace/src + command: "git status ", // Extra whitespace will be collapsed + // Transcript with ANSI codes and timestamps that will be normalized + transcript: `\x1b[32m[12:34:56]\x1b[0m Running git status... +On branch main +Your branch is up to date with 'origin/main'. + +\x1b[33mnothing to commit, working tree clean\x1b[0m`, + env: { + HOME: "/home/user", + PATH: "/usr/bin:/bin", + AWS_SECRET_KEY: "should-be-redacted", // Secrets are redacted + EDITOR: "vim", + }, + }; + + // Create provider with capture function + const terminalProvider = new OpenClawTerminalEvidenceProvider( + () => terminalContext, + ); + + // Build evidence with canonical hashing (default) + const terminalEvidence = await buildTerminalEvidenceFromProvider( + terminalProvider, + { useCanonicalHash: true }, + ); + + console.log("\nTerminal Evidence:"); + console.log(JSON.stringify(terminalEvidence, null, 2)); + + // Demonstrate hash stability - same content with different formatting + const terminalContext2: TerminalRuntimeContext = { + ...terminalContext, + cwd: "/workspace/src", // Same path after normalization + command: "git status", // Same command after whitespace collapse + // Same content without ANSI codes and different timestamps + transcript: `[09:00:00] Running git status... +On branch main +Your branch is up to date with 'origin/main'. + +nothing to commit, working tree clean`, + }; + + const terminalProvider2 = new OpenClawTerminalEvidenceProvider( + () => terminalContext2, + ); + + const terminalEvidence2 = await buildTerminalEvidenceFromProvider( + terminalProvider2, + { useCanonicalHash: true }, + ); + + console.log("\nTerminal Evidence (normalized variant):"); + console.log(JSON.stringify(terminalEvidence2, null, 2)); + + const hashesMatch = terminalEvidence.state_hash === terminalEvidence2.state_hash; + console.log(`\nHashes match: ${hashesMatch ? "YES (canonicalization working)" : "NO"}`); +} + +// ============================================================================ +// Desktop Accessibility Evidence Demo +// ============================================================================ + +async function demoDesktopEvidence(): Promise { + console.log("\n" + "=".repeat(60)); + console.log("Desktop Accessibility Evidence Provider Demo"); + console.log("=".repeat(60)); + + // Simulated desktop accessibility context + const desktopContext: DesktopRuntimeContext = { + appName: " Visual Studio Code ", // Will be trimmed and normalized + windowTitle: "main.ts - my-project", + focusedRole: "editor", + focusedName: "Text Editor", + // Simulated UI tree text (in real usage, capture from OS accessibility API) + uiTreeText: ` + Window: Visual Studio Code + Toolbar: + Button: New File + Button: Save + Editor: + TextArea: main.ts content + StatusBar: + Label: Ln 42, Col 15 + `, + confidence: 0.95, + }; + + // Create provider with capture function + const desktopProvider = new OpenClawDesktopAccessibilityEvidenceProvider( + () => desktopContext, + ); + + // Build evidence with canonical hashing + const desktopEvidence = await buildDesktopEvidenceFromProvider( + desktopProvider, + { useCanonicalHash: true }, + ); + + console.log("\nDesktop Evidence:"); + console.log(JSON.stringify(desktopEvidence, null, 2)); + + // Demonstrate hash stability with whitespace variations + const desktopContext2: DesktopRuntimeContext = { + ...desktopContext, + appName: "Visual Studio Code", // Same after normalization + // Same content with different whitespace + uiTreeText: `Window: Visual Studio Code +Toolbar: +Button: New File +Button: Save +Editor: +TextArea: main.ts content +StatusBar: +Label: Ln 42, Col 15`, + }; + + const desktopProvider2 = new OpenClawDesktopAccessibilityEvidenceProvider( + () => desktopContext2, + ); + + const desktopEvidence2 = await buildDesktopEvidenceFromProvider( + desktopProvider2, + { useCanonicalHash: true }, + ); + + console.log("\nDesktop Evidence (normalized variant):"); + console.log(JSON.stringify(desktopEvidence2, null, 2)); + + const hashesMatch = desktopEvidence.state_hash === desktopEvidence2.state_hash; + console.log(`\nHashes match: ${hashesMatch ? "YES (canonicalization working)" : "NO"}`); +} + +// ============================================================================ +// Main +// ============================================================================ + +async function main(): Promise { + console.log("OpenClaw Non-Web Evidence Provider Demo"); + console.log("Demonstrates canonical hashing for terminal and desktop contexts\n"); + + await demoTerminalEvidence(); + await demoDesktopEvidence(); + + console.log("\n" + "=".repeat(60)); + console.log("Demo complete!"); + console.log("=".repeat(60)); +} + +main().catch(console.error); diff --git a/package.json b/package.json index 2aca266..e57b7cc 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "openclaw-predicate-provider", + "name": "predicate-claw", "version": "0.1.0", "description": "TypeScript OpenClaw security provider with Predicate Authority pre-execution checks.", "main": "dist/src/index.js", diff --git a/src/non-web-evidence.ts b/src/non-web-evidence.ts index aa33588..e88a9e7 100644 --- a/src/non-web-evidence.ts +++ b/src/non-web-evidence.ts @@ -1,12 +1,11 @@ -import crypto from "node:crypto"; import { - buildDesktopAccessibilityStateEvidence, - buildTerminalStateEvidence, type DesktopAccessibilityEvidenceProvider, type DesktopAccessibilitySnapshot, type StateEvidence, type TerminalEvidenceProvider, type TerminalSessionSnapshot, + buildDesktopAccessibilityStateEvidence, + buildTerminalStateEvidence, } from "@predicatesystems/authority"; export interface TerminalRuntimeContext { @@ -14,9 +13,12 @@ export interface TerminalRuntimeContext { terminalId?: string; cwd?: string; command?: string; + /** Raw transcript text (will be canonicalized before hashing) */ transcript?: string; observedAt?: string; confidence?: number; + /** Environment variables (secrets will be redacted before hashing) */ + env?: Record; } export interface DesktopRuntimeContext { @@ -24,7 +26,9 @@ export interface DesktopRuntimeContext { windowTitle?: string; focusedRole?: string; focusedName?: string; + /** Raw UI tree text (will be normalized before hashing) */ uiTreeText?: string; + /** Pre-computed UI tree hash (bypasses canonicalization) */ uiTreeHash?: string; observedAt?: string; confidence?: number; @@ -46,7 +50,10 @@ export class OpenClawTerminalEvidenceProvider terminal_id: runtime.terminalId, cwd: runtime.cwd, command: runtime.command, - transcript_hash: sha256(runtime.transcript ?? ""), + // Pass raw transcript - canonicalization happens in buildTerminalStateEvidence + // when useCanonicalHash is enabled. The field is named transcript_hash for + // backward compatibility but carries raw text when canonical hashing is used. + transcript_hash: runtime.transcript ?? "", observed_at: runtime.observedAt ?? new Date().toISOString(), confidence: runtime.confidence, }; @@ -64,32 +71,46 @@ export class OpenClawDesktopAccessibilityEvidenceProvider async captureAccessibilitySnapshot(): Promise { const runtime = await this.capture(); + // Pass raw UI tree text - canonicalization happens in buildDesktopAccessibilityStateEvidence + // when useCanonicalHash is enabled. Use pre-computed hash if available for legacy mode. + // The field is named ui_tree_hash for backward compatibility but carries raw text + // when canonical hashing is used. return { app_name: runtime.appName, window_title: runtime.windowTitle, focused_role: runtime.focusedRole, focused_name: runtime.focusedName, - ui_tree_hash: runtime.uiTreeHash ?? sha256(runtime.uiTreeText ?? ""), + ui_tree_hash: runtime.uiTreeHash ?? runtime.uiTreeText ?? "", observed_at: runtime.observedAt ?? new Date().toISOString(), confidence: runtime.confidence, }; } } +export interface BuildEvidenceOptions { + /** + * Use canonical hashing with proper normalization. + * When true, applies ANSI stripping, timestamp normalization, whitespace + * collapsing, and other canonicalization rules for reproducible hashes. + * @default true + */ + useCanonicalHash?: boolean; +} + export async function buildTerminalEvidenceFromProvider( provider: TerminalEvidenceProvider, + options: BuildEvidenceOptions = {}, ): Promise { const snapshot = await provider.captureTerminalSnapshot(); - return buildTerminalStateEvidence({ snapshot }); + const useCanonicalHash = options.useCanonicalHash ?? true; + return buildTerminalStateEvidence({ snapshot, useCanonicalHash }); } export async function buildDesktopEvidenceFromProvider( provider: DesktopAccessibilityEvidenceProvider, + options: BuildEvidenceOptions = {}, ): Promise { const snapshot = await provider.captureAccessibilitySnapshot(); - return buildDesktopAccessibilityStateEvidence({ snapshot }); -} - -function sha256(input: string): string { - return crypto.createHash("sha256").update(input).digest("hex"); + const useCanonicalHash = options.useCanonicalHash ?? true; + return buildDesktopAccessibilityStateEvidence({ snapshot, useCanonicalHash }); } diff --git a/tests/non-web-evidence.test.ts b/tests/non-web-evidence.test.ts index cd1a642..7bab9c8 100644 --- a/tests/non-web-evidence.test.ts +++ b/tests/non-web-evidence.test.ts @@ -7,50 +7,162 @@ import { } from "../src/non-web-evidence.js"; describe("non-web evidence providers", () => { - it("builds terminal session state evidence", async () => { - const provider = new OpenClawTerminalEvidenceProvider(() => ({ - sessionId: "s-1", - terminalId: "t-1", - cwd: "/workspace", - command: "cat secrets.txt", - transcript: "line1\nline2\n", - observedAt: "2026-02-20T08:00:00.000Z", - confidence: 0.92, - })); - - const snapshot = await provider.captureTerminalSnapshot(); - const evidence = await buildTerminalEvidenceFromProvider(provider); - - expect(snapshot.session_id).toBe("s-1"); - expect(snapshot.transcript_hash).toEqual(expect.any(String)); - expect(evidence).toMatchObject({ - source: "terminal", - schema_version: "terminal-v1", - confidence: 0.92, + describe("legacy mode (useCanonicalHash=false)", () => { + it("builds terminal session state evidence", async () => { + const provider = new OpenClawTerminalEvidenceProvider(() => ({ + sessionId: "s-1", + terminalId: "t-1", + cwd: "/workspace", + command: "cat secrets.txt", + transcript: "line1\nline2\n", + observedAt: "2026-02-20T08:00:00.000Z", + confidence: 0.92, + })); + + const snapshot = await provider.captureTerminalSnapshot(); + const evidence = await buildTerminalEvidenceFromProvider(provider, { + useCanonicalHash: false, + }); + + expect(snapshot.session_id).toBe("s-1"); + expect(snapshot.transcript_hash).toEqual(expect.any(String)); + expect(evidence).toMatchObject({ + source: "terminal", + schema_version: "terminal-v1", + confidence: 0.92, + }); + expect(evidence.state_hash).toEqual(expect.any(String)); + }); + + it("builds desktop accessibility state evidence", async () => { + const provider = new OpenClawDesktopAccessibilityEvidenceProvider(() => ({ + appName: "Terminal", + windowTitle: "Deploy Prod", + focusedRole: "button", + focusedName: "Confirm", + uiTreeText: "root > dialog > button:Confirm", + observedAt: "2026-02-20T08:01:00.000Z", + confidence: 0.88, + })); + + const snapshot = await provider.captureAccessibilitySnapshot(); + const evidence = await buildDesktopEvidenceFromProvider(provider, { + useCanonicalHash: false, + }); + + expect(snapshot.ui_tree_hash).toEqual(expect.any(String)); + expect(evidence).toMatchObject({ + source: "desktop_accessibility", + schema_version: "desktop-a11y-v1", + confidence: 0.88, + }); + expect(evidence.state_hash).toEqual(expect.any(String)); }); - expect(evidence.state_hash).toEqual(expect.any(String)); }); - it("builds desktop accessibility state evidence", async () => { - const provider = new OpenClawDesktopAccessibilityEvidenceProvider(() => ({ - appName: "Terminal", - windowTitle: "Deploy Prod", - focusedRole: "button", - focusedName: "Confirm", - uiTreeText: "root > dialog > button:Confirm", - observedAt: "2026-02-20T08:01:00.000Z", - confidence: 0.88, - })); - - const snapshot = await provider.captureAccessibilitySnapshot(); - const evidence = await buildDesktopEvidenceFromProvider(provider); - - expect(snapshot.ui_tree_hash).toEqual(expect.any(String)); - expect(evidence).toMatchObject({ - source: "desktop_accessibility", - schema_version: "desktop-a11y-v1", - confidence: 0.88, + describe("canonical mode (default)", () => { + it("builds terminal evidence with canonical schema version", async () => { + const provider = new OpenClawTerminalEvidenceProvider(() => ({ + sessionId: "s-1", + terminalId: "t-1", + cwd: "/workspace", + command: "npm test", + transcript: "\x1b[32mPASS\x1b[0m all tests", + observedAt: "2026-02-20T08:00:00.000Z", + confidence: 0.95, + })); + + const evidence = await buildTerminalEvidenceFromProvider(provider); + + expect(evidence).toMatchObject({ + source: "terminal", + schema_version: "terminal:v1.0", + confidence: 0.95, + }); + expect(evidence.state_hash).toMatch(/^sha256:[a-f0-9]{64}$/); + }); + + it("builds desktop evidence with canonical schema version", async () => { + const provider = new OpenClawDesktopAccessibilityEvidenceProvider(() => ({ + appName: "Firefox", + windowTitle: "GitHub", + focusedRole: "button", + focusedName: "Submit", + uiTreeText: "window > form > button:Submit", + observedAt: "2026-02-20T08:01:00.000Z", + confidence: 0.9, + })); + + const evidence = await buildDesktopEvidenceFromProvider(provider); + + expect(evidence).toMatchObject({ + source: "desktop_accessibility", + schema_version: "desktop:v1.0", + confidence: 0.9, + }); + expect(evidence.state_hash).toMatch(/^sha256:[a-f0-9]{64}$/); + }); + + it("produces stable hashes for equivalent terminal inputs", async () => { + // Same content with different whitespace/ANSI codes + const provider1 = new OpenClawTerminalEvidenceProvider(() => ({ + sessionId: "s-1", + command: " npm test ", + transcript: "\x1b[32mOK\x1b[0m", + })); + + const provider2 = new OpenClawTerminalEvidenceProvider(() => ({ + sessionId: "s-1", + command: "npm test", + transcript: "OK", + })); + + const evidence1 = await buildTerminalEvidenceFromProvider(provider1); + const evidence2 = await buildTerminalEvidenceFromProvider(provider2); + + // Canonical hashing should produce identical hashes + expect(evidence1.state_hash).toBe(evidence2.state_hash); + }); + + it("produces stable hashes for equivalent desktop inputs", async () => { + // Same content with different whitespace + const provider1 = new OpenClawDesktopAccessibilityEvidenceProvider(() => ({ + appName: " Firefox ", + windowTitle: " GitHub ", + focusedRole: "BUTTON", + focusedName: " Submit ", + })); + + const provider2 = new OpenClawDesktopAccessibilityEvidenceProvider(() => ({ + appName: "Firefox", + windowTitle: "GitHub", + focusedRole: "button", + focusedName: "Submit", + })); + + const evidence1 = await buildDesktopEvidenceFromProvider(provider1); + const evidence2 = await buildDesktopEvidenceFromProvider(provider2); + + // Canonical hashing should produce identical hashes + expect(evidence1.state_hash).toBe(evidence2.state_hash); + }); + + it("passes raw transcript for canonical hashing in SDK", async () => { + const provider = new OpenClawTerminalEvidenceProvider(() => ({ + sessionId: "s-1", + transcript: "\x1b[31mERROR\x1b[0m: something went wrong", + })); + + const snapshot = await provider.captureTerminalSnapshot(); + + // transcript_hash now contains raw text (hashing is done by SDK when useCanonicalHash=true) + expect(snapshot.transcript_hash).toEqual(expect.any(String)); + // Raw transcript with ANSI codes is 36 chars + expect(snapshot.transcript_hash).toBe("\x1b[31mERROR\x1b[0m: something went wrong"); + + // Verify the final evidence hash is canonical (sha256-prefixed) + const evidence = await buildTerminalEvidenceFromProvider(provider); + expect(evidence.state_hash).toMatch(/^sha256:[a-f0-9]{64}$/); }); - expect(evidence.state_hash).toEqual(expect.any(String)); }); }); From 0c9c71010b5d88e1c693cea20abffe96469e5fcb Mon Sep 17 00:00:00 2001 From: SentienceDEV Date: Fri, 20 Feb 2026 19:47:59 -0800 Subject: [PATCH 2/2] updated dep version --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7e68710..01478d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { - "name": "openclaw-predicate-provider", + "name": "predicate-claw", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "openclaw-predicate-provider", + "name": "predicate-claw", "version": "0.1.0", "license": "(MIT OR Apache-2.0)", "dependencies": { - "@predicatesystems/authority": "^0.3.2" + "@predicatesystems/authority": "^0.3.3" }, "devDependencies": { "@types/node": "^25.3.0", @@ -3743,9 +3743,9 @@ } }, "node_modules/@predicatesystems/authority": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@predicatesystems/authority/-/authority-0.3.2.tgz", - "integrity": "sha512-+QAd3Bo4lgY17SGN1hU39se/cdAvlehyZ7E+YtABtcZsJTWxS4bu2b0FuH+7YFkpn3T+05ckV173UdtBSAAjVg==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@predicatesystems/authority/-/authority-0.3.3.tgz", + "integrity": "sha512-AGGfrzgnox7IG/9o3tAVLDd4eRkxvz+JTkNoQ+ypiQwxqRMchOX3gXyBP78pqg0TtkkBsCwtGMN8ml7XdE0otw==", "license": "(MIT OR Apache-2.0)", "engines": { "node": ">=20.0.0" diff --git a/package.json b/package.json index e57b7cc..0b328dd 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "license": "(MIT OR Apache-2.0)", "type": "module", "dependencies": { - "@predicatesystems/authority": "^0.3.2" + "@predicatesystems/authority": "^0.3.3" }, "devDependencies": { "@types/node": "^25.3.0",