@datacules/agent-identity-anomaly 0.10.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +109 -0
- package/dist/cjs/index.js +134 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +130 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types/index.d.ts +64 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +16 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Datacules Agent Identity License — Version 1.0
|
|
2
|
+
Copyright (c) 2026 Datacules LLC. All rights reserved.
|
|
3
|
+
|
|
4
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
PREAMBLE
|
|
6
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
This software — Agent Identity & Auth Patterns — is developed and owned by
|
|
9
|
+
Datacules LLC. It is made available to the public as open-source software
|
|
10
|
+
under the permissive terms below.
|
|
11
|
+
|
|
12
|
+
Datacules LLC retains ownership and authorship of this software while
|
|
13
|
+
granting broad, royalty-free rights for anyone to use, copy, modify, and
|
|
14
|
+
distribute it — in commercial or non-commercial contexts — without requiring
|
|
15
|
+
that derivative works also become open source.
|
|
16
|
+
|
|
17
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
TERMS AND CONDITIONS
|
|
19
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
1. PERMISSION TO USE
|
|
22
|
+
|
|
23
|
+
Permission is hereby granted, free of charge, to any person or
|
|
24
|
+
organization obtaining a copy of this software and associated
|
|
25
|
+
documentation files (the "Software"), to use, copy, modify, merge,
|
|
26
|
+
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
27
|
+
and to permit persons to whom the Software is furnished to do so,
|
|
28
|
+
subject to the conditions below.
|
|
29
|
+
|
|
30
|
+
2. ATTRIBUTION
|
|
31
|
+
|
|
32
|
+
a. Redistributions of source code must retain this copyright notice,
|
|
33
|
+
this list of conditions, and the disclaimer below.
|
|
34
|
+
|
|
35
|
+
b. Redistributions in binary form or as a product must reproduce this
|
|
36
|
+
copyright notice, this list of conditions, and the disclaimer in the
|
|
37
|
+
documentation and/or other materials provided with the distribution.
|
|
38
|
+
|
|
39
|
+
c. Neither the name "Datacules LLC" nor the names of its contributors
|
|
40
|
+
may be used to endorse or promote products derived from this Software
|
|
41
|
+
without prior written permission from Datacules LLC.
|
|
42
|
+
|
|
43
|
+
3. COMMERCIAL USE
|
|
44
|
+
|
|
45
|
+
Use of this Software in commercial products, SaaS platforms, internal
|
|
46
|
+
enterprise tools, or any revenue-generating context is explicitly
|
|
47
|
+
permitted without royalty, fee, or additional licensing agreement,
|
|
48
|
+
provided that the conditions in Section 2 (Attribution) are met.
|
|
49
|
+
|
|
50
|
+
4. NO COPYLEFT / NO VIRAL REQUIREMENT
|
|
51
|
+
|
|
52
|
+
This license does NOT require that derivative works, modifications,
|
|
53
|
+
or software that uses or embeds this Software be made open source.
|
|
54
|
+
You may incorporate this Software into proprietary or closed-source
|
|
55
|
+
products under your own license terms.
|
|
56
|
+
|
|
57
|
+
5. MODIFICATIONS
|
|
58
|
+
|
|
59
|
+
Modified versions of the Software may be distributed under the same
|
|
60
|
+
terms as this license or under any other permissive open-source
|
|
61
|
+
license (e.g. MIT, Apache 2.0, BSD), provided that:
|
|
62
|
+
|
|
63
|
+
a. The original copyright notice of Datacules LLC is preserved.
|
|
64
|
+
b. Modifications are clearly documented and distinguished from the
|
|
65
|
+
original work.
|
|
66
|
+
|
|
67
|
+
6. COMPATIBILITY
|
|
68
|
+
|
|
69
|
+
This license is compatible with other permissive open-source licenses
|
|
70
|
+
such as MIT, BSD 2-Clause, BSD 3-Clause, and Apache License 2.0. It
|
|
71
|
+
is also GPL-compatible — this Software may coexist with GPL-licensed
|
|
72
|
+
code, though this Software itself is not distributed under the GPL.
|
|
73
|
+
|
|
74
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
75
|
+
DISCLAIMER
|
|
76
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
THIS SOFTWARE IS PROVIDED BY DATACULES LLC AND CONTRIBUTORS "AS IS" AND
|
|
79
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
80
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
81
|
+
AND NON-INFRINGEMENT ARE DISCLAIMED.
|
|
82
|
+
|
|
83
|
+
IN NO EVENT SHALL DATACULES LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
84
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
85
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
86
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
87
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
88
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
89
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
90
|
+
|
|
91
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
92
|
+
SUMMARY (non-binding)
|
|
93
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
✔ Use freely — commercial, proprietary, or open-source projects
|
|
96
|
+
✔ Modify and distribute with or without changes
|
|
97
|
+
✔ Sell products built on this Software
|
|
98
|
+
✔ No royalties or fees
|
|
99
|
+
✔ No requirement to open-source your own code
|
|
100
|
+
✔ Attribution to Datacules LLC required in source and binary distributions
|
|
101
|
+
✗ Do not use "Datacules LLC" to endorse derived products without permission
|
|
102
|
+
|
|
103
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
104
|
+
CONTACT
|
|
105
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
Datacules LLC
|
|
108
|
+
For licensing enquiries: legal@datacules.com
|
|
109
|
+
Product: https://github.com/hvrcharon1/agent-identity
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AnomalyDetector = void 0;
|
|
4
|
+
function freshBaseline() {
|
|
5
|
+
return {
|
|
6
|
+
sampleCount: 0,
|
|
7
|
+
knownCredentialKinds: new Set(),
|
|
8
|
+
knownActions: new Set(),
|
|
9
|
+
knownResourceKinds: new Set(),
|
|
10
|
+
knownProviders: new Set(),
|
|
11
|
+
ewmaRatePerHour: 0,
|
|
12
|
+
callsThisHour: 0,
|
|
13
|
+
hourWindowStart: Date.now(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
class AnomalyDetector {
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.baselines = new Map();
|
|
20
|
+
this.policy = {
|
|
21
|
+
lowAction: 'warn',
|
|
22
|
+
mediumAction: 'warn',
|
|
23
|
+
highAction: 'warn',
|
|
24
|
+
baselineSamples: 20,
|
|
25
|
+
rateSpikeThreshold: 3.0,
|
|
26
|
+
...config.policy,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Wrap a resolveAsync call with anomaly detection.
|
|
31
|
+
* Returns null if the policy action is 'block' and an anomaly is detected.
|
|
32
|
+
*/
|
|
33
|
+
async observe(ctx, resolveFunc) {
|
|
34
|
+
const baseline = this.getOrCreate(ctx.userId);
|
|
35
|
+
const anomalies = this.score(ctx, baseline);
|
|
36
|
+
for (const anomaly of anomalies) {
|
|
37
|
+
await this.emitAnomaly(ctx, anomaly);
|
|
38
|
+
const action = this.actionForSeverity(anomaly.severity);
|
|
39
|
+
if (action === 'block')
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const resolved = await resolveFunc();
|
|
43
|
+
if (resolved)
|
|
44
|
+
this.updateBaseline(ctx, resolved, baseline);
|
|
45
|
+
return resolved;
|
|
46
|
+
}
|
|
47
|
+
/** Reset a specific agent's baseline (call after investigating an anomaly) */
|
|
48
|
+
resetBaseline(userId) {
|
|
49
|
+
this.baselines.delete(userId);
|
|
50
|
+
}
|
|
51
|
+
getOrCreate(userId) {
|
|
52
|
+
let b = this.baselines.get(userId);
|
|
53
|
+
if (!b) {
|
|
54
|
+
b = freshBaseline();
|
|
55
|
+
this.baselines.set(userId, b);
|
|
56
|
+
}
|
|
57
|
+
return b;
|
|
58
|
+
}
|
|
59
|
+
score(ctx, b) {
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
// Roll hourly window and count calls even during baseline collection
|
|
62
|
+
if (now - b.hourWindowStart > 3600000) {
|
|
63
|
+
b.callsThisHour = 0;
|
|
64
|
+
b.hourWindowStart = now;
|
|
65
|
+
}
|
|
66
|
+
b.callsThisHour += 1;
|
|
67
|
+
if (b.sampleCount < this.policy.baselineSamples)
|
|
68
|
+
return []; // still collecting baseline
|
|
69
|
+
const events = [];
|
|
70
|
+
const ts = new Date().toISOString();
|
|
71
|
+
// Rate spike: current hourly rate vs EWMA
|
|
72
|
+
const currentRate = b.callsThisHour;
|
|
73
|
+
if (b.ewmaRatePerHour > 0 && currentRate > b.ewmaRatePerHour * this.policy.rateSpikeThreshold) {
|
|
74
|
+
events.push({ signal: 'rate_spike', severity: 'high', baselineValue: b.ewmaRatePerHour, observedValue: currentRate, userId: ctx.userId, timestamp: ts });
|
|
75
|
+
}
|
|
76
|
+
// New action type
|
|
77
|
+
if (!b.knownActions.has(ctx.action)) {
|
|
78
|
+
events.push({ signal: 'new_action_type', severity: 'medium', baselineValue: [...b.knownActions], observedValue: ctx.action, userId: ctx.userId, timestamp: ts });
|
|
79
|
+
}
|
|
80
|
+
// New resource kind
|
|
81
|
+
if (!b.knownResourceKinds.has(ctx.resourceKind)) {
|
|
82
|
+
events.push({ signal: 'new_resource_kind', severity: 'medium', baselineValue: [...b.knownResourceKinds], observedValue: ctx.resourceKind, userId: ctx.userId, timestamp: ts });
|
|
83
|
+
}
|
|
84
|
+
// New provider
|
|
85
|
+
if (!b.knownProviders.has(ctx.provider)) {
|
|
86
|
+
events.push({ signal: 'new_provider', severity: 'low', baselineValue: [...b.knownProviders], observedValue: ctx.provider, userId: ctx.userId, timestamp: ts });
|
|
87
|
+
}
|
|
88
|
+
return events;
|
|
89
|
+
}
|
|
90
|
+
updateBaseline(ctx, resolved, b) {
|
|
91
|
+
b.sampleCount += 1;
|
|
92
|
+
b.knownActions.add(ctx.action);
|
|
93
|
+
b.knownResourceKinds.add(ctx.resourceKind);
|
|
94
|
+
b.knownProviders.add(ctx.provider);
|
|
95
|
+
b.knownCredentialKinds.add(resolved.kind);
|
|
96
|
+
// EWMA update: alpha = 0.1
|
|
97
|
+
b.ewmaRatePerHour = b.ewmaRatePerHour === 0
|
|
98
|
+
? b.callsThisHour
|
|
99
|
+
: 0.1 * b.callsThisHour + 0.9 * b.ewmaRatePerHour;
|
|
100
|
+
}
|
|
101
|
+
actionForSeverity(severity) {
|
|
102
|
+
if (severity === 'high')
|
|
103
|
+
return this.policy.highAction;
|
|
104
|
+
if (severity === 'medium')
|
|
105
|
+
return this.policy.mediumAction;
|
|
106
|
+
return this.policy.lowAction;
|
|
107
|
+
}
|
|
108
|
+
async emitAnomaly(ctx, event) {
|
|
109
|
+
this.config.onAnomaly?.(event);
|
|
110
|
+
const entry = {
|
|
111
|
+
timestamp: event.timestamp,
|
|
112
|
+
traceId: ctx.traceId,
|
|
113
|
+
userId: ctx.userId,
|
|
114
|
+
action: 'credential.anomaly',
|
|
115
|
+
resourceId: ctx.resourceId,
|
|
116
|
+
resourceKind: ctx.resourceKind,
|
|
117
|
+
provider: ctx.provider,
|
|
118
|
+
model: ctx.model,
|
|
119
|
+
credentialId: event.credentialId ?? 'unknown',
|
|
120
|
+
credentialKind: 'fixed',
|
|
121
|
+
resolvedFor: ctx.userId,
|
|
122
|
+
signal: event.signal,
|
|
123
|
+
severity: event.severity,
|
|
124
|
+
baselineValue: event.baselineValue,
|
|
125
|
+
observedValue: event.observedValue,
|
|
126
|
+
};
|
|
127
|
+
// AuditLogger.log() returns void | Promise<void>. Wrap in Promise.resolve()
|
|
128
|
+
// so .catch() is always valid regardless of whether the implementation is
|
|
129
|
+
// sync (returns void) or async (returns Promise<void>).
|
|
130
|
+
await Promise.resolve(this.config.logger.log(entry)).catch(console.error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.AnomalyDetector = AnomalyDetector;
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
function freshBaseline() {
|
|
2
|
+
return {
|
|
3
|
+
sampleCount: 0,
|
|
4
|
+
knownCredentialKinds: new Set(),
|
|
5
|
+
knownActions: new Set(),
|
|
6
|
+
knownResourceKinds: new Set(),
|
|
7
|
+
knownProviders: new Set(),
|
|
8
|
+
ewmaRatePerHour: 0,
|
|
9
|
+
callsThisHour: 0,
|
|
10
|
+
hourWindowStart: Date.now(),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export class AnomalyDetector {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.config = config;
|
|
16
|
+
this.baselines = new Map();
|
|
17
|
+
this.policy = {
|
|
18
|
+
lowAction: 'warn',
|
|
19
|
+
mediumAction: 'warn',
|
|
20
|
+
highAction: 'warn',
|
|
21
|
+
baselineSamples: 20,
|
|
22
|
+
rateSpikeThreshold: 3.0,
|
|
23
|
+
...config.policy,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Wrap a resolveAsync call with anomaly detection.
|
|
28
|
+
* Returns null if the policy action is 'block' and an anomaly is detected.
|
|
29
|
+
*/
|
|
30
|
+
async observe(ctx, resolveFunc) {
|
|
31
|
+
const baseline = this.getOrCreate(ctx.userId);
|
|
32
|
+
const anomalies = this.score(ctx, baseline);
|
|
33
|
+
for (const anomaly of anomalies) {
|
|
34
|
+
await this.emitAnomaly(ctx, anomaly);
|
|
35
|
+
const action = this.actionForSeverity(anomaly.severity);
|
|
36
|
+
if (action === 'block')
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const resolved = await resolveFunc();
|
|
40
|
+
if (resolved)
|
|
41
|
+
this.updateBaseline(ctx, resolved, baseline);
|
|
42
|
+
return resolved;
|
|
43
|
+
}
|
|
44
|
+
/** Reset a specific agent's baseline (call after investigating an anomaly) */
|
|
45
|
+
resetBaseline(userId) {
|
|
46
|
+
this.baselines.delete(userId);
|
|
47
|
+
}
|
|
48
|
+
getOrCreate(userId) {
|
|
49
|
+
let b = this.baselines.get(userId);
|
|
50
|
+
if (!b) {
|
|
51
|
+
b = freshBaseline();
|
|
52
|
+
this.baselines.set(userId, b);
|
|
53
|
+
}
|
|
54
|
+
return b;
|
|
55
|
+
}
|
|
56
|
+
score(ctx, b) {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
// Roll hourly window and count calls even during baseline collection
|
|
59
|
+
if (now - b.hourWindowStart > 3600000) {
|
|
60
|
+
b.callsThisHour = 0;
|
|
61
|
+
b.hourWindowStart = now;
|
|
62
|
+
}
|
|
63
|
+
b.callsThisHour += 1;
|
|
64
|
+
if (b.sampleCount < this.policy.baselineSamples)
|
|
65
|
+
return []; // still collecting baseline
|
|
66
|
+
const events = [];
|
|
67
|
+
const ts = new Date().toISOString();
|
|
68
|
+
// Rate spike: current hourly rate vs EWMA
|
|
69
|
+
const currentRate = b.callsThisHour;
|
|
70
|
+
if (b.ewmaRatePerHour > 0 && currentRate > b.ewmaRatePerHour * this.policy.rateSpikeThreshold) {
|
|
71
|
+
events.push({ signal: 'rate_spike', severity: 'high', baselineValue: b.ewmaRatePerHour, observedValue: currentRate, userId: ctx.userId, timestamp: ts });
|
|
72
|
+
}
|
|
73
|
+
// New action type
|
|
74
|
+
if (!b.knownActions.has(ctx.action)) {
|
|
75
|
+
events.push({ signal: 'new_action_type', severity: 'medium', baselineValue: [...b.knownActions], observedValue: ctx.action, userId: ctx.userId, timestamp: ts });
|
|
76
|
+
}
|
|
77
|
+
// New resource kind
|
|
78
|
+
if (!b.knownResourceKinds.has(ctx.resourceKind)) {
|
|
79
|
+
events.push({ signal: 'new_resource_kind', severity: 'medium', baselineValue: [...b.knownResourceKinds], observedValue: ctx.resourceKind, userId: ctx.userId, timestamp: ts });
|
|
80
|
+
}
|
|
81
|
+
// New provider
|
|
82
|
+
if (!b.knownProviders.has(ctx.provider)) {
|
|
83
|
+
events.push({ signal: 'new_provider', severity: 'low', baselineValue: [...b.knownProviders], observedValue: ctx.provider, userId: ctx.userId, timestamp: ts });
|
|
84
|
+
}
|
|
85
|
+
return events;
|
|
86
|
+
}
|
|
87
|
+
updateBaseline(ctx, resolved, b) {
|
|
88
|
+
b.sampleCount += 1;
|
|
89
|
+
b.knownActions.add(ctx.action);
|
|
90
|
+
b.knownResourceKinds.add(ctx.resourceKind);
|
|
91
|
+
b.knownProviders.add(ctx.provider);
|
|
92
|
+
b.knownCredentialKinds.add(resolved.kind);
|
|
93
|
+
// EWMA update: alpha = 0.1
|
|
94
|
+
b.ewmaRatePerHour = b.ewmaRatePerHour === 0
|
|
95
|
+
? b.callsThisHour
|
|
96
|
+
: 0.1 * b.callsThisHour + 0.9 * b.ewmaRatePerHour;
|
|
97
|
+
}
|
|
98
|
+
actionForSeverity(severity) {
|
|
99
|
+
if (severity === 'high')
|
|
100
|
+
return this.policy.highAction;
|
|
101
|
+
if (severity === 'medium')
|
|
102
|
+
return this.policy.mediumAction;
|
|
103
|
+
return this.policy.lowAction;
|
|
104
|
+
}
|
|
105
|
+
async emitAnomaly(ctx, event) {
|
|
106
|
+
this.config.onAnomaly?.(event);
|
|
107
|
+
const entry = {
|
|
108
|
+
timestamp: event.timestamp,
|
|
109
|
+
traceId: ctx.traceId,
|
|
110
|
+
userId: ctx.userId,
|
|
111
|
+
action: 'credential.anomaly',
|
|
112
|
+
resourceId: ctx.resourceId,
|
|
113
|
+
resourceKind: ctx.resourceKind,
|
|
114
|
+
provider: ctx.provider,
|
|
115
|
+
model: ctx.model,
|
|
116
|
+
credentialId: event.credentialId ?? 'unknown',
|
|
117
|
+
credentialKind: 'fixed',
|
|
118
|
+
resolvedFor: ctx.userId,
|
|
119
|
+
signal: event.signal,
|
|
120
|
+
severity: event.severity,
|
|
121
|
+
baselineValue: event.baselineValue,
|
|
122
|
+
observedValue: event.observedValue,
|
|
123
|
+
};
|
|
124
|
+
// AuditLogger.log() returns void | Promise<void>. Wrap in Promise.resolve()
|
|
125
|
+
// so .catch() is always valid regardless of whether the implementation is
|
|
126
|
+
// sync (returns void) or async (returns Promise<void>).
|
|
127
|
+
await Promise.resolve(this.config.logger.log(entry)).catch(console.error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @datacules/agent-identity-anomaly
|
|
3
|
+
*
|
|
4
|
+
* Behavioral baseline and anomaly detection for @datacules/agent-identity.
|
|
5
|
+
* Wraps the audit pipeline — no changes to routing config needed.
|
|
6
|
+
*
|
|
7
|
+
* Each agent ID builds a rolling behavioral baseline over its first N
|
|
8
|
+
* resolutions. A lightweight EWMA model scores each new resolution
|
|
9
|
+
* and emits credential.anomaly audit events when deviations are detected.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* import { AnomalyDetector } from '@datacules/agent-identity-anomaly';
|
|
13
|
+
*
|
|
14
|
+
* const detector = new AnomalyDetector({ logger, policy: { highAction: 'block' } });
|
|
15
|
+
*
|
|
16
|
+
* // Wrap resolve calls:
|
|
17
|
+
* const result = await detector.observe(ctx, () => router.resolveAsync(ctx));
|
|
18
|
+
*/
|
|
19
|
+
import type { AuditLogger, AgentRequestContext, ResolvedCredential } from '@datacules/agent-identity';
|
|
20
|
+
export type AnomalySignal = 'rate_spike' | 'new_credential_type' | 'new_action_type' | 'new_resource_kind' | 'off_hours' | 'new_provider';
|
|
21
|
+
export type AnomalySeverity = 'low' | 'medium' | 'high';
|
|
22
|
+
export type AnomalyAction = 'warn' | 'throttle' | 'block';
|
|
23
|
+
export interface AnomalyEvent {
|
|
24
|
+
signal: AnomalySignal;
|
|
25
|
+
severity: AnomalySeverity;
|
|
26
|
+
baselineValue: unknown;
|
|
27
|
+
observedValue: unknown;
|
|
28
|
+
userId: string;
|
|
29
|
+
credentialId?: string;
|
|
30
|
+
timestamp: string;
|
|
31
|
+
}
|
|
32
|
+
export interface AnomalyPolicy {
|
|
33
|
+
lowAction?: AnomalyAction;
|
|
34
|
+
mediumAction?: AnomalyAction;
|
|
35
|
+
highAction?: AnomalyAction;
|
|
36
|
+
/** How many resolutions to collect before scoring starts (default: 20) */
|
|
37
|
+
baselineSamples?: number;
|
|
38
|
+
/** Rate spike threshold multiplier (default: 3.0) */
|
|
39
|
+
rateSpikeThreshold?: number;
|
|
40
|
+
}
|
|
41
|
+
export interface AnomalyDetectorConfig {
|
|
42
|
+
logger: AuditLogger;
|
|
43
|
+
policy?: AnomalyPolicy;
|
|
44
|
+
onAnomaly?: (event: AnomalyEvent) => void;
|
|
45
|
+
}
|
|
46
|
+
export declare class AnomalyDetector {
|
|
47
|
+
private readonly config;
|
|
48
|
+
private readonly baselines;
|
|
49
|
+
private readonly policy;
|
|
50
|
+
constructor(config: AnomalyDetectorConfig);
|
|
51
|
+
/**
|
|
52
|
+
* Wrap a resolveAsync call with anomaly detection.
|
|
53
|
+
* Returns null if the policy action is 'block' and an anomaly is detected.
|
|
54
|
+
*/
|
|
55
|
+
observe(ctx: AgentRequestContext, resolveFunc: () => Promise<ResolvedCredential | null>): Promise<ResolvedCredential | null>;
|
|
56
|
+
/** Reset a specific agent's baseline (call after investigating an anomaly) */
|
|
57
|
+
resetBaseline(userId: string): void;
|
|
58
|
+
private getOrCreate;
|
|
59
|
+
private score;
|
|
60
|
+
private updateBaseline;
|
|
61
|
+
private actionForSeverity;
|
|
62
|
+
private emitAnomaly;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAiB,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIrH,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,qBAAqB,GACrB,iBAAiB,GACjB,mBAAmB,GACnB,WAAW,GACX,cAAc,CAAC;AAEnB,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AACxD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,eAAe,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,0EAA0E;IAC1E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAgCD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CAC3C;AAED,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;gBAEpB,MAAM,EAAE,qBAAqB;IAW1D;;;OAGG;IACG,OAAO,CACX,GAAG,EAAE,mBAAmB,EACxB,WAAW,EAAE,MAAM,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,GACpD,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAerC,8EAA8E;IAC9E,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAInC,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,KAAK;IAsCb,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,iBAAiB;YAMX,WAAW;CAwB1B"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datacules/agent-identity-anomaly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Anomaly detection and behavioral baseline for @datacules/agent-identity — statistical detection of unusual credential usage patterns",
|
|
6
6
|
"author": "Datacules LLC",
|
|
7
|
-
"license": "
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "https://github.com/hvrcharon1/agent-identity.git",
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
|
-
"README.md"
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
26
27
|
],
|
|
27
28
|
"scripts": {
|
|
28
|
-
"build": "tsc -p tsconfig.build.json",
|
|
29
|
+
"build": "tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json",
|
|
29
30
|
"type-check": "tsc --noEmit",
|
|
30
31
|
"lint": "eslint src --ext .ts"
|
|
31
32
|
},
|
|
@@ -34,6 +35,15 @@
|
|
|
34
35
|
"typescript": "^5"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
|
-
"@datacules/agent-identity": "^0.
|
|
38
|
-
}
|
|
38
|
+
"@datacules/agent-identity": "^0.11.1"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"agent-identity",
|
|
42
|
+
"anomaly-detection",
|
|
43
|
+
"ewma",
|
|
44
|
+
"behavioral-baseline",
|
|
45
|
+
"security",
|
|
46
|
+
"ai-agents",
|
|
47
|
+
"datacules"
|
|
48
|
+
]
|
|
39
49
|
}
|