Skip to content

Commit 82888d4

Browse files
authored
test(cli): cover ssl-enforcement get and update (CLI-2270) (#6444)
## TL;DR adds live e2e coverage for `ssl-enforcement get` and `update`, covering the ssl-enforcement command family ## whats introduced? - `ssl-enforcement get`: reads the target project's posture and proves the json payload carries `currentConfig.database` and `appliedSuccessfully` - `ssl-enforcement update`: captures the current posture, toggles it, proves the flip in its own output and through get, then restores the captured posture in the same test ## ref: - closes: CLI-2270
1 parent 1f85d4b commit 82888d4

6 files changed

Lines changed: 144 additions & 10 deletions

File tree

apps/cli/src/legacy/commands/postgres-config/delete/delete.live.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from "vitest";
22

33
import {
4-
postgresConfigLiveFlags,
4+
experimentalProjectLiveFlags,
55
removePostgresConfigLiveOverride,
66
requireLiveSuccess,
77
test,
@@ -12,7 +12,7 @@ import {
1212
// assertion cannot be satisfied by the pre-seed state. Teardown removes the
1313
// seeded key only when the test did not already prove it gone.
1414
test("removes the test-seeded override and get proves it is gone", async ({ cli, project }) => {
15-
const flags = postgresConfigLiveFlags(project);
15+
const flags = experimentalProjectLiveFlags(project);
1616
let targetError: unknown;
1717
const cleanupErrors: Array<unknown> = [];
1818
let cleanupNeeded = true;

apps/cli/src/legacy/commands/postgres-config/get/get.live.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect } from "vitest";
22

3-
import { postgresConfigLiveFlags, test } from "../../../../../tests/helpers/live.ts";
3+
import { experimentalProjectLiveFlags, test } from "../../../../../tests/helpers/live.ts";
44

55
// A freshly provisioned project can have zero overrides, so the golden path
66
// pins the payload shape rather than any key: exit 0 and a JSON object on
@@ -9,7 +9,7 @@ test("reads the current config of the target project", async ({ cli, project })
99
const result = await cli([
1010
"postgres-config",
1111
"get",
12-
...postgresConfigLiveFlags(project),
12+
...experimentalProjectLiveFlags(project),
1313
"-o",
1414
"json",
1515
]);

apps/cli/src/legacy/commands/postgres-config/update/update.live.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from "vitest";
22

33
import {
4-
postgresConfigLiveFlags,
4+
experimentalProjectLiveFlags,
55
removePostgresConfigLiveOverride,
66
requireLiveSuccess,
77
test,
@@ -11,7 +11,7 @@ import {
1111
// --no-restart skips the database restart; work_mem is a dynamic parameter, so
1212
// the override still takes effect.
1313
test("applies an override with --no-restart and get proves it", async ({ cli, project }) => {
14-
const flags = postgresConfigLiveFlags(project);
14+
const flags = experimentalProjectLiveFlags(project);
1515
let targetError: unknown;
1616
const cleanupErrors: Array<unknown> = [];
1717
try {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { expect } from "vitest";
2+
3+
import { experimentalProjectLiveFlags, test } from "../../../../../tests/helpers/live.ts";
4+
5+
test("reads the SSL enforcement posture of the target project", async ({ cli, project }) => {
6+
const result = await cli([
7+
"ssl-enforcement",
8+
"get",
9+
...experimentalProjectLiveFlags(project),
10+
"-o",
11+
"json",
12+
]);
13+
expect(result.exitCode, result.stderr).toBe(0);
14+
expect(result.stdout, result.stderr).not.toBe("");
15+
expect(JSON.parse(result.stdout), result.stdout).toMatchObject({
16+
currentConfig: { database: expect.any(Boolean) },
17+
appliedSuccessfully: expect.any(Boolean),
18+
});
19+
});
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { Schema } from "effect";
2+
import { expect } from "vitest";
3+
4+
import {
5+
experimentalProjectLiveFlags,
6+
type LiveFixtures,
7+
requireLiveSuccess,
8+
test,
9+
throwWithCleanup,
10+
} from "../../../../../tests/helpers/live.ts";
11+
12+
type LiveCli = LiveFixtures["cli"];
13+
14+
// Bound the polled gets and the restore so one hung subprocess cannot exhaust
15+
// the live testTimeout and leave the shared project with a flipped posture.
16+
const POLL_ATTEMPT_EXIT_TIMEOUT_MS = 20_000;
17+
const RESTORE_EXIT_TIMEOUT_MS = 60_000;
18+
19+
const SslEnforcementPosture = Schema.Struct({
20+
currentConfig: Schema.Struct({ database: Schema.Boolean }),
21+
appliedSuccessfully: Schema.Boolean,
22+
});
23+
24+
function enforcementFlag(enforce: boolean): string {
25+
return enforce ? "--enable-db-ssl-enforcement" : "--disable-db-ssl-enforcement";
26+
}
27+
28+
async function readPosture(
29+
cli: LiveCli,
30+
flags: ReadonlyArray<string>,
31+
label: string,
32+
exitTimeoutMs?: number,
33+
): Promise<typeof SslEnforcementPosture.Type> {
34+
const result = await cli(["ssl-enforcement", "get", ...flags, "-o", "json"], { exitTimeoutMs });
35+
requireLiveSuccess(result, label);
36+
expect(result.stdout, result.stderr).not.toBe("");
37+
const payload: unknown = JSON.parse(result.stdout);
38+
if (!Schema.is(SslEnforcementPosture)(payload)) {
39+
throw new Error(`${label}: unexpected ssl-enforcement get payload\n${result.stdout}`);
40+
}
41+
return payload;
42+
}
43+
44+
// get reports `appliedSuccessfully: false` while a requested posture has not
45+
// propagated yet (see ../get/SIDE_EFFECTS.md), so proving a toggle or a restore
46+
// means polling get until the requested value is reported as applied.
47+
function expectApplied(
48+
cli: LiveCli,
49+
flags: ReadonlyArray<string>,
50+
enforce: boolean,
51+
label: string,
52+
): Promise<void> {
53+
return expect
54+
.poll(() => readPosture(cli, flags, label, POLL_ATTEMPT_EXIT_TIMEOUT_MS), {
55+
interval: 2_000,
56+
timeout: 60_000,
57+
message: label,
58+
})
59+
.toEqual({ currentConfig: { database: enforce }, appliedSuccessfully: true });
60+
}
61+
62+
test("toggles enforcement, get proves it, and restores the captured posture", async ({
63+
cli,
64+
project,
65+
}) => {
66+
const flags = experimentalProjectLiveFlags(project);
67+
const posture = (
68+
await readPosture(cli, flags, "ssl-enforcement get capture for ssl-enforcement update")
69+
).currentConfig.database;
70+
let targetError: unknown;
71+
const cleanupErrors: Array<unknown> = [];
72+
try {
73+
const updated = await cli([
74+
"ssl-enforcement",
75+
"update",
76+
enforcementFlag(!posture),
77+
...flags,
78+
"-o",
79+
"json",
80+
]);
81+
expect(updated.exitCode, updated.stderr).toBe(0);
82+
expect(updated.stdout, updated.stderr).not.toBe("");
83+
expect(JSON.parse(updated.stdout), updated.stdout).toMatchObject({
84+
currentConfig: { database: !posture },
85+
});
86+
87+
await expectApplied(
88+
cli,
89+
flags,
90+
!posture,
91+
"ssl-enforcement get proof for ssl-enforcement update",
92+
);
93+
} catch (error) {
94+
targetError = error;
95+
} finally {
96+
try {
97+
const restored = await cli(
98+
["ssl-enforcement", "update", enforcementFlag(posture), ...flags],
99+
{
100+
exitTimeoutMs: RESTORE_EXIT_TIMEOUT_MS,
101+
},
102+
);
103+
requireLiveSuccess(restored, "ssl-enforcement update restore of the captured posture");
104+
await expectApplied(
105+
cli,
106+
flags,
107+
posture,
108+
"ssl-enforcement get proof of the restored posture for ssl-enforcement update",
109+
);
110+
} catch (error) {
111+
cleanupErrors.push(error);
112+
}
113+
}
114+
throwWithCleanup(targetError, cleanupErrors);
115+
});

apps/cli/tests/helpers/live.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ export async function removeStorageLiveObject(
145145
}
146146
}
147147

148-
/** Flags every postgres-config live test passes: the family is
149-
* experimental-gated and addresses the shared project by ref. */
150-
export function postgresConfigLiveFlags(project: LiveProject): ReadonlyArray<string> {
148+
/** Flags for experimental-gated live tests that address the shared project by
149+
* ref rather than linking it (contrast `storageLiveFlags`). */
150+
export function experimentalProjectLiveFlags(project: LiveProject): ReadonlyArray<string> {
151151
return ["--project-ref", project.ref, "--experimental"];
152152
}
153153

@@ -166,7 +166,7 @@ export async function removePostgresConfigLiveOverride(
166166
"delete",
167167
"--config",
168168
key,
169-
...postgresConfigLiveFlags(project),
169+
...experimentalProjectLiveFlags(project),
170170
"--no-restart",
171171
]);
172172
requireLiveSuccess(removed, `postgres-config delete cleanup for ${key}`);

0 commit comments

Comments
 (0)