@intentius/chant-lexicon-prometheus 0.98.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/import/embedded.d.ts +14 -0
  3. package/dist/import/embedded.d.ts.map +1 -0
  4. package/dist/import/generator.d.ts +15 -0
  5. package/dist/import/generator.d.ts.map +1 -1
  6. package/dist/import/parser.d.ts.map +1 -1
  7. package/dist/integrations.d.ts +531 -0
  8. package/dist/integrations.d.ts.map +1 -0
  9. package/dist/integrity.json +4 -4
  10. package/dist/lint/rules/literal-credential.d.ts.map +1 -1
  11. package/dist/manifest.json +1 -1
  12. package/dist/model.d.ts +58 -123
  13. package/dist/model.d.ts.map +1 -1
  14. package/dist/plugin.d.ts.map +1 -1
  15. package/dist/rules/literal-credential.ts +41 -10
  16. package/dist/skills/chant-prometheus-alertmanager.md +1 -1
  17. package/package.json +2 -2
  18. package/src/import/embedded.test.ts +56 -0
  19. package/src/import/embedded.ts +44 -0
  20. package/src/import/generated-types.e2e.test.ts +3 -1
  21. package/src/import/generator.test.ts +21 -4
  22. package/src/import/generator.ts +32 -24
  23. package/src/import/parser.test.ts +13 -0
  24. package/src/import/parser.ts +18 -1
  25. package/src/import/roundtrip.test.ts +46 -9
  26. package/src/import/testdata/alertmanager-full.yml +3 -3
  27. package/src/import/testdata/alertmanager-integrations.yml +215 -0
  28. package/src/import/testdata/fixtures.ts +8 -0
  29. package/src/import/testdata/upstream/alertmanager-conf-good.yml +120 -0
  30. package/src/import/testdata/upstream/alertmanager-mattermost-default-webhook-url-file.yml +16 -0
  31. package/src/import/testdata/upstream/alertmanager-opsgenie-default-apikey-file.yml +27 -0
  32. package/src/import/testdata/upstream/alertmanager-rocketchat-default-token-file.yml +25 -0
  33. package/src/import/testdata/upstream/alertmanager-sns-topic-arn.yml +17 -0
  34. package/src/import/testdata/upstream/alertmanager-telegram-default-bot-token-file.yml +16 -0
  35. package/src/import/testdata/upstream/alertmanager-victorops-default-apikey-file.yml +23 -0
  36. package/src/import/testdata/upstream/alertmanager-wechat-default-api-secret-file.yml +18 -0
  37. package/src/integrations.ts +538 -0
  38. package/src/lint/rules/literal-credential.ts +41 -10
  39. package/src/lint/rules/rules.test.ts +31 -1
  40. package/src/model.ts +136 -110
  41. package/src/plugin.ts +5 -0
  42. 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
- /** HTTP client settings shared by the receivers that make HTTP calls. */
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
- webhook_configs?: WebhookConfig[];
70
+ discord_configs?: DiscordConfig[];
182
71
  email_configs?: EmailConfig[];
183
- slack_configs?: SlackConfig[];
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
- /** `global:` settings. */
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
- http_config?: HttpClientConfig;
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?: HttpClientConfig["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 four receiver integrations this lexicon types. */
277
- export declare const RECEIVER_INTEGRATIONS: readonly ["webhook_configs", "email_configs", "slack_configs", "pagerduty_configs"];
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
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
@@ -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;AA8B9D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAqG9B,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
- "slack_api_url",
12
- "routing_key",
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
- const scanValue = (key: string | undefined, value: ts.Expression) => {
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. Integrations the lexicon doesn't type (`opsgenie_configs`, `msteams_configs`, ...) are spread in from an untyped const. `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.
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.98.0",
3
+ "version": "0.99.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.98.0",
74
+ "@intentius/chant": "^0.99.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: .*'message_text' does not exist in type 'SlackConfig'/)]);
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("an integration the lexicon does not type is spread in from an untyped const, with a comment", () => {
84
+ test("every integration Alertmanager defines is declared with its type", () => {
85
85
  const files = byPath(
86
- generateAlertmanagerFiles({ receivers: [{ name: "ops", opsgenie_configs: [{ api_key_file: "/k" }] } as never] }),
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": opsgenie_configs is not typed by this lexicon, so it is carried as data.',
91
- 'const opsUntyped = { opsgenie_configs: [{ api_key_file: "/k" }] };',
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