Skip to content

[HYPERSHELL-259] feat: reconcile gateway version for CLI installation - #210

Open
jsell-rh wants to merge 9 commits into
mainfrom
feature/gateway-version-install
Open

[HYPERSHELL-259] feat: reconcile gateway version for CLI installation#210
jsell-rh wants to merge 9 commits into
mainfrom
feature/gateway-version-install

Conversation

@jsell-rh

@jsell-rh jsell-rh commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Jira: HYPERSHELL-259

Summary

  • Read the runtime version from each ready gateway through its internal health endpoint.
  • Reconcile a dedicated ClusterIP Service and a controller-only NetworkPolicy for health access.
  • Store the complete reported value in the read-only gateway_version API field through an atomic field-owned write.
  • Use an initial list, periodic resync, four bounded workers, and one serial pass for each gateway.
  • Add bounded timeouts, reject redirects, and repair drift in the owned health-access resources.
  • Build the OpenShell installation command without an installed OpenShell CLI or jq.
  • Remove the first - and all following text from the installer version. For example, use v0.0.109 when the gateway reports v0.0.109-rh9a8f8.
  • Keep the full reported version in the API and keep the installer URL on the NVIDIA OpenShell main branch.
  • Poll for a missing reconciled version for a bounded period and remove duplicate installation text.

Validation

  • make check
  • go test ./... in components/control-plane
  • go test -race ./internal/gateway ./internal/reconciler in components/control-plane
  • go test ./... in components/sdk-go
  • pnpm --filter @openshift-online/hypershell-gateway-management-ui check
  • pnpm --filter @openshift-online/hypershell-sdk check
  • Full web console checks, production build, and Storybook build
  • API server and control-plane lint checks
  • Base and OpenShift Kustomize render checks

The API integration harness currently stops before the tests because its shared migration setup reports pq: got 2 parameters but the statement requires 1. The focused API compile check and an isolated PostgreSQL test for the guarded version update pass.

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: d32125e8-5f4c-41d8-9563-9a44725aba9b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@jsell-rh jsell-rh changed the title feat(web-console): add gateway-matched CLI installation [HYPERSHELL-259] feat(web-console): add gateway-matched CLI installation Aug 26, 2026
@jsell-rh
jsell-rh added this pull request to the merge queue Aug 27, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 27, 2026
@jsell-rh

jsell-rh commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Amber review

Status: Complete

Verdict

This is a clean, well-tested web-console change that adds a gateway-version-matched OpenShell CLI install command, reorders the Connection tab so installation precedes the combined registration + provider block, and removes the service-account shortcut - all reflected in the spec and covered by additive tests. I recommend it for merge after two Minor cleanups; the main action item is cross-PR coordination with #208, which restructures the same Connection tab and still consumes the pre-rename EditableCommand/buildSetupScript API this PR replaces.

Amber Analysis

The refactor of EditableCommand -> CommandBlock (making marker/label/value props optional so a static command can reuse the same highlighted, copyable block) is a good consolidation, and the user-supplied endpoint is correctly passed through shellArgument() before it lands in the generated command (with a test that injects a space). Test diff scrutiny came back clean: the modified assertions track real behavior changes (prereq copy, step ordering, service-account link removal) and are all mirrored in the spec and PR description, not silent contract removals - and the endpoint-undefined readiness case that moved out of gateway-connection-steps.test.tsx is still covered by the unit test in gateway-connections.test.ts.

Findings

[Minor] Translator description contradicts the rendered order - Content / i18n
connectionInstallPrereq's description says the note is "shown after gateway registration and before provider setup" (messages.ts:102, en.json:156), but the component renders the prerequisite alert (and its install command) before the combined registration+provider block, and the test asserts exactly that (installationIndex < registrationIndex). The description gives translators the wrong placement context; align it with the actual "before the one-time setup commands" order the spec mandates.

[Minor] install.sh is fetched from main while the CLI version is pinned - Supply chain (Confidence: Low)
buildOpenShellInstallCommand pins OPENSHELL_VERSION to the gateway's reported version but pulls the installer itself from .../NVIDIA/OpenShell/main/install.sh (gateway-connections.ts:80-81,104). A future breaking change to install.sh on main could desync from the pinned version. This matches the command verbatim added to architecture.spec.md in this same PR, so it is intentional - flagging only so maintainers consciously accept pulling the installer from an unpinned ref.

