Skip to content

ROSAENG-62084 | feat: Integrate Hyperfleet Platform API v2 with the ROSA CLI - #3448

Draft
gdbranco wants to merge 9 commits into
openshift:masterfrom
gdbranco:feat/rosaeng-62084
Draft

ROSAENG-62084 | feat: Integrate Hyperfleet Platform API v2 with the ROSA CLI#3448
gdbranco wants to merge 9 commits into
openshift:masterfrom
gdbranco:feat/rosaeng-62084

Conversation

@gdbranco

@gdbranco gdbranco commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

PR Summary

POC integration with hyperfleet sdk

Detailed Description of the Issue

These commits wire the ROSA CLI into the Hyperfleet Platform API v2, an alternative control plane for managing HyperShift-based clusters and node pools without going through OCM.

  1. --hyperfleet-url flag + runtime — New CLI flag that activates Hyperfleet mode and a WithHyperFleet runtime that authenticates via SigV4 to the Platform API endpoint.
  2. Cluster CRUD dispatch — create/describe/list/edit/delete cluster commands detect the flag and call the Platform API v2 instead of OCM. Includes wire mapping and transport layer.
  3. Login/whoami + unit tests — rosa login and rosa whoami populate Hyperfleet context; unit tests cover URL parsing, region extraction, roles ref helpers, and state management.
  4. Machinepool create/describe/list — Same dispatch pattern for node pool operations; derives worker instance profile from the cluster's RolesRef automatically.
  5. E2E sanity test + cleanup hardening — Full end-to-end test covering VPC/subnet/IAM/OIDC setup, cluster create/ready/nodepool/delete flow. Cleanup was hardened to handle real AWS teardown ordering: wait for EC2 instances to
    terminate, drain orphaned ENIs, delete classic ELBs and ALB/NLBs before releasing the VPC, and purge hosted zone records before deletion.

Why: Enables ROSA CLI users to manage clusters through the new Platform API v2 without OCM as an intermediary, which is the foundation for the Hyperfleet product offering.

Related Issues and PRs

ROSAENG-62084 — Hyperfleet (Platform API v2) integration in the ROSA CLI

Type of Change

  • feat - adds a new user-facing capability.
  • fix - resolves an incorrect behavior or bug.
  • docs - updates documentation only.
  • style - formatting or naming changes with no logic impact.
  • refactor - code restructuring with no behavior change.
  • test - adds or updates tests only.
  • chore - maintenance work (tooling, housekeeping, non-product code).
  • build - changes build system, packaging, or dependencies for build output.
  • ci - changes CI pipelines, jobs, or automation workflows.
  • perf - improves performance without changing intended behavior.

Developer Verification Checklist

  • Commit subject/title follows [JIRA-TICKET] | [TYPE]: <MESSAGE>.
  • PR description clearly explains both what changed and why.
  • Relevant Jira/GitHub issues and related PRs are linked.
  • make install-hooks has been run in this clone.
  • Tests were added/updated where appropriate.
  • I manually tested the change.
  • make test passes.
  • make lint passes.
  • make rosa passes.
  • Documentation or repo-local agent guidance was added/updated where appropriate.
  • Any risk, limitation, or follow-up work is documented.

Summary by CodeRabbit

  • New Features

    • Added HyperFleet support for creating, viewing, listing, editing, and deleting clusters and machine pools.
    • Added HyperFleet-only login and account information flows, including saved endpoint configuration.
    • Added structured and human-readable cluster and machine pool output.
    • Added AWS region detection, endpoint validation, and mismatch warnings.
    • Added an end-to-end HyperFleet sanity test workflow.
  • Bug Fixes

    • Improved validation and error handling for missing or unresolved resources.
    • Standardized command error messages.
    • Improved handling of invalid credentials and HyperFleet-only configurations.

…ntime

Adds Platform API v2 (hyperfleet) client support as the foundation for
routing HCP cluster and nodepool commands to the v2 SDK instead of OCM.

- pkg/hyperfleet: new package with --hyperfleet-url flag wiring,
  AWS region extraction from URL (standard + GovCloud regex),
  WarnOnMismatch helper, and IAM role/instance-profile helpers
- pkg/rosa: Runtime.WithHyperFleet() builds a hyperfleet Clientset via
  AWS SigV4 (awsconfig + STS GetCallerIdentity, no OCM login required);
  RuntimeWithHyperFleet() visitor wires it into DefaultRunner
- cmd/rosa/main.go: registers --hyperfleet-url as a persistent root flag
- test/reporter: shared FakeLogger test double (callback-based) replaces
  ad-hoc fakeReporter/mockReporter in pkg/output and cmd/verify/oc
- vendor: adds rosa-hyperfleet-api/clientset, hypershift/api, and
  related transitive dependencies
…st/edit/delete cluster

Routes rosa create/describe/list/edit/delete cluster through the Platform
API (hyperfleet) when --hyperfleet-url is supplied, bypassing the OCM
path entirely. Includes mappers from v1alpha1.Cluster to the existing
rosa describe/list output shapes, expiration support in edit, and an e2e
sanity test that exercises the full cluster lifecycle via CLI subprocesses.
Each CLI call in the e2e test now explicitly supplies --hyperfleet-url so
subprocesses enter hyperfleet mode without relying on env-var magic.
Wire --hyperfleet-url through rosa login and rosa whoami so that the
Platform API URL is persisted to config on login and displayed in whoami
output. Support hyperfleet-only login (no OCM token required) by
short-circuiting before the cfg.Armed() check so that an existing config
with expired tokens does not block the flow.

Seed the persisted URL back into the hyperfleet runtime via
PersistentPreRun in main.go so subsequent commands route correctly
without repeating the flag.

Add unit tests covering: SetURL/Reset in pkg/hyperfleet, hfClusterToMap
in describe/cluster, hyperfleet-only login path, whoami hyperfleet-only
output, and config error paths (invalid JSON, invalid JWT, missing/
non-string claims). Fix pre-existing ST1005 lint violations in
pkg/config/config.go (capitalized error strings).
…fleet fixes

- Add subnet and auto-derived IAM instance profile to node pool creation
- Show subnet in node pool describe/list output
- Add WithAWSOnly() runtime method; fix rosa whoami for hyperfleet-only mode
- Add InstanceProfileFromRolesRef and ComputeInstanceProfile helpers
- Fix e2e cleanup ordering: hoist IAM/OIDC DeferCleanup before cluster
  delete so they run after cluster is fully gone (LIFO); add ENI drain
  and EC2 instance termination wait before VPC resource teardown
- Hoist IAM/OIDC DeferCleanup registrations before cluster delete so
  roles and OIDC provider are cleaned up after cluster is gone
- Wait for worker EC2 instances to terminate before releasing VPC resources
- Delete orphaned ENIs left by cluster controllers (ingress, CSI, CCM)
- Purge non-NS/SOA records from hosted zone before deletion to prevent
  stale zone pollution across test runs
- Add classic ELB (v1) sweep before ALB/NLB sweep to remove all LBs
  blocking VPC subnet/SG deletion; vendor elasticloadbalancing SDK
