@intentius/chant-lexicon-prometheus 0.98.0 → 0.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/import/embedded.d.ts +14 -0
- package/dist/import/embedded.d.ts.map +1 -0
- package/dist/import/generator.d.ts +15 -0
- package/dist/import/generator.d.ts.map +1 -1
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/integrations.d.ts +531 -0
- package/dist/integrations.d.ts.map +1 -0
- package/dist/integrity.json +4 -4
- package/dist/lint/rules/literal-credential.d.ts.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/model.d.ts +58 -123
- package/dist/model.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/rules/literal-credential.ts +41 -10
- package/dist/skills/chant-prometheus-alertmanager.md +1 -1
- package/package.json +2 -2
- package/src/import/embedded.test.ts +56 -0
- package/src/import/embedded.ts +44 -0
- package/src/import/generated-types.e2e.test.ts +3 -1
- package/src/import/generator.test.ts +21 -4
- package/src/import/generator.ts +32 -24
- package/src/import/parser.test.ts +13 -0
- package/src/import/parser.ts +18 -1
- package/src/import/roundtrip.test.ts +46 -9
- package/src/import/testdata/alertmanager-full.yml +3 -3
- package/src/import/testdata/alertmanager-integrations.yml +215 -0
- package/src/import/testdata/fixtures.ts +8 -0
- package/src/import/testdata/upstream/alertmanager-conf-good.yml +120 -0
- package/src/import/testdata/upstream/alertmanager-mattermost-default-webhook-url-file.yml +16 -0
- package/src/import/testdata/upstream/alertmanager-opsgenie-default-apikey-file.yml +27 -0
- package/src/import/testdata/upstream/alertmanager-rocketchat-default-token-file.yml +25 -0
- package/src/import/testdata/upstream/alertmanager-sns-topic-arn.yml +17 -0
- package/src/import/testdata/upstream/alertmanager-telegram-default-bot-token-file.yml +16 -0
- package/src/import/testdata/upstream/alertmanager-victorops-default-apikey-file.yml +23 -0
- package/src/import/testdata/upstream/alertmanager-wechat-default-api-secret-file.yml +18 -0
- package/src/integrations.ts +538 -0
- package/src/lint/rules/literal-credential.ts +41 -10
- package/src/lint/rules/rules.test.ts +31 -1
- package/src/model.ts +136 -110
- package/src/plugin.ts +5 -0
- package/src/skills/chant-prometheus-alertmanager.md +1 -1
package/dist/model.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* so a declaration reads the same as the file it produces and the upstream
|
|
13
13
|
* docs apply word for word.
|
|
14
14
|
*/
|
|
15
|
+
import { type DiscordConfig, type EmailConfig, type HttpClientConfig, type IncidentioConfig, type JiraConfig, type MattermostConfig, type MSTeamsConfig, type MSTeamsV2Config, type OpsGenieConfig, type PagerDutyConfig, type PushoverConfig, type ReceiverIntegration, type RocketchatConfig, type SlackConfig, type SNSConfig, type TelegramConfig, type TlsConfig, type VictorOpsConfig, type WebexConfig, type WebhookConfig, type WechatConfig } from "./integrations.js";
|
|
15
16
|
/** Labels or annotations: string keys to string values. */
|
|
16
17
|
export type LabelSet = Record<string, string>;
|
|
17
18
|
/** A recording rule: evaluates `expr` and stores the result as the series `record`. */
|
|
@@ -60,128 +61,30 @@ export declare function isRecordingRuleConfig(rule: unknown): rule is RecordingR
|
|
|
60
61
|
export declare function isAlertingRuleConfig(rule: unknown): rule is AlertingRuleConfig;
|
|
61
62
|
/** The rule's name: `record` for a recording rule, `alert` for an alerting rule. */
|
|
62
63
|
export declare function ruleName(rule: RuleConfig): string;
|
|
63
|
-
|
|
64
|
-
export interface HttpClientConfig {
|
|
65
|
-
basic_auth?: {
|
|
66
|
-
username?: string;
|
|
67
|
-
username_file?: string;
|
|
68
|
-
password?: string;
|
|
69
|
-
password_file?: string;
|
|
70
|
-
};
|
|
71
|
-
authorization?: {
|
|
72
|
-
type?: string;
|
|
73
|
-
credentials?: string;
|
|
74
|
-
credentials_file?: string;
|
|
75
|
-
};
|
|
76
|
-
bearer_token?: string;
|
|
77
|
-
bearer_token_file?: string;
|
|
78
|
-
oauth2?: Record<string, unknown>;
|
|
79
|
-
proxy_url?: string;
|
|
80
|
-
follow_redirects?: boolean;
|
|
81
|
-
enable_http2?: boolean;
|
|
82
|
-
tls_config?: {
|
|
83
|
-
ca_file?: string;
|
|
84
|
-
cert_file?: string;
|
|
85
|
-
key_file?: string;
|
|
86
|
-
server_name?: string;
|
|
87
|
-
insecure_skip_verify?: boolean;
|
|
88
|
-
min_version?: string;
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
interface NotifierBase {
|
|
92
|
-
/** Whether to notify about resolved alerts too. */
|
|
93
|
-
send_resolved?: boolean;
|
|
94
|
-
}
|
|
95
|
-
export interface WebhookConfig extends NotifierBase {
|
|
96
|
-
/** Where alerts are POSTed. Set this or `url_file`. */
|
|
97
|
-
url?: string;
|
|
98
|
-
url_file?: string;
|
|
99
|
-
http_config?: HttpClientConfig;
|
|
100
|
-
/** Most alerts per message; 0 sends them all. */
|
|
101
|
-
max_alerts?: number;
|
|
102
|
-
timeout?: string;
|
|
103
|
-
}
|
|
104
|
-
export interface EmailConfig extends NotifierBase {
|
|
105
|
-
to: string;
|
|
106
|
-
from?: string;
|
|
107
|
-
/** `host:port` of the SMTP server. Falls back to `global.smtp_smarthost`. */
|
|
108
|
-
smarthost?: string;
|
|
109
|
-
hello?: string;
|
|
110
|
-
auth_username?: string;
|
|
111
|
-
auth_password?: string;
|
|
112
|
-
auth_password_file?: string;
|
|
113
|
-
auth_secret?: string;
|
|
114
|
-
auth_secret_file?: string;
|
|
115
|
-
auth_identity?: string;
|
|
116
|
-
require_tls?: boolean;
|
|
117
|
-
tls_config?: HttpClientConfig["tls_config"];
|
|
118
|
-
html?: string;
|
|
119
|
-
text?: string;
|
|
120
|
-
headers?: Record<string, string>;
|
|
121
|
-
}
|
|
122
|
-
export interface SlackConfig extends NotifierBase {
|
|
123
|
-
/** The incoming-webhook URL. It is a credential: prefer `api_url_file`. */
|
|
124
|
-
api_url?: string;
|
|
125
|
-
api_url_file?: string;
|
|
126
|
-
channel?: string;
|
|
127
|
-
username?: string;
|
|
128
|
-
color?: string;
|
|
129
|
-
title?: string;
|
|
130
|
-
title_link?: string;
|
|
131
|
-
pretext?: string;
|
|
132
|
-
text?: string;
|
|
133
|
-
footer?: string;
|
|
134
|
-
fallback?: string;
|
|
135
|
-
icon_emoji?: string;
|
|
136
|
-
icon_url?: string;
|
|
137
|
-
link_names?: boolean;
|
|
138
|
-
short_fields?: boolean;
|
|
139
|
-
mrkdwn_in?: string[];
|
|
140
|
-
fields?: Array<{
|
|
141
|
-
title: string;
|
|
142
|
-
value: string;
|
|
143
|
-
short?: boolean;
|
|
144
|
-
}>;
|
|
145
|
-
actions?: Array<Record<string, unknown>>;
|
|
146
|
-
http_config?: HttpClientConfig;
|
|
147
|
-
}
|
|
148
|
-
export interface PagerDutyConfig extends NotifierBase {
|
|
149
|
-
/** Events API v2 integration key. A credential: prefer `routing_key_file`. */
|
|
150
|
-
routing_key?: string;
|
|
151
|
-
routing_key_file?: string;
|
|
152
|
-
/** Events API v1 integration key. A credential: prefer `service_key_file`. */
|
|
153
|
-
service_key?: string;
|
|
154
|
-
service_key_file?: string;
|
|
155
|
-
url?: string;
|
|
156
|
-
client?: string;
|
|
157
|
-
client_url?: string;
|
|
158
|
-
description?: string;
|
|
159
|
-
severity?: string;
|
|
160
|
-
class?: string;
|
|
161
|
-
component?: string;
|
|
162
|
-
group?: string;
|
|
163
|
-
source?: string;
|
|
164
|
-
details?: Record<string, string>;
|
|
165
|
-
links?: Array<{
|
|
166
|
-
href: string;
|
|
167
|
-
text?: string;
|
|
168
|
-
}>;
|
|
169
|
-
images?: Array<{
|
|
170
|
-
src: string;
|
|
171
|
-
alt?: string;
|
|
172
|
-
href?: string;
|
|
173
|
-
}>;
|
|
174
|
-
http_config?: HttpClientConfig;
|
|
175
|
-
}
|
|
64
|
+
export * from "./integrations.js";
|
|
176
65
|
/** One entry under `receivers:`. */
|
|
177
66
|
export interface ReceiverConfig {
|
|
178
67
|
name: string;
|
|
179
68
|
/** Labels on the receiver, exposed to notification templates. */
|
|
180
69
|
labels?: LabelSet;
|
|
181
|
-
|
|
70
|
+
discord_configs?: DiscordConfig[];
|
|
182
71
|
email_configs?: EmailConfig[];
|
|
183
|
-
|
|
72
|
+
incidentio_configs?: IncidentioConfig[];
|
|
184
73
|
pagerduty_configs?: PagerDutyConfig[];
|
|
74
|
+
slack_configs?: SlackConfig[];
|
|
75
|
+
webhook_configs?: WebhookConfig[];
|
|
76
|
+
opsgenie_configs?: OpsGenieConfig[];
|
|
77
|
+
wechat_configs?: WechatConfig[];
|
|
78
|
+
pushover_configs?: PushoverConfig[];
|
|
79
|
+
victorops_configs?: VictorOpsConfig[];
|
|
80
|
+
sns_configs?: SNSConfig[];
|
|
81
|
+
telegram_configs?: TelegramConfig[];
|
|
82
|
+
webex_configs?: WebexConfig[];
|
|
83
|
+
msteams_configs?: MSTeamsConfig[];
|
|
84
|
+
msteamsv2_configs?: MSTeamsV2Config[];
|
|
85
|
+
jira_configs?: JiraConfig[];
|
|
86
|
+
rocketchat_configs?: RocketchatConfig[];
|
|
87
|
+
mattermost_configs?: MattermostConfig[];
|
|
185
88
|
}
|
|
186
89
|
/** A route in the routing tree. The top-level `route:` is the root. */
|
|
187
90
|
export interface RouteConfig {
|
|
@@ -234,12 +137,18 @@ export interface TimeIntervalConfig {
|
|
|
234
137
|
name: string;
|
|
235
138
|
time_intervals: TimePeriodConfig[];
|
|
236
139
|
}
|
|
237
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* `global:` settings: defaults the receivers fall back to. Credentials with
|
|
142
|
+
* a `*_file` sibling are best set through it; PROM001 flags a literal.
|
|
143
|
+
*/
|
|
238
144
|
export interface AlertmanagerGlobalConfig {
|
|
145
|
+
/** How long an alert that stops being updated stays firing. */
|
|
239
146
|
resolve_timeout?: string;
|
|
147
|
+
http_config?: HttpClientConfig;
|
|
148
|
+
jira_api_url?: string;
|
|
240
149
|
smtp_from?: string;
|
|
241
|
-
smtp_smarthost?: string;
|
|
242
150
|
smtp_hello?: string;
|
|
151
|
+
smtp_smarthost?: string;
|
|
243
152
|
smtp_auth_username?: string;
|
|
244
153
|
smtp_auth_password?: string;
|
|
245
154
|
smtp_auth_password_file?: string;
|
|
@@ -247,11 +156,38 @@ export interface AlertmanagerGlobalConfig {
|
|
|
247
156
|
smtp_auth_secret_file?: string;
|
|
248
157
|
smtp_auth_identity?: string;
|
|
249
158
|
smtp_require_tls?: boolean;
|
|
159
|
+
smtp_tls_config?: TlsConfig;
|
|
160
|
+
smtp_force_implicit_tls?: boolean;
|
|
250
161
|
slack_api_url?: string;
|
|
251
162
|
slack_api_url_file?: string;
|
|
163
|
+
slack_app_token?: string;
|
|
164
|
+
slack_app_token_file?: string;
|
|
165
|
+
slack_app_url?: string;
|
|
252
166
|
pagerduty_url?: string;
|
|
253
|
-
|
|
254
|
-
|
|
167
|
+
opsgenie_api_url?: string;
|
|
168
|
+
opsgenie_api_key?: string;
|
|
169
|
+
opsgenie_api_key_file?: string;
|
|
170
|
+
wechat_api_url?: string;
|
|
171
|
+
wechat_api_secret?: string;
|
|
172
|
+
wechat_api_secret_file?: string;
|
|
173
|
+
wechat_api_corp_id?: string;
|
|
174
|
+
victorops_api_url?: string;
|
|
175
|
+
victorops_api_key?: string;
|
|
176
|
+
victorops_api_key_file?: string;
|
|
177
|
+
telegram_api_url?: string;
|
|
178
|
+
telegram_bot_token?: string;
|
|
179
|
+
telegram_bot_token_file?: string;
|
|
180
|
+
webex_api_url?: string;
|
|
181
|
+
rocketchat_api_url?: string;
|
|
182
|
+
rocketchat_token?: string;
|
|
183
|
+
rocketchat_token_file?: string;
|
|
184
|
+
rocketchat_token_id?: string;
|
|
185
|
+
rocketchat_token_id_file?: string;
|
|
186
|
+
mattermost_webhook_url?: string;
|
|
187
|
+
mattermost_webhook_url_file?: string;
|
|
188
|
+
}
|
|
189
|
+
/** Every `global:` field, as a list, for code that reads a parsed file. */
|
|
190
|
+
export declare const ALERTMANAGER_GLOBAL_FIELDS: readonly (keyof AlertmanagerGlobalConfig)[];
|
|
255
191
|
/** `tracing:` settings: where Alertmanager sends its own traces. */
|
|
256
192
|
export interface AlertmanagerTracingConfig {
|
|
257
193
|
client_type?: "grpc" | "http";
|
|
@@ -261,7 +197,7 @@ export interface AlertmanagerTracingConfig {
|
|
|
261
197
|
headers?: Record<string, string>;
|
|
262
198
|
compression?: string;
|
|
263
199
|
timeout?: string;
|
|
264
|
-
tls_config?:
|
|
200
|
+
tls_config?: TlsConfig;
|
|
265
201
|
}
|
|
266
202
|
/** A whole `alertmanager.yml`, the file `amtool check-config` reads. */
|
|
267
203
|
export interface AlertmanagerConfig {
|
|
@@ -273,11 +209,10 @@ export interface AlertmanagerConfig {
|
|
|
273
209
|
time_intervals?: TimeIntervalConfig[];
|
|
274
210
|
tracing?: AlertmanagerTracingConfig;
|
|
275
211
|
}
|
|
276
|
-
/** The
|
|
277
|
-
export declare const RECEIVER_INTEGRATIONS: readonly [
|
|
212
|
+
/** The receiver integrations, every one Alertmanager defines. */
|
|
213
|
+
export declare const RECEIVER_INTEGRATIONS: readonly ReceiverIntegration[];
|
|
278
214
|
/** True when a parsed document has the shape of a Prometheus rule file. */
|
|
279
215
|
export declare function looksLikeRuleFile(value: unknown): value is RuleFileConfig;
|
|
280
216
|
/** True when a parsed document has the shape of an `alertmanager.yml`. */
|
|
281
217
|
export declare function looksLikeAlertmanagerConfig(value: unknown): value is AlertmanagerConfig;
|
|
282
|
-
export {};
|
|
283
218
|
//# sourceMappingURL=model.d.ts.map
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,2DAA2D;AAC3D,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,oFAAoF;IACpF,WAAW,CAAC,EAAE,QAAQ,CAAC;CACxB;AAED,MAAM,MAAM,UAAU,GAAG,mBAAmB,GAAG,kBAAkB,CAAC;AAElE,qGAAqG;AACrG,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oGAAoG;IACpG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,mBAAmB,CAEhF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,kBAAkB,CAE9E;AAED,oFAAoF;AACpF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAEjD;AAID,
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA+B9D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAyG9B,CAAC"}
|
|
@@ -7,20 +7,47 @@ import { calleeName, constInitializers, CREDENTIAL_CLASS, literalText, position,
|
|
|
7
7
|
* reads it from a mounted file instead.
|
|
8
8
|
*/
|
|
9
9
|
export const SECRET_FIELDS = new Set([
|
|
10
|
-
"api_url", // slack_configs: the incoming-webhook URL is the credential
|
|
11
|
-
"
|
|
12
|
-
"
|
|
10
|
+
"api_url", // slack_configs only: the incoming-webhook URL is the credential (see SECRET_ONLY_IN)
|
|
11
|
+
"webhook_url", // discord, msteams, msteamsv2 and mattermost
|
|
12
|
+
"app_token",
|
|
13
|
+
"routing_key", // pagerduty (victorops' routing_key names a route, see SECRET_ONLY_IN)
|
|
13
14
|
"service_key",
|
|
15
|
+
"api_key",
|
|
16
|
+
"api_secret",
|
|
17
|
+
"bot_token",
|
|
18
|
+
"token",
|
|
19
|
+
"token_id",
|
|
20
|
+
"user_key",
|
|
21
|
+
"alert_source_token",
|
|
14
22
|
"auth_password",
|
|
15
23
|
"auth_secret",
|
|
16
24
|
"smtp_auth_password",
|
|
17
25
|
"smtp_auth_secret",
|
|
26
|
+
"slack_api_url",
|
|
27
|
+
"slack_app_token",
|
|
28
|
+
"opsgenie_api_key",
|
|
29
|
+
"wechat_api_secret",
|
|
30
|
+
"victorops_api_key",
|
|
31
|
+
"telegram_bot_token",
|
|
32
|
+
"rocketchat_token",
|
|
33
|
+
"rocketchat_token_id",
|
|
34
|
+
"mattermost_webhook_url",
|
|
18
35
|
"password",
|
|
19
36
|
"credentials",
|
|
20
37
|
"bearer_token",
|
|
21
38
|
"client_secret",
|
|
22
39
|
]);
|
|
23
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Fields that are a secret in one integration and plain elsewhere: `api_url`
|
|
43
|
+
* is Slack's webhook credential but only an endpoint for the others, and a
|
|
44
|
+
* VictorOps `routing_key` names a route.
|
|
45
|
+
*/
|
|
46
|
+
const SECRET_ONLY_IN: Record<string, string> = {
|
|
47
|
+
api_url: "slack_configs",
|
|
48
|
+
routing_key: "pagerduty_configs",
|
|
49
|
+
};
|
|
50
|
+
|
|
24
51
|
/**
|
|
25
52
|
* PROM001: a credential written as a literal in a `Receiver` or
|
|
26
53
|
* `AlertmanagerSettings`.
|
|
@@ -46,16 +73,20 @@ export const literalCredentialRule: LintRule = {
|
|
|
46
73
|
|
|
47
74
|
// A value is followed to the const it names, so a list lifted out of the
|
|
48
75
|
// constructor (`email_configs: heartbeatEmail`) is scanned where it is used.
|
|
49
|
-
|
|
76
|
+
// `integration` is the `*_configs` list a value sits in, when that is known.
|
|
77
|
+
const scanValue = (key: string | undefined, value: ts.Expression, integration?: string) => {
|
|
50
78
|
const init = resolveConst(value, consts);
|
|
79
|
+
const within = key?.endsWith("_configs") ? key : integration;
|
|
51
80
|
if (ts.isObjectLiteralExpression(init) || ts.isArrayLiteralExpression(init)) {
|
|
52
81
|
if (scanned.has(init)) return;
|
|
53
82
|
scanned.add(init);
|
|
54
|
-
if (ts.isObjectLiteralExpression(init)) scan(init);
|
|
55
|
-
else for (const el of init.elements) scanValue(undefined, el);
|
|
83
|
+
if (ts.isObjectLiteralExpression(init)) scan(init, within);
|
|
84
|
+
else for (const el of init.elements) scanValue(undefined, el, within);
|
|
56
85
|
return;
|
|
57
86
|
}
|
|
58
87
|
if (!key || !SECRET_FIELDS.has(key)) return;
|
|
88
|
+
const only = SECRET_ONLY_IN[key];
|
|
89
|
+
if (only && integration !== undefined && integration !== only) return;
|
|
59
90
|
const text = literalText(init);
|
|
60
91
|
if (text === undefined || text === "") return;
|
|
61
92
|
diagnostics.push({
|
|
@@ -67,11 +98,11 @@ export const literalCredentialRule: LintRule = {
|
|
|
67
98
|
});
|
|
68
99
|
};
|
|
69
100
|
|
|
70
|
-
const scan = (obj: ts.ObjectLiteralExpression) => {
|
|
101
|
+
const scan = (obj: ts.ObjectLiteralExpression, integration?: string) => {
|
|
71
102
|
for (const prop of obj.properties) {
|
|
72
|
-
if (ts.isPropertyAssignment(prop)) scanValue(propertyName(prop), prop.initializer);
|
|
73
|
-
else if (ts.isShorthandPropertyAssignment(prop)) scanValue(prop.name.text, prop.name);
|
|
74
|
-
else if (ts.isSpreadAssignment(prop)) scanValue(undefined, prop.expression);
|
|
103
|
+
if (ts.isPropertyAssignment(prop)) scanValue(propertyName(prop), prop.initializer, integration);
|
|
104
|
+
else if (ts.isShorthandPropertyAssignment(prop)) scanValue(prop.name.text, prop.name, integration);
|
|
105
|
+
else if (ts.isSpreadAssignment(prop)) scanValue(undefined, prop.expression, integration);
|
|
75
106
|
}
|
|
76
107
|
};
|
|
77
108
|
|
|
@@ -49,7 +49,7 @@ export const pageMutesTicket = new InhibitRule({
|
|
|
49
49
|
|
|
50
50
|
## Starting from an existing alertmanager.yml
|
|
51
51
|
|
|
52
|
-
Import it rather than retyping it: `chant import alertmanager.yml --output src` (with `--lexicon prometheus` outside a chant project). The importer writes `receivers.ts`, `time-intervals.ts`, `routes.ts` (the root `Route`, children as `RouteProps` that reference receivers and time intervals by variable), `inhibit-rules.ts` and `settings.ts`. `*_file` paths and Go templates are kept as written; a literal credential is imported as found and PROM001 reports it, so offer to move it to the `*_file` field.
|
|
52
|
+
Import it rather than retyping it: `chant import alertmanager.yml --output src` (with `--lexicon prometheus` outside a chant project). The importer writes `receivers.ts`, `time-intervals.ts`, `routes.ts` (the root `Route`, children as `RouteProps` that reference receivers and time intervals by variable), `inhibit-rules.ts` and `settings.ts`. `*_file` paths and Go templates are kept as written; a literal credential is imported as found and PROM001 reports it, so offer to move it to the `*_file` field. Every integration comes back typed (`OpsGenieConfig[]`, `MSTeamsV2Config[]`, ...); a receiver or `global` key Alertmanager doesn't define is spread in from an untyped const, with a warning. `match`/`match_re` and the top-level `mute_time_intervals` come back in their current spelling (`matchers`, `time_intervals`), and `chant import` prints a warning for each.
|
|
53
53
|
|
|
54
54
|
## What the checks hold you to
|
|
55
55
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-prometheus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.100.0",
|
|
4
4
|
"description": "Prometheus lexicon for chant — typed recording and alerting rule groups and Alertmanager routing, serialized to a rule file and alertmanager.yml",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"typescript": "^5.9.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
|
-
"@intentius/chant": "^0.
|
|
74
|
+
"@intentius/chant": "^0.100.0",
|
|
75
75
|
"typescript": "^5.9.3"
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { embeddedDocument, type EmbeddedContent } from "@intentius/chant/import/embedded";
|
|
3
|
+
import { prometheusPlugin } from "../plugin";
|
|
4
|
+
import { ruleGroupsImporter } from "./embedded";
|
|
5
|
+
|
|
6
|
+
const GROUPS = [
|
|
7
|
+
{ name: "api", rules: [{ alert: "ApiDown", expr: "up{job=\"api\"} == 0", for: "5m" }] },
|
|
8
|
+
{ name: "recording", rules: [{ record: "job:up:sum", expr: "sum by (job) (up)" }] },
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const RULE_FILE = `groups:
|
|
12
|
+
- name: api
|
|
13
|
+
rules:
|
|
14
|
+
- alert: ApiDown
|
|
15
|
+
expr: up{job="api"} == 0
|
|
16
|
+
for: 5m
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const site = (over: Partial<EmbeddedContent>): EmbeddedContent => ({
|
|
20
|
+
host: "k8s",
|
|
21
|
+
hostType: "K8s::Monitoring::PrometheusRule",
|
|
22
|
+
location: "PrometheusRule api spec.groups",
|
|
23
|
+
directory: "api",
|
|
24
|
+
...over,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("rule groups embedded in another lexicon's resource (#2962)", () => {
|
|
28
|
+
test("the plugin registers the importer", () => {
|
|
29
|
+
expect(prometheusPlugin.embeddedImporters?.()).toEqual([ruleGroupsImporter]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("matches a PrometheusRule's groups and a rule file held as text; not an alertmanager.yml", () => {
|
|
33
|
+
expect(ruleGroupsImporter.matches(site({ document: { groups: GROUPS }, select: "groups" }))).toBe(true);
|
|
34
|
+
expect(ruleGroupsImporter.matches(site({ text: RULE_FILE, document: embeddedDocument(RULE_FILE) }))).toBe(true);
|
|
35
|
+
const am = "route:\n receiver: x\nreceivers:\n - name: x\n";
|
|
36
|
+
expect(ruleGroupsImporter.matches(site({ text: am, document: embeddedDocument(am) }))).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("spec.groups becomes the list of declared groups, in the source's order", () => {
|
|
40
|
+
const out = ruleGroupsImporter.import(site({ document: { groups: GROUPS }, select: "groups" }));
|
|
41
|
+
expect(out.files.map((f) => f.path)).toEqual(["rules.ts"]);
|
|
42
|
+
expect(out.value).toEqual({
|
|
43
|
+
bindings: [
|
|
44
|
+
{ from: "rules.ts", name: "api" },
|
|
45
|
+
{ from: "rules.ts", name: "recording" },
|
|
46
|
+
],
|
|
47
|
+
shape: "list",
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("a rule file held as text goes through ruleFileYaml", () => {
|
|
52
|
+
const out = ruleGroupsImporter.import(site({ text: RULE_FILE, document: embeddedDocument(RULE_FILE) }));
|
|
53
|
+
expect(out.value.through).toEqual({ from: "@intentius/chant-lexicon-prometheus", name: "ruleFileYaml" });
|
|
54
|
+
expect(out.value.bindings).toEqual([{ from: "rules.ts", name: "api" }]);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule groups embedded in another lexicon's resource, for `chant import`
|
|
3
|
+
* (#2962): a k8s `PrometheusRule`'s `spec.groups`, or a rule file held as
|
|
4
|
+
* text in a ConfigMap.
|
|
5
|
+
*
|
|
6
|
+
* The groups are imported exactly as `chant import rules.yml` would import
|
|
7
|
+
* them, into a directory of its own. `spec.groups` becomes the list of the
|
|
8
|
+
* declared groups (an `Slo`'s by its `rules` member), which the k8s
|
|
9
|
+
* serializer renders as the same groups; a rule file becomes
|
|
10
|
+
* `ruleFileYaml([...])`, the text the prometheus serializer writes.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { EmbeddedContentImporter, EmbeddedImport } from "@intentius/chant/import/embedded";
|
|
14
|
+
import { looksLikeRuleFile } from "../model";
|
|
15
|
+
import { parsePrometheusYaml } from "./parser";
|
|
16
|
+
import { generateRuleFile } from "./generator";
|
|
17
|
+
|
|
18
|
+
const PACKAGE = "@intentius/chant-lexicon-prometheus";
|
|
19
|
+
|
|
20
|
+
export const ruleGroupsImporter: EmbeddedContentImporter = {
|
|
21
|
+
what: "Prometheus rule groups",
|
|
22
|
+
|
|
23
|
+
matches(content) {
|
|
24
|
+
if (!looksLikeRuleFile(content.document)) return false;
|
|
25
|
+
return content.select === "groups" || (content.select === undefined && typeof content.text === "string");
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
import(content): EmbeddedImport {
|
|
29
|
+
// JSON is YAML: the document goes through the same parser a rule file does.
|
|
30
|
+
const source = content.select === undefined ? content.text! : JSON.stringify(content.document);
|
|
31
|
+
const parsed = parsePrometheusYaml(source);
|
|
32
|
+
if (parsed.kind !== "rules") throw new Error("this is not a Prometheus rule file");
|
|
33
|
+
const { files, groups } = generateRuleFile(parsed.file);
|
|
34
|
+
const bindings = groups.map((g) => ({ from: g.path, name: g.name, ...(g.member ? { member: g.member } : {}) }));
|
|
35
|
+
return {
|
|
36
|
+
files,
|
|
37
|
+
value:
|
|
38
|
+
content.select === undefined
|
|
39
|
+
? { bindings, shape: "list", through: { from: PACKAGE, name: "ruleFileYaml" } }
|
|
40
|
+
: { bindings, shape: "list" },
|
|
41
|
+
warnings: parsed.warnings,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
};
|
|
@@ -50,6 +50,7 @@ describe("the generated source type-checks against the lexicon's types", () => {
|
|
|
50
50
|
const projects: Record<string, Files> = {
|
|
51
51
|
rulesFull: generate(read("rules-full.yml")),
|
|
52
52
|
alertmanagerFull: generate(read("alertmanager-full.yml")),
|
|
53
|
+
alertmanagerIntegrations: generate(read("alertmanager-integrations.yml")),
|
|
53
54
|
...Object.fromEntries(UPSTREAM.map((f) => [f, generate(read("upstream", f))])),
|
|
54
55
|
...Object.fromEntries(sloOutputs().map((o) => [o.name, generate(o.yaml)])),
|
|
55
56
|
...Object.fromEntries((await exampleOutputs()).map((o) => [o.name, generate(o.yaml)])),
|
|
@@ -67,9 +68,10 @@ describe("the generated source type-checks against the lexicon's types", () => {
|
|
|
67
68
|
" - channel: '#alerts'",
|
|
68
69
|
" api_url_file: /etc/alertmanager/slack-url",
|
|
69
70
|
" message_text: '{{ .CommonLabels.alertname }}'",
|
|
71
|
+
" mesage_txt: typo",
|
|
70
72
|
"",
|
|
71
73
|
].join("\n");
|
|
72
74
|
const errors = typeErrors({ slack: generate(yaml) });
|
|
73
|
-
expect(errors).toEqual([expect.stringMatching(/^slack\/receivers\.ts: .*'
|
|
75
|
+
expect(errors).toEqual([expect.stringMatching(/^slack\/receivers\.ts: .*'mesage_txt' does not exist in type 'SlackConfig'/)]);
|
|
74
76
|
}, 120_000);
|
|
75
77
|
});
|
|
@@ -81,17 +81,34 @@ describe("alertmanager.yml", () => {
|
|
|
81
81
|
expect(files["routes.ts"]).toContain("const root = new Route({ receiver: fallback, routes: rootChildren });");
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
test("
|
|
84
|
+
test("every integration Alertmanager defines is declared with its type", () => {
|
|
85
85
|
const files = byPath(
|
|
86
|
-
generateAlertmanagerFiles({
|
|
86
|
+
generateAlertmanagerFiles({
|
|
87
|
+
receivers: [{ name: "ops", opsgenie_configs: [{ api_key_file: "/k", priority: "P1" }], msteamsv2_configs: [{ webhook_url_file: "/t" }] }],
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
expect(files["receivers.ts"]).toContain('const opsOpsgenie: OpsGenieConfig[] = [{ api_key_file: "/k", priority: "P1" }];');
|
|
91
|
+
expect(files["receivers.ts"]).toContain('const opsMsteamsv2: MSTeamsV2Config[] = [{ webhook_url_file: "/t" }];');
|
|
92
|
+
expect(files["receivers.ts"]).not.toContain("Untyped");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("a receiver or global key Alertmanager doesn't define is spread in from an untyped const, with a comment", () => {
|
|
96
|
+
const files = byPath(
|
|
97
|
+
generateAlertmanagerFiles({
|
|
98
|
+
global: { resolve_timeout: "5m", pigeon_loft: "roof" } as never,
|
|
99
|
+
receivers: [{ name: "ops", pigeon_configs: [{ loft: "roof" }] } as never],
|
|
100
|
+
}),
|
|
87
101
|
);
|
|
88
102
|
expect(files["receivers.ts"]).toContain(
|
|
89
103
|
[
|
|
90
|
-
'// Receiver "ops":
|
|
91
|
-
|
|
104
|
+
'// Receiver "ops": pigeon_configs is not a field Alertmanager v0.34.1 defines, so it is carried as',
|
|
105
|
+
"// data, untyped.",
|
|
106
|
+
'const opsUntyped = { pigeon_configs: [{ loft: "roof" }] };',
|
|
92
107
|
'const ops = new Receiver({ name: "ops", ...opsUntyped });',
|
|
93
108
|
].join("\n"),
|
|
94
109
|
);
|
|
110
|
+
expect(files["settings.ts"]).toContain("// global: pigeon_loft is not a field Alertmanager v0.34.1 defines");
|
|
111
|
+
expect(files["settings.ts"]).toContain("...globalUntyped,");
|
|
95
112
|
});
|
|
96
113
|
});
|
|
97
114
|
|