@checkstack/healthcheck-ssh-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 CHANGED
@@ -1,5 +1,124 @@
1
1
  # @checkstack/healthcheck-ssh-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
+ - @checkstack/healthcheck-ssh-common@0.1.28
50
+
51
+ ## 0.4.0
52
+
53
+ ### Minor Changes
54
+
55
+ - faf98f5: Security: config secrets (health-check strategy/collector credentials such as
56
+ SSH passwords, DB credentials, HTTP auth, and integration connection
57
+ credentials) ride ONE shared, domain-agnostic extraction channel instead of
58
+ being stored as plaintext or re-implemented per plugin.
59
+
60
+ New primitive and shared service:
61
+
62
+ - `configSecret({ id })` (in `@checkstack/backend-api`) declares an
63
+ extraction-channel secret keyed by a STABLE `id`, independent of field name or
64
+ position, so renaming or reordering a field never orphans its value. Use it
65
+ (not `configString({ "x-secret": true })`) for any credential whose config is
66
+ relayed to a satellite, projected to AI, or diffed by GitOps. `validateSecretIds`
67
+ rejects, at plugin registration, an `x-secret` field with no `id`, a duplicate
68
+ `id`, or a secret nested in an un-keyable container (array / record / tuple /
69
+ map) - so a mis-keyable schema fails boot rather than at run time.
70
+ - `ConfigSecretChannel` (in `@checkstack/secrets-backend`) is the single
71
+ extract / inflate / collect / redact / merge / delete / prune implementation.
72
+ Health-checks and integration connections both BIND it to their own scope
73
+ (marker prefix + internal-secret key layout); neither re-implements the walk.
74
+
75
+ Lifecycle (both bindings):
76
+
77
+ - **Write**: an inline value is extracted into the encrypted internal secret
78
+ store; the stored config keeps only an opaque marker. `${{ secrets.NAME }}`
79
+ references are stored verbatim and resolve through the active backend (local
80
+ or Vault) at run time.
81
+ - **Read**: configuration and connection reads strip `x-secret` values and
82
+ internal markers while keeping `${{ secrets.NAME }}` references visible; the
83
+ AI `getConfigurations` tool and create/update responses are redacted too. A
84
+ value never reaches a browser or an AI model context.
85
+ - **Run**: the core executor inflates markers/references in memory just before
86
+ the client is built. Satellites receive markers only and fetch values
87
+ just-in-time over the authenticated WS channel, per run, never persisted, then
88
+ fail CLOSED if any marker/reference survives resolution.
89
+ - **No orphan**: clearing a secret, removing a field/collector, swapping an
90
+ inline value for a reference, updating a connection, or deleting a
91
+ configuration/connection deletes the now-unreferenced internal secret. Cleanup
92
+ is schema-free (scans markers by prefix) and best-effort on delete, so it works
93
+ even when the owning plugin is uninstalled and never blocks a delete.
94
+ - **Forged-marker safe**: extract/inflate key each internal secret by the
95
+ SCHEMA leaf's stable `id`, never by an id parsed out of a stored marker string,
96
+ so a crafted marker can never resolve or delete another scope's secret.
97
+
98
+ Health-checks additionally get an idempotent, advisory-locked backfill that
99
+ moves pre-existing plaintext values into the internal store, and per-config-id
100
+ locking so concurrent writers across pods can never leave a dangling marker.
101
+ Integration connection credentials keep their released `__connref__:` marker
102
+ prefix and key layout (id equals the flat field name), so existing stored
103
+ connections are byte-compatible.
104
+
105
+ BREAKING CHANGES:
106
+
107
+ - Configuration and connection reads no longer include `x-secret` field values
108
+ (clients must treat blank-on-save as keep-existing; the bundled editors
109
+ already do).
110
+ - Satellites must be upgraded together with the core: an old satellite cannot
111
+ resolve the markers a new core stores, so its credentialed checks fail until
112
+ upgraded.
113
+
114
+ ### Patch Changes
115
+
116
+ - Updated dependencies [faf98f5]
117
+ - @checkstack/backend-api@0.29.0
118
+ - @checkstack/common@0.20.0
119
+ - @checkstack/healthcheck-common@1.12.0
120
+ - @checkstack/healthcheck-ssh-common@0.1.27
121
+
3
122
  ## 0.3.5
4
123
 
5
124
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/healthcheck-ssh-backend",
3
- "version": "0.3.5",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "checkstack": {
@@ -17,10 +17,10 @@
17
17
  "pack": "bunx @checkstack/scripts plugin-pack"
18
18
  },
19
19
  "dependencies": {
20
- "@checkstack/backend-api": "0.28.0",
21
- "@checkstack/common": "0.19.0",
22
- "@checkstack/healthcheck-common": "1.11.0",
23
- "@checkstack/healthcheck-ssh-common": "0.1.26",
20
+ "@checkstack/backend-api": "0.29.1",
21
+ "@checkstack/common": "0.21.0",
22
+ "@checkstack/healthcheck-common": "1.13.0",
23
+ "@checkstack/healthcheck-ssh-common": "0.1.28",
24
24
  "ssh2": "1.16.0"
25
25
  },
26
26
  "devDependencies": {
@@ -28,7 +28,7 @@
28
28
  "@types/ssh2": "1.15.0",
29
29
  "typescript": "^5.0.0",
30
30
  "@checkstack/tsconfig": "0.0.7",
31
- "@checkstack/scripts": "0.7.0"
31
+ "@checkstack/scripts": "0.7.2"
32
32
  },