Cross-PR coordination

I reviewed the other open PRs in openshift-online/hypershell (#216, #214, #212, #211, #209, #208, #207, #206, #201, #200, #194, #189, #188, #185, #182, #179, #151, #150, #148, #135, #109, #75, #73). One material conflict:

No material conflict with the other open PRs. The dashboard PRs (#209/#214) and the deps/i18n PRs touch locales/en.json/messages.ts only additively (no competing design), #206 (hsctl login) is a separate Go CLI and does not compete with this UI's "register the gateway" copy change, and #216 (OpenShift Route console) changes how the control plane publishes the gateway endpoint but keeps the same endpoint field this UI consumes.

Findings Summary (ordered by severity, highest first)

  1. [Minor] Translator description for connectionInstallPrereq says "after gateway registration" but the alert renders before registration - Content / i18n (messages.ts L102, en.json L156)
  2. [Minor] Installer pulled from NVIDIA/OpenShell/main/install.sh (unpinned) while CLI version is pinned - Supply chain (gateway-connections.ts L80-81, L104)

Convention Checklist

Convention Result
Input validated / shell arguments quoted Pass
No secrets in logs or responses Pass
Reuse shared/PatternFly UI components (no duplicate component) Pass
Config separate from code (i18n messages, URLs) Pass
Test Diff Scrutiny (modified assertions justified, no hidden contract removal) Pass
Spec updated to match behavior Pass
Conventional commit messages Pass

@jsell-rh jsell-rh left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

This is a clean, well-tested web-console change that adds a gateway-version-matched OpenShell CLI install command, reorders the Connection tab so installation precedes the combined registration + provider block, and removes the service-account shortcut - all reflected in the spec and covered by additive tests. I recommend it for merge after two Minor cleanups; the main action item is cross-PR coordination with #208, which restructures the same Connection tab and still consumes the pre-rename EditableCommand/buildSetupScript API this PR replaces.

Amber Analysis

The refactor of EditableCommand -> CommandBlock (making marker/label/value props optional so a static command can reuse the same highlighted, copyable block) is a good consolidation, and the user-supplied endpoint is correctly passed through shellArgument() before it lands in the generated command (with a test that injects a space). Test diff scrutiny came back clean: the modified assertions track real behavior changes (prereq copy, step ordering, service-account link removal) and are all mirrored in the spec and PR description, not silent contract removals - and the endpoint-undefined readiness case that moved out of gateway-connection-steps.test.tsx is still covered by the unit test in gateway-connections.test.ts.

Findings

[Minor] Translator description contradicts the rendered order - Content / i18n
connectionInstallPrereq's description says the note is "shown after gateway registration and before provider setup" (messages.ts:102, en.json:156), but the component renders the prerequisite alert (and its install command) before the combined registration+provider block, and the test asserts exactly that (installationIndex < registrationIndex). The description gives translators the wrong placement context; align it with the actual "before the one-time setup commands" order the spec mandates.

[Minor] install.sh is fetched from main while the CLI version is pinned - Supply chain (Confidence: Low)
buildOpenShellInstallCommand pins OPENSHELL_VERSION to the gateway's reported version but pulls the installer itself from .../NVIDIA/OpenShell/main/install.sh (gateway-connections.ts:80-81,104). A future breaking change to install.sh on main could desync from the pinned version. This matches the command verbatim added to architecture.spec.md in this same PR, so it is intentional - flagging only so maintainers consciously accept pulling the installer from an unpinned ref.

Cross-PR coordination

I reviewed the other open PRs in openshift-online/hypershell (#216, #214, #212, #211, #209, #208, #207, #206, #201, #200, #194, #189, #188, #185, #182, #179, #151, #150, #148, #135, #109, #75, #73). One material conflict:

  • #208 "[HYPERSHELL-129] feat(web-console): Adding section to gateway UI with instructions for sandbox connecting" - This is a genuine design/interface conflict, not just a file-merge overlap. Both PRs restructure the same Connection tab and edit the same shared files (editable-command.tsx, gateway-connection-steps.tsx, gateway-connections.ts, gateway-connection-steps.test.tsx, gateway-connections.test.ts, messages.ts, locales/en.json). Critically, #210 renames the shared exports EditableCommand -> CommandBlock and buildSetupScript -> buildOneTimeSetupScript, while #208 still imports and uses the old EditableCommand and buildSetupScript to add its "Connect to a sandbox" step. Whichever merges first, the other must rebase onto the renamed component API and the reordered step layout - and both are inserting/reordering children inside the same GatewayConnectionSteps step list. Maintainers should decide a merge order and have the later PR adopt this PR's CommandBlock/buildOneTimeSetupScript API rather than reintroducing the old names.

No material conflict with the other open PRs. The dashboard PRs (#209/#214) and the deps/i18n PRs touch locales/en.json/messages.ts only additively (no competing design), #206 (hsctl login) is a separate Go CLI and does not compete with this UI's "register the gateway" copy change, and #216 (OpenShift Route console) changes how the control plane publishes the gateway endpoint but keeps the same endpoint field this UI consumes.

Findings Summary (ordered by severity, highest first)

  1. [Minor] Translator description for connectionInstallPrereq says "after gateway registration" but the alert renders before registration - Content / i18n (messages.ts L102, en.json L156)
  2. [Minor] Installer pulled from NVIDIA/OpenShell/main/install.sh (unpinned) while CLI version is pinned - Supply chain (gateway-connections.ts L80-81, L104)

Convention Checklist

Convention Result
Input validated / shell arguments quoted Pass
No secrets in logs or responses Pass
Reuse shared/PatternFly UI components (no duplicate component) Pass
Config separate from code (i18n messages, URLs) Pass
Test Diff Scrutiny (modified assertions justified, no hidden contract removal) Pass
Spec updated to match behavior Pass
Conventional commit messages Pass

Comment thread packages/gateway-management-ui/src/messages.ts Outdated
Comment thread packages/gateway-management-ui/src/gateways/gateway-connections.ts
@jsell-rh

jsell-rh commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Amber review: comment

Amber review

Status: Complete

Verdict

This is a clean, well-scoped web-console change: the version-matched OpenShell install command is shell-escaped, the spec and i18n catalog are updated in lockstep, and the tests exercise ordering, copy behaviour, and the not-ready gating. My only substantive questions are about the install command's own bootstrapping assumptions and one cross-PR coordination point on the shared connection-tab components.

Highlights

  • buildOpenShellInstallCommand reuses shellArgument() so the endpoint is single-quoted when it contains anything outside the safe charset, and the command substitution re-tokenizes correctly. Injection surface is covered by the "quotes the gateway endpoint" test.
  • Readiness gating is consistent: both the install command and the setup script return undefined unless phase === "Running" and an endpoint exists, and the UI renders nothing rather than a partial command.
  • Test-diff scrutiny: the renamed "hides the installation prerequisite until the gateway is ready" test now keeps endpoint populated while phase is Provisioning. This is a stronger assertion (matches the spec's "give a Provisioning gateway an endpoint" case), and the endpoint-absent path is still covered in gateway-connections.test.ts, so no guarantee was dropped.

Findings

[Minor] Install command depends on openshell (and jq) already being present. The command computes OPENSHELL_GATEWAY_VERSION by invoking openshell ... status | jq -r '.version' — i.e. it requires the CLI it is meant to install, plus an undocumented jq dependency. The alert is titled "Prerequisite" and the copy says "Install the OpenShell CLI version for this gateway," which reads as first-install guidance to a user who has no CLI yet. If the intent is "re-install / pin to the gateway's version for someone who already has openshell," a one-line clarification in the prerequisite text (and/or noting the jq requirement) would prevent a confusing failure. Please confirm the assumed starting state. (gateway-connections.ts) Confidence: Medium.

[Minor] Duplicated instruction text. connectionInstallPrereq and connectionSetupDescription both now open with "Install the OpenShell CLI version for this gateway…". The repetition is harmless but slightly noisy in the rendered step; consider letting the setup description focus on the register/provider/model sequence. (messages.ts) Confidence: High.

Cross-PR coordination

Another open pull request adds a new "Connect to a sandbox" step to the same Connection tab and builds directly on the current shared exports — it renders its new command through EditableCommand and imports buildSetupScript from gateway-connections.ts. This PR renames those exact symbols (EditableCommandCommandBlock, buildSetupScriptbuildOneTimeSetupScript) and reworks the same gateway-connection-steps.tsx, its test, and the .shiki-count assertions. This is a competing interface change plus a shared-composition change, not just file overlap: whichever merges first forces the other to be rewritten against the new names and to reconcile the expected number of command blocks on the tab. Maintainers should decide a merge order and have the second PR rebase onto the renamed API (and agree on the final ordering of install / setup / create-sandbox / connect-sandbox steps). PR #208.

Convention Checklist

Convention Result
Input validated / shell arguments escaped Pass
No secrets in logs or responses Pass
Config separate from code (URLs as constants) Pass
i18n catalog matches message definitions Pass
Spec updated to match behavior Pass
Test Diff Scrutiny (no silently removed guarantees) Pass

Findings Summary (ordered by severity, highest first):

  1. [Minor] Install command assumes openshell/jq already installed while framed as a first-install prerequisite - UX / Logic (gateway-connections.ts)
  2. [Minor] Duplicated "Install the OpenShell CLI version…" text across two adjacent messages - Content (messages.ts)

@jsell-rh jsell-rh left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

This is a clean, well-scoped web-console change: the version-matched OpenShell install command is shell-escaped, the spec and i18n catalog are updated in lockstep, and the tests exercise ordering, copy behaviour, and the not-ready gating. My only substantive questions are about the install command's own bootstrapping assumptions and one cross-PR coordination point on the shared connection-tab components.

Highlights

  • buildOpenShellInstallCommand reuses shellArgument() so the endpoint is single-quoted when it contains anything outside the safe charset, and the command substitution re-tokenizes correctly. Injection surface is covered by the "quotes the gateway endpoint" test.
  • Readiness gating is consistent: both the install command and the setup script return undefined unless phase === "Running" and an endpoint exists, and the UI renders nothing rather than a partial command.
  • Test-diff scrutiny: the renamed "hides the installation prerequisite until the gateway is ready" test now keeps endpoint populated while phase is Provisioning. This is a stronger assertion (matches the spec's "give a Provisioning gateway an endpoint" case), and the endpoint-absent path is still covered in gateway-connections.test.ts, so no guarantee was dropped.

Findings

[Minor] Install command depends on openshell (and jq) already being present. The command computes OPENSHELL_GATEWAY_VERSION by invoking openshell ... status | jq -r '.version' — i.e. it requires the CLI it is meant to install, plus an undocumented jq dependency. The alert is titled "Prerequisite" and the copy says "Install the OpenShell CLI version for this gateway," which reads as first-install guidance to a user who has no CLI yet. If the intent is "re-install / pin to the gateway's version for someone who already has openshell," a one-line clarification in the prerequisite text (and/or noting the jq requirement) would prevent a confusing failure. Please confirm the assumed starting state. (gateway-connections.ts) Confidence: Medium.

[Minor] Duplicated instruction text. connectionInstallPrereq and connectionSetupDescription both now open with "Install the OpenShell CLI version for this gateway…". The repetition is harmless but slightly noisy in the rendered step; consider letting the setup description focus on the register/provider/model sequence. (messages.ts) Confidence: High.

Cross-PR coordination

Another open pull request adds a new "Connect to a sandbox" step to the same Connection tab and builds directly on the current shared exports — it renders its new command through EditableCommand and imports buildSetupScript from gateway-connections.ts. This PR renames those exact symbols (EditableCommandCommandBlock, buildSetupScriptbuildOneTimeSetupScript) and reworks the same gateway-connection-steps.tsx, its test, and the .shiki-count assertions. This is a competing interface change plus a shared-composition change, not just file overlap: whichever merges first forces the other to be rewritten against the new names and to reconcile the expected number of command blocks on the tab. Maintainers should decide a merge order and have the second PR rebase onto the renamed API (and agree on the final ordering of install / setup / create-sandbox / connect-sandbox steps). PR #208.

Convention Checklist

Convention Result
Input validated / shell arguments escaped Pass
No secrets in logs or responses Pass
Config separate from code (URLs as constants) Pass
i18n catalog matches message definitions Pass
Spec updated to match behavior Pass
Test Diff Scrutiny (no silently removed guarantees) Pass

Findings Summary (ordered by severity, highest first):

  1. [Minor] Install command assumes openshell/jq already installed while framed as a first-install prerequisite - UX / Logic (gateway-connections.ts)
  2. [Minor] Duplicated "Install the OpenShell CLI version…" text across two adjacent messages - Content (messages.ts)

Comment thread packages/gateway-management-ui/src/gateways/gateway-connections.ts Outdated
Comment thread packages/gateway-management-ui/src/messages.ts Outdated
@jsell-rh jsell-rh changed the title [HYPERSHELL-259] feat(web-console): add gateway-matched CLI installation [HYPERSHELL-259] feat: reconcile gateway version for CLI installation Aug 27, 2026
@jsell-rh

jsell-rh commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

Amber review: changes requested

Amber review

Status: Complete

Verdict

REQUEST_CHANGES

This is a well-structured, well-tested feature: the new gateway_version field is written through a dedicated atomic API path that a whole-row replace cannot clobber, health/version work is ordered and bounded, and the health Service/NetworkPolicy are reconciled with update-or-create semantics. The one blocking concern is that moving the health loop from serial to concurrent workers now shares a single Keycloak client whose token read is not fully lock-protected, which is a data race in production reconciler code.

@jsell-rh jsell-rh left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

REQUEST_CHANGES

This is a well-structured, well-tested feature: the new gateway_version field is written through a dedicated atomic API path that a whole-row replace cannot clobber, health/version work is ordered and bounded, and the health Service/NetworkPolicy are reconciled with update-or-create semantics. The one blocking concern is that moving the health loop from serial to concurrent workers now shares a single Keycloak client whose token read is not fully lock-protected, which is a data race in production reconciler code.

Findings

Major

Concurrent workers share a Keycloak client with an unsynchronized token readcomponents/control-plane/internal/reconciler/health.go

reconcileGateways (health.go:200) now fans work out across up to four concurrent workers (runGatewayWorkers), and each worker's residual-absence path can call the single shared consoleClientChecker (ConsoleClientExists). The reconciler previously ran serially, and the removed comment even said so ("The health loop is serial, so a single shared client needs no additional synchronization"). The replacement comment (health.go:72) now claims "The client protects its shared token state for concurrent use" — but that is not fully true. keycloak.Client.ensureToken writes c.token under c.mu, while doRequestRaw reads c.token to build the Authorization header outside the lock. With two workers hitting a token-refresh boundary, one worker's unlocked read of c.token races the other worker's locked write — a data race (undefined behavior) that can produce a torn/partial admin token.

The PR's -race validation did not catch this because the reconciler tests use a fake ConsoleClientChecker, so the real client's concurrency path is never exercised under the race detector.

Fix options: snapshot the token inside ensureToken and return it (so the caller never reads c.token unlocked), or guard the token read in doRequestRaw with c.mu. Either way, please correct the health.go comment so it does not assert a guarantee the client does not currently provide.

Confidence: High.

Minor

Observed version is logged without sanitizing embedded control characterscomponents/control-plane/internal/reconciler/gateway_version.go

observedVersion comes from the gateway's own /health response (a semi-trusted, potentially attacker-influenced source if a gateway is compromised) and is only strings.TrimSpaced — that trims the ends but leaves embedded \n/\r intact. It is then logged verbatim (gateway_version.go:62, plus the WARN lines). security.spec.md calls for log-injection sanitization on values that flow into logs. Consider rejecting versions containing control characters, or stripping \r/\n before logging. The length bound (128) and shellArgument quoting in the console already limit blast radius, hence Minor.

Confidence: Medium.

Cross-PR coordination

Two open pull requests have material overlap that maintainers must resolve.

  • #194 shifts gateway deployment away from static YAML manifests to the upstream OpenShell Helm chart and records an explicit "no NetworkPolicies" decision, replacing the same files and code paths this PR builds on (manifests/gateway/service.yaml, manifests/gateway/networkpolicy.yaml, internal/gateway/manifests.go, internal/gateway/reconciler.go, internal/reconciler/health.go). This PR depends on those static manifests to ship the new openshell-gateway-health Service and the controller-only openshell-gateway-allow-controller-health NetworkPolicy, and adds a CONTROL_PLANE_NAMESPACE_PLACEHOLDER substitution in that manifest path. Maintainers must decide which deployment mechanism owns the health Service, whether the controller-health NetworkPolicy survives the no-NetworkPolicies decision, how the controller reaches the gateway health port under the Helm model, and the merge order of the two efforts.

  • #208 adds a new step to the same shared GatewayConnectionSteps component and new command builders in packages/gateway-management-ui/src/gateways/gateway-connections.ts, and imports/uses the exported buildSetupScript. This PR renames that export to buildOneTimeSetupScript and restructures the same connection-steps workflow. This is a competing interface/ownership change, not just a text merge: whoever merges second must adapt to the renamed export and reconcile the competing step layout. The owners should agree on the shared component structure and a merge order.

Findings Summary (ordered by severity, highest first)

  1. [Major] Concurrent health workers share a Keycloak client whose token read is unlocked, creating a data race (and a comment that overstates the safety guarantee) - Concurrency / Control Plane (health.go:72, health.go:200)
  2. [Minor] Observed gateway version logged without control-character sanitization - Security (log injection) (gateway_version.go:62)

Convention Checklist

Convention Result
No panic() in production code Pass
Errors wrapped with fmt.Errorf context Pass
errors.IsNotFound handled for 404 scenarios Pass
No secrets in logs or responses Pass
Input validated Pass
Log injection prevented Fail
SecurityContext on new pod specs N/A (no new pod specs)
Reconcile (update-or-create) pattern used Pass
Status/owned-field updates on error paths Pass
Proper context propagation (bounded timeouts, stream ctx) Pass
Concurrency safety of shared state Fail
Image references consistent across manifests Pass
OpenAPI/proto client generated, not hand-edited Pass
DB migration registered + nullable/back-compatible Pass
Test Diff Scrutiny (no silently flipped assertions) Pass


// consoleClientChecker is one long-lived Keycloak client for residual-absence
// checks. It keeps its token cache between passes. It is nil when Keycloak is
// not configured. The client protects its shared token state for concurrent

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Major] Concurrency: shared Keycloak client token read is not lock-protected.

This comment now asserts the console client "protects its shared token state for concurrent use," but with the switch to bounded concurrent workers (reconcileGateways/runGatewayWorkers) that guarantee does not hold. keycloak.Client.ensureToken writes c.token under c.mu, while doRequestRaw reads c.token to build the Authorization header outside the lock. Two workers hitting a token-refresh boundary race read-vs-write on c.token (undefined behavior).

The reconciler was previously serial (the prior comment said as much). Please either snapshot the token inside ensureToken and return it, or guard the token read in doRequestRaw with c.mu, and correct this comment. Note the -race run did not exercise this because the tests use a fake ConsoleClientChecker.

log.Printf("WARN gateway version: store runtime version for %s: %v", gatewayID, err)
return
}
log.Printf("INFO gateway version: %s runtime version set to %s", gatewayID, observedVersion)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor] Log injection: sanitize the observed version before logging.

observedVersion comes from the gateway /health response and is only strings.TrimSpaced, so embedded \r/\n survive and are logged verbatim here (and in the WARN lines above). security.spec.md calls for log-injection sanitization on externally-sourced values. Consider rejecting versions containing control characters, or stripping \r/\n before logging.

@JuanmaBM

Copy link
Copy Markdown
Collaborator

Follow-up stacked on this PR: #219 makes the e2e test install the openshell CLI via the console-recommended command, deriving the version from the gateway_version field added here (instead of a hardcoded pin). It's based on this branch and should merge after this one lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants