hackmyagent 0.16.5 → 0.17.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.
Files changed (71) hide show
  1. package/dist/.integrity-manifest.json +1 -1
  2. package/dist/arp/crypto/hybrid-signing.d.ts +107 -0
  3. package/dist/arp/crypto/hybrid-signing.d.ts.map +1 -0
  4. package/dist/arp/crypto/hybrid-signing.js +321 -0
  5. package/dist/arp/crypto/hybrid-signing.js.map +1 -0
  6. package/dist/arp/crypto/index.d.ts +13 -0
  7. package/dist/arp/crypto/index.d.ts.map +1 -0
  8. package/dist/arp/crypto/index.js +33 -0
  9. package/dist/arp/crypto/index.js.map +1 -0
  10. package/dist/arp/crypto/manifest-loader.d.ts +117 -0
  11. package/dist/arp/crypto/manifest-loader.d.ts.map +1 -0
  12. package/dist/arp/crypto/manifest-loader.js +361 -0
  13. package/dist/arp/crypto/manifest-loader.js.map +1 -0
  14. package/dist/arp/crypto/types.d.ts +69 -0
  15. package/dist/arp/crypto/types.d.ts.map +1 -0
  16. package/dist/arp/crypto/types.js +11 -0
  17. package/dist/arp/crypto/types.js.map +1 -0
  18. package/dist/arp/index.d.ts +28 -1
  19. package/dist/arp/index.d.ts.map +1 -1
  20. package/dist/arp/index.js +97 -4
  21. package/dist/arp/index.js.map +1 -1
  22. package/dist/arp/intelligence/behavioral-risk-server.d.ts +82 -0
  23. package/dist/arp/intelligence/behavioral-risk-server.d.ts.map +1 -0
  24. package/dist/arp/intelligence/behavioral-risk-server.js +258 -0
  25. package/dist/arp/intelligence/behavioral-risk-server.js.map +1 -0
  26. package/dist/arp/intelligence/behavioral-risk.d.ts +217 -0
  27. package/dist/arp/intelligence/behavioral-risk.d.ts.map +1 -0
  28. package/dist/arp/intelligence/behavioral-risk.js +429 -0
  29. package/dist/arp/intelligence/behavioral-risk.js.map +1 -0
  30. package/dist/arp/intelligence/coordinator.d.ts +93 -2
  31. package/dist/arp/intelligence/coordinator.d.ts.map +1 -1
  32. package/dist/arp/intelligence/coordinator.js +281 -1
  33. package/dist/arp/intelligence/coordinator.js.map +1 -1
  34. package/dist/arp/intelligence/guard-anomaly.d.ts +349 -0
  35. package/dist/arp/intelligence/guard-anomaly.d.ts.map +1 -0
  36. package/dist/arp/intelligence/guard-anomaly.js +399 -0
  37. package/dist/arp/intelligence/guard-anomaly.js.map +1 -0
  38. package/dist/arp/intelligence/nanomind-l1.d.ts +37 -0
  39. package/dist/arp/intelligence/nanomind-l1.d.ts.map +1 -1
  40. package/dist/arp/intelligence/nanomind-l1.js +78 -0
  41. package/dist/arp/intelligence/nanomind-l1.js.map +1 -1
  42. package/dist/arp/intelligence/runtime-twin.d.ts +157 -0
  43. package/dist/arp/intelligence/runtime-twin.d.ts.map +1 -0
  44. package/dist/arp/intelligence/runtime-twin.js +479 -0
  45. package/dist/arp/intelligence/runtime-twin.js.map +1 -0
  46. package/dist/arp/intelligence/verify-classification.d.ts +124 -0
  47. package/dist/arp/intelligence/verify-classification.d.ts.map +1 -0
  48. package/dist/arp/intelligence/verify-classification.js +329 -0
  49. package/dist/arp/intelligence/verify-classification.js.map +1 -0
  50. package/dist/arp/proxy/server.d.ts +38 -8
  51. package/dist/arp/proxy/server.d.ts.map +1 -1
  52. package/dist/arp/proxy/server.js +89 -0
  53. package/dist/arp/proxy/server.js.map +1 -1
  54. package/dist/arp/types.d.ts +229 -1
  55. package/dist/arp/types.d.ts.map +1 -1
  56. package/dist/cli.js +691 -154
  57. package/dist/cli.js.map +1 -1
  58. package/dist/hardening/scanner.d.ts.map +1 -1
  59. package/dist/hardening/scanner.js +11 -1
  60. package/dist/hardening/scanner.js.map +1 -1
  61. package/dist/nanomind-core/compiler/semantic-compiler.d.ts.map +1 -1
  62. package/dist/nanomind-core/compiler/semantic-compiler.js +170 -10
  63. package/dist/nanomind-core/compiler/semantic-compiler.js.map +1 -1
  64. package/dist/nanomind-core/compiler/source-code-preprocessor.d.ts +64 -0
  65. package/dist/nanomind-core/compiler/source-code-preprocessor.d.ts.map +1 -0
  66. package/dist/nanomind-core/compiler/source-code-preprocessor.js +656 -0
  67. package/dist/nanomind-core/compiler/source-code-preprocessor.js.map +1 -0
  68. package/dist/nanomind-core/ingestion/artifact-parser.d.ts.map +1 -1
  69. package/dist/nanomind-core/ingestion/artifact-parser.js +15 -6
  70. package/dist/nanomind-core/ingestion/artifact-parser.js.map +1 -1
  71. package/package.json +3 -1