33
33
  "description": "Checkstack healthcheck-ssh-backend plugin",
34
34
  "author": {
@@ -43,6 +43,8 @@ const commandResultSchema = healthResultSchema({
43
43
  // by the aggregated successRate). Treating exit-code changes as anomalies
44
44
  // is a classic alert-fatigue source. Still chartable; users can opt in.
45
45
  "x-anomaly-enabled": false,
46
+ "x-chart-priority": 20,
47
+ "x-chart-good-direction": "down",
46
48
  }),
47
49
  stdout: healthResultString({
48
50
  "x-chart-type": "text",
@@ -64,6 +66,7 @@ const commandResultSchema = healthResultSchema({
64
66
  "x-anomaly-confirmation-window": 3,
65
67
  "x-anomaly-min-absolute-delta": 50,
66
68
  "x-anomaly-min-relative-delta": 0.5,
69
+ "x-chart-priority": 10,
67
70
  }),
68
71
  });
69
72
 
@@ -83,6 +86,7 @@ const commandAggregatedFields = {
83
86
  "x-anomaly-confirmation-window": 3,
84
87
  "x-anomaly-min-absolute-delta": 50,
85
88
  "x-anomaly-min-relative-delta": 0.5,
89
+ "x-chart-priority": 10,
86
90
  }),
87
91
  successRate: aggregatedRate({
88
92
  "x-chart-type": "gauge",
@@ -94,6 +98,7 @@ const commandAggregatedFields = {
94
98
  // of real movement before alerting.
95
99
  "x-anomaly-confirmation-window": 3,
96
100
  "x-anomaly-min-absolute-delta": 5,
101
+ "x-chart-priority": 20,
97
102
  }),
98
103
  };
99
104
 
package/src/strategy.ts CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  mergeCounter,
14
14
  mergeMinMax,
15
15
  z,
16
- configString,
16
+ configSecret,
17
17
  type ConnectedClient,
18
18
  type TransportTimings,
19
19
  type InferAggregatedResult,
@@ -39,13 +39,13 @@ export const sshConfigSchema = baseStrategyConfigSchema.extend({
39
39
  host: z.string().describe("SSH server hostname"),
40
40
  port: z.number().int().min(1).max(65_535).default(22).describe("SSH port"),
41
41
  username: z.string().describe("SSH username"),
42
- password: configString({ "x-secret": true })
42
+ password: configSecret({ id: "password" })
43
43
  .describe("Password for authentication")
44
44
  .optional(),
45
- privateKey: configString({ "x-secret": true })
45
+ privateKey: configSecret({ id: "privateKey" })
46
46
  .describe("Private key for authentication")
47
47
  .optional(),
48
- passphrase: configString({ "x-secret": true })
48
+ passphrase: configSecret({ id: "passphrase" })
49
49
  .describe("Passphrase for private key")
50
50
  .optional(),
51
51
  });
@@ -60,8 +60,12 @@ const sshResultSchema = healthResultSchema({
60
60
  connected: healthResultBoolean({
61
61
  "x-chart-type": "boolean",
62
62
  "x-chart-label": "Connected",
63
+ "x-chart-true-label": "connected",
64
+ "x-chart-false-label": "disconnected",
63
65
  "x-anomaly-enabled": true,
64
66
  "x-anomaly-direction": "dominance",
67
+ "x-chart-priority": 20,
68
+ "x-chart-good-direction": "up",
65
69
  }),
66
70
  connectionTimeMs: healthResultNumber({
67
71
  "x-chart-type": "line",
@@ -73,6 +77,7 @@ const sshResultSchema = healthResultSchema({
73
77
  "x-anomaly-confirmation-window": 3,
74
78
  "x-anomaly-min-absolute-delta": 50,
75
79
  "x-anomaly-min-relative-delta": 0.5,
80
+ "x-chart-priority": 10,
76
81
  }),
77
82
  error: healthResultString({
78
83
  "x-chart-type": "status",
@@ -97,6 +102,7 @@ const sshAggregatedFields = {
97
102
  "x-anomaly-confirmation-window": 3,
98
103
  "x-anomaly-min-absolute-delta": 50,
99
104
  "x-anomaly-min-relative-delta": 0.5,
105
+ "x-chart-priority": 10,
100
106
  }),
101
107
  maxConnectionTime: aggregatedMinMax({
102
108
  "x-chart-type": "line",
@@ -107,6 +113,8 @@ const sshAggregatedFields = {
107
113
  // already covers sustained latency regressions, so keep this off by default
108
114
  // (still chartable for tail-latency inspection).
109
115
  "x-anomaly-enabled": false,
116
+ "x-chart-priority": 30,
117
+ "x-chart-good-direction": "down",
110
118
  }),
111
119
  successRate: aggregatedRate({
112
120
  "x-chart-type": "gauge",
@@ -118,6 +126,7 @@ const sshAggregatedFields = {
118
126
  // of real movement before alerting.
119
127
  "x-anomaly-confirmation-window": 3,
120
128
  "x-anomaly-min-absolute-delta": 5,
129
+ "x-chart-priority": 20,
121
130
  }),
122
131
  errorCount: aggregatedCounter({
123
132
  "x-chart-type": "counter",
@@ -127,6 +136,8 @@ const sshAggregatedFields = {
127
136
  // volume rather than with a real problem. Availability is already covered
128
137
  // by successRate (the percent form), so prefer that and keep this off.
129
138
  "x-anomaly-enabled": false,
139
+ "x-chart-priority": 90,
140
+ "x-chart-good-direction": "down",
130
141
  }),
131
142
  };
132
143