Skip to content

HYPERFLEET-1247 - fix: distinguish broken URL 404 from resource 404#211

Open
rafabene wants to merge 1 commit into
openshift-hyperfleet:mainfrom
rafabene:HYPERFLEET-1247-distinguish-precondition-404-from-force-delete
Open

HYPERFLEET-1247 - fix: distinguish broken URL 404 from resource 404#211
rafabene wants to merge 1 commit into
openshift-hyperfleet:mainfrom
rafabene:HYPERFLEET-1247-distinguish-precondition-404-from-force-delete

Conversation

@rafabene

@rafabene rafabene commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adapter now checks the RFC 9457 error code on 404 responses to distinguish broken endpoints from force-deleted resources
  • A 404 with code HYPERFLEET-NTF-000 (catch-all, no route matched) is treated as a configuration error
  • Any other 404 (including missing/stripped response body) defaults to resource-not-found — graceful handling
  • Added IsResourceNotFound() / IsResourceNotFoundError() to pkg/errors/api_error.go
  • Updated test fixtures to use RFC 9457 format
  • Updated adapter-authoring-guide documentation

Dependencies

Test plan

  • Unit tests for IsResourceNotFound with NTF-000/NTF-002/NTF-003/empty body/unparseable body
  • Unit tests for IsResourceNotFoundError with direct and wrapped errors
  • Executor test: broken URL 404 (NTF-000) results in error status
  • Executor test: resource not found 404 (NTF-002) continues graceful handling
  • All existing 404 tests still pass
  • make lint passes with 0 issues

Fixes: https://redhat.atlassian.net/browse/HYPERFLEET-1247

@openshift-ci openshift-ci Bot requested review from jsell-rh and ldornele June 24, 2026 18:21
@openshift-ci

openshift-ci Bot commented Jun 24, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign pnguyen44 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

404 handling now classifies RFC 9457 problem-details responses by error code and trace_id. pkg/errors adds IsResourceNotFound() and IsResourceNotFoundError(err). internal/executor uses that classification for preconditions and post-actions. Tests, fixtures, and the adapter guide now use the problem-details 404 shape.

Sequence Diagram(s)

sequenceDiagram
  participant Executor
  participant APIErrors
  participant APIError
  participant ExecutorState
  Executor->>APIErrors: IsResourceNotFoundError(err)
  APIErrors->>APIError: IsResourceNotFound()
  APIError->>APIError: parseProblemDetails()
  APIError-->>APIErrors: 404 + allowed code
  APIErrors-->>Executor: true
  Executor->>ExecutorState: skip or stop gracefully
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 10 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (10 passed)
Check name Status Explanation
Title check ✅ Passed It clearly describes the main change: distinguishing broken URL 404s from resource-not-found 404s.
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.
Sec-02: Secrets In Log Output ✅ Passed No non-test log/print calls in touched runtime code include token/password/credential/secret fields or interpolated strings; only event/phase/status metadata is logged (CWE-532).
No Hardcoded Secrets ✅ Passed PASS: No CWE-798 indicators in touched code; no apiKey/secret/token/password string literals, private keys, or embedded creds. Only docs/test fixture placeholders.
No Weak Cryptography ✅ Passed No banned primitives, ECB, custom crypto, or secret/HMAC comparisons were added; touched Go code only parses JSON and compares RFC 9457 codes. CWE-327 not introduced.
No Injection Vectors ✅ Passed No CWE-89/78/79/502 sinks in touched prod code; only fmt.Sprintf in logs/tests and json.Unmarshal of response bodies.
No Privileged Containers ✅ Passed PASS: PR only changes docs/Go/JSON fixtures; no Kubernetes/OpenShift manifests, Helm templates, or Dockerfiles were modified, so no privileged-container finding (CWE-284).
No Pii Or Sensitive Data In Logs ✅ Passed PASS: no new logs; no CWE-532/CWE-200 exposure in added code. Only 404 classification changed, with no bodies/PII/hostnames emitted.
Description check ✅ Passed The description matches the patch: it explains the 404 classification change, new helpers, updated fixtures, docs, and tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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

@hyperfleet-ci-bot

hyperfleet-ci-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

Risk Score: 1 — risk/low

Signal Detail Points
PR size 344 lines (>200) +1
Sensitive paths none +0
Test coverage Tests cover changed packages +0

Computed by hyperfleet-risk-scorer

@rafabene rafabene force-pushed the HYPERFLEET-1247-distinguish-precondition-404-from-force-delete branch from e0d0094 to 6486532 Compare June 24, 2026 18:29

@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: 1

🧹 Nitpick comments (1)
internal/executor/executor_test.go (1)

