@attestplane/attestplane 0.0.1 → 0.0.3-alpha
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 +23 -9
- package/dist/adapter_conformance.d.ts +46 -0
- package/dist/adapter_conformance.d.ts.map +1 -0
- package/dist/adapter_conformance.js +160 -0
- package/dist/adapter_conformance.js.map +1 -0
- package/dist/adapters/langfuse.d.ts +51 -0
- package/dist/adapters/langfuse.d.ts.map +1 -0
- package/dist/adapters/langfuse.js +157 -0
- package/dist/adapters/langfuse.js.map +1 -0
- package/dist/adapters/langsmith.d.ts +53 -0
- package/dist/adapters/langsmith.d.ts.map +1 -0
- package/dist/adapters/langsmith.js +173 -0
- package/dist/adapters/langsmith.js.map +1 -0
- package/dist/adapters.d.ts +88 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +109 -0
- package/dist/adapters.js.map +1 -0
- package/dist/anchoring.d.ts +119 -0
- package/dist/anchoring.d.ts.map +1 -0
- package/dist/anchoring.js +340 -0
- package/dist/anchoring.js.map +1 -0
- package/dist/canonical.d.ts +11 -2
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +44 -31
- package/dist/canonical.js.map +1 -1
- package/dist/canonical_text.d.ts +30 -0
- package/dist/canonical_text.d.ts.map +1 -0
- package/dist/canonical_text.js +100 -0
- package/dist/canonical_text.js.map +1 -0
- package/dist/der.d.ts +55 -0
- package/dist/der.d.ts.map +1 -0
- package/dist/der.js +200 -0
- package/dist/der.js.map +1 -0
- package/dist/event_payloads.d.ts +118 -0
- package/dist/event_payloads.d.ts.map +1 -0
- package/dist/event_payloads.js +348 -0
- package/dist/event_payloads.js.map +1 -0
- package/dist/event_types.d.ts +47 -0
- package/dist/event_types.d.ts.map +1 -0
- package/dist/event_types.js +63 -0
- package/dist/event_types.js.map +1 -0
- package/dist/hashchain.d.ts +1 -0
- package/dist/hashchain.d.ts.map +1 -1
- package/dist/hashchain.js +25 -1
- package/dist/hashchain.js.map +1 -1
- package/dist/index.d.ts +23 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/index.js.map +1 -1
- package/dist/index_version.d.ts +9 -0
- package/dist/index_version.d.ts.map +1 -0
- package/dist/index_version.js +11 -0
- package/dist/index_version.js.map +1 -0
- package/dist/intoto.d.ts +48 -0
- package/dist/intoto.d.ts.map +1 -0
- package/dist/intoto.js +106 -0
- package/dist/intoto.js.map +1 -0
- package/dist/obligations.d.ts +41 -0
- package/dist/obligations.d.ts.map +1 -0
- package/dist/obligations.js +312 -0
- package/dist/obligations.js.map +1 -0
- package/dist/proof_bundle.d.ts +186 -0
- package/dist/proof_bundle.d.ts.map +1 -0
- package/dist/proof_bundle.js +299 -0
- package/dist/proof_bundle.js.map +1 -0
- package/dist/reason_codes.d.ts +38 -0
- package/dist/reason_codes.d.ts.map +1 -0
- package/dist/reason_codes.js +97 -0
- package/dist/reason_codes.js.map +1 -0
- package/dist/replay_verifier.d.ts +43 -0
- package/dist/replay_verifier.d.ts.map +1 -0
- package/dist/replay_verifier.js +98 -0
- package/dist/replay_verifier.js.map +1 -0
- package/dist/rfc3161.d.ts +52 -0
- package/dist/rfc3161.d.ts.map +1 -0
- package/dist/rfc3161.js +480 -0
- package/dist/rfc3161.js.map +1 -0
- package/dist/settlement_verifier.d.ts +34 -0
- package/dist/settlement_verifier.d.ts.map +1 -0
- package/dist/settlement_verifier.js +139 -0
- package/dist/settlement_verifier.js.map +1 -0
- package/dist/signing/base.d.ts +101 -0
- package/dist/signing/base.d.ts.map +1 -0
- package/dist/signing/base.js +144 -0
- package/dist/signing/base.js.map +1 -0
- package/dist/signing/providers.d.ts +113 -0
- package/dist/signing/providers.d.ts.map +1 -0
- package/dist/signing/providers.js +230 -0
- package/dist/signing/providers.js.map +1 -0
- package/dist/signing/signer.d.ts +66 -0
- package/dist/signing/signer.d.ts.map +1 -0
- package/dist/signing/signer.js +146 -0
- package/dist/signing/signer.js.map +1 -0
- package/dist/signing/trust_roots.d.ts +71 -0
- package/dist/signing/trust_roots.d.ts.map +1 -0
- package/dist/signing/trust_roots.js +267 -0
- package/dist/signing/trust_roots.js.map +1 -0
- package/dist/signing/verifier_ext.d.ts +77 -0
- package/dist/signing/verifier_ext.d.ts.map +1 -0
- package/dist/signing/verifier_ext.js +340 -0
- package/dist/signing/verifier_ext.js.map +1 -0
- package/dist/verifier.d.ts +39 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +374 -0
- package/dist/verifier.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# @attestplane/attestplane — TypeScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Apache-2.0 attestation and audit substrate for AI agent evidence chains.
|
|
4
4
|
|
|
5
|
-
> **Status: alpha (v0.0.
|
|
5
|
+
> **Status: alpha (v0.0.3-alpha).** Wire format is byte-locked against the Python
|
|
6
6
|
> SDK's [`vectors.json`](../python/tests/conformance/vectors.json) — see
|
|
7
7
|
> [ADR-0002][adr2]. APIs may still change before v0.1.0.
|
|
8
|
+
> The current Python CLI `attestplane verify` path is chain/report-oriented
|
|
9
|
+
> with ProofBundle metadata and `policy_trace_refs` closure checks. It does
|
|
10
|
+
> not perform full ProofBundle, signature, anchor, or compliance
|
|
11
|
+
> certification verification.
|
|
8
12
|
|
|
9
13
|
See the [project README][project-readme] for background, governance, and
|
|
10
14
|
trademark policy.
|
|
@@ -15,9 +19,16 @@ trademark policy.
|
|
|
15
19
|
## Install
|
|
16
20
|
|
|
17
21
|
```bash
|
|
18
|
-
|
|
22
|
+
# Pin the alpha explicitly; v0.0.3-alpha is on the 'alpha' dist-tag.
|
|
23
|
+
npm install @attestplane/attestplane@alpha
|
|
24
|
+
# or, equivalent:
|
|
25
|
+
npm install @attestplane/attestplane@0.0.3-alpha
|
|
19
26
|
```
|
|
20
27
|
|
|
28
|
+
`npm install @attestplane/attestplane` without a tag also resolves to
|
|
29
|
+
the current published dist-tag. Treat the `alpha` tag as the authoritative
|
|
30
|
+
pre-release channel until v0.1.0 ships.
|
|
31
|
+
|
|
21
32
|
Requires Node.js ≥ 22.
|
|
22
33
|
|
|
23
34
|
## Quickstart
|
|
@@ -55,9 +66,11 @@ will reproduce the exact byte value from the same input.
|
|
|
55
66
|
## What this SDK gives you
|
|
56
67
|
|
|
57
68
|
- An **append-only** audit log with cryptographic integrity (SHA-256 hash chain).
|
|
58
|
-
- Built-in **EU AI Act Art. 12(2)(a)**
|
|
69
|
+
- Built-in fields designed toward **EU AI Act Art. 12(2)(a)** auditability from day one.
|
|
59
70
|
- Byte-identical canonical format compatible with the Python SDK.
|
|
60
71
|
- Strong **GDPR pseudonymization typing** via `SubjectRef`.
|
|
72
|
+
- Alpha-grade verifier predicates; do not treat this SDK as production-ready
|
|
73
|
+
governance, compliance certification, or runtime execution authority.
|
|
61
74
|
|
|
62
75
|
## API conventions
|
|
63
76
|
|
|
@@ -76,17 +89,18 @@ Payloads must satisfy the restricted profile of ADR-0002:
|
|
|
76
89
|
|---|---|
|
|
77
90
|
| `string` (NFC-normalized UTF-8) | non-NFC strings |
|
|
78
91
|
| `number` (integer, safe range) | floats, `NaN`, `Infinity` |
|
|
79
|
-
| `
|
|
92
|
+
| `number` values must be safe integers | unsafe integers; direct `bigint` |
|
|
80
93
|
| `true` / `false` / `null` | — |
|
|
81
94
|
| plain objects (string keys) | non-string keys; duplicate keys |
|
|
82
|
-
| arrays |
|
|
95
|
+
| arrays | sparse arrays; `undefined` items |
|
|
83
96
|
| `Uint8Array` (emits as base64url no padding) | other byte types |
|
|
84
|
-
|
|
|
97
|
+
| explicit RFC 3339 timestamp strings | direct `Date` objects in canonical JSON payloads |
|
|
85
98
|
|
|
86
99
|
Violations throw `CanonicalizationError` at append time.
|
|
87
100
|
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
`AttestSubstrate.append()` accepts `Date` at the typed SDK boundary for
|
|
102
|
+
`AuditEvent.timestamp` and converts it explicitly before hashing. Payloads
|
|
103
|
+
should carry timestamps as strings when they need to be part of canonical JSON.
|
|
90
104
|
|
|
91
105
|
## Development
|
|
92
106
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter-conformance fixture replayer (ADR-0014 P2.2).
|
|
3
|
+
*
|
|
4
|
+
* TypeScript mirror of `attestplane.adapter_conformance` (Python).
|
|
5
|
+
* Loads a fixture file, calls `adapter.translate()` per case, asserts
|
|
6
|
+
* canonical-bytes equality against `expected_event_draft`. Pure — no
|
|
7
|
+
* I/O beyond the fixture file read.
|
|
8
|
+
*/
|
|
9
|
+
import type { EventDraft } from './types.js';
|
|
10
|
+
export interface AdapterCaseResult {
|
|
11
|
+
readonly case_name: string;
|
|
12
|
+
readonly ok: boolean;
|
|
13
|
+
readonly reason: string | null;
|
|
14
|
+
readonly expected_canonical_hash: string | null;
|
|
15
|
+
readonly actual_canonical_hash: string | null;
|
|
16
|
+
}
|
|
17
|
+
export interface AdapterConformanceReport {
|
|
18
|
+
readonly fixture_path: string;
|
|
19
|
+
readonly runtime_kind: string;
|
|
20
|
+
readonly fixture_version: number;
|
|
21
|
+
readonly cases_total: number;
|
|
22
|
+
readonly cases_passed: number;
|
|
23
|
+
readonly cases_failed: number;
|
|
24
|
+
readonly results: readonly AdapterCaseResult[];
|
|
25
|
+
readonly ok: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare class AdapterConformanceError extends Error {
|
|
28
|
+
constructor(message: string);
|
|
29
|
+
}
|
|
30
|
+
export interface ReplayOptions {
|
|
31
|
+
/** Optional callback to convert raw `runtime_event_input` into the
|
|
32
|
+
* runtime-event type the adapter's `translate()` expects. */
|
|
33
|
+
readonly pre_translate?: (raw: Record<string, unknown>) => unknown;
|
|
34
|
+
}
|
|
35
|
+
/** An adapter-shaped object: has a `translate()` method returning an `EventDraft`. */
|
|
36
|
+
export interface TranslateAdapter<RE = unknown> {
|
|
37
|
+
translate(runtimeEvent: RE): EventDraft;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Replay every case in `fixturePath` against `adapter.translate()`.
|
|
41
|
+
*
|
|
42
|
+
* `report.ok` is true iff every case's adapter output matches its
|
|
43
|
+
* `expected_event_draft` byte-equal under canonical-JSON.
|
|
44
|
+
*/
|
|
45
|
+
export declare function replayFixture(fixturePath: string, adapter: TranslateAdapter, options?: ReplayOptions): AdapterConformanceReport;
|
|
46
|
+
//# sourceMappingURL=adapter_conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter_conformance.d.ts","sourceRoot":"","sources":["../src/adapter_conformance.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;CACtB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AA+HD,MAAM,WAAW,aAAa;IAC5B;kEAC8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;CACpE;AAED,sFAAsF;AACtF,MAAM,WAAW,gBAAgB,CAAC,EAAE,GAAG,OAAO;IAC5C,SAAS,CAAC,YAAY,EAAE,EAAE,GAAG,UAAU,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,OAAO,GAAE,aAAkB,GAC1B,wBAAwB,CAyD1B"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 The Attestplane Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Adapter-conformance fixture replayer (ADR-0014 P2.2).
|
|
5
|
+
*
|
|
6
|
+
* TypeScript mirror of `attestplane.adapter_conformance` (Python).
|
|
7
|
+
* Loads a fixture file, calls `adapter.translate()` per case, asserts
|
|
8
|
+
* canonical-bytes equality against `expected_event_draft`. Pure — no
|
|
9
|
+
* I/O beyond the fixture file read.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from 'node:crypto';
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import { canonicalize } from './canonical.js';
|
|
14
|
+
export class AdapterConformanceError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'AdapterConformanceError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function subjectRefToDict(ref) {
|
|
21
|
+
if (ref === null || ref === undefined)
|
|
22
|
+
return null;
|
|
23
|
+
return { scheme: ref.scheme, value: ref.value };
|
|
24
|
+
}
|
|
25
|
+
function eventDraftToDict(draft) {
|
|
26
|
+
return {
|
|
27
|
+
event_type: draft.event_type,
|
|
28
|
+
actor: draft.actor,
|
|
29
|
+
payload: draft.payload,
|
|
30
|
+
subject_ref: subjectRefToDict(draft.subject_ref),
|
|
31
|
+
session_id: draft.session_id,
|
|
32
|
+
reference_db_ref: draft.reference_db_ref,
|
|
33
|
+
matched_input_ref: draft.matched_input_ref,
|
|
34
|
+
human_verifier: subjectRefToDict(draft.human_verifier),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function canonicalBytesHash(d) {
|
|
38
|
+
return createHash('sha256').update(canonicalize(d)).digest('hex');
|
|
39
|
+
}
|
|
40
|
+
function loadAndValidateFixture(fixturePath) {
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = JSON.parse(readFileSync(fixturePath, 'utf-8'));
|
|
44
|
+
}
|
|
45
|
+
catch (exc) {
|
|
46
|
+
throw new AdapterConformanceError(`cannot load fixture ${fixturePath}: ${exc.message}`);
|
|
47
|
+
}
|
|
48
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
49
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: top level must be object, got ${Array.isArray(raw) ? 'array' : raw === null ? 'null' : typeof raw}`);
|
|
50
|
+
}
|
|
51
|
+
const obj = raw;
|
|
52
|
+
if (obj.$schema_version !== 1) {
|
|
53
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: $schema_version must be 1, got ${JSON.stringify(obj.$schema_version)}`);
|
|
54
|
+
}
|
|
55
|
+
if (obj.fixture_kind !== 'adapter_conformance') {
|
|
56
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: fixture_kind must be 'adapter_conformance', got ${JSON.stringify(obj.fixture_kind)}`);
|
|
57
|
+
}
|
|
58
|
+
if (typeof obj.runtime_kind !== 'string' || obj.runtime_kind.length === 0) {
|
|
59
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: runtime_kind must be non-empty string`);
|
|
60
|
+
}
|
|
61
|
+
if (typeof obj.fixture_version !== 'number' ||
|
|
62
|
+
!Number.isInteger(obj.fixture_version) ||
|
|
63
|
+
obj.fixture_version < 1) {
|
|
64
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: fixture_version must be integer >= 1`);
|
|
65
|
+
}
|
|
66
|
+
if (!Array.isArray(obj.cases) || obj.cases.length === 0) {
|
|
67
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: cases must be non-empty array`);
|
|
68
|
+
}
|
|
69
|
+
const seenNames = new Set();
|
|
70
|
+
for (let i = 0; i < obj.cases.length; i++) {
|
|
71
|
+
const c = obj.cases[i];
|
|
72
|
+
if (c === null || typeof c !== 'object' || Array.isArray(c)) {
|
|
73
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: cases[${i}] must be object`);
|
|
74
|
+
}
|
|
75
|
+
const co = c;
|
|
76
|
+
if (typeof co.name !== 'string' || co.name.length === 0) {
|
|
77
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: cases[${i}].name must be non-empty string`);
|
|
78
|
+
}
|
|
79
|
+
if (seenNames.has(co.name)) {
|
|
80
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: duplicate case name ${JSON.stringify(co.name)}`);
|
|
81
|
+
}
|
|
82
|
+
seenNames.add(co.name);
|
|
83
|
+
if (!('runtime_event_input' in co)) {
|
|
84
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: cases[${i}] missing runtime_event_input`);
|
|
85
|
+
}
|
|
86
|
+
if (!('expected_event_draft' in co)) {
|
|
87
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: cases[${i}] missing expected_event_draft`);
|
|
88
|
+
}
|
|
89
|
+
if (co.expected_event_draft === null ||
|
|
90
|
+
typeof co.expected_event_draft !== 'object' ||
|
|
91
|
+
Array.isArray(co.expected_event_draft)) {
|
|
92
|
+
throw new AdapterConformanceError(`fixture ${fixturePath}: cases[${i}].expected_event_draft must be object`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return obj;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Replay every case in `fixturePath` against `adapter.translate()`.
|
|
99
|
+
*
|
|
100
|
+
* `report.ok` is true iff every case's adapter output matches its
|
|
101
|
+
* `expected_event_draft` byte-equal under canonical-JSON.
|
|
102
|
+
*/
|
|
103
|
+
export function replayFixture(fixturePath, adapter, options = {}) {
|
|
104
|
+
const fixture = loadAndValidateFixture(fixturePath);
|
|
105
|
+
const results = [];
|
|
106
|
+
let passed = 0;
|
|
107
|
+
let failed = 0;
|
|
108
|
+
for (const c of fixture.cases) {
|
|
109
|
+
const expectedHash = canonicalBytesHash(c.expected_event_draft);
|
|
110
|
+
try {
|
|
111
|
+
const runtimeEvent = options.pre_translate !== undefined
|
|
112
|
+
? options.pre_translate(c.runtime_event_input)
|
|
113
|
+
: c.runtime_event_input;
|
|
114
|
+
const actualDraft = adapter.translate(runtimeEvent);
|
|
115
|
+
const actual = eventDraftToDict(actualDraft);
|
|
116
|
+
const actualHash = canonicalBytesHash(actual);
|
|
117
|
+
if (actualHash === expectedHash) {
|
|
118
|
+
results.push({
|
|
119
|
+
case_name: c.name,
|
|
120
|
+
ok: true,
|
|
121
|
+
reason: null,
|
|
122
|
+
expected_canonical_hash: expectedHash,
|
|
123
|
+
actual_canonical_hash: actualHash,
|
|
124
|
+
});
|
|
125
|
+
passed++;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
results.push({
|
|
129
|
+
case_name: c.name,
|
|
130
|
+
ok: false,
|
|
131
|
+
reason: `canonical-bytes mismatch (expected hash ${expectedHash}, got ${actualHash})`,
|
|
132
|
+
expected_canonical_hash: expectedHash,
|
|
133
|
+
actual_canonical_hash: actualHash,
|
|
134
|
+
});
|
|
135
|
+
failed++;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (exc) {
|
|
139
|
+
results.push({
|
|
140
|
+
case_name: c.name,
|
|
141
|
+
ok: false,
|
|
142
|
+
reason: `adapter raised: ${exc.name}: ${exc.message}`,
|
|
143
|
+
expected_canonical_hash: expectedHash,
|
|
144
|
+
actual_canonical_hash: null,
|
|
145
|
+
});
|
|
146
|
+
failed++;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
fixture_path: fixturePath,
|
|
151
|
+
runtime_kind: fixture.runtime_kind,
|
|
152
|
+
fixture_version: fixture.fixture_version,
|
|
153
|
+
cases_total: fixture.cases.length,
|
|
154
|
+
cases_passed: passed,
|
|
155
|
+
cases_failed: failed,
|
|
156
|
+
results,
|
|
157
|
+
ok: failed === 0,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=adapter_conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter_conformance.js","sourceRoot":"","sources":["../src/adapter_conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangFuse → Attestplane evidence-event adapter (TypeScript port of
|
|
3
|
+
* `sdk/python/src/attestplane/adapters/langfuse.py`).
|
|
4
|
+
*
|
|
5
|
+
* Byte-identical translation semantics with the Python adapter.
|
|
6
|
+
*
|
|
7
|
+
* Pure function per GenericRuntimeAdapter contract: no I/O, no
|
|
8
|
+
* LangFuse API calls.
|
|
9
|
+
*
|
|
10
|
+
* Trust boundary (ADR-0004 § 4): adapter consumes the public
|
|
11
|
+
* LangFuse Observation shape; LangFuse / ClickHouse do not endorse
|
|
12
|
+
* this adapter (see docs/policy/forbidden_claims.md § G).
|
|
13
|
+
*
|
|
14
|
+
* Redaction (ADR-0008 § Boundary anti-requirements):
|
|
15
|
+
* - Raw input / output never copied to payload — only SHA-256 hashes.
|
|
16
|
+
* - status_message truncated to 200 chars before placing in error_code.
|
|
17
|
+
* - user_id (from parent Trace) wrapped in SubjectRef(scheme="opaque").
|
|
18
|
+
*
|
|
19
|
+
* Observation type → event_type mapping:
|
|
20
|
+
* GENERATION / SPAN / EVENT → tool_call_event with payload.kind set.
|
|
21
|
+
*
|
|
22
|
+
* Level → result_status mapping:
|
|
23
|
+
* ERROR → "ERROR"; everything else → "OK" (WARNING preserved as
|
|
24
|
+
* payload.level but not flipping status).
|
|
25
|
+
*/
|
|
26
|
+
import { GenericRuntimeAdapter } from '../adapters.js';
|
|
27
|
+
import { type EventDraft } from '../types.js';
|
|
28
|
+
export interface LangFuseObservation {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly trace_id: string;
|
|
31
|
+
readonly type: string;
|
|
32
|
+
readonly name?: string | null;
|
|
33
|
+
readonly start_time?: Date | null;
|
|
34
|
+
readonly end_time?: Date | null;
|
|
35
|
+
readonly input?: unknown;
|
|
36
|
+
readonly output?: unknown;
|
|
37
|
+
readonly level?: string | null;
|
|
38
|
+
readonly metadata?: Record<string, unknown>;
|
|
39
|
+
readonly status_message?: string | null;
|
|
40
|
+
readonly model?: string | null;
|
|
41
|
+
readonly user_id?: string | null;
|
|
42
|
+
}
|
|
43
|
+
export declare class LangFuseAdapter extends GenericRuntimeAdapter<LangFuseObservation> {
|
|
44
|
+
readonly runtime_name = "langfuse";
|
|
45
|
+
readonly schema_version = 1;
|
|
46
|
+
translate(runtime_event: LangFuseObservation): EventDraft;
|
|
47
|
+
static fromDict(raw: Record<string, unknown>, options?: {
|
|
48
|
+
readonly user_id?: string;
|
|
49
|
+
}): LangFuseObservation;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=langfuse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langfuse.d.ts","sourceRoot":"","sources":["../../src/adapters/langfuse.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAIH,OAAO,EAA2B,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,aAAa,CAAC;AAK9E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAiCD,qBAAa,eAAgB,SAAQ,qBAAqB,CAAC,mBAAmB,CAAC;IAC7E,QAAQ,CAAC,YAAY,cAAc;IACnC,QAAQ,CAAC,cAAc,KAAK;IAE5B,SAAS,CAAC,aAAa,EAAE,mBAAmB,GAAG,UAAU;IA+DzD,MAAM,CAAC,QAAQ,CACb,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACtC,mBAAmB;CA4CvB"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 The Attestplane Authors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* LangFuse → Attestplane evidence-event adapter (TypeScript port of
|
|
5
|
+
* `sdk/python/src/attestplane/adapters/langfuse.py`).
|
|
6
|
+
*
|
|
7
|
+
* Byte-identical translation semantics with the Python adapter.
|
|
8
|
+
*
|
|
9
|
+
* Pure function per GenericRuntimeAdapter contract: no I/O, no
|
|
10
|
+
* LangFuse API calls.
|
|
11
|
+
*
|
|
12
|
+
* Trust boundary (ADR-0004 § 4): adapter consumes the public
|
|
13
|
+
* LangFuse Observation shape; LangFuse / ClickHouse do not endorse
|
|
14
|
+
* this adapter (see docs/policy/forbidden_claims.md § G).
|
|
15
|
+
*
|
|
16
|
+
* Redaction (ADR-0008 § Boundary anti-requirements):
|
|
17
|
+
* - Raw input / output never copied to payload — only SHA-256 hashes.
|
|
18
|
+
* - status_message truncated to 200 chars before placing in error_code.
|
|
19
|
+
* - user_id (from parent Trace) wrapped in SubjectRef(scheme="opaque").
|
|
20
|
+
*
|
|
21
|
+
* Observation type → event_type mapping:
|
|
22
|
+
* GENERATION / SPAN / EVENT → tool_call_event with payload.kind set.
|
|
23
|
+
*
|
|
24
|
+
* Level → result_status mapping:
|
|
25
|
+
* ERROR → "ERROR"; everything else → "OK" (WARNING preserved as
|
|
26
|
+
* payload.level but not flipping status).
|
|
27
|
+
*/
|
|
28
|
+
import { createHash } from 'node:crypto';
|
|
29
|
+
import { AdapterTranslationError, GenericRuntimeAdapter } from '../adapters.js';
|
|
30
|
+
import { TOOL_CALL_EVENT } from '../event_types.js';
|
|
31
|
+
import { makeEventDraft, makeSubjectRef } from '../types.js';
|
|
32
|
+
const KNOWN_OBSERVATION_TYPES = new Set(['GENERATION', 'SPAN', 'EVENT']);
|
|
33
|
+
const KNOWN_LEVELS = new Set(['DEFAULT', 'DEBUG', 'WARNING', 'ERROR']);
|
|
34
|
+
function _canonicalReplacer() {
|
|
35
|
+
return function (_key, value) {
|
|
36
|
+
if (value === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (value instanceof Date)
|
|
39
|
+
return value.toISOString();
|
|
40
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
41
|
+
const sorted = {};
|
|
42
|
+
const obj = value;
|
|
43
|
+
for (const k of Object.keys(obj).sort()) {
|
|
44
|
+
sorted[k] = obj[k];
|
|
45
|
+
}
|
|
46
|
+
return sorted;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function _hashJson(value) {
|
|
52
|
+
const sorted = JSON.parse(JSON.stringify(value, _canonicalReplacer()));
|
|
53
|
+
const compact = JSON.stringify(sorted);
|
|
54
|
+
return createHash('sha256').update(compact, 'utf-8').digest('hex');
|
|
55
|
+
}
|
|
56
|
+
function _truncate(text, n = 200) {
|
|
57
|
+
if (text.length <= n)
|
|
58
|
+
return text;
|
|
59
|
+
return `${text.slice(0, n - 3)}...`;
|
|
60
|
+
}
|
|
61
|
+
function _levelToStatus(level) {
|
|
62
|
+
return level === 'ERROR' ? 'ERROR' : 'OK';
|
|
63
|
+
}
|
|
64
|
+
export class LangFuseAdapter extends GenericRuntimeAdapter {
|
|
65
|
+
runtime_name = 'langfuse';
|
|
66
|
+
schema_version = 1;
|
|
67
|
+
translate(runtime_event) {
|
|
68
|
+
if (typeof runtime_event !== 'object' ||
|
|
69
|
+
runtime_event === null ||
|
|
70
|
+
typeof runtime_event.id !== 'string' ||
|
|
71
|
+
typeof runtime_event.trace_id !== 'string' ||
|
|
72
|
+
typeof runtime_event.type !== 'string') {
|
|
73
|
+
throw new AdapterTranslationError(`expected LangFuseObservation object, got ${runtime_event === null ? 'null' : typeof runtime_event}`);
|
|
74
|
+
}
|
|
75
|
+
const obs = runtime_event;
|
|
76
|
+
const kind = KNOWN_OBSERVATION_TYPES.has(obs.type) ? obs.type.toLowerCase() : 'unknown';
|
|
77
|
+
const resultStatus = _levelToStatus(obs.level);
|
|
78
|
+
const payload = {
|
|
79
|
+
kind,
|
|
80
|
+
tool_name: `langfuse.${kind}.${obs.name ?? 'unnamed'}`,
|
|
81
|
+
tool_call_id: obs.id,
|
|
82
|
+
result_status: resultStatus,
|
|
83
|
+
};
|
|
84
|
+
if (obs.input !== undefined && obs.input !== null) {
|
|
85
|
+
payload.arguments_hash = _hashJson(obs.input);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Schema requires arguments_hash always present; hash empty dict.
|
|
89
|
+
payload.arguments_hash = _hashJson({});
|
|
90
|
+
}
|
|
91
|
+
if (obs.output !== undefined && obs.output !== null) {
|
|
92
|
+
payload.result_hash = _hashJson(obs.output);
|
|
93
|
+
}
|
|
94
|
+
if (obs.start_time != null && obs.end_time != null) {
|
|
95
|
+
const ms = obs.end_time.getTime() - obs.start_time.getTime();
|
|
96
|
+
payload.latency_ms = Math.trunc(ms);
|
|
97
|
+
}
|
|
98
|
+
if (obs.status_message && resultStatus === 'ERROR') {
|
|
99
|
+
payload.error_code = _truncate(obs.status_message);
|
|
100
|
+
}
|
|
101
|
+
if (obs.model) {
|
|
102
|
+
payload.tool_version = obs.model;
|
|
103
|
+
}
|
|
104
|
+
if (obs.level && KNOWN_LEVELS.has(obs.level) && obs.level !== 'DEFAULT') {
|
|
105
|
+
payload.level = obs.level;
|
|
106
|
+
}
|
|
107
|
+
return makeEventDraft({
|
|
108
|
+
event_type: TOOL_CALL_EVENT,
|
|
109
|
+
actor: `langfuse://${kind}/${obs.name ?? 'unnamed'}`,
|
|
110
|
+
payload,
|
|
111
|
+
subject_ref: obs.user_id ? makeSubjectRef('opaque', obs.user_id) : null,
|
|
112
|
+
session_id: obs.trace_id,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
static fromDict(raw, options) {
|
|
116
|
+
const required = ['id', 'trace_id', 'type'];
|
|
117
|
+
const missing = required.filter((k) => !(k in raw));
|
|
118
|
+
if (missing.length > 0) {
|
|
119
|
+
throw new AdapterTranslationError(`LangFuse observation dict missing required fields: ${JSON.stringify(missing.sort())}`);
|
|
120
|
+
}
|
|
121
|
+
const parseDt = (value) => {
|
|
122
|
+
if (value == null)
|
|
123
|
+
return null;
|
|
124
|
+
if (value instanceof Date)
|
|
125
|
+
return value;
|
|
126
|
+
if (typeof value === 'string') {
|
|
127
|
+
const normalized = value.endsWith('Z') ? value.replace('Z', '+00:00') : value;
|
|
128
|
+
const d = new Date(normalized);
|
|
129
|
+
if (Number.isNaN(d.getTime())) {
|
|
130
|
+
throw new AdapterTranslationError(`unparsable datetime ${JSON.stringify(value)}`);
|
|
131
|
+
}
|
|
132
|
+
return d;
|
|
133
|
+
}
|
|
134
|
+
throw new AdapterTranslationError(`datetime field has type ${typeof value}`);
|
|
135
|
+
};
|
|
136
|
+
const metadata = raw.metadata ?? {};
|
|
137
|
+
if (typeof metadata !== 'object' || Array.isArray(metadata)) {
|
|
138
|
+
throw new AdapterTranslationError('metadata must be an object');
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
id: String(raw.id),
|
|
142
|
+
trace_id: String(raw.trace_id),
|
|
143
|
+
type: String(raw.type),
|
|
144
|
+
name: raw.name ?? null,
|
|
145
|
+
start_time: parseDt(raw.start_time),
|
|
146
|
+
end_time: parseDt(raw.end_time),
|
|
147
|
+
input: raw.input,
|
|
148
|
+
output: raw.output,
|
|
149
|
+
level: raw.level ?? null,
|
|
150
|
+
metadata,
|
|
151
|
+
status_message: raw.status_message ?? null,
|
|
152
|
+
model: raw.model ?? null,
|
|
153
|
+
user_id: options?.user_id ?? null,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=langfuse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langfuse.js","sourceRoot":"","sources":["../../src/adapters/langfuse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangSmith → Attestplane evidence-event adapter (TypeScript port of
|
|
3
|
+
* `sdk/python/src/attestplane/adapters/langsmith.py`).
|
|
4
|
+
*
|
|
5
|
+
* Byte-identical translation semantics with the Python adapter:
|
|
6
|
+
* given the same LangSmith Run, both adapters produce the same
|
|
7
|
+
* EventDraft fields (event_type, actor, payload, subject_ref,
|
|
8
|
+
* session_id, reference_db_ref).
|
|
9
|
+
*
|
|
10
|
+
* Pure function per GenericRuntimeAdapter contract: no I/O, no
|
|
11
|
+
* LangSmith API calls.
|
|
12
|
+
*
|
|
13
|
+
* Trust boundary (ADR-0004 § 4): adapter consumes the public
|
|
14
|
+
* LangSmith Run shape, not LangChain proprietary code. LangChain
|
|
15
|
+
* does not endorse this adapter; see docs/policy/forbidden_claims.md
|
|
16
|
+
* § G.
|
|
17
|
+
*
|
|
18
|
+
* Redaction (ADR-0008 § Boundary anti-requirements):
|
|
19
|
+
* - Raw inputs / outputs are NEVER copied to payload — only SHA-256
|
|
20
|
+
* hashes go in `arguments_hash` / `result_hash`.
|
|
21
|
+
* - Error strings are truncated to 200 chars to limit PII leakage.
|
|
22
|
+
* - end_user_id (from LangSmith metadata.user_id) is wrapped in
|
|
23
|
+
* SubjectRef(scheme="opaque").
|
|
24
|
+
*
|
|
25
|
+
* Run type → event_type mapping is identical to the Python adapter:
|
|
26
|
+
* all run_types map to `tool_call_event` in v1; payload.kind carries
|
|
27
|
+
* the LangSmith run_type for downstream filtering.
|
|
28
|
+
*/
|
|
29
|
+
import { GenericRuntimeAdapter } from '../adapters.js';
|
|
30
|
+
import { type EventDraft } from '../types.js';
|
|
31
|
+
export interface LangSmithRun {
|
|
32
|
+
readonly id: string;
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly run_type: string;
|
|
35
|
+
readonly start_time: Date;
|
|
36
|
+
readonly end_time?: Date | null;
|
|
37
|
+
readonly inputs?: Record<string, unknown>;
|
|
38
|
+
readonly outputs?: Record<string, unknown> | null;
|
|
39
|
+
readonly error?: string | null;
|
|
40
|
+
readonly trace_id?: string | null;
|
|
41
|
+
readonly parent_run_id?: string | null;
|
|
42
|
+
readonly status?: string | null;
|
|
43
|
+
readonly tags?: readonly string[];
|
|
44
|
+
readonly metadata?: Record<string, unknown>;
|
|
45
|
+
readonly end_user_id?: string | null;
|
|
46
|
+
}
|
|
47
|
+
export declare class LangSmithAdapter extends GenericRuntimeAdapter<LangSmithRun> {
|
|
48
|
+
readonly runtime_name = "langsmith";
|
|
49
|
+
readonly schema_version = 1;
|
|
50
|
+
translate(runtime_event: LangSmithRun): EventDraft;
|
|
51
|
+
static fromDict(raw: Record<string, unknown>): LangSmithRun;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=langsmith.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"langsmith.d.ts","sourceRoot":"","sources":["../../src/adapters/langsmith.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAA2B,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,EAAE,KAAK,UAAU,EAAkC,MAAM,aAAa,CAAC;AAY9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAmCD,qBAAa,gBAAiB,SAAQ,qBAAqB,CAAC,YAAY,CAAC;IACvE,QAAQ,CAAC,YAAY,eAAe;IACpC,QAAQ,CAAC,cAAc,KAAK;IAE5B,SAAS,CAAC,aAAa,EAAE,YAAY,GAAG,UAAU;IAyDlD,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY;CAoD5D"}
|