|
1 | 1 | import assert from "node:assert/strict" |
2 | | -import { mkdtemp, readFile, rm } from "node:fs/promises" |
| 2 | +import { mkdtemp, readFile, readdir, rm } from "node:fs/promises" |
3 | 3 | import { tmpdir } from "node:os" |
4 | 4 | import { join } from "node:path" |
5 | 5 | import { executeRuntimeServiceProcess, provisionRuntimeServices, RuntimeServiceProvisionError, runtimeServicePlan, type RuntimeServiceDependencies } from "../packages/cli/src/runtime-services.ts" |
@@ -116,45 +116,52 @@ assert.equal(provisioned.env.DB_HOST, "database.internal") |
116 | 116 | assert.equal(provisioned.env.DB_PORT, "3307") |
117 | 117 | assert.match(provisioned.env.DB_NAME ?? "", /^wp_codebox_[a-f0-9]{24}$/) |
118 | 118 | assert.match(provisioned.env.DB_USER ?? "", /^wpcb_[a-f0-9]{24}$/) |
119 | | -assert.equal(provisioned.secretEnv.DB_PASSWORD, provisioned.env.DB_PASSWORD) |
| 119 | +const generatedPassword = provisioned.secretEnv.DB_PASSWORD ?? "" |
| 120 | +assert.match(generatedPassword, /^[A-Za-z0-9_-]+$/) |
| 121 | +assert.equal(provisioned.env.DB_PASSWORD, undefined, "password is absent from the non-secret output channel") |
120 | 122 | assert.equal(provisioned.evidence[0]?.provider, "external") |
121 | 123 | assert.equal(provisioned.evidence[0]?.readiness, "ready") |
122 | 124 | const createDatabase = successFake.calls.find((call) => call.stdin?.startsWith("CREATE DATABASE")) |
123 | 125 | const createUser = successFake.calls.find((call) => call.stdin?.startsWith("CREATE USER")) |
124 | 126 | assert.match(createDatabase?.stdin ?? "", /^CREATE DATABASE `wp_codebox_[a-f0-9]{24}`;\n$/) |
125 | 127 | assert.match(createUser?.stdin ?? "", /^CREATE USER 'wpcb_[a-f0-9]{24}'@'%' IDENTIFIED BY '[A-Za-z0-9_-]+';\n$/) |
126 | | -assert.equal(successFake.calls.some((call) => call.args.some((arg) => arg.includes(adminPassword) || arg.includes(provisioned.env.DB_PASSWORD ?? ""))), false, "passwords never enter argv") |
| 128 | +assert.equal(successFake.calls.some((call) => call.args.some((arg) => arg.includes(adminPassword) || arg.includes(generatedPassword))), false, "passwords never enter argv") |
127 | 129 | assert.equal(JSON.stringify(runtimeServicePlan([externalService])).includes(adminPassword), false) |
128 | 130 | assert.equal(JSON.stringify(provisioned.evidence).includes(adminPassword), false) |
129 | | -assert.equal(JSON.stringify(provisioned.evidence).includes(provisioned.env.DB_PASSWORD ?? ""), false) |
| 131 | +assert.equal(JSON.stringify(provisioned.evidence).includes(generatedPassword), false) |
130 | 132 | const bootstrapRoot = await mkdtemp(join(tmpdir(), "wp-codebox-external-mysql-bootstrap-")) |
131 | 133 | const wordpressRoot = await mkdtemp(join(tmpdir(), "wp-codebox-external-mysql-wordpress-")) |
132 | 134 | try { |
133 | 135 | const bootstrapCalls: Parameters<PlaygroundCliModule["runCLI"]>[0][] = [] |
| 136 | + const bootstrapRuns: Array<({ code: string } | { scriptPath: string }) & { env?: Record<string, string> }> = [] |
134 | 137 | const cliModule: PlaygroundCliModule = { async runCLI(options) { |
135 | 138 | bootstrapCalls.push(options) |
136 | | - return { serverUrl: "http://127.0.0.1:65535", playground: { async run() { return { text: "" } } }, async [Symbol.asyncDispose]() {} } |
| 139 | + return { serverUrl: "http://127.0.0.1:65535", playground: { async run(runOptions) { bootstrapRuns.push(runOptions); return { text: runOptions.env?.DB_PASSWORD ?? "" } } }, async [Symbol.asyncDispose]() {} } |
137 | 140 | } } |
138 | | - const { DB_PASSWORD: _password, ...runtimeEnv } = provisioned.env |
139 | 141 | const runtimeSpec: RuntimeCreateSpec = { |
140 | 142 | backend: "wordpress-playground", |
141 | 143 | environment: { version: "mounted", wordpressInstallMode: "do-not-attempt-installing", databaseSetup: "external", assets: { wordpressDirectory: wordpressRoot }, blueprint: {} }, |
142 | 144 | policy, |
143 | | - runtimeEnv, |
| 145 | + runtimeEnv: provisioned.env, |
144 | 146 | secretEnv: provisioned.secretEnv, |
145 | 147 | artifactsDirectory: bootstrapRoot, |
146 | 148 | } |
147 | 149 | const server = await startPlaygroundCliServer(runtimeSpec, [], { cliModule }) |
| 150 | + const connectorResponse = await server.playground.run({ code: "<?php echo getenv('DB_PASSWORD');" }) |
| 151 | + assert.equal(connectorResponse.text, generatedPassword, "generated password reaches PHP through the ephemeral run environment") |
| 152 | + assert.equal(bootstrapRuns[0]?.env?.DB_PASSWORD, generatedPassword) |
148 | 153 | await server[Symbol.asyncDispose]() |
149 | 154 | const mounts = bootstrapCalls[0]?.["mount-before-install"] ?? [] |
150 | 155 | const autoPrependPath = mounts.find((mount) => mount.vfsPath === "/internal/shared/wp-codebox-auto-prepend.php")?.hostPath |
151 | 156 | const wpConfigPath = mounts.find((mount) => mount.vfsPath === "/wordpress/wp-config.php")?.hostPath |
152 | 157 | assert.ok(autoPrependPath && wpConfigPath) |
153 | 158 | const autoPrepend = await readFile(autoPrependPath, "utf8") |
154 | 159 | const wpConfig = await readFile(wpConfigPath, "utf8") |
155 | | - assert.match(autoPrepend, new RegExp(`putenv\\("DB_PASSWORD=${provisioned.env.DB_PASSWORD}`), "generated password reaches the connector bootstrap environment") |
156 | 160 | assert.match(wpConfig, /getenv\('DB_PASSWORD'\)/) |
157 | | - assert.equal(wpConfig.includes(provisioned.env.DB_PASSWORD ?? ""), false, "generated password is not serialized into wp-config") |
| 161 | + assert.equal(autoPrepend.includes(generatedPassword), false, "generated password is not serialized into auto-prepend PHP") |
| 162 | + assert.equal(wpConfig.includes(generatedPassword), false, "generated password is not serialized into wp-config") |
| 163 | + assert.equal(await directoryContains(bootstrapRoot, generatedPassword), false, "generated password is absent from persisted artifact files") |
| 164 | + assert.equal(await directoryContains(wordpressRoot, generatedPassword), false, "generated password is absent from persisted WordPress files") |
158 | 165 | } finally { |
159 | 166 | await rm(bootstrapRoot, { recursive: true, force: true }) |
160 | 167 | await rm(wordpressRoot, { recursive: true, force: true }) |
@@ -243,3 +250,15 @@ await assert.rejects(executeRuntimeServiceProcess(process.execPath, ["-e", "proc |
243 | 250 | }) |
244 | 251 |
|
245 | 252 | console.log("external MySQL runtime service tests passed") |
| 253 | + |
| 254 | +async function directoryContains(root: string, needle: string): Promise<boolean> { |
| 255 | + for (const entry of await readdir(root, { withFileTypes: true })) { |
| 256 | + const path = join(root, entry.name) |
| 257 | + if (entry.isDirectory()) { |
| 258 | + if (await directoryContains(path, needle)) return true |
| 259 | + } else if (entry.isFile() && (await readFile(path)).includes(Buffer.from(needle))) { |
| 260 | + return true |
| 261 | + } |
| 262 | + } |
| 263 | + return false |
| 264 | +} |
0 commit comments