@attested-intelligence/aga-mcp-server 0.1.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/AGA_MCP_SERVER_SPEC.md +632 -0
- package/LICENSE +21 -0
- package/README.md +42 -0
- package/dist/core/artifact.d.ts +19 -0
- package/dist/core/artifact.d.ts.map +1 -0
- package/dist/core/artifact.js +27 -0
- package/dist/core/artifact.js.map +1 -0
- package/dist/core/attestation.d.ts +19 -0
- package/dist/core/attestation.d.ts.map +1 -0
- package/dist/core/attestation.js +12 -0
- package/dist/core/attestation.js.map +1 -0
- package/dist/core/behavioral.d.ts +45 -0
- package/dist/core/behavioral.d.ts.map +1 -0
- package/dist/core/behavioral.js +88 -0
- package/dist/core/behavioral.js.map +1 -0
- package/dist/core/bundle.d.ts +13 -0
- package/dist/core/bundle.d.ts.map +1 -0
- package/dist/core/bundle.js +31 -0
- package/dist/core/bundle.js.map +1 -0
- package/dist/core/chain.d.ts +13 -0
- package/dist/core/chain.d.ts.map +1 -0
- package/dist/core/chain.js +63 -0
- package/dist/core/chain.js.map +1 -0
- package/dist/core/checkpoint.d.ts +8 -0
- package/dist/core/checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint.js +21 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/delegation.d.ts +37 -0
- package/dist/core/delegation.d.ts.map +1 -0
- package/dist/core/delegation.js +104 -0
- package/dist/core/delegation.js.map +1 -0
- package/dist/core/disclosure.d.ts +12 -0
- package/dist/core/disclosure.d.ts.map +1 -0
- package/dist/core/disclosure.js +25 -0
- package/dist/core/disclosure.js.map +1 -0
- package/dist/core/index.d.ts +12 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/portal.d.ts +28 -0
- package/dist/core/portal.d.ts.map +1 -0
- package/dist/core/portal.js +95 -0
- package/dist/core/portal.js.map +1 -0
- package/dist/core/quarantine.d.ts +8 -0
- package/dist/core/quarantine.d.ts.map +1 -0
- package/dist/core/quarantine.js +13 -0
- package/dist/core/quarantine.js.map +1 -0
- package/dist/core/receipt.d.ts +17 -0
- package/dist/core/receipt.d.ts.map +1 -0
- package/dist/core/receipt.js +17 -0
- package/dist/core/receipt.js.map +1 -0
- package/dist/core/subject.d.ts +4 -0
- package/dist/core/subject.d.ts.map +1 -0
- package/dist/core/subject.js +9 -0
- package/dist/core/subject.js.map +1 -0
- package/dist/core/types.d.ts +167 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/crypto/hash.d.ts +9 -0
- package/dist/crypto/hash.d.ts.map +1 -0
- package/dist/crypto/hash.js +30 -0
- package/dist/crypto/hash.js.map +1 -0
- package/dist/crypto/index.d.ts +6 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +6 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/merkle.d.ts +8 -0
- package/dist/crypto/merkle.d.ts.map +1 -0
- package/dist/crypto/merkle.js +42 -0
- package/dist/crypto/merkle.js.map +1 -0
- package/dist/crypto/salt.d.ts +5 -0
- package/dist/crypto/salt.d.ts.map +1 -0
- package/dist/crypto/salt.js +14 -0
- package/dist/crypto/salt.js.map +1 -0
- package/dist/crypto/sign.d.ts +11 -0
- package/dist/crypto/sign.d.ts.map +1 -0
- package/dist/crypto/sign.js +37 -0
- package/dist/crypto/sign.js.map +1 -0
- package/dist/crypto/types.d.ts +24 -0
- package/dist/crypto/types.d.ts.map +1 -0
- package/dist/crypto/types.js +2 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/governance.d.ts +27 -0
- package/dist/middleware/governance.d.ts.map +1 -0
- package/dist/middleware/governance.js +65 -0
- package/dist/middleware/governance.js.map +1 -0
- package/dist/middleware/index.d.ts +2 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +2 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +369 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +3 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/interface.d.ts +21 -0
- package/dist/storage/interface.d.ts.map +1 -0
- package/dist/storage/interface.js +2 -0
- package/dist/storage/interface.js.map +1 -0
- package/dist/storage/memory.d.ts +26 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +24 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/sqlite.d.ts +25 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +44 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/utils/canonical.d.ts +3 -0
- package/dist/utils/canonical.d.ts.map +1 -0
- package/dist/utils/canonical.js +17 -0
- package/dist/utils/canonical.js.map +1 -0
- package/dist/utils/constants.d.ts +4 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +4 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/timestamp.d.ts +4 -0
- package/dist/utils/timestamp.d.ts.map +1 -0
- package/dist/utils/timestamp.js +13 -0
- package/dist/utils/timestamp.js.map +1 -0
- package/dist/utils/uuid.d.ts +2 -0
- package/dist/utils/uuid.d.ts.map +1 -0
- package/dist/utils/uuid.js +3 -0
- package/dist/utils/uuid.js.map +1 -0
- package/package.json +45 -0
- package/src/core/artifact.ts +45 -0
- package/src/core/attestation.ts +33 -0
- package/src/core/behavioral.ts +132 -0
- package/src/core/bundle.ts +31 -0
- package/src/core/chain.ts +72 -0
- package/src/core/checkpoint.ts +22 -0
- package/src/core/delegation.ts +146 -0
- package/src/core/disclosure.ts +32 -0
- package/src/core/index.ts +11 -0
- package/src/core/portal.ts +96 -0
- package/src/core/quarantine.ts +16 -0
- package/src/core/receipt.ts +33 -0
- package/src/core/subject.ts +11 -0
- package/src/core/types.ts +244 -0
- package/src/crypto/hash.ts +33 -0
- package/src/crypto/index.ts +5 -0
- package/src/crypto/merkle.ts +43 -0
- package/src/crypto/salt.ts +18 -0
- package/src/crypto/sign.ts +35 -0
- package/src/crypto/types.ts +19 -0
- package/src/index.ts +12 -0
- package/src/middleware/governance.ts +95 -0
- package/src/middleware/index.ts +1 -0
- package/src/server.ts +436 -0
- package/src/storage/index.ts +3 -0
- package/src/storage/interface.ts +21 -0
- package/src/storage/memory.ts +27 -0
- package/src/storage/sqlite.ts +45 -0
- package/src/tools/README.md +13 -0
- package/src/utils/canonical.ts +14 -0
- package/src/utils/constants.ts +3 -0
- package/src/utils/timestamp.ts +12 -0
- package/src/utils/uuid.ts +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @attested-intelligence/aga-mcp-server
|
|
2
|
+
|
|
3
|
+
MCP server implementing the Attested Governance Artifact (AGA) protocol.
|
|
4
|
+
|
|
5
|
+
**Patent Pending:** USPTO Application No. 19/433,835
|
|
6
|
+
**Referenced in:** NIST-2025-0035, NCCoE AI Agent Identity and Authorization
|
|
7
|
+
|
|
8
|
+
## What It Does
|
|
9
|
+
|
|
10
|
+
This server acts as a **Portal** (enforcement boundary) for AI agents. Every tool call is attested, measured, and logged to a tamper-evident continuity chain.
|
|
11
|
+
|
|
12
|
+
| MCP Tool | Patent Claim | Description |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `attest_subject` | 1a-1d | Attest and seal a policy artifact |
|
|
15
|
+
| `measure_integrity` | 1e-1g | Measure, compare, enforce, receipt |
|
|
16
|
+
| `revoke_artifact` | NCCoE 3b | Mid-session artifact revocation |
|
|
17
|
+
| `request_claim` | 2 | Privacy-preserving disclosure |
|
|
18
|
+
| `init_chain` | 3a | Initialize continuity chain |
|
|
19
|
+
| `verify_chain` | 3c | Verify chain integrity |
|
|
20
|
+
| `create_checkpoint` | 3d-3f | Merkle tree + anchor |
|
|
21
|
+
| `generate_evidence_bundle` | 9 | Offline-verifiable package |
|
|
22
|
+
| `delegate_to_subagent` | NCCoE | Constrained sub-agent delegation |
|
|
23
|
+
| `measure_behavior` | NIST-2025-0035 | Behavioral drift detection |
|
|
24
|
+
| `get_portal_state` | — | Current enforcement status |
|
|
25
|
+
| `get_receipts` | — | Signed measurement receipts |
|
|
26
|
+
| `get_chain_events` | — | Continuity chain events |
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
npm install && npm run build && npm run demo
|
|
31
|
+
|
|
32
|
+
## Connect to Claude Desktop
|
|
33
|
+
|
|
34
|
+
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"aga": { "command": "node", "args": ["/path/to/dist/index.js"] }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
## License
|
|
42
|
+
MIT — NeuroCrypt / Attested Intelligence Holdings LLC
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { KeyPair, HashHex } from '../crypto/types.js';
|
|
2
|
+
import type { PolicyArtifact, SubjectIdentifier, EnforcementParams, DisclosurePolicy, EvidenceCommitmentRecord } from './types.js';
|
|
3
|
+
export interface ArtifactInput {
|
|
4
|
+
subject_identifier: SubjectIdentifier;
|
|
5
|
+
policy_reference: HashHex;
|
|
6
|
+
policy_version: number;
|
|
7
|
+
sealed_hash: HashHex;
|
|
8
|
+
seal_salt: string;
|
|
9
|
+
enforcement_parameters: EnforcementParams;
|
|
10
|
+
disclosure_policy: DisclosurePolicy;
|
|
11
|
+
evidence_commitments: EvidenceCommitmentRecord[];
|
|
12
|
+
issuer_keypair: KeyPair;
|
|
13
|
+
effective_timestamp?: string;
|
|
14
|
+
expiration_timestamp?: string | null;
|
|
15
|
+
}
|
|
16
|
+
export declare function generateArtifact(input: ArtifactInput): PolicyArtifact;
|
|
17
|
+
export declare function hashArtifact(a: PolicyArtifact): HashHex;
|
|
18
|
+
export declare function verifyArtifactSignature(a: PolicyArtifact, issuerPkHex: string): boolean;
|
|
19
|
+
//# sourceMappingURL=artifact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../src/core/artifact.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEnI,MAAM,WAAW,aAAa;IAC5B,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,iBAAiB,CAAC;IAC1C,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,oBAAoB,EAAE,wBAAwB,EAAE,CAAC;IACjD,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAerE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,CAAuC;AAE/F,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAGvF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { signStr, sigToB64, b64ToSig, pkToHex, hexToPk, verifyStr } from '../crypto/sign.js';
|
|
2
|
+
import { sha256Str } from '../crypto/hash.js';
|
|
3
|
+
import { canonicalize } from '../utils/canonical.js';
|
|
4
|
+
import { utcNow } from '../utils/timestamp.js';
|
|
5
|
+
import { SCHEMA_VERSION, PROTOCOL_VERSION } from '../utils/constants.js';
|
|
6
|
+
export function generateArtifact(input) {
|
|
7
|
+
const now = utcNow();
|
|
8
|
+
const unsigned = {
|
|
9
|
+
schema_version: SCHEMA_VERSION, protocol_version: PROTOCOL_VERSION,
|
|
10
|
+
subject_identifier: input.subject_identifier, policy_reference: input.policy_reference,
|
|
11
|
+
policy_version: input.policy_version, sealed_hash: input.sealed_hash,
|
|
12
|
+
seal_salt: input.seal_salt, issued_timestamp: now,
|
|
13
|
+
effective_timestamp: input.effective_timestamp ?? now,
|
|
14
|
+
expiration_timestamp: input.expiration_timestamp ?? null,
|
|
15
|
+
issuer_identifier: pkToHex(input.issuer_keypair.publicKey),
|
|
16
|
+
enforcement_parameters: input.enforcement_parameters,
|
|
17
|
+
disclosure_policy: input.disclosure_policy,
|
|
18
|
+
evidence_commitments: input.evidence_commitments,
|
|
19
|
+
};
|
|
20
|
+
return { ...unsigned, signature: sigToB64(signStr(canonicalize(unsigned), input.issuer_keypair.secretKey)) };
|
|
21
|
+
}
|
|
22
|
+
export function hashArtifact(a) { return sha256Str(canonicalize(a)); }
|
|
23
|
+
export function verifyArtifactSignature(a, issuerPkHex) {
|
|
24
|
+
const { signature, ...unsigned } = a;
|
|
25
|
+
return verifyStr(b64ToSig(signature), canonicalize(unsigned), hexToPk(issuerPkHex));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../src/core/artifact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAkBzE,MAAM,UAAU,gBAAgB,CAAC,KAAoB;IACnD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,MAAM,QAAQ,GAAsC;QAClD,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB;QAClE,kBAAkB,EAAE,KAAK,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACtF,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW;QACpE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,gBAAgB,EAAE,GAAG;QACjD,mBAAmB,EAAE,KAAK,CAAC,mBAAmB,IAAI,GAAG;QACrD,oBAAoB,EAAE,KAAK,CAAC,oBAAoB,IAAI,IAAI;QACxD,iBAAiB,EAAE,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC;QAC1D,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;QACpD,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;KACjD,CAAC;IACF,OAAO,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;AAC/G,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAiB,IAAa,OAAO,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/F,MAAM,UAAU,uBAAuB,CAAC,CAAiB,EAAE,WAAmB;IAC5E,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,GAAG,CAAC,CAAC;IACrC,OAAO,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { SubjectIdentifier, EvidenceCommitmentRecord } from './types.js';
|
|
2
|
+
import type { HashHex, SaltHex } from '../crypto/types.js';
|
|
3
|
+
export interface AttestationInput {
|
|
4
|
+
subject_identifier: SubjectIdentifier;
|
|
5
|
+
policy_reference: HashHex;
|
|
6
|
+
evidence_items: Array<{
|
|
7
|
+
label: string;
|
|
8
|
+
content: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export interface AttestationResult {
|
|
12
|
+
success: boolean;
|
|
13
|
+
sealed_hash: HashHex | null;
|
|
14
|
+
seal_salt: SaltHex | null;
|
|
15
|
+
evidence_commitments: EvidenceCommitmentRecord[];
|
|
16
|
+
rejection_reason: string | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function performAttestation(input: AttestationInput): AttestationResult;
|
|
19
|
+
//# sourceMappingURL=attestation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../../src/core/attestation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,oBAAoB,EAAE,wBAAwB,EAAE,CAAC;IACjD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAa7E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { saltedCommitment, generateSalt } from '../crypto/salt.js';
|
|
2
|
+
import { sha256HexCat } from '../crypto/hash.js';
|
|
3
|
+
export function performAttestation(input) {
|
|
4
|
+
const evidence_commitments = input.evidence_items.map(item => {
|
|
5
|
+
const { commitment, salt } = saltedCommitment(item.content);
|
|
6
|
+
return { commitment, salt, label: item.label };
|
|
7
|
+
});
|
|
8
|
+
const seal_salt = generateSalt();
|
|
9
|
+
const sealed_hash = sha256HexCat(input.subject_identifier.bytes_hash, input.subject_identifier.metadata_hash, input.policy_reference, seal_salt);
|
|
10
|
+
return { success: true, sealed_hash, seal_salt, evidence_commitments, rejection_reason: null };
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=attestation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attestation.js","sourceRoot":"","sources":["../../src/core/attestation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAkBjD,MAAM,UAAU,kBAAkB,CAAC,KAAuB;IACxD,MAAM,oBAAoB,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC3D,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5D,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,WAAW,GAAG,YAAY,CAC9B,KAAK,CAAC,kBAAkB,CAAC,UAAU,EACnC,KAAK,CAAC,kBAAkB,CAAC,aAAa,EACtC,KAAK,CAAC,gBAAgB,EACtB,SAAS,CACV,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;AACjG,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { HashHex } from '../crypto/types.js';
|
|
2
|
+
export interface ToolInvocation {
|
|
3
|
+
tool_name: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
args_hash: HashHex;
|
|
6
|
+
}
|
|
7
|
+
export interface BehavioralBaseline {
|
|
8
|
+
/** Allowed tools in this policy context */
|
|
9
|
+
permitted_tools: string[];
|
|
10
|
+
/** Maximum invocations per tool per measurement window */
|
|
11
|
+
rate_limits: Record<string, number>;
|
|
12
|
+
/** Forbidden tool sequences (e.g., read_secret then send_email) */
|
|
13
|
+
forbidden_sequences: string[][];
|
|
14
|
+
/** Measurement window in milliseconds */
|
|
15
|
+
window_ms: number;
|
|
16
|
+
}
|
|
17
|
+
export interface BehavioralMeasurement {
|
|
18
|
+
window_start: string;
|
|
19
|
+
window_end: string;
|
|
20
|
+
invocations: ToolInvocation[];
|
|
21
|
+
violations: BehavioralViolation[];
|
|
22
|
+
behavioral_hash: HashHex;
|
|
23
|
+
drift_detected: boolean;
|
|
24
|
+
}
|
|
25
|
+
export type BehavioralViolation = {
|
|
26
|
+
type: 'UNAUTHORIZED_TOOL';
|
|
27
|
+
tool: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: 'RATE_EXCEEDED';
|
|
30
|
+
tool: string;
|
|
31
|
+
count: number;
|
|
32
|
+
limit: number;
|
|
33
|
+
} | {
|
|
34
|
+
type: 'FORBIDDEN_SEQUENCE';
|
|
35
|
+
sequence: string[];
|
|
36
|
+
};
|
|
37
|
+
export declare class BehavioralMonitor {
|
|
38
|
+
private invocations;
|
|
39
|
+
private baseline;
|
|
40
|
+
setBaseline(baseline: BehavioralBaseline): void;
|
|
41
|
+
recordInvocation(toolName: string, argsHash: HashHex): void;
|
|
42
|
+
measure(): BehavioralMeasurement;
|
|
43
|
+
reset(): void;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=behavioral.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavioral.d.ts","sourceRoot":"","sources":["../../src/core/behavioral.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,2CAA2C;IAC3C,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,mEAAmE;IACnE,mBAAmB,EAAE,MAAM,EAAE,EAAE,CAAC;IAChC,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,QAAQ,CAAmC;IAEnD,WAAW,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI;IAI/C,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAQ3D,OAAO,IAAI,qBAAqB;IA0DhC,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behavioral Drift Detection.
|
|
3
|
+
* NIST-2025-0035: "Governance mechanisms must measure behavioral outputs
|
|
4
|
+
* and decision patterns in addition to static artifacts."
|
|
5
|
+
*
|
|
6
|
+
* Tracks tool invocation patterns and compares against a behavioral
|
|
7
|
+
* baseline sealed in the policy artifact.
|
|
8
|
+
*/
|
|
9
|
+
import { sha256Str } from '../crypto/hash.js';
|
|
10
|
+
export class BehavioralMonitor {
|
|
11
|
+
invocations = [];
|
|
12
|
+
baseline = null;
|
|
13
|
+
setBaseline(baseline) {
|
|
14
|
+
this.baseline = baseline;
|
|
15
|
+
}
|
|
16
|
+
recordInvocation(toolName, argsHash) {
|
|
17
|
+
this.invocations.push({
|
|
18
|
+
tool_name: toolName,
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
args_hash: argsHash,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
measure() {
|
|
24
|
+
if (!this.baseline) {
|
|
25
|
+
return {
|
|
26
|
+
window_start: '', window_end: '', invocations: [],
|
|
27
|
+
violations: [], behavioral_hash: sha256Str('no-baseline'),
|
|
28
|
+
drift_detected: false,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
const windowStart = now - this.baseline.window_ms;
|
|
33
|
+
const windowInvocations = this.invocations.filter(i => Date.parse(i.timestamp) >= windowStart);
|
|
34
|
+
const violations = [];
|
|
35
|
+
// Check unauthorized tools
|
|
36
|
+
for (const inv of windowInvocations) {
|
|
37
|
+
if (!this.baseline.permitted_tools.includes(inv.tool_name)) {
|
|
38
|
+
violations.push({ type: 'UNAUTHORIZED_TOOL', tool: inv.tool_name });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Check rate limits
|
|
42
|
+
const counts = {};
|
|
43
|
+
for (const inv of windowInvocations) {
|
|
44
|
+
counts[inv.tool_name] = (counts[inv.tool_name] ?? 0) + 1;
|
|
45
|
+
}
|
|
46
|
+
for (const [tool, count] of Object.entries(counts)) {
|
|
47
|
+
const limit = this.baseline.rate_limits[tool];
|
|
48
|
+
if (limit !== undefined && count > limit) {
|
|
49
|
+
violations.push({ type: 'RATE_EXCEEDED', tool, count, limit });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Check forbidden sequences
|
|
53
|
+
const toolSequence = windowInvocations.map(i => i.tool_name);
|
|
54
|
+
for (const forbidden of this.baseline.forbidden_sequences) {
|
|
55
|
+
if (containsSubsequence(toolSequence, forbidden)) {
|
|
56
|
+
violations.push({ type: 'FORBIDDEN_SEQUENCE', sequence: forbidden });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Compute behavioral hash (pattern fingerprint)
|
|
60
|
+
const pattern = windowInvocations.map(i => i.tool_name).join('|');
|
|
61
|
+
const behavioral_hash = sha256Str(pattern);
|
|
62
|
+
return {
|
|
63
|
+
window_start: new Date(windowStart).toISOString(),
|
|
64
|
+
window_end: new Date(now).toISOString(),
|
|
65
|
+
invocations: windowInvocations,
|
|
66
|
+
violations,
|
|
67
|
+
behavioral_hash,
|
|
68
|
+
drift_detected: violations.length > 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
reset() {
|
|
72
|
+
this.invocations = [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function containsSubsequence(haystack, needle) {
|
|
76
|
+
if (needle.length === 0)
|
|
77
|
+
return true;
|
|
78
|
+
let ni = 0;
|
|
79
|
+
for (const h of haystack) {
|
|
80
|
+
if (h === needle[ni]) {
|
|
81
|
+
ni++;
|
|
82
|
+
if (ni === needle.length)
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=behavioral.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"behavioral.js","sourceRoot":"","sources":["../../src/core/behavioral.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { KeyPair, MerkleInclusionProof } from '../crypto/types.js';
|
|
2
|
+
import type { EvidenceBundle, PolicyArtifact, SignedReceipt, CheckpointReference } from './types.js';
|
|
3
|
+
export declare function generateBundle(artifact: PolicyArtifact, receipts: SignedReceipt[], proofs: MerkleInclusionProof[], checkpoint: CheckpointReference, kp: KeyPair): EvidenceBundle;
|
|
4
|
+
export interface VerificationResult {
|
|
5
|
+
step1_artifact_sig: boolean;
|
|
6
|
+
step2_receipt_sigs: boolean;
|
|
7
|
+
step3_merkle_proofs: boolean;
|
|
8
|
+
step4_anchor: 'SKIPPED_OFFLINE' | boolean;
|
|
9
|
+
overall: boolean;
|
|
10
|
+
errors: string[];
|
|
11
|
+
}
|
|
12
|
+
export declare function verifyBundleOffline(bundle: EvidenceBundle, pinnedPkHex: string): VerificationResult;
|
|
13
|
+
//# sourceMappingURL=bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../src/core/bundle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAErG,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,UAAU,EAAE,mBAAmB,EAAE,EAAE,EAAE,OAAO,GAAG,cAAc,CAGhL;AAED,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,EAAE,OAAO,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAC;IACzD,mBAAmB,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,iBAAiB,GAAG,OAAO,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;CACpC;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAanG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { signStr, sigToB64, b64ToSig, hexToPk, verifyStr, pkToHex } from '../crypto/sign.js';
|
|
2
|
+
import { verifyProof } from '../crypto/merkle.js';
|
|
3
|
+
import { canonicalize } from '../utils/canonical.js';
|
|
4
|
+
export function generateBundle(artifact, receipts, proofs, checkpoint, kp) {
|
|
5
|
+
const unsigned = { artifact, receipts, merkle_proofs: proofs, checkpoint_reference: checkpoint, public_key: pkToHex(kp.publicKey) };
|
|
6
|
+
return { ...unsigned, bundle_signature: sigToB64(signStr(canonicalize(unsigned), kp.secretKey)) };
|
|
7
|
+
}
|
|
8
|
+
export function verifyBundleOffline(bundle, pinnedPkHex) {
|
|
9
|
+
const errors = [];
|
|
10
|
+
const { signature: aSig, ...aU } = bundle.artifact;
|
|
11
|
+
const s1 = verifyStr(b64ToSig(aSig), canonicalize(aU), hexToPk(pinnedPkHex));
|
|
12
|
+
if (!s1)
|
|
13
|
+
errors.push('Artifact signature failed');
|
|
14
|
+
let s2 = true;
|
|
15
|
+
for (const r of bundle.receipts) {
|
|
16
|
+
const { portal_signature, ...rU } = r;
|
|
17
|
+
if (!verifyStr(b64ToSig(portal_signature), canonicalize(rU), hexToPk(bundle.public_key))) {
|
|
18
|
+
s2 = false;
|
|
19
|
+
errors.push(`Receipt ${r.receipt_id} sig failed`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
let s3 = true;
|
|
23
|
+
for (const p of bundle.merkle_proofs) {
|
|
24
|
+
if (!verifyProof(p)) {
|
|
25
|
+
s3 = false;
|
|
26
|
+
errors.push(`Merkle proof failed leaf ${p.leafIndex}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { step1_artifact_sig: s1, step2_receipt_sigs: s2, step3_merkle_proofs: s3, step4_anchor: 'SKIPPED_OFFLINE', overall: s1 && s2 && s3, errors };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=bundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../src/core/bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAIrD,MAAM,UAAU,cAAc,CAAC,QAAwB,EAAE,QAAyB,EAAE,MAA8B,EAAE,UAA+B,EAAE,EAAW;IAC9J,MAAM,QAAQ,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,oBAAoB,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;IACpI,OAAO,EAAE,GAAG,QAAQ,EAAE,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;AACpG,CAAC;AAQD,MAAM,UAAU,mBAAmB,CAAC,MAAsB,EAAE,WAAmB;IAC7E,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;IACnD,MAAM,EAAE,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7E,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAClD,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YAAC,EAAE,GAAG,KAAK,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,UAAU,aAAa,CAAC,CAAC;QAAC,CAAC;IAC9J,CAAC;IACD,IAAI,EAAE,GAAG,IAAI,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YAAC,EAAE,GAAG,KAAK,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QAAC,CAAC;IAAC,CAAC;IACtI,OAAO,EAAE,kBAAkB,EAAE,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,mBAAmB,EAAE,EAAE,EAAE,YAAY,EAAE,iBAAiB,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC;AACvJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { KeyPair, HashHex } from '../crypto/types.js';
|
|
2
|
+
import type { ContinuityEvent, StructuralMetadata, EventType } from './types.js';
|
|
3
|
+
/** Leaf hash from structural metadata ONLY. Payload EXCLUDED. Uses "||" delimiter. */
|
|
4
|
+
export declare function computeLeafHash(m: StructuralMetadata): HashHex;
|
|
5
|
+
export declare function computePayloadHash(payload: unknown): HashHex;
|
|
6
|
+
export declare function createGenesisEvent(kp: KeyPair, specHash: HashHex): ContinuityEvent;
|
|
7
|
+
export declare function appendEvent(type: EventType, payload: unknown, prev: ContinuityEvent, kp: KeyPair): ContinuityEvent;
|
|
8
|
+
export declare function verifyChainIntegrity(events: ContinuityEvent[]): {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
brokenAt: number | null;
|
|
11
|
+
error: string | null;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/core/chain.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAkB,kBAAkB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjG,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAK9D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE5D;AAqBD,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,eAAe,CAMlF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,OAAO,GAAG,eAAe,CAElH;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG;IAC/D,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/D,CAiBA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { sha256Str } from '../crypto/hash.js';
|
|
2
|
+
import { signStr, sigToB64, pkToHex } from '../crypto/sign.js';
|
|
3
|
+
import { canonicalize } from '../utils/canonical.js';
|
|
4
|
+
import { utcNow } from '../utils/timestamp.js';
|
|
5
|
+
import { uuid } from '../utils/uuid.js';
|
|
6
|
+
import { SCHEMA_VERSION, PROTOCOL_VERSION, TAXONOMY_VERSION } from '../utils/constants.js';
|
|
7
|
+
/** Leaf hash from structural metadata ONLY. Payload EXCLUDED. Uses "||" delimiter. */
|
|
8
|
+
export function computeLeafHash(m) {
|
|
9
|
+
return sha256Str([
|
|
10
|
+
m.schema_version, m.protocol_version, m.event_type, m.event_id,
|
|
11
|
+
String(m.sequence_number), m.timestamp, m.previous_leaf_hash ?? 'NULL'
|
|
12
|
+
].join('||'));
|
|
13
|
+
}
|
|
14
|
+
export function computePayloadHash(payload) {
|
|
15
|
+
return sha256Str(canonicalize(payload));
|
|
16
|
+
}
|
|
17
|
+
function buildEvent(type, payload, seq, prevLeaf, kp) {
|
|
18
|
+
const id = uuid(), ts = utcNow();
|
|
19
|
+
const meta = {
|
|
20
|
+
schema_version: SCHEMA_VERSION, protocol_version: PROTOCOL_VERSION,
|
|
21
|
+
event_type: type, event_id: id, sequence_number: seq,
|
|
22
|
+
timestamp: ts, previous_leaf_hash: prevLeaf,
|
|
23
|
+
};
|
|
24
|
+
const leafHash = computeLeafHash(meta);
|
|
25
|
+
const payloadHash = computePayloadHash(payload);
|
|
26
|
+
const sig = signStr(canonicalize({ ...meta, leaf_hash: leafHash, payload, payload_hash: payloadHash }), kp.secretKey);
|
|
27
|
+
return {
|
|
28
|
+
schema_version: SCHEMA_VERSION, protocol_version: PROTOCOL_VERSION,
|
|
29
|
+
event_type: type, event_id: id, sequence_number: seq,
|
|
30
|
+
timestamp: ts, previous_leaf_hash: prevLeaf,
|
|
31
|
+
leaf_hash: leafHash, payload, payload_hash: payloadHash,
|
|
32
|
+
event_signature: sigToB64(sig),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function createGenesisEvent(kp, specHash) {
|
|
36
|
+
const payload = {
|
|
37
|
+
protocol_version: PROTOCOL_VERSION, taxonomy_version: TAXONOMY_VERSION,
|
|
38
|
+
root_fingerprint: pkToHex(kp.publicKey), specification_hash: specHash, marker: 'GENESIS',
|
|
39
|
+
};
|
|
40
|
+
return buildEvent('GENESIS', payload, 0, null, kp);
|
|
41
|
+
}
|
|
42
|
+
export function appendEvent(type, payload, prev, kp) {
|
|
43
|
+
return buildEvent(type, payload, prev.sequence_number + 1, prev.leaf_hash, kp);
|
|
44
|
+
}
|
|
45
|
+
export function verifyChainIntegrity(events) {
|
|
46
|
+
for (let i = 0; i < events.length; i++) {
|
|
47
|
+
const e = events[i];
|
|
48
|
+
const meta = {
|
|
49
|
+
schema_version: e.schema_version, protocol_version: e.protocol_version,
|
|
50
|
+
event_type: e.event_type, event_id: e.event_id,
|
|
51
|
+
sequence_number: e.sequence_number, timestamp: e.timestamp,
|
|
52
|
+
previous_leaf_hash: e.previous_leaf_hash,
|
|
53
|
+
};
|
|
54
|
+
if (e.leaf_hash !== computeLeafHash(meta))
|
|
55
|
+
return { valid: false, brokenAt: e.sequence_number, error: `Leaf hash mismatch at seq ${e.sequence_number}` };
|
|
56
|
+
if (i > 0 && e.previous_leaf_hash !== events[i - 1].leaf_hash)
|
|
57
|
+
return { valid: false, brokenAt: e.sequence_number, error: `Chain linkage broken at seq ${e.sequence_number}` };
|
|
58
|
+
if (e.payload_hash !== computePayloadHash(e.payload))
|
|
59
|
+
return { valid: false, brokenAt: e.sequence_number, error: `Payload hash mismatch at seq ${e.sequence_number}` };
|
|
60
|
+
}
|
|
61
|
+
return { valid: true, brokenAt: null, error: null };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../../src/core/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ContinuityEvent, CheckpointReference, AnchorBatchPayload } from './types.js';
|
|
2
|
+
import type { MerkleInclusionProof } from '../crypto/types.js';
|
|
3
|
+
export declare function createCheckpoint(events: ContinuityEvent[], anchorNetwork?: string): {
|
|
4
|
+
checkpoint: CheckpointReference;
|
|
5
|
+
payload: AnchorBatchPayload;
|
|
6
|
+
};
|
|
7
|
+
export declare function eventInclusionProof(events: ContinuityEvent[], targetSeq: number): MerkleInclusionProof;
|
|
8
|
+
//# sourceMappingURL=checkpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/core/checkpoint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE/D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,aAAa,SAAU,GAAG;IAAE,UAAU,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CASrJ;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,oBAAoB,CAItG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { buildMerkleTree, inclusionProof } from '../crypto/merkle.js';
|
|
2
|
+
import { utcNow } from '../utils/timestamp.js';
|
|
3
|
+
import { uuid } from '../utils/uuid.js';
|
|
4
|
+
export function createCheckpoint(events, anchorNetwork = 'local') {
|
|
5
|
+
if (!events.length)
|
|
6
|
+
throw new Error('No events to checkpoint');
|
|
7
|
+
const { root } = buildMerkleTree(events.map(e => e.leaf_hash));
|
|
8
|
+
const checkpoint = {
|
|
9
|
+
merkle_root: root, batch_start_sequence: events[0].sequence_number,
|
|
10
|
+
batch_end_sequence: events[events.length - 1].sequence_number,
|
|
11
|
+
anchor_network: anchorNetwork, transaction_id: `${anchorNetwork}:${uuid()}`, timestamp: utcNow(),
|
|
12
|
+
};
|
|
13
|
+
return { checkpoint, payload: { checkpoint_reference: checkpoint, leaf_count: events.length } };
|
|
14
|
+
}
|
|
15
|
+
export function eventInclusionProof(events, targetSeq) {
|
|
16
|
+
const idx = events.findIndex(e => e.sequence_number === targetSeq);
|
|
17
|
+
if (idx === -1)
|
|
18
|
+
throw new Error(`Sequence ${targetSeq} not in batch`);
|
|
19
|
+
return inclusionProof(events.map(e => e.leaf_hash), idx);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../src/core/checkpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAIxC,MAAM,UAAU,gBAAgB,CAAC,MAAyB,EAAE,aAAa,GAAG,OAAO;IACjF,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/D,MAAM,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAwB;QACtC,WAAW,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,eAAe;QAClE,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,eAAe;QAC7D,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,aAAa,IAAI,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;KACjG,CAAC;IACF,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,oBAAoB,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;AAClG,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAyB,EAAE,SAAiB;IAC9E,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC;IACnE,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,YAAY,SAAS,eAAe,CAAC,CAAC;IACtE,OAAO,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PolicyArtifact, EnforcementAction, MeasurementType } from './types.js';
|
|
2
|
+
import type { KeyPair } from '../crypto/types.js';
|
|
3
|
+
export interface DelegationRequest {
|
|
4
|
+
/** Subset of parent's enforcement triggers */
|
|
5
|
+
enforcement_triggers: EnforcementAction[];
|
|
6
|
+
/** Subset of parent's measurement types */
|
|
7
|
+
measurement_types: MeasurementType[];
|
|
8
|
+
/** Requested TTL in seconds (will be clamped to parent remaining) */
|
|
9
|
+
requested_ttl_seconds: number;
|
|
10
|
+
/** Description of the delegation purpose */
|
|
11
|
+
delegation_purpose: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DelegationResult {
|
|
14
|
+
success: boolean;
|
|
15
|
+
child_artifact?: PolicyArtifact;
|
|
16
|
+
child_artifact_hash?: string;
|
|
17
|
+
parent_artifact_hash: string;
|
|
18
|
+
effective_ttl_seconds?: number;
|
|
19
|
+
scope_reduction?: {
|
|
20
|
+
triggers_removed: string[];
|
|
21
|
+
measurement_types_removed: string[];
|
|
22
|
+
};
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Derive a constrained artifact from a parent artifact.
|
|
27
|
+
* Key rule: scope can only diminish, never expand.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deriveArtifact(parentArtifact: PolicyArtifact, request: DelegationRequest, issuerKP: KeyPair): DelegationResult;
|
|
30
|
+
/**
|
|
31
|
+
* Validate that a child artifact is a valid delegation of a parent.
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateDelegation(parent: PolicyArtifact, child: PolicyArtifact): {
|
|
34
|
+
valid: boolean;
|
|
35
|
+
errors: string[];
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=delegation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegation.d.ts","sourceRoot":"","sources":["../../src/core/delegation.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,8CAA8C;IAC9C,oBAAoB,EAAE,iBAAiB,EAAE,CAAC;IAC1C,2CAA2C;IAC3C,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,qEAAqE;IACrE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,4CAA4C;IAC5C,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,eAAe,CAAC,EAAE;QAChB,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,yBAAyB,EAAE,MAAM,EAAE,CAAC;KACrC,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,OAAO,GAChB,gBAAgB,CAoElB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CA0BtH"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constrained Sub-Agent Delegation.
|
|
3
|
+
* NCCoE filing: "Scope can only diminish through delegation, never expand."
|
|
4
|
+
*
|
|
5
|
+
* Primary agent's portal issues a derived artifact to secondary agent:
|
|
6
|
+
* - TTL <= parent's remaining TTL
|
|
7
|
+
* - Scope can only diminish, never expand
|
|
8
|
+
* - Secondary's genesis links to parent's chain
|
|
9
|
+
*/
|
|
10
|
+
import { generateArtifact, hashArtifact } from './artifact.js';
|
|
11
|
+
import { isExpired } from '../utils/timestamp.js';
|
|
12
|
+
/**
|
|
13
|
+
* Derive a constrained artifact from a parent artifact.
|
|
14
|
+
* Key rule: scope can only diminish, never expand.
|
|
15
|
+
*/
|
|
16
|
+
export function deriveArtifact(parentArtifact, request, issuerKP) {
|
|
17
|
+
const parentHash = hashArtifact(parentArtifact);
|
|
18
|
+
// Validate parent is not expired
|
|
19
|
+
if (isExpired(parentArtifact.issued_timestamp, parentArtifact.enforcement_parameters.ttl_seconds)) {
|
|
20
|
+
return { success: false, parent_artifact_hash: parentHash, error: 'Parent artifact TTL has expired' };
|
|
21
|
+
}
|
|
22
|
+
// Calculate parent remaining TTL
|
|
23
|
+
const parentIssuedMs = Date.parse(parentArtifact.issued_timestamp);
|
|
24
|
+
const parentExpiresMs = parentIssuedMs + (parentArtifact.enforcement_parameters.ttl_seconds * 1000);
|
|
25
|
+
const remainingMs = parentExpiresMs - Date.now();
|
|
26
|
+
const remainingSeconds = Math.max(0, Math.floor(remainingMs / 1000));
|
|
27
|
+
// Clamp child TTL to parent remaining
|
|
28
|
+
const effectiveTTL = Math.min(request.requested_ttl_seconds, remainingSeconds);
|
|
29
|
+
if (effectiveTTL <= 0) {
|
|
30
|
+
return { success: false, parent_artifact_hash: parentHash, error: 'No remaining TTL to delegate' };
|
|
31
|
+
}
|
|
32
|
+
// Validate triggers are subset of parent
|
|
33
|
+
const parentTriggers = new Set(parentArtifact.enforcement_parameters.enforcement_triggers);
|
|
34
|
+
const invalidTriggers = request.enforcement_triggers.filter(t => !parentTriggers.has(t));
|
|
35
|
+
if (invalidTriggers.length > 0) {
|
|
36
|
+
return { success: false, parent_artifact_hash: parentHash, error: `Cannot expand scope: triggers [${invalidTriggers.join(', ')}] not in parent` };
|
|
37
|
+
}
|
|
38
|
+
// Validate measurement types are subset of parent
|
|
39
|
+
const parentTypes = new Set(parentArtifact.enforcement_parameters.measurement_types);
|
|
40
|
+
const invalidTypes = request.measurement_types.filter(t => !parentTypes.has(t));
|
|
41
|
+
if (invalidTypes.length > 0) {
|
|
42
|
+
return { success: false, parent_artifact_hash: parentHash, error: `Cannot expand scope: measurement types [${invalidTypes.join(', ')}] not in parent` };
|
|
43
|
+
}
|
|
44
|
+
// Build constrained child artifact
|
|
45
|
+
const childArtifact = generateArtifact({
|
|
46
|
+
subject_identifier: parentArtifact.subject_identifier,
|
|
47
|
+
policy_reference: parentArtifact.policy_reference,
|
|
48
|
+
policy_version: parentArtifact.policy_version,
|
|
49
|
+
sealed_hash: parentArtifact.sealed_hash,
|
|
50
|
+
seal_salt: parentArtifact.seal_salt,
|
|
51
|
+
enforcement_parameters: {
|
|
52
|
+
measurement_cadence_ms: parentArtifact.enforcement_parameters.measurement_cadence_ms,
|
|
53
|
+
ttl_seconds: effectiveTTL,
|
|
54
|
+
enforcement_triggers: request.enforcement_triggers,
|
|
55
|
+
re_attestation_required: parentArtifact.enforcement_parameters.re_attestation_required,
|
|
56
|
+
measurement_types: request.measurement_types,
|
|
57
|
+
},
|
|
58
|
+
disclosure_policy: parentArtifact.disclosure_policy, // cannot expand
|
|
59
|
+
evidence_commitments: parentArtifact.evidence_commitments,
|
|
60
|
+
issuer_keypair: issuerKP,
|
|
61
|
+
});
|
|
62
|
+
// Track scope reduction
|
|
63
|
+
const triggersRemoved = [...parentTriggers].filter(t => !request.enforcement_triggers.includes(t));
|
|
64
|
+
const typesRemoved = [...parentTypes].filter(t => !request.measurement_types.includes(t));
|
|
65
|
+
return {
|
|
66
|
+
success: true,
|
|
67
|
+
child_artifact: childArtifact,
|
|
68
|
+
child_artifact_hash: hashArtifact(childArtifact),
|
|
69
|
+
parent_artifact_hash: parentHash,
|
|
70
|
+
effective_ttl_seconds: effectiveTTL,
|
|
71
|
+
scope_reduction: {
|
|
72
|
+
triggers_removed: triggersRemoved,
|
|
73
|
+
measurement_types_removed: typesRemoved,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Validate that a child artifact is a valid delegation of a parent.
|
|
79
|
+
*/
|
|
80
|
+
export function validateDelegation(parent, child) {
|
|
81
|
+
const errors = [];
|
|
82
|
+
// TTL must be <= parent TTL
|
|
83
|
+
if (child.enforcement_parameters.ttl_seconds > parent.enforcement_parameters.ttl_seconds) {
|
|
84
|
+
errors.push(`Child TTL (${child.enforcement_parameters.ttl_seconds}s) exceeds parent (${parent.enforcement_parameters.ttl_seconds}s)`);
|
|
85
|
+
}
|
|
86
|
+
// Triggers must be subset
|
|
87
|
+
const pTriggers = new Set(parent.enforcement_parameters.enforcement_triggers);
|
|
88
|
+
for (const t of child.enforcement_parameters.enforcement_triggers) {
|
|
89
|
+
if (!pTriggers.has(t))
|
|
90
|
+
errors.push(`Child trigger '${t}' not in parent scope`);
|
|
91
|
+
}
|
|
92
|
+
// Measurement types must be subset
|
|
93
|
+
const pTypes = new Set(parent.enforcement_parameters.measurement_types);
|
|
94
|
+
for (const t of child.enforcement_parameters.measurement_types) {
|
|
95
|
+
if (!pTypes.has(t))
|
|
96
|
+
errors.push(`Child measurement type '${t}' not in parent scope`);
|
|
97
|
+
}
|
|
98
|
+
// Subject must match
|
|
99
|
+
if (child.subject_identifier.bytes_hash !== parent.subject_identifier.bytes_hash) {
|
|
100
|
+
errors.push('Child subject bytes_hash does not match parent');
|
|
101
|
+
}
|
|
102
|
+
return { valid: errors.length === 0, errors };
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=delegation.js.map
|