diff --git a/cli/deploy.js b/cli/deploy.js index 8f33982..0a9b15d 100644 --- a/cli/deploy.js +++ b/cli/deploy.js @@ -12,6 +12,23 @@ import { detectWorkflow } from '../lib/workflow.js' export const options = { command: 'deploy', strict: true } +// Docker build args for a deploy. Query-string skew protection needs ONE value +// in three places: baked into the client assets as `?dpl=` at build time, +// set as plt.dev/version on the workload, and therefore used as the gateway's +// match key. --version is that value, so it has to reach the build as well as +// the deploy. +// +// Exported so this is covered by a test: the failure is silent. Without the +// build arg the image builds, the workload deploys, and the app runs, but its +// assets carry no ?dpl, so ICC sees a version that was not built with its own id +// and correctly refuses to route to it. Nothing errors. +// +// An app whose Dockerfile does not declare `ARG PLT_DEPLOYMENT_ID=` simply +// ignores it. +export function deployBuildArgs (version) { + return version ? { PLT_DEPLOYMENT_ID: version } : {} +} + export function imageName (image) { return image.split('/').at(-1).split('@')[0].split(':')[0] } @@ -91,7 +108,9 @@ export default async function cli (argv) { } const isWorkflow = detectWorkflow(dockerfile, envVars) - if (directory) await registry.buildFromDirectory(directory, appImage, { npmrc: args.npmrc }) + + const buildArgs = deployBuildArgs(args.version) + if (directory) await registry.buildFromDirectory(directory, appImage, { npmrc: args.npmrc, buildArgs }) const clusterStatus = await getClusterStatus({ context }) if (clusterStatus.kafka?.connectionString) { diff --git a/profiles/development.yaml b/profiles/development.yaml index 0c153d1..298f432 100644 --- a/profiles/development.yaml +++ b/profiles/development.yaml @@ -59,6 +59,7 @@ platformatic: check_interval_ms: 10000 # 10 seconds traffic_window_ms: 60000 # 1 min cookie_max_age: 43200 # 12h in seconds (keep default) + default_routing_mode: query # query | cookie; per-app override in ICC settings icc_jobs: enable: true diff --git a/profiles/oss.yaml b/profiles/oss.yaml index 9473571..f4d6600 100644 --- a/profiles/oss.yaml +++ b/profiles/oss.yaml @@ -69,6 +69,7 @@ platformatic: check_interval_ms: 10000 # 10 seconds traffic_window_ms: 30000 # 30 seconds for e2e testing cookie_max_age: 43200 # 12h in seconds (keep default) + default_routing_mode: query # query | cookie; per-app override in ICC settings icc_jobs: enable: true diff --git a/profiles/skew-protection.yaml b/profiles/skew-protection.yaml index c27dc5a..00140da 100644 --- a/profiles/skew-protection.yaml +++ b/profiles/skew-protection.yaml @@ -57,6 +57,7 @@ platformatic: check_interval_ms: 10000 # 10 seconds traffic_window_ms: 60000 # 1 min cookie_max_age: 43200 # 12h in seconds (keep default) + default_routing_mode: query # query | cookie; per-app override in ICC settings icc_jobs: enable: true diff --git a/tests/deploy.test.js b/tests/deploy.test.js index db333ac..8dc0fae 100644 --- a/tests/deploy.test.js +++ b/tests/deploy.test.js @@ -4,7 +4,7 @@ import { mkdtemp, readFile, rm } from 'node:fs/promises' import { join } from 'node:path' import { tmpdir } from 'node:os' import { createDeployment } from '../lib/deploy.js' -import { imageName } from '../cli/deploy.js' +import { imageName, deployBuildArgs } from '../cli/deploy.js' test('imageName handles registry ports, tags, and digests', () => { assert.equal(imageName('localhost:5000/orders:v2'), 'orders') @@ -49,3 +49,21 @@ test('workflow deployment has authoritative world metadata', async () => { await rm(runDir, { recursive: true, force: true }) } }) + +test('--version reaches the image build as PLT_DEPLOYMENT_ID', () => { + // The value has to land in three places at once: the build arg (so the client + // assets carry ?dpl=), the plt.dev/version label, and therefore the + // gateway's match key. This covers the build-arg half; the label half is + // asserted by the createDeployment tests above. + assert.deepEqual(deployBuildArgs('v2'), { PLT_DEPLOYMENT_ID: 'v2' }) + assert.deepEqual(deployBuildArgs('a1b2c3d4e5f6'), { PLT_DEPLOYMENT_ID: 'a1b2c3d4e5f6' }) +}) + +test('a deploy without --version passes no build args', () => { + // Unversioned deploys must build exactly as before. Passing an empty + // PLT_DEPLOYMENT_ID would make the framework hooks stamp `?dpl=` on every + // asset URL, which matches nothing. + assert.deepEqual(deployBuildArgs(undefined), {}) + assert.deepEqual(deployBuildArgs(null), {}) + assert.deepEqual(deployBuildArgs(''), {}) +})