@oneuptime/common 12.0.20 → 12.0.21
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/Models/AnalyticsModels/ChangeEvent.ts +331 -0
- package/Models/AnalyticsModels/Index.ts +2 -0
- package/Server/EnvironmentConfig.ts +1 -8
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +42 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +0 -2
- package/Server/Services/ChangeEventService.ts +11 -0
- package/Server/Services/EnterpriseLicenseService.ts +3 -3
- package/Server/Services/Index.ts +2 -0
- package/Server/Utils/Attribution.ts +11 -11
- package/Server/Utils/Marketing/MarketingEventWebhook.ts +4 -5
- package/Server/Utils/Telemetry/ChangeEventRow.ts +228 -0
- package/Server/Views/Partials/AnalyticsConsent.ejs +3 -95
- package/Tests/App/Dashboard/DashboardChartWidgetZoom.test.tsx +64 -0
- package/Tests/App/Dashboard/EventOverlayHook.test.tsx +249 -0
- package/Tests/App/Dashboard/InvestigationArtifacts.test.tsx +315 -0
- package/Tests/App/Dashboard/InvestigationDrawer.test.tsx +258 -0
- package/Tests/App/Dashboard/MetricChartsCompare.test.tsx +171 -0
- package/Tests/App/Dashboard/MetricViewCompare.test.tsx +233 -0
- package/Tests/Server/Infrastructure/Postgres/AddUserSlackAndMicrosoftTeamsMigration.test.ts +236 -0
- package/Tests/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.test.ts +224 -0
- package/Tests/Server/Utils/Attribution.test.ts +4 -5
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +2 -2
- package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.test.ts +300 -0
- package/Tests/UI/Components/Charts/ChartGhostSeries.test.tsx +103 -0
- package/Tests/UI/Components/Charts/TooltipEntries.test.ts +44 -8
- package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +13 -2
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +7 -0
- package/Types/Marketing/Attribution.ts +9 -15
- package/Types/Marketing/MarketingEvent.ts +10 -46
- package/UI/Components/Charts/Area/AreaChart.tsx +15 -0
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +16 -1
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +189 -93
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +6 -1
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +213 -114
- package/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.ts +42 -27
- package/UI/Components/Charts/Line/LineChart.tsx +15 -0
- package/Utils/Metrics/MetricExplorerUrl.ts +119 -5
- package/Utils/Telemetry/CrossSignalScope.ts +19 -10
- package/build/dist/Models/AnalyticsModels/ChangeEvent.js +298 -0
- package/build/dist/Models/AnalyticsModels/ChangeEvent.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/Index.js +2 -0
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +1 -7
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +39 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +0 -2
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/ChangeEventService.js +9 -0
- package/build/dist/Server/Services/ChangeEventService.js.map +1 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js +3 -3
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js +6 -6
- package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +4 -5
- package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ChangeEventRow.js +150 -0
- package/build/dist/Server/Utils/Telemetry/ChangeEventRow.js.map +1 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +7 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/Marketing/Attribution.js +9 -15
- package/build/dist/Types/Marketing/Attribution.js.map +1 -1
- package/build/dist/Types/Marketing/MarketingEvent.js +2 -33
- package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +9 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +92 -38
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +8 -8
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +95 -37
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js +39 -24
- package/build/dist/UI/Components/Charts/ChartLibrary/Utils/TooltipEntries.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/Utils/Metrics/MetricExplorerUrl.js +81 -0
- package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +14 -8
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/package.json +1 -1
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +0 -117
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +0 -106
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +0 -1
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
* Scrub monitor ingest keys out of payloads that were already persisted.
|
|
5
|
-
*
|
|
6
|
-
* https://github.com/OneUptime/oneuptime/issues/3360
|
|
7
|
-
*
|
|
8
|
-
* An Incoming Email monitor's `incomingEmailSecretKey` IS its inbound address:
|
|
9
|
-
* `SendGridInboundProvider.generateMonitorEmailAddress` builds
|
|
10
|
-
* `monitor-{secretKey}@{inboundDomain}`, and `extractSecretKeyFromEmail` reads
|
|
11
|
-
* the key straight back out. Every stored copy of the recipient was therefore a
|
|
12
|
-
* stored copy of a live bearer credential — `emailTo`, the `To:` header, and
|
|
13
|
-
* the `Received:` / `Delivered-To:` headers added in transit.
|
|
14
|
-
*
|
|
15
|
-
* `ProcessProbeIngest.processIncomingEmailFromQueue` now masks the key at the
|
|
16
|
-
* ingest boundary, so nothing written from here on carries it. That fixes the
|
|
17
|
-
* flow and not the stock: rows written before this deploy still hold the key in
|
|
18
|
-
* plaintext, in columns a `Permission.Viewer` can select. Narrowing a read ACL
|
|
19
|
-
* would not have helped either — the same snapshot is copied onto incidents and
|
|
20
|
-
* alerts, which are gated on their own permissions.
|
|
21
|
-
*
|
|
22
|
-
* The four Postgres sinks, all of them jsonb:
|
|
23
|
-
*
|
|
24
|
-
* - `Monitor.incomingEmailMonitorRequest` (the reported leak)
|
|
25
|
-
* - `Monitor.incomingMonitorRequest` (same shape, `incomingRequestSecretKey`)
|
|
26
|
-
* - `Incident.monitorSummary` (via MonitorSummaryCapture)
|
|
27
|
-
* - `Alert.monitorSummary` (via MonitorSummaryCapture)
|
|
28
|
-
*
|
|
29
|
-
* `MonitorLog.logBody` is the fifth sink and is deliberately not touched here:
|
|
30
|
-
* it lives in ClickHouse, not Postgres, and every row carries a `retentionDate`
|
|
31
|
-
* with a `retentionDate DELETE` TTL, so historical rows age out on their own.
|
|
32
|
-
*
|
|
33
|
-
* Matching is case-insensitive (`gi`). A uuid renders lowercase in Postgres,
|
|
34
|
-
* but the key reaches these payloads through relay headers that preserve
|
|
35
|
-
* whatever case the sender used. A uuid is made of hex digits and hyphens, so
|
|
36
|
-
* it needs no regex escaping, and the replacement text contains no backslash,
|
|
37
|
-
* so it needs none either.
|
|
38
|
-
*/
|
|
39
|
-
export class RedactStoredMonitorIngestSecrets1788900000000
|
|
40
|
-
implements MigrationInterface
|
|
41
|
-
{
|
|
42
|
-
public name: string = "RedactStoredMonitorIngestSecrets1788900000000";
|
|
43
|
-
|
|
44
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
45
|
-
/*
|
|
46
|
-
* The monitor's own row: the key and the payload quoting it are on the
|
|
47
|
-
* same row, so this needs no join.
|
|
48
|
-
*/
|
|
49
|
-
await queryRunner.query(
|
|
50
|
-
`UPDATE "Monitor"
|
|
51
|
-
SET "incomingEmailMonitorRequest" = regexp_replace(
|
|
52
|
-
"incomingEmailMonitorRequest"::text,
|
|
53
|
-
"incomingEmailSecretKey"::text,
|
|
54
|
-
'[REDACTED]',
|
|
55
|
-
'gi'
|
|
56
|
-
)::jsonb
|
|
57
|
-
WHERE "incomingEmailSecretKey" IS NOT NULL
|
|
58
|
-
AND "incomingEmailMonitorRequest" IS NOT NULL
|
|
59
|
-
AND "incomingEmailMonitorRequest"::text ILIKE '%' || "incomingEmailSecretKey"::text || '%'`,
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
await queryRunner.query(
|
|
63
|
-
`UPDATE "Monitor"
|
|
64
|
-
SET "incomingMonitorRequest" = regexp_replace(
|
|
65
|
-
"incomingMonitorRequest"::text,
|
|
66
|
-
"incomingRequestSecretKey"::text,
|
|
67
|
-
'[REDACTED]',
|
|
68
|
-
'gi'
|
|
69
|
-
)::jsonb
|
|
70
|
-
WHERE "incomingRequestSecretKey" IS NOT NULL
|
|
71
|
-
AND "incomingMonitorRequest" IS NOT NULL
|
|
72
|
-
AND "incomingMonitorRequest"::text ILIKE '%' || "incomingRequestSecretKey"::text || '%'`,
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
/*
|
|
76
|
-
* Incident and Alert keep a copy of the snapshot the monitor was evaluated
|
|
77
|
-
* from. The key is not on those rows, so join back to the monitor. The
|
|
78
|
-
* `projectId` equality keeps the join from degenerating into a cross
|
|
79
|
-
* product; the ILIKE is what actually selects the affected rows, and a
|
|
80
|
-
* snapshot describes exactly one monitor, so at most one monitor row can
|
|
81
|
-
* match a given summary.
|
|
82
|
-
*/
|
|
83
|
-
for (const table of ["Incident", "Alert"]) {
|
|
84
|
-
for (const secretColumn of [
|
|
85
|
-
"incomingEmailSecretKey",
|
|
86
|
-
"incomingRequestSecretKey",
|
|
87
|
-
]) {
|
|
88
|
-
await queryRunner.query(
|
|
89
|
-
`UPDATE "${table}" AS t
|
|
90
|
-
SET "monitorSummary" = regexp_replace(
|
|
91
|
-
t."monitorSummary"::text,
|
|
92
|
-
m."${secretColumn}"::text,
|
|
93
|
-
'[REDACTED]',
|
|
94
|
-
'gi'
|
|
95
|
-
)::jsonb
|
|
96
|
-
FROM "Monitor" AS m
|
|
97
|
-
WHERE m."${secretColumn}" IS NOT NULL
|
|
98
|
-
AND m."projectId" = t."projectId"
|
|
99
|
-
AND t."monitorSummary" IS NOT NULL
|
|
100
|
-
AND t."monitorSummary"::text ILIKE '%' || m."${secretColumn}"::text || '%'`,
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
public async down(): Promise<void> {
|
|
107
|
-
/*
|
|
108
|
-
* Deliberately empty. The whole point of the up migration is that these
|
|
109
|
-
* values are gone; the original text is not recoverable from anything else
|
|
110
|
-
* in the schema, and recovering it would mean re-publishing the leak.
|
|
111
|
-
*
|
|
112
|
-
* Nothing depends on the redacted text either: `IncomingEmailCriteria`
|
|
113
|
-
* re-evaluates against live mail, and the summary cards render whatever
|
|
114
|
-
* string is stored. Rolling the schema back therefore needs no data change.
|
|
115
|
-
*/
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Scrub monitor ingest keys out of payloads that were already persisted.
|
|
3
|
-
*
|
|
4
|
-
* https://github.com/OneUptime/oneuptime/issues/3360
|
|
5
|
-
*
|
|
6
|
-
* An Incoming Email monitor's `incomingEmailSecretKey` IS its inbound address:
|
|
7
|
-
* `SendGridInboundProvider.generateMonitorEmailAddress` builds
|
|
8
|
-
* `monitor-{secretKey}@{inboundDomain}`, and `extractSecretKeyFromEmail` reads
|
|
9
|
-
* the key straight back out. Every stored copy of the recipient was therefore a
|
|
10
|
-
* stored copy of a live bearer credential — `emailTo`, the `To:` header, and
|
|
11
|
-
* the `Received:` / `Delivered-To:` headers added in transit.
|
|
12
|
-
*
|
|
13
|
-
* `ProcessProbeIngest.processIncomingEmailFromQueue` now masks the key at the
|
|
14
|
-
* ingest boundary, so nothing written from here on carries it. That fixes the
|
|
15
|
-
* flow and not the stock: rows written before this deploy still hold the key in
|
|
16
|
-
* plaintext, in columns a `Permission.Viewer` can select. Narrowing a read ACL
|
|
17
|
-
* would not have helped either — the same snapshot is copied onto incidents and
|
|
18
|
-
* alerts, which are gated on their own permissions.
|
|
19
|
-
*
|
|
20
|
-
* The four Postgres sinks, all of them jsonb:
|
|
21
|
-
*
|
|
22
|
-
* - `Monitor.incomingEmailMonitorRequest` (the reported leak)
|
|
23
|
-
* - `Monitor.incomingMonitorRequest` (same shape, `incomingRequestSecretKey`)
|
|
24
|
-
* - `Incident.monitorSummary` (via MonitorSummaryCapture)
|
|
25
|
-
* - `Alert.monitorSummary` (via MonitorSummaryCapture)
|
|
26
|
-
*
|
|
27
|
-
* `MonitorLog.logBody` is the fifth sink and is deliberately not touched here:
|
|
28
|
-
* it lives in ClickHouse, not Postgres, and every row carries a `retentionDate`
|
|
29
|
-
* with a `retentionDate DELETE` TTL, so historical rows age out on their own.
|
|
30
|
-
*
|
|
31
|
-
* Matching is case-insensitive (`gi`). A uuid renders lowercase in Postgres,
|
|
32
|
-
* but the key reaches these payloads through relay headers that preserve
|
|
33
|
-
* whatever case the sender used. A uuid is made of hex digits and hyphens, so
|
|
34
|
-
* it needs no regex escaping, and the replacement text contains no backslash,
|
|
35
|
-
* so it needs none either.
|
|
36
|
-
*/
|
|
37
|
-
export class RedactStoredMonitorIngestSecrets1788900000000 {
|
|
38
|
-
constructor() {
|
|
39
|
-
this.name = "RedactStoredMonitorIngestSecrets1788900000000";
|
|
40
|
-
}
|
|
41
|
-
async up(queryRunner) {
|
|
42
|
-
/*
|
|
43
|
-
* The monitor's own row: the key and the payload quoting it are on the
|
|
44
|
-
* same row, so this needs no join.
|
|
45
|
-
*/
|
|
46
|
-
await queryRunner.query(`UPDATE "Monitor"
|
|
47
|
-
SET "incomingEmailMonitorRequest" = regexp_replace(
|
|
48
|
-
"incomingEmailMonitorRequest"::text,
|
|
49
|
-
"incomingEmailSecretKey"::text,
|
|
50
|
-
'[REDACTED]',
|
|
51
|
-
'gi'
|
|
52
|
-
)::jsonb
|
|
53
|
-
WHERE "incomingEmailSecretKey" IS NOT NULL
|
|
54
|
-
AND "incomingEmailMonitorRequest" IS NOT NULL
|
|
55
|
-
AND "incomingEmailMonitorRequest"::text ILIKE '%' || "incomingEmailSecretKey"::text || '%'`);
|
|
56
|
-
await queryRunner.query(`UPDATE "Monitor"
|
|
57
|
-
SET "incomingMonitorRequest" = regexp_replace(
|
|
58
|
-
"incomingMonitorRequest"::text,
|
|
59
|
-
"incomingRequestSecretKey"::text,
|
|
60
|
-
'[REDACTED]',
|
|
61
|
-
'gi'
|
|
62
|
-
)::jsonb
|
|
63
|
-
WHERE "incomingRequestSecretKey" IS NOT NULL
|
|
64
|
-
AND "incomingMonitorRequest" IS NOT NULL
|
|
65
|
-
AND "incomingMonitorRequest"::text ILIKE '%' || "incomingRequestSecretKey"::text || '%'`);
|
|
66
|
-
/*
|
|
67
|
-
* Incident and Alert keep a copy of the snapshot the monitor was evaluated
|
|
68
|
-
* from. The key is not on those rows, so join back to the monitor. The
|
|
69
|
-
* `projectId` equality keeps the join from degenerating into a cross
|
|
70
|
-
* product; the ILIKE is what actually selects the affected rows, and a
|
|
71
|
-
* snapshot describes exactly one monitor, so at most one monitor row can
|
|
72
|
-
* match a given summary.
|
|
73
|
-
*/
|
|
74
|
-
for (const table of ["Incident", "Alert"]) {
|
|
75
|
-
for (const secretColumn of [
|
|
76
|
-
"incomingEmailSecretKey",
|
|
77
|
-
"incomingRequestSecretKey",
|
|
78
|
-
]) {
|
|
79
|
-
await queryRunner.query(`UPDATE "${table}" AS t
|
|
80
|
-
SET "monitorSummary" = regexp_replace(
|
|
81
|
-
t."monitorSummary"::text,
|
|
82
|
-
m."${secretColumn}"::text,
|
|
83
|
-
'[REDACTED]',
|
|
84
|
-
'gi'
|
|
85
|
-
)::jsonb
|
|
86
|
-
FROM "Monitor" AS m
|
|
87
|
-
WHERE m."${secretColumn}" IS NOT NULL
|
|
88
|
-
AND m."projectId" = t."projectId"
|
|
89
|
-
AND t."monitorSummary" IS NOT NULL
|
|
90
|
-
AND t."monitorSummary"::text ILIKE '%' || m."${secretColumn}"::text || '%'`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
async down() {
|
|
95
|
-
/*
|
|
96
|
-
* Deliberately empty. The whole point of the up migration is that these
|
|
97
|
-
* values are gone; the original text is not recoverable from anything else
|
|
98
|
-
* in the schema, and recovering it would mean re-publishing the leak.
|
|
99
|
-
*
|
|
100
|
-
* Nothing depends on the redacted text either: `IncomingEmailCriteria`
|
|
101
|
-
* re-evaluates against live mail, and the summary cards render whatever
|
|
102
|
-
* string is stored. Rolling the schema back therefore needs no data change.
|
|
103
|
-
*/
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
//# sourceMappingURL=1788900000000-RedactStoredMonitorIngestSecrets.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"1788900000000-RedactStoredMonitorIngestSecrets.js","sourceRoot":"","sources":["../../../../../../Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,OAAO,6CAA6C;IAA1D;QAGS,SAAI,GAAW,+CAA+C,CAAC;IA2ExE,CAAC;IAzEQ,KAAK,CAAC,EAAE,CAAC,WAAwB;QACtC;;;WAGG;QACH,MAAM,WAAW,CAAC,KAAK,CACrB;;;;;;;;;qGAS+F,CAChG,CAAC;QAEF,MAAM,WAAW,CAAC,KAAK,CACrB;;;;;;;;;kGAS4F,CAC7F,CAAC;QAEF;;;;;;;WAOG;QACH,KAAK,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;YAC1C,KAAK,MAAM,YAAY,IAAI;gBACzB,wBAAwB;gBACxB,0BAA0B;aAC3B,EAAE,CAAC;gBACF,MAAM,WAAW,CAAC,KAAK,CACrB,WAAW,KAAK;;;yBAGD,YAAY;;;;;uBAKd,YAAY;;;6DAG0B,YAAY,gBAAgB,CAChF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,IAAI;QACf;;;;;;;;WAQG;IACL,CAAC;CACF"}
|