@clawbureau/clawverify-core 0.1.1 → 0.2.1
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 +12 -0
- package/dist/badge-health.d.ts +40 -0
- package/dist/badge-health.d.ts.map +1 -0
- package/dist/badge-health.js +56 -0
- package/dist/badge-health.js.map +1 -0
- package/dist/compliance.d.ts +106 -0
- package/dist/compliance.d.ts.map +1 -0
- package/dist/compliance.js +356 -0
- package/dist/compliance.js.map +1 -0
- package/dist/hashcash.d.ts +44 -0
- package/dist/hashcash.d.ts.map +1 -0
- package/dist/hashcash.js +97 -0
- package/dist/hashcash.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/policy-evaluator.d.ts +119 -0
- package/dist/policy-evaluator.d.ts.map +1 -0
- package/dist/policy-evaluator.js +452 -0
- package/dist/policy-evaluator.js.map +1 -0
- package/dist/trace-compiler.d.ts +7 -0
- package/dist/trace-compiler.d.ts.map +1 -0
- package/dist/trace-compiler.js +46 -0
- package/dist/trace-compiler.js.map +1 -0
- package/dist/types.d.ts +68 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/verify-causal-integrity.d.ts +68 -0
- package/dist/verify-causal-integrity.d.ts.map +1 -0
- package/dist/verify-causal-integrity.js +186 -0
- package/dist/verify-causal-integrity.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -35,6 +35,18 @@ console.log(result.reason_code); // 'OK', 'SIGNATURE_INVALID', etc.
|
|
|
35
35
|
|
|
36
36
|
Unknown schema versions, hash algorithms, or envelope formats produce `FAIL` — never silently pass.
|
|
37
37
|
|
|
38
|
+
## Learn more
|
|
39
|
+
|
|
40
|
+
- **[Full documentation](https://www.clawea.com/docs)** — Quick Start, SDK reference, API reference, protocol spec
|
|
41
|
+
- **[Adoption guide](https://github.com/clawbureau/clawbureau/blob/main/docs/specs/clawsig-protocol/ADOPTION_GUIDE.md)** — integrate in a day
|
|
42
|
+
- **[Clawsig Protocol](https://clawsig.com)** — protocol overview, design principles, conformance suite
|
|
43
|
+
|
|
44
|
+
### Enterprise
|
|
45
|
+
|
|
46
|
+
Running AI agents in regulated environments? Claw EA provides approval gates, DLP redaction, audit trails, and compliance evidence for SOX, HIPAA, and FedRAMP.
|
|
47
|
+
|
|
48
|
+
**[See enterprise plans →](https://www.clawea.com/pricing/enterprise)**
|
|
49
|
+
|
|
38
50
|
## License
|
|
39
51
|
|
|
40
52
|
MIT
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* badge-health.ts — Heartbeat Badge status computation
|
|
3
|
+
*
|
|
4
|
+
* Red Team Fix #9: Dynamic badge that reflects real-time verification
|
|
5
|
+
* activity. Prevents frameworks from passing conformance once and then
|
|
6
|
+
* silently removing the integration while keeping the badge.
|
|
7
|
+
*
|
|
8
|
+
* The badge color is computed from trailing 7-day run statistics.
|
|
9
|
+
*/
|
|
10
|
+
/** Badge color enum for rendering. */
|
|
11
|
+
export type BadgeColor = 'green' | 'yellow' | 'gray' | 'red';
|
|
12
|
+
/** Input statistics for badge computation. */
|
|
13
|
+
export interface BadgeStats {
|
|
14
|
+
/** Number of verification runs in the last 7 days. */
|
|
15
|
+
runs_7d: number;
|
|
16
|
+
/** Number of policy violations in the last 7 days. */
|
|
17
|
+
violations_7d: number;
|
|
18
|
+
/** ISO 8601 timestamp of the most recent run. */
|
|
19
|
+
last_run_at: string;
|
|
20
|
+
}
|
|
21
|
+
/** Computed badge status. */
|
|
22
|
+
export interface BadgeStatus {
|
|
23
|
+
/** Badge color for rendering. */
|
|
24
|
+
color: BadgeColor;
|
|
25
|
+
/** Human-readable label. */
|
|
26
|
+
label: string;
|
|
27
|
+
/** Whether the badge represents a healthy integration. */
|
|
28
|
+
healthy: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compute the badge status from trailing 7-day run statistics.
|
|
32
|
+
*
|
|
33
|
+
* Color logic:
|
|
34
|
+
* - Green: runs_7d >= 10 AND violations_7d == 0
|
|
35
|
+
* - Yellow: runs_7d >= 10 AND violations_7d > 0 (but within 10%)
|
|
36
|
+
* - Gray: runs_7d < 10 (insufficient recent activity)
|
|
37
|
+
* - Red: violations_7d > runs_7d * 0.1 (>10% violation rate)
|
|
38
|
+
*/
|
|
39
|
+
export declare function computeBadgeStatus(stats: BadgeStats): BadgeStatus;
|
|
40
|
+
//# sourceMappingURL=badge-health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge-health.d.ts","sourceRoot":"","sources":["../src/badge-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,6BAA6B;AAC7B,MAAM,WAAW,WAAW;IAC1B,iCAAiC;IACjC,KAAK,EAAE,UAAU,CAAC;IAClB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;CAClB;AAQD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAoCjE"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* badge-health.ts — Heartbeat Badge status computation
|
|
3
|
+
*
|
|
4
|
+
* Red Team Fix #9: Dynamic badge that reflects real-time verification
|
|
5
|
+
* activity. Prevents frameworks from passing conformance once and then
|
|
6
|
+
* silently removing the integration while keeping the badge.
|
|
7
|
+
*
|
|
8
|
+
* The badge color is computed from trailing 7-day run statistics.
|
|
9
|
+
*/
|
|
10
|
+
/** Minimum number of runs in 7 days for the badge to be considered active. */
|
|
11
|
+
const MIN_ACTIVE_RUNS = 10;
|
|
12
|
+
/** Violation rate threshold (fraction) above which the badge turns red. */
|
|
13
|
+
const RED_VIOLATION_RATE = 0.1;
|
|
14
|
+
/**
|
|
15
|
+
* Compute the badge status from trailing 7-day run statistics.
|
|
16
|
+
*
|
|
17
|
+
* Color logic:
|
|
18
|
+
* - Green: runs_7d >= 10 AND violations_7d == 0
|
|
19
|
+
* - Yellow: runs_7d >= 10 AND violations_7d > 0 (but within 10%)
|
|
20
|
+
* - Gray: runs_7d < 10 (insufficient recent activity)
|
|
21
|
+
* - Red: violations_7d > runs_7d * 0.1 (>10% violation rate)
|
|
22
|
+
*/
|
|
23
|
+
export function computeBadgeStatus(stats) {
|
|
24
|
+
const { runs_7d, violations_7d } = stats;
|
|
25
|
+
// Insufficient activity — badge is stale
|
|
26
|
+
if (runs_7d < MIN_ACTIVE_RUNS) {
|
|
27
|
+
return {
|
|
28
|
+
color: 'gray',
|
|
29
|
+
label: 'Insufficient activity',
|
|
30
|
+
healthy: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// High violation rate — badge is red
|
|
34
|
+
if (violations_7d > runs_7d * RED_VIOLATION_RATE) {
|
|
35
|
+
return {
|
|
36
|
+
color: 'red',
|
|
37
|
+
label: `${violations_7d} violations (${((violations_7d / runs_7d) * 100).toFixed(1)}%)`,
|
|
38
|
+
healthy: false,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Some violations but within tolerance — badge is yellow
|
|
42
|
+
if (violations_7d > 0) {
|
|
43
|
+
return {
|
|
44
|
+
color: 'yellow',
|
|
45
|
+
label: `${violations_7d} violation${violations_7d === 1 ? '' : 's'} in 7d`,
|
|
46
|
+
healthy: true,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Clean — badge is green
|
|
50
|
+
return {
|
|
51
|
+
color: 'green',
|
|
52
|
+
label: `${runs_7d} verified runs`,
|
|
53
|
+
healthy: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=badge-health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge-health.js","sourceRoot":"","sources":["../src/badge-health.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,8EAA8E;AAC9E,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,2EAA2E;AAC3E,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB;IAClD,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAEzC,yCAAyC;IACzC,IAAI,OAAO,GAAG,eAAe,EAAE,CAAC;QAC9B,OAAO;YACL,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,uBAAuB;YAC9B,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,IAAI,aAAa,GAAG,OAAO,GAAG,kBAAkB,EAAE,CAAC;QACjD,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,GAAG,aAAa,gBAAgB,CAAC,CAAC,aAAa,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;YACvF,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAED,yDAAyD;IACzD,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO;YACL,KAAK,EAAE,QAAQ;YACf,KAAK,EAAE,GAAG,aAAa,aAAa,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ;YAC1E,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,yBAAyB;IACzB,OAAO;QACL,KAAK,EAAE,OAAO;QACd,KAAK,EAAE,GAAG,OAAO,gBAAgB;QACjC,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Report Generator
|
|
3
|
+
*
|
|
4
|
+
* Maps verified Clawsig proof bundles to enterprise compliance framework controls.
|
|
5
|
+
* P9 (Revenue): SOC2 is the wedge, EU AI Act is the whale.
|
|
6
|
+
*
|
|
7
|
+
* Mapping rules (from Gemini Deep Think Round 2):
|
|
8
|
+
* CC6.1 (Logical Access) <- WPC allowed_models + proof_tier
|
|
9
|
+
* CC6.2 (System Boundaries) <- side_effect_receipts (network_egress)
|
|
10
|
+
* CC7.1 (Detection of Changes) <- tool_receipts (file changes)
|
|
11
|
+
* CC7.2 (Monitoring) <- event_chain existence + log_inclusion_proof
|
|
12
|
+
* CC8.1 (Change Management) <- human_approval_receipts OR gateway_receipt tier
|
|
13
|
+
*/
|
|
14
|
+
export type ComplianceFramework = 'SOC2_Type2' | 'ISO27001' | 'EU_AI_Act' | 'NIST_AI_RMF';
|
|
15
|
+
export type ControlStatus = 'PASS' | 'FAIL' | 'NOT_APPLICABLE' | 'INSUFFICIENT_EVIDENCE';
|
|
16
|
+
export type EvidenceType = 'gateway_receipt' | 'tool_receipt' | 'side_effect_receipt' | 'human_approval_receipt' | 'wpc' | 'event_chain' | 'delegation_receipt' | 'log_inclusion_proof';
|
|
17
|
+
export interface ControlResult {
|
|
18
|
+
control_id: string;
|
|
19
|
+
control_name: string;
|
|
20
|
+
status: ControlStatus;
|
|
21
|
+
evidence_type?: EvidenceType;
|
|
22
|
+
evidence_ref?: string;
|
|
23
|
+
narrative?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ComplianceGap {
|
|
26
|
+
control_id: string;
|
|
27
|
+
description: string;
|
|
28
|
+
recommendation: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ComplianceReport {
|
|
31
|
+
report_version: '1';
|
|
32
|
+
framework: ComplianceFramework;
|
|
33
|
+
generated_at: string;
|
|
34
|
+
proof_bundle_hash_b64u: string;
|
|
35
|
+
agent_did: string;
|
|
36
|
+
policy_hash_b64u?: string;
|
|
37
|
+
controls: ControlResult[];
|
|
38
|
+
gaps: ComplianceGap[];
|
|
39
|
+
}
|
|
40
|
+
export interface ComplianceBundleInput {
|
|
41
|
+
bundle_version?: string;
|
|
42
|
+
bundle_id?: string;
|
|
43
|
+
agent_did: string;
|
|
44
|
+
event_chain?: unknown[];
|
|
45
|
+
receipts?: Array<{
|
|
46
|
+
payload?: {
|
|
47
|
+
receipt_id?: string;
|
|
48
|
+
model?: string;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
};
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
}>;
|
|
53
|
+
tool_receipts?: Array<{
|
|
54
|
+
receipt_id?: string;
|
|
55
|
+
tool_name?: string;
|
|
56
|
+
[key: string]: unknown;
|
|
57
|
+
}>;
|
|
58
|
+
side_effect_receipts?: Array<{
|
|
59
|
+
receipt_id?: string;
|
|
60
|
+
effect_class?: string;
|
|
61
|
+
[key: string]: unknown;
|
|
62
|
+
}>;
|
|
63
|
+
human_approval_receipts?: Array<{
|
|
64
|
+
receipt_id?: string;
|
|
65
|
+
approval_type?: string;
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
}>;
|
|
68
|
+
delegation_receipts?: Array<{
|
|
69
|
+
receipt_id?: string;
|
|
70
|
+
delegate_did?: string;
|
|
71
|
+
delegate_bundle_hash_b64u?: string;
|
|
72
|
+
[key: string]: unknown;
|
|
73
|
+
}>;
|
|
74
|
+
attestations?: unknown[];
|
|
75
|
+
metadata?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
export interface CompliancePolicyInput {
|
|
78
|
+
/** Raw WPC hash (base64url). Used for CC6.1 evidence. */
|
|
79
|
+
policy_hash_b64u?: string;
|
|
80
|
+
/** If the WPC contains allowed_models, list them here. */
|
|
81
|
+
allowed_models?: string[];
|
|
82
|
+
/** Minimum model identity tier required by the WPC. */
|
|
83
|
+
minimum_model_identity_tier?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Maps a proof bundle to SOC2 Type II controls.
|
|
87
|
+
*
|
|
88
|
+
* The bundle should already be verified (signature + hash chain valid).
|
|
89
|
+
* This function evaluates evidence presence and quality, not cryptographic integrity.
|
|
90
|
+
*/
|
|
91
|
+
export declare function mapToSOC2(bundle: ComplianceBundleInput, policy?: CompliancePolicyInput, opts?: {
|
|
92
|
+
bundleHash?: string;
|
|
93
|
+
}): ComplianceReport;
|
|
94
|
+
export declare function mapToISO27001(bundle: ComplianceBundleInput, policy?: CompliancePolicyInput, opts?: {
|
|
95
|
+
bundleHash?: string;
|
|
96
|
+
}): ComplianceReport;
|
|
97
|
+
export declare function mapToEUAIAct(bundle: ComplianceBundleInput, policy?: CompliancePolicyInput, opts?: {
|
|
98
|
+
bundleHash?: string;
|
|
99
|
+
}): ComplianceReport;
|
|
100
|
+
/**
|
|
101
|
+
* Generate a compliance report for any supported framework.
|
|
102
|
+
*/
|
|
103
|
+
export declare function generateComplianceReport(framework: ComplianceFramework, bundle: ComplianceBundleInput, policy?: CompliancePolicyInput, opts?: {
|
|
104
|
+
bundleHash?: string;
|
|
105
|
+
}): ComplianceReport;
|
|
106
|
+
//# sourceMappingURL=compliance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.d.ts","sourceRoot":"","sources":["../src/compliance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAE1F,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,gBAAgB,GAAG,uBAAuB,CAAC;AAEzF,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,cAAc,GACd,qBAAqB,GACrB,wBAAwB,GACxB,KAAK,GACL,aAAa,GACb,oBAAoB,GACpB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB,aAAa,CAAC,EAAE,YAAY,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,GAAG,CAAC;IACpB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,IAAI,EAAE,aAAa,EAAE,CAAC;CACvB;AAOD,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,OAAO,CAAC,EAAE;YACR,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;QACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,oBAAoB,CAAC,EAAE,KAAK,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,uBAAuB,CAAC,EAAE,KAAK,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,mBAAmB,CAAC,EAAE,KAAK,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,uDAAuD;IACvD,2BAA2B,CAAC,EAAE,MAAM,CAAC;CACtC;AAqMD;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,qBAAqB,EAC7B,MAAM,CAAC,EAAE,qBAAqB,EAC9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,gBAAgB,CAqClB;AA8BD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,qBAAqB,EAC7B,MAAM,CAAC,EAAE,qBAAqB,EAC9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,gBAAgB,CAwBlB;AAaD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,qBAAqB,EAC7B,MAAM,CAAC,EAAE,qBAAqB,EAC9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,gBAAgB,CAgClB;AAMD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,mBAAmB,EAC9B,MAAM,EAAE,qBAAqB,EAC7B,MAAM,CAAC,EAAE,qBAAqB,EAC9B,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,gBAAgB,CA+BlB"}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compliance Report Generator
|
|
3
|
+
*
|
|
4
|
+
* Maps verified Clawsig proof bundles to enterprise compliance framework controls.
|
|
5
|
+
* P9 (Revenue): SOC2 is the wedge, EU AI Act is the whale.
|
|
6
|
+
*
|
|
7
|
+
* Mapping rules (from Gemini Deep Think Round 2):
|
|
8
|
+
* CC6.1 (Logical Access) <- WPC allowed_models + proof_tier
|
|
9
|
+
* CC6.2 (System Boundaries) <- side_effect_receipts (network_egress)
|
|
10
|
+
* CC7.1 (Detection of Changes) <- tool_receipts (file changes)
|
|
11
|
+
* CC7.2 (Monitoring) <- event_chain existence + log_inclusion_proof
|
|
12
|
+
* CC8.1 (Change Management) <- human_approval_receipts OR gateway_receipt tier
|
|
13
|
+
*/
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Helpers
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
function hashBundle(bundle) {
|
|
18
|
+
// Deterministic hash placeholder — in production this would be
|
|
19
|
+
// sha256_b64u(JCS(bundle)). The CLI layer computes the real hash
|
|
20
|
+
// before calling the mapper.
|
|
21
|
+
return 'BUNDLE_HASH_COMPUTED_BY_CALLER';
|
|
22
|
+
}
|
|
23
|
+
function hasNetworkEgressReceipts(bundle) {
|
|
24
|
+
return (bundle.side_effect_receipts ?? []).some((r) => r.effect_class === 'network_egress');
|
|
25
|
+
}
|
|
26
|
+
function hasFileWriteReceipts(bundle) {
|
|
27
|
+
return (bundle.tool_receipts ?? []).length > 0;
|
|
28
|
+
}
|
|
29
|
+
function hasHumanApprovals(bundle) {
|
|
30
|
+
return (bundle.human_approval_receipts ?? []).some((r) => r.approval_type === 'explicit_approve');
|
|
31
|
+
}
|
|
32
|
+
function hasGatewayReceipts(bundle) {
|
|
33
|
+
return (bundle.receipts ?? []).length > 0;
|
|
34
|
+
}
|
|
35
|
+
function hasEventChain(bundle) {
|
|
36
|
+
return (bundle.event_chain ?? []).length > 0;
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// SOC2 Type II Mapper
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
function mapCC6_1(bundle, policy) {
|
|
42
|
+
const control = {
|
|
43
|
+
control_id: 'CC6.1',
|
|
44
|
+
control_name: 'Logical Access Controls',
|
|
45
|
+
status: 'INSUFFICIENT_EVIDENCE',
|
|
46
|
+
};
|
|
47
|
+
// CC6.1: WPC allowed_models + proof_tier from gateway receipts
|
|
48
|
+
if (policy?.allowed_models && policy.allowed_models.length > 0) {
|
|
49
|
+
const gatewayModels = (bundle.receipts ?? [])
|
|
50
|
+
.map((r) => r.payload?.model)
|
|
51
|
+
.filter(Boolean);
|
|
52
|
+
if (gatewayModels.length > 0) {
|
|
53
|
+
const allWithinPolicy = gatewayModels.every((m) => policy.allowed_models.includes(m));
|
|
54
|
+
control.status = allWithinPolicy ? 'PASS' : 'FAIL';
|
|
55
|
+
control.evidence_type = 'wpc';
|
|
56
|
+
control.evidence_ref = policy.policy_hash_b64u;
|
|
57
|
+
control.narrative = allWithinPolicy
|
|
58
|
+
? `All ${gatewayModels.length} gateway receipt(s) reference models within the WPC allowlist (${policy.allowed_models.join(', ')}). Agent operated strictly within approved intelligence boundaries.`
|
|
59
|
+
: `One or more gateway receipts reference a model outside the WPC allowlist. Models used: ${gatewayModels.join(', ')}.`;
|
|
60
|
+
}
|
|
61
|
+
else if (hasGatewayReceipts(bundle)) {
|
|
62
|
+
control.status = 'PASS';
|
|
63
|
+
control.evidence_type = 'gateway_receipt';
|
|
64
|
+
control.evidence_ref = bundle.receipts[0].payload?.receipt_id;
|
|
65
|
+
control.narrative =
|
|
66
|
+
'Gateway receipts present; WPC policy defines allowed models. Agent used approved gateway for all LLM calls.';
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
control.narrative =
|
|
70
|
+
'WPC defines allowed_models but no gateway receipts present to verify compliance.';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (hasGatewayReceipts(bundle)) {
|
|
74
|
+
// No WPC but gateway receipts exist — partial evidence
|
|
75
|
+
control.status = 'PASS';
|
|
76
|
+
control.evidence_type = 'gateway_receipt';
|
|
77
|
+
control.evidence_ref = bundle.receipts[0].payload?.receipt_id;
|
|
78
|
+
control.narrative =
|
|
79
|
+
'Gateway receipts prove agent routed through trusted proxy. No WPC model allowlist configured — recommend adding allowed_models for full CC6.1 coverage.';
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
control.narrative =
|
|
83
|
+
'No gateway receipts and no WPC model allowlist. Cannot verify logical access controls for LLM usage.';
|
|
84
|
+
}
|
|
85
|
+
return control;
|
|
86
|
+
}
|
|
87
|
+
function mapCC6_2(bundle) {
|
|
88
|
+
const control = {
|
|
89
|
+
control_id: 'CC6.2',
|
|
90
|
+
control_name: 'System Boundary Controls',
|
|
91
|
+
status: 'INSUFFICIENT_EVIDENCE',
|
|
92
|
+
};
|
|
93
|
+
const networkReceipts = (bundle.side_effect_receipts ?? []).filter((r) => r.effect_class === 'network_egress');
|
|
94
|
+
if (networkReceipts.length > 0) {
|
|
95
|
+
control.status = 'PASS';
|
|
96
|
+
control.evidence_type = 'side_effect_receipt';
|
|
97
|
+
control.evidence_ref = networkReceipts[0].receipt_id;
|
|
98
|
+
control.narrative = `${networkReceipts.length} network egress side-effect receipt(s) present. Every outbound network call by the agent is cryptographically logged with target digest and response hash.`;
|
|
99
|
+
}
|
|
100
|
+
else if ((bundle.side_effect_receipts ?? []).length > 0) {
|
|
101
|
+
// Has side-effect receipts but none for network egress
|
|
102
|
+
control.status = 'PASS';
|
|
103
|
+
control.evidence_type = 'side_effect_receipt';
|
|
104
|
+
control.evidence_ref = bundle.side_effect_receipts[0].receipt_id;
|
|
105
|
+
control.narrative =
|
|
106
|
+
'Side-effect receipts present (non-network). No network egress detected — agent stayed within system boundaries.';
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
control.narrative =
|
|
110
|
+
'No side-effect receipts present. Cannot verify system boundary compliance. Add side-effect receipt instrumentation to the harness.';
|
|
111
|
+
}
|
|
112
|
+
return control;
|
|
113
|
+
}
|
|
114
|
+
function mapCC7_1(bundle) {
|
|
115
|
+
const control = {
|
|
116
|
+
control_id: 'CC7.1',
|
|
117
|
+
control_name: 'Detection of Changes',
|
|
118
|
+
status: 'INSUFFICIENT_EVIDENCE',
|
|
119
|
+
};
|
|
120
|
+
if (hasFileWriteReceipts(bundle)) {
|
|
121
|
+
control.status = 'PASS';
|
|
122
|
+
control.evidence_type = 'tool_receipt';
|
|
123
|
+
control.evidence_ref = bundle.tool_receipts[0].receipt_id;
|
|
124
|
+
control.narrative = `${bundle.tool_receipts.length} tool receipt(s) present. Every file modification and tool invocation by the agent is logged with input/output hashes in an immutable event chain.`;
|
|
125
|
+
}
|
|
126
|
+
else if (hasEventChain(bundle)) {
|
|
127
|
+
control.status = 'PASS';
|
|
128
|
+
control.evidence_type = 'event_chain';
|
|
129
|
+
control.narrative =
|
|
130
|
+
'Event chain present but no tool receipts. Change detection relies on event chain integrity — recommend adding tool receipt instrumentation for granular file-level evidence.';
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
control.narrative =
|
|
134
|
+
'No tool receipts or event chain present. Cannot verify change detection compliance.';
|
|
135
|
+
}
|
|
136
|
+
return control;
|
|
137
|
+
}
|
|
138
|
+
function mapCC7_2(bundle) {
|
|
139
|
+
const control = {
|
|
140
|
+
control_id: 'CC7.2',
|
|
141
|
+
control_name: 'System Monitoring',
|
|
142
|
+
status: 'INSUFFICIENT_EVIDENCE',
|
|
143
|
+
};
|
|
144
|
+
if (hasEventChain(bundle)) {
|
|
145
|
+
control.status = 'PASS';
|
|
146
|
+
control.evidence_type = 'event_chain';
|
|
147
|
+
control.narrative = `Hash-linked event chain present with ${bundle.event_chain.length} event(s). Every agent action is logged to a tamper-evident, append-only chain. Receipt Transparency Log integration provides additional Merkle tree inclusion proof coverage.`;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
control.narrative =
|
|
151
|
+
'No event chain present. System monitoring requires a tamper-evident event log. Configure the harness to emit an event chain.';
|
|
152
|
+
}
|
|
153
|
+
return control;
|
|
154
|
+
}
|
|
155
|
+
function mapCC8_1(bundle) {
|
|
156
|
+
const control = {
|
|
157
|
+
control_id: 'CC8.1',
|
|
158
|
+
control_name: 'Change Management',
|
|
159
|
+
status: 'INSUFFICIENT_EVIDENCE',
|
|
160
|
+
};
|
|
161
|
+
if (hasHumanApprovals(bundle)) {
|
|
162
|
+
const approvals = bundle.human_approval_receipts.filter((r) => r.approval_type === 'explicit_approve');
|
|
163
|
+
control.status = 'PASS';
|
|
164
|
+
control.evidence_type = 'human_approval_receipt';
|
|
165
|
+
control.evidence_ref = approvals[0]?.receipt_id;
|
|
166
|
+
control.narrative = `${approvals.length} explicit human approval receipt(s) present. Cryptographic proof that a human reviewer authorized changes before deployment. This satisfies change management controls without traditional peer review.`;
|
|
167
|
+
}
|
|
168
|
+
else if (hasGatewayReceipts(bundle)) {
|
|
169
|
+
// Gateway receipts provide weaker but acceptable evidence
|
|
170
|
+
control.status = 'PASS';
|
|
171
|
+
control.evidence_type = 'gateway_receipt';
|
|
172
|
+
control.evidence_ref = bundle.receipts[0].payload?.receipt_id;
|
|
173
|
+
control.narrative =
|
|
174
|
+
'Gateway receipts prove code was generated through a trusted, auditable proxy under policy constraints. No explicit human approval — recommend adding human_approval_receipts for stronger CC8.1 evidence.';
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
control.narrative =
|
|
178
|
+
'No human approval receipts or gateway receipts present. Change management requires either human oversight proof or gateway-tier evidence.';
|
|
179
|
+
}
|
|
180
|
+
return control;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Maps a proof bundle to SOC2 Type II controls.
|
|
184
|
+
*
|
|
185
|
+
* The bundle should already be verified (signature + hash chain valid).
|
|
186
|
+
* This function evaluates evidence presence and quality, not cryptographic integrity.
|
|
187
|
+
*/
|
|
188
|
+
export function mapToSOC2(bundle, policy, opts) {
|
|
189
|
+
const controls = [
|
|
190
|
+
mapCC6_1(bundle, policy),
|
|
191
|
+
mapCC6_2(bundle),
|
|
192
|
+
mapCC7_1(bundle),
|
|
193
|
+
mapCC7_2(bundle),
|
|
194
|
+
mapCC8_1(bundle),
|
|
195
|
+
];
|
|
196
|
+
const gaps = [];
|
|
197
|
+
for (const c of controls) {
|
|
198
|
+
if (c.status === 'FAIL') {
|
|
199
|
+
gaps.push({
|
|
200
|
+
control_id: c.control_id,
|
|
201
|
+
description: c.narrative ?? `Control ${c.control_id} failed evaluation.`,
|
|
202
|
+
recommendation: getRemediation(c.control_id),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else if (c.status === 'INSUFFICIENT_EVIDENCE') {
|
|
206
|
+
gaps.push({
|
|
207
|
+
control_id: c.control_id,
|
|
208
|
+
description: c.narrative ?? `Insufficient evidence for ${c.control_id}.`,
|
|
209
|
+
recommendation: getRemediation(c.control_id),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
report_version: '1',
|
|
215
|
+
framework: 'SOC2_Type2',
|
|
216
|
+
generated_at: new Date().toISOString(),
|
|
217
|
+
proof_bundle_hash_b64u: opts?.bundleHash ?? hashBundle(bundle),
|
|
218
|
+
agent_did: bundle.agent_did,
|
|
219
|
+
policy_hash_b64u: policy?.policy_hash_b64u,
|
|
220
|
+
controls,
|
|
221
|
+
gaps,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function getRemediation(controlId) {
|
|
225
|
+
switch (controlId) {
|
|
226
|
+
case 'CC6.1':
|
|
227
|
+
return 'Configure a Work Policy Contract (WPC) with allowed_models and route LLM calls through clawproxy to generate gateway receipts.';
|
|
228
|
+
case 'CC6.2':
|
|
229
|
+
return 'Instrument the agent harness to emit side_effect_receipts for all network egress calls.';
|
|
230
|
+
case 'CC7.1':
|
|
231
|
+
return 'Instrument the agent harness to emit tool_receipts for all file system operations and tool invocations.';
|
|
232
|
+
case 'CC7.2':
|
|
233
|
+
return 'Configure the agent harness to emit a hash-linked event chain. Enable Receipt Transparency Log integration for Merkle tree inclusion proofs.';
|
|
234
|
+
case 'CC8.1':
|
|
235
|
+
return 'Add human-in-the-loop approval gates for high-risk actions. The harness should emit human_approval_receipts, or at minimum route through clawproxy for gateway-tier evidence.';
|
|
236
|
+
default:
|
|
237
|
+
return 'Review the Clawsig Protocol documentation for instrumentation guidance.';
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// ISO 27001 Mapper (stub)
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
// TODO: Implement ISO 27001 information security control mapping.
|
|
244
|
+
// Key controls to map:
|
|
245
|
+
// A.9.1 (Access Control Policy) <- WPC + gateway_receipts
|
|
246
|
+
// A.9.2 (User Access Management) <- agent_did + owner_attestation
|
|
247
|
+
// A.12.4 (Logging and Monitoring) <- event_chain + log_inclusion_proof
|
|
248
|
+
// A.14.2 (Security in Development) <- tool_receipts + human_approval_receipts
|
|
249
|
+
// A.18.1 (Compliance with Legal Requirements) <- full proof_bundle
|
|
250
|
+
export function mapToISO27001(bundle, policy, opts) {
|
|
251
|
+
return {
|
|
252
|
+
report_version: '1',
|
|
253
|
+
framework: 'ISO27001',
|
|
254
|
+
generated_at: new Date().toISOString(),
|
|
255
|
+
proof_bundle_hash_b64u: opts?.bundleHash ?? hashBundle(bundle),
|
|
256
|
+
agent_did: bundle.agent_did,
|
|
257
|
+
policy_hash_b64u: policy?.policy_hash_b64u,
|
|
258
|
+
controls: [
|
|
259
|
+
{
|
|
260
|
+
control_id: 'A.9.1',
|
|
261
|
+
control_name: 'Access Control Policy',
|
|
262
|
+
status: 'NOT_APPLICABLE',
|
|
263
|
+
narrative: 'ISO 27001 mapper not yet implemented. SOC2 mapping is available.',
|
|
264
|
+
},
|
|
265
|
+
],
|
|
266
|
+
gaps: [
|
|
267
|
+
{
|
|
268
|
+
control_id: 'A.9.1',
|
|
269
|
+
description: 'ISO 27001 compliance mapping is not yet implemented.',
|
|
270
|
+
recommendation: 'Use SOC2 framework for current compliance reporting. ISO 27001 support is planned.',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// EU AI Act Mapper (stub)
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
// TODO: Implement EU AI Act compliance mapping.
|
|
279
|
+
// Key articles to map:
|
|
280
|
+
// Art 9 (Risk Management) <- WPC + proof_tier
|
|
281
|
+
// Art 11 (Technical Documentation) <- export_bundle + urm
|
|
282
|
+
// Art 13 (Transparency) <- system_prompt_report + model_identity
|
|
283
|
+
// Art 14 (Human Oversight) <- human_approval_receipts (the killer feature)
|
|
284
|
+
// Art 15 (Accuracy, Robustness, Security) <- audit_result_attestations
|
|
285
|
+
export function mapToEUAIAct(bundle, policy, opts) {
|
|
286
|
+
return {
|
|
287
|
+
report_version: '1',
|
|
288
|
+
framework: 'EU_AI_Act',
|
|
289
|
+
generated_at: new Date().toISOString(),
|
|
290
|
+
proof_bundle_hash_b64u: opts?.bundleHash ?? hashBundle(bundle),
|
|
291
|
+
agent_did: bundle.agent_did,
|
|
292
|
+
policy_hash_b64u: policy?.policy_hash_b64u,
|
|
293
|
+
controls: [
|
|
294
|
+
{
|
|
295
|
+
control_id: 'Art14',
|
|
296
|
+
control_name: 'Human Oversight',
|
|
297
|
+
status: hasHumanApprovals(bundle) ? 'PASS' : 'INSUFFICIENT_EVIDENCE',
|
|
298
|
+
evidence_type: hasHumanApprovals(bundle) ? 'human_approval_receipt' : undefined,
|
|
299
|
+
evidence_ref: hasHumanApprovals(bundle)
|
|
300
|
+
? bundle.human_approval_receipts?.find((r) => r.approval_type === 'explicit_approve')?.receipt_id
|
|
301
|
+
: undefined,
|
|
302
|
+
narrative: hasHumanApprovals(bundle)
|
|
303
|
+
? 'Cryptographic proof of Article 14 compliance. High-risk actions are mathematically locked until a HumanApprovalReceipt is signed by a verified operator.'
|
|
304
|
+
: 'No human approval receipts present. Article 14 requires proof of human oversight for high-risk AI systems.',
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
gaps: hasHumanApprovals(bundle)
|
|
308
|
+
? []
|
|
309
|
+
: [
|
|
310
|
+
{
|
|
311
|
+
control_id: 'Art14',
|
|
312
|
+
description: 'No human approval receipts. EU AI Act Article 14 requires verifiable human oversight.',
|
|
313
|
+
recommendation: 'Add human-in-the-loop approval gates. The harness should emit human_approval_receipts for high-risk operations.',
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// Dispatcher
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
/**
|
|
322
|
+
* Generate a compliance report for any supported framework.
|
|
323
|
+
*/
|
|
324
|
+
export function generateComplianceReport(framework, bundle, policy, opts) {
|
|
325
|
+
switch (framework) {
|
|
326
|
+
case 'SOC2_Type2':
|
|
327
|
+
return mapToSOC2(bundle, policy, opts);
|
|
328
|
+
case 'ISO27001':
|
|
329
|
+
return mapToISO27001(bundle, policy, opts);
|
|
330
|
+
case 'EU_AI_Act':
|
|
331
|
+
return mapToEUAIAct(bundle, policy, opts);
|
|
332
|
+
case 'NIST_AI_RMF':
|
|
333
|
+
// TODO: Implement NIST AI RMF mapping
|
|
334
|
+
return {
|
|
335
|
+
report_version: '1',
|
|
336
|
+
framework: 'NIST_AI_RMF',
|
|
337
|
+
generated_at: new Date().toISOString(),
|
|
338
|
+
proof_bundle_hash_b64u: opts?.bundleHash ?? hashBundle(bundle),
|
|
339
|
+
agent_did: bundle.agent_did,
|
|
340
|
+
policy_hash_b64u: policy?.policy_hash_b64u,
|
|
341
|
+
controls: [],
|
|
342
|
+
gaps: [
|
|
343
|
+
{
|
|
344
|
+
control_id: 'GOVERN',
|
|
345
|
+
description: 'NIST AI RMF compliance mapping is not yet implemented.',
|
|
346
|
+
recommendation: 'Use SOC2 framework for current compliance reporting. NIST AI RMF support is planned.',
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
};
|
|
350
|
+
default: {
|
|
351
|
+
const _exhaustive = framework;
|
|
352
|
+
throw new Error(`Unknown compliance framework: ${_exhaustive}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
//# sourceMappingURL=compliance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.js","sourceRoot":"","sources":["../src/compliance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hashcash.ts — Proof-of-Work for VaaS DoS protection
|
|
3
|
+
*
|
|
4
|
+
* Red Team Fix #8: Requires unauthenticated API callers to present a
|
|
5
|
+
* valid PoW token, making volumetric DoS economically infeasible.
|
|
6
|
+
*
|
|
7
|
+
* Uses WebCrypto (crypto.subtle) for Cloudflare Workers compatibility.
|
|
8
|
+
*
|
|
9
|
+
* Challenge format: `${dateHourUTC}:${clientIdentifier}`
|
|
10
|
+
* The client must find a nonce such that SHA-256(challenge + ":" + nonce)
|
|
11
|
+
* has `difficulty` leading zero hex characters.
|
|
12
|
+
*
|
|
13
|
+
* Default difficulty: 4 (approx 65,536 attempts, ~100ms on modern hardware).
|
|
14
|
+
*/
|
|
15
|
+
/** Default number of leading zero hex chars required. */
|
|
16
|
+
export declare const DEFAULT_POW_DIFFICULTY = 4;
|
|
17
|
+
/**
|
|
18
|
+
* Generate the current date-hour challenge component.
|
|
19
|
+
* Format: YYYYMMDDHH (UTC).
|
|
20
|
+
*/
|
|
21
|
+
export declare function getDateHourUTC(date?: Date): string;
|
|
22
|
+
/**
|
|
23
|
+
* Build a challenge string from the date-hour and client identifier.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildChallenge(clientIdentifier: string, date?: Date): string;
|
|
26
|
+
/**
|
|
27
|
+
* Find a nonce such that SHA-256(challenge + ":" + nonce) has `difficulty`
|
|
28
|
+
* leading zero hex characters.
|
|
29
|
+
*
|
|
30
|
+
* @param challenge The challenge string (e.g. "2026021223:192.168.1.1")
|
|
31
|
+
* @param difficulty Number of leading zero hex chars required (default: 4)
|
|
32
|
+
* @returns The nonce string that satisfies the PoW
|
|
33
|
+
*/
|
|
34
|
+
export declare function generatePoW(challenge: string, difficulty?: number): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Verify that a nonce satisfies the PoW requirement.
|
|
37
|
+
*
|
|
38
|
+
* @param challenge The challenge string
|
|
39
|
+
* @param nonce The claimed nonce
|
|
40
|
+
* @param difficulty Number of leading zero hex chars required (default: 4)
|
|
41
|
+
* @returns true if the PoW is valid
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyPoW(challenge: string, nonce: string, difficulty?: number): Promise<boolean>;
|
|
44
|
+
//# sourceMappingURL=hashcash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashcash.d.ts","sourceRoot":"","sources":["../src/hashcash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,yDAAyD;AACzD,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,CAOlD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,gBAAgB,EAAE,MAAM,EACxB,IAAI,CAAC,EAAE,IAAI,GACV,MAAM,CAER;AA0BD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAA+B,GAC1C,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAA+B,GAC1C,OAAO,CAAC,OAAO,CAAC,CASlB"}
|