- Add **/*.test to .gitignore to exclude compiled Go test binaries
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 5, 2026
@openshift-ci

openshift-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci

openshift-ci Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: gdbranco

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 5, 2026
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 2ea6f28a-3be7-481f-93a2-da7e937cad52

📥 Commits

Reviewing files that changed from the base of the PR and between 3fb1fec and 9518ec2.

📒 Files selected for processing (1)
  • tests/e2e/hyperfleet_sanity_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/e2e/hyperfleet_sanity_test.go

📝 Walkthrough

Walkthrough

Added HyperFleet support across the CLI. The change adds AWS-backed runtime initialization, HyperFleet URL configuration, cluster and node pool create, list, describe, edit, and delete commands, and HyperFleet-only authentication. It also adds resource resolution and IAM helpers, mock and reporter test utilities, extensive unit coverage, dependency updates, coverage exclusions, Make targets, and an end-to-end AWS lifecycle sanity test.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (2 errors, 6 warnings)

Check name Status Explanation Resolution
No-Weak-Crypto ❌ Error The PR adds crypto/sha1 and sha1.Sum in tests/e2e/hyperfleet_sanity_test.go to generate an OIDC root-certificate fingerprint for IAM. Replace SHA-1 with an approved certificate-thumbprint mechanism, or isolate and formally document the unavoidable AWS IAM compatibility exception.
No-Sensitive-Data-In-Logs ❌ Error login and WarnOnMismatch log the full user-supplied Hyperfleet URL; HTTPS validation permits URL userinfo/query data, so passwords, tokens, or internal hostnames can be exposed. Redact URL userinfo, query, and fragments before logging, or log only the parsed hostname and region; apply the same redaction to validation and region-mismatch errors.
Description check ⚠️ Warning The description explains the purpose and major changes, but omits several required template sections and reproducible validation details. Add Previous Behavior, Behavior After This Change, How to Test, Proof of the Fix, Breaking Changes, and documented risks or limitations.
Docstring Coverage ⚠️ Warning Docstring coverage is 43.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning The 844-line e2e It covers login, AWS provisioning, cluster/nodepool CRUD, and cleanup; unit tests also use bare assertions such as resolve_test.go:48 and list/cluster/hyperfleet_run_test.go:68. Split the e2e lifecycle into focused Its with shared BeforeEach/AfterEach cleanup, and add diagnostic messages to assertions in the new unit tests.
Microshift Test Compatibility ⚠️ Warning tests/e2e/hyperfleet_sanity_test.go references the unavailable openshift-image-registry namespace and creates worker node pools, with no MicroShift skip tag or guard. MicroShift compatibility notice: Add [Skipped:MicroShift] or an IsMicroShiftCluster/g.Skip guard; otherwise verify this test with the prescribed MicroShift e2e job.
Single Node Openshift (Sno) Test Compatibility ⚠️ Warning tests/e2e/hyperfleet_sanity_test.go creates worker pools with 2 and 1 replicas, waits for both, and deletes both; no SNO label or topology guard protects the test. Single Node OpenShift (SNO) compatibility notice: add [Skipped:SingleReplicaTopology] or a SingleReplicaTopologyMode skip, or verify with /payload-job periodic-ci-openshift-release-master-ci-4.22-e2e-aws-upgrade-ovn-single-node.
Ipv6 And Disconnected Network Test Compatibility ⚠️ Warning The new Ginkgo test hardcodes IPv4 CIDRs/routes, builds an endpoint with fmt.Sprintf without IPv6 brackets, and calls AWS, Hyperfleet, and OIDC endpoints outside the cluster. Add the required IPv6/disconnected compatibility notice and IPv6 CI job. Use family-aware CIDRs and net.JoinHostPort, or add [Skipped:Disconnected] if external access is unavoidable.
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the Hyperfleet Platform API v2 integration as the primary change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All added Ginkgo titles are static literals; the only computed context titles use fixed KeyringEnvKey, and no title contains runtime names, timestamps, UUIDs, IPs, or node data.
Topology-Aware Scheduling Compatibility ✅ Passed The PR adds CLI/API integration and E2E cleanup only; no deployment manifests, operator/controllers, or scheduling constraints were added or modified.
Ote Binary Stdout Contract ✅ Passed No process-level stdout violation found: main writes errors to os.Stderr, init/BeforeSuite only register flags or assign state, and Hyperfleet diagnostics use GinkgoWriter inside the test.
Container-Privileges ✅ Passed PR diff adds no prohibited privilege settings and changes no Dockerfile, Containerfile, or YAML/JSON manifest; the new target only runs Ginkgo.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 18

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (11)
tests/e2e/hyperfleet_sanity_test.go-1189-1190 (1)

1189-1190: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Do not discard the json.Marshal error.

hfBuildTrustPolicy drops the marshal error. If marshalling ever fails, the function returns "" and CreateRole fails later with an opaque AWS error. Surface the failure at the source.

🔧 Proposed fix
-	b, _ := json.Marshal(doc)
-	return string(b)
+	b, err := json.Marshal(doc)
+	Expect(err).NotTo(HaveOccurred(), "marshalling trust policy for provider %s", oidcProvider)
+	return string(b)
 }

As per path instructions: "Never ignore error returns".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` around lines 1189 - 1190, Update
hfBuildTrustPolicy to handle the error returned by json.Marshal instead of
discarding it. Surface marshalling failures immediately through the function’s
existing error-handling or return contract, ensuring CreateRole does not receive
an empty policy string after serialization fails.

Source: Path instructions

tests/e2e/hyperfleet_sanity_test.go-791-794 (1)

791-794: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document HYPERFLEET_INSTANCE_TYPE in the Makefile target.

The test reads HYPERFLEET_INSTANCE_TYPE here, but the e2e-hyperfleet documentation block in Makefile (Lines 178 to 187) does not list it, and the target does not forward it to ginkgo. ginkgo run passes the parent environment through, so the variable still reaches the test when exported. Add it to the "Optional" list so the supported inputs are discoverable.

🔧 Makefile documentation update
 #   OPERATOR_ROLES_PREFIX — defaults to CLUSTER_NAME
+#   HYPERFLEET_INSTANCE_TYPE — node pool instance type; defaults to m5.xlarge
 #   AWS_DEFAULT_REGION    — fallback when region cannot be derived from HYPERFLEET_URL
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` around lines 791 - 794, Update the
e2e-hyperfleet documentation block in the Makefile to list
HYPERFLEET_INSTANCE_TYPE under the Optional inputs, matching the environment
variable consumed near instanceType. Do not change the test logic or add
explicit ginkgo forwarding, since the inherited environment already provides the
variable.
tests/e2e/hyperfleet_sanity_test.go-1129-1154 (1)

1129-1154: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Weak Cryptography (CWE-295): Improper Certificate Validation

Reachability: Internal

Set MinVersion: tls.VersionTLS12 and clarify the chain-validation tradeoff.

The function dials the OIDC issuer with InsecureSkipVerify: true to extract the SHA-1 thumbprint, then registers it in the test AWS account. An on-path attacker could present a substituted chain and register the attacker's root in IAM. Add MinVersion: tls.VersionTLS12 and document why validation is skipped and why the residual risk is acceptable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` around lines 1129 - 1154, Update
hfOIDCThumbprint to set MinVersion to tls.VersionTLS12 in the tls.Config passed
to tls.Dial, and add a clear comment explaining that certificate validation is
intentionally skipped only to read the issuer’s raw chain for thumbprint
registration. Keep the existing InsecureSkipVerify behavior and SHA-1 thumbprint
extraction unchanged, but document the tradeoff and why the residual risk is
acceptable in this test-only flow.

Source: Linters/SAST tools

cmd/list/cluster/hyperfleet.go-48-48 (1)

48-48: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Handle the tabwriter.Flush error.

If stdout fails during a pipe or redirect, Flush returns an error. The command currently reports success after partial output. Report the error and exit with a nonzero status.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/list/cluster/hyperfleet.go` at line 48, Update the output finalization
around writer.Flush in the command flow to check and handle its returned error.
Report the flush failure and terminate with a nonzero status instead of allowing
the command to report success after partial output.

Sources: Coding guidelines, Path instructions

cmd/list/machinepool/hyperfleet_run_test.go-83-89 (1)

83-89: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Restore the original ocm cluster key in each test.

Each test overwrites process-global state and restores the literal value "cluster1". A preceding spec can set a different key. Capture the prior key before mutation and restore that exact value during cleanup.

  • cmd/list/machinepool/hyperfleet_run_test.go#L83-L89: restore the captured key instead of "cluster1".
  • cmd/dlt/cluster/hyperfleet_run_test.go#L48-L54: restore the captured key instead of "cluster1".
  • cmd/edit/machinepool/hyperfleet_run_test.go#L133-L149: restore the captured key instead of "cluster1".

Based on learnings, tests that override globals must restore the original values to prevent cross-test interference.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/list/machinepool/hyperfleet_run_test.go` around lines 83 - 89, Capture
the existing cluster key before each test mutates it, then restore that captured
value during cleanup instead of the hardcoded "cluster1". Apply this in
cmd/list/machinepool/hyperfleet_run_test.go#L83-L89,
cmd/dlt/cluster/hyperfleet_run_test.go#L48-L54, and
cmd/edit/machinepool/hyperfleet_run_test.go#L133-L149, using the relevant test
setup and ocm.SetClusterKey calls.

Source: Learnings

cmd/edit/cluster/hyperfleet_run_test.go-65-66 (1)

65-66: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the expiration timestamp in the update payload.

This test only proves that Update executes. It does not prove that updated.Spec.ExpirationTimestamp contains the requested expiration.

Capture the Update argument. Assert that the timestamp is non-nil and matches the requested one-hour expiration within a small test tolerance.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/edit/cluster/hyperfleet_run_test.go` around lines 65 - 66, Update the
mock expectation in the hyperfleet run test to capture the payload passed to
clusters.Update, then assert that updated.Spec.ExpirationTimestamp is non-nil
and matches the requested one-hour expiration within a small test tolerance.
Keep the existing Get and Update behavior unchanged while validating the update
payload.

Source: Coding guidelines

cmd/dlt/machinepool/hyperfleet_run_test.go-93-94 (1)

93-94: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Restore the original cluster key in test cleanup.

Both tests restore a fixed "cluster1" value instead of the value that existed before the test. A prior or future test that sets another cluster key can leak state into later examples.

  • cmd/dlt/machinepool/hyperfleet_run_test.go#L93-L94: capture the existing cluster key before clearing it and restore that captured value.
  • cmd/edit/cluster/hyperfleet_run_test.go#L76-L77: capture the existing cluster key before clearing it and restore that captured value.

Based on learnings, tests that override shared state must restore the original value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/dlt/machinepool/hyperfleet_run_test.go` around lines 93 - 94, Update the
test setup in cmd/dlt/machinepool/hyperfleet_run_test.go at lines 93-94 and
cmd/edit/cluster/hyperfleet_run_test.go at lines 76-77: capture the current
cluster key before calling ocm.SetClusterKey(""), then have each DeferCleanup
restore that captured value instead of the fixed "cluster1".

Source: Learnings

cmd/dlt/machinepool/cmd.go-86-88 (1)

86-88: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Change error format verb from %v to %w to preserve error chain.

Line 88 wraps the service error using %v, which prevents errors.Is() and errors.As() from inspecting the error chain. Change the format verb to %w:

Diff
- return fmt.Errorf("error deleting machinepool: %v", err)
+ return fmt.Errorf("error deleting machinepool: %w", err)

The test assertions use ContainSubstring() to check error messages. The error message text remains identical with %w, so tests will continue to pass. The coding guidelines require "Wrap returned errors with context using %w; do not drop the original error."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/dlt/machinepool/cmd.go` around lines 86 - 88, Update the error wrapping
in the DeleteMachinePool call within the machinepool command to use the wrapping
format that preserves the underlying error chain, while keeping the existing
contextual message unchanged.

Source: Coding guidelines

cmd/create/machinepool/hyperfleet_run_test.go-115-116 (1)

115-116: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Restore the previous cluster key.

Line 116 always restores "cluster1". This changes shared OCM state when the prior key differs. Read the original key before Line 115 and restore that exact value in DeferCleanup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/create/machinepool/hyperfleet_run_test.go` around lines 115 - 116, Update
the test setup around ocm.SetClusterKey to capture the existing cluster key
before clearing it, then have DeferCleanup restore that captured value instead
of hardcoding "cluster1".

Source: Learnings

cmd/create/cluster/hyperfleet.go-34-49 (1)

34-49: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate --version and --operator-roles-prefix before building the cluster spec.

Two validation gaps exist in this block:

  • args.version is never checked. Line 77 assigns it to Release.Image. An empty value produces a cluster spec with an empty release image. The HyperFleet node pool path in cmd/create/machinepool/hyperfleet.go Lines 69-72 rejects the empty case explicitly. Match that behavior.
  • args.operatorRolesPrefix is only checked for emptiness. The OCM path in cmd/create/cluster/cmd.go Lines 1931-1938 also enforces a 32-character limit and aws.RoleNameRE. Without those checks, ComputeRolesRef builds malformed IAM role ARNs and the API call fails with an unclear error.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/create/cluster/hyperfleet.go` around lines 34 - 49, Extend the validation
block before building the cluster spec in the cluster creation flow: reject an
empty args.version with the same required-value behavior used by the HyperFleet
machine-pool path, and validate args.operatorRolesPrefix against the existing
32-character maximum and aws.RoleNameRE used by the OCM path. Preserve the
current required checks and report validation errors before constructing the
spec or making the API call.
cmd/create/machinepool/hyperfleet.go-95-95 (1)

95-95: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Bounds-check the replica count before narrowing to int32.

userOptions.Replicas is an int. On a 64-bit platform a value above math.MaxInt32 wraps and can become negative. The negative value is then written to NodePoolSpec.Replicas.

🐛 Proposed fix
-	replicas := int32(userOptions.Replicas)
+	if userOptions.Replicas < 0 || userOptions.Replicas > math.MaxInt32 {
+		r.Reporter.Errorf("--replicas must be between 0 and %d", math.MaxInt32)
+		exitFn(1)
+		return
+	}
+	replicas := int32(userOptions.Replicas)

Add the math import.

As per path instructions: "Integer overflow: bounds-check user-supplied sizes".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/create/machinepool/hyperfleet.go` at line 95, Bounds-check
userOptions.Replicas before converting it to int32 in the machine pool creation
flow. Use the math package’s int32 maximum, reject values above that limit with
the existing validation/error path, and only then assign the narrowed value to
NodePoolSpec.Replicas.

Sources: Path instructions, Linters/SAST tools

🧹 Nitpick comments (15)
cmd/login/cmd.go (1)

285-286: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Preserve the config.Save error chain.

Line 286 formats err with %v. Callers cannot inspect the root cause. Use %w instead. This preserves the current CLI text.

Proposed fix
-			return fmt.Errorf("failed to save config file: %v", err)
+			return fmt.Errorf("failed to save config file: %w", err)

As per coding guidelines, “Wrap returned errors with context using %w; do not drop the original error.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/login/cmd.go` around lines 285 - 286, Update the error formatting in the
config.Save failure branch to use the error-wrapping verb instead of value
formatting, preserving the existing context message and allowing callers to
inspect the underlying save error.

Source: Coding guidelines

tests/e2e/hyperfleet_sanity_test.go (5)

1073-1100: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Honor context cancellation in the polling loop.

The loop uses time.Sleep and checks only the wall-clock deadline. If ctx is cancelled, the loop keeps polling until the deadline. Select on ctx.Done() so the wait stops promptly.

🔧 Proposed change
-		time.Sleep(15 * time.Second)
+		select {
+		case <-ctx.Done():
+			GinkgoWriter.Printf("Context cancelled while waiting for VPC %s to drain\n", vpcID)
+			return
+		case <-time.After(15 * time.Second):
+		}

As per path instructions: "context.Context for cancellation and timeouts".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` around lines 1073 - 1100, Update
hfWaitVPCInstancesTerminated to honor ctx cancellation throughout the polling
loop: check ctx.Done() before polling and replace the fixed time.Sleep with a
context-aware wait that returns promptly when cancellation occurs, while
preserving the existing deadline, success, and timeout behavior.

Source: Path instructions


152-152: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Attach a deadline to the root context.

context.Background() carries no deadline. The AWS waiters take explicit timeouts, but hfWaitVPCInstancesTerminated and the direct SDK calls rely on SDK defaults only. The same ctx is also captured by every DeferCleanup closure, so a hung cleanup call can block the suite until the Ginkgo --timeout 3h fires.

Derive a bounded context and register its cancel function.

As per path instructions: "context.Context for cancellation and timeouts".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` at line 152, Replace
context.Background() in the test setup with a bounded context carrying an
appropriate deadline, retain its cancel function, and register cancellation
through the test cleanup mechanism. Ensure the derived context is the one passed
to hfWaitVPCInstancesTerminated, direct SDK calls, and captured by DeferCleanup
closures.

Source: Path instructions


195-195: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Resolve the availability zone instead of appending "a".

az := region + "a" assumes the region always exposes an AZ with the a suffix and that the calling account can use it. AWS maps AZ names per account, and some accounts do not have <region>a available for every instance type. CreateSubnet then fails and the test aborts before any cluster is created.

Call DescribeAvailabilityZones and use the first available zone.

🔧 Proposed change
-			az := region + "a"
+			azOut, err := ec2Client.DescribeAvailabilityZones(ctx, &ec2svc.DescribeAvailabilityZonesInput{})
+			Expect(err).NotTo(HaveOccurred(), "describing availability zones in %s", region)
+			Expect(azOut.AvailabilityZones).NotTo(BeEmpty(), "no availability zones in %s", region)
+			az := awssdk.ToString(azOut.AvailabilityZones[0].ZoneName)

Note: ec2Client is created at Line 185, so move this block after that line.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` at line 195, Replace the hard-coded az
assignment in the test setup with a DescribeAvailabilityZones call using
ec2Client, select the first available zone, and use its name for subnet
creation. Move this lookup after ec2Client is initialized and preserve the
test’s existing failure handling if no availability zone is returned.

113-115: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Split the single It into focused specs with BeforeEach/AfterEach.

One It block spans Lines 115 to 933 and covers login, whoami, VPC and IAM provisioning, cluster creation, describe, list, and the full node pool lifecycle. When any assertion fails, Ginkgo reports one spec failure and every later assertion is skipped, so the report does not identify which behavior regressed.

Move the shared AWS and Hyperfleet setup into BeforeAll/BeforeEach inside an Ordered container, then express each behavior as its own It: cluster reaches Ready, rosa list clusters shows the cluster, rosa describe cluster matches the API Get response, node pools reach Ready, and node pool deletion completes.

Add a Ginkgo label so the suite can select or exclude this long-running test through the --label-filter used by the e2e_test target.

As per coding guidelines: "Ginkgo tests must have single responsibility (one specific behavior per It block), proper setup/cleanup using BeforeEach/AfterEach (especially for cluster-scoped resources)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` around lines 113 - 115, Refactor the
“Hyperfleet sanity” suite into an Ordered container with shared AWS/Hyperfleet
setup in BeforeAll/BeforeEach and cleanup in AfterEach, then split the
monolithic It into focused specs for cluster readiness, listing, description/API
consistency, node-pool readiness, and node-pool deletion. Add the suite label
used by the e2e_test --label-filter, while preserving the existing resource
lifecycle and test ordering.

Source: Coding guidelines


941-972: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Paginate and batch Route 53 record deletions.

ListResourceRecordSets is paginated, so the current code can leave records that cause DeleteHostedZone to return HostedZoneNotEmpty. Split ChangeResourceRecordSets requests within Route 53 limits, and report DeleteHostedZone errors instead of discarding them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/hyperfleet_sanity_test.go` around lines 941 - 972, Update
hfPurgeHostedZoneRecords to paginate ListResourceRecordSets using its
continuation markers, collecting deletable records across all pages. Submit
ChangeResourceRecordSets requests in batches within Route 53 limits, handling
and reporting each batch error. Also update the DeleteHostedZone call site to
capture and report its returned error instead of discarding it.
Makefile (1)

188-200: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Build the rosa binary before running the Hyperfleet e2e target.

The sanity test drives the CLI through rosacli.NewClient().Runner, which executes the installed rosa binary. The existing e2e_test target declares install as a prerequisite. e2e-hyperfleet does not, so the test can run against a stale binary or fail when no binary exists.

🔧 Add the `install` prerequisite
 .PHONY: e2e-hyperfleet
-e2e-hyperfleet:
+e2e-hyperfleet: install
 	HYPERFLEET_URL="$${HYPERFLEET_URL}" \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 188 - 200, Update the e2e-hyperfleet Make target to
depend on the existing install target, ensuring the rosa binary is built before
Ginkgo runs while preserving the current environment variables and test
arguments.
pkg/output/reporter_test.go (1)

138-139: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen the IsTerminal delegation test.

The fake uses the zero value, so Terminal is false. The assertion passes even if IsTerminal returned a constant false and never called the inner logger. Add the true case to prove delegation.

🔧 Proposed test
 		It("IsTerminal delegates to inner", func() {
 			Expect(NewStructuredReporter(&reportertest.FakeLogger{}).IsTerminal()).To(BeFalse())
+			Expect(NewStructuredReporter(&reportertest.FakeLogger{Terminal: true}).IsTerminal()).To(BeTrue())
 		})

Based on path instructions: "Flag weak tests that only restate implementation or changes that weaken existing assertions."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/output/reporter_test.go` around lines 138 - 139, Strengthen the
IsTerminal test by configuring the reportertest.FakeLogger with Terminal set to
true before constructing NewStructuredReporter, then assert IsTerminal returns
true. Keep the test focused on proving delegation rather than allowing the
zero-value false result to pass without calling the inner logger.

Source: Path instructions

cmd/describe/cluster/hyperfleet_run_test.go (1)

39-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the emitted command output.

These tests verify API calls but do not verify text or structured output. Capture stdout. Assert the text output. Decode and assert the structured output.

  • cmd/describe/cluster/hyperfleet_run_test.go#L39-L61: assert the rendered cluster text.
  • cmd/describe/cluster/hyperfleet_run_test.go#L80-L96: assert the structured cluster fields.
  • cmd/describe/machinepool/hyperfleet_run_test.go#L44-L71: assert the rendered node-pool text.
  • cmd/describe/machinepool/hyperfleet_run_test.go#L95-L118: assert the structured node-pool fields.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/describe/cluster/hyperfleet_run_test.go` around lines 39 - 61, Extend the
describe command tests to capture stdout and assert emitted output: in
cmd/describe/cluster/hyperfleet_run_test.go:39-61, assert the rendered cluster
text; in cmd/describe/cluster/hyperfleet_run_test.go:80-96, decode the
structured output and verify cluster fields; in
cmd/describe/machinepool/hyperfleet_run_test.go:44-71, assert the rendered
node-pool text; and in cmd/describe/machinepool/hyperfleet_run_test.go:95-118,
decode the structured output and verify node-pool fields. Keep the existing API
mock expectations and runHyperfleetDescribe flows intact.

Source: Coding guidelines

cmd/describe/cluster/hyperfleet.go (1)

30-50: 🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

Propagate a cancellable context to HyperFleet requests.

Replace context.Background() in the three handlers with the Cobra command context. Pass the command through hfDescribeMachinePool and hfListClusters. In cmd/rosa/main.go, execute the root command with a signal-backed context; root.Execute() currently provides no cancellation context. The HyperFleet client forwards request contexts through Get and List.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/describe/cluster/hyperfleet.go` around lines 30 - 50, Propagate a
cancellable Cobra context through the HyperFleet describe/list flows instead of
using context.Background(): update runHyperfleetDescribe, hfDescribeMachinePool,
and hfListClusters to use the command context and thread the command through the
helper calls where needed. Also update cmd/rosa/main.go so the root command is
executed with a signal-backed context, since root.Execute() does not provide
cancellation; keep the existing HyperFleet Get/List call sites using the
passed-in request context.

Sources: Coding guidelines, Path instructions

cmd/dlt/cluster/hyperfleet.go (1)

14-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Replace mutable package-level command seams with explicit dependencies.

These variables let tests mutate production dispatch and exit behavior through shared package state. This creates test-order coupling and blocks safe parallel execution.

  • cmd/dlt/cluster/hyperfleet.go#L14-L22: pass HyperFleet dispatch and exit dependencies through a per-call dependency struct.
  • cmd/dlt/machinepool/hyperfleet.go#L14-L22: pass HyperFleet dispatch and exit dependencies through a per-call dependency struct.
  • cmd/edit/cluster/hyperfleet.go#L17-L25: pass HyperFleet dispatch and exit dependencies through a per-call dependency struct.

Based on learnings, “avoid using mutable package-level function variables for new command-level seams.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/dlt/cluster/hyperfleet.go` around lines 14 - 22, Replace the mutable
package-level seams around hfEnabled, exitFn, and hfDeleteCluster with a
per-call dependency struct in cmd/dlt/cluster/hyperfleet.go lines 14-22, and
update the command flow to receive and use those dependencies. Apply the same
change to cmd/dlt/machinepool/hyperfleet.go lines 14-22 and
cmd/edit/cluster/hyperfleet.go lines 17-25, preserving production defaults while
preventing shared test state and enabling safe parallel execution.

Source: Learnings

pkg/rosa/runtime.go (1)

96-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the shared AWS initialization and align the exit style.

WithAWSOnly duplicates lines 82-92 of WithAWS exactly. Two copies of the creator lookup will drift.

WithAWSOnly also calls os.Exit(1) directly while the neighbouring new function WithHyperFleet calls hfExitFn(1). Use one exit mechanism across the new runtime code so tests can stub it.

♻️ Proposed refactor
 func (r *Runtime) WithAWS() *Runtime {
 	// dependency to ocm client to validate the region
 	r.WithOCM()
 	err := r.OCMClient.ValidateAwsClientRegion()
 	if err != nil {
 		r.Reporter.Errorf("%s", err)
 		os.Exit(1)
 	}
-	if r.AWSClient == nil {
-		r.AWSClient = aws.CreateNewClientOrExit(r.Logger, r.Reporter)
-	}
-	if r.Creator == nil {
-		var err error
-		r.Creator, err = r.AWSClient.GetCreator()
-		if err != nil {
-			r.Reporter.Errorf("Failed to get AWS creator: %v", err)
-			os.Exit(1)
-		}
-	}
-	return r
+	return r.WithAWSOnly()
 }

Then in WithAWSOnly, replace os.Exit(1) with hfExitFn(1) followed by return r.

As per coding guidelines: "Prefer small focused functions and early returns over deeply nested branches" and the repository DRY expectation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/rosa/runtime.go` around lines 96 - 111, Refactor WithAWSOnly to reuse the
existing shared AWS client and creator initialization performed by WithAWS
instead of duplicating the creator lookup. Replace its direct os.Exit(1) call
with the shared hfExitFn(1) mechanism, then return r after the exit call so the
function remains testable and preserves the current failure flow.

Source: Coding guidelines

pkg/hyperfleet/endpoint.go (1)

11-30: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Match the region per hostname label.

awsRegionRE runs an unanchored search over the whole hostname. A hostname label such as api-prod-2.example.com matches the pattern and yields api-prod-2 as the region. ExtractRegion then returns a value that is not an AWS region, and SigV4 signs with it. The request fails later with an opaque signature error instead of the clear "cannot derive AWS region" message.

Split the hostname on . and match each label with an anchored pattern.

♻️ Proposed change to match labels
-var awsRegionRE = regexp.MustCompile(`[a-z]+-(?:[a-z]+-)+\d+`)
+var awsRegionRE = regexp.MustCompile(`^(?:us|eu|ap|sa|ca|me|af|il|mx)-(?:gov-)?[a-z]+-\d+$`)
@@
-	region := awsRegionRE.FindString(u.Hostname())
+	var region string
+	for _, label := range strings.Split(u.Hostname(), ".") {
+		if awsRegionRE.MatchString(label) {
+			region = label
+			break
+		}
+	}
As per path instructions: "Normalize Unicode and anchor regexes (^$); watch for ReDoS".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/hyperfleet/endpoint.go` around lines 11 - 30, Update awsRegionRE and
ExtractRegion so region matching is performed against individual dot-separated
hostname labels rather than an unanchored search across the full hostname.
Anchor the regex to the complete label, normalize the hostname appropriately
before splitting, and return the existing “cannot derive AWS region” error when
no entire label matches; preserve valid standard and GovCloud region extraction.

Source: Path instructions

pkg/hyperfleet/flags.go (1)

7-18: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add doc comments to the new exported functions.

AddFlags, Enabled, and ExplicitURL are new exported symbols without doc comments. SetURL and Reset below already have them.

♻️ Proposed doc comments
+// AddFlags registers the hidden --hyperfleet-url persistent flag on cmd.
 func AddFlags(cmd *cobra.Command) {
@@
+// Enabled reports whether commands must route to the Platform API instead of OCM.
 func Enabled() bool       { return hyperfleetURL != "" }
+
+// ExplicitURL returns the configured Platform API endpoint URL.
 func ExplicitURL() string { return hyperfleetURL }
As per coding guidelines: "Use exported symbol doc comments when new public types or functions are introduced".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/hyperfleet/flags.go` around lines 7 - 18, Add Go doc comments to the
exported functions AddFlags, Enabled, and ExplicitURL in
pkg/hyperfleet/flags.go. Each comment must begin with the corresponding function
name and briefly describe its purpose, matching the existing documentation style
used by SetURL and Reset.

Source: Coding guidelines

pkg/hyperfleet/hyperfleet_test.go (1)

100-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add GovCloud coverage for ComputeRolesRef.

The suite asserts GovCloud region extraction at Lines 32-33, but ComputeRolesRef is only tested with the commercial partition. The missing case is exactly the one that hides the hardcoded arn:aws:iam:: partition in pkg/hyperfleet/roles.go.

Add an entry that builds ARNs for a GovCloud caller and asserts the aws-us-gov partition.

As per coding guidelines: "All code should be covered by tests, using Ginkgo".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/hyperfleet/hyperfleet_test.go` around lines 100 - 111, Extend the Ginkgo
test for ComputeRolesRef with a GovCloud caller case, using a GovCloud ARN input
and asserting every generated role ARN uses the aws-us-gov partition while
preserving the cluster prefix and account ID. Add coverage for all seven fields
in the existing ComputeRolesRef test.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/create/cluster/hyperfleet.go`:
- Around line 60-65: Update the subnet handling near subnetOut.Subnets in the
hyperfleet creation flow to import and use awssdk.ToString for VpcId and
AvailabilityZone instead of direct pointer dereferences. Validate both converted
values, report an error through r.Reporter.Errorf, and exit when either field is
missing, while preserving the existing empty-subnet handling.

In `@cmd/create/machinepool/hyperfleet_run_test.go`:
- Around line 71-80: Update the success tests around runHyperfleetCreate and the
nodePools.EXPECT().Create mocks to capture the NodePool argument instead of
accepting gomock.Any(). Assert the payload’s name, release image, replica count,
instance profile, subnet, and cluster name, and verify the positional-name case
sets ObjectMeta.Name to "my-np".

In `@cmd/create/machinepool/hyperfleet.go`:
- Around line 40-93: Update the validation and error-handling branches in the
machine pool creation flow to return immediately after every exitFn(1) call,
including the node name, cluster key, cluster resolution, cluster fetch, release
image, subnet, instance profile, and final validation branches. Match the
existing WithHyperFleet pattern so stubbed exitFn calls cannot fall through into
invalid state or dereference a nil cluster.

In `@cmd/dlt/cluster/hyperfleet.go`:
- Around line 42-45: Restore the existing confirmation flow before the
destructive delete calls: in cmd/dlt/cluster/hyperfleet.go lines 42-45, invoke
the established delete-cluster confirmation before Clusters(...).Delete; in
cmd/dlt/machinepool/hyperfleet.go lines 54-57, invoke the established
machine-pool confirmation before NodePools(...).Delete. Preserve --yes behavior
and only call each API after confirmation succeeds.
- Line 28: Replace context.Background in the Hyperfleet command flows with the
Cobra command context, then apply the existing command timeout policy before
Platform API operations: update cmd/dlt/cluster/hyperfleet.go lines 28-28 for
resolving and deleting, cmd/dlt/machinepool/hyperfleet.go lines 25-25 for
resolving and deleting, and cmd/edit/cluster/hyperfleet.go lines 31-31 for
resolving, reading, and updating. Propagate the resulting context through each
relevant API call so cancellation and timeouts terminate blocked requests.

In `@cmd/edit/cluster/hyperfleet.go`:
- Around line 39-42: Extend the validation before clusters.Update in the
HyperFleet edit flow to reject any changed edit flag that HyperFleet does not
support, including combinations of --expiration with OCM-only flags. Preserve
--cluster and selector/output flags as valid, and retain the existing
error-reporting and exit behavior for unsupported combinations.

In `@cmd/edit/machinepool/hyperfleet.go`:
- Around line 70-74: Validate userOptions.replicas in the HyperFleet edit flow
before casting it to int32, since this path bypasses EditMachinepoolOptions.Bind
and can otherwise accept negative values or overflow beyond math.MaxInt32.
Update the logic around the updated := np.DeepCopy() and nodePools.Update call
to reject any replica count below 0 or above int32 limits, and preserve the
existing update behavior for valid inputs. Add boundary tests covering the lower
and upper rejected values as well as a valid in-range case.

In `@cmd/list/cluster/hyperfleet.go`:
- Around line 33-48: Update the HyperFleet cluster-list handler to check
output.HasFlag() before creating the tabwriter and serialize a stable
cluster-list representation for JSON and YAML output, preserving the existing
table behavior when no structured format is requested. Follow the command’s
existing structured-output conventions and add coverage for both JSON and YAML
paths.

In `@cmd/whoami/cmd.go`:
- Around line 61-65: Update run’s endpoint-selection logic to derive the
effective Hyperfleet URL from hyperfleet.ExplicitURL(), falling back to
cfg.HyperfleetURL when no explicit URL is provided. Select WithAWSOnly when that
effective URL exists and cfg is absent or has an invalid/expired OCM token,
using cfg.Armed() or equivalent validity logic instead of config.IsNotValid;
otherwise preserve WithAWS, and add coverage for both explicit-URL and
expired-token scenarios.

In `@go.mod`:
- Around line 30-31: Replace the pseudo-version entries for
github.com/openshift-online/rosa-hyperfleet-api/clientset and
github.com/openshift/hypershift/api in go.mod, including the additional
occurrence, with exact pinned official release versions. If an approved
HyperFleet preview exception applies, document its scope and obtain human review
before shipping.

In `@Makefile`:
- Line 166: Replace the non-portable sed invocation in the mocks target with a
rewrite that works on both GNU and BSD/macOS sed, while preserving the existing
import-path substitution in wrappers_mock.go. Alternatively, configure mockgen
with the required imports/package options and remove the post-processing step.

In `@pkg/config/config.go`:
- Around line 154-166: Replace the %v verbs with %w in the returned fmt.Errorf
calls at pkg/config/config.go lines 154-166, 195-199, 269-270, 305-306, and
329-330, and in pkg/hyperfleet/nodepool.go lines 16-19, preserving each existing
error message and wrapped error value so errors.Is and errors.As can inspect the
underlying errors.

In `@pkg/hyperfleet/cluster.go`:
- Around line 16-19: Update the error formatting in the cluster-listing flow to
wrap the original error with `%w` instead of formatting it with `%v`. Preserve
the existing context message and return behavior in the `Clusters(...).List`
call so callers can use errors.Is or errors.As on the returned error.

In `@pkg/hyperfleet/endpoint.go`:
- Around line 17-30: Update ExtractRegion to reject any URL whose parsed scheme
is not HTTPS, returning a clear validation error before deriving the region.
Ensure the same validation is applied when URLs enter the runtime through
WithHyperFleet and hyperfleet.SetURL, so all HyperFleet client configuration
paths reject cleartext endpoints.

In `@pkg/hyperfleet/roles.go`:
- Around line 12-25: Update ComputeRolesRef in pkg/hyperfleet/roles.go to accept
an AWS partition parameter and use it when constructing role ARNs, then update
its caller in cmd/create/cluster/hyperfleet.go to pass r.Creator.Partition.
Extend the test case in pkg/hyperfleet/hyperfleet_test.go to pass aws-us-gov and
assert the resulting GovCloud role ARNs, while preserving commercial ARN
coverage.

In `@pkg/rosa/runtime_test.go`:
- Around line 78-95: Update the hfNewClient stub in the success test to capture
the supplied *hfrest.Config, control AWS_REGION for a deterministic value, and
assert the captured configuration’s Host, Region, AccountID, and CallerARN
alongside the existing Runtime assertions. Preserve the current successful
client setup and cleanup any environment override after the test.

In `@pkg/rosa/runtime.go`:
- Around line 158-216: Update Runtime.WithHyperFleet to create a bounded context
with a timeout instead of context.Background(), and defer its cancel function
immediately after creation. Reuse this context for awsLoadConfig and
awsGetIdentity so HyperFleet initialization cannot hang indefinitely.

In `@tests/e2e/hyperfleet_sanity_test.go`:
- Around line 309-321: Register cleanup immediately after each AWS create call
in tests/e2e/hyperfleet_sanity_test.go:281-307, 309-321, 358-423, and 425-461:
clean up igwID, natEIPAllocID, publicRTID, privateRTID, and workerSGID before
subsequent fallible calls; make route-table cleanup disassociate only when its
matching association ID is non-empty, and ensure each cleanup tolerates partial
configuration while removing any duplicate later registrations.

---

Minor comments:
In `@cmd/create/cluster/hyperfleet.go`:
- Around line 34-49: Extend the validation block before building the cluster
spec in the cluster creation flow: reject an empty args.version with the same
required-value behavior used by the HyperFleet machine-pool path, and validate
args.operatorRolesPrefix against the existing 32-character maximum and
aws.RoleNameRE used by the OCM path. Preserve the current required checks and
report validation errors before constructing the spec or making the API call.

In `@cmd/create/machinepool/hyperfleet_run_test.go`:
- Around line 115-116: Update the test setup around ocm.SetClusterKey to capture
the existing cluster key before clearing it, then have DeferCleanup restore that
captured value instead of hardcoding "cluster1".

In `@cmd/create/machinepool/hyperfleet.go`:
- Line 95: Bounds-check userOptions.Replicas before converting it to int32 in
the machine pool creation flow. Use the math package’s int32 maximum, reject
values above that limit with the existing validation/error path, and only then
assign the narrowed value to NodePoolSpec.Replicas.

In `@cmd/dlt/machinepool/cmd.go`:
- Around line 86-88: Update the error wrapping in the DeleteMachinePool call
within the machinepool command to use the wrapping format that preserves the
underlying error chain, while keeping the existing contextual message unchanged.

In `@cmd/dlt/machinepool/hyperfleet_run_test.go`:
- Around line 93-94: Update the test setup in
cmd/dlt/machinepool/hyperfleet_run_test.go at lines 93-94 and
cmd/edit/cluster/hyperfleet_run_test.go at lines 76-77: capture the current
cluster key before calling ocm.SetClusterKey(""), then have each DeferCleanup
restore that captured value instead of the fixed "cluster1".

In `@cmd/edit/cluster/hyperfleet_run_test.go`:
- Around line 65-66: Update the mock expectation in the hyperfleet run test to
capture the payload passed to clusters.Update, then assert that
updated.Spec.ExpirationTimestamp is non-nil and matches the requested one-hour
expiration within a small test tolerance. Keep the existing Get and Update
behavior unchanged while validating the update payload.

In `@cmd/list/cluster/hyperfleet.go`:
- Line 48: Update the output finalization around writer.Flush in the command
flow to check and handle its returned error. Report the flush failure and
terminate with a nonzero status instead of allowing the command to report
success after partial output.

In `@cmd/list/machinepool/hyperfleet_run_test.go`:
- Around line 83-89: Capture the existing cluster key before each test mutates
it, then restore that captured value during cleanup instead of the hardcoded
"cluster1". Apply this in cmd/list/machinepool/hyperfleet_run_test.go#L83-L89,
cmd/dlt/cluster/hyperfleet_run_test.go#L48-L54, and
cmd/edit/machinepool/hyperfleet_run_test.go#L133-L149, using the relevant test
setup and ocm.SetClusterKey calls.

In `@tests/e2e/hyperfleet_sanity_test.go`:
- Around line 1189-1190: Update hfBuildTrustPolicy to handle the error returned
by json.Marshal instead of discarding it. Surface marshalling failures
immediately through the function’s existing error-handling or return contract,
ensuring CreateRole does not receive an empty policy string after serialization
fails.
- Around line 791-794: Update the e2e-hyperfleet documentation block in the
Makefile to list HYPERFLEET_INSTANCE_TYPE under the Optional inputs, matching
the environment variable consumed near instanceType. Do not change the test
logic or add explicit ginkgo forwarding, since the inherited environment already
provides the variable.
- Around line 1129-1154: Update hfOIDCThumbprint to set MinVersion to
tls.VersionTLS12 in the tls.Config passed to tls.Dial, and add a clear comment
explaining that certificate validation is intentionally skipped only to read the
issuer’s raw chain for thumbprint registration. Keep the existing
InsecureSkipVerify behavior and SHA-1 thumbprint extraction unchanged, but
document the tradeoff and why the residual risk is acceptable in this test-only
flow.

---

Nitpick comments:
In `@cmd/describe/cluster/hyperfleet_run_test.go`:
- Around line 39-61: Extend the describe command tests to capture stdout and
assert emitted output: in cmd/describe/cluster/hyperfleet_run_test.go:39-61,
assert the rendered cluster text; in
cmd/describe/cluster/hyperfleet_run_test.go:80-96, decode the structured output
and verify cluster fields; in
cmd/describe/machinepool/hyperfleet_run_test.go:44-71, assert the rendered
node-pool text; and in cmd/describe/machinepool/hyperfleet_run_test.go:95-118,
decode the structured output and verify node-pool fields. Keep the existing API
mock expectations and runHyperfleetDescribe flows intact.

In `@cmd/describe/cluster/hyperfleet.go`:
- Around line 30-50: Propagate a cancellable Cobra context through the
HyperFleet describe/list flows instead of using context.Background(): update
runHyperfleetDescribe, hfDescribeMachinePool, and hfListClusters to use the
command context and thread the command through the helper calls where needed.
Also update cmd/rosa/main.go so the root command is executed with a
signal-backed context, since root.Execute() does not provide cancellation; keep
the existing HyperFleet Get/List call sites using the passed-in request context.

In `@cmd/dlt/cluster/hyperfleet.go`:
- Around line 14-22: Replace the mutable package-level seams around hfEnabled,
exitFn, and hfDeleteCluster with a per-call dependency struct in
cmd/dlt/cluster/hyperfleet.go lines 14-22, and update the command flow to
receive and use those dependencies. Apply the same change to
cmd/dlt/machinepool/hyperfleet.go lines 14-22 and cmd/edit/cluster/hyperfleet.go
lines 17-25, preserving production defaults while preventing shared test state
and enabling safe parallel execution.

In `@cmd/login/cmd.go`:
- Around line 285-286: Update the error formatting in the config.Save failure
branch to use the error-wrapping verb instead of value formatting, preserving
the existing context message and allowing callers to inspect the underlying save
error.

In `@Makefile`:
- Around line 188-200: Update the e2e-hyperfleet Make target to depend on the
existing install target, ensuring the rosa binary is built before Ginkgo runs
while preserving the current environment variables and test arguments.

In `@pkg/hyperfleet/endpoint.go`:
- Around line 11-30: Update awsRegionRE and ExtractRegion so region matching is
performed against individual dot-separated hostname labels rather than an
unanchored search across the full hostname. Anchor the regex to the complete
label, normalize the hostname appropriately before splitting, and return the
existing “cannot derive AWS region” error when no entire label matches; preserve
valid standard and GovCloud region extraction.

In `@pkg/hyperfleet/flags.go`:
- Around line 7-18: Add Go doc comments to the exported functions AddFlags,
Enabled, and ExplicitURL in pkg/hyperfleet/flags.go. Each comment must begin
with the corresponding function name and briefly describe its purpose, matching
the existing documentation style used by SetURL and Reset.

In `@pkg/hyperfleet/hyperfleet_test.go`:
- Around line 100-111: Extend the Ginkgo test for ComputeRolesRef with a
GovCloud caller case, using a GovCloud ARN input and asserting every generated
role ARN uses the aws-us-gov partition while preserving the cluster prefix and
account ID. Add coverage for all seven fields in the existing ComputeRolesRef
test.

In `@pkg/output/reporter_test.go`:
- Around line 138-139: Strengthen the IsTerminal test by configuring the
reportertest.FakeLogger with Terminal set to true before constructing
NewStructuredReporter, then assert IsTerminal returns true. Keep the test
focused on proving delegation rather than allowing the zero-value false result
to pass without calling the inner logger.

In `@pkg/rosa/runtime.go`:
- Around line 96-111: Refactor WithAWSOnly to reuse the existing shared AWS
client and creator initialization performed by WithAWS instead of duplicating
the creator lookup. Replace its direct os.Exit(1) call with the shared
hfExitFn(1) mechanism, then return r after the exit call so the function remains
testable and preserves the current failure flow.

In `@tests/e2e/hyperfleet_sanity_test.go`:
- Around line 1073-1100: Update hfWaitVPCInstancesTerminated to honor ctx
cancellation throughout the polling loop: check ctx.Done() before polling and
replace the fixed time.Sleep with a context-aware wait that returns promptly
when cancellation occurs, while preserving the existing deadline, success, and
timeout behavior.
- Line 152: Replace context.Background() in the test setup with a bounded
context carrying an appropriate deadline, retain its cancel function, and
register cancellation through the test cleanup mechanism. Ensure the derived
context is the one passed to hfWaitVPCInstancesTerminated, direct SDK calls, and
captured by DeferCleanup closures.
- Line 195: Replace the hard-coded az assignment in the test setup with a
DescribeAvailabilityZones call using ec2Client, select the first available zone,
and use its name for subnet creation. Move this lookup after ec2Client is
initialized and preserve the test’s existing failure handling if no availability
zone is returned.
- Around line 113-115: Refactor the “Hyperfleet sanity” suite into an Ordered
container with shared AWS/Hyperfleet setup in BeforeAll/BeforeEach and cleanup
in AfterEach, then split the monolithic It into focused specs for cluster
readiness, listing, description/API consistency, node-pool readiness, and
node-pool deletion. Add the suite label used by the e2e_test --label-filter,
while preserving the existing resource lifecycle and test ordering.
- Around line 941-972: Update hfPurgeHostedZoneRecords to paginate
ListResourceRecordSets using its continuation markers, collecting deletable
records across all pages. Submit ChangeResourceRecordSets requests in batches
within Route 53 limits, handling and reporting each batch error. Also update the
DeleteHostedZone call site to capture and report its returned error instead of
discarding it.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment thread cmd/create/cluster/hyperfleet.go Outdated
Comment thread cmd/create/machinepool/hyperfleet_run_test.go Outdated
Comment thread cmd/create/machinepool/hyperfleet.go
Comment thread cmd/dlt/cluster/hyperfleet.go Outdated
Comment thread cmd/dlt/cluster/hyperfleet.go
Comment on lines +17 to +30
func ExtractRegion(rawURL string) (string, error) {
u, err := url.Parse(rawURL)
if err != nil {
return "", fmt.Errorf("invalid --hyperfleet-url %q: %w", rawURL, err)
}
region := awsRegionRE.FindString(u.Hostname())
if region == "" {
return "", fmt.Errorf(
"cannot derive AWS region from --hyperfleet-url %q; use --region to specify it explicitly",
rawURL,
)
}
return region, nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether any HyperFleet code path validates the URL scheme.
rg -nP -C4 '(hyperfleet-url|hyperfleetURL|HyperfleetURL|rawURL)' --type=go -g '!vendor/**'
# Inspect how the vendored client treats Config.Host schemes.
fd -t f -p 'rosa-hyperfleet-api/clientset/rest' vendor | head -50
rg -nP -C4 '(Host|https?://|url\.Parse|Scheme)' --type=go -g 'vendor/github.com/openshift-online/rosa-hyperfleet-api/clientset/rest/**'

Repository: openshift/rosa

Length of output: 152


🏁 Script executed:

#!/bin/bash
set -u
printf '%s\n' '--- HyperFleet client files ---'
git ls-files | grep -E 'rosa-hyperfleet-api|hyperfleet.*rest|clientset/rest' || true
printf '%s\n' '--- Host and signing references ---'
rg -n -C4 'type Config struct|Host[[:space:]]+string|Config\.Host|SigV4|SignHTTP|Signing|url\.Parse|http://' . \
  -g '*.go' -g '!vendor/**' -g 'vendor/**' | head -300
printf '%s\n' '--- URL entry points and setters ---'
rg -n -C4 'SetURL|hfExplicitURL|HyperFleet.*URL|hyperfleet-url' --type=go . | head -250

Repository: openshift/rosa

Length of output: 39110


🏁 Script executed:

#!/bin/bash
set -u
for f in \
  vendor/github.com/openshift-online/rosa-hyperfleet-api/clientset/rest/config.go \
  vendor/github.com/openshift-online/rosa-hyperfleet-api/clientset/transport/sigv4.go \
  vendor/github.com/openshift-online/rosa-hyperfleet-api/clientset/hyperfleet.go \
  pkg/hyperfleet/flags.go \
  cmd/rosa/main.go; do
  printf '\n--- %s ---\n' "$f"
  cat -n "$f"
done

Repository: openshift/rosa

Length of output: 18724


🏁 Script executed:

#!/bin/bash
python3 - <<'PY'
from pathlib import Path

endpoint = Path("pkg/hyperfleet/endpoint.go").read_text()
runtime = Path("pkg/rosa/runtime.go").read_text()
transport = Path("vendor/github.com/openshift-online/rosa-hyperfleet-api/clientset/transport/sigv4.go").read_text()
client = Path("vendor/github.com/openshift-online/rosa-hyperfleet-api/clientset/hyperfleet.go").read_text()

assert "url.Parse(rawURL)" in endpoint
assert "u.Scheme" not in endpoint
assert 'Host:      rawURL' in runtime
assert "signer.SignHTTP" in transport
assert "return t.inner.RoundTrip(req)" in transport
assert "Transport: sigv4" in client
assert "Host:    cfg.Host" in client
print("ExtractRegion accepts parsed URLs without a scheme check.")
print("WithHyperFleet forwards rawURL as hfrest.Config.Host.")
print("NewForConfig installs the SigV4 transport for requests using cfg.Host.")
print("SigV4RoundTripper signs requests and forwards them unchanged to the inner transport; an http:// Host therefore uses cleartext HTTP.")
PY

Repository: openshift/rosa

Length of output: 467


Sensitive Data Exposure (CWE-319): Cleartext Transmission of Sensitive Information

Reachability: Internal · Exploitability: Moderate

Reachability path
● Entry
  pkg/rosa/runner_test.go:84
  RuntimeWithHyperFleet
│
▼
● Hop
  pkg/rosa/runner.go:64
  RuntimeWithHyperFleet
│
▼
● Hop
  pkg/rosa/runtime.go:158
  WithHyperFleet: Resolve region: explicit flag/env takes precedence, then extracted from URL.
│
▼
● Sink
  pkg/hyperfleet/endpoint.go

Reject non-HTTPS HyperFleet endpoint URLs.

ExtractRegion does not validate the URL scheme. WithHyperFleet passes rawURL to hfrest.Config.Host, and the client signs requests before forwarding them. An http:// URL therefore sends AWS credentials over cleartext. Validate the scheme when the URL enters the runtime, including URLs loaded through hyperfleet.SetURL.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/hyperfleet/endpoint.go` around lines 17 - 30, Update ExtractRegion to
reject any URL whose parsed scheme is not HTTPS, returning a clear validation
error before deriving the region. Ensure the same validation is applied when
URLs enter the runtime through WithHyperFleet and hyperfleet.SetURL, so all
HyperFleet client configuration paths reject cleartext endpoints.

Comment thread pkg/hyperfleet/roles.go Outdated
Comment thread pkg/rosa/runtime_test.go Outdated
Comment thread pkg/rosa/runtime.go
Comment thread tests/e2e/hyperfleet_sanity_test.go
@gdbranco gdbranco changed the title Feat/rosaeng 62084 ROSAENG-62084 | feat: Integrate Hyperfleet Platform API v2 with the ROSA CLI Aug 5, 2026
@lucasponce

Copy link
Copy Markdown
Contributor

Testing it

$ rosa login --hyperfleet-url https://cwxtdgpqj1.execute-api.us-east-1.amazonaws.com/prod
I: Logged in to Platform API: https://cwxtdgpqj1.execute-api.us-east-1.amazonaws.com/prod

- Portable `perl -pi -e` in Makefile replacing non-portable `sed -i ''`
- `%w` error wrapping in pkg/config/config.go, pkg/hyperfleet/cluster.go, pkg/hyperfleet/nodepool.go
- HTTPS validation at WithHyperFleet entry; SetURL and ExtractRegion reject cleartext HTTP
- whoami endpoint-selection uses cfg.Armed() + ExplicitURL() fallback via useAWSOnly helper
- hyperfleet cluster list checks output.HasFlag() and emits structured JSON/YAML via clusterListItem
- edit machinepool validates replicas within [0, math.MaxInt32] before int32 cast
- delete cluster/machinepool: add confirmFn stub, call before delete; thread cmd.Context() through dispatch
- create machinepool: return after every exitFn(1) to prevent fall-through into invalid state
- create machinepool success tests capture NodePool argument and assert all payload fields
- create cluster: awssdk.ToString for VpcId/AvailabilityZone with missing-field validation

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
cmd/dlt/machinepool/hyperfleet.go (1)

15-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use explicit dependencies for the new command seams.

exitFn, confirmFn, and hfDeleteMachinePool add mutable package state for test control. Pass these collaborators through runHyperfleetDelete or a dependency struct instead. This keeps command dependencies explicit and prevents cross-test interference.

Based on learnings, “Avoid using mutable package-level function variables for new command-level seams.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/dlt/machinepool/hyperfleet.go` around lines 15 - 23, Remove the mutable
package-level seams exitFn, confirmFn, and hfDeleteMachinePool, and make these
collaborators explicit through runHyperfleetDelete or a dedicated dependency
struct. Update the command setup and callers to pass the required exit,
confirmation, and delete-handler dependencies directly, preserving existing
behavior without shared package state.

Sources: Coding guidelines, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/edit/machinepool/hyperfleet_run_test.go`:
- Around line 218-245: Strengthen the test around runHyperfleetEdit by capturing
the NodePool argument passed to nps.EXPECT().Update instead of accepting any
payload, then assert that the updated Spec.NodePool.Replicas equals
math.MaxInt32. Keep the existing setup and execution unchanged, and ensure the
assertion verifies the value was propagated without truncation or leaving the
original replica count.

In `@cmd/list/cluster/hyperfleet_run_test.go`:
- Around line 42-50: Update the captureStdout helper to handle errors from
os.Pipe, w.Close, and io.ReadAll instead of discarding them, using the test’s
established failure mechanism. Register cleanup to restore os.Stdout before
invoking f so it is restored even if the callback panics, while preserving
captured output behavior.

---

Nitpick comments:
In `@cmd/dlt/machinepool/hyperfleet.go`:
- Around line 15-23: Remove the mutable package-level seams exitFn, confirmFn,
and hfDeleteMachinePool, and make these collaborators explicit through
runHyperfleetDelete or a dedicated dependency struct. Update the command setup
and callers to pass the required exit, confirmation, and delete-handler
dependencies directly, preserving existing behavior without shared package
state.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 15726836-f131-4e96-ba84-7b00ab43fa04

📥 Commits

Reviewing files that changed from the base of the PR and between 0808cae and 3fb1fec.

⛔ Files ignored due to path filters (1)
  • assets/bindata.go is excluded by !assets/bindata.go
📒 Files selected for processing (31)
  • Makefile
  • cmd/create/cluster/hyperfleet.go
  • cmd/create/cluster/hyperfleet_test.go
  • cmd/create/machinepool/hyperfleet.go
  • cmd/create/machinepool/hyperfleet_run_test.go
  • cmd/dlt/cluster/cmd.go
  • cmd/dlt/cluster/hyperfleet.go
  • cmd/dlt/cluster/hyperfleet_run_test.go
  • cmd/dlt/cluster/hyperfleet_test.go
  • cmd/dlt/machinepool/cmd.go
  • cmd/dlt/machinepool/hyperfleet.go
  • cmd/dlt/machinepool/hyperfleet_run_test.go
  • cmd/dlt/machinepool/hyperfleet_test.go
  • cmd/edit/cluster/hyperfleet.go
  • cmd/edit/cluster/hyperfleet_run_test.go
  • cmd/edit/machinepool/hyperfleet.go
  • cmd/edit/machinepool/hyperfleet_run_test.go
  • cmd/list/cluster/hyperfleet.go
  • cmd/list/cluster/hyperfleet_run_test.go
  • cmd/whoami/cmd.go
  • cmd/whoami/cmd_test.go
  • pkg/config/config.go
  • pkg/hyperfleet/cluster.go
  • pkg/hyperfleet/endpoint.go
  • pkg/hyperfleet/flags.go
  • pkg/hyperfleet/hyperfleet_test.go
  • pkg/hyperfleet/nodepool.go
  • pkg/hyperfleet/roles.go
  • pkg/rosa/runtime.go
  • pkg/rosa/runtime_test.go
  • tests/e2e/hyperfleet_sanity_test.go
🚧 Files skipped from review as they are similar to previous changes (19)
  • cmd/dlt/machinepool/hyperfleet_test.go
  • cmd/dlt/machinepool/cmd.go
  • Makefile
  • pkg/hyperfleet/cluster.go
  • cmd/dlt/cluster/hyperfleet.go
  • cmd/dlt/cluster/hyperfleet_test.go
  • pkg/hyperfleet/nodepool.go
  • cmd/dlt/cluster/hyperfleet_run_test.go
  • cmd/create/machinepool/hyperfleet_run_test.go
  • pkg/hyperfleet/hyperfleet_test.go
  • cmd/edit/cluster/hyperfleet.go
  • cmd/create/machinepool/hyperfleet.go
  • cmd/edit/machinepool/hyperfleet.go
  • cmd/dlt/cluster/cmd.go
  • cmd/create/cluster/hyperfleet.go
  • pkg/config/config.go
  • cmd/whoami/cmd.go
  • pkg/rosa/runtime.go
  • tests/e2e/hyperfleet_sanity_test.go

Comment on lines +218 to +245
It("accepts math.MaxInt32 as a valid replica count", func() {
ctrl := gomock.NewController(GinkgoT())
_, nodePools, np := func() (*hfmocks.MockInterface, *hfmocks.MockNodePoolInterface, *v1alpha1.NodePool) {
hf, clusters, nps := newEditMPMocks(ctrl)
replicas := int32(3)
np := &v1alpha1.NodePool{
ObjectMeta: metav1.ObjectMeta{Name: "my-np", UID: types.UID("np-uid-1")},
Spec: v1alpha1.NodePoolSpec{
NodePool: hypershiftv1beta1.NodePoolSpec{Replicas: &replicas},
},
}
clusters.EXPECT().List(gomock.Any(), gomock.Any()).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{{
ObjectMeta: metav1.ObjectMeta{Name: "cluster1", UID: types.UID("cluster-uid")},
}}}, nil)
nps.EXPECT().List(gomock.Any(), gomock.Any()).Return(
&v1alpha1.NodePoolList{Items: []v1alpha1.NodePool{*np}}, nil)
nps.EXPECT().Get(gomock.Any(), "np-uid-1", gomock.Any()).Return(np, nil)
nps.EXPECT().Update(gomock.Any(), gomock.Any(), gomock.Any()).Return(np, nil)
t.RosaRuntime.HyperFleetClient = hf
return hf, nps, np
}()
_ = nodePools
_ = np

runHyperfleetEdit(t.RosaRuntime,
&EditMachinepoolUserOptions{machinepool: "my-np", replicas: math.MaxInt32},
makeEditCmd("5"), nil)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the replica value passed to Update.

The mock accepts any update payload. The test passes if runHyperfleetEdit truncates math.MaxInt32 or leaves the existing value unchanged. Capture the updated NodePool and assert that Spec.NodePool.Replicas equals math.MaxInt32.

As per path instructions, “Flag weak tests that only restate implementation.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/edit/machinepool/hyperfleet_run_test.go` around lines 218 - 245,
Strengthen the test around runHyperfleetEdit by capturing the NodePool argument
passed to nps.EXPECT().Update instead of accepting any payload, then assert that
the updated Spec.NodePool.Replicas equals math.MaxInt32. Keep the existing setup
and execution unchanged, and ensure the assertion verifies the value was
propagated without truncation or leaving the original replica count.

Sources: Coding guidelines, Path instructions

Comment on lines +42 to +50
captureStdout := func(f func()) string {
r, w, _ := os.Pipe()
orig := os.Stdout
os.Stdout = w
f()
w.Close()
os.Stdout = orig
out, _ := io.ReadAll(r)
return string(out)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Handle stdout capture errors and always restore os.Stdout.

os.Pipe, w.Close, and io.ReadAll errors are discarded. A callback panic also leaves the process stdout redirected. Check each I/O error and restore stdout with cleanup before invoking the callback.

As per path instructions, “Never ignore error returns.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/list/cluster/hyperfleet_run_test.go` around lines 42 - 50, Update the
captureStdout helper to handle errors from os.Pipe, w.Close, and io.ReadAll
instead of discarding them, using the test’s established failure mechanism.
Register cleanup to restore os.Stdout before invoking f so it is restored even
if the callback panics, while preserving captured output behavior.

Source: Path instructions

…VPC teardown

SGs created by the cluster controller and ingress controller are not removed
when the cluster is deleted, causing DeleteVpc to fail silently and leak the
VPC. Add hfDeleteVPCSecurityGroups (same pattern as hfDeleteAvailableENIs)
and call it in the cluster DeferCleanup after ENI cleanup.
…rdown

ALB/NLB deletion is async; security groups they reference cannot be deleted
until AWS fully removes the load balancer. Add hfWaitVPCClassicLoadBalancersDeleted
and hfWaitVPCLoadBalancersDeleted polls after each LB delete step, and add
hfDeleteVPCSecurityGroups to remove controller-created SGs before DeleteVpc.
Also verify VPC deletion via hfWaitVPCDeleted and log errors on DeleteVpc failure.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants