Initial commit: Elydora Open Source — self-hosted audit platform for AI agents

Full self-hosted port of the Elydora tamper-evident audit protocol:
- Hono API server with PostgreSQL, Redis, MinIO adapters
- Ed25519 signed operations, chain hashing, Merkle epoch rollups
- PBKDF2 password hashing, HMAC-SHA256 JWT, 5-role RBAC
- Next.js management console
- Node.js, Python, and Go SDKs
- Docker Compose for local deployment
- Helm chart for Kubernetes
- Comprehensive security hardening and audit fixes applied

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-02 13:41:42 -05:00
1 parent 15547a8c35
commit e390e68594
207 files changed
+32790 -63

No files matched your search

@@ -0,0 +1,19 @@
import type { ErrorCode } from '../types/enums.js';
/** Map of all Elydora error codes to default human-readable messages */
export const ERROR_CODES: Readonly<Record<ErrorCode, string>> = {
INVALID_SIGNATURE: 'The operation signature is invalid.',
UNKNOWN_AGENT: 'The specified agent does not exist.',
KEY_REVOKED: 'The signing key has been revoked.',
AGENT_FROZEN: 'The agent is frozen and cannot submit operations.',
TTL_EXPIRED: 'The operation TTL has expired.',
REPLAY_DETECTED: 'A duplicate nonce was detected (replay attack).',
PREV_HASH_MISMATCH: 'The previous chain hash does not match.',
PAYLOAD_TOO_LARGE: 'The operation payload exceeds the maximum allowed size.',
RATE_LIMITED: 'Too many requests. Please retry later.',
INTERNAL_ERROR: 'An internal server error occurred.',
UNAUTHORIZED: 'Authentication is required.',
FORBIDDEN: 'You do not have permission to perform this action.',
NOT_FOUND: 'The requested resource was not found.',
VALIDATION_ERROR: 'The request failed validation.',
} as const;
@@ -0,0 +1,13 @@
export { ERROR_CODES } from './errors.js';
export {
MAX_PAYLOAD_SIZE,
MAX_TTL_MS,
MIN_TTL_MS,
MAX_NONCE_LENGTH,
STARTER_MAX_AGENTS,
DEFAULT_RETENTION_DAYS,
DEFAULT_EPOCH_INTERVAL_MS,
MAX_QUERY_LIMIT,
DEFAULT_QUERY_LIMIT,
DEFAULT_JWT_TTL_SECONDS,
} from './limits.js';
@@ -0,0 +1,29 @@
/** Maximum payload size in bytes (256 KB) */
export const MAX_PAYLOAD_SIZE = 256 * 1024;
/** Maximum TTL in milliseconds (5 minutes) */
export const MAX_TTL_MS = 300_000;
/** Minimum TTL in milliseconds (1 second) */
export const MIN_TTL_MS = 1_000;
/** Maximum nonce length in characters */
export const MAX_NONCE_LENGTH = 64;
/** Maximum number of agents on the Starter plan */
export const STARTER_MAX_AGENTS = 10;
/** Default data retention period in days */
export const DEFAULT_RETENTION_DAYS = 30;
/** Default epoch interval in milliseconds (5 minutes) */
export const DEFAULT_EPOCH_INTERVAL_MS = 300_000;
/** Maximum number of results per query */
export const MAX_QUERY_LIMIT = 1000;
/** Default number of results per query */
export const DEFAULT_QUERY_LIMIT = 100;
/** Default JWT token lifetime in seconds (24 hours) */
export const DEFAULT_JWT_TTL_SECONDS = 86400;
+66
View File
@@ -0,0 +1,66 @@
export type {
AgentStatus,
KeyStatus,
ExportStatus,
AdminAction,
RbacRole,
ErrorCode,
EOR,
ECH,
EAR,
EER,
Agent,
AgentKey,
Operation,
Receipt,
Epoch,
AdminEvent,
Export,
Organization,
User,
RegisterAgentRequest,
RegisterAgentResponse,
GetAgentResponse,
ListAgentsResponse,
FreezeAgentRequest,
UnfreezeAgentRequest,
RevokeAgentRequest,
UpdateAgentRequest,
SubmitOperationRequest,
SubmitOperationResponse,
GetOperationResponse,
VerifyOperationResponse,
AuditQueryRequest,
AuditQueryResponse,
GetEpochResponse,
ListEpochsResponse,
CreateExportRequest,
CreateExportResponse,
GetExportResponse,
ListExportsResponse,
AuthRegisterRequest,
AuthRegisterResponse,
AuthLoginRequest,
AuthLoginResponse,
AuthMeResponse,
AuthRefreshResponse,
IssueTokenRequest,
IssueTokenResponse,
JWK,
JWKSResponse,
ErrorResponse,
} from './types/index.js';
export {
ERROR_CODES,
MAX_PAYLOAD_SIZE,
MAX_TTL_MS,
MIN_TTL_MS,
MAX_NONCE_LENGTH,
STARTER_MAX_AGENTS,
DEFAULT_RETENTION_DAYS,
DEFAULT_EPOCH_INTERVAL_MS,
MAX_QUERY_LIMIT,
DEFAULT_QUERY_LIMIT,
DEFAULT_JWT_TTL_SECONDS,
} from './constants/index.js';
+213
View File
@@ -0,0 +1,213 @@
import type { Agent, AgentKey, Epoch, Export, Operation, Organization, Receipt, User } from './entities.js';
import type { ErrorCode } from './enums.js';
import type { EAR, EOR } from './protocol.js';
// ---------------------------------------------------------------------------
// Agent endpoints
// ---------------------------------------------------------------------------
export interface RegisterAgentRequest {
readonly agent_id: string;
readonly display_name?: string;
readonly responsible_entity?: string;
readonly integration_type?: string;
readonly keys: ReadonlyArray<{
readonly kid: string;
readonly public_key: string;
readonly algorithm: 'ed25519';
}>;
}
export interface RegisterAgentResponse {
readonly agent: Agent;
readonly keys: AgentKey[];
}
export interface GetAgentResponse {
readonly agent: Agent;
readonly keys: AgentKey[];
}
export interface ListAgentsResponse {
readonly agents: Agent[];
}
export interface FreezeAgentRequest {
readonly reason: string;
}
export interface UnfreezeAgentRequest {
readonly reason: string;
}
export interface RevokeAgentRequest {
readonly kid: string;
readonly reason: string;
}
export interface UpdateAgentRequest {
readonly integration_type: string;
}
// ---------------------------------------------------------------------------
// Operation endpoints
// ---------------------------------------------------------------------------
export type SubmitOperationRequest = EOR;
export interface SubmitOperationResponse {
readonly receipt: EAR;
}
export interface GetOperationResponse {
readonly operation: Operation;
readonly receipt?: Receipt;
readonly payload?: Record<string, unknown>;
}
export interface VerifyOperationResponse {
readonly valid: boolean;
readonly checks: {
readonly signature: boolean;
readonly chain: boolean;
readonly receipt: boolean;
readonly merkle?: boolean;
};
readonly errors?: string[];
}
// ---------------------------------------------------------------------------
// Audit query endpoints
// ---------------------------------------------------------------------------
export interface AuditQueryRequest {
readonly org_id?: string;
readonly agent_id?: string;
readonly operation_type?: string;
readonly start_time?: number;
readonly end_time?: number;
readonly cursor?: string;
readonly limit?: number;
}
export interface AuditQueryResponse {
readonly operations: Operation[];
readonly cursor?: string;
readonly total_count: number;
}
// ---------------------------------------------------------------------------
// Epoch endpoints
// ---------------------------------------------------------------------------
export interface GetEpochResponse {
readonly epoch: Epoch;
readonly anchor?: {
readonly tsa_token?: string;
readonly tsa_url?: string;
readonly anchored_at?: number;
};
}
export interface ListEpochsResponse {
readonly epochs: Epoch[];
}
// ---------------------------------------------------------------------------
// Export endpoints
// ---------------------------------------------------------------------------
export interface CreateExportRequest {
readonly start_time: number;
readonly end_time: number;
readonly agent_id?: string;
readonly operation_type?: string;
readonly format: 'json' | 'pdf';
}
export interface CreateExportResponse {
readonly export: Export;
}
export interface GetExportResponse {
readonly export: Export;
readonly download_url?: string;
}
export interface ListExportsResponse {
readonly exports: Export[];
}
// ---------------------------------------------------------------------------
// JWKS endpoint
// ---------------------------------------------------------------------------
export interface JWK {
readonly kty: string;
readonly crv?: string;
readonly x?: string;
readonly kid: string;
readonly use: string;
readonly alg: string;
}
export interface JWKSResponse {
readonly keys: JWK[];
}
// ---------------------------------------------------------------------------
// Auth endpoints
// ---------------------------------------------------------------------------
export interface AuthRegisterRequest {
readonly email: string;
readonly password: string;
readonly display_name?: string;
readonly org_name?: string;
}
export interface AuthRegisterResponse {
readonly user: User;
readonly organization: Organization;
readonly token: string;
}
export interface AuthLoginRequest {
readonly email: string;
readonly password: string;
}
export interface AuthLoginResponse {
readonly user: User;
readonly token: string;
}
export interface AuthMeResponse {
readonly user: User;
}
export interface AuthRefreshResponse {
readonly token: string;
}
export interface IssueTokenRequest {
readonly ttl_seconds?: number | null; // null = never expire
}
export interface IssueTokenResponse {
readonly token: string;
readonly expires_at: number | null; // null = never expire
}
// ---------------------------------------------------------------------------
// Error response
// ---------------------------------------------------------------------------
export interface ErrorResponse {
readonly error: {
readonly code: ErrorCode;
readonly message: string;
readonly request_id: string;
readonly details?: Record<string, unknown>;
};
}
@@ -0,0 +1,109 @@
import type { AgentStatus, ExportStatus, KeyStatus, RbacRole } from './enums.js';
/** Registered AI agent within an organization */
export interface Agent {
readonly agent_id: string;
readonly org_id: string;
readonly display_name: string;
readonly responsible_entity: string;
readonly integration_type: string;
readonly status: AgentStatus;
readonly created_at: number;
readonly updated_at: number;
}
/** Public key associated with an agent for signing operations */
export interface AgentKey {
readonly kid: string;
readonly agent_id: string;
/** Base64-encoded public key (stored as BLOB in D1) */
readonly public_key: string;
readonly algorithm: 'ed25519';
readonly status: KeyStatus;
readonly created_at: number;
readonly retired_at: number | null;
}
/** Persisted operation record in D1 */
export interface Operation {
readonly operation_id: string;
readonly org_id: string;
readonly agent_id: string;
readonly seq_no: number;
readonly operation_type: string;
readonly issued_at: number;
readonly ttl_ms: number;
readonly nonce: string;
readonly subject: string;
readonly action: string;
readonly payload_hash: string;
readonly prev_chain_hash: string;
readonly chain_hash: string;
readonly agent_pubkey_kid: string;
readonly signature: string;
readonly r2_payload_key: string | null;
readonly created_at: number;
}
/** Receipt stored in R2, referenced from D1 */
export interface Receipt {
readonly receipt_id: string;
readonly operation_id: string;
readonly r2_receipt_key: string;
readonly created_at: number;
}
/** Periodic Merkle epoch rollup record */
export interface Epoch {
readonly epoch_id: string;
readonly org_id: string;
readonly start_time: number;
readonly end_time: number;
readonly root_hash: string;
readonly leaf_count: number;
readonly r2_epoch_key: string;
readonly created_at: number;
}
/** Admin audit event log entry */
export interface AdminEvent {
readonly event_id: string;
readonly org_id: string;
readonly actor: string;
readonly action: string;
readonly target_type: string;
readonly target_id: string;
readonly details: string | null;
readonly created_at: number;
}
/** Organization */
export interface Organization {
readonly org_id: string;
readonly name: string;
readonly created_at: number;
readonly updated_at: number;
}
/** Console user within an organization */
export interface User {
readonly user_id: string;
readonly org_id: string;
readonly email: string;
readonly display_name: string;
readonly role: RbacRole;
readonly status: 'active' | 'suspended';
readonly created_at: number;
readonly updated_at: number;
}
/** Compliance export job */
export interface Export {
readonly export_id: string;
readonly org_id: string;
readonly status: ExportStatus;
readonly query_params: string;
readonly r2_export_key: string | null;
readonly created_at: number;
readonly completed_at: number | null;
}
+44
View File
@@ -0,0 +1,44 @@
/** Agent lifecycle status */
export type AgentStatus = 'active' | 'frozen' | 'revoked';
/** Agent key lifecycle status */
export type KeyStatus = 'active' | 'retired' | 'revoked';
/** Export job status */
export type ExportStatus = 'queued' | 'running' | 'done' | 'failed';
/** Administrative action types for audit logging */
export type AdminAction =
| 'agent.register'
| 'agent.update'
| 'agent.freeze'
| 'agent.unfreeze'
| 'agent.revoke'
| 'agent.delete'
| 'key.revoke'
| 'export.create';
/** RBAC roles for console access */
export type RbacRole =
| 'org_owner'
| 'security_admin'
| 'compliance_auditor'
| 'readonly_investigator'
| 'integration_engineer';
/** Error codes returned by the API */
export type ErrorCode =
| 'INVALID_SIGNATURE'
| 'UNKNOWN_AGENT'
| 'KEY_REVOKED'
| 'AGENT_FROZEN'
| 'TTL_EXPIRED'
| 'REPLAY_DETECTED'
| 'PREV_HASH_MISMATCH'
| 'PAYLOAD_TOO_LARGE'
| 'RATE_LIMITED'
| 'INTERNAL_ERROR'
| 'UNAUTHORIZED'
| 'FORBIDDEN'
| 'NOT_FOUND'
| 'VALIDATION_ERROR';
+61
View File
@@ -0,0 +1,61 @@
export type {
AgentStatus,
KeyStatus,
ExportStatus,
AdminAction,
RbacRole,
ErrorCode,
} from './enums.js';
export type {
EOR,
ECH,
EAR,
EER,
} from './protocol.js';
export type {
Agent,
AgentKey,
Operation,
Receipt,
Epoch,
AdminEvent,
Export,
Organization,
User,
} from './entities.js';
export type {
RegisterAgentRequest,
RegisterAgentResponse,
GetAgentResponse,
ListAgentsResponse,
FreezeAgentRequest,
UnfreezeAgentRequest,
RevokeAgentRequest,
UpdateAgentRequest,
SubmitOperationRequest,
SubmitOperationResponse,
GetOperationResponse,
VerifyOperationResponse,
AuditQueryRequest,
AuditQueryResponse,
GetEpochResponse,
ListEpochsResponse,
CreateExportRequest,
CreateExportResponse,
GetExportResponse,
ListExportsResponse,
AuthRegisterRequest,
AuthRegisterResponse,
AuthLoginRequest,
AuthLoginResponse,
AuthMeResponse,
AuthRefreshResponse,
IssueTokenRequest,
IssueTokenResponse,
JWK,
JWKSResponse,
ErrorResponse,
} from './api.js';
@@ -0,0 +1,112 @@
/**
* Elydora Operation Record (EOR)
*
* The fundamental unit of auditable activity in the Elydora protocol.
* Signed by the agent's Ed25519 key and chained via prev_chain_hash.
*/
export interface EOR {
/** Protocol version, always "1.0" */
readonly op_version: '1.0';
/** Unique operation identifier (UUIDv7) */
readonly operation_id: string;
/** Organization identifier */
readonly org_id: string;
/** Agent that issued this operation */
readonly agent_id: string;
/** Timestamp when issued (Unix milliseconds) */
readonly issued_at: number;
/** Time-to-live in milliseconds */
readonly ttl_ms: number;
/** Replay-prevention nonce (base64url) */
readonly nonce: string;
/** Classification of the operation */
readonly operation_type: string;
/** Subject of the operation */
readonly subject: Record<string, unknown>;
/** Action performed */
readonly action: Record<string, unknown>;
/** Operation payload */
readonly payload: Record<string, unknown> | string | null;
/** SHA-256 hash of the payload (base64url) */
readonly payload_hash: string;
/** Hash of the previous operation in the agent's chain (base64url) */
readonly prev_chain_hash: string;
/** Key ID of the agent's signing key */
readonly agent_pubkey_kid: string;
/** Ed25519 signature over the canonical EOR (base64url) */
readonly signature: string;
}
/**
* Elydora Chain Hash (ECH)
*
* Represents the chain hash computation linking operations together.
*/
export interface ECH {
/** Previous chain hash (base64url) */
readonly prev_ech: string;
/** SHA-256 hash of the operation payload (base64url) */
readonly payload_hash: string;
/** Operation identifier (UUIDv7) */
readonly operation_id: string;
/** Timestamp when issued (Unix milliseconds) */
readonly issued_at: number;
/** Resulting chain hash (base64url) */
readonly chain_hash: string;
}
/**
* Elydora Acknowledgment Receipt (EAR)
*
* Server-issued receipt confirming acceptance of an operation.
*/
export interface EAR {
/** Receipt version */
readonly receipt_version: string;
/** Unique receipt identifier */
readonly receipt_id: string;
/** Operation this receipt acknowledges */
readonly operation_id: string;
/** Organization identifier */
readonly org_id: string;
/** Agent that submitted the operation */
readonly agent_id: string;
/** Timestamp when the server received the operation (Unix ms) */
readonly server_received_at: number;
/** Sequence number assigned to the operation */
readonly seq_no: number;
/** Chain hash at time of receipt */
readonly chain_hash: string;
/** Queue message ID for async processing */
readonly queue_message_id: string;
/** Hash of this receipt */
readonly receipt_hash: string;
/** Elydora server key ID used for signing */
readonly elydora_kid: string;
/** Elydora server signature over the receipt */
readonly elydora_signature: string;
}
/**
* Elydora Epoch Record (EER)
*
* Periodic Merkle-tree rollup anchoring operations to a root hash.
*/
export interface EER {
/** Unique epoch identifier */
readonly epoch_id: string;
/** Organization identifier */
readonly org_id: string;
/** Epoch start time (Unix ms) */
readonly start_time: number;
/** Epoch end time (Unix ms) */
readonly end_time: number;
/** Number of leaf operations in this epoch */
readonly leaf_count: number;
/** Merkle root hash */
readonly root_hash: string;
/** Hash algorithm used (e.g. "sha256") */
readonly hash_alg: string;
/** Elydora server signature over the epoch record */
readonly signature_by_elydora: string;
}