@checkstack/healthcheck-postgres-backend 0.3.5 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +117 -0
- package/package.json +5 -5
- package/src/query-collector.ts +6 -0
- package/src/strategy.ts +10 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,122 @@
|
|
|
1
1
|
# @checkstack/healthcheck-postgres-backend
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- c55d7c6: Unify the healthcheck chart system on the `@checkstack/ui` SVG kit and
|
|
8
|
+
redesign the HealthCheck drawer.
|
|
9
|
+
|
|
10
|
+
- `@checkstack/ui` gains six chart primitives (each with a Storybook story):
|
|
11
|
+
`StackedTimeline` (stacked status counts per bucket on the colorblind-safe
|
|
12
|
+
status triad), `ChartTooltip` + `useBandHover` (the one shared chart
|
|
13
|
+
tooltip and its cursor hit-testing), `ChartCard` / `chartCardChromeClass`
|
|
14
|
+
(the premium gradient card chrome, flat on low-power devices), `StatTile`
|
|
15
|
+
(number-led metric tile with delta chip, sparkline/ribbon footer, and
|
|
16
|
+
click-to-expand disclosure), `DistributionBar` (stacked horizontal
|
|
17
|
+
distribution + legend, replaces pies), and `CategoryRibbon` (categorical
|
|
18
|
+
history ribbon). `TimeSeriesChart` gains a hover tooltip with a crosshair
|
|
19
|
+
marker.
|
|
20
|
+
- `@checkstack/common` adds four optional chart metadata keys to
|
|
21
|
+
`BaseHealthResultMeta`: `x-chart-priority` (tile sort weight, lower first,
|
|
22
|
+
default 100), `x-chart-good-direction` (`"up" | "down"`, which direction
|
|
23
|
+
of change is an improvement; consumers fall back to
|
|
24
|
+
`x-anomaly-direction`), and `x-chart-true-label` / `x-chart-false-label`
|
|
25
|
+
(prose for a boolean field's values wherever they surface in text, e.g. a
|
|
26
|
+
dominance chip reading "Usually successful (98%)" instead of "Usually
|
|
27
|
+
true"). Built-in collector backends annotate their headline metrics and
|
|
28
|
+
boolean fields accordingly (purely additive metadata).
|
|
29
|
+
- `@checkstack/healthcheck-frontend` rebuilds the drawer: a hero status
|
|
30
|
+
banner (status pill, healthy %, avg latency, interval, last run with the
|
|
31
|
+
exact datetime on hover, full-width status ribbon) replaces the metric
|
|
32
|
+
tiles; the status timeline and latency heroes share the `ChartCard`
|
|
33
|
+
chrome; the auto-generated charts become a prioritized, click-to-expand
|
|
34
|
+
2-up tile grid (collector ids demoted to hover titles); the anomaly
|
|
35
|
+
Expected/Trend derivation is consolidated into one tested module shared by
|
|
36
|
+
the latency hero and the tiles.
|
|
37
|
+
|
|
38
|
+
BREAKING CHANGES: `recharts` is removed from `@checkstack/healthcheck-frontend`
|
|
39
|
+
(and the unused dependency from `@checkstack/ui`); the
|
|
40
|
+
`HealthCheckStatusTimeline` and `SparklineTooltip` components are deleted.
|
|
41
|
+
Extensions rendering into `HealthCheckDiagramSlot` should build on the
|
|
42
|
+
`@checkstack/ui` chart primitives instead.
|
|
43
|
+
|
|
44
|
+
- Updated dependencies [c55d7c6]
|
|
45
|
+
- Updated dependencies [c55d7c6]
|
|
46
|
+
- @checkstack/healthcheck-common@1.13.0
|
|
47
|
+
- @checkstack/common@0.21.0
|
|
48
|
+
- @checkstack/backend-api@0.29.1
|
|
49
|
+
|
|
50
|
+
## 0.4.0
|
|
51
|
+
|
|
52
|
+
### Minor Changes
|
|
53
|
+
|
|
54
|
+
- faf98f5: Security: config secrets (health-check strategy/collector credentials such as
|
|
55
|
+
SSH passwords, DB credentials, HTTP auth, and integration connection
|
|
56
|
+
credentials) ride ONE shared, domain-agnostic extraction channel instead of
|
|
57
|
+
being stored as plaintext or re-implemented per plugin.
|
|
58
|
+
|
|
59
|
+
New primitive and shared service:
|
|
60
|
+
|
|
61
|
+
- `configSecret({ id })` (in `@checkstack/backend-api`) declares an
|
|
62
|
+
extraction-channel secret keyed by a STABLE `id`, independent of field name or
|
|
63
|
+
position, so renaming or reordering a field never orphans its value. Use it
|
|
64
|
+
(not `configString({ "x-secret": true })`) for any credential whose config is
|
|
65
|
+
relayed to a satellite, projected to AI, or diffed by GitOps. `validateSecretIds`
|
|
66
|
+
rejects, at plugin registration, an `x-secret` field with no `id`, a duplicate
|
|
67
|
+
`id`, or a secret nested in an un-keyable container (array / record / tuple /
|
|
68
|
+
map) - so a mis-keyable schema fails boot rather than at run time.
|
|
69
|
+
- `ConfigSecretChannel` (in `@checkstack/secrets-backend`) is the single
|
|
70
|
+
extract / inflate / collect / redact / merge / delete / prune implementation.
|
|
71
|
+
Health-checks and integration connections both BIND it to their own scope
|
|
72
|
+
(marker prefix + internal-secret key layout); neither re-implements the walk.
|
|
73
|
+
|
|
74
|
+
Lifecycle (both bindings):
|
|
75
|
+
|
|
76
|
+
- **Write**: an inline value is extracted into the encrypted internal secret
|
|
77
|
+
store; the stored config keeps only an opaque marker. `${{ secrets.NAME }}`
|
|
78
|
+
references are stored verbatim and resolve through the active backend (local
|
|
79
|
+
or Vault) at run time.
|
|
80
|
+
- **Read**: configuration and connection reads strip `x-secret` values and
|
|
81
|
+
internal markers while keeping `${{ secrets.NAME }}` references visible; the
|
|
82
|
+
AI `getConfigurations` tool and create/update responses are redacted too. A
|
|
83
|
+
value never reaches a browser or an AI model context.
|
|
84
|
+
- **Run**: the core executor inflates markers/references in memory just before
|
|
85
|
+
the client is built. Satellites receive markers only and fetch values
|
|
86
|
+
just-in-time over the authenticated WS channel, per run, never persisted, then
|
|
87
|
+
fail CLOSED if any marker/reference survives resolution.
|
|
88
|
+
- **No orphan**: clearing a secret, removing a field/collector, swapping an
|
|
89
|
+
inline value for a reference, updating a connection, or deleting a
|
|
90
|
+
configuration/connection deletes the now-unreferenced internal secret. Cleanup
|
|
91
|
+
is schema-free (scans markers by prefix) and best-effort on delete, so it works
|
|
92
|
+
even when the owning plugin is uninstalled and never blocks a delete.
|
|
93
|
+
- **Forged-marker safe**: extract/inflate key each internal secret by the
|
|
94
|
+
SCHEMA leaf's stable `id`, never by an id parsed out of a stored marker string,
|
|
95
|
+
so a crafted marker can never resolve or delete another scope's secret.
|
|
96
|
+
|
|
97
|
+
Health-checks additionally get an idempotent, advisory-locked backfill that
|
|
98
|
+
moves pre-existing plaintext values into the internal store, and per-config-id
|
|
99
|
+
locking so concurrent writers across pods can never leave a dangling marker.
|
|
100
|
+
Integration connection credentials keep their released `__connref__:` marker
|
|
101
|
+
prefix and key layout (id equals the flat field name), so existing stored
|
|
102
|
+
connections are byte-compatible.
|
|
103
|
+
|
|
104
|
+
BREAKING CHANGES:
|
|
105
|
+
|
|
106
|
+
- Configuration and connection reads no longer include `x-secret` field values
|
|
107
|
+
(clients must treat blank-on-save as keep-existing; the bundled editors
|
|
108
|
+
already do).
|
|
109
|
+
- Satellites must be upgraded together with the core: an old satellite cannot
|
|
110
|
+
resolve the markers a new core stores, so its credentialed checks fail until
|
|
111
|
+
upgraded.
|
|
112
|
+
|
|
113
|
+
### Patch Changes
|
|
114
|
+
|
|
115
|
+
- Updated dependencies [faf98f5]
|
|
116
|
+
- @checkstack/backend-api@0.29.0
|
|
117
|
+
- @checkstack/common@0.20.0
|
|
118
|
+
- @checkstack/healthcheck-common@1.12.0
|
|
119
|
+
|
|
3
120
|
## 0.3.5
|
|
4
121
|
|
|
5
122
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/healthcheck-postgres-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"checkstack": {
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
"pack": "bunx @checkstack/scripts plugin-pack"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@checkstack/backend-api": "0.
|
|
18
|
-
"@checkstack/common": "0.
|
|
19
|
-
"@checkstack/healthcheck-common": "1.
|
|
17
|
+
"@checkstack/backend-api": "0.29.1",
|
|
18
|
+
"@checkstack/common": "0.21.0",
|
|
19
|
+
"@checkstack/healthcheck-common": "1.13.0",
|
|
20
20
|
"pg": "^8.11.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@types/pg": "^8.11.0",
|
|
25
25
|
"typescript": "^5.0.0",
|
|
26
26
|
"@checkstack/tsconfig": "0.0.7",
|
|
27
|
-
"@checkstack/scripts": "0.7.
|
|
27
|
+
"@checkstack/scripts": "0.7.2"
|
|
28
28
|
},
|
|
29
29
|
"description": "Checkstack healthcheck-postgres-backend plugin",
|
|
30
30
|
"author": {
|
package/src/query-collector.ts
CHANGED
|
@@ -43,6 +43,7 @@ const queryResultSchema = healthResultSchema({
|
|
|
43
43
|
// fire on routine data growth, so it is off by default. Still chartable
|
|
44
44
|
// and opt-in per check.
|
|
45
45
|
"x-anomaly-enabled": false,
|
|
46
|
+
"x-chart-priority": 30,
|
|
46
47
|
}),
|
|
47
48
|
executionTimeMs: healthResultNumber({
|
|
48
49
|
"x-chart-type": "line",
|
|
@@ -54,12 +55,16 @@ const queryResultSchema = healthResultSchema({
|
|
|
54
55
|
"x-anomaly-confirmation-window": 3,
|
|
55
56
|
"x-anomaly-min-absolute-delta": 50,
|
|
56
57
|
"x-anomaly-min-relative-delta": 0.5,
|
|
58
|
+
"x-chart-priority": 10,
|
|
57
59
|
}),
|
|
58
60
|
success: healthResultBoolean({
|
|
59
61
|
"x-chart-type": "boolean",
|
|
60
62
|
"x-chart-label": "Success",
|
|
63
|
+
"x-chart-true-label": "successful",
|
|
64
|
+
"x-chart-false-label": "failing",
|
|
61
65
|
"x-anomaly-enabled": true,
|
|
62
66
|
"x-anomaly-direction": "dominance",
|
|
67
|
+
"x-chart-good-direction": "up",
|
|
63
68
|
}),
|
|
64
69
|
});
|
|
65
70
|
|
|
@@ -79,6 +84,7 @@ const queryAggregatedFields = {
|
|
|
79
84
|
"x-anomaly-confirmation-window": 3,
|
|
80
85
|
"x-anomaly-min-absolute-delta": 50,
|
|
81
86
|
"x-anomaly-min-relative-delta": 0.5,
|
|
87
|
+
"x-chart-priority": 10,
|
|
82
88
|
}),
|
|
83
89
|
successRate: aggregatedRate({
|
|
84
90
|
"x-chart-type": "gauge",
|
package/src/strategy.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
mergeMinMax,
|
|
15
15
|
z,
|
|
16
16
|
configString,
|
|
17
|
+
configSecret,
|
|
17
18
|
configNumber,
|
|
18
19
|
configBoolean,
|
|
19
20
|
type ConnectedClient,
|
|
@@ -52,7 +53,7 @@ export const postgresConfigSchema = baseStrategyConfigSchema.extend({
|
|
|
52
53
|
.describe("PostgreSQL port"),
|
|
53
54
|
database: configString({}).describe("Database name"),
|
|
54
55
|
user: configString({}).describe("Database user"),
|
|
55
|
-
password:
|
|
56
|
+
password: configSecret({ id: "password" }).describe("Database password"),
|
|
56
57
|
ssl: configBoolean({}).default(false).describe("Use SSL connection"),
|
|
57
58
|
});
|
|
58
59
|
|
|
@@ -66,8 +67,11 @@ const postgresResultSchema = healthResultSchema({
|
|
|
66
67
|
connected: healthResultBoolean({
|
|
67
68
|
"x-chart-type": "boolean",
|
|
68
69
|
"x-chart-label": "Connected",
|
|
70
|
+
"x-chart-true-label": "connected",
|
|
71
|
+
"x-chart-false-label": "disconnected",
|
|
69
72
|
"x-anomaly-enabled": true,
|
|
70
73
|
"x-anomaly-direction": "dominance",
|
|
74
|
+
"x-chart-good-direction": "up",
|
|
71
75
|
}),
|
|
72
76
|
connectionTimeMs: healthResultNumber({
|
|
73
77
|
"x-chart-type": "line",
|
|
@@ -79,6 +83,7 @@ const postgresResultSchema = healthResultSchema({
|
|
|
79
83
|
"x-anomaly-confirmation-window": 3,
|
|
80
84
|
"x-anomaly-min-absolute-delta": 50,
|
|
81
85
|
"x-anomaly-min-relative-delta": 0.5,
|
|
86
|
+
"x-chart-priority": 10,
|
|
82
87
|
}),
|
|
83
88
|
error: healthResultString({
|
|
84
89
|
"x-chart-type": "status",
|
|
@@ -103,6 +108,7 @@ const postgresAggregatedFields = {
|
|
|
103
108
|
"x-anomaly-confirmation-window": 3,
|
|
104
109
|
"x-anomaly-min-absolute-delta": 50,
|
|
105
110
|
"x-anomaly-min-relative-delta": 0.5,
|
|
111
|
+
"x-chart-priority": 10,
|
|
106
112
|
}),
|
|
107
113
|
maxConnectionTime: aggregatedMinMax({
|
|
108
114
|
"x-chart-type": "line",
|
|
@@ -113,6 +119,7 @@ const postgresAggregatedFields = {
|
|
|
113
119
|
// alerts. Average connection time already covers the latency-saturation
|
|
114
120
|
// signal, so the max is off by default and remains chartable.
|
|
115
121
|
"x-anomaly-enabled": false,
|
|
122
|
+
"x-chart-good-direction": "down",
|
|
116
123
|
}),
|
|
117
124
|
successRate: aggregatedRate({
|
|
118
125
|
"x-chart-type": "gauge",
|
|
@@ -133,6 +140,8 @@ const postgresAggregatedFields = {
|
|
|
133
140
|
// failures as a normalized percent, so this absolute twin is off by default
|
|
134
141
|
// to avoid duplicate, volume-sensitive alerts.
|
|
135
142
|
"x-anomaly-enabled": false,
|
|
143
|
+
"x-chart-good-direction": "down",
|
|
144
|
+
"x-chart-priority": 90,
|
|
136
145
|
}),
|
|
137
146
|
};
|
|
138
147
|
|