@primust/artifact-core 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +93 -0
- package/dist/canonical.d.ts +11 -0
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +92 -0
- package/dist/canonical.js.map +1 -1
- package/dist/commitment.d.ts +29 -8
- package/dist/commitment.d.ts.map +1 -1
- package/dist/commitment.js +45 -17
- package/dist/commitment.js.map +1 -1
- package/dist/commitment.test.js +14 -3
- package/dist/commitment.test.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata_source.d.ts +4 -0
- package/dist/metadata_source.d.ts.map +1 -0
- package/dist/metadata_source.js +54 -0
- package/dist/metadata_source.js.map +1 -0
- package/dist/metadata_source.test.d.ts +2 -0
- package/dist/metadata_source.test.d.ts.map +1 -0
- package/dist/metadata_source.test.js +29 -0
- package/dist/metadata_source.test.js.map +1 -0
- package/dist/reversibility_taxonomy.d.ts +23 -0
- package/dist/reversibility_taxonomy.d.ts.map +1 -0
- package/dist/reversibility_taxonomy.js +208 -0
- package/dist/reversibility_taxonomy.js.map +1 -0
- package/dist/reversibility_taxonomy.test.d.ts +2 -0
- package/dist/reversibility_taxonomy.test.d.ts.map +1 -0
- package/dist/reversibility_taxonomy.test.js +146 -0
- package/dist/reversibility_taxonomy.test.js.map +1 -0
- package/dist/signing.d.ts.map +1 -1
- package/dist/signing.js +30 -6
- package/dist/signing.js.map +1 -1
- package/dist/trust_edge_mapping.d.ts +12 -0
- package/dist/trust_edge_mapping.d.ts.map +1 -0
- package/dist/trust_edge_mapping.js +88 -0
- package/dist/trust_edge_mapping.js.map +1 -0
- package/dist/trust_edge_mapping.test.d.ts +2 -0
- package/dist/trust_edge_mapping.test.d.ts.map +1 -0
- package/dist/trust_edge_mapping.test.js +86 -0
- package/dist/trust_edge_mapping.test.js.map +1 -0
- package/dist/types/artifact.d.ts +65 -4
- package/dist/types/artifact.d.ts.map +1 -1
- package/dist/types/proof_artifact.d.ts +52 -0
- package/dist/types/proof_artifact.d.ts.map +1 -0
- package/dist/types/proof_artifact.js +12 -0
- package/dist/types/proof_artifact.js.map +1 -0
- package/dist/validate-artifact.d.ts.map +1 -1
- package/dist/validate-artifact.js +88 -10
- package/dist/validate-artifact.js.map +1 -1
- package/dist/validate-artifact.test.js +16 -2
- package/dist/validate-artifact.test.js.map +1 -1
- package/package.json +13 -7
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// metadata_source enum — TypeScript sibling of
|
|
2
|
+
// `packages/primust-checks/src/primust_checks/metadata_source.py`.
|
|
3
|
+
//
|
|
4
|
+
// Single source of truth for the metadata_source CHECK enum on
|
|
5
|
+
// check_execution_records (migration 179) on the TS side.
|
|
6
|
+
//
|
|
7
|
+
// Each of the four values is a PRECISE, NARROW provenance claim —
|
|
8
|
+
// not a fallback ladder. The values' trust meaning depends on staying
|
|
9
|
+
// narrow.
|
|
10
|
+
//
|
|
11
|
+
// - 'hook_observed' — A runtime intercept (CC / Cursor / Anthropic
|
|
12
|
+
// Agent SDK lifecycle hook) saw this at the framework boundary.
|
|
13
|
+
// Substrate witness; strongest non-repudiation.
|
|
14
|
+
//
|
|
15
|
+
// - 'sdk_decomposed' — An SDK adapter derived the bounded metadata
|
|
16
|
+
// in-process (LLM quadruple, enforcement attribution, redaction).
|
|
17
|
+
// Adapter composition — observed and shaped, not relayed.
|
|
18
|
+
//
|
|
19
|
+
// - 'sdk_caller_supplied' — App code passed metadata args to
|
|
20
|
+
// run.record() and the SDK relayed without deriving or
|
|
21
|
+
// independently observing. Caller-as-source-of-truth. Honest,
|
|
22
|
+
// narrow; weaker evidence than hook_observed (no substrate
|
|
23
|
+
// witness) or sdk_decomposed (no adapter composition).
|
|
24
|
+
//
|
|
25
|
+
// - 'hook_and_sdk_concordant' — Both layers independently confirmed
|
|
26
|
+
// the same fact via the trace_context join (Phase 3+). Cross-
|
|
27
|
+
// checked; highest trust. Back-filled server-side.
|
|
28
|
+
//
|
|
29
|
+
// - NULL — RESERVED for legacy pre-179 rows and aggregator-emitted
|
|
30
|
+
// records with no single per-record derivation. No new emitter
|
|
31
|
+
// should land NULL. A NULL on a fresh record is an emitter bug.
|
|
32
|
+
//
|
|
33
|
+
// SI-1: enum-constrained string, never content.
|
|
34
|
+
export const METADATA_SOURCE_VALUES = [
|
|
35
|
+
// Runtime intercept saw the event at the framework boundary.
|
|
36
|
+
// Substrate witness; strongest non-repudiation.
|
|
37
|
+
'hook_observed',
|
|
38
|
+
// SDK adapter derived the bounded metadata in-process (LLM
|
|
39
|
+
// quadruple, enforcement attribution, redaction). Adapter
|
|
40
|
+
// composition — observed and shaped, not relayed.
|
|
41
|
+
'sdk_decomposed',
|
|
42
|
+
// App code passed metadata args to run.record() and the SDK
|
|
43
|
+
// relayed without deriving or independently observing. Honest,
|
|
44
|
+
// narrow; weaker than hook_observed / sdk_decomposed.
|
|
45
|
+
'sdk_caller_supplied',
|
|
46
|
+
// Both layers independently confirmed the same fact via the
|
|
47
|
+
// trace_context join (Phase 3+). Cross-checked; highest trust.
|
|
48
|
+
// Back-filled server-side; never emitted directly by a single layer.
|
|
49
|
+
'hook_and_sdk_concordant',
|
|
50
|
+
];
|
|
51
|
+
export function isMetadataSource(value) {
|
|
52
|
+
return (typeof value === 'string' && METADATA_SOURCE_VALUES.includes(value));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=metadata_source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata_source.js","sourceRoot":"","sources":["../src/metadata_source.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,mEAAmE;AACnE,EAAE;AACF,+DAA+D;AAC/D,0DAA0D;AAC1D,EAAE;AACF,kEAAkE;AAClE,sEAAsE;AACtE,UAAU;AACV,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,oDAAoD;AACpD,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,8DAA8D;AAC9D,EAAE;AACF,+DAA+D;AAC/D,2DAA2D;AAC3D,kEAAkE;AAClE,+DAA+D;AAC/D,2DAA2D;AAC3D,EAAE;AACF,sEAAsE;AACtE,kEAAkE;AAClE,uDAAuD;AACvD,EAAE;AACF,qEAAqE;AACrE,mEAAmE;AACnE,oEAAoE;AACpE,EAAE;AACF,gDAAgD;AAEhD,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,6DAA6D;IAC7D,gDAAgD;IAChD,eAAe;IAEf,2DAA2D;IAC3D,0DAA0D;IAC1D,kDAAkD;IAClD,gBAAgB;IAEhB,4DAA4D;IAC5D,+DAA+D;IAC/D,sDAAsD;IACtD,qBAAqB;IAErB,4DAA4D;IAC5D,+DAA+D;IAC/D,qEAAqE;IACrE,yBAAyB;CACjB,CAAC;AAIX,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ,IAAK,sBAA4C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC3F,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata_source.test.d.ts","sourceRoot":"","sources":["../src/metadata_source.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { METADATA_SOURCE_VALUES, isMetadataSource } from './metadata_source.js';
|
|
3
|
+
describe('metadata_source', () => {
|
|
4
|
+
it('has exactly the four canonical values from migration 179', () => {
|
|
5
|
+
expect(new Set(METADATA_SOURCE_VALUES)).toEqual(new Set([
|
|
6
|
+
'hook_observed',
|
|
7
|
+
'sdk_decomposed',
|
|
8
|
+
'sdk_caller_supplied',
|
|
9
|
+
'hook_and_sdk_concordant',
|
|
10
|
+
]));
|
|
11
|
+
});
|
|
12
|
+
it('isMetadataSource accepts all four enum strings', () => {
|
|
13
|
+
for (const v of METADATA_SOURCE_VALUES) {
|
|
14
|
+
expect(isMetadataSource(v)).toBe(true);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
it('rejects unknown strings (including the distinct `source` enum)', () => {
|
|
18
|
+
expect(isMetadataSource('garbage')).toBe(false);
|
|
19
|
+
expect(isMetadataSource('hook')).toBe(false); // bare 'hook' is `source`, not metadata_source
|
|
20
|
+
expect(isMetadataSource('sdk')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it('rejects non-strings', () => {
|
|
23
|
+
expect(isMetadataSource(null)).toBe(false);
|
|
24
|
+
expect(isMetadataSource(42)).toBe(false);
|
|
25
|
+
expect(isMetadataSource([])).toBe(false);
|
|
26
|
+
expect(isMetadataSource({ value: 'hook_observed' })).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=metadata_source.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata_source.test.js","sourceRoot":"","sources":["../src/metadata_source.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,IAAI,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAC7C,IAAI,GAAG,CAAC;YACN,eAAe;YACf,gBAAgB;YAChB,qBAAqB;YACrB,yBAAyB;SAC1B,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,KAAK,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC;YACvC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,+CAA+C;QAC7F,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const TAXONOMY_VERSION: "1.0.0";
|
|
2
|
+
export declare const REVERSIBILITY_CLASSES: readonly ["reversible", "append_only", "external_side_effect", "irreversible", "unknown"];
|
|
3
|
+
export type ReversibilityClass = (typeof REVERSIBILITY_CLASSES)[number];
|
|
4
|
+
export declare function isReversibilityClass(v: unknown): v is ReversibilityClass;
|
|
5
|
+
export interface ClassifyOptions {
|
|
6
|
+
overrides?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Classify an outbound action by `(target_system_kind, operation)`.
|
|
10
|
+
*
|
|
11
|
+
* Lookup order:
|
|
12
|
+
* 1. Customer override for the exact (kind, op) pair.
|
|
13
|
+
* 2. System default for the exact (kind, op) pair.
|
|
14
|
+
* 3. Per-kind fallback.
|
|
15
|
+
* 4. `'unknown'`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function classify(target_system_kind: string, operation: string, options?: ClassifyOptions): ReversibilityClass;
|
|
18
|
+
/**
|
|
19
|
+
* True if this kind has real (non-`'unknown'`) classifications in the
|
|
20
|
+
* system defaults. Used by the Phase 1 acceptance gate.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isWedgeSurfaceCovered(target_system_kind: string): boolean;
|
|
23
|
+
//# sourceMappingURL=reversibility_taxonomy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reversibility_taxonomy.d.ts","sourceRoot":"","sources":["../src/reversibility_taxonomy.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,gBAAgB,EAAG,OAAgB,CAAC;AAEjD,eAAO,MAAM,qBAAqB,2FAMxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAGxE,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,kBAAkB,CAExE;AAgKD,MAAM,WAAW,eAAe;IAI9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,eAAoB,GAC5B,kBAAkB,CAcpB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAMzE"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// Reversibility taxonomy for outbound-action records.
|
|
2
|
+
//
|
|
3
|
+
// TypeScript sibling of
|
|
4
|
+
// `packages/primust-checks/src/primust_checks/reversibility_taxonomy.py`.
|
|
5
|
+
// Both implementations stamp the same `TAXONOMY_VERSION` so a credential
|
|
6
|
+
// classified by either side is comparable.
|
|
7
|
+
//
|
|
8
|
+
// Implements the system-default classification referenced by
|
|
9
|
+
// `docs/v30/foundation/OUTBOUND_ACTION_EVIDENCE_SPEC_v0_1.md` §1.2 and §2.5
|
|
10
|
+
// and `AGENT_MANIFEST_SPEC_v0_1.md` §3.3 (`reversibility_overrides`).
|
|
11
|
+
//
|
|
12
|
+
// SI-1: this module emits only enum / count / hash / typed-reference values.
|
|
13
|
+
// The taxonomy itself is content-free.
|
|
14
|
+
export const TAXONOMY_VERSION = '1.0.0';
|
|
15
|
+
export const REVERSIBILITY_CLASSES = [
|
|
16
|
+
'reversible',
|
|
17
|
+
'append_only',
|
|
18
|
+
'external_side_effect',
|
|
19
|
+
'irreversible',
|
|
20
|
+
'unknown',
|
|
21
|
+
];
|
|
22
|
+
// Type guard for safe parsing of customer-supplied override strings.
|
|
23
|
+
export function isReversibilityClass(v) {
|
|
24
|
+
return typeof v === 'string' && REVERSIBILITY_CLASSES.includes(v);
|
|
25
|
+
}
|
|
26
|
+
// Operation-specific defaults, keyed by `${kind}::${operation}`.
|
|
27
|
+
//
|
|
28
|
+
// Operation strings follow the spec's per-adapter convention; see the
|
|
29
|
+
// Python sibling for the full convention table.
|
|
30
|
+
const DEFAULTS = {
|
|
31
|
+
// ───────── AWS API ─────────
|
|
32
|
+
'aws_api::GetObject': 'reversible',
|
|
33
|
+
'aws_api::ListObjects': 'reversible',
|
|
34
|
+
'aws_api::ListObjectsV2': 'reversible',
|
|
35
|
+
'aws_api::HeadObject': 'reversible',
|
|
36
|
+
'aws_api::ListBuckets': 'reversible',
|
|
37
|
+
'aws_api::DescribeInstances': 'reversible',
|
|
38
|
+
'aws_api::DescribeDBInstances': 'reversible',
|
|
39
|
+
'aws_api::GetItem': 'reversible',
|
|
40
|
+
'aws_api::Query': 'reversible',
|
|
41
|
+
'aws_api::Scan': 'reversible',
|
|
42
|
+
'aws_api::PutObject': 'append_only',
|
|
43
|
+
'aws_api::PutItem': 'append_only',
|
|
44
|
+
'aws_api::CreateBucket': 'append_only',
|
|
45
|
+
'aws_api::CreateTable': 'append_only',
|
|
46
|
+
'aws_api::RunInstances': 'append_only',
|
|
47
|
+
'aws_api::CreateDBInstance': 'append_only',
|
|
48
|
+
'aws_api::SendEmail': 'external_side_effect',
|
|
49
|
+
'aws_api::Publish': 'external_side_effect',
|
|
50
|
+
'aws_api::SendMessage': 'external_side_effect',
|
|
51
|
+
'aws_api::Invoke': 'external_side_effect',
|
|
52
|
+
'aws_api::RebootInstances': 'external_side_effect',
|
|
53
|
+
'aws_api::StopInstances': 'external_side_effect',
|
|
54
|
+
'aws_api::StartInstances': 'external_side_effect',
|
|
55
|
+
'aws_api::DeleteObject': 'irreversible',
|
|
56
|
+
'aws_api::DeleteObjects': 'irreversible',
|
|
57
|
+
'aws_api::DeleteBucket': 'irreversible',
|
|
58
|
+
'aws_api::DeleteTable': 'irreversible',
|
|
59
|
+
'aws_api::DeleteItem': 'irreversible',
|
|
60
|
+
'aws_api::TerminateInstances': 'irreversible',
|
|
61
|
+
'aws_api::DeleteDBInstance': 'irreversible',
|
|
62
|
+
// ───────── Stripe API (per spec §2.5) ─────────
|
|
63
|
+
'stripe_api::charges.list': 'reversible',
|
|
64
|
+
'stripe_api::charges.retrieve': 'reversible',
|
|
65
|
+
'stripe_api::customers.list': 'reversible',
|
|
66
|
+
'stripe_api::customers.retrieve': 'reversible',
|
|
67
|
+
'stripe_api::balance.retrieve': 'reversible',
|
|
68
|
+
'stripe_api::charges.create': 'irreversible',
|
|
69
|
+
'stripe_api::payment_intents.confirm': 'irreversible',
|
|
70
|
+
'stripe_api::charges.refund': 'append_only',
|
|
71
|
+
'stripe_api::customers.create': 'append_only',
|
|
72
|
+
'stripe_api::subscriptions.create': 'append_only',
|
|
73
|
+
'stripe_api::invoices.create': 'append_only',
|
|
74
|
+
'stripe_api::customers.update': 'external_side_effect',
|
|
75
|
+
'stripe_api::subscriptions.update': 'external_side_effect',
|
|
76
|
+
'stripe_api::webhooks.create': 'external_side_effect',
|
|
77
|
+
'stripe_api::customers.delete': 'irreversible',
|
|
78
|
+
'stripe_api::subscriptions.delete': 'irreversible',
|
|
79
|
+
// ───────── GitHub API ─────────
|
|
80
|
+
'github_api::GET /repos/{owner}/{repo}': 'reversible',
|
|
81
|
+
'github_api::GET /repos/{owner}/{repo}/issues': 'reversible',
|
|
82
|
+
'github_api::GET /repos/{owner}/{repo}/pulls': 'reversible',
|
|
83
|
+
'github_api::GET /repos/{owner}/{repo}/contents/{path}': 'reversible',
|
|
84
|
+
'github_api::POST /repos/{owner}/{repo}/issues': 'append_only',
|
|
85
|
+
'github_api::POST /repos/{owner}/{repo}/pulls': 'append_only',
|
|
86
|
+
'github_api::POST /repos/{owner}/{repo}/issues/{number}/comments': 'append_only',
|
|
87
|
+
'github_api::POST /repos/{owner}/{repo}/pulls/{number}/reviews': 'append_only',
|
|
88
|
+
'github_api::POST /repos/{owner}/{repo}/pulls/{number}/merge': 'external_side_effect',
|
|
89
|
+
'github_api::PATCH /repos/{owner}/{repo}/issues/{number}': 'reversible',
|
|
90
|
+
'github_api::PATCH /repos/{owner}/{repo}/pulls/{number}': 'reversible',
|
|
91
|
+
'github_api::PUT /repos/{owner}/{repo}/contents/{path}': 'append_only',
|
|
92
|
+
'github_api::DELETE /repos/{owner}/{repo}/contents/{path}': 'irreversible',
|
|
93
|
+
'github_api::DELETE /repos/{owner}/{repo}': 'irreversible',
|
|
94
|
+
'github_api::DELETE /repos/{owner}/{repo}/branches/{branch}': 'reversible',
|
|
95
|
+
// ───────── Salesforce REST ─────────
|
|
96
|
+
'salesforce_rest::GET /sobjects/Account/{id}': 'reversible',
|
|
97
|
+
'salesforce_rest::GET /sobjects/Task/{id}': 'reversible',
|
|
98
|
+
'salesforce_rest::GET /query': 'reversible',
|
|
99
|
+
'salesforce_rest::POST /sobjects/Task': 'append_only',
|
|
100
|
+
'salesforce_rest::POST /sobjects/Account': 'append_only',
|
|
101
|
+
'salesforce_rest::POST /sobjects/Lead': 'append_only',
|
|
102
|
+
'salesforce_rest::POST /sobjects/Contact': 'append_only',
|
|
103
|
+
'salesforce_rest::POST /sobjects/Opportunity': 'append_only',
|
|
104
|
+
'salesforce_rest::POST /sobjects/Case': 'append_only',
|
|
105
|
+
'salesforce_rest::PATCH /sobjects/Account/{id}': 'reversible',
|
|
106
|
+
'salesforce_rest::PATCH /sobjects/Task/{id}': 'reversible',
|
|
107
|
+
'salesforce_rest::DELETE /sobjects/Account/{id}': 'irreversible',
|
|
108
|
+
'salesforce_rest::DELETE /sobjects/Task/{id}': 'irreversible',
|
|
109
|
+
// ───────── Slack ─────────
|
|
110
|
+
'slack::conversations.history': 'reversible',
|
|
111
|
+
'slack::conversations.list': 'reversible',
|
|
112
|
+
'slack::users.list': 'reversible',
|
|
113
|
+
'slack::chat.postMessage': 'external_side_effect',
|
|
114
|
+
'slack::chat.postEphemeral': 'external_side_effect',
|
|
115
|
+
'slack::chat.update': 'external_side_effect',
|
|
116
|
+
'slack::files.upload': 'append_only',
|
|
117
|
+
'slack::conversations.invite': 'external_side_effect',
|
|
118
|
+
'slack::conversations.kick': 'external_side_effect',
|
|
119
|
+
'slack::conversations.create': 'append_only',
|
|
120
|
+
'slack::conversations.archive': 'reversible',
|
|
121
|
+
'slack::chat.delete': 'irreversible',
|
|
122
|
+
// ───────── Kubernetes ─────────
|
|
123
|
+
'k8s::GET /api/v1/namespaces': 'reversible',
|
|
124
|
+
'k8s::GET /api/v1/namespaces/{ns}/pods': 'reversible',
|
|
125
|
+
'k8s::GET /apis/apps/v1/namespaces/{ns}/deployments': 'reversible',
|
|
126
|
+
'k8s::POST /apis/apps/v1/namespaces/{ns}/deployments': 'append_only',
|
|
127
|
+
'k8s::POST /api/v1/namespaces/{ns}/configmaps': 'append_only',
|
|
128
|
+
'k8s::POST /api/v1/namespaces/{ns}/secrets': 'append_only',
|
|
129
|
+
'k8s::PATCH /apis/apps/v1/namespaces/{ns}/deployments/{name}': 'reversible',
|
|
130
|
+
'k8s::PATCH /api/v1/namespaces/{ns}/configmaps/{name}': 'reversible',
|
|
131
|
+
'k8s::DELETE /api/v1/namespaces/{ns}/pods/{name}': 'reversible',
|
|
132
|
+
'k8s::DELETE /apis/apps/v1/namespaces/{ns}/deployments/{name}': 'irreversible',
|
|
133
|
+
'k8s::DELETE /api/v1/namespaces/{ns}': 'irreversible',
|
|
134
|
+
'k8s::DELETE /api/v1/namespaces/{ns}/secrets/{name}': 'irreversible',
|
|
135
|
+
// ───────── Postgres / Snowflake ─────────
|
|
136
|
+
'postgres::SELECT': 'reversible',
|
|
137
|
+
'postgres::INSERT': 'append_only',
|
|
138
|
+
'postgres::UPDATE': 'external_side_effect',
|
|
139
|
+
'postgres::DELETE': 'irreversible',
|
|
140
|
+
'postgres::DROP TABLE': 'irreversible',
|
|
141
|
+
'postgres::TRUNCATE': 'irreversible',
|
|
142
|
+
'snowflake::SELECT': 'reversible',
|
|
143
|
+
'snowflake::INSERT': 'append_only',
|
|
144
|
+
'snowflake::UPDATE': 'external_side_effect',
|
|
145
|
+
'snowflake::DELETE': 'irreversible',
|
|
146
|
+
'snowflake::DROP TABLE': 'irreversible',
|
|
147
|
+
// ───────── Vector stores (per spec §1.2) ─────────
|
|
148
|
+
'pinecone::upsert': 'append_only',
|
|
149
|
+
'pinecone::delete': 'irreversible',
|
|
150
|
+
'pinecone::query': 'reversible',
|
|
151
|
+
'pinecone::fetch': 'reversible',
|
|
152
|
+
'vector_store::upsert': 'append_only',
|
|
153
|
+
'vector_store::query': 'reversible',
|
|
154
|
+
'vector_store::delete': 'irreversible',
|
|
155
|
+
};
|
|
156
|
+
// Per-kind fallback when the exact (kind, op) isn't in DEFAULTS.
|
|
157
|
+
const KIND_DEFAULTS = {
|
|
158
|
+
mcp_tool: 'unknown',
|
|
159
|
+
sdk_tool: 'unknown',
|
|
160
|
+
cli_subprocess: 'unknown',
|
|
161
|
+
anthropic_messages: 'append_only',
|
|
162
|
+
openai_chat: 'append_only',
|
|
163
|
+
bedrock_invoke: 'append_only',
|
|
164
|
+
calibrated_profile: 'append_only',
|
|
165
|
+
approval_gate: 'external_side_effect',
|
|
166
|
+
cli_prompt: 'external_side_effect',
|
|
167
|
+
dashboard_escalation: 'external_side_effect',
|
|
168
|
+
subagent_spawn: 'append_only',
|
|
169
|
+
mcp_sampling: 'append_only',
|
|
170
|
+
cross_org_delegation: 'append_only',
|
|
171
|
+
governance_config_surface: 'external_side_effect',
|
|
172
|
+
filesystem: 'unknown',
|
|
173
|
+
generic_http: 'unknown',
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Classify an outbound action by `(target_system_kind, operation)`.
|
|
177
|
+
*
|
|
178
|
+
* Lookup order:
|
|
179
|
+
* 1. Customer override for the exact (kind, op) pair.
|
|
180
|
+
* 2. System default for the exact (kind, op) pair.
|
|
181
|
+
* 3. Per-kind fallback.
|
|
182
|
+
* 4. `'unknown'`.
|
|
183
|
+
*/
|
|
184
|
+
export function classify(target_system_kind, operation, options = {}) {
|
|
185
|
+
const key = `${target_system_kind}::${operation}`;
|
|
186
|
+
const override = options.overrides?.[key];
|
|
187
|
+
if (override !== undefined && isReversibilityClass(override)) {
|
|
188
|
+
return override;
|
|
189
|
+
}
|
|
190
|
+
const exact = DEFAULTS[key];
|
|
191
|
+
if (exact !== undefined) {
|
|
192
|
+
return exact;
|
|
193
|
+
}
|
|
194
|
+
return KIND_DEFAULTS[target_system_kind] ?? 'unknown';
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* True if this kind has real (non-`'unknown'`) classifications in the
|
|
198
|
+
* system defaults. Used by the Phase 1 acceptance gate.
|
|
199
|
+
*/
|
|
200
|
+
export function isWedgeSurfaceCovered(target_system_kind) {
|
|
201
|
+
const prefix = `${target_system_kind}::`;
|
|
202
|
+
for (const [k, v] of Object.entries(DEFAULTS)) {
|
|
203
|
+
if (k.startsWith(prefix) && v !== 'unknown')
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=reversibility_taxonomy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reversibility_taxonomy.js","sourceRoot":"","sources":["../src/reversibility_taxonomy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reversibility_taxonomy.test.d.ts","sourceRoot":"","sources":["../src/reversibility_taxonomy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { TAXONOMY_VERSION, REVERSIBILITY_CLASSES, isReversibilityClass, classify, isWedgeSurfaceCovered, } from './reversibility_taxonomy.js';
|
|
3
|
+
describe('reversibility_taxonomy', () => {
|
|
4
|
+
describe('Phase 1 acceptance gate: wedge surfaces', () => {
|
|
5
|
+
const wedge = ['salesforce_rest', 'slack', 'github_api', 'stripe_api', 'k8s', 'aws_api'];
|
|
6
|
+
for (const kind of wedge) {
|
|
7
|
+
it(`${kind} has real (non-unknown) classifications`, () => {
|
|
8
|
+
expect(isWedgeSurfaceCovered(kind)).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
describe('per-spec examples (§2.5)', () => {
|
|
13
|
+
it('stripe charges.create → irreversible', () => {
|
|
14
|
+
expect(classify('stripe_api', 'charges.create')).toBe('irreversible');
|
|
15
|
+
});
|
|
16
|
+
it('stripe customers.update → external_side_effect', () => {
|
|
17
|
+
expect(classify('stripe_api', 'customers.update')).toBe('external_side_effect');
|
|
18
|
+
});
|
|
19
|
+
it('stripe charges.list → reversible', () => {
|
|
20
|
+
expect(classify('stripe_api', 'charges.list')).toBe('reversible');
|
|
21
|
+
});
|
|
22
|
+
it('governance_config_surface default → external_side_effect', () => {
|
|
23
|
+
expect(classify('governance_config_surface', 'edit_settings_json')).toBe('external_side_effect');
|
|
24
|
+
});
|
|
25
|
+
it('vector_store upsert → append_only', () => {
|
|
26
|
+
expect(classify('vector_store', 'upsert')).toBe('append_only');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('AWS', () => {
|
|
30
|
+
it('GetObject → reversible', () => {
|
|
31
|
+
expect(classify('aws_api', 'GetObject')).toBe('reversible');
|
|
32
|
+
});
|
|
33
|
+
it('DeleteBucket → irreversible', () => {
|
|
34
|
+
expect(classify('aws_api', 'DeleteBucket')).toBe('irreversible');
|
|
35
|
+
});
|
|
36
|
+
it('PutObject → append_only', () => {
|
|
37
|
+
expect(classify('aws_api', 'PutObject')).toBe('append_only');
|
|
38
|
+
});
|
|
39
|
+
it('SendEmail → external_side_effect', () => {
|
|
40
|
+
expect(classify('aws_api', 'SendEmail')).toBe('external_side_effect');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('Salesforce', () => {
|
|
44
|
+
it('POST /sobjects/Task → append_only', () => {
|
|
45
|
+
expect(classify('salesforce_rest', 'POST /sobjects/Task')).toBe('append_only');
|
|
46
|
+
});
|
|
47
|
+
it('PATCH /sobjects/Account/{id} → reversible (field audit trail)', () => {
|
|
48
|
+
expect(classify('salesforce_rest', 'PATCH /sobjects/Account/{id}')).toBe('reversible');
|
|
49
|
+
});
|
|
50
|
+
it('DELETE /sobjects/Account/{id} → irreversible', () => {
|
|
51
|
+
expect(classify('salesforce_rest', 'DELETE /sobjects/Account/{id}')).toBe('irreversible');
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe('Slack', () => {
|
|
55
|
+
it('chat.postMessage → external_side_effect', () => {
|
|
56
|
+
expect(classify('slack', 'chat.postMessage')).toBe('external_side_effect');
|
|
57
|
+
});
|
|
58
|
+
it('conversations.history → reversible', () => {
|
|
59
|
+
expect(classify('slack', 'conversations.history')).toBe('reversible');
|
|
60
|
+
});
|
|
61
|
+
it('chat.delete → irreversible', () => {
|
|
62
|
+
expect(classify('slack', 'chat.delete')).toBe('irreversible');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('Kubernetes', () => {
|
|
66
|
+
it('DELETE pod → reversible (controller recreates)', () => {
|
|
67
|
+
expect(classify('k8s', 'DELETE /api/v1/namespaces/{ns}/pods/{name}')).toBe('reversible');
|
|
68
|
+
});
|
|
69
|
+
it('DELETE deployment → irreversible', () => {
|
|
70
|
+
expect(classify('k8s', 'DELETE /apis/apps/v1/namespaces/{ns}/deployments/{name}')).toBe('irreversible');
|
|
71
|
+
});
|
|
72
|
+
it('DELETE namespace → irreversible', () => {
|
|
73
|
+
expect(classify('k8s', 'DELETE /api/v1/namespaces/{ns}')).toBe('irreversible');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
describe('Postgres', () => {
|
|
77
|
+
it('SELECT → reversible', () => {
|
|
78
|
+
expect(classify('postgres', 'SELECT')).toBe('reversible');
|
|
79
|
+
});
|
|
80
|
+
it('UPDATE → external_side_effect', () => {
|
|
81
|
+
expect(classify('postgres', 'UPDATE')).toBe('external_side_effect');
|
|
82
|
+
});
|
|
83
|
+
it('DELETE → irreversible', () => {
|
|
84
|
+
expect(classify('postgres', 'DELETE')).toBe('irreversible');
|
|
85
|
+
});
|
|
86
|
+
it('DROP TABLE → irreversible', () => {
|
|
87
|
+
expect(classify('postgres', 'DROP TABLE')).toBe('irreversible');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('model surfaces', () => {
|
|
91
|
+
it('anthropic_messages → append_only default', () => {
|
|
92
|
+
expect(classify('anthropic_messages', 'POST /v1/messages')).toBe('append_only');
|
|
93
|
+
});
|
|
94
|
+
it('openai_chat → append_only default', () => {
|
|
95
|
+
expect(classify('openai_chat', 'POST /v1/chat/completions')).toBe('append_only');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('fallback behavior', () => {
|
|
99
|
+
it('unknown kind → unknown', () => {
|
|
100
|
+
expect(classify('not_a_real_kind', 'op')).toBe('unknown');
|
|
101
|
+
});
|
|
102
|
+
it('unmapped op on mcp_tool → unknown (kind default)', () => {
|
|
103
|
+
expect(classify('mcp_tool', 'some_tool_call')).toBe('unknown');
|
|
104
|
+
});
|
|
105
|
+
it('unmapped op on aws → unknown', () => {
|
|
106
|
+
expect(classify('aws_api', 'SomeFutureAction')).toBe('unknown');
|
|
107
|
+
});
|
|
108
|
+
it('human-facing default → external_side_effect', () => {
|
|
109
|
+
expect(classify('approval_gate', 'request')).toBe('external_side_effect');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('customer overrides', () => {
|
|
113
|
+
it('override beats system default', () => {
|
|
114
|
+
expect(classify('stripe_api', 'charges.create', {
|
|
115
|
+
overrides: { 'stripe_api::charges.create': 'reversible' },
|
|
116
|
+
})).toBe('reversible');
|
|
117
|
+
});
|
|
118
|
+
it('invalid override falls back to system default', () => {
|
|
119
|
+
expect(classify('stripe_api', 'charges.create', {
|
|
120
|
+
overrides: { 'stripe_api::charges.create': 'not_a_valid_class' },
|
|
121
|
+
})).toBe('irreversible');
|
|
122
|
+
});
|
|
123
|
+
it('override works for unmapped kind', () => {
|
|
124
|
+
expect(classify('custom_internal_api', 'credit_account', {
|
|
125
|
+
overrides: { 'custom_internal_api::credit_account': 'irreversible' },
|
|
126
|
+
})).toBe('irreversible');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('versioning + SI-1 shape', () => {
|
|
130
|
+
it('TAXONOMY_VERSION is semver', () => {
|
|
131
|
+
expect(TAXONOMY_VERSION).toMatch(/^\d+\.\d+\.\d+$/);
|
|
132
|
+
});
|
|
133
|
+
it('all class values use safe alphabet', () => {
|
|
134
|
+
for (const cls of REVERSIBILITY_CLASSES) {
|
|
135
|
+
expect(cls.replace(/_/g, '')).toMatch(/^[a-z]+$/);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
it('isReversibilityClass type guard works', () => {
|
|
139
|
+
expect(isReversibilityClass('reversible')).toBe(true);
|
|
140
|
+
expect(isReversibilityClass('garbage')).toBe(false);
|
|
141
|
+
expect(isReversibilityClass(null)).toBe(false);
|
|
142
|
+
expect(isReversibilityClass(42)).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
//# sourceMappingURL=reversibility_taxonomy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reversibility_taxonomy.test.js","sourceRoot":"","sources":["../src/reversibility_taxonomy.test.ts"],"names":[],"mappings":"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"}
|
package/dist/signing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa9E,6CAA6C;AAC7C,iBAAS,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAM9C;AAED,gCAAgC;AAChC,iBAAS,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CASjD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GACrB;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAsBxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,CAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,GACzB;IAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAA;CAAE,CAkB7E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,MAAM,GACtB,OAAO,
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa9E,6CAA6C;AAC7C,iBAAS,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAM9C;AAED,gCAAgC;AAChC,iBAAS,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CASjD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,GACrB;IAAE,YAAY,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAsBxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,IAAI,CAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY,GACzB;IAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAA;CAAE,CAkB7E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,MAAM,GACtB,OAAO,CAmCT;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,cAAc,EAAE,YAAY,GAAG;IACvD,aAAa,EAAE,YAAY,CAAC;IAC5B,SAAS,EAAE,YAAY,CAAC;IACxB,aAAa,EAAE,UAAU,CAAC;CAC3B,CAyBA;AAGD,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,CAAC"}
|
package/dist/signing.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import * as ed from '@noble/ed25519';
|
|
20
20
|
import { sha512 } from '@noble/hashes/sha512';
|
|
21
21
|
import { sha256 } from '@noble/hashes/sha256';
|
|
22
|
-
import { canonical } from './canonical.js';
|
|
22
|
+
import { canonical, canonicalLegacy } from './canonical.js';
|
|
23
23
|
// Configure ed25519 to use sha512
|
|
24
24
|
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
|
|
25
25
|
/** Generate a cryptographically random hex string */
|
|
@@ -117,16 +117,40 @@ export function sign(document, privateKey, signerRecord) {
|
|
|
117
117
|
* @returns true if the cryptographic signature is valid
|
|
118
118
|
*/
|
|
119
119
|
export function verify(document, signatureEnvelope, publicKeyB64Url) {
|
|
120
|
+
let signatureBytes;
|
|
121
|
+
let publicKeyBytes;
|
|
120
122
|
try {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const signatureBytes = fromBase64Url(signatureEnvelope.signature);
|
|
124
|
-
const publicKeyBytes = fromBase64Url(publicKeyB64Url);
|
|
125
|
-
return ed.verify(signatureBytes, hashBytes, publicKeyBytes);
|
|
123
|
+
signatureBytes = fromBase64Url(signatureEnvelope.signature);
|
|
124
|
+
publicKeyBytes = fromBase64Url(publicKeyB64Url);
|
|
126
125
|
}
|
|
127
126
|
catch {
|
|
128
127
|
return false;
|
|
129
128
|
}
|
|
129
|
+
// Try the spec-compliant (ECMA-262) canonical form first; fall back
|
|
130
|
+
// to the legacy Python form that signed VPECs before 2026-04-19.
|
|
131
|
+
// Stored signatures are against whichever form was current at
|
|
132
|
+
// sign-time — new code must still be able to verify legacy VPECs
|
|
133
|
+
// until every customer rolls forward.
|
|
134
|
+
// The legacy form has subtle ambiguity (number formatting, key order)
|
|
135
|
+
// that a malicious prover could exploit; only accept it for signatures
|
|
136
|
+
// claimed to have been produced before the canonical-form cutover.
|
|
137
|
+
const LEGACY_CUTOFF = '2026-04-19';
|
|
138
|
+
const signedAt = signatureEnvelope.signed_at ?? '';
|
|
139
|
+
const legacyAllowed = signedAt !== '' && signedAt.slice(0, 10) < LEGACY_CUTOFF;
|
|
140
|
+
const candidates = legacyAllowed ? [canonical, canonicalLegacy] : [canonical];
|
|
141
|
+
for (const canonFn of candidates) {
|
|
142
|
+
try {
|
|
143
|
+
const canonicalStr = canonFn(document);
|
|
144
|
+
const hashBytes = sha256(new TextEncoder().encode(canonicalStr));
|
|
145
|
+
if (ed.verify(signatureBytes, hashBytes, publicKeyBytes)) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// try next form
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
130
154
|
}
|
|
131
155
|
/**
|
|
132
156
|
* Rotate a key: create a new kid under the same signer_id.
|
package/dist/signing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const MAPPING_VERSION: "1.0.0";
|
|
2
|
+
export declare const TRUST_EDGES: readonly ["A2T", "A2M", "A2H", "A2A", "A2S", "A2D"];
|
|
3
|
+
export type TrustEdge = (typeof TRUST_EDGES)[number];
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the trust edge for a `(target_system_kind, operation)` pair.
|
|
6
|
+
* Returns `null` if the kind is not recognized — callers MUST treat
|
|
7
|
+
* this as a gap (record the kind, do not invent a trust edge).
|
|
8
|
+
*/
|
|
9
|
+
export declare function classify(target_system_kind: string, operation: string): TrustEdge | null;
|
|
10
|
+
/** All target_system_kind values this mapping recognizes. */
|
|
11
|
+
export declare function knownKinds(): ReadonlySet<string>;
|
|
12
|
+
//# sourceMappingURL=trust_edge_mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust_edge_mapping.d.ts","sourceRoot":"","sources":["../src/trust_edge_mapping.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,eAAe,EAAG,OAAgB,CAAC;AAEhD,eAAO,MAAM,WAAW,qDAAsD,CAAC;AAC/E,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AA8DrD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,GAChB,SAAS,GAAG,IAAI,CAalB;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,IAAI,WAAW,CAAC,MAAM,CAAC,CAEhD"}
|