@blink-authority-com/claude-code-plugin 1.0.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.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/dist/bsec-client.d.ts +35 -0
- package/dist/bsec-client.d.ts.map +1 -0
- package/dist/bsec-client.js +122 -0
- package/dist/bsec-client.js.map +1 -0
- package/dist/docs/cache.d.ts +19 -0
- package/dist/docs/cache.d.ts.map +1 -0
- package/dist/docs/cache.js +92 -0
- package/dist/docs/cache.js.map +1 -0
- package/dist/docs/fetcher.d.ts +19 -0
- package/dist/docs/fetcher.d.ts.map +1 -0
- package/dist/docs/fetcher.js +81 -0
- package/dist/docs/fetcher.js.map +1 -0
- package/dist/docs/parser.d.ts +33 -0
- package/dist/docs/parser.d.ts.map +1 -0
- package/dist/docs/parser.js +145 -0
- package/dist/docs/parser.js.map +1 -0
- package/dist/docs/search.d.ts +38 -0
- package/dist/docs/search.d.ts.map +1 -0
- package/dist/docs/search.js +180 -0
- package/dist/docs/search.js.map +1 -0
- package/dist/docs/tools/api.d.ts +12 -0
- package/dist/docs/tools/api.d.ts.map +1 -0
- package/dist/docs/tools/api.js +58 -0
- package/dist/docs/tools/api.js.map +1 -0
- package/dist/docs/tools/cli.d.ts +12 -0
- package/dist/docs/tools/cli.d.ts.map +1 -0
- package/dist/docs/tools/cli.js +56 -0
- package/dist/docs/tools/cli.js.map +1 -0
- package/dist/docs/tools/concepts.d.ts +18 -0
- package/dist/docs/tools/concepts.d.ts.map +1 -0
- package/dist/docs/tools/concepts.js +136 -0
- package/dist/docs/tools/concepts.js.map +1 -0
- package/dist/docs/tools/sdk.d.ts +12 -0
- package/dist/docs/tools/sdk.d.ts.map +1 -0
- package/dist/docs/tools/sdk.js +72 -0
- package/dist/docs/tools/sdk.js.map +1 -0
- package/dist/docs/tools/search.d.ts +11 -0
- package/dist/docs/tools/search.d.ts.map +1 -0
- package/dist/docs/tools/search.js +36 -0
- package/dist/docs/tools/search.js.map +1 -0
- package/dist/docs/types.d.ts +70 -0
- package/dist/docs/types.d.ts.map +1 -0
- package/dist/docs/types.js +8 -0
- package/dist/docs/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +622 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/debug.d.ts +16 -0
- package/dist/prompts/debug.d.ts.map +1 -0
- package/dist/prompts/debug.js +34 -0
- package/dist/prompts/debug.js.map +1 -0
- package/dist/prompts/integrate.d.ts +16 -0
- package/dist/prompts/integrate.d.ts.map +1 -0
- package/dist/prompts/integrate.js +30 -0
- package/dist/prompts/integrate.js.map +1 -0
- package/dist/prompts/review.d.ts +16 -0
- package/dist/prompts/review.d.ts.map +1 -0
- package/dist/prompts/review.js +28 -0
- package/dist/prompts/review.js.map +1 -0
- package/dist/resources/changelog.d.ts +22 -0
- package/dist/resources/changelog.d.ts.map +1 -0
- package/dist/resources/changelog.js +55 -0
- package/dist/resources/changelog.js.map +1 -0
- package/dist/resources/errors.d.ts +16 -0
- package/dist/resources/errors.d.ts.map +1 -0
- package/dist/resources/errors.js +103 -0
- package/dist/resources/errors.js.map +1 -0
- package/dist/resources/patterns.d.ts +16 -0
- package/dist/resources/patterns.d.ts.map +1 -0
- package/dist/resources/patterns.js +151 -0
- package/dist/resources/patterns.js.map +1 -0
- package/dist/templates/approval-workflow.d.ts +6 -0
- package/dist/templates/approval-workflow.d.ts.map +1 -0
- package/dist/templates/approval-workflow.js +467 -0
- package/dist/templates/approval-workflow.js.map +1 -0
- package/dist/templates/audit-trail.d.ts +6 -0
- package/dist/templates/audit-trail.d.ts.map +1 -0
- package/dist/templates/audit-trail.js +396 -0
- package/dist/templates/audit-trail.js.map +1 -0
- package/dist/templates/cli-tool.d.ts +6 -0
- package/dist/templates/cli-tool.d.ts.map +1 -0
- package/dist/templates/cli-tool.js +346 -0
- package/dist/templates/cli-tool.js.map +1 -0
- package/dist/templates/express-api.d.ts +6 -0
- package/dist/templates/express-api.d.ts.map +1 -0
- package/dist/templates/express-api.js +314 -0
- package/dist/templates/express-api.js.map +1 -0
- package/dist/templates/notary.d.ts +6 -0
- package/dist/templates/notary.d.ts.map +1 -0
- package/dist/templates/notary.js +360 -0
- package/dist/templates/notary.js.map +1 -0
- package/dist/test.d.ts +8 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +140 -0
- package/dist/test.js.map +1 -0
- package/dist/tools/add-signing.d.ts +19 -0
- package/dist/tools/add-signing.d.ts.map +1 -0
- package/dist/tools/add-signing.js +317 -0
- package/dist/tools/add-signing.js.map +1 -0
- package/dist/tools/decode.d.ts +13 -0
- package/dist/tools/decode.d.ts.map +1 -0
- package/dist/tools/decode.js +262 -0
- package/dist/tools/decode.js.map +1 -0
- package/dist/tools/hierarchy.d.ts +13 -0
- package/dist/tools/hierarchy.d.ts.map +1 -0
- package/dist/tools/hierarchy.js +319 -0
- package/dist/tools/hierarchy.js.map +1 -0
- package/dist/tools/lint.d.ts +13 -0
- package/dist/tools/lint.d.ts.map +1 -0
- package/dist/tools/lint.js +323 -0
- package/dist/tools/lint.js.map +1 -0
- package/dist/tools/scaffold.d.ts +11 -0
- package/dist/tools/scaffold.d.ts.map +1 -0
- package/dist/tools/scaffold.js +84 -0
- package/dist/tools/scaffold.js.map +1 -0
- package/dist/tools/sign-test.d.ts +17 -0
- package/dist/tools/sign-test.d.ts.map +1 -0
- package/dist/tools/sign-test.js +126 -0
- package/dist/tools/sign-test.js.map +1 -0
- package/dist/tools/test-vectors.d.ts +13 -0
- package/dist/tools/test-vectors.d.ts.map +1 -0
- package/dist/tools/test-vectors.js +169 -0
- package/dist/tools/test-vectors.js.map +1 -0
- package/dist/tools/verify-local.d.ts +17 -0
- package/dist/tools/verify-local.d.ts.map +1 -0
- package/dist/tools/verify-local.js +233 -0
- package/dist/tools/verify-local.js.map +1 -0
- package/dist/tools/verify-test.d.ts +17 -0
- package/dist/tools/verify-test.d.ts.map +1 -0
- package/dist/tools/verify-test.js +107 -0
- package/dist/tools/verify-test.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit trail scaffold template.
|
|
3
|
+
* Generates a hash-chained audit log with BLINK signatures.
|
|
4
|
+
*/
|
|
5
|
+
export function generateAuditTrail(name, features) {
|
|
6
|
+
const files = {};
|
|
7
|
+
// --- package.json ---
|
|
8
|
+
files['package.json'] = JSON.stringify({
|
|
9
|
+
name,
|
|
10
|
+
version: '0.1.0',
|
|
11
|
+
description: `${name} — Hash-chained audit trail with BLINK Authority signatures`,
|
|
12
|
+
type: 'module',
|
|
13
|
+
scripts: {
|
|
14
|
+
build: 'tsc',
|
|
15
|
+
start: 'node dist/server.js',
|
|
16
|
+
dev: 'tsx src/server.ts',
|
|
17
|
+
},
|
|
18
|
+
dependencies: {
|
|
19
|
+
'@blink-technology/sdk': '^0.14.0',
|
|
20
|
+
express: '^4.21.0',
|
|
21
|
+
dotenv: '^16.4.0',
|
|
22
|
+
},
|
|
23
|
+
devDependencies: {
|
|
24
|
+
'@types/express': '^4.17.21',
|
|
25
|
+
'@types/node': '^22.15.2',
|
|
26
|
+
typescript: '^5.8.3',
|
|
27
|
+
tsx: '^4.19.0',
|
|
28
|
+
},
|
|
29
|
+
}, null, 2);
|
|
30
|
+
// --- tsconfig.json ---
|
|
31
|
+
files['tsconfig.json'] = JSON.stringify({
|
|
32
|
+
compilerOptions: {
|
|
33
|
+
target: 'ES2022',
|
|
34
|
+
module: 'Node16',
|
|
35
|
+
moduleResolution: 'Node16',
|
|
36
|
+
outDir: 'dist',
|
|
37
|
+
rootDir: 'src',
|
|
38
|
+
strict: true,
|
|
39
|
+
esModuleInterop: true,
|
|
40
|
+
skipLibCheck: true,
|
|
41
|
+
forceConsistentCasingInFileNames: true,
|
|
42
|
+
declaration: true,
|
|
43
|
+
sourceMap: true,
|
|
44
|
+
},
|
|
45
|
+
include: ['src/**/*'],
|
|
46
|
+
exclude: ['node_modules', 'dist'],
|
|
47
|
+
}, null, 2);
|
|
48
|
+
// --- .env.example ---
|
|
49
|
+
files['.env.example'] = `# BLINK Secure Engine connection
|
|
50
|
+
BSEC_URL=http://localhost:9100
|
|
51
|
+
BSEC_TOKEN=your-bsec-token-here
|
|
52
|
+
SLOT_NAME=default
|
|
53
|
+
|
|
54
|
+
# Server
|
|
55
|
+
PORT=3000
|
|
56
|
+
`;
|
|
57
|
+
// --- src/blink.ts ---
|
|
58
|
+
files['src/blink.ts'] = `/**
|
|
59
|
+
* BLINK Secure Engine connection management.
|
|
60
|
+
*
|
|
61
|
+
* BLINK Authority — https://blink-authority.com
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
import { BlinkSigner, BlinkVerifier, AlgoSuiteId } from '@blink-technology/sdk';
|
|
65
|
+
|
|
66
|
+
let signer: BlinkSigner;
|
|
67
|
+
let vrfPublicKey: Uint8Array;
|
|
68
|
+
|
|
69
|
+
export async function initBlink(bsecUrl: string, slotName: string): Promise<void> {
|
|
70
|
+
signer = await BlinkSigner.connect(bsecUrl, slotName, AlgoSuiteId.Ed25519);
|
|
71
|
+
vrfPublicKey = await signer.vrfPublicKey();
|
|
72
|
+
console.log(
|
|
73
|
+
\`[blink] Connected to BSEC at \${bsecUrl} \` +
|
|
74
|
+
\`(slot=\${slotName}, pk=\${Buffer.from(vrfPublicKey).toString('hex').slice(0, 16)}...)\`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function getSigner(): BlinkSigner { return signer; }
|
|
79
|
+
export function getVrfPublicKey(): Uint8Array { return vrfPublicKey; }
|
|
80
|
+
export function getVrfPublicKeyHex(): string { return Buffer.from(vrfPublicKey).toString('hex'); }
|
|
81
|
+
|
|
82
|
+
export function createVerifier(): BlinkVerifier {
|
|
83
|
+
return new BlinkVerifier(vrfPublicKey, {
|
|
84
|
+
freshnessWindowMs: 10 * 365.25 * 24 * 60 * 60 * 1000, // 10 years
|
|
85
|
+
clockSkewToleranceMs: 60_000,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function shutdownBlink(): Promise<void> {
|
|
90
|
+
if (signer) {
|
|
91
|
+
await signer.close();
|
|
92
|
+
console.log('[blink] Disconnected from BLINK Secure Engine');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
// --- src/hash-chain.ts ---
|
|
97
|
+
files['src/hash-chain.ts'] = `/**
|
|
98
|
+
* Hash-chain utilities for the audit trail.
|
|
99
|
+
*
|
|
100
|
+
* Each audit entry includes a \`previousEntryHash\` field, creating a tamper-evident
|
|
101
|
+
* chain. The hash of each entry is computed from its BLINK envelope (not the payload),
|
|
102
|
+
* so tampering with any entry breaks the chain.
|
|
103
|
+
*
|
|
104
|
+
* Chain structure:
|
|
105
|
+
* GENESIS -> Entry 1 -> Entry 2 -> ... -> Entry N
|
|
106
|
+
* Each entry's previousEntryHash = SHA-256(previous entry's envelope)
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
import { createHash } from 'node:crypto';
|
|
110
|
+
|
|
111
|
+
/** The genesis hash — the previousEntryHash for the first entry in the chain. */
|
|
112
|
+
export const GENESIS_HASH = '0'.repeat(64);
|
|
113
|
+
|
|
114
|
+
/** Audit entry before signing (no envelope or signerPublicKey yet). */
|
|
115
|
+
export interface UnsignedAuditEntry {
|
|
116
|
+
id: string;
|
|
117
|
+
sequenceNumber: number;
|
|
118
|
+
timestamp: string;
|
|
119
|
+
actor: string;
|
|
120
|
+
action: string;
|
|
121
|
+
resource: string;
|
|
122
|
+
detail?: string;
|
|
123
|
+
metadata?: Record<string, unknown>;
|
|
124
|
+
previousEntryHash: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Audit entry after signing. */
|
|
128
|
+
export interface AuditEntry extends UnsignedAuditEntry {
|
|
129
|
+
envelope: string;
|
|
130
|
+
signerPublicKey: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Build the canonical JSON payload to sign.
|
|
135
|
+
* Excludes envelope and signerPublicKey (those are outputs of signing).
|
|
136
|
+
*/
|
|
137
|
+
export function buildSignPayload(entry: UnsignedAuditEntry): Uint8Array {
|
|
138
|
+
const canonical: Record<string, unknown> = {
|
|
139
|
+
id: entry.id,
|
|
140
|
+
sequenceNumber: entry.sequenceNumber,
|
|
141
|
+
timestamp: entry.timestamp,
|
|
142
|
+
actor: entry.actor,
|
|
143
|
+
action: entry.action,
|
|
144
|
+
resource: entry.resource,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
if (entry.detail !== undefined) canonical['detail'] = entry.detail;
|
|
148
|
+
if (entry.metadata !== undefined) canonical['metadata'] = entry.metadata;
|
|
149
|
+
canonical['previousEntryHash'] = entry.previousEntryHash;
|
|
150
|
+
|
|
151
|
+
return new TextEncoder().encode(JSON.stringify(canonical));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Compute the chain link hash from a BLINK envelope.
|
|
156
|
+
* This hash becomes the previousEntryHash for the next entry.
|
|
157
|
+
*/
|
|
158
|
+
export function computeEnvelopeHash(envelopeBase64: string): string {
|
|
159
|
+
const envelopeBytes = Buffer.from(envelopeBase64, 'base64');
|
|
160
|
+
return createHash('sha256').update(envelopeBytes).digest('hex');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Format an audit entry ID from a sequence number. */
|
|
164
|
+
export function formatEntryId(seq: number): string {
|
|
165
|
+
return \`AUD-\${seq.toString().padStart(8, '0')}\`;
|
|
166
|
+
}
|
|
167
|
+
`;
|
|
168
|
+
// --- src/audit-log.ts ---
|
|
169
|
+
files['src/audit-log.ts'] = `/**
|
|
170
|
+
* In-memory audit log with hash-chained BLINK signatures.
|
|
171
|
+
*
|
|
172
|
+
* Each new entry is:
|
|
173
|
+
* 1. Assigned a sequence number and linked to the previous entry's hash
|
|
174
|
+
* 2. Signed with BLINK (single-use credential via Temporal Key Assurance)
|
|
175
|
+
* 3. Stored in the chain
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
import { getSigner, getVrfPublicKeyHex } from './blink.js';
|
|
179
|
+
import {
|
|
180
|
+
GENESIS_HASH,
|
|
181
|
+
buildSignPayload,
|
|
182
|
+
computeEnvelopeHash,
|
|
183
|
+
formatEntryId,
|
|
184
|
+
type AuditEntry,
|
|
185
|
+
type UnsignedAuditEntry,
|
|
186
|
+
} from './hash-chain.js';
|
|
187
|
+
|
|
188
|
+
// In-memory storage (replace with a database in production)
|
|
189
|
+
const entries: AuditEntry[] = [];
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Append a new entry to the audit trail.
|
|
193
|
+
* Automatically handles sequencing, hash-chaining, and BLINK signing.
|
|
194
|
+
*/
|
|
195
|
+
export async function appendEntry(input: {
|
|
196
|
+
actor: string;
|
|
197
|
+
action: string;
|
|
198
|
+
resource: string;
|
|
199
|
+
detail?: string;
|
|
200
|
+
metadata?: Record<string, unknown>;
|
|
201
|
+
}): Promise<AuditEntry> {
|
|
202
|
+
const seq = entries.length + 1;
|
|
203
|
+
const lastEntry = entries.length > 0 ? entries[entries.length - 1] : undefined;
|
|
204
|
+
|
|
205
|
+
// Link to previous entry via hash chain
|
|
206
|
+
const previousEntryHash = lastEntry
|
|
207
|
+
? computeEnvelopeHash(lastEntry.envelope)
|
|
208
|
+
: GENESIS_HASH;
|
|
209
|
+
|
|
210
|
+
const unsigned: UnsignedAuditEntry = {
|
|
211
|
+
id: formatEntryId(seq),
|
|
212
|
+
sequenceNumber: seq,
|
|
213
|
+
timestamp: new Date().toISOString(),
|
|
214
|
+
actor: input.actor,
|
|
215
|
+
action: input.action,
|
|
216
|
+
resource: input.resource,
|
|
217
|
+
detail: input.detail,
|
|
218
|
+
metadata: input.metadata,
|
|
219
|
+
previousEntryHash,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Sign the entry with BLINK
|
|
223
|
+
const payload = buildSignPayload(unsigned);
|
|
224
|
+
const envelopeBytes = await getSigner().sign(payload);
|
|
225
|
+
|
|
226
|
+
const entry: AuditEntry = {
|
|
227
|
+
...unsigned,
|
|
228
|
+
envelope: Buffer.from(envelopeBytes).toString('base64'),
|
|
229
|
+
signerPublicKey: getVrfPublicKeyHex(),
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
entries.push(entry);
|
|
233
|
+
return entry;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** List entries with pagination and optional filters. */
|
|
237
|
+
export function listEntries(opts: {
|
|
238
|
+
limit?: number;
|
|
239
|
+
offset?: number;
|
|
240
|
+
actor?: string;
|
|
241
|
+
action?: string;
|
|
242
|
+
}): { entries: AuditEntry[]; total: number } {
|
|
243
|
+
let filtered = entries;
|
|
244
|
+
if (opts.actor) filtered = filtered.filter(e => e.actor === opts.actor);
|
|
245
|
+
if (opts.action) filtered = filtered.filter(e => e.action === opts.action);
|
|
246
|
+
|
|
247
|
+
const offset = opts.offset ?? 0;
|
|
248
|
+
const limit = opts.limit ?? 50;
|
|
249
|
+
return {
|
|
250
|
+
entries: filtered.slice(offset, offset + limit),
|
|
251
|
+
total: filtered.length,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Get a single entry by ID. */
|
|
256
|
+
export function getEntryById(id: string): AuditEntry | undefined {
|
|
257
|
+
return entries.find(e => e.id === id);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Get the latest entry (tail of the chain). */
|
|
261
|
+
export function getLatestEntry(): AuditEntry | undefined {
|
|
262
|
+
return entries.length > 0 ? entries[entries.length - 1] : undefined;
|
|
263
|
+
}
|
|
264
|
+
`;
|
|
265
|
+
// --- src/server.ts ---
|
|
266
|
+
files['src/server.ts'] = `/**
|
|
267
|
+
* ${name} — Hash-chained audit trail with BLINK Authority signatures.
|
|
268
|
+
*
|
|
269
|
+
* Every audit entry is signed with a single-use BLINK credential and
|
|
270
|
+
* linked to the previous entry via a hash chain, creating a tamper-evident log.
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
import 'dotenv/config';
|
|
274
|
+
import express from 'express';
|
|
275
|
+
import { initBlink, shutdownBlink, getVrfPublicKeyHex } from './blink.js';
|
|
276
|
+
import { appendEntry, listEntries, getEntryById } from './audit-log.js';
|
|
277
|
+
|
|
278
|
+
async function main(): Promise<void> {
|
|
279
|
+
const bsecUrl = process.env['BSEC_URL'] ?? 'http://localhost:9100';
|
|
280
|
+
const slotName = process.env['SLOT_NAME'] ?? 'default';
|
|
281
|
+
const port = parseInt(process.env['PORT'] ?? '3000', 10);
|
|
282
|
+
|
|
283
|
+
await initBlink(bsecUrl, slotName);
|
|
284
|
+
|
|
285
|
+
const app = express();
|
|
286
|
+
app.use(express.json());
|
|
287
|
+
|
|
288
|
+
// POST /entries — Create a new audit entry
|
|
289
|
+
app.post('/entries', async (req, res, next) => {
|
|
290
|
+
try {
|
|
291
|
+
const { actor, action, resource, detail, metadata } = req.body;
|
|
292
|
+
if (!actor || !action || !resource) {
|
|
293
|
+
res.status(400).json({ error: 'Missing required fields: actor, action, resource' });
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const entry = await appendEntry({ actor, action, resource, detail, metadata });
|
|
297
|
+
res.status(201).json(entry);
|
|
298
|
+
} catch (err) {
|
|
299
|
+
next(err);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// GET /entries — List entries with optional filters
|
|
304
|
+
app.get('/entries', (req, res) => {
|
|
305
|
+
const limit = parseInt(req.query['limit'] as string, 10) || 50;
|
|
306
|
+
const offset = parseInt(req.query['offset'] as string, 10) || 0;
|
|
307
|
+
const actor = req.query['actor'] as string | undefined;
|
|
308
|
+
const action = req.query['action'] as string | undefined;
|
|
309
|
+
const result = listEntries({ limit, offset, actor, action });
|
|
310
|
+
res.json({ ...result, limit, offset });
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// GET /entries/:id — Get a single entry
|
|
314
|
+
app.get('/entries/:id', (req, res) => {
|
|
315
|
+
const entry = getEntryById(req.params['id']!);
|
|
316
|
+
if (!entry) {
|
|
317
|
+
res.status(404).json({ error: 'Entry not found' });
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
res.json(entry);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// GET /health
|
|
324
|
+
app.get('/health', (_req, res) => {
|
|
325
|
+
res.json({
|
|
326
|
+
status: 'ok',
|
|
327
|
+
service: '${name}',
|
|
328
|
+
signerPublicKey: getVrfPublicKeyHex(),
|
|
329
|
+
timestamp: new Date().toISOString(),
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const server = app.listen(port, () => {
|
|
334
|
+
console.log(\`[server] ${name} listening on port \${port}\`);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Graceful shutdown
|
|
338
|
+
const shutdown = async (signal: string) => {
|
|
339
|
+
console.log(\`[server] Received \${signal}, shutting down...\`);
|
|
340
|
+
server.close();
|
|
341
|
+
await shutdownBlink();
|
|
342
|
+
process.exit(0);
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
346
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
main().catch((err) => {
|
|
350
|
+
console.error('[server] Fatal error:', err);
|
|
351
|
+
process.exit(1);
|
|
352
|
+
});
|
|
353
|
+
`;
|
|
354
|
+
// --- README.md ---
|
|
355
|
+
files['README.md'] = `# ${name}
|
|
356
|
+
|
|
357
|
+
Hash-chained audit trail with **BLINK Authority** signatures. Every audit entry is
|
|
358
|
+
cryptographically signed and linked to the previous entry, creating a tamper-evident log.
|
|
359
|
+
|
|
360
|
+
## Quick Start
|
|
361
|
+
|
|
362
|
+
\`\`\`bash
|
|
363
|
+
npm install
|
|
364
|
+
cp .env.example .env
|
|
365
|
+
npm run dev
|
|
366
|
+
\`\`\`
|
|
367
|
+
|
|
368
|
+
## API
|
|
369
|
+
|
|
370
|
+
### POST /entries
|
|
371
|
+
Create a new audit entry. Automatically signed and hash-chained.
|
|
372
|
+
|
|
373
|
+
\`\`\`bash
|
|
374
|
+
curl -X POST http://localhost:3000/entries \\
|
|
375
|
+
-H "Content-Type: application/json" \\
|
|
376
|
+
-d '{"actor":"alice","action":"approve","resource":"order-123"}'
|
|
377
|
+
\`\`\`
|
|
378
|
+
|
|
379
|
+
### GET /entries
|
|
380
|
+
List entries with pagination. Supports \`?actor=\` and \`?action=\` filters.
|
|
381
|
+
|
|
382
|
+
### GET /entries/:id
|
|
383
|
+
Get a single entry by ID.
|
|
384
|
+
|
|
385
|
+
## How the Hash Chain Works
|
|
386
|
+
|
|
387
|
+
1. Each entry includes a \`previousEntryHash\` field
|
|
388
|
+
2. The hash is computed from the previous entry's BLINK envelope
|
|
389
|
+
3. The first entry links to a well-known genesis hash
|
|
390
|
+
4. Tampering with any entry breaks the chain from that point forward
|
|
391
|
+
|
|
392
|
+
Built with [BLINK Authority](https://blink-authority.com).
|
|
393
|
+
`;
|
|
394
|
+
return files;
|
|
395
|
+
}
|
|
396
|
+
//# sourceMappingURL=audit-trail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-trail.js","sourceRoot":"","sources":["../../src/templates/audit-trail.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,QAAkB;IAElB,MAAM,KAAK,GAA2B,EAAE,CAAC;IAEzC,uBAAuB;IACvB,KAAK,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,SAAS,CACpC;QACE,IAAI;QACJ,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,GAAG,IAAI,6DAA6D;QACjF,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,qBAAqB;YAC5B,GAAG,EAAE,mBAAmB;SACzB;QACD,YAAY,EAAE;YACZ,uBAAuB,EAAE,SAAS;YAClC,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,SAAS;SAClB;QACD,eAAe,EAAE;YACf,gBAAgB,EAAE,UAAU;YAC5B,aAAa,EAAE,UAAU;YACzB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,SAAS;SACf;KACF,EACD,IAAI,EACJ,CAAC,CACF,CAAC;IAEF,wBAAwB;IACxB,KAAK,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC,SAAS,CACrC;QACE,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,QAAQ;YAC1B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,gCAAgC,EAAE,IAAI;YACtC,WAAW,EAAE,IAAI;YACjB,SAAS,EAAE,IAAI;SAChB;QACD,OAAO,EAAE,CAAC,UAAU,CAAC;QACrB,OAAO,EAAE,CAAC,cAAc,EAAE,MAAM,CAAC;KAClC,EACD,IAAI,EACJ,CAAC,CACF,CAAC;IAEF,uBAAuB;IACvB,KAAK,CAAC,cAAc,CAAC,GAAG;;;;;;;CAOzB,CAAC;IAEA,uBAAuB;IACvB,KAAK,CAAC,cAAc,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCzB,CAAC;IAEA,4BAA4B;IAC5B,KAAK,CAAC,mBAAmB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsE9B,CAAC;IAEA,2BAA2B;IAC3B,KAAK,CAAC,kBAAkB,CAAC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+F7B,CAAC;IAEA,wBAAwB;IACxB,KAAK,CAAC,eAAe,CAAC,GAAG;KACtB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4DS,IAAI;;;;;;;6BAOO,IAAI;;;;;;;;;;;;;;;;;;;CAmBhC,CAAC;IAEA,oBAAoB;IACpB,KAAK,CAAC,WAAW,CAAC,GAAG,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsC/B,CAAC;IAEA,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-tool.d.ts","sourceRoot":"","sources":["../../src/templates/cli-tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAsWxB"}
|