@@ -0,0 +1,124 @@
1
+ /**
2
+ * NanoMind-Guard classification verifier (AIComply P1, producer side).
3
+ *
4
+ * This module is the producer-side companion to the L0-comply gate on
5
+ * `IntelligenceCoordinator`. NanoMind-Guard produces classification labels
6
+ * for runtime events; every result it emits is hybrid-signed with
7
+ * Ed25519+ML-DSA-44 (the high-throughput variant, deliberately chosen over
8
+ * ML-DSA-65 to keep per-event signing cost bounded). Before the coordinator
9
+ * can trust a classification, the signature must verify and the class must
10
+ * pass a tier-keyed rejection matrix that bounds what a given capability
11
+ * tier can ever emit, regardless of what the per-manifest permitted list
12
+ * says.
13
+ *
14
+ * The order of checks is:
15
+ *
16
+ * 1. Schema sanity of the result object and signature block.
17
+ * 2. Algorithm gate: the signature must advertise Ed25519+ML-DSA-44.
18
+ * Anything else is refused before any crypto runs, so an attacker
19
+ * cannot downgrade the Guard to a weaker algorithm.
20
+ * 3. Key and signature byte-size checks after base64 decode. Node's
21
+ * `Buffer.from(_, 'base64')` is permissive, so malformed inputs are
22
+ * caught here as KEY_FORMAT_ERROR rather than falling through to a
23
+ * SIGNATURE_INVALID that hides a structural problem.
24
+ * 4. Hybrid signature verification over the canonical signed payload.
25
+ * Both halves must pass; the underlying `hybridVerify` is
26
+ * non-short-circuit for timing reasons.
27
+ * 5. Freshness: the signed timestamp must be within `maxAgeMs` of now and
28
+ * must not be more than `futureSkewMs` in the future.
29
+ * 6. Rejection matrix keyed on `manifest.tier`. Any classification on the
30
+ * absolute deny list is rejected regardless of tier. Any classification
31
+ * whose minimum required tier exceeds the manifest's tier is rejected.
32
+ * Any classification not in the registry is rejected as unknown
33
+ * (parse-to-deny).
34
+ *
35
+ * A verified result returns `{valid: true, classification}`; the caller
36
+ * assigns `event.data.classification = result.classification` before
37
+ * handing the event to the coordinator, where the session 26 comply gate
38
+ * takes over and enforces the per-manifest permitted/prohibited lists. This
39
+ * is a defense-in-depth composition: the rejection matrix here is a hard
40
+ * ceiling that even a permissive manifest cannot override; the per-manifest
41
+ * lists are a narrower policy on top of that ceiling.
42
+ *
43
+ * Parse-to-deny (CR-001) applies to every failure path. The function never
44
+ * throws; all rejection branches return a typed `{valid: false}` object.
45
+ * Callers must treat `valid === false` as authoritative and refuse to
46
+ * populate `event.data.classification` on failure.
47
+ */
48
+ import type { CapabilityTier, NanoMindGuardResult, NanoMindGuardVerifyOptions, NanoMindGuardVerifyResult } from '../types';
49
+ import type { HybridAlgorithm } from '../crypto/types';
50
+ /**
51
+ * Only hybrid algorithm accepted for NanoMind-Guard classification results.
52
+ * ML-DSA-44 is the FIPS 204 high-throughput variant. Do not accept ML-DSA-65
53
+ * here: the manifest loader uses ML-DSA-65 for long-lived capability
54
+ * manifests, and keeping the two algorithm lanes disjoint prevents a
55
+ * manifest key from being mistakenly used to mint per-event classifications.
56
+ */
57
+ export declare const GUARD_SIGNATURE_ALGORITHM: HybridAlgorithm;
58
+ /**
59
+ * Default freshness window for a Guard signature. Per-event signing is
60
+ * expected to complete well under a second, so 5 minutes is a generous
61
+ * upper bound that still closes the replay window.
62
+ */
63
+ export declare const DEFAULT_MAX_AGE_MS: number;
64
+ /**
65
+ * Default tolerance for signatures that appear to be timestamped in the
66
+ * future. Accounts for small clock skew between the Guard and the
67
+ * coordinator; anything beyond this is a bug or an attack.
68
+ */
69
+ export declare const DEFAULT_FUTURE_SKEW_MS: number;
70
+ /**
71
+ * Minimum capability tier required to act on a given classification. A
72
+ * classification not in this registry is treated as unknown and denied
73
+ * outright (parse-to-deny, CR-001). Callers that want to allow a new class
74
+ * must add it here first; silent acceptance is a vulnerability.
75
+ *
76
+ * The exact values are policy, not physics: they are the floor below which
77
+ * ARP will not execute the class regardless of the per-manifest envelope.
78
+ * A more permissive tier still has to pass the per-manifest comply gate
79
+ * inside the coordinator before the class actually runs.
80
+ */
81
+ export declare const CLASSIFICATION_MIN_TIER: Readonly<Record<string, CapabilityTier>>;
82
+ /**
83
+ * Classifications that are denied at every tier, including privileged.
84
+ * Raw credential access is always routed through the credential broker, so
85
+ * a Guard result labelled `credential-access` or `credential-exfiltration`
86
+ * is by construction a signal that something is wrong. Parse-to-deny.
87
+ */
88
+ export declare const ABSOLUTE_DENY_CLASSES: ReadonlySet<string>;
89
+ /**
90
+ * Produce canonical signed-payload bytes for a NanoMind-Guard result.
91
+ * Exported so out-of-repo signers can produce byte-identical payloads. Any
92
+ * drift between signer and verifier defeats verification.
93
+ *
94
+ * Canonicalization rules:
95
+ * 1. Remove the `signature` field if present.
96
+ * 2. Serialize as JSON with recursively sorted object keys and no
97
+ * whitespace between tokens.
98
+ * 3. Encode as UTF-8.
99
+ */
100
+ export declare function canonicalizeGuardResultPayload(payload: Record<string, unknown>): Uint8Array;
101
+ /**
102
+ * Verify a NanoMind-Guard classification result and clear it against the
103
+ * capability manifest's tier. Never throws; every failure path returns a
104
+ * typed `{valid: false, code, reason}` the caller routes on.
105
+ *
106
+ * On success, the returned `classification` is the cleared label the caller
107
+ * should write into `event.data.classification` before handing the event to
108
+ * the coordinator. The per-manifest permitted/prohibited envelope is NOT
109
+ * applied here; the coordinator's L0-comply gate handles that layer.
110
+ */
111
+ export declare function verifyClassification(result: NanoMindGuardResult, options: NanoMindGuardVerifyOptions): Promise<NanoMindGuardVerifyResult>;
112
+ /**
113
+ * Convenience wrapper: verify a Guard result and, on success, write the
114
+ * cleared classification into `event.data.classification` so the
115
+ * coordinator's L0-comply gate can consume it. Returns the verification
116
+ * result regardless of outcome so callers can route on the reason without
117
+ * re-running verification. On rejection, `event.data.classification` is
118
+ * LEFT UNCHANGED -- a failed verification must never plant a classification.
119
+ *
120
+ * The `event.data` argument is typed as `Record<string, unknown>` because
121
+ * that matches `ARPEvent.data`; the caller passes `event.data` directly.
122
+ */
123
+ export declare function applyVerifiedClassification(eventData: Record<string, unknown>, result: NanoMindGuardResult, options: NanoMindGuardVerifyOptions): Promise<NanoMindGuardVerifyResult>;
124
+ //# sourceMappingURL=verify-classification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-classification.d.ts","sourceRoot":"","sources":["../../../src/arp/intelligence/verify-classification.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EAEnB,0BAA0B,EAC1B,yBAAyB,EAC1B,MAAM,UAAU,CAAC;AAOlB,OAAO,KAAK,EAGV,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,EAAE,eACnB,CAAC;AAEtB;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAY,CAAC;AAehD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAiB5E,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAGpD,CAAC;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,UAAU,CAIZ;AAeD;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAmJpC;AAkED;;;;;;;;;;GAUG;AACH,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAMpC"}
@@ -0,0 +1,329 @@
1
+ "use strict";
2
+ /**
3
+ * NanoMind-Guard classification verifier (AIComply P1, producer side).
4
+ *
5
+ * This module is the producer-side companion to the L0-comply gate on
6
+ * `IntelligenceCoordinator`. NanoMind-Guard produces classification labels
7
+ * for runtime events; every result it emits is hybrid-signed with
8
+ * Ed25519+ML-DSA-44 (the high-throughput variant, deliberately chosen over
9
+ * ML-DSA-65 to keep per-event signing cost bounded). Before the coordinator
10
+ * can trust a classification, the signature must verify and the class must
11
+ * pass a tier-keyed rejection matrix that bounds what a given capability
12
+ * tier can ever emit, regardless of what the per-manifest permitted list
13
+ * says.
14
+ *
15
+ * The order of checks is:
16
+ *
17
+ * 1. Schema sanity of the result object and signature block.
18
+ * 2. Algorithm gate: the signature must advertise Ed25519+ML-DSA-44.
19
+ * Anything else is refused before any crypto runs, so an attacker
20
+ * cannot downgrade the Guard to a weaker algorithm.
21
+ * 3. Key and signature byte-size checks after base64 decode. Node's
22
+ * `Buffer.from(_, 'base64')` is permissive, so malformed inputs are
23
+ * caught here as KEY_FORMAT_ERROR rather than falling through to a
24
+ * SIGNATURE_INVALID that hides a structural problem.
25
+ * 4. Hybrid signature verification over the canonical signed payload.
26
+ * Both halves must pass; the underlying `hybridVerify` is
27
+ * non-short-circuit for timing reasons.
28
+ * 5. Freshness: the signed timestamp must be within `maxAgeMs` of now and
29
+ * must not be more than `futureSkewMs` in the future.
30
+ * 6. Rejection matrix keyed on `manifest.tier`. Any classification on the
31
+ * absolute deny list is rejected regardless of tier. Any classification
32
+ * whose minimum required tier exceeds the manifest's tier is rejected.
33
+ * Any classification not in the registry is rejected as unknown
34
+ * (parse-to-deny).
35
+ *
36
+ * A verified result returns `{valid: true, classification}`; the caller
37
+ * assigns `event.data.classification = result.classification` before
38
+ * handing the event to the coordinator, where the session 26 comply gate
39
+ * takes over and enforces the per-manifest permitted/prohibited lists. This
40
+ * is a defense-in-depth composition: the rejection matrix here is a hard
41
+ * ceiling that even a permissive manifest cannot override; the per-manifest
42
+ * lists are a narrower policy on top of that ceiling.
43
+ *
44
+ * Parse-to-deny (CR-001) applies to every failure path. The function never
45
+ * throws; all rejection branches return a typed `{valid: false}` object.
46
+ * Callers must treat `valid === false` as authoritative and refuse to
47
+ * populate `event.data.classification` on failure.
48
+ */
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.ABSOLUTE_DENY_CLASSES = exports.CLASSIFICATION_MIN_TIER = exports.DEFAULT_FUTURE_SKEW_MS = exports.DEFAULT_MAX_AGE_MS = exports.GUARD_SIGNATURE_ALGORITHM = void 0;
51
+ exports.canonicalizeGuardResultPayload = canonicalizeGuardResultPayload;
52
+ exports.verifyClassification = verifyClassification;
53
+ exports.applyVerifiedClassification = applyVerifiedClassification;
54
+ const hybrid_signing_1 = require("../crypto/hybrid-signing");
55
+ /**
56
+ * Only hybrid algorithm accepted for NanoMind-Guard classification results.
57
+ * ML-DSA-44 is the FIPS 204 high-throughput variant. Do not accept ML-DSA-65
58
+ * here: the manifest loader uses ML-DSA-65 for long-lived capability
59
+ * manifests, and keeping the two algorithm lanes disjoint prevents a
60
+ * manifest key from being mistakenly used to mint per-event classifications.
61
+ */
62
+ exports.GUARD_SIGNATURE_ALGORITHM = 'Ed25519+ML-DSA-44';
63
+ /**
64
+ * Default freshness window for a Guard signature. Per-event signing is
65
+ * expected to complete well under a second, so 5 minutes is a generous
66
+ * upper bound that still closes the replay window.
67
+ */
68
+ exports.DEFAULT_MAX_AGE_MS = 5 * 60 * 1000;
69
+ /**
70
+ * Default tolerance for signatures that appear to be timestamped in the
71
+ * future. Accounts for small clock skew between the Guard and the
72
+ * coordinator; anything beyond this is a bug or an attack.
73
+ */
74
+ exports.DEFAULT_FUTURE_SKEW_MS = 30 * 1000;
75
+ /**
76
+ * Total order on capability tiers. A classification requiring tier T is
77
+ * permitted only when the manifest's tier is at least T. Synchronized with
78
+ * `CapabilityTier` in `../types.ts`.
79
+ */
80
+ const TIER_LEVEL = {
81
+ minimal: 0,
82
+ read: 1,
83
+ execute: 2,
84
+ mutate: 3,
85
+ privileged: 4,
86
+ };
87
+ /**
88
+ * Minimum capability tier required to act on a given classification. A
89
+ * classification not in this registry is treated as unknown and denied
90
+ * outright (parse-to-deny, CR-001). Callers that want to allow a new class
91
+ * must add it here first; silent acceptance is a vulnerability.
92
+ *
93
+ * The exact values are policy, not physics: they are the floor below which
94
+ * ARP will not execute the class regardless of the per-manifest envelope.
95
+ * A more permissive tier still has to pass the per-manifest comply gate
96
+ * inside the coordinator before the class actually runs.
97
+ */
98
+ exports.CLASSIFICATION_MIN_TIER = {
99
+ // Tier 0: minimal -- read-only, no side effects
100
+ 'documentation': 'minimal',
101
+ // Tier 1: read -- observe state, no mutation
102
+ 'code-analysis': 'read',
103
+ 'data-read': 'read',
104
+ // Tier 2: execute -- sandboxed side effects and controlled egress
105
+ 'code-generation': 'execute',
106
+ 'network-egress': 'execute',
107
+ 'process-spawn': 'execute',
108
+ // Tier 3: mutate -- write user-visible state
109
+ 'data-write': 'mutate',
110
+ 'file-write': 'mutate',
111
+ // Tier 4: privileged -- irreversible or cross-user effects
112
+ 'file-delete': 'privileged',
113
+ 'system-mutation': 'privileged',
114
+ 'privileged-operation': 'privileged',
115
+ };
116
+ /**
117
+ * Classifications that are denied at every tier, including privileged.
118
+ * Raw credential access is always routed through the credential broker, so
119
+ * a Guard result labelled `credential-access` or `credential-exfiltration`
120
+ * is by construction a signal that something is wrong. Parse-to-deny.
121
+ */
122
+ exports.ABSOLUTE_DENY_CLASSES = new Set([
123
+ 'credential-access',
124
+ 'credential-exfiltration',
125
+ ]);
126
+ /**
127
+ * Produce canonical signed-payload bytes for a NanoMind-Guard result.
128
+ * Exported so out-of-repo signers can produce byte-identical payloads. Any
129
+ * drift between signer and verifier defeats verification.
130
+ *
131
+ * Canonicalization rules:
132
+ * 1. Remove the `signature` field if present.
133
+ * 2. Serialize as JSON with recursively sorted object keys and no
134
+ * whitespace between tokens.
135
+ * 3. Encode as UTF-8.
136
+ */
137
+ function canonicalizeGuardResultPayload(payload) {
138
+ const stripped = { ...payload };
139
+ delete stripped.signature;
140
+ return new TextEncoder().encode(stableStringify(stripped));
141
+ }
142
+ function stableStringify(value) {
143
+ if (value === null || typeof value !== 'object')
144
+ return JSON.stringify(value);
145
+ if (Array.isArray(value)) {
146
+ return `[${value.map((v) => stableStringify(v)).join(',')}]`;
147
+ }
148
+ const obj = value;
149
+ const keys = Object.keys(obj).sort();
150
+ const pairs = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`);
151
+ return `{${pairs.join(',')}}`;
152
+ }
153
+ /**
154
+ * Verify a NanoMind-Guard classification result and clear it against the
155
+ * capability manifest's tier. Never throws; every failure path returns a
156
+ * typed `{valid: false, code, reason}` the caller routes on.
157
+ *
158
+ * On success, the returned `classification` is the cleared label the caller
159
+ * should write into `event.data.classification` before handing the event to
160
+ * the coordinator. The per-manifest permitted/prohibited envelope is NOT
161
+ * applied here; the coordinator's L0-comply gate handles that layer.
162
+ */
163
+ async function verifyClassification(result, options) {
164
+ // 1. Schema sanity. We refuse to crypto-verify a malformed object.
165
+ const schemaError = validateResultSchema(result);
166
+ if (schemaError !== null) {
167
+ return invalid('SCHEMA_ERROR', schemaError);
168
+ }
169
+ // 2. Algorithm gate. The Guard MUST advertise Ed25519+ML-DSA-44. Refusing
170
+ // anything else prevents algorithm downgrade, and prevents a manifest
171
+ // key (ML-DSA-65) from being replayed as a classification signing key.
172
+ const sig = result.signature;
173
+ if (sig.alg !== exports.GUARD_SIGNATURE_ALGORITHM) {
174
+ return invalid('ALGORITHM_UNSUPPORTED', `signature algorithm must be ${exports.GUARD_SIGNATURE_ALGORITHM}, got ${JSON.stringify(sig.alg)}`);
175
+ }
176
+ if (options.guardPublicKey.algorithm !== exports.GUARD_SIGNATURE_ALGORITHM) {
177
+ return invalid('ALGORITHM_UNSUPPORTED', `guard public key algorithm must be ${exports.GUARD_SIGNATURE_ALGORITHM}, got ${JSON.stringify(options.guardPublicKey.algorithm)}`);
178
+ }
179
+ if (options.guardPublicKey.mldsaVariant !== 'ML-DSA-44') {
180
+ return invalid('ALGORITHM_UNSUPPORTED', `guard public key mldsaVariant must be ML-DSA-44, got ${JSON.stringify(options.guardPublicKey.mldsaVariant)}`);
181
+ }
182
+ // 3. Decode keys and signature. Base64 decode followed by FIPS 204 size
183
+ // checks; any failure here is KEY_FORMAT_ERROR so callers can tell
184
+ // "structurally malformed" apart from "cryptographically wrong".
185
+ let publicKeyBytes;
186
+ let signatureBytes;
187
+ try {
188
+ const encodedPk = options.guardPublicKey;
189
+ publicKeyBytes = (0, hybrid_signing_1.decodeHybridPublicKey)(encodedPk);
190
+ const encodedSig = {
191
+ alg: exports.GUARD_SIGNATURE_ALGORITHM,
192
+ ed25519Sig: sig.ed25519Sig,
193
+ mldsaSig: sig.mldsaSig,
194
+ ts: sig.ts,
195
+ };
196
+ signatureBytes = (0, hybrid_signing_1.decodeHybridSignature)(encodedSig);
197
+ }
198
+ catch (err) {
199
+ return invalid('KEY_FORMAT_ERROR', `failed to decode hybrid key or signature bytes: ${err.message}`);
200
+ }
201
+ if (!(0, hybrid_signing_1.validateKeySize)('Ed25519', 'publicKey', publicKeyBytes.ed25519PublicKey)) {
202
+ return invalid('KEY_FORMAT_ERROR', `ed25519 public key has wrong length: ${publicKeyBytes.ed25519PublicKey.length}`);
203
+ }
204
+ if (!(0, hybrid_signing_1.validateKeySize)('ML-DSA-44', 'publicKey', publicKeyBytes.mldsaPublicKey)) {
205
+ return invalid('KEY_FORMAT_ERROR', `ml-dsa-44 public key has wrong length: ${publicKeyBytes.mldsaPublicKey.length}`);
206
+ }
207
+ if (!(0, hybrid_signing_1.validateKeySize)('Ed25519', 'signature', signatureBytes.ed25519Sig)) {
208
+ return invalid('KEY_FORMAT_ERROR', `ed25519 signature has wrong length: ${signatureBytes.ed25519Sig.length}`);
209
+ }
210
+ if (!(0, hybrid_signing_1.validateKeySize)('ML-DSA-44', 'signature', signatureBytes.mldsaSig)) {
211
+ return invalid('KEY_FORMAT_ERROR', `ml-dsa-44 signature has wrong length: ${signatureBytes.mldsaSig.length}`);
212
+ }
213
+ // 4. Canonicalize the signed payload (result minus signature block) and
214
+ // run the non-short-circuit hybrid verifier. Both halves are evaluated on
215
+ // every call.
216
+ const canonical = canonicalizeGuardResultPayload(result);
217
+ const verifyResult = await (0, hybrid_signing_1.hybridVerify)(canonical, signatureBytes, publicKeyBytes);
218
+ if (!verifyResult.valid) {
219
+ return invalid('SIGNATURE_INVALID', verifyResult.reason ?? 'hybrid signature rejected by verifier');
220
+ }
221
+ // 5. Freshness check. Runs AFTER signature verification so that an
222
+ // attacker who manipulates the timestamp cannot distinguish "signature
223
+ // broken" from "timestamp too old" via timing or error code. A valid
224
+ // signature over a stale timestamp is still STALE.
225
+ const now = (options.now ?? Date.now)();
226
+ const maxAgeMs = options.maxAgeMs ?? exports.DEFAULT_MAX_AGE_MS;
227
+ const futureSkewMs = options.futureSkewMs ?? exports.DEFAULT_FUTURE_SKEW_MS;
228
+ const age = now - result.timestamp;
229
+ if (age > maxAgeMs) {
230
+ return invalid('STALE', `signature timestamp is ${age} ms old, exceeds maxAgeMs=${maxAgeMs}`);
231
+ }
232
+ if (-age > futureSkewMs) {
233
+ return invalid('FUTURE_DATED', `signature timestamp is ${-age} ms in the future, exceeds futureSkewMs=${futureSkewMs}`);
234
+ }
235
+ // 6. Tier rejection matrix. The absolute deny list is checked first and
236
+ // applies at every tier. Unknown classifications are parse-to-deny.
237
+ if (exports.ABSOLUTE_DENY_CLASSES.has(result.classification)) {
238
+ return invalid('ABSOLUTE_DENY', `classification ${JSON.stringify(result.classification)} is on the absolute deny list`);
239
+ }
240
+ const requiredTier = exports.CLASSIFICATION_MIN_TIER[result.classification];
241
+ if (requiredTier === undefined) {
242
+ return invalid('UNKNOWN_CLASSIFICATION', `classification ${JSON.stringify(result.classification)} is not in the tier registry; parse-to-deny`);
243
+ }
244
+ const manifestLevel = TIER_LEVEL[options.manifest.tier];
245
+ const requiredLevel = TIER_LEVEL[requiredTier];
246
+ if (manifestLevel < requiredLevel) {
247
+ return invalid('TIER_REJECTED', `classification ${JSON.stringify(result.classification)} requires tier ${requiredTier}, manifest tier is ${options.manifest.tier}`);
248
+ }
249
+ return {
250
+ valid: true,
251
+ classification: result.classification,
252
+ tier: options.manifest.tier,
253
+ confidence: result.confidence,
254
+ };
255
+ }
256
+ /**
257
+ * Validate the runtime shape of a `NanoMindGuardResult`. Returns a
258
+ * human-readable error string on failure, or `null` if the result passes.
259
+ * Kept as a string-returning helper so the caller can wrap the result in a
260
+ * typed `invalid()` without mixing exception and value control flow.
261
+ */
262
+ function validateResultSchema(result) {
263
+ if (result === null || typeof result !== 'object') {
264
+ return 'result must be an object';
265
+ }
266
+ if (typeof result.classification !== 'string' || result.classification.length === 0) {
267
+ return 'classification must be a non-empty string';
268
+ }
269
+ if (typeof result.confidence !== 'number' ||
270
+ !Number.isFinite(result.confidence) ||
271
+ result.confidence < 0 ||
272
+ result.confidence > 1) {
273
+ return 'confidence must be a finite number in [0, 1]';
274
+ }
275
+ if (typeof result.modelVersion !== 'string' || result.modelVersion.length === 0) {
276
+ return 'modelVersion must be a non-empty string';
277
+ }
278
+ if (typeof result.contentHash !== 'string' ||
279
+ !/^[0-9a-fA-F]{64}$/.test(result.contentHash)) {
280
+ return 'contentHash must be a 64-character hex string (SHA-256)';
281
+ }
282
+ if (typeof result.timestamp !== 'number' || !Number.isFinite(result.timestamp)) {
283
+ return 'timestamp must be a finite number (Unix ms)';
284
+ }
285
+ const sig = result.signature;
286
+ if (sig === null || typeof sig !== 'object') {
287
+ return 'signature must be a mapping';
288
+ }
289
+ if (typeof sig.alg !== 'string') {
290
+ return 'signature.alg must be a string';
291
+ }
292
+ if (typeof sig.ed25519Sig !== 'string' || sig.ed25519Sig.length === 0) {
293
+ return 'signature.ed25519Sig must be a non-empty base64 string';
294
+ }
295
+ if (typeof sig.mldsaSig !== 'string' || sig.mldsaSig.length === 0) {
296
+ return 'signature.mldsaSig must be a non-empty base64 string';
297
+ }
298
+ if (typeof sig.ts !== 'number' || !Number.isFinite(sig.ts)) {
299
+ return 'signature.ts must be a finite number';
300
+ }
301
+ return null;
302
+ }
303
+ /**
304
+ * Ensure the structurally identical invalid-result shape across every
305
+ * failure branch. Kept as a tiny helper so the TypeScript discriminant on
306
+ * `valid` narrows correctly in callers.
307
+ */
308
+ function invalid(code, reason) {
309
+ return { valid: false, code, reason };
310
+ }
311
+ /**
312
+ * Convenience wrapper: verify a Guard result and, on success, write the
313
+ * cleared classification into `event.data.classification` so the
314
+ * coordinator's L0-comply gate can consume it. Returns the verification
315
+ * result regardless of outcome so callers can route on the reason without
316
+ * re-running verification. On rejection, `event.data.classification` is
317
+ * LEFT UNCHANGED -- a failed verification must never plant a classification.
318
+ *
319
+ * The `event.data` argument is typed as `Record<string, unknown>` because
320
+ * that matches `ARPEvent.data`; the caller passes `event.data` directly.
321
+ */
322
+ async function applyVerifiedClassification(eventData, result, options) {
323
+ const verifyResult = await verifyClassification(result, options);
324
+ if (verifyResult.valid) {
325
+ eventData.classification = verifyResult.classification;
326
+ }
327
+ return verifyResult;
328
+ }
329
+ //# sourceMappingURL=verify-classification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-classification.js","sourceRoot":"","sources":["../../../src/arp/intelligence/verify-classification.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { ProxyConfig } from '../types';
1
+ import type { ProxyConfig, CapabilityManifest, ManifestRejectionLog } from '../types';
2
2
  import type { EventEngine } from '../engine/event-engine';
3
3
  import type { PromptInterceptor } from '../interceptors/prompt';
4
4
  import type { MCPProtocolInterceptor } from '../interceptors/mcp-protocol';
@@ -8,20 +8,50 @@ export interface ARPProxyDeps {
8
8
  promptInterceptor?: PromptInterceptor;
9
9
  mcpInterceptor?: MCPProtocolInterceptor;
10
10
  a2aInterceptor?: A2AProtocolInterceptor;
11
+ /**
12
+ * Optional hook invoked when a capability manifest is rejected at proxy
13
+ * start. Implementations should forward the structured log to a SIEM or
14
+ * audit trail. If not provided, a single-line structured JSON record is
15
+ * written to stderr via `console.error` so that a deployed proxy still
16
+ * leaves evidence of the rejection.
17
+ *
18
+ * The rejection entry never crosses the wire to clients; clients only see
19
+ * a generic 403 deny reason.
20
+ */
21
+ onManifestRejection?: (entry: ManifestRejectionLog) => void;
11
22
  }
12
- /**
13
- * ARP HTTP Reverse Proxy — sits between clients and upstream AI services,
14
- * inspecting requests and responses for AI-layer threats.
15
- *
16
- * Zero external dependencies (uses Node.js built-in http module).
17
- * Alert-only by default; optional blockOnDetection mode.
18
- */
19
23
  export declare class ARPProxy {
20
24
  private readonly config;
21
25
  private readonly deps;
22
26
  private server;
27
+ /**
28
+ * Loaded capability manifest once verification succeeds at start(). Kept on
29
+ * the instance so downstream wiring (e.g. IntelligenceCoordinator comply
30
+ * checks) can read it without re-loading the YAML.
31
+ */
32
+ private manifest;
33
+ /**
34
+ * Set to true when manifest loading failed at start(). In this state the
35
+ * HTTP server still accepts connections (so the deploy does not crash) but
36
+ * every request is answered with the generic 403 deny reason. Fail closed
37
+ * per CR-001.
38
+ */
39
+ private manifestRejected;
23
40
  constructor(config: ProxyConfig, deps: ARPProxyDeps);
41
+ /** The verified manifest, or null if none was configured / it was rejected. */
42
+ getManifest(): CapabilityManifest | null;
43
+ /** True if the proxy is in deny-all state due to a manifest rejection. */
44
+ isManifestRejected(): boolean;
24
45
  start(): Promise<void>;
46
+ /**
47
+ * Emit a structured log entry for a manifest rejection. Client responses
48
+ * only ever carry the generic deny reason; the discrete error code and any
49
+ * loader-provided reason stay in the log channel.
50
+ *
51
+ * Wraps the user-supplied hook in a try/catch so that a misbehaving hook
52
+ * cannot convert a soft rejection into a hard crash.
53
+ */
54
+ private reportManifestRejection;
25
55
  stop(): Promise<void>;
26
56
  getPort(): number;
27
57
  private handleRequest;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/arp/proxy/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAA2B,MAAM,UAAU,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAG3E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,cAAc,CAAC,EAAE,sBAAsB,CAAC;CACzC;AAED;;;;;;GAMG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,MAAM,CAA4B;gBAE9B,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY;IAK7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,OAAO,IAAI,MAAM;YAUH,aAAa;IAiD3B,OAAO,CAAC,YAAY;IAQpB;;;OAGG;YACW,cAAc;IA8B5B;;OAEG;YACW,eAAe;IA+B7B,sFAAsF;IACtF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAc;IAEzD;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,qBAAqB;IAwB7B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,kBAAkB;IAgC1B,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,iBAAiB;IAmDzB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;CAmBzB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/arp/proxy/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EAGX,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAO3E,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC;;;;;;;;;OASG;IACH,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC7D;AAiBD,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,MAAM,CAA4B;IAC1C;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAmC;IACnD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAS;gBAErB,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY;IAKnD,+EAA+E;IAC/E,WAAW,IAAI,kBAAkB,GAAG,IAAI;IAIxC,0EAA0E;IAC1E,kBAAkB,IAAI,OAAO;IAIvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC5B;;;;;;;OAOG;IACH,OAAO,CAAC,uBAAuB;IAmCzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,OAAO,IAAI,MAAM;YAUH,aAAa;IAyD3B,OAAO,CAAC,YAAY;IAQpB;;;OAGG;YACW,cAAc;IA8B5B;;OAEG;YACW,eAAe;IA+B7B,sFAAsF;IACtF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAc;IAEzD;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,qBAAqB;IAwB7B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,kBAAkB;IAgC1B,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,iBAAiB;IAmDzB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;CAmBzB"}