provenance-protocol 0.1.2 → 0.1.4

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 CHANGED
@@ -21,9 +21,10 @@ const trust = await provenance.check('provenance:github:alice/research-assistant
21
21
  console.log(trust);
22
22
  // {
23
23
  // found: true,
24
+ // identity: 'verified', // 'inferred' | 'declared' | 'verified'
25
+ // identity_verified: true,
24
26
  // declared: true,
25
27
  // age_days: 142,
26
- // confidence: 0.9,
27
28
  // capabilities: ['read:web', 'write:summaries'],
28
29
  // constraints: ['no:financial:transact', 'no:pii'],
29
30
  // incidents: 0,
@@ -39,11 +40,11 @@ The most useful method for receiving systems.
39
40
 
40
41
  ```js
41
42
  const result = await provenance.gate('provenance:github:alice/agent', {
42
- requireDeclared: true, // must have PROVENANCE.yml
43
+ requireDeclared: true, // must have PROVENANCE.yml
44
+ requireVerified: true, // must have identity_verified: true
43
45
  requireConstraints: ['no:financial:transact', 'no:pii'], // must have committed to these
44
- requireClean: true, // no open incidents
45
- requireMinAge: 30, // must be at least 30 days old
46
- requireMinConfidence: 0.7, // classification confidence
46
+ requireClean: true, // no open incidents
47
+ requireMinAge: 30, // must be at least 30 days old
47
48
  });
48
49
 
49
50
  if (!result.allowed) {
@@ -119,35 +120,42 @@ if (result.fallback) {
119
120
  | Field | Type | Description |
120
121
  |---|---|---|
121
122
  | `found` | boolean | Agent exists in Provenance index |
122
- | `declared` | boolean | Has a PROVENANCE.yml file |
123
+ | `identity` | string | `'inferred'` \| `'declared'` \| `'verified'` — see below |
124
+ | `identity_verified` | boolean | Cryptographic key ownership confirmed against a public URL |
125
+ | `declared` | boolean | Agent has a PROVENANCE.yml (or registered via API with full fields) |
123
126
  | `age_days` | number | Days since first indexed |
124
- | `confidence` | number | 0–1 classification confidence |
125
127
  | `capabilities` | string[] | What the agent declares it can do |
126
128
  | `constraints` | string[] | What the agent has publicly committed never to do |
127
129
  | `incidents` | number | Number of open incidents |
128
- | `status` | string | active / suspended / removed |
130
+ | `status` | string | `active` / `suspended` / `removed` |
129
131
  | `model` | object | `{ provider, model_id }` if declared |
130
132
  | `public_key` | string\|null | Base64 Ed25519 public key, if registered |
131
- | `identity_verified` | boolean | Cryptographic proof of key ownership confirmed |
132
133
  | `ajp_endpoint` | string\|null | AJP job endpoint URL, if the agent accepts delegated jobs |
133
134
  | `first_seen` | string | ISO date of first public appearance |
134
135
 
136
+ ### Identity states
137
+
138
+ | State | Meaning |
139
+ |---|---|
140
+ | `inferred` | Indexed by crawler from a public repo. No PROVENANCE.yml, no self-registration. |
141
+ | `declared` | Agent registered itself (or has PROVENANCE.yml) but without cryptographic key verification. |
142
+ | `verified` | Agent registered with a keypair and the public key was confirmed against a publicly fetchable PROVENANCE.yml. **Independently auditable** — anyone can re-verify without trusting the Provenance registry. |
143
+
135
144
  ---
136
145
 
137
146
  ## Registering your own agent
138
147
 
139
- ```js
140
- import { Provenance } from 'provenance-protocol';
141
- import { generateProvenanceKeyPair, signChallenge } from 'provenance-protocol/keygen';
148
+ ### Public repo (GitHub / HuggingFace / npm)
142
149
 
143
- const provenance = new Provenance();
150
+ Push a `PROVENANCE.yml` containing your public key to the repo, then register. The server fetches the file and confirms the key — independently verifiable by anyone.
144
151
 
145
- // One-time: generate a keypair
146
- const { publicKey, privateKey } = generateProvenanceKeyPair();
147
- // Store privateKey as PROVENANCE_PRIVATE_KEY env var — never commit it
152
+ ```js
153
+ import { generateProvenanceKeyPair, signForProvenance, signChallenge } from 'provenance-protocol/keygen';
148
154
 
149
- // Sign proof of key ownership for registration
155
+ const { publicKey, privateKey } = generateProvenanceKeyPair();
150
156
  const provenanceId = 'provenance:github:your-org/your-agent';
157
+
158
+ // Add to PROVENANCE.yml → commit → push, then:
151
159
  const signed_challenge = signChallenge(privateKey, provenanceId, 'REGISTER');
152
160
 
153
161
  await provenance.register({
@@ -158,11 +166,34 @@ await provenance.register({
158
166
  capabilities: ['read:web', 'write:summaries'],
159
167
  constraints: ['no:pii'],
160
168
  public_key: publicKey,
161
- signed_challenge, // proves you control the private key
169
+ signed_challenge,
162
170
  });
163
- // → { created: true, identity_verified: true, confidence: 1.0 }
171
+ // → { created: true, agent: { identity: 'verified', identity_verified: true } }
164
172
  ```
165
173
 
174
+ ### Private agent (no public repo)
175
+
176
+ Use `provenance:custom:` platform. Host your `PROVENANCE.yml` at any public URL you control and pass it as `url` — this makes the identity independently verifiable. Without a `url`, verification is registry-dependent (key control only).
177
+
178
+ ```js
179
+ const provenanceId = 'provenance:custom:your-org/your-agent';
180
+ const signed_challenge = signChallenge(privateKey, provenanceId, 'REGISTER');
181
+
182
+ await provenance.register({
183
+ id: provenanceId,
184
+ url: 'https://yourdomain.com/.well-known/provenance.yml', // optional but recommended
185
+ name: 'Your Agent',
186
+ description: 'What it does',
187
+ capabilities: ['read:web'],
188
+ constraints: ['no:pii'],
189
+ public_key: publicKey,
190
+ signed_challenge,
191
+ });
192
+ // → { created: true, agent: { identity: 'verified', identity_verified: true } }
193
+ ```
194
+
195
+ See [getprovenance.dev/docs#ai-quickstart](https://getprovenance.dev/docs#ai-quickstart) for full automated scripts.
196
+
166
197
  ## Revoking a compromised key
167
198
 
168
199
  ```js
package/package.json CHANGED
@@ -1,19 +1,29 @@
1
1
  {
2
2
  "name": "provenance-protocol",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "SDK for querying the Provenance agent identity index",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "types": "./src/index.d.ts",
8
+ "bin": {
9
+ "provenance": "./src/cli.js"
10
+ },
8
11
  "exports": {
9
12
  ".": {
10
13
  "types": "./src/index.d.ts",
11
14
  "import": "./src/index.js"
15
+ },
16
+ "./keygen": {
17
+ "types": "./src/keygen.d.ts",
18
+ "import": "./src/keygen.js"
12
19
  }
13
20
  },
14
21
  "files": [
15
22
  "src/index.js",
16
23
  "src/index.d.ts",
24
+ "src/keygen.js",
25
+ "src/keygen.d.ts",
26
+ "src/cli.js",
17
27
  "README.md"
18
28
  ],
19
29
  "keywords": [
package/src/cli.js ADDED
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * provenance CLI
4
+ *
5
+ * npx provenance keygen
6
+ * npx provenance register --id provenance:github:org/agent --url https://...
7
+ * npx provenance status provenance:github:org/agent
8
+ * npx provenance revoke --id provenance:github:org/agent
9
+ */
10
+
11
+ import { writeFileSync, readFileSync, existsSync } from 'fs';
12
+ import { execSync } from 'child_process';
13
+ import { generateProvenanceKeyPair, signChallenge, signForProvenance, signRevocation } from './keygen.js';
14
+
15
+ const API = 'https://getprovenance.dev/api/agents';
16
+ const KEY_FILE = '.provenance-key';
17
+
18
+ function readPrivateKey() {
19
+ if (process.env.PROVENANCE_PRIVATE_KEY) return process.env.PROVENANCE_PRIVATE_KEY.trim();
20
+ if (existsSync(KEY_FILE)) return readFileSync(KEY_FILE, 'utf8').trim();
21
+ console.error(`No private key found. Set PROVENANCE_PRIVATE_KEY or run: npx provenance keygen`);
22
+ process.exit(1);
23
+ }
24
+
25
+ function parseArgs(argv) {
26
+ const args = {};
27
+ for (let i = 0; i < argv.length; i++) {
28
+ if (argv[i].startsWith('--')) {
29
+ args[argv[i].slice(2)] = argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : true;
30
+ } else {
31
+ args._ = args._ || [];
32
+ args._.push(argv[i]);
33
+ }
34
+ }
35
+ return args;
36
+ }
37
+
38
+ const [,, command, ...rest] = process.argv;
39
+ const args = parseArgs(rest);
40
+
41
+ // ── keygen ──────────────────────────────────────────────────────────────────
42
+
43
+ if (command === 'keygen') {
44
+ const { publicKey, privateKey } = generateProvenanceKeyPair();
45
+
46
+ writeFileSync(KEY_FILE, privateKey, { mode: 0o600 });
47
+ try { execSync(`grep -qxF "${KEY_FILE}" .gitignore 2>/dev/null || echo "${KEY_FILE}" >> .gitignore`); } catch {}
48
+
49
+ console.log(`\nKeypair generated.\n`);
50
+ console.log(`Private key → ${KEY_FILE} (chmod 600, added to .gitignore)`);
51
+ console.log(`\nPublic key (add to PROVENANCE.yml):\n`);
52
+ console.log(` identity:`);
53
+ console.log(` public_key: "${publicKey}"`);
54
+ console.log(` algorithm: ed25519`);
55
+ console.log(`\nNext: npx provenance register --id provenance:<platform>:<org>/<name>\n`);
56
+ process.exit(0);
57
+ }
58
+
59
+ // ── register ─────────────────────────────────────────────────────────────────
60
+
61
+ if (command === 'register') {
62
+ const id = args.id || args._?.[0];
63
+ if (!id) { console.error('Usage: npx provenance register --id provenance:<platform>:<org>/<name> [options]'); process.exit(1); }
64
+
65
+ const privateKey = readPrivateKey();
66
+ const { publicKey } = (() => {
67
+ // derive public key from private key for display — we just use the stored one
68
+ // We can't derive public from private easily here, so read from PROVENANCE.yml or require --public-key
69
+ return { publicKey: args['public-key'] || null };
70
+ })();
71
+
72
+ // If no public key arg, re-generate won't work — need the stored public key
73
+ // Best path: require keygen was run, read public key from PROVENANCE.yml if present
74
+ let pubKey = args['public-key'];
75
+ if (!pubKey) {
76
+ if (existsSync('PROVENANCE.yml')) {
77
+ const yml = readFileSync('PROVENANCE.yml', 'utf8');
78
+ const match = yml.match(/public_key:\s*["']?([A-Za-z0-9+/=]+)["']?/);
79
+ if (match) pubKey = match[1];
80
+ }
81
+ }
82
+ if (!pubKey) {
83
+ console.error('Public key required. Pass --public-key or add identity.public_key to PROVENANCE.yml first.');
84
+ process.exit(1);
85
+ }
86
+
87
+ const signed_challenge = signChallenge(privateKey, id, 'REGISTER');
88
+
89
+ const body = {
90
+ provenance_id: id,
91
+ public_key: pubKey,
92
+ signed_challenge,
93
+ ...(args.url ? { url: args.url } : {}),
94
+ ...(args.name ? { name: args.name } : {}),
95
+ ...(args.description ? { description: args.description } : {}),
96
+ ...(args.capabilities ? { capabilities: args.capabilities.split(',').map(s => s.trim()) } : {}),
97
+ ...(args.constraints ? { constraints: args.constraints.split(',').map(s => s.trim()) } : {}),
98
+ ...(args.model ? { model_provider: args.model } : {}),
99
+ ...(args['model-id'] ? { model_id: args['model-id'] } : {}),
100
+ };
101
+
102
+ try {
103
+ const res = await fetch(`${API}/register`, {
104
+ method: 'POST',
105
+ headers: { 'Content-Type': 'application/json' },
106
+ body: JSON.stringify(body),
107
+ });
108
+ const data = await res.json();
109
+ if (!res.ok) {
110
+ console.error(`\nRegistration failed: ${data.error}`);
111
+ if (data.hint) console.error(`Hint: ${data.hint}`);
112
+ process.exit(1);
113
+ }
114
+ console.log(`\n${data.created ? 'Registered' : 'Updated'}: ${id}`);
115
+ console.log(`identity: ${data.agent?.identity}`);
116
+ console.log(`profile: https://getprovenance.dev/agent/${id.replace('provenance:', '').replace(':', '/')}\n`);
117
+ } catch (e) {
118
+ console.error('Network error:', e.message);
119
+ process.exit(1);
120
+ }
121
+ process.exit(0);
122
+ }
123
+
124
+ // ── status ───────────────────────────────────────────────────────────────────
125
+
126
+ if (command === 'status') {
127
+ const id = args._?.[0] || args.id;
128
+ if (!id) { console.error('Usage: npx provenance status <provenance_id>'); process.exit(1); }
129
+
130
+ try {
131
+ const res = await fetch(`${API}/register?provenance_id=${encodeURIComponent(id)}`);
132
+ const data = await res.json();
133
+ if (!data.registered) { console.log(`\nNot registered: ${id}\n`); process.exit(0); }
134
+ const a = data.agent;
135
+ console.log(`\n${id}`);
136
+ console.log(`name: ${a.name || '—'}`);
137
+ console.log(`identity: ${a.identity}`);
138
+ console.log(`status: ${a.status}`);
139
+ console.log(`profile: https://getprovenance.dev/agent/${id.replace('provenance:', '').replace(':', '/')}\n`);
140
+ } catch (e) {
141
+ console.error('Network error:', e.message);
142
+ process.exit(1);
143
+ }
144
+ process.exit(0);
145
+ }
146
+
147
+ // ── revoke ───────────────────────────────────────────────────────────────────
148
+
149
+ if (command === 'revoke') {
150
+ const id = args.id || args._?.[0];
151
+ if (!id) { console.error('Usage: npx provenance revoke --id <provenance_id>'); process.exit(1); }
152
+
153
+ const privateKey = readPrivateKey();
154
+ const signed_challenge = signRevocation(privateKey, id);
155
+
156
+ try {
157
+ const res = await fetch(`${API}/revoke`, {
158
+ method: 'POST',
159
+ headers: { 'Content-Type': 'application/json' },
160
+ body: JSON.stringify({ provenance_id: id, signed_challenge }),
161
+ });
162
+ const data = await res.json();
163
+ if (!res.ok) { console.error(`Revocation failed: ${data.error}`); process.exit(1); }
164
+ console.log(`\nKey revoked for ${id}.`);
165
+ console.log(`Run npx provenance keygen && npx provenance register --id ${id} to re-register with a new key.\n`);
166
+ } catch (e) {
167
+ console.error('Network error:', e.message);
168
+ process.exit(1);
169
+ }
170
+ process.exit(0);
171
+ }
172
+
173
+ // ── help ─────────────────────────────────────────────────────────────────────
174
+
175
+ console.log(`
176
+ provenance <command>
177
+
178
+ keygen Generate an Ed25519 keypair
179
+ register --id <id> [options] Register or update your agent
180
+ status <id> Check registration status
181
+ revoke --id <id> Revoke your registered key
182
+
183
+ register options:
184
+ --id provenance:<platform>:<org>/<name> (required)
185
+ --url URL to your PROVENANCE.yml (for independent verification)
186
+ --name Agent display name
187
+ --description One-sentence description
188
+ --capabilities read:web,write:summaries
189
+ --constraints no:pii,no:financial:transact
190
+ --model anthropic / openai / etc.
191
+ --model-id claude-sonnet-4-6 / gpt-4o / etc.
192
+ --public-key Base64 public key (auto-read from PROVENANCE.yml if present)
193
+
194
+ Full docs: https://getprovenance.dev/docs
195
+ `);
196
+ process.exit(0);
@@ -0,0 +1,48 @@
1
+ /**
2
+ * provenance-protocol — Key generation and signing utilities (TypeScript definitions)
3
+ * Node.js only. Not for browser use.
4
+ */
5
+
6
+ export interface KeyPair {
7
+ /** Base64-encoded SPKI DER public key. Put this in PROVENANCE.yml identity.public_key */
8
+ publicKey: string;
9
+ /** Base64-encoded PKCS8 DER private key. Store as PROVENANCE_PRIVATE_KEY env var. Never commit. */
10
+ privateKey: string;
11
+ }
12
+
13
+ /**
14
+ * Generate a new Ed25519 keypair for Provenance identity.
15
+ * Run once during agent setup.
16
+ */
17
+ export function generateProvenanceKeyPair(): KeyPair;
18
+
19
+ /**
20
+ * Sign a challenge nonce from a receiving system.
21
+ * Returns a base64-encoded signature over `${provenanceId}:${nonce}`.
22
+ *
23
+ * @param privateKeyBase64 Your PROVENANCE_PRIVATE_KEY (base64 PKCS8 DER)
24
+ * @param provenanceId Your agent's Provenance ID
25
+ * @param nonce The nonce sent by the receiving system
26
+ */
27
+ export function signChallenge(privateKeyBase64: string, provenanceId: string, nonce: string): string;
28
+
29
+ /**
30
+ * Sign your PROVENANCE.yml identity claim.
31
+ *
32
+ * Produces the `identity.signature` value for PROVENANCE.yml.
33
+ * Signs `${provenanceId}:${publicKeyBase64}` — binding the keypair to your specific agent ID.
34
+ * Run once during setup, after generateProvenanceKeyPair().
35
+ *
36
+ * @param privateKeyBase64 Your PROVENANCE_PRIVATE_KEY (base64 PKCS8 DER)
37
+ * @param provenanceId Your agent's Provenance ID
38
+ * @param publicKeyBase64 The public key you generated (base64 SPKI DER)
39
+ * @returns Base64 signature — put in PROVENANCE.yml identity.signature
40
+ */
41
+ export function signForProvenance(privateKeyBase64: string, provenanceId: string, publicKeyBase64: string): string;
42
+
43
+ /**
44
+ * Sign a revocation request — clears your agent's public key and identity_verified status.
45
+ * Use when your private key is compromised or you're rotating keys.
46
+ * Send the result as signed_challenge to POST /api/agents/revoke.
47
+ */
48
+ export function signRevocation(privateKeyBase64: string, provenanceId: string): string;
package/src/keygen.js ADDED
@@ -0,0 +1,142 @@
1
+ /**
2
+ * provenance-protocol — Key generation and signing utilities
3
+ *
4
+ * Agent operators use this to:
5
+ * 1. Generate an Ed25519 keypair once (setup)
6
+ * 2. Put the public key in PROVENANCE.yml under identity.public_key
7
+ * 3. Keep the private key in their environment (never committed, never shared)
8
+ * 4. Sign challenges from receiving systems at runtime
9
+ *
10
+ * Usage (one-time setup):
11
+ * import { generateProvenanceKeyPair } from 'provenance-protocol/keygen';
12
+ * const { publicKey, privateKey } = generateProvenanceKeyPair();
13
+ * // Add publicKey to your PROVENANCE.yml:
14
+ * // identity:
15
+ * // public_key: "<publicKey>"
16
+ * // Store privateKey as an environment variable: PROVENANCE_PRIVATE_KEY=<privateKey>
17
+ *
18
+ * Usage (runtime — signing challenges):
19
+ * import { signChallenge } from 'provenance-protocol/keygen';
20
+ * const signature = signChallenge(process.env.PROVENANCE_PRIVATE_KEY, provenanceId, nonce);
21
+ * // Return signature to the receiving system
22
+ *
23
+ * Note: This module uses Node.js built-in crypto. It is Node-only (not browser).
24
+ * The verification side (in index.js) uses Web Crypto and works everywhere.
25
+ */
26
+
27
+ import { generateKeyPairSync, sign, createPrivateKey } from 'crypto';
28
+
29
+ /**
30
+ * Generate a new Ed25519 keypair for use with Provenance identity.
31
+ *
32
+ * Run this once during agent setup. Add the public key to PROVENANCE.yml.
33
+ * Store the private key securely as an environment variable.
34
+ *
35
+ * @returns {{ publicKey: string, privateKey: string }}
36
+ * publicKey — base64-encoded SPKI DER. Goes in PROVENANCE.yml identity.public_key
37
+ * privateKey — base64-encoded PKCS8 DER. Store as PROVENANCE_PRIVATE_KEY env var
38
+ *
39
+ * Example:
40
+ * const { publicKey, privateKey } = generateProvenanceKeyPair();
41
+ * console.log('Add to PROVENANCE.yml:');
42
+ * console.log('identity:');
43
+ * console.log(` public_key: "${publicKey}"`);
44
+ * console.log('\nStore as environment variable:');
45
+ * console.log(`PROVENANCE_PRIVATE_KEY=${privateKey}`);
46
+ */
47
+ export function generateProvenanceKeyPair() {
48
+ const { publicKey, privateKey } = generateKeyPairSync('ed25519', {
49
+ publicKeyEncoding: { type: 'spki', format: 'der' },
50
+ privateKeyEncoding: { type: 'pkcs8', format: 'der' },
51
+ });
52
+
53
+ return {
54
+ publicKey: Buffer.from(publicKey).toString('base64'),
55
+ privateKey: Buffer.from(privateKey).toString('base64'),
56
+ };
57
+ }
58
+
59
+ /**
60
+ * Sign a challenge from a receiving system.
61
+ *
62
+ * Call this when a receiving system sends you a nonce to prove your identity.
63
+ * The signed message is always `${provenanceId}:${nonce}` — this binds the
64
+ * signature to your specific identity and prevents replay attacks.
65
+ *
66
+ * @param {string} privateKeyBase64 Your PROVENANCE_PRIVATE_KEY (base64 PKCS8 DER)
67
+ * @param {string} provenanceId Your provenance ID, e.g. "provenance:github:alice/agent"
68
+ * @param {string} nonce The nonce sent by the receiving system
69
+ * @returns {string} Base64-encoded signature to return to the receiver
70
+ *
71
+ * Example:
72
+ * app.post('/prove-identity', (req, res) => {
73
+ * const { provenanceId, nonce } = req.body;
74
+ * const signature = signChallenge(
75
+ * process.env.PROVENANCE_PRIVATE_KEY,
76
+ * provenanceId,
77
+ * nonce
78
+ * );
79
+ * res.json({ signature });
80
+ * });
81
+ */
82
+ export function signChallenge(privateKeyBase64, provenanceId, nonce) {
83
+ const keyBuffer = Buffer.from(privateKeyBase64, 'base64');
84
+ const privateKey = createPrivateKey({ key: keyBuffer, format: 'der', type: 'pkcs8' });
85
+ const message = Buffer.from(`${provenanceId}:${nonce}`, 'utf8');
86
+ return sign(null, message, privateKey).toString('base64');
87
+ }
88
+
89
+ /**
90
+ * Sign your PROVENANCE.yml identity claim.
91
+ *
92
+ * Call this once after generating your keypair to produce the `identity.signature`
93
+ * value that goes into PROVENANCE.yml. The signature proves you control the private
94
+ * key that matches the public key in the file.
95
+ *
96
+ * The signed message is `${provenanceId}:${publicKeyBase64}` — this binds the key
97
+ * pair to your specific Provenance ID, preventing key reuse across identities.
98
+ *
99
+ * @param {string} privateKeyBase64 Your PROVENANCE_PRIVATE_KEY (base64 PKCS8 DER)
100
+ * @param {string} provenanceId Your agent's Provenance ID, e.g. "provenance:github:alice/agent"
101
+ * @param {string} publicKeyBase64 The public key you're registering (base64 SPKI DER)
102
+ * @returns {string} Base64-encoded signature — put this in identity.signature
103
+ *
104
+ * Example (one-time setup):
105
+ * import { generateProvenanceKeyPair, signForProvenance } from 'provenance-protocol/keygen';
106
+ * const { publicKey, privateKey } = generateProvenanceKeyPair();
107
+ * const id = 'provenance:github:your-org/your-agent';
108
+ * const signature = signForProvenance(privateKey, id, publicKey);
109
+ * console.log('Add to PROVENANCE.yml:');
110
+ * console.log('identity:');
111
+ * console.log(` public_key: "${publicKey}"`);
112
+ * console.log(` signature: "${signature}"`);
113
+ */
114
+ /**
115
+ * Sign a revocation request.
116
+ *
117
+ * Call this when you want to revoke your agent's cryptographic identity —
118
+ * e.g. if your private key was compromised or you're rotating keys.
119
+ *
120
+ * @param {string} privateKeyBase64 Your current PROVENANCE_PRIVATE_KEY
121
+ * @param {string} provenanceId Your agent's Provenance ID
122
+ * @returns {string} Base64 signature — send as signed_challenge to POST /api/agents/revoke
123
+ *
124
+ * Example:
125
+ * import { signRevocation } from 'provenance-protocol/keygen';
126
+ * const signed_challenge = signRevocation(process.env.PROVENANCE_PRIVATE_KEY, provenanceId);
127
+ * await fetch('https://getprovenance.dev/api/agents/revoke', {
128
+ * method: 'POST',
129
+ * headers: { 'Content-Type': 'application/json' },
130
+ * body: JSON.stringify({ provenance_id: provenanceId, signed_challenge }),
131
+ * });
132
+ */
133
+ export function signRevocation(privateKeyBase64, provenanceId) {
134
+ return signChallenge(privateKeyBase64, provenanceId, 'REVOKE');
135
+ }
136
+
137
+ export function signForProvenance(privateKeyBase64, provenanceId, publicKeyBase64) {
138
+ const keyBuffer = Buffer.from(privateKeyBase64, 'base64');
139
+ const privateKey = createPrivateKey({ key: keyBuffer, format: 'der', type: 'pkcs8' });
140
+ const message = Buffer.from(`${provenanceId}:${publicKeyBase64}`, 'utf8');
141
+ return sign(null, message, privateKey).toString('base64');
142
+ }