Add CI stress metrics artifacts and optional Pushgateway export#58
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Reviewer's GuideAdds a new stress metrics collection/publish script, wires it into the Linux QA workflow to generate artifacts and optionally push Prometheus metrics to a Pushgateway, documents how to run and consume the outputs, and tightens SonarCloud configuration with explicit CPD exclusions. Sequence diagram for CI stress metrics publish to PushgatewaysequenceDiagram
participant GitHubRunner
participant Npm as npm_cli
participant Script as publish_stress_metrics_js
participant FS as FileSystem
participant PushGW as Pushgateway
GitHubRunner->>Npm: npm run stress:metrics
Npm->>Script: node scripts/publish-stress-metrics.js
Script->>FS: read benchmark JSON files from dist/benchmarks
FS-->>Script: JSON contents and file stats
Script->>Script: normalize records and build summary
Script->>FS: write summary.json
Script->>Script: build Prometheus metrics payload
Script->>FS: write stress-metrics.prom
Script->>Script: check PUSHGATEWAY_URL env
alt PUSHGATEWAY_URL not set
Script-->>GitHubRunner: log skipping Pushgateway publish
else PUSHGATEWAY_URL set
Script->>PushGW: HTTP PUT metrics with job and instance labels
alt HTTP 2xx
PushGW-->>Script: success status
Script-->>GitHubRunner: log successful push
else non-2xx or network error
Script->>Script: check PUSHGATEWAY_STRICT
alt strict mode
Script-->>GitHubRunner: log failure and exit 1
else non-strict mode
Script-->>GitHubRunner: warn but exit 0
end
end
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Review Summary by QodoAdd stress metrics reporting and optional Pushgateway integration
WalkthroughsDescription• Add stress metrics reporting script with Prometheus format export • Integrate optional Pushgateway publishing for CI metrics tracking • Wire stress metrics task into QA workflow on Linux runners • Upload benchmark artifacts and document stress testing outputs • Add explicit SonarCloud CPD exclusions for consistency Diagramflowchart LR
A["Benchmark JSON Files"] -->|normalizeBenchmarkRecord| B["Normalized Records"]
B -->|buildPrometheusPayload| C["Prometheus Metrics"]
C -->|Write Files| D["summary.json<br/>stress-metrics.prom"]
C -->|Optional Push| E["Pushgateway"]
D -->|Upload| F["CI Artifacts"]
File Changes1. scripts/publish-stress-metrics.js
|
Summary of ChangesHello @Mehdi-Bl, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the project's continuous integration capabilities by introducing automated collection and reporting of stress test metrics. It provides a structured way to process benchmark results, generate Prometheus-compatible metrics, and optionally push them to a Pushgateway for external monitoring. This integration aims to provide better visibility into application performance and stability over time within the CI pipeline. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
📝 WalkthroughWalkthroughThis change introduces a stress benchmark metrics workflow that aggregates benchmark results, publishes them in Prometheus format, and optionally pushes to a Pushgateway. It adds CI steps, an npm script, a new metrics aggregation script, and documentation updates to enable stress test monitoring. Changes
Sequence DiagramsequenceDiagram
participant CI as GitHub Actions<br/>(qa-matrix)
participant FS as File System<br/>(dist/benchmarks)
participant Script as publish-stress-metrics.js
participant PG as Pushgateway<br/>(optional)
CI->>FS: Stress tests complete,<br/>write JSON files
CI->>Script: npm run stress:metrics
Script->>FS: Read benchmark JSON files
Script->>Script: Normalize records<br/>(p50, p95, p99, etc.)
Script->>Script: Build summary payload<br/>& Prometheus format
Script->>FS: Write summary.json<br/>& stress-metrics.prom
alt PUSHGATEWAY_URL configured
Script->>PG: POST metrics payload<br/>(with job/instance labels)
PG-->>Script: Success or error response
alt Strict mode
Script->>Script: Throw on error
else Warning mode
Script->>Script: Log warning, continue
end
else No Pushgateway
Script->>Script: Skip push
end
Script->>CI: Complete, log output paths
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The
pushToPushgatewayHTTP(S) request currently has no timeout, so a slow or unresponsive Pushgateway could stall the CI job; consider adding a reasonable request timeout or abort mechanism, ideally configurable via env. - In
readBenchmarkFiles/normalizeBenchmarkRecord, a single malformed or partially written JSON file will cause the whole script to fail; you may want to catch and log per-file parse errors and skip those files so metrics generation is more robust.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `pushToPushgateway` HTTP(S) request currently has no timeout, so a slow or unresponsive Pushgateway could stall the CI job; consider adding a reasonable request timeout or abort mechanism, ideally configurable via env.
- In `readBenchmarkFiles`/`normalizeBenchmarkRecord`, a single malformed or partially written JSON file will cause the whole script to fail; you may want to catch and log per-file parse errors and skip those files so metrics generation is more robust.
## Individual Comments
### Comment 1
<location> `scripts/publish-stress-metrics.js:182-191` </location>
<code_context>
+function pushToPushgateway(endpointUrl, payload) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The Pushgateway HTTP request has no timeout, which can hang the process if the endpoint is slow or unresponsive.
Relying on default socket behavior means a slow or misbehaving Pushgateway can leave the CI job hanging until an external timeout intervenes. Please add an explicit request timeout (for example, via `request.setTimeout(...)` that rejects on timeout) so failures are bounded and predictable in the CI context.
Suggested implementation:
```javascript
function pushToPushgateway(endpointUrl, payload) {
return new Promise((resolve, reject) => {
const client = endpointUrl.protocol === 'https:' ? https : http;
const REQUEST_TIMEOUT_MS = 10_000;
const request = client.request(
endpointUrl,
{
method: 'PUT',
timeout: REQUEST_TIMEOUT_MS,
headers: {
'Content-Length': Buffer.byteLength(payload),
'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
```
To fully implement the explicit timeout behavior so that the promise rejects instead of just emitting a `timeout` event, you should also:
1. Add a `request.on('timeout', ...)` handler after the `client.request(...)` call that:
- Calls `request.destroy(new Error('Request to Pushgateway timed out'))` (or similar).
- Ensures the promise is rejected exactly once (e.g. via a small `let settled = false;` guard shared with the existing `error`/`response` handlers if present).
2. Ensure any existing `request.on('error', ...)` handler will surface the timeout error by rejecting the promise.
Place the `request.on('timeout', ...)` alongside the existing `request.on('error', ...)` / response handlers within `pushToPushgateway`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| function pushToPushgateway(endpointUrl, payload) { | ||
| return new Promise((resolve, reject) => { | ||
| const client = endpointUrl.protocol === 'https:' ? https : http; | ||
|
|
||
| const request = client.request( | ||
| endpointUrl, | ||
| { | ||
| method: 'PUT', | ||
| headers: { | ||
| 'Content-Length': Buffer.byteLength(payload), |
There was a problem hiding this comment.
suggestion (bug_risk): The Pushgateway HTTP request has no timeout, which can hang the process if the endpoint is slow or unresponsive.
Relying on default socket behavior means a slow or misbehaving Pushgateway can leave the CI job hanging until an external timeout intervenes. Please add an explicit request timeout (for example, via request.setTimeout(...) that rejects on timeout) so failures are bounded and predictable in the CI context.
Suggested implementation:
function pushToPushgateway(endpointUrl, payload) {
return new Promise((resolve, reject) => {
const client = endpointUrl.protocol === 'https:' ? https : http;
const REQUEST_TIMEOUT_MS = 10_000;
const request = client.request(
endpointUrl,
{
method: 'PUT',
timeout: REQUEST_TIMEOUT_MS,
headers: {
'Content-Length': Buffer.byteLength(payload),
'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',To fully implement the explicit timeout behavior so that the promise rejects instead of just emitting a timeout event, you should also:
- Add a
request.on('timeout', ...)handler after theclient.request(...)call that:- Calls
request.destroy(new Error('Request to Pushgateway timed out'))(or similar). - Ensures the promise is rejected exactly once (e.g. via a small
let settled = false;guard shared with the existingerror/responsehandlers if present).
- Calls
- Ensure any existing
request.on('error', ...)handler will surface the timeout error by rejecting the promise.
Place the request.on('timeout', ...) alongside the existing request.on('error', ...) / response handlers within pushToPushgateway.
There was a problem hiding this comment.
Code Review
This pull request introduces a new script for processing stress test benchmark results, generating a summary and Prometheus metrics, and optionally publishing them to a Pushgateway. The implementation is robust and well-structured. I've provided a couple of suggestions to refactor the new script to reduce some code duplication, which would improve its long-term maintainability. The accompanying changes to package.json and documentation are correct and complete.
| const runs = Array.isArray(parsed.runs) | ||
| ? parsed.runs.map((value) => toFiniteNumber(value)).filter((value) => value !== null) | ||
| : []; | ||
| const lagSamplesMs = Array.isArray(parsed.lagSamplesMs) | ||
| ? parsed.lagSamplesMs.map((value) => toFiniteNumber(value)).filter((value) => value !== null) | ||
| : []; |
There was a problem hiding this comment.
The logic for parsing and filtering numeric arrays from parsed.runs and parsed.lagSamplesMs is duplicated. This can be extracted into a helper function to improve readability and reduce code duplication. For example, you could define a helper and use it like this:
const getNumericArray = (data) =>
Array.isArray(data)
? data.map(toFiniteNumber).filter((v) => v !== null)
: [];
const runs = getNumericArray(parsed.runs);
const lagSamplesMs = getNumericArray(parsed.lagSamplesMs);| lines.push(`# HELP ${METRIC_PREFIX}_sample_count Number of sampled points for each scenario.`); | ||
| lines.push(`# TYPE ${METRIC_PREFIX}_sample_count gauge`); | ||
|
|
||
| for (const record of records) { | ||
| const line = toMetricLine(`${METRIC_PREFIX}_sample_count`, record.sampleCount, { | ||
| scenario: record.scenario, | ||
| }); | ||
| if (line) { | ||
| lines.push(line); | ||
| } | ||
| } | ||
|
|
||
| lines.push(`# HELP ${METRIC_PREFIX}_file_count Number of files exercised by the stress scenario.`); | ||
| lines.push(`# TYPE ${METRIC_PREFIX}_file_count gauge`); | ||
|
|
||
| for (const record of records) { | ||
| const line = toMetricLine(`${METRIC_PREFIX}_file_count`, record.fileCount, { | ||
| scenario: record.scenario, | ||
| }); | ||
| if (line) { | ||
| lines.push(line); | ||
| } | ||
| } | ||
|
|
||
| lines.push(`# HELP ${METRIC_PREFIX}_iterations Number of iterations executed by the scenario.`); | ||
| lines.push(`# TYPE ${METRIC_PREFIX}_iterations gauge`); | ||
|
|
||
| for (const record of records) { | ||
| const line = toMetricLine(`${METRIC_PREFIX}_iterations`, record.iterations, { | ||
| scenario: record.scenario, | ||
| }); | ||
| if (line) { | ||
| lines.push(line); | ||
| } | ||
| } |
There was a problem hiding this comment.
There's significant code duplication in how gauge metrics for sample_count, file_count, and iterations are generated. This can be refactored by iterating over a configuration array to build these metrics, which will make the code more concise and easier to maintain.
const gaugeMetrics = [
{ name: 'sample_count', help: 'Number of sampled points for each scenario.', key: 'sampleCount' },
{ name: 'file_count', help: 'Number of files exercised by the stress scenario.', key: 'fileCount' },
{ name: 'iterations', help: 'Number of iterations executed by the scenario.', key: 'iterations' },
];
for (const { name, help, key } of gaugeMetrics) {
lines.push(`# HELP ${METRIC_PREFIX}_${name} ${help}`);
lines.push(`# TYPE ${METRIC_PREFIX}_${name} gauge`);
for (const record of records) {
const line = toMetricLine(`${METRIC_PREFIX}_${name}`, record[key], {
scenario: record.scenario,
});
if (line) {
lines.push(line);
}
}
}
|
Code Review by Qodo
1. pushEndpoint logged with secret
|
| const pushgatewayUrl = (process.env.PUSHGATEWAY_URL || '').trim(); | ||
| if (!pushgatewayUrl) { | ||
| console.log('PUSHGATEWAY_URL not set; skipping pushgateway publish.'); | ||
| return; | ||
| } | ||
|
|
||
| const defaultInstance = | ||
| [process.env.GITHUB_RUN_ID, process.env.GITHUB_RUN_ATTEMPT, process.env.RUNNER_OS] | ||
| .filter((segment) => typeof segment === 'string' && segment.length > 0) | ||
| .join('-') || os.hostname(); | ||
|
|
||
| const jobName = (process.env.PUSHGATEWAY_JOB || 'ai_code_fusion_stress').trim(); | ||
| const instanceName = (process.env.PUSHGATEWAY_INSTANCE || defaultInstance).trim(); | ||
| const strictMode = process.env.PUSHGATEWAY_STRICT === 'true'; | ||
|
|
||
| const pushEndpoint = buildPushgatewayUrl(pushgatewayUrl, jobName, instanceName); | ||
| try { | ||
| await pushToPushgateway(pushEndpoint, prometheusPayload); | ||
| console.log(`Stress metrics pushed to Pushgateway: ${pushEndpoint.toString()}`); | ||
| } catch (error) { |
There was a problem hiding this comment.
1. pushendpoint logged with secret 📘 Rule violation ⛨ Security
The script logs pushEndpoint.toString() which is derived from PUSHGATEWAY_URL (a secret in CI) and can leak credentials if the URL contains embedded auth or sensitive query params. This violates secure logging requirements by potentially exposing secrets in CI logs.
Agent Prompt
## Issue description
`scripts/publish-stress-metrics.js` logs `pushEndpoint.toString()` which is derived from `PUSHGATEWAY_URL` provided via CI secrets; this can leak credentials or sensitive query parameters into CI logs.
## Issue Context
`PUSHGATEWAY_URL` is provided from GitHub Actions secrets and may contain embedded credentials (e.g., basic auth) depending on environment. Logging the full URL violates secure logging requirements.
## Fix Focus Areas
- scripts/publish-stress-metrics.js[247-266]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.github/workflows/qa-matrix.yml:
- Around line 99-108: The upload step "Upload stress benchmark artifacts"
currently runs unconditionally (if: runner.os == 'Linux' && always()) and uses
if-no-files-found: error which causes a hard fail when the stress step is
skipped or fails; change the step so it either (A) sets if-no-files-found: warn
instead of error, or (B) gate the step on the stress step succeeding by
replacing always() with the stress step outcome (e.g., check that the job step
that runs stress/metrics completed successfully) so the artifact upload only
runs when artifacts are expected (update the step condition and/or
if-no-files-found accordingly).
In `@scripts/publish-stress-metrics.js`:
- Line 274: Current console.log prints pushEndpoint.toString() which can leak
embedded credentials; update the log to print a sanitized URL instead. Locate
the console.log using the pushEndpoint variable and replace
pushEndpoint.toString() with either pushEndpoint.origin + pushEndpoint.pathname
or a redacted form that omits pushEndpoint.username and pushEndpoint.password
(e.g., build a string using pushEndpoint.protocol, host without credentials, and
pathname) so credentials are not logged. Ensure any tests or downstream messages
still receive the safe string.
- Around line 191-230: The pushToPushgateway function creates an HTTP/HTTPS
request without any socket/response timeout, so the CI can hang if the
Pushgateway accepts connections but never responds; update pushToPushgateway to
attach a timeout (e.g., using request.setTimeout or request.on('socket', s =>
s.setTimeout(...))) and on timeout abort the request and reject the promise with
a descriptive timeout Error; ensure you wire the timeout handler to call
request.destroy() or request.abort() and remove/cleanup listeners so the promise
always resolves or rejects (reference function pushToPushgateway and the local
variable request).
| - name: Upload stress benchmark artifacts | ||
| if: runner.os == 'Linux' && always() | ||
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f | ||
| with: | ||
| name: stress-benchmarks-linux | ||
| path: | | ||
| dist/benchmarks/*.json | ||
| dist/benchmarks/*.prom | ||
| if-no-files-found: error | ||
| retention-days: 14 |
There was a problem hiding this comment.
Upload will hard-fail when the stress step is skipped or fails.
If npm test (Line 41) or stress:metrics (Line 43) fails, the upload step still runs due to always(), but if-no-files-found: error will produce a second, misleading failure. Consider using warn instead, or gating the upload on the stress step's outcome.
Suggested fix
- name: Upload stress benchmark artifacts
- if: runner.os == 'Linux' && always()
+ if: runner.os == 'Linux' && success()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f
with:
name: stress-benchmarks-linux
path: |
dist/benchmarks/*.json
dist/benchmarks/*.prom
- if-no-files-found: error
+ if-no-files-found: warn
retention-days: 14📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Upload stress benchmark artifacts | |
| if: runner.os == 'Linux' && always() | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f | |
| with: | |
| name: stress-benchmarks-linux | |
| path: | | |
| dist/benchmarks/*.json | |
| dist/benchmarks/*.prom | |
| if-no-files-found: error | |
| retention-days: 14 | |
| - name: Upload stress benchmark artifacts | |
| if: runner.os == 'Linux' && success() | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f | |
| with: | |
| name: stress-benchmarks-linux | |
| path: | | |
| dist/benchmarks/*.json | |
| dist/benchmarks/*.prom | |
| if-no-files-found: warn | |
| retention-days: 14 |
🤖 Prompt for AI Agents
In @.github/workflows/qa-matrix.yml around lines 99 - 108, The upload step
"Upload stress benchmark artifacts" currently runs unconditionally (if:
runner.os == 'Linux' && always()) and uses if-no-files-found: error which causes
a hard fail when the stress step is skipped or fails; change the step so it
either (A) sets if-no-files-found: warn instead of error, or (B) gate the step
on the stress step succeeding by replacing always() with the stress step outcome
(e.g., check that the job step that runs stress/metrics completed successfully)
so the artifact upload only runs when artifacts are expected (update the step
condition and/or if-no-files-found accordingly).
| function pushToPushgateway(endpointUrl, payload) { | ||
| return new Promise((resolve, reject) => { | ||
| const client = endpointUrl.protocol === 'https:' ? https : http; | ||
|
|
||
| const request = client.request( | ||
| endpointUrl, | ||
| { | ||
| method: 'PUT', | ||
| headers: { | ||
| 'Content-Length': Buffer.byteLength(payload), | ||
| 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8', | ||
| }, | ||
| }, | ||
| (response) => { | ||
| const responseChunks = []; | ||
|
|
||
| response.on('data', (chunk) => responseChunks.push(chunk)); | ||
| response.on('end', () => { | ||
| const responseBody = Buffer.concat(responseChunks).toString('utf8').trim(); | ||
| if (response.statusCode && response.statusCode >= 200 && response.statusCode < 300) { | ||
| resolve(); | ||
| return; | ||
| } | ||
|
|
||
| reject( | ||
| new Error( | ||
| `Pushgateway returned ${response.statusCode || 'unknown status'}${ | ||
| responseBody ? `: ${responseBody}` : '' | ||
| }` | ||
| ) | ||
| ); | ||
| }); | ||
| } | ||
| ); | ||
|
|
||
| request.on('error', (error) => reject(error)); | ||
| request.write(payload); | ||
| request.end(); | ||
| }); | ||
| } |
There was a problem hiding this comment.
Missing request timeout — CI job can hang indefinitely if the Pushgateway is unresponsive.
The HTTP request has no socket or response timeout. If the Pushgateway accepts the connection but never responds, the CI runner will block until the GitHub Actions job-level timeout (typically 6 hours).
Suggested fix — add a socket timeout
const request = client.request(
endpointUrl,
{
method: 'PUT',
+ timeout: 15_000,
headers: {
'Content-Length': Buffer.byteLength(payload),
'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
},
},
(response) => {+ request.on('timeout', () => {
+ request.destroy(new Error('Pushgateway request timed out'));
+ });
request.on('error', (error) => reject(error));
request.write(payload);
request.end();🤖 Prompt for AI Agents
In `@scripts/publish-stress-metrics.js` around lines 191 - 230, The
pushToPushgateway function creates an HTTP/HTTPS request without any
socket/response timeout, so the CI can hang if the Pushgateway accepts
connections but never responds; update pushToPushgateway to attach a timeout
(e.g., using request.setTimeout or request.on('socket', s => s.setTimeout(...)))
and on timeout abort the request and reject the promise with a descriptive
timeout Error; ensure you wire the timeout handler to call request.destroy() or
request.abort() and remove/cleanup listeners so the promise always resolves or
rejects (reference function pushToPushgateway and the local variable request).
| const pushEndpoint = buildPushgatewayUrl(pushgatewayUrl, jobName, instanceName); | ||
| try { | ||
| await pushToPushgateway(pushEndpoint, prometheusPayload); | ||
| console.log(`Stress metrics pushed to Pushgateway: ${pushEndpoint.toString()}`); |
There was a problem hiding this comment.
Minor: logging the full Pushgateway URL may leak credentials embedded in the URL.
If someone sets PUSHGATEWAY_URL with basic-auth credentials (e.g. https://user:pass@gateway/), pushEndpoint.toString() will include them. Consider using pushEndpoint.origin + pushEndpoint.pathname or redacting username/password.
🤖 Prompt for AI Agents
In `@scripts/publish-stress-metrics.js` at line 274, Current console.log prints
pushEndpoint.toString() which can leak embedded credentials; update the log to
print a sanitized URL instead. Locate the console.log using the pushEndpoint
variable and replace pushEndpoint.toString() with either pushEndpoint.origin +
pushEndpoint.pathname or a redacted form that omits pushEndpoint.username and
pushEndpoint.password (e.g., build a string using pushEndpoint.protocol, host
without credentials, and pathname) so credentials are not logged. Ensure any
tests or downstream messages still receive the safe string.



Summary
scripts/publish-stress-metrics.jsto consolidate stress benchmark JSON into:dist/benchmarks/summary.jsondist/benchmarks/stress-metrics.promPUSHGATEWAY_URL(+PUSHGATEWAY_JOB,PUSHGATEWAY_INSTANCE,PUSHGATEWAY_STRICT)tests/catalog.mdValidation
npm run lintnpm test -- --runInBandnpm run stress:metricsNotes
Summary by CodeRabbit
New Features
CI/CD
Documentation