🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@open-agent-trust/cli

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@open-agent-trust/cli - npm Package Compare versions

Comparing version
1.0.6
to
1.0.7
+89
dist/commands/compile.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.compile = compile;
const promises_1 = require("fs/promises");
const path_1 = require("path");
const ed = __importStar(require("@noble/ed25519"));
async function compile(options) {
try {
console.log('Compiling registry manifest...');
const registryDir = (0, path_1.join)(process.cwd(), '../registry');
const issuersDir = (0, path_1.join)(registryDir, 'issuers');
const files = await (0, promises_1.readdir)(issuersDir);
const issuers = {};
for (const file of files) {
if (file.endsWith('.json')) {
const content = await (0, promises_1.readFile)((0, path_1.join)(issuersDir, file), 'utf8');
const parsed = JSON.parse(content);
issuers[parsed.issuer_id] = parsed;
}
}
const timestamp = new Date().toISOString();
const expires = new Date(Date.now() + 60 * 60 * 1000).toISOString(); // +1 hour
const manifest = {
version: "1.0",
generated_at: timestamp,
expires_at: expires,
total_issuers: Object.keys(issuers).length,
issuers: issuers,
signature: ""
};
const payloadToSign = JSON.stringify({
version: manifest.version,
generated_at: manifest.generated_at,
expires_at: manifest.expires_at,
total_issuers: manifest.total_issuers,
issuers: manifest.issuers
});
const privateKeyBuffer = Buffer.from(options.privateKey, 'base64url');
if (privateKeyBuffer.length !== 32) {
throw new Error("Invalid private key length. Must be 32 bytes (base64url encoded).");
}
// Use async signing to avoid needing the sync sha512 configuration
const signatureBytes = await ed.signAsync(Buffer.from(payloadToSign, 'utf8'), privateKeyBuffer);
const signatureStr = Buffer.from(signatureBytes).toString('base64url');
manifest.signature = `ed25519:${signatureStr}`;
const outputPath = (0, path_1.join)(registryDir, 'manifest.json');
await (0, promises_1.writeFile)(outputPath, JSON.stringify(manifest, null, 2));
console.log('✅ Success!');
console.log(`Signed Manifest saved to: ${outputPath}`);
console.log(`Total Issuers: ${manifest.total_issuers}`);
}
catch (error) {
console.error('❌ Failed to compile registry:', error.message);
process.exit(1);
}
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.issue = void 0;
const jose_1 = require("jose");
const promises_1 = require("fs/promises");
const path_1 = require("path");
const crypto_1 = require("crypto");
const issue = async (options) => {
try {
console.log('[1/3] Loading Ed25519 private key...');
const keyPath = (0, path_1.resolve)(process.cwd(), options.privateKey);
const privateKeyB64 = await (0, promises_1.readFile)(keyPath, 'utf-8');
const privateKeyBytes = Buffer.from(privateKeyB64.trim(), 'base64url');
const seedHex = privateKeyBytes.subarray(0, 32).toString('hex');
console.log('[2/3] Preparing agent-attestation+jwt payload...');
const now = Math.floor(Date.now() / 1000);
const payload = {
sub: 'agent-instance-' + crypto.randomUUID().slice(0, 8),
aud: options.audience,
iat: now,
nonce: crypto.randomUUID(),
scope: options.scope.split(',').map(s => s.trim()),
constraints: {
time_bound: true
},
user_pseudonym: 'pairwise-' + crypto.randomUUID().slice(0, 8),
runtime_version: '1.0.0'
};
console.log('[3/3] Signing EdDSA attestation token...');
// Wrap the raw 32-byte Ed25519 seed in a PKCS#8 DER ASN.1 structure
// 302e020100300506032b657004220420 is the standard ASN.1 prefix for Ed25519 private keys
const pkcs8Der = Buffer.from('302e020100300506032b657004220420' + seedHex, 'hex');
const privateKeyObj = (0, crypto_1.createPrivateKey)({
key: pkcs8Der,
format: 'der',
type: 'pkcs8'
});
const jwt = await new jose_1.SignJWT(payload)
.setProtectedHeader({
alg: 'EdDSA',
kid: options.kid,
iss: options.issuerId,
typ: 'agent-attestation+jwt'
})
.setExpirationTime(now + options.expiresIn)
.sign(privateKeyObj);
console.log('\n✓ Test Attestation Generated Successfully:');
console.log('--------------------------------------------------');
console.log(jwt);
console.log('--------------------------------------------------');
console.log(`\nTo test verification, copy the string above and run:\nagent-trust verify <TOKEN> --audience ${options.audience}`);
}
catch (err) {
if (err instanceof Error) {
console.error('\n❌ Failed to generate test attestation:', err.message);
}
else {
console.error('\n❌ An unexpected error occurred while generating the test attestation.');
}
process.exit(1);
}
};
exports.issue = issue;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.keygen = void 0;
const ed = __importStar(require("@noble/ed25519"));
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
// Polyfill for noble in raw node environments
if (!globalThis.crypto) {
globalThis.crypto = crypto.webcrypto;
}
const keygen = async (options) => {
try {
console.log(`\nGenerating Ed25519 keypair for issuer '${options.issuerId}'...\n`);
const privateKeyRaw = ed.utils.randomSecretKey();
const publicKeyRaw = await ed.getPublicKeyAsync(privateKeyRaw);
const privateKeyBase64Url = Buffer.from(privateKeyRaw).toString('base64url');
const publicKeyBase64Url = Buffer.from(publicKeyRaw).toString('base64url');
// Create the kid (Key ID) using a stable date prefix
const dateStr = new Date().toISOString().substring(0, 7); // e.g., 2026-03
const kid = `${options.issuerId}-${dateStr}`;
// Industry standard .pem extension with 'private' in filename for clarity
const privateKeyPath = path.join(options.outDir, `${options.issuerId}.private.pem`);
fs.writeFileSync(privateKeyPath, privateKeyBase64Url, { mode: 0o600 });
console.log(`✅ Keypair generated successfully!\n`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
console.log(` Private Key: ${privateKeyPath}`);
console.log(` KID: ${kid}`);
console.log(` Algorithm: Ed25519`);
console.log(` Public Key: ${publicKeyBase64Url}`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
console.log(`⚠️ Keep your private key secret. Never commit it to a repo.\n`);
console.log(` To view it: cat ${privateKeyPath}`);
console.log(` To secure it: chmod 600 ${privateKeyPath}\n`);
console.log(` Note: Do not double-click the .pem file. On macOS, this opens`);
console.log(` Keychain Access. Always use 'cat' or a text editor from the terminal.\n`);
console.log(`Next steps:\n`);
console.log(` 1. Add your public key to your agent.json for Tier 3 identity:\n`);
console.log(` "identity": {`);
console.log(` "did": "did:web:yourdomain.com",`);
console.log(` "public_key": "${publicKeyBase64Url}"`);
console.log(` }\n`);
console.log(` 2. Host a DID document at https://yourdomain.com/.well-known/did.json`);
console.log(` (See docs: https://agentinternetruntime.com/spec/agent-json#becoming-tier-3)\n`);
console.log(` 3. To register as a trusted runtime issuer in the Trust Registry:`);
console.log(` npx @open-agent-trust/cli register --issuer-id ${options.issuerId} \\`);
console.log(` --display-name "Your Display Name" --website https://yourdomain.com \\`);
console.log(` --contact security@yourdomain.com --public-key ${publicKeyBase64Url}\n`);
}
catch (err) {
console.error('Failed to generate keypair:', err);
process.exit(1);
}
};
exports.keygen = keygen;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.prove = void 0;
const promises_1 = require("fs/promises");
const path_1 = require("path");
const ed = __importStar(require("@noble/ed25519"));
const PROOF_VERSION = 'oatr-proof-v1';
const ISSUER_ID_PATTERN = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
const prove = async (options) => {
try {
// Validate issuer_id format
if (!ISSUER_ID_PATTERN.test(options.issuerId)) {
throw new Error(`Invalid issuer_id "${options.issuerId}". Must be lowercase alphanumeric and hyphens only, ` +
`no leading/trailing hyphens. Example: my-runtime`);
}
console.log('[1/3] Loading Ed25519 private key...');
const keyPath = (0, path_1.resolve)(process.cwd(), options.privateKey);
const privateKeyB64 = await (0, promises_1.readFile)(keyPath, 'utf-8');
const privateKeyBuffer = Buffer.from(privateKeyB64.trim(), 'base64url');
if (privateKeyBuffer.length !== 32) {
throw new Error(`Invalid private key length (${privateKeyBuffer.length} bytes). ` +
`Must be 32 bytes (base64url encoded). Ensure this is an Ed25519 seed from 'agent-trust keygen'.`);
}
console.log('[2/3] Signing proof-of-key-ownership...');
const canonicalMessage = `${PROOF_VERSION}:${options.issuerId}`;
const messageBytes = Buffer.from(canonicalMessage, 'utf8');
const signatureBytes = await ed.signAsync(messageBytes, privateKeyBuffer);
const signature = Buffer.from(signatureBytes).toString('base64url');
const proofContent = [
'-----BEGIN OATR KEY OWNERSHIP PROOF-----',
`Canonical-Message: ${canonicalMessage}`,
`Signature: ${signature}`,
'-----END OATR KEY OWNERSHIP PROOF-----',
'' // trailing newline for POSIX compliance
].join('\n');
console.log('[3/3] Writing proof file...');
const outPath = options.outFile
? (0, path_1.resolve)(process.cwd(), options.outFile)
: (0, path_1.join)(process.cwd(), 'registry', 'proofs', `${options.issuerId}.proof`);
await (0, promises_1.mkdir)((0, path_1.dirname)(outPath), { recursive: true });
await (0, promises_1.writeFile)(outPath, proofContent);
console.log(`\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
console.log(` ✅ Proof of Key Ownership Generated`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`);
console.log(` Issuer ID: ${options.issuerId}`);
console.log(` Proof file: ${outPath}`);
console.log(` Format: ${PROOF_VERSION}`);
console.log(`━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`);
console.log(`Next steps:\n`);
console.log(` 1. Ensure your issuer JSON is at registry/issuers/${options.issuerId}.json`);
console.log(` 2. Ensure your domain verification is live at:`);
console.log(` https://yourdomain.com/.well-known/agent-trust.json\n`);
console.log(` 3. Submit a Pull Request with both files:`);
console.log(` - registry/issuers/${options.issuerId}.json`);
console.log(` - registry/proofs/${options.issuerId}.proof\n`);
console.log(` The CI pipeline will verify your proof, check your domain,`);
console.log(` and auto-merge if all checks pass.\n`);
}
catch (error) {
console.error('❌ Failed to generate proof:', error.message);
process.exit(1);
}
};
exports.prove = prove;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.register = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const register = async (options) => {
const nowISO = new Date().toISOString();
// Hardcoded to standard generic capabilities for Phase 1 scaffolding.
// Real users would edit this draft JSON file.
let entry = {
"issuer_id": options.issuerId,
"display_name": options.displayName,
"website": options.website,
"security_contact": options.contact,
"status": "active",
"added_at": nowISO,
"last_verified": nowISO,
"public_keys": [
{
"kid": `${options.issuerId}-${nowISO.substring(0, 7)}`,
"algorithm": "Ed25519",
"public_key": options.publicKey,
"status": "active",
"issued_at": nowISO,
"expires_at": new Date(Date.now() + 31536000000).toISOString(), // +1 year
"deprecated_at": null,
"revoked_at": null
}
],
"capabilities": {
"supervision_model": "tiered",
"audit_logging": true,
"immutable_audit": false,
"attestation_format": "jwt",
"max_attestation_ttl_seconds": 3600,
"capabilities_verified": false
}
};
const outPath = options.outFile || path.join(process.cwd(), `${options.issuerId}.json`);
fs.writeFileSync(outPath, JSON.stringify(entry, null, 2));
console.log(`✅ Draft Issuer Entry generated at: ${outPath}`);
console.log(`\nPlease review the \"capabilities\" block to ensure it matches your runtime's exact profile.`);
console.log(`When ready, submit this file as a Pull Request to 'registry/issuers/' in the open source repository.`);
};
exports.register = register;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = void 0;
const registry_1 = require("@open-agent-trust/registry");
const verify = async (attestation, options) => {
try {
console.log(`[1/2] Fetching registry manifest from mirror (${options.mirror})...`);
const registry = await registry_1.OpenAgentTrustRegistry.load(options.mirror);
console.log(`[2/2] Attempting 14-step verification against audience bounds (${options.audience})...`);
const result = await registry.verifyToken(attestation, options.audience);
if (result.valid) {
console.log(`\n✅ Valid Attestation`);
console.log(`Issuer: ${result.issuer?.display_name} (${result.issuer?.issuer_id})`);
console.log(`Token Subject: ${result.claims?.sub}`);
console.log(`Authorized As: ${result.claims?.user_pseudonym}`);
console.log(`Expires: ${new Date(result.claims?.exp * 1000).toISOString()}`);
console.log(`Constraints: `, result.claims?.constraints);
process.exit(0);
}
else {
console.error(`\n❌ Token mathematically rejected by the Registry.`);
console.error(`Reason: ${result.reason}`);
if (result.issuer) {
console.error(`Identified Issuer: ${result.issuer.display_name}`);
}
process.exit(1);
}
}
catch (err) {
console.error(`\n❌ Verification engine failure: ${err.message}`);
process.exit(1);
}
};
exports.verify = verify;
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const commander_1 = require("commander");
const keygen_1 = require("./commands/keygen");
const register_1 = require("./commands/register");
const verify_1 = require("./commands/verify");
const issue_1 = require("./commands/issue");
const compile_1 = require("./commands/compile");
const prove_1 = require("./commands/prove");
const program = new commander_1.Command();
program
.name('agent-trust')
.description('Open Agent Trust Registry CLI Utilities')
.version('1.0.0');
program
.command('keygen')
.description('Generate a new Ed25519 keypair for your runtime')
.requiredOption('-i, --issuer-id <string>', 'Your globally unique issuer identifier')
.option('-o, --out-dir <path>', 'Directory to save the private key', './')
.action(keygen_1.keygen);
program
.command('register')
.description('Generate a compliant issuer_entry JSON file')
.requiredOption('-i, --issuer-id <string>', 'Your globally unique issuer identifier')
.requiredOption('-n, --display-name <string>', 'Human-readable name of the runtime')
.requiredOption('-w, --website <url>', 'Public resolving website of the operator')
.requiredOption('-c, --contact <email>', 'Security responsible contact email')
.requiredOption('-k, --public-key <base64url>', 'The base64url Ed25519 public key generated from keygen')
.option('-o, --out-file <path>', 'Output path for the generated JSON')
.action(register_1.register);
program
.command('verify')
.description('Verify an agent attestation JWS against the registry')
.argument('<attestation>', 'The raw JWT/JWS token string')
.requiredOption('-a, --audience <url>', 'The origin URL of the service expecting the token')
.option('-m, --mirror <url>', 'Custom registry mirror URL', 'http://localhost:3000')
.action(verify_1.verify);
program
.command('issue')
.description('Generate a signed test agent-attestation+jwt token (useful for local integration testing)')
.requiredOption('-i, --issuer-id <string>', 'Your globally unique issuer identifier')
.requiredOption('-k, --kid <string>', 'The key ID (kid) of the key used to sign')
.requiredOption('-p, --private-key <path>', 'Path to your .key file generated by keygen')
.requiredOption('-a, --audience <url>', 'The origin URL of the service expecting the token')
.option('-s, --scope <string>', 'Comma-separated list of scopes (e.g., read:email,send:email)', 'read:data')
.option('-e, --expires-in <seconds>', 'Expiration time in seconds', (val) => parseInt(val, 10), 3600)
.action(issue_1.issue);
program
.command('compile')
.description('Compiles and signs the final manifest.json from the registry folder')
.requiredOption('-p, --private-key <key>', 'Ed25519 private key to sign the manifest')
.action(compile_1.compile);
program
.command('prove')
.description('Generate a cryptographic proof-of-key-ownership for registry registration')
.requiredOption('-i, --issuer-id <string>', 'Your globally unique issuer identifier')
.requiredOption('-p, --private-key <path>', 'Path to your .private.pem key file')
.option('-o, --out-file <path>', 'Output path for the proof file')
.action(prove_1.prove);
program.parse(process.argv);
+4
-3
{
"name": "@open-agent-trust/cli",
"version": "1.0.6",
"version": "1.0.7",
"description": "CLI utilities for the Open Agent Trust Registry",

@@ -17,3 +17,4 @@ "license": "MIT",

"build": "tsc",
"start": "tsx src/index.ts"
"start": "tsx src/index.ts",
"prepublishOnly": "npm run build"
},

@@ -29,4 +30,4 @@ "dependencies": {

"tsx": "^4.19.3",
"typescript": "^5.7.3"
"typescript": "^5.9.3"
}
}