fix(process): normalize ports that end a sentence
Contextual port normalization refused any port followed by a period, so common log lines such as "Listening on port: 8080." or "http://localhost:8080." kept their run-specific port and equivalent captures compared as changed. Accept a sentence-ending period while still refusing a period that continues a decimal, version, or host name, and bump the committed port-normalization version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
33bf585185
commit
db98a51dd1
|
|
@ -112,8 +112,10 @@ same admitted PTY chunks rather than a second unbounded stream.
|
|||
|
||||
Port normalization recognizes explicit `port`, `tcp_port`, `udp_port`, and
|
||||
`listen` fields, URL authorities, IP endpoints, and `localhost` endpoints, with
|
||||
ports from 0 through 65535. It preserves ordinary counters, dimensions, file
|
||||
line numbers, and ambiguous bare host labels. Use explicit literal `patterns`
|
||||
ports from 0 through 65535. A port may end a sentence, as in `port: 8080.`;
|
||||
a period followed by a letter or digit continues a decimal, version, or host
|
||||
name instead. It preserves ordinary counters, dimensions, file line numbers,
|
||||
and ambiguous bare host labels. Use explicit literal `patterns`
|
||||
for a different application-specific spelling. Set `ports: false` to preserve
|
||||
all endpoint numbers in comparison text. Captures commit the port-normalization
|
||||
version so older broad numeric normalization cannot silently compare as the
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ export const processComparisonContract = (
|
|||
limits: scenario.limits,
|
||||
normalization: scenario.normalization,
|
||||
...(scenario.normalization.ports
|
||||
? { port_normalization_version: "contextual-endpoints-v1" }
|
||||
? { port_normalization_version: "contextual-endpoints-v2" }
|
||||
: {}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,25 @@ it("normalizes only contextual ports before overlapping PID values and honors di
|
|||
).toBe(input);
|
||||
});
|
||||
|
||||
it("normalizes ports that end a sentence but not decimal or host continuations", () => {
|
||||
const input = [
|
||||
"Listening on port: 8080.",
|
||||
"Server at http://localhost:8080. Ready",
|
||||
"Bound [::1]:3000.",
|
||||
"listen=9000.\n",
|
||||
"port: 80.5 localhost:8080.5 localhost:8080.example.test",
|
||||
].join("\n");
|
||||
expect(normalizeProcessText(input, scenario({}), "/temporary", rootPid)).toBe(
|
||||
[
|
||||
"Listening on port: <port>.",
|
||||
"Server at http://localhost:<port>. Ready",
|
||||
"Bound [::1]:<port>.",
|
||||
"listen=<port>.\n",
|
||||
"port: 80.5 localhost:8080.5 localhost:8080.example.test",
|
||||
].join("\n"),
|
||||
);
|
||||
});
|
||||
|
||||
it("normalizes representative process identities and preserves null, zero, and unrelated numbers", () => {
|
||||
const before = JSON.stringify(samples);
|
||||
const normalized = normalizeProcessSamples(samples, scenario({}), rootPid);
|
||||
|
|
|
|||
|
|
@ -41,9 +41,11 @@ export const normalizeProcessText = (
|
|||
return normalized;
|
||||
};
|
||||
|
||||
// A port may end a sentence, but a period followed by a word character
|
||||
// continues a decimal, version, or host name and is not a port boundary.
|
||||
const normalizePortTokens = (value: string): string => {
|
||||
const endpointNormalized = value.replaceAll(
|
||||
/(\b[a-z][a-z0-9+.-]*:\/\/[^\s/?#"'<>]+|\blocalhost|\b(?:\d{1,3}\.){3}\d{1,3}|\[[\da-f:.%]+\]):(\d{1,5})(?![\w.@:])/giu,
|
||||
/(\b[a-z][a-z0-9+.-]*:\/\/[^\s/?#"'<>]+|\blocalhost|\b(?:\d{1,3}\.){3}\d{1,3}|\[[\da-f:.%]+\]):(\d{1,5})(?![\w@:]|\.\w)/giu,
|
||||
(match: string, endpoint: string, port: string) => {
|
||||
if (Number(port) > 65_535) return match;
|
||||
const isEndpoint = endpoint.includes("://")
|
||||
|
|
@ -54,7 +56,7 @@ const normalizePortTokens = (value: string): string => {
|
|||
},
|
||||
);
|
||||
return endpointNormalized.replaceAll(
|
||||
/(\b(?:port|tcp_port|udp_port|listen)\b["']?\s*[:=]\s*)(\d{1,5})(?![\w.])/giu,
|
||||
/(\b(?:port|tcp_port|udp_port|listen)\b["']?\s*[:=]\s*)(\d{1,5})(?!\w|\.\w)/giu,
|
||||
(match: string, prefix: string, port: string) =>
|
||||
Number(port) <= 65_535 ? `${prefix}<port>` : match,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ itWithCaptureCapability(
|
|||
),
|
||||
).toBe(true);
|
||||
expect(capture.manifest.comparison_contract).toMatchObject({
|
||||
port_normalization_version: "contextual-endpoints-v1",
|
||||
port_normalization_version: "contextual-endpoints-v2",
|
||||
});
|
||||
expect(capture.exit).toMatchObject({ code: 0, reason: "exited" });
|
||||
expect(capture.cleanup).toMatchObject({
|
||||
|
|
|
|||
Loading…
Reference in New Issue