1672-1707: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Tests assert failure status but never prove the graceful branch was bypassed.

Both tests only check StatusFailed / non-empty errors. A regression that flips the trace_id gate could still leave the broken-endpoint path failing for an unrelated reason and these would pass. Pin the discriminator explicitly:

♻️ Lock in that the broken-URL 404 is NOT treated as resource-not-found
 	assert.NotEmpty(t, result.Errors,
 		"errors should be recorded for a broken URL 404")
+	assert.NotEqual(t, ResourceNotFoundReason, result.SkipReason,
+		"broken URL 404 must NOT be classified as resource-not-found")
🤖 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 `@internal/executor/executor_test.go` around lines 1672 - 1707, The two tests
in executor_test.go only assert failure, so they do not prove the broken-URL 404
path was routed away from the graceful resource-not-found handling. Update
TestBrokenURL404_... and TestPostActionBrokenURL404_ReportsError to explicitly
assert the error/result is not classified as the graceful not-found case (for
example by checking the relevant error category or absence of the
resource-not-found signal on result.Errors / PhasePostActions), using the
existing helpers like new404PostActionConfig, mockBrokenEndpoint404Response, and
exec.Execute to lock in the discriminator.
🤖 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 `@pkg/errors/api_error_test.go`:
- Around line 84-88: The table-driven assertions in api_error_test should
include descriptive failure messages instead of bare assert.Equal calls. Update
the affected tests that use t.Run(tt.name) so each assert.Equal includes tt.name
or a similar case-specific message, making it clear which expectation failed
without needing to cross-reference the table entry. Apply the same change to the
other shared assertion block noted in the review, using the existing test names
and error-checking helpers like IsResourceNotFound().

---

Nitpick comments:
In `@internal/executor/executor_test.go`:
- Around line 1672-1707: The two tests in executor_test.go only assert failure,
so they do not prove the broken-URL 404 path was routed away from the graceful
resource-not-found handling. Update TestBrokenURL404_... and
TestPostActionBrokenURL404_ReportsError to explicitly assert the error/result is
not classified as the graceful not-found case (for example by checking the
relevant error category or absence of the resource-not-found signal on
result.Errors / PhasePostActions), using the existing helpers like
new404PostActionConfig, mockBrokenEndpoint404Response, and exec.Execute to lock
in the discriminator.
🪄 Autofix (Beta)

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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 84938ea9-ec86-4db7-8f77-0613dcddd643

📥 Commits

Reviewing files that changed from the base of the PR and between 2d82a5b and e0d0094.

📒 Files selected for processing (7)
  • docs/adapter-authoring-guide.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • pkg/errors/api_error.go
  • pkg/errors/api_error_test.go
  • test/testdata/dryrun/dryrun-404-api-responses.json
  • test/testdata/dryrun/dryrun-post-action-404-api-responses.json
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)

Comment thread pkg/errors/api_error_test.go
@rafabene rafabene changed the title HYPERFLEET-1247 - fix: distinguish broken precondition URL 404 from force-deleted resource 404 HYPERFLEET-1247 - fix: distinguish broken URL 404 from resource 404 Jun 24, 2026
@rafabene rafabene force-pushed the HYPERFLEET-1247-distinguish-precondition-404-from-force-delete branch 3 times, most recently from 9f0d9e3 to 3c62abf Compare June 24, 2026 21:01

@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: 1

🤖 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 `@pkg/errors/api_error.go`:
- Around line 99-113: The IsResourceNotFound method in APIError is too strict
because it only returns true when parseProblemDetails succeeds and the RFC 9457
code matches, which misclassifies valid 404s when the body is missing or
rewritten. Update the logic so a plain IsNotFound() is treated as
resource-not-found by default, and only return false when you have a positive
signal that the endpoint itself is wrong; use the existing APIError,
parseProblemDetails, and resourceNotFoundCode symbols to adjust the fallback
behavior.
🪄 Autofix (Beta)

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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: f11709df-6c93-4cd5-8f6c-c79903c2432c

📥 Commits

Reviewing files that changed from the base of the PR and between bcdfbe9 and 9f0d9e3.

📒 Files selected for processing (7)
  • docs/adapter-authoring-guide.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • pkg/errors/api_error.go
  • pkg/errors/api_error_test.go
  • test/testdata/dryrun/dryrun-404-api-responses.json
  • test/testdata/dryrun/dryrun-post-action-404-api-responses.json
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
✅ Files skipped from review due to trivial changes (1)
  • test/testdata/dryrun/dryrun-404-api-responses.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/executor/executor.go
  • test/testdata/dryrun/dryrun-post-action-404-api-responses.json
  • internal/executor/executor_test.go

