@riocrypto/common-server 1.0.2934 → 1.0.2936
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/build/bot/gcp-logging-client.d.ts +26 -0
- package/build/bot/gcp-logging-client.js +127 -0
- package/build/bot/git-repo-cache.d.ts +33 -0
- package/build/bot/git-repo-cache.js +244 -0
- package/build/bot/github-app-auth.d.ts +15 -0
- package/build/bot/github-app-auth.js +93 -0
- package/build/bot/injection-markers.d.ts +1 -0
- package/build/bot/injection-markers.js +16 -0
- package/build/bot/k8s-client.d.ts +45 -0
- package/build/bot/k8s-client.js +151 -0
- package/build/bot/redactor.d.ts +11 -0
- package/build/bot/redactor.js +186 -0
- package/build/bot/slack-notifier.d.ts +15 -0
- package/build/bot/slack-notifier.js +54 -0
- package/build/bot/tool.d.ts +26 -0
- package/build/bot/tool.js +60 -0
- package/build/index.d.ts +15 -1
- package/build/index.js +15 -1
- package/build/models/inbound-deposit-intake.d.ts +43 -0
- package/build/models/inbound-deposit-intake.js +106 -0
- package/build/models/security-baseline.d.ts +13 -0
- package/build/models/security-baseline.js +23 -0
- package/build/models/security-bot-audit-event.d.ts +36 -0
- package/build/models/security-bot-audit-event.js +51 -0
- package/build/models/security-bot-controls.d.ts +23 -0
- package/build/models/security-bot-controls.js +42 -0
- package/build/models/security-finding.d.ts +38 -0
- package/build/models/security-finding.js +59 -0
- package/build/models/security-known-pattern.d.ts +12 -0
- package/build/models/security-known-pattern.js +28 -0
- package/build/models/security-sweep-run.d.ts +41 -0
- package/build/models/security-sweep-run.js +67 -0
- package/package.json +3 -2
- package/build/models/fintoc-deposit-intake.d.ts +0 -39
- package/build/models/fintoc-deposit-intake.js +0 -95
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildInboundDepositIntake = exports.InboundDepositIntakeStatus = void 0;
|
|
4
|
+
const common_1 = require("@riocrypto/common");
|
|
5
|
+
// One row per inbound deposit a provider has told us about, written the moment we
|
|
6
|
+
// learn the deposit exists and before any work is done on it. This is what lets a
|
|
7
|
+
// deposit survive the pod being killed mid-processing: the webhook only records
|
|
8
|
+
// that the deposit arrived, and a worker in the provider's service does the
|
|
9
|
+
// matching from here, so a restart resumes rather than forgets. It is a processing
|
|
10
|
+
// ledger, not an accounting record; the money itself is recorded in
|
|
11
|
+
// InboundBankDeposit once matching has run.
|
|
12
|
+
//
|
|
13
|
+
// Shared across providers. Each service works only the rows for its own provider,
|
|
14
|
+
// and what "processing" means for a row is that service's business.
|
|
15
|
+
var InboundDepositIntakeStatus;
|
|
16
|
+
(function (InboundDepositIntakeStatus) {
|
|
17
|
+
/** Recorded, waiting for the worker. */
|
|
18
|
+
InboundDepositIntakeStatus["Pending"] = "pending";
|
|
19
|
+
/** A worker has taken it. Reset to pending if left here too long. */
|
|
20
|
+
InboundDepositIntakeStatus["Processing"] = "processing";
|
|
21
|
+
/** Matching ran to completion, whatever it concluded. See `outcome`. */
|
|
22
|
+
InboundDepositIntakeStatus["Done"] = "done";
|
|
23
|
+
/** Matching threw and retries are exhausted. Needs a person. */
|
|
24
|
+
InboundDepositIntakeStatus["Failed"] = "failed";
|
|
25
|
+
})(InboundDepositIntakeStatus = exports.InboundDepositIntakeStatus || (exports.InboundDepositIntakeStatus = {}));
|
|
26
|
+
// Finished rows are kept a month for tracing a payment that went wrong, then
|
|
27
|
+
// dropped. Rows that never finish have no finishedAt and so never expire, which is
|
|
28
|
+
// the point: an unfinished deposit should stay visible until someone deals with it.
|
|
29
|
+
const FINISHED_ROW_TTL_SECONDS = 30 * 24 * 60 * 60;
|
|
30
|
+
const buildInboundDepositIntake = (mongoose) => {
|
|
31
|
+
if (mongoose.models.InboundDepositIntake) {
|
|
32
|
+
return mongoose.model("InboundDepositIntake");
|
|
33
|
+
}
|
|
34
|
+
const InboundDepositIntakeSchema = new mongoose.Schema({
|
|
35
|
+
provider: {
|
|
36
|
+
type: String,
|
|
37
|
+
required: true,
|
|
38
|
+
enum: Object.values(common_1.TreasuryProvider),
|
|
39
|
+
},
|
|
40
|
+
externalId: {
|
|
41
|
+
type: String,
|
|
42
|
+
required: true,
|
|
43
|
+
},
|
|
44
|
+
source: {
|
|
45
|
+
type: String,
|
|
46
|
+
required: true,
|
|
47
|
+
enum: ["webhook", "poller"],
|
|
48
|
+
},
|
|
49
|
+
externalEventId: {
|
|
50
|
+
type: String,
|
|
51
|
+
},
|
|
52
|
+
status: {
|
|
53
|
+
type: String,
|
|
54
|
+
required: true,
|
|
55
|
+
enum: Object.values(InboundDepositIntakeStatus),
|
|
56
|
+
default: InboundDepositIntakeStatus.Pending,
|
|
57
|
+
},
|
|
58
|
+
attempts: {
|
|
59
|
+
type: Number,
|
|
60
|
+
required: true,
|
|
61
|
+
default: 0,
|
|
62
|
+
},
|
|
63
|
+
outcome: {
|
|
64
|
+
type: String,
|
|
65
|
+
},
|
|
66
|
+
processed: {
|
|
67
|
+
type: Boolean,
|
|
68
|
+
},
|
|
69
|
+
lastError: {
|
|
70
|
+
type: String,
|
|
71
|
+
},
|
|
72
|
+
receivedAt: {
|
|
73
|
+
type: Date,
|
|
74
|
+
required: true,
|
|
75
|
+
},
|
|
76
|
+
startedAt: {
|
|
77
|
+
type: Date,
|
|
78
|
+
},
|
|
79
|
+
finishedAt: {
|
|
80
|
+
type: Date,
|
|
81
|
+
},
|
|
82
|
+
}, {
|
|
83
|
+
toJSON: {
|
|
84
|
+
transform(doc, ret) {
|
|
85
|
+
ret.id = ret._id.valueOf();
|
|
86
|
+
delete ret._id;
|
|
87
|
+
delete ret.__v;
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
// The dedup. A webhook delivered twice, or a deposit the poller sees after the
|
|
92
|
+
// webhook already recorded it, is an insert that fails rather than a second row.
|
|
93
|
+
// Scoped by provider so two providers' id schemes can never collide.
|
|
94
|
+
InboundDepositIntakeSchema.index({ provider: 1, externalId: 1 }, { unique: true });
|
|
95
|
+
// What each worker polls on: the oldest pending row for its provider first, and
|
|
96
|
+
// the processing rows whose startedAt says their owner died.
|
|
97
|
+
InboundDepositIntakeSchema.index({ provider: 1, status: 1, receivedAt: 1 });
|
|
98
|
+
InboundDepositIntakeSchema.index({ provider: 1, status: 1, startedAt: 1 });
|
|
99
|
+
InboundDepositIntakeSchema.index({ finishedAt: 1 }, { expireAfterSeconds: FINISHED_ROW_TTL_SECONDS });
|
|
100
|
+
InboundDepositIntakeSchema.statics.build = (attrs) => {
|
|
101
|
+
return new InboundDepositIntake(attrs);
|
|
102
|
+
};
|
|
103
|
+
const InboundDepositIntake = mongoose.model("InboundDepositIntake", InboundDepositIntakeSchema);
|
|
104
|
+
return InboundDepositIntake;
|
|
105
|
+
};
|
|
106
|
+
exports.buildInboundDepositIntake = buildInboundDepositIntake;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
export interface SecurityBaselineDoc extends mongoose.Document {
|
|
3
|
+
entityKind: string;
|
|
4
|
+
entityId: string;
|
|
5
|
+
metric: string;
|
|
6
|
+
bucket: string;
|
|
7
|
+
value: number;
|
|
8
|
+
samples: number;
|
|
9
|
+
updatedAt: Date;
|
|
10
|
+
}
|
|
11
|
+
export type SecurityBaselineModel = mongoose.Model<SecurityBaselineDoc>;
|
|
12
|
+
declare const buildSecurityBaseline: (mongoose: typeof mongoose) => SecurityBaselineModel;
|
|
13
|
+
export { buildSecurityBaseline };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSecurityBaseline = void 0;
|
|
4
|
+
const buildSecurityBaseline = (mongoose) => {
|
|
5
|
+
if (mongoose.models.SecurityBaseline) {
|
|
6
|
+
return mongoose.model("SecurityBaseline");
|
|
7
|
+
}
|
|
8
|
+
const schema = new mongoose.Schema({
|
|
9
|
+
entityKind: { type: String, required: true },
|
|
10
|
+
entityId: { type: String, required: true },
|
|
11
|
+
metric: { type: String, required: true },
|
|
12
|
+
bucket: { type: String, required: true },
|
|
13
|
+
value: { type: Number, default: 0 },
|
|
14
|
+
samples: { type: Number, default: 0 },
|
|
15
|
+
}, {
|
|
16
|
+
timestamps: { createdAt: false, updatedAt: true },
|
|
17
|
+
collection: "securityBaselines",
|
|
18
|
+
});
|
|
19
|
+
schema.index({ entityKind: 1, entityId: 1, metric: 1, bucket: 1 }, { unique: true });
|
|
20
|
+
schema.index({ updatedAt: 1 }, { expireAfterSeconds: 120 * 24 * 60 * 60 });
|
|
21
|
+
return mongoose.model("SecurityBaseline", schema);
|
|
22
|
+
};
|
|
23
|
+
exports.buildSecurityBaseline = buildSecurityBaseline;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
export declare enum SecurityBotAuditType {
|
|
3
|
+
SweepStarted = "sweepStarted",
|
|
4
|
+
SweepToolCall = "sweepToolCall",
|
|
5
|
+
SweepCompleted = "sweepCompleted",
|
|
6
|
+
SweepFailed = "sweepFailed",
|
|
7
|
+
Triage = "triage",
|
|
8
|
+
FindingStatusChanged = "findingStatusChanged",
|
|
9
|
+
RuleMuted = "ruleMuted",
|
|
10
|
+
RuleUnmuted = "ruleUnmuted",
|
|
11
|
+
ControlsChanged = "controlsChanged",
|
|
12
|
+
BudgetPaused = "budgetPaused",
|
|
13
|
+
InjectionRejected = "injectionRejected"
|
|
14
|
+
}
|
|
15
|
+
export interface SecurityBotAuditEventDoc extends mongoose.Document {
|
|
16
|
+
type: SecurityBotAuditType;
|
|
17
|
+
sweepRunId?: string;
|
|
18
|
+
findingId?: string;
|
|
19
|
+
adminAuthId?: string;
|
|
20
|
+
adminAuthEmail?: string;
|
|
21
|
+
toolName?: string;
|
|
22
|
+
toolInput?: any;
|
|
23
|
+
ok?: boolean;
|
|
24
|
+
durationMs?: number;
|
|
25
|
+
error?: string;
|
|
26
|
+
detail?: string;
|
|
27
|
+
redactionCounts?: Record<string, number>;
|
|
28
|
+
modelId?: string;
|
|
29
|
+
inputTokens?: number;
|
|
30
|
+
outputTokens?: number;
|
|
31
|
+
estimatedUsd?: number;
|
|
32
|
+
createdAt: Date;
|
|
33
|
+
}
|
|
34
|
+
export type SecurityBotAuditEventModel = mongoose.Model<SecurityBotAuditEventDoc>;
|
|
35
|
+
declare const buildSecurityBotAuditEvent: (mongoose: typeof mongoose) => SecurityBotAuditEventModel;
|
|
36
|
+
export { buildSecurityBotAuditEvent };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSecurityBotAuditEvent = exports.SecurityBotAuditType = void 0;
|
|
4
|
+
// Every model call and every admin action on security-bot, with token
|
|
5
|
+
// counts, so the daily and monthly budgets are computed from the same rows
|
|
6
|
+
// that would be reviewed after an incident.
|
|
7
|
+
var SecurityBotAuditType;
|
|
8
|
+
(function (SecurityBotAuditType) {
|
|
9
|
+
SecurityBotAuditType["SweepStarted"] = "sweepStarted";
|
|
10
|
+
SecurityBotAuditType["SweepToolCall"] = "sweepToolCall";
|
|
11
|
+
SecurityBotAuditType["SweepCompleted"] = "sweepCompleted";
|
|
12
|
+
SecurityBotAuditType["SweepFailed"] = "sweepFailed";
|
|
13
|
+
SecurityBotAuditType["Triage"] = "triage";
|
|
14
|
+
SecurityBotAuditType["FindingStatusChanged"] = "findingStatusChanged";
|
|
15
|
+
SecurityBotAuditType["RuleMuted"] = "ruleMuted";
|
|
16
|
+
SecurityBotAuditType["RuleUnmuted"] = "ruleUnmuted";
|
|
17
|
+
SecurityBotAuditType["ControlsChanged"] = "controlsChanged";
|
|
18
|
+
SecurityBotAuditType["BudgetPaused"] = "budgetPaused";
|
|
19
|
+
SecurityBotAuditType["InjectionRejected"] = "injectionRejected";
|
|
20
|
+
})(SecurityBotAuditType = exports.SecurityBotAuditType || (exports.SecurityBotAuditType = {}));
|
|
21
|
+
const buildSecurityBotAuditEvent = (mongoose) => {
|
|
22
|
+
if (mongoose.models.SecurityBotAuditEvent) {
|
|
23
|
+
return mongoose.model("SecurityBotAuditEvent");
|
|
24
|
+
}
|
|
25
|
+
const schema = new mongoose.Schema({
|
|
26
|
+
type: { type: String, enum: Object.values(SecurityBotAuditType), required: true },
|
|
27
|
+
sweepRunId: { type: String },
|
|
28
|
+
findingId: { type: String },
|
|
29
|
+
adminAuthId: { type: String },
|
|
30
|
+
adminAuthEmail: { type: String },
|
|
31
|
+
toolName: { type: String },
|
|
32
|
+
toolInput: { type: mongoose.Schema.Types.Mixed },
|
|
33
|
+
ok: { type: Boolean },
|
|
34
|
+
durationMs: { type: Number },
|
|
35
|
+
error: { type: String },
|
|
36
|
+
detail: { type: String },
|
|
37
|
+
redactionCounts: { type: mongoose.Schema.Types.Mixed },
|
|
38
|
+
modelId: { type: String },
|
|
39
|
+
inputTokens: { type: Number },
|
|
40
|
+
outputTokens: { type: Number },
|
|
41
|
+
estimatedUsd: { type: Number },
|
|
42
|
+
}, {
|
|
43
|
+
timestamps: { createdAt: true, updatedAt: false },
|
|
44
|
+
collection: "securityBotAuditEvents",
|
|
45
|
+
});
|
|
46
|
+
schema.index({ type: 1, createdAt: -1 });
|
|
47
|
+
schema.index({ sweepRunId: 1, createdAt: 1 });
|
|
48
|
+
schema.index({ findingId: 1, createdAt: 1 });
|
|
49
|
+
return mongoose.model("SecurityBotAuditEvent", schema);
|
|
50
|
+
};
|
|
51
|
+
exports.buildSecurityBotAuditEvent = buildSecurityBotAuditEvent;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
export declare const SECURITY_BOT_CONTROLS_KEY = "global";
|
|
3
|
+
export interface SecurityBotMutedRule {
|
|
4
|
+
ruleId: string;
|
|
5
|
+
until: Date;
|
|
6
|
+
mutedBy: string;
|
|
7
|
+
reason?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SecurityBotControlsDoc extends mongoose.Document {
|
|
10
|
+
key: string;
|
|
11
|
+
disabled: boolean;
|
|
12
|
+
disabledAt?: Date;
|
|
13
|
+
disabledBy?: string;
|
|
14
|
+
reason?: string;
|
|
15
|
+
sweepsPaused: boolean;
|
|
16
|
+
sweepsPausedAt?: Date;
|
|
17
|
+
sweepsPausedBy?: string;
|
|
18
|
+
sweepsPausedReason?: string;
|
|
19
|
+
mutedRules: SecurityBotMutedRule[];
|
|
20
|
+
}
|
|
21
|
+
export type SecurityBotControlsModel = mongoose.Model<SecurityBotControlsDoc>;
|
|
22
|
+
declare const buildSecurityBotControls: (mongoose: typeof mongoose) => SecurityBotControlsModel;
|
|
23
|
+
export { buildSecurityBotControls };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSecurityBotControls = exports.SECURITY_BOT_CONTROLS_KEY = void 0;
|
|
4
|
+
// Singleton (key "global"). Read before every sweep and every rule
|
|
5
|
+
// evaluation so the switch and the mutes work without a redeploy. Flipped by
|
|
6
|
+
// a super admin from the dashboard or by the bot itself when a budget cap
|
|
7
|
+
// is hit.
|
|
8
|
+
exports.SECURITY_BOT_CONTROLS_KEY = "global";
|
|
9
|
+
const buildSecurityBotControls = (mongoose) => {
|
|
10
|
+
if (mongoose.models.SecurityBotControls) {
|
|
11
|
+
return mongoose.model("SecurityBotControls");
|
|
12
|
+
}
|
|
13
|
+
const mutedRuleSchema = new mongoose.Schema({
|
|
14
|
+
ruleId: { type: String, required: true },
|
|
15
|
+
until: { type: Date, required: true },
|
|
16
|
+
mutedBy: { type: String, required: true },
|
|
17
|
+
reason: { type: String },
|
|
18
|
+
}, { _id: false });
|
|
19
|
+
const schema = new mongoose.Schema({
|
|
20
|
+
key: { type: String, required: true, unique: true },
|
|
21
|
+
disabled: { type: Boolean, default: false },
|
|
22
|
+
disabledAt: { type: Date },
|
|
23
|
+
disabledBy: { type: String },
|
|
24
|
+
reason: { type: String },
|
|
25
|
+
sweepsPaused: { type: Boolean, default: false },
|
|
26
|
+
sweepsPausedAt: { type: Date },
|
|
27
|
+
sweepsPausedBy: { type: String },
|
|
28
|
+
sweepsPausedReason: { type: String },
|
|
29
|
+
mutedRules: { type: [mutedRuleSchema], default: [] },
|
|
30
|
+
}, {
|
|
31
|
+
collection: "securityBotControls",
|
|
32
|
+
toJSON: {
|
|
33
|
+
transform(_doc, ret) {
|
|
34
|
+
delete ret._id;
|
|
35
|
+
delete ret.__v;
|
|
36
|
+
delete ret.key;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
return mongoose.model("SecurityBotControls", schema);
|
|
41
|
+
};
|
|
42
|
+
exports.buildSecurityBotControls = buildSecurityBotControls;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
import { SecurityFindingSeverity, SecurityFindingSource, SecurityFindingStatus } from "@riocrypto/common";
|
|
3
|
+
export interface SecurityFindingEvidence {
|
|
4
|
+
kind: string;
|
|
5
|
+
ref: string;
|
|
6
|
+
note?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SecurityFindingEntity {
|
|
9
|
+
kind: string;
|
|
10
|
+
id: string;
|
|
11
|
+
}
|
|
12
|
+
export interface SecurityFindingDoc extends mongoose.Document {
|
|
13
|
+
fingerprint: string;
|
|
14
|
+
ruleId: string;
|
|
15
|
+
source: SecurityFindingSource;
|
|
16
|
+
severity: SecurityFindingSeverity;
|
|
17
|
+
status: SecurityFindingStatus;
|
|
18
|
+
title: string;
|
|
19
|
+
summary: string;
|
|
20
|
+
evidence: SecurityFindingEvidence[];
|
|
21
|
+
entity?: SecurityFindingEntity;
|
|
22
|
+
lens?: string;
|
|
23
|
+
sweepRunId?: string;
|
|
24
|
+
confidence?: number;
|
|
25
|
+
firstSeenAt: Date;
|
|
26
|
+
lastSeenAt: Date;
|
|
27
|
+
count: number;
|
|
28
|
+
resolvedAt?: Date;
|
|
29
|
+
resolvedBy?: string;
|
|
30
|
+
resolutionNote?: string;
|
|
31
|
+
triageNote?: string;
|
|
32
|
+
triagedAt?: Date;
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
updatedAt: Date;
|
|
35
|
+
}
|
|
36
|
+
export type SecurityFindingModel = mongoose.Model<SecurityFindingDoc>;
|
|
37
|
+
declare const buildSecurityFinding: (mongoose: typeof mongoose) => SecurityFindingModel;
|
|
38
|
+
export { buildSecurityFinding };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSecurityFinding = void 0;
|
|
4
|
+
const common_1 = require("@riocrypto/common");
|
|
5
|
+
const buildSecurityFinding = (mongoose) => {
|
|
6
|
+
if (mongoose.models.SecurityFinding) {
|
|
7
|
+
return mongoose.model("SecurityFinding");
|
|
8
|
+
}
|
|
9
|
+
const evidenceSchema = new mongoose.Schema({
|
|
10
|
+
kind: { type: String, required: true },
|
|
11
|
+
ref: { type: String, required: true },
|
|
12
|
+
note: { type: String },
|
|
13
|
+
}, { _id: false });
|
|
14
|
+
const schema = new mongoose.Schema({
|
|
15
|
+
fingerprint: { type: String, required: true, unique: true },
|
|
16
|
+
ruleId: { type: String, required: true },
|
|
17
|
+
source: { type: String, enum: Object.values(common_1.SecurityFindingSource), required: true },
|
|
18
|
+
severity: { type: String, enum: Object.values(common_1.SecurityFindingSeverity), required: true },
|
|
19
|
+
status: {
|
|
20
|
+
type: String,
|
|
21
|
+
enum: Object.values(common_1.SecurityFindingStatus),
|
|
22
|
+
required: true,
|
|
23
|
+
default: common_1.SecurityFindingStatus.Open,
|
|
24
|
+
},
|
|
25
|
+
title: { type: String, required: true },
|
|
26
|
+
summary: { type: String, default: "" },
|
|
27
|
+
evidence: { type: [evidenceSchema], default: [] },
|
|
28
|
+
entity: {
|
|
29
|
+
type: new mongoose.Schema({ kind: { type: String, required: true }, id: { type: String, required: true } }, { _id: false }),
|
|
30
|
+
},
|
|
31
|
+
lens: { type: String },
|
|
32
|
+
sweepRunId: { type: String },
|
|
33
|
+
confidence: { type: Number },
|
|
34
|
+
firstSeenAt: { type: Date, required: true },
|
|
35
|
+
lastSeenAt: { type: Date, required: true },
|
|
36
|
+
count: { type: Number, default: 1 },
|
|
37
|
+
resolvedAt: { type: Date },
|
|
38
|
+
resolvedBy: { type: String },
|
|
39
|
+
resolutionNote: { type: String },
|
|
40
|
+
triageNote: { type: String },
|
|
41
|
+
triagedAt: { type: Date },
|
|
42
|
+
}, {
|
|
43
|
+
timestamps: true,
|
|
44
|
+
collection: "securityFindings",
|
|
45
|
+
toJSON: {
|
|
46
|
+
transform(_doc, ret) {
|
|
47
|
+
ret.id = ret._id;
|
|
48
|
+
delete ret._id;
|
|
49
|
+
delete ret.__v;
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
schema.index({ status: 1, severity: 1, lastSeenAt: -1 });
|
|
54
|
+
schema.index({ ruleId: 1, lastSeenAt: -1 });
|
|
55
|
+
schema.index({ "entity.kind": 1, "entity.id": 1, lastSeenAt: -1 });
|
|
56
|
+
schema.index({ source: 1, lastSeenAt: -1 });
|
|
57
|
+
return mongoose.model("SecurityFinding", schema);
|
|
58
|
+
};
|
|
59
|
+
exports.buildSecurityFinding = buildSecurityFinding;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
export interface SecurityKnownPatternDoc extends mongoose.Document {
|
|
3
|
+
lens: string;
|
|
4
|
+
ruleId?: string;
|
|
5
|
+
text: string;
|
|
6
|
+
createdBy: string;
|
|
7
|
+
findingId?: string;
|
|
8
|
+
createdAt: Date;
|
|
9
|
+
}
|
|
10
|
+
export type SecurityKnownPatternModel = mongoose.Model<SecurityKnownPatternDoc>;
|
|
11
|
+
declare const buildSecurityKnownPattern: (mongoose: typeof mongoose) => SecurityKnownPatternModel;
|
|
12
|
+
export { buildSecurityKnownPattern };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSecurityKnownPattern = void 0;
|
|
4
|
+
const buildSecurityKnownPattern = (mongoose) => {
|
|
5
|
+
if (mongoose.models.SecurityKnownPattern) {
|
|
6
|
+
return mongoose.model("SecurityKnownPattern");
|
|
7
|
+
}
|
|
8
|
+
const schema = new mongoose.Schema({
|
|
9
|
+
lens: { type: String, required: true },
|
|
10
|
+
ruleId: { type: String },
|
|
11
|
+
text: { type: String, required: true },
|
|
12
|
+
createdBy: { type: String, required: true },
|
|
13
|
+
findingId: { type: String },
|
|
14
|
+
}, {
|
|
15
|
+
timestamps: { createdAt: true, updatedAt: false },
|
|
16
|
+
collection: "securityKnownPatterns",
|
|
17
|
+
toJSON: {
|
|
18
|
+
transform(_doc, ret) {
|
|
19
|
+
ret.id = ret._id;
|
|
20
|
+
delete ret._id;
|
|
21
|
+
delete ret.__v;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
schema.index({ lens: 1, createdAt: -1 });
|
|
26
|
+
return mongoose.model("SecurityKnownPattern", schema);
|
|
27
|
+
};
|
|
28
|
+
exports.buildSecurityKnownPattern = buildSecurityKnownPattern;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import mongoose from "mongoose";
|
|
2
|
+
export declare enum SecuritySweepRunStatus {
|
|
3
|
+
Running = "running",
|
|
4
|
+
Completed = "completed",
|
|
5
|
+
Failed = "failed",
|
|
6
|
+
Skipped = "skipped"
|
|
7
|
+
}
|
|
8
|
+
export declare enum SecuritySweepTrigger {
|
|
9
|
+
Schedule = "schedule",
|
|
10
|
+
Signal = "signal",
|
|
11
|
+
Manual = "manual"
|
|
12
|
+
}
|
|
13
|
+
export interface SecuritySweepRunDoc extends mongoose.Document {
|
|
14
|
+
lens: string;
|
|
15
|
+
trigger: SecuritySweepTrigger;
|
|
16
|
+
triggerDetail?: string;
|
|
17
|
+
windowStart: Date;
|
|
18
|
+
windowEnd: Date;
|
|
19
|
+
status: SecuritySweepRunStatus;
|
|
20
|
+
modelId: string;
|
|
21
|
+
escalated: boolean;
|
|
22
|
+
inputSnapshot?: string;
|
|
23
|
+
output?: string;
|
|
24
|
+
findingIds: string[];
|
|
25
|
+
toolCalls: number;
|
|
26
|
+
toolErrors: number;
|
|
27
|
+
toolsAvailable: string[];
|
|
28
|
+
sourcesUnavailable: string[];
|
|
29
|
+
inputTokens: number;
|
|
30
|
+
outputTokens: number;
|
|
31
|
+
estimatedUsd: number;
|
|
32
|
+
error?: string;
|
|
33
|
+
requestedBy?: string;
|
|
34
|
+
leaseUntil?: Date;
|
|
35
|
+
startedAt: Date;
|
|
36
|
+
finishedAt?: Date;
|
|
37
|
+
createdAt: Date;
|
|
38
|
+
}
|
|
39
|
+
export type SecuritySweepRunModel = mongoose.Model<SecuritySweepRunDoc>;
|
|
40
|
+
declare const buildSecuritySweepRun: (mongoose: typeof mongoose) => SecuritySweepRunModel;
|
|
41
|
+
export { buildSecuritySweepRun };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSecuritySweepRun = exports.SecuritySweepTrigger = exports.SecuritySweepRunStatus = void 0;
|
|
4
|
+
// One row per AI sweep. The redacted input snapshot is kept next to the
|
|
5
|
+
// output so a false positive can be diagnosed by looking at exactly what the
|
|
6
|
+
// model saw, and so a prompt change can be replayed against stored inputs.
|
|
7
|
+
// Both are stripped from toJSON; the super admin trace route exposes them.
|
|
8
|
+
var SecuritySweepRunStatus;
|
|
9
|
+
(function (SecuritySweepRunStatus) {
|
|
10
|
+
SecuritySweepRunStatus["Running"] = "running";
|
|
11
|
+
SecuritySweepRunStatus["Completed"] = "completed";
|
|
12
|
+
SecuritySweepRunStatus["Failed"] = "failed";
|
|
13
|
+
SecuritySweepRunStatus["Skipped"] = "skipped";
|
|
14
|
+
})(SecuritySweepRunStatus = exports.SecuritySweepRunStatus || (exports.SecuritySweepRunStatus = {}));
|
|
15
|
+
var SecuritySweepTrigger;
|
|
16
|
+
(function (SecuritySweepTrigger) {
|
|
17
|
+
SecuritySweepTrigger["Schedule"] = "schedule";
|
|
18
|
+
SecuritySweepTrigger["Signal"] = "signal";
|
|
19
|
+
SecuritySweepTrigger["Manual"] = "manual";
|
|
20
|
+
})(SecuritySweepTrigger = exports.SecuritySweepTrigger || (exports.SecuritySweepTrigger = {}));
|
|
21
|
+
const buildSecuritySweepRun = (mongoose) => {
|
|
22
|
+
if (mongoose.models.SecuritySweepRun) {
|
|
23
|
+
return mongoose.model("SecuritySweepRun");
|
|
24
|
+
}
|
|
25
|
+
const schema = new mongoose.Schema({
|
|
26
|
+
lens: { type: String, required: true },
|
|
27
|
+
trigger: { type: String, enum: Object.values(SecuritySweepTrigger), required: true },
|
|
28
|
+
triggerDetail: { type: String },
|
|
29
|
+
windowStart: { type: Date, required: true },
|
|
30
|
+
windowEnd: { type: Date, required: true },
|
|
31
|
+
status: { type: String, enum: Object.values(SecuritySweepRunStatus), required: true },
|
|
32
|
+
modelId: { type: String, default: "" },
|
|
33
|
+
escalated: { type: Boolean, default: false },
|
|
34
|
+
inputSnapshot: { type: String },
|
|
35
|
+
output: { type: String },
|
|
36
|
+
findingIds: { type: [String], default: [] },
|
|
37
|
+
toolCalls: { type: Number, default: 0 },
|
|
38
|
+
toolErrors: { type: Number, default: 0 },
|
|
39
|
+
toolsAvailable: { type: [String], default: [] },
|
|
40
|
+
sourcesUnavailable: { type: [String], default: [] },
|
|
41
|
+
inputTokens: { type: Number, default: 0 },
|
|
42
|
+
outputTokens: { type: Number, default: 0 },
|
|
43
|
+
estimatedUsd: { type: Number, default: 0 },
|
|
44
|
+
error: { type: String },
|
|
45
|
+
requestedBy: { type: String },
|
|
46
|
+
leaseUntil: { type: Date },
|
|
47
|
+
startedAt: { type: Date, required: true },
|
|
48
|
+
finishedAt: { type: Date },
|
|
49
|
+
}, {
|
|
50
|
+
timestamps: { createdAt: true, updatedAt: false },
|
|
51
|
+
collection: "securitySweepRuns",
|
|
52
|
+
toJSON: {
|
|
53
|
+
transform(_doc, ret) {
|
|
54
|
+
ret.id = ret._id;
|
|
55
|
+
delete ret._id;
|
|
56
|
+
delete ret.__v;
|
|
57
|
+
delete ret.inputSnapshot;
|
|
58
|
+
delete ret.output;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
schema.index({ startedAt: -1 });
|
|
63
|
+
schema.index({ lens: 1, startedAt: -1 });
|
|
64
|
+
schema.index({ trigger: 1, startedAt: -1 });
|
|
65
|
+
return mongoose.model("SecuritySweepRun", schema);
|
|
66
|
+
};
|
|
67
|
+
exports.buildSecuritySweepRun = buildSecuritySweepRun;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riocrypto/common-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2936",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@google-cloud/secret-manager": "^5.6.0",
|
|
29
29
|
"@google-cloud/storage": "^7.19.0",
|
|
30
30
|
"@hyperdx/node-opentelemetry": "^0.10.3",
|
|
31
|
-
"@riocrypto/common": "1.0.
|
|
31
|
+
"@riocrypto/common": "1.0.2732",
|
|
32
32
|
"@slack/web-api": "^7.15.0",
|
|
33
33
|
"@types/express": "^4.17.25",
|
|
34
34
|
"axios": "1.18.1",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"express-rate-limit": "^7.5.1",
|
|
38
38
|
"express-validator": "^6.15.0",
|
|
39
39
|
"fireblocks-sdk": "^5.38.0",
|
|
40
|
+
"google-auth-library": "9.15.1",
|
|
40
41
|
"googleapis": "^135.1.0",
|
|
41
42
|
"he": "^1.2.0",
|
|
42
43
|
"jose": "^6.2.2",
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Mongoose, Model, Document, HydratedDocument } from "mongoose";
|
|
2
|
-
export declare enum FintocDepositIntakeStatus {
|
|
3
|
-
/** Recorded, waiting for the worker. */
|
|
4
|
-
Pending = "pending",
|
|
5
|
-
/** A worker has taken it. Reset to pending if left here too long. */
|
|
6
|
-
Processing = "processing",
|
|
7
|
-
/** Matching ran to completion, whatever it concluded. See `outcome`. */
|
|
8
|
-
Done = "done",
|
|
9
|
-
/** Matching threw and retries are exhausted. Needs a person. */
|
|
10
|
-
Failed = "failed"
|
|
11
|
-
}
|
|
12
|
-
export type FintocDepositIntakeSource = "webhook" | "poller";
|
|
13
|
-
interface FintocDepositIntakeAttrs {
|
|
14
|
-
fintocTransferId: string;
|
|
15
|
-
source: FintocDepositIntakeSource;
|
|
16
|
-
/** Fintoc's webhook event id, for tracing back to their dashboard. */
|
|
17
|
-
fintocEventId?: string;
|
|
18
|
-
receivedAt: Date;
|
|
19
|
-
}
|
|
20
|
-
interface FintocDepositIntakeDoc extends Document {
|
|
21
|
-
fintocTransferId: string;
|
|
22
|
-
source: FintocDepositIntakeSource;
|
|
23
|
-
fintocEventId?: string;
|
|
24
|
-
status: FintocDepositIntakeStatus;
|
|
25
|
-
attempts: number;
|
|
26
|
-
/** The `reason` processInboundFintocDeposit returned, once it has run. */
|
|
27
|
-
outcome?: string;
|
|
28
|
-
/** Whether that run published a payment, as opposed to skipping or rejecting. */
|
|
29
|
-
processed?: boolean;
|
|
30
|
-
lastError?: string;
|
|
31
|
-
receivedAt: Date;
|
|
32
|
-
startedAt?: Date;
|
|
33
|
-
finishedAt?: Date;
|
|
34
|
-
}
|
|
35
|
-
interface FintocDepositIntakeModel extends Model<FintocDepositIntakeDoc> {
|
|
36
|
-
build(attrs: FintocDepositIntakeAttrs): HydratedDocument<FintocDepositIntakeDoc>;
|
|
37
|
-
}
|
|
38
|
-
declare const buildFintocDepositIntake: (mongoose: Mongoose) => FintocDepositIntakeModel;
|
|
39
|
-
export { buildFintocDepositIntake, FintocDepositIntakeDoc, FintocDepositIntakeAttrs, };
|