Skip to content

Commit 37e1232

Browse files
danielpaulusclaude
andcommitted
fix(ssl): carry the textResponse regex in the assertion property slot
The backend Joi schema and the go-runner (EvaluateRegExp) read the TEXT_RESPONSE extraction pattern from `property`; the `regex` field is never consulted. textResponse(pattern) previously emitted the pattern into `regex`, so it validated fine but was silently ignored at evaluation — the comparison ran against the whole serialized response document. Emit it as `property` (builder + import codegen) and pin the wire shape in tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXP63MTUyPnuc48ZWGovhR
1 parent f97166f commit 37e1232

4 files changed

Lines changed: 15 additions & 11 deletions

File tree

packages/cli/src/constructs/__tests__/ssl-assertion-codegen.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ describe('SSL Assertion Codegen', () => {
4848
input: { source: 'JSON_RESPONSE', property: '$.status', comparison: 'EQUALS', target: 'ok', regex: null },
4949
expected: 'SslAssertionBuilder.jsonResponse(\'$.status\').equals(\'ok\')\n',
5050
},
51-
// TEXT_RESPONSE emits the regex slot, not a property.
51+
// TEXT_RESPONSE carries its regex in the property slot (the backend/runner contract).
5252
{
5353
input: { source: 'TEXT_RESPONSE', property: '', comparison: 'CONTAINS', target: 'healthy', regex: null },
5454
expected: 'SslAssertionBuilder.textResponse().contains(\'healthy\')\n',
5555
},
5656
{
57-
input: { source: 'TEXT_RESPONSE', property: '', comparison: 'EQUALS', target: 'ok', regex: 'status: OK' },
58-
expected: 'SslAssertionBuilder.textResponse(\'status: OK\').equals(\'ok\')\n',
57+
input: { source: 'TEXT_RESPONSE', property: 'status: (\\w+)', comparison: 'EQUALS', target: 'ok', regex: null },
58+
expected: 'SslAssertionBuilder.textResponse(\'status: (\\\\w+)\').equals(\'ok\')\n',
5959
},
6060
]
6161
for (const test of cases) {

packages/cli/src/constructs/__tests__/ssl-assertion.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,10 @@ describe('SslAssertionBuilder', () => {
117117
expect(SslAssertionBuilder.textResponse().contains('healthy')).toMatchObject({
118118
source: 'TEXT_RESPONSE', property: '', comparison: 'CONTAINS', target: 'healthy', regex: null,
119119
})
120+
// The pattern rides in `property` — the slot the backend Joi schema and the
121+
// go-runner (EvaluateRegExp) read the TEXT_RESPONSE pattern from; `regex` is dead.
120122
expect(SslAssertionBuilder.textResponse('status: (\\w+)').equals('ok')).toMatchObject({
121-
source: 'TEXT_RESPONSE', property: '', comparison: 'EQUALS', target: 'ok', regex: 'status: (\\w+)',
123+
source: 'TEXT_RESPONSE', property: 'status: (\\w+)', comparison: 'EQUALS', target: 'ok', regex: null,
122124
})
123125
})
124126
})

packages/cli/src/constructs/ssl-assertion-codegen.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import {
88
import { isSslNumericTarget, sslPropertyValueType } from './internal/ssl-properties.js'
99
import { SslAssertion } from './ssl-assertion.js'
1010

11-
// CERTIFICATE / CONNECTION / JSON_RESPONSE address a value by property name and carry
12-
// no regex, so the property slot is emitted and the regex slot suppressed.
11+
// Every SSL source addresses its value through the property slot — CERTIFICATE /
12+
// CONNECTION use a field selector, JSON_RESPONSE a JSONPath, and TEXT_RESPONSE a
13+
// regex (the backend and runner read the TEXT_RESPONSE pattern from `property`,
14+
// not `regex`). The regex slot is never emitted.
1315
const withProperty = { hasProperty: true, hasRegex: false }
14-
// TEXT_RESPONSE carries a regex and no property.
15-
const withRegex = { hasProperty: false, hasRegex: true }
1616

1717
// The comparisons each typed helper can render. A comparison outside the set makes the
1818
// helper throw, which would abort the whole import over a single assertion, so the
@@ -71,7 +71,7 @@ export function valueForSslAssertion (genfile: GeneratedFile, assertion: SslAsse
7171
case 'JSON_RESPONSE':
7272
return valueForGeneralAssertion('SslAssertionBuilder', 'jsonResponse', assertion, withProperty)
7373
case 'TEXT_RESPONSE':
74-
return valueForGeneralAssertion('SslAssertionBuilder', 'textResponse', assertion, withRegex)
74+
return valueForGeneralAssertion('SslAssertionBuilder', 'textResponse', assertion, withProperty)
7575
case 'RESPONSE_TIME':
7676
return valueForNumericAssertion('SslAssertionBuilder', 'responseTime', assertion)
7777
default:

packages/cli/src/constructs/ssl-assertion.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,9 +501,11 @@ export class SslAssertionBuilder {
501501

502502
/**
503503
* Creates an assertion builder for a text response body.
504-
* @param regex Optional regex pattern applied to the response text before comparison.
504+
* @param regex Optional regex pattern (with a capture group) used to extract the value
505+
* to compare from the serialized response document. Carried in the assertion's
506+
* `property` field — the slot the backend and runner read the pattern from.
505507
*/
506508
static textResponse (regex?: string) {
507-
return new GeneralAssertionBuilder<SslAssertionSource>('TEXT_RESPONSE', undefined, regex)
509+
return new GeneralAssertionBuilder<SslAssertionSource>('TEXT_RESPONSE', regex)
508510
}
509511
}

0 commit comments

Comments
 (0)