Comment thread pkg/errors/api_error.go
@rafabene rafabene force-pushed the HYPERFLEET-1247-distinguish-precondition-404-from-force-delete branch from 3c62abf to 4c33513 Compare June 24, 2026 21:05

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/adapter-authoring-guide.md (1)

790-810: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore the trace_id gate here.

This section still reduces the decision to the RFC 9457 code, but the new contract treats empty/missing trace_id as the broken-URL case. Without that, a malformed 404 can still be documented as a graceful force-delete skip.

Suggested wording
- - **Resource not found** (error code `HYPERFLEET-NTF-002` or `HYPERFLEET-NTF-003` in the RFC 9457 response body): the resource handler processed the request but the resource was deleted. The adapter handles this gracefully — resources are skipped and post-actions still execute.
- - **Broken endpoint** (any other error code, e.g. `HYPERFLEET-NTF-001`): the precondition URL itself is misconfigured. The adapter treats this as an error and reports failure status.
+ - **Resource not found** (RFC 9457 body with `HYPERFLEET-NTF-002` or `HYPERFLEET-NTF-003` and a populated `trace_id`): the resource handler processed the request but the resource was deleted. The adapter handles this gracefully — resources are skipped and post-actions still execute.
+ - **Broken endpoint** (empty/missing `trace_id`, or any other error code such as `HYPERFLEET-NTF-001`): the precondition URL itself is misconfigured. The adapter treats this as an error and reports failure 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 `@docs/adapter-authoring-guide.md` around lines 790 - 810, Restore the
`trace_id` check in this 404 handling section so the graceful skip path only
applies when the RFC 9457 response includes a valid trace identifier; an empty
or missing `trace_id` must be documented as the broken-endpoint case even if the
`code` looks like `HYPERFLEET-NTF-002` or `HYPERFLEET-NTF-003`. Update the
wording around the adapter’s `resourcesSkipped` and `skipReason` behavior to
make clear that `ResourceNotFound` is only set for legitimate force-delete
responses with the expected `trace_id`, while malformed 404s still fail the
precondition or post-action flow.

Source: Linked repositories

🤖 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 `@docs/adapter-authoring-guide.md`:
- Line 1761: Broaden the Appendix D 404 guidance for the status-path check so it
covers nodepool lookups, not just the current HYPERFLEET-NTF-002 case. In the
table row describing post-action API calls and the status endpoints, update the
wording to allow both cluster and nodepool status failures by referencing the
status endpoint rules in the Appendix D section, especially the NodePool
statuses path, and make the error-code guidance consistent with
HYPERFLEET-NTF-003 as a valid nodepool-not-found outcome.

---

Outside diff comments:
In `@docs/adapter-authoring-guide.md`:
- Around line 790-810: Restore the `trace_id` check in this 404 handling section
so the graceful skip path only applies when the RFC 9457 response includes a
valid trace identifier; an empty or missing `trace_id` must be documented as the
broken-endpoint case even if the `code` looks like `HYPERFLEET-NTF-002` or
`HYPERFLEET-NTF-003`. Update the wording around the adapter’s `resourcesSkipped`
and `skipReason` behavior to make clear that `ResourceNotFound` is only set for
legitimate force-delete responses with the expected `trace_id`, while malformed
404s still fail the precondition or post-action flow.
🪄 Autofix (Beta)

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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 7507b0d2-164a-4807-8273-62573cde289e

📥 Commits

Reviewing files that changed from the base of the PR and between 9f0d9e3 and 3c62abf.

📒 Files selected for processing (7)
  • docs/adapter-authoring-guide.md
  • internal/executor/executor.go
  • internal/executor/executor_test.go
  • pkg/errors/api_error.go
  • pkg/errors/api_error_test.go
  • test/testdata/dryrun/dryrun-404-api-responses.json
  • test/testdata/dryrun/dryrun-post-action-404-api-responses.json
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
🚧 Files skipped from review as they are similar to previous changes (6)
  • test/testdata/dryrun/dryrun-post-action-404-api-responses.json
  • test/testdata/dryrun/dryrun-404-api-responses.json
  • pkg/errors/api_error.go
  • pkg/errors/api_error_test.go
  • internal/executor/executor.go
  • internal/executor/executor_test.go

Comment thread docs/adapter-authoring-guide.md Outdated
Parse the RFC 9457 response body on 404 errors to check for a populated
trace_id. A populated trace_id confirms the endpoint is valid and the
resource was genuinely not found (force-delete), while an empty or absent
trace_id indicates a misconfigured URL that should be reported as an error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant