Skip to content

TRT-2768: Import /payload job results from PRs into postgres#3728

Open
dgoodwin wants to merge 6 commits into
openshift:mainfrom
dgoodwin:import-pr-payload-jobs
Open

TRT-2768: Import /payload job results from PRs into postgres#3728
dgoodwin wants to merge 6 commits into
openshift:mainfrom
dgoodwin:import-pr-payload-jobs

Conversation

@dgoodwin

@dgoodwin dgoodwin commented Jul 2, 2026

Copy link
Copy Markdown
Contributor
  • Core change here is to begin importing jobs run in a PR via /payload commands as if they were presubmit data.
  • Involves a small hack to normalize the prow job name openshift-origin-31301-ci-5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-rt-upgrade by removing the PR number, so any /payload job run of this job gets the same job name: openshift-origin-ci-5.0-upgrade-from-stable-4.22-e2e-gcp-ovn-rt-upgrade
  • Ports the api endpoint for test_results for a PR to now use postgresql instead of BQ.
  • This positions the endpoint as cost effective to roll out a risk analysis agent across many repositories, which will examine PR test results for anything suspicious and related to the code change, without worrying about bigquery costs.
    • In my testing, the response for a 2 week query of presubmit data for one PR in the prod db is now very fast with the sharding.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Expanded synthetic seeding to include Presubmits test data.
    • Added end-to-end coverage for /api/pull_requests/test_results (defaults, filters, date ranges, and error/empty states).
  • Bug Fixes

    • Improved /payload sub-job handling: they’re rewritten/routed as presubmit-style entries with more reliable job/variant matching.
    • Payload presubmit jobs no longer generate a TestGrid link where it doesn’t apply.
  • API Updates

    • /api/pull_requests/test_results now always uses PostgreSQL, with updated response fields and filtering behavior (failures by default, optional successes and latest_sha_only).

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@dgoodwin dgoodwin changed the title Import /payload job results from PRs TRT-2768: Import /payload job results from PRs into postgres Jul 2, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 2, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 2, 2026

Copy link
Copy Markdown

@dgoodwin: This pull request references TRT-2768 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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: 832cf3a3-fed1-48a6-b33b-a2db2b2f2562

📥 Commits

Reviewing files that changed from the base of the PR and between 966df4b and d5763a0.

📒 Files selected for processing (2)
  • pkg/api/prtestresults.go
  • test/e2e/pull_requests_test.go

Walkthrough

This PR normalizes payload Prow jobs, seeds matching presubmit data, and switches PR test results retrieval and serving to PostgreSQL-backed logic.

Changes

Payload job and PR results flow

Layer / File(s) Summary
Payload job normalization
pkg/dataloader/prowloader/bigqueryjobs.go
Detects /payload sub-jobs, rewrites their job metadata, and emits Prow jobs with computed type and name.
Payload routing and storage updates
pkg/dataloader/prowloader/prow.go
Short-circuits payload sub-jobs into presubmit handling, rewrites payload-aware variants, and changes TestGridURL behavior for payload presubmits.
Synthetic presubmit seeding
cmd/sippy/seed_data.go
Adds Presubmits to the synthetic release set and seeds presubmit pull requests, runs, tests, and outputs.
PostgreSQL PR test results API
pkg/api/prtestresults.go, pkg/sippyserver/server.go
Replaces PR test results retrieval with PostgreSQL-backed querying, updates request/response handling, and serves the endpoint from the local DB.
Endpoint e2e coverage
test/e2e/pull_requests_test.go
Adds e2e coverage for default filtering, include-successes, SHA filtering, default dates, missing params, multiple PRs, and empty results.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 20 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Test Coverage For New Features ⚠️ Warning Only e2e coverage exists for /api/pull_requests/test_results; no unit tests cover new GetPRTestResults/PrintPRTestResultsJSON or payload normalization helpers. Add unit/regression tests for payload job normalization and PR test-result query/handler logic, or refactor pure parts into testable helpers.
✅ Passed checks (20 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: importing /payload PR job results into PostgreSQL.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Go Error Handling ✅ Passed Changed Go code wraps query errors with %w, handles bad params explicitly, and adds no panic or ignored-error sites in the commit.
Sql Injection Prevention ✅ Passed GetPRTestResults uses GORM placeholders for org/repo/PR/date/status/LIKE filters; no SQL text is built from request values.
Excessive Css In React Should Use Styles ✅ Passed No React components or inline CSS changes are present; the commit only touches Go backend/API and tests.
Single Responsibility And Clear Naming ✅ Passed PASS: The new names are specific, and the added functions/structs stay centered on one concept each (payload import, presubmit seeding, PR test results).
Feature Documentation ✅ Passed No relevant docs/features page covers the changed PR test_results/payload-ingestion feature, and no feature doc was modified.
Stable And Deterministic Test Names ✅ Passed The new test names and subtest titles are static strings; no dynamic IDs, dates, or generated values appear in titles.
Test Structure And Quality ✅ Passed PASS: The new tests are isolated HTTP checks, create no resources, use no waits, and include assertion messages; no Ginkgo lifecycle issues apply.
Microshift Test Compatibility ✅ Passed The added tests are plain HTTP endpoint checks; they use no OpenShift-only APIs/resources and include no MicroShift-sensitive assumptions.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The new e2e tests only call the PR test_results API and assert returned fields/statuses; they don't inspect nodes, scheduling, topology, or HA behavior.
Topology-Aware Scheduling Compatibility ✅ Passed The PR only changes API/query logic and e2e tests; no deployment manifests, operator code, or controller scheduling constraints were added.
Ote Binary Stdout Contract ✅ Passed PASS: The changed code adds no stdout writes in main/init/TestMain or suite setup; it only uses logrus logging and HTTP response writes.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The new e2e tests only call the local Sippy API; the helper uses net.JoinHostPort and localhost, with no IPv4 literals or public-internet dependencies.
No-Weak-Crypto ✅ Passed No weak cryptographic algorithms (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB), custom crypto implementations, or unsafe secret comparisons detected in the modified files.
Container-Privileges ✅ Passed Checked the PR diff and changed manifest files; no privileged, hostPID/hostNetwork/hostIPC, SYS_ADMIN, root, or allowPrivilegeEscalation settings were added.
No-Sensitive-Data-In-Logs ✅ Passed New logs only contain public job/PR metadata (org/repo/PR number/job names/counts); no passwords, tokens, PII, customer data, or hostnames are logged.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci openshift-ci Bot requested review from neisw and petr-muller July 2, 2026 14:18
@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dgoodwin

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 Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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)
pkg/dataloader/prowloader/prow.go (1)

1002-1035: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep payload TestGridURL suppressed on updates too.

New payload jobs skip TestGridURL, but the existing-job path later backfills it whenever the field is empty. That makes the payload-specific behavior disappear after a subsequent import.

Proposed fix
-		if len(dbProwJob.TestGridURL) == 0 {
+		if isPayloadPresubmit && dbProwJob.TestGridURL != "" {
+			dbProwJob.TestGridURL = ""
+			saveDB = true
+		} else if !isPayloadPresubmit && len(dbProwJob.TestGridURL) == 0 {
 			dbProwJob.TestGridURL = pl.generateTestGridURL(release, pj.Spec.Job).String()
 			if len(dbProwJob.TestGridURL) > 0 {
 				saveDB = true
 			}
🤖 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/dataloader/prowloader/prow.go` around lines 1002 - 1035, The existing-job
update path in the prow loader is backfilling TestGridURL even for payload jobs,
which breaks the payload-specific suppression. Update the logic in the prow job
import flow around pl.generateTestGridURL and dbProwJob handling so TestGridURL
is only populated for non-payload jobs, both on insert and on subsequent
updates, and leave empty values untouched for payload imports.
🧹 Nitpick comments (2)
pkg/dataloader/prowloader/prow.go (1)

975-1020: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add regression tests for payload variant and persistence behavior.

Please cover releaseJobName-based variant identification, release variant rewriting to Presubmits, create-vs-update behavior, and TestGridURL suppression. As per coding guidelines, modified Go functionality should include test coverage.

🤖 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/dataloader/prowloader/prow.go` around lines 975 - 1020, Add regression
tests around prow job persistence in the prow loader to cover the new payload
handling in identifyVariants and the dbProwJob create/update path. Verify that
when pj.Annotations["releaseJobName"] is present and pj.Spec.Refs is non-nil,
the variant name comes from releaseJobName, any release variant is rewritten to
Presubmits, and TestGridURL is left empty; also cover the non-payload case where
generateTestGridURL is used. Include both the new ProwJob creation path and the
existing cache/update path in the prowJobCache logic so the behavior stays
covered.

Source: Coding guidelines

pkg/dataloader/prowloader/bigqueryjobs.go (1)

132-176: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Add regression coverage for the payload transformation contract.

This new branch rewrites identity, type, annotations, and PR refs. Please add tests for stable-name stripping, fallback naming, aggregator skipping, and comma-normalized releaseJobName values. As per coding guidelines, new or modified functionality should include test coverage.

🤖 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/dataloader/prowloader/bigqueryjobs.go` around lines 132 - 176, Add
regression tests for the payload sub-job transformation in the bigquery job
ingestion path, covering the branch that rewrites `jobName` and `jobType` when
`releaseJobName` is present. Exercise stable-name stripping from `bqjr.JobName`,
the `payload-pr-` fallback when the PR prefix cannot be removed, skipping jobs
whose names start with `aggregator-`, and normalization of comma-separated
`releaseJobName` values. Add assertions around the resulting `prow.ProwJob`
fields produced by the `prowJobs` population logic so the identity and type
contract stays covered.

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 `@pkg/dataloader/prowloader/bigqueryjobs.go`:
- Around line 139-156: The fallback path in bigqueryjobs.go uses the raw
releaseJobName annotation, which can include comma-delimited suffixes and lead
to incorrect canonical job names. Normalize releaseJobName the same way the
BigQuery query-generator does by trimming everything after the first comma
before building stableName or any downstream variant identifiers. Apply this in
the releaseJobName handling block near the stableName fallback so all consumers
see the normalized value.

---

Outside diff comments:
In `@pkg/dataloader/prowloader/prow.go`:
- Around line 1002-1035: The existing-job update path in the prow loader is
backfilling TestGridURL even for payload jobs, which breaks the payload-specific
suppression. Update the logic in the prow job import flow around
pl.generateTestGridURL and dbProwJob handling so TestGridURL is only populated
for non-payload jobs, both on insert and on subsequent updates, and leave empty
values untouched for payload imports.

---

Nitpick comments:
In `@pkg/dataloader/prowloader/bigqueryjobs.go`:
- Around line 132-176: Add regression tests for the payload sub-job
transformation in the bigquery job ingestion path, covering the branch that
rewrites `jobName` and `jobType` when `releaseJobName` is present. Exercise
stable-name stripping from `bqjr.JobName`, the `payload-pr-` fallback when the
PR prefix cannot be removed, skipping jobs whose names start with `aggregator-`,
and normalization of comma-separated `releaseJobName` values. Add assertions
around the resulting `prow.ProwJob` fields produced by the `prowJobs` population
logic so the identity and type contract stays covered.

In `@pkg/dataloader/prowloader/prow.go`:
- Around line 975-1020: Add regression tests around prow job persistence in the
prow loader to cover the new payload handling in identifyVariants and the
dbProwJob create/update path. Verify that when pj.Annotations["releaseJobName"]
is present and pj.Spec.Refs is non-nil, the variant name comes from
releaseJobName, any release variant is rewritten to Presubmits, and TestGridURL
is left empty; also cover the non-payload case where generateTestGridURL is
used. Include both the new ProwJob creation path and the existing cache/update
path in the prowJobCache logic so the behavior stays covered.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: c6a2fb07-147f-4982-809e-c476b82a5c71

📥 Commits

Reviewing files that changed from the base of the PR and between c4d96fa and ce37c2e.

📒 Files selected for processing (2)
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go

Comment thread pkg/dataloader/prowloader/bigqueryjobs.go
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

dgoodwin and others added 4 commits July 2, 2026 11:37
…kfill

Normalize releaseJobName by stripping comma-delimited suffixes to match
the BigQuery query generator behavior. Also prevent the TestGridURL
update path from backfilling a URL on payload presubmit jobs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
start_date and end_date are now optional (default to last 14 days).
Added sha query param to filter results to a specific commit.
Updated e2e tests accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
pkg/api/prtestresults.go (1)

42-124: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add test coverage for GetPRTestResults and PrintPRTestResultsJSON functions.

Per coding guidelines, new functionality requires unit tests. The PostgreSQL query in GetPRTestResults (lines 42–124) contains complex JOIN logic, conditional filtering, and date bounds that should be covered by tests. The HTTP handler PrintPRTestResultsJSON (lines 126–220) should also be tested. Add tests covering: default failure-only results, include_successes pattern matching, output joins, date boundary filtering, and invalid input handling.

🤖 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/api/prtestresults.go` around lines 42 - 124, Add unit tests for
GetPRTestResults and PrintPRTestResultsJSON to cover the new query and handler
behavior. Focus on GetPRTestResults’s JOIN/filter logic by testing default
failure-only results, includeSuccesses pattern matching, output join population,
and start/end date boundary handling using the function name and its
query-building flow to locate the code. Also add handler tests for
PrintPRTestResultsJSON to verify valid responses and invalid input handling,
ensuring the JSON endpoint exercises the same PR test result path.

Source: Coding guidelines

🧹 Nitpick comments (1)
cmd/sippy/seed_data.go (1)

903-963: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use status constants and align the comments with the seeded tests.

The seed rows use raw status integers and two comments describe different tests than the TestID actually assigned. This makes the API fixture easy to misread.

Proposed cleanup
-		// Failure result for install test
+		// Seed an install failure so the default PR test-results view has data.
 		failResult := models.ProwJobRunTest{
@@
-			Status:              12,
+			Status:              int(v1.TestStatusFailure),
@@
-		// Success result for install test (same test, different run aspect)
+		// Seed a network success so include_successes exercises non-failure statuses.
 		successResult := models.ProwJobRunTest{
@@
-			Status:              1,
+			Status:              int(v1.TestStatusSuccess),
@@
-		// Flake result for network test on a different test
+		// Seed an install flake so include_successes exercises flakes.
 		flakeResult := models.ProwJobRunTest{
@@
-			Status:              13,
+			Status:              int(v1.TestStatusFlake),

As per coding guidelines, “Follow idiomatic Go practices” and keep comments minimal/helpful.

🤖 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/sippy/seed_data.go` around lines 903 - 963, The seeded ProwJobRunTest
rows are hard to read because they use raw status integers and the comments
don’t match the actual TestID being set. Update the seeding logic to use the
existing status constants instead of literal values, and revise or remove the
comments so they accurately describe each result created via failResult,
successResult, and flakeResult with installTestID/networkTestID. Keep the
fixture idiomatic and minimal so the test data is self-explanatory.

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 `@pkg/api/prtestresults.go`:
- Around line 81-85: Normalize and validate include_successes before
constructing the query in the prtestresults filtering logic, since the current
loop in the query builder can produce unrestricted LIKE matches. In the code
around the conditions assembly, trim out empty entries, enforce a reasonable
maximum count and per-item length, and escape SQL LIKE wildcard characters
before passing patterns into the Or("t.name LIKE ?", ...) clauses. Apply the
same hardening to the related include_successes handling referenced by the
second occurrence so the endpoint only accepts safe, bounded values.
- Around line 210-215: The error handling in the PR test results path is leaking
backend error details to clients. Update the error branch in the PR test results
handler to keep the detailed failure only in the `log.WithError(err).Error(...)`
call and return a generic HTTP 500 JSON body from `RespondWithJSON` without
embedding `err` in the `message` field.

---

Outside diff comments:
In `@pkg/api/prtestresults.go`:
- Around line 42-124: Add unit tests for GetPRTestResults and
PrintPRTestResultsJSON to cover the new query and handler behavior. Focus on
GetPRTestResults’s JOIN/filter logic by testing default failure-only results,
includeSuccesses pattern matching, output join population, and start/end date
boundary handling using the function name and its query-building flow to locate
the code. Also add handler tests for PrintPRTestResultsJSON to verify valid
responses and invalid input handling, ensuring the JSON endpoint exercises the
same PR test result path.

---

Nitpick comments:
In `@cmd/sippy/seed_data.go`:
- Around line 903-963: The seeded ProwJobRunTest rows are hard to read because
they use raw status integers and the comments don’t match the actual TestID
being set. Update the seeding logic to use the existing status constants instead
of literal values, and revise or remove the comments so they accurately describe
each result created via failResult, successResult, and flakeResult with
installTestID/networkTestID. Keep the fixture idiomatic and minimal so the test
data is self-explanatory.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: ad4774e2-3201-48f9-a252-0e2a78f221d5

📥 Commits

Reviewing files that changed from the base of the PR and between ce37c2e and cc2b47b.

📒 Files selected for processing (5)
  • cmd/sippy/seed_data.go
  • pkg/api/prtestresults.go
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go
  • pkg/sippyserver/server.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/dataloader/prowloader/bigqueryjobs.go
  • pkg/dataloader/prowloader/prow.go

Comment thread pkg/api/prtestresults.go
Comment on lines +81 to +85
conditions := dbc.DB.Where("pjrt.status = ?", int(sippyprocessingv1.TestStatusFailure))
for _, pattern := range includeSuccesses {
conditions = conditions.Or("t.name LIKE ?", "%"+pattern+"%")
}
whereClause += `
)
)`
}
whereClause += `
)`

queryString := fmt.Sprintf(`
WITH deduped_testcases AS (
SELECT
junit.*,
ROW_NUMBER() OVER(PARTITION BY prowjob_build_id, file_path, test_name, testsuite ORDER BY
CASE
WHEN flake_count > 0 THEN 0
WHEN success_val > 0 THEN 1
ELSE 2
END) AS row_num,
CASE
WHEN flake_count > 0 THEN 0
ELSE success_val
END AS adjusted_success_val,
CASE
WHEN flake_count > 0 THEN 1
ELSE 0
END AS adjusted_flake_count
FROM
%s.%s AS junit
WHERE
junit.modified_time >= DATETIME(@StartDate)
AND junit.modified_time < DATETIME(@EndDate)
AND junit.skipped = false
)
SELECT
jobs.prowjob_build_id,
jobs.prowjob_job_name AS prowjob_name,
jobs.prowjob_url,
jobs.pr_sha,
jobs.prowjob_start,
deduped.test_name,
deduped.testsuite,
CASE
WHEN deduped.adjusted_flake_count > 0 THEN TRUE
ELSE FALSE
END AS flaked,
CASE
WHEN deduped.adjusted_flake_count > 0 THEN TRUE
WHEN deduped.adjusted_success_val > 0 THEN TRUE
ELSE FALSE
END AS success,
deduped.failure_content
FROM
%s.jobs AS jobs
INNER JOIN
deduped_testcases AS deduped
ON
jobs.prowjob_build_id = deduped.prowjob_build_id
AND deduped.row_num = 1
WHERE
jobs.org = @Org
AND jobs.repo = @Repo
AND jobs.pr_number = @PRNumber
AND jobs.prowjob_start >= DATETIME(@StartDate)
AND jobs.prowjob_start < DATETIME(@EndDate)%s
ORDER BY
jobs.prowjob_start DESC,
deduped.test_name ASC
`, bqc.Dataset, junitTable, bqc.Dataset, whereClause)

query := bqc.BQ.Query(queryString)
query.Parameters = []bigquery.QueryParameter{
{
Name: "Org",
Value: org,
},
{
Name: "Repo",
Value: repo,
},
{
Name: "PRNumber",
Value: strconv.Itoa(prNumber),
},
{
Name: "StartDate",
Value: startDate,
},
{
Name: "EndDate",
Value: endDate,
},
}

// Add parameters for includeSuccesses LIKE clauses
for i, testName := range includeSuccesses {
query.Parameters = append(query.Parameters, bigquery.QueryParameter{
Name: fmt.Sprintf("IncludeSuccess%d", i),
Value: "%" + testName + "%", // Wrap in % for SQL LIKE partial matching
query = query.Where(conditions)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Normalize include_successes before building LIKE clauses.

?include_successes= produces LIKE '%%', and % / _ values can intentionally match every test name. Since the endpoint no longer uses param.SafeRead for this list parameter, trim empty values, cap count/length, and escape LIKE wildcards before querying.

Proposed hardening
+func escapeLikePattern(pattern string) string {
+	replacer := strings.NewReplacer(`\`, `\\`, `%`, `\%`, `_`, `\_`)
+	return replacer.Replace(pattern)
+}
+
@@
 	} else {
 		conditions := dbc.DB.Where("pjrt.status = ?", int(sippyprocessingv1.TestStatusFailure))
 		for _, pattern := range includeSuccesses {
-			conditions = conditions.Or("t.name LIKE ?", "%"+pattern+"%")
+			conditions = conditions.Or("t.name LIKE ? ESCAPE '\\'", "%"+escapeLikePattern(pattern)+"%")
 		}
 		query = query.Where(conditions)
 	}
@@
-	includeSuccesses := req.URL.Query()["include_successes"]
+	includeSuccesses := make([]string, 0, len(req.URL.Query()["include_successes"]))
+	for _, pattern := range req.URL.Query()["include_successes"] {
+		pattern = strings.TrimSpace(pattern)
+		if pattern != "" {
+			includeSuccesses = append(includeSuccesses, pattern)
+		}
+	}

As per path instructions, “Validate at trust boundaries with allow-lists, not deny-lists.”

Also applies to: 207-209

🤖 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/api/prtestresults.go` around lines 81 - 85, Normalize and validate
include_successes before constructing the query in the prtestresults filtering
logic, since the current loop in the query builder can produce unrestricted LIKE
matches. In the code around the conditions assembly, trim out empty entries,
enforce a reasonable maximum count and per-item length, and escape SQL LIKE
wildcard characters before passing patterns into the Or("t.name LIKE ?", ...)
clauses. Apply the same hardening to the related include_successes handling
referenced by the second occurrence so the endpoint only accepts safe, bounded
values.

Source: Path instructions

Comment thread pkg/api/prtestresults.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
pkg/api/prtestresults.go (1)

208-213: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Keep backend error details out of 500 responses.

Line 212 still echoes the wrapped DB error to clients. Keep the detailed error in log.WithError(err) and return a generic message body.

Proposed fix
 		RespondWithJSON(http.StatusInternalServerError, w, map[string]any{
 			"code":    http.StatusInternalServerError,
-			"message": fmt.Sprintf("error fetching test results: %v", err),
+			"message": "error fetching test results",
 		})
🤖 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/api/prtestresults.go` around lines 208 - 213, The PR test results error
path in the handler should not leak backend details in the HTTP 500 response
body. In the same block that logs with log.WithError(err) inside the PR test
results handler, change the RespondWithJSON payload to return a generic message
only, while keeping the full wrapped error detail in the log for debugging.
🤖 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/api/prtestresults.go`:
- Around line 165-193: The date range handling in prtestresults should validate
the normalized window before querying, since explicit start_date and end_date
can now create arbitrarily large ranges or an empty half-open interval after
end_date is made inclusive. In the request-handling logic around param.SafeRead,
the time.Parse blocks, and the prow_job_run_tests query setup, reintroduce the
previous/documented maximum span cap and reject requests where the normalized
endDate is not after startDate before continuing. Keep the existing inclusive
end-date behavior, but ensure the final normalized bounds are checked as a valid
allow-listed window before any query is executed.

---

Duplicate comments:
In `@pkg/api/prtestresults.go`:
- Around line 208-213: The PR test results error path in the handler should not
leak backend details in the HTTP 500 response body. In the same block that logs
with log.WithError(err) inside the PR test results handler, change the
RespondWithJSON payload to return a generic message only, while keeping the full
wrapped error detail in the log for debugging.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 88ca46e1-07a1-41b0-b785-829de19913ab

📥 Commits

Reviewing files that changed from the base of the PR and between cc2b47b and 966df4b.

📒 Files selected for processing (2)
  • pkg/api/prtestresults.go
  • test/e2e/pull_requests_test.go

Comment thread pkg/api/prtestresults.go
Comment on lines +165 to +193
now := time.Now().UTC()
startDate := now.AddDate(0, 0, -14)
endDate := now.AddDate(0, 0, 1)

startDate, err := time.Parse("2006-01-02", startDateStr)
if err != nil {
RespondWithJSON(http.StatusBadRequest, w, map[string]interface{}{
"code": http.StatusBadRequest,
"message": fmt.Sprintf("invalid start_date format (expected YYYY-MM-DD): %v", err),
})
return
startDateStr := param.SafeRead(req, "start_date")
if startDateStr != "" {
parsed, err := time.Parse("2006-01-02", startDateStr)
if err != nil {
RespondWithJSON(http.StatusBadRequest, w, map[string]any{
"code": http.StatusBadRequest,
"message": fmt.Sprintf("invalid start_date format (expected YYYY-MM-DD): %v", err),
})
return
}
startDate = parsed
}

endDateStr := param.SafeRead(req, "end_date")
if endDateStr == "" {
RespondWithJSON(http.StatusBadRequest, w, map[string]interface{}{
"code": http.StatusBadRequest,
"message": "required parameter 'end_date' is missing (format: YYYY-MM-DD)",
})
return
}

endDate, err := time.Parse("2006-01-02", endDateStr)
if err != nil {
RespondWithJSON(http.StatusBadRequest, w, map[string]interface{}{
"code": http.StatusBadRequest,
"message": fmt.Sprintf("invalid end_date format (expected YYYY-MM-DD): %v", err),
})
return
if endDateStr != "" {
parsed, err := time.Parse("2006-01-02", endDateStr)
if err != nil {
RespondWithJSON(http.StatusBadRequest, w, map[string]any{
"code": http.StatusBadRequest,
"message": fmt.Sprintf("invalid end_date format (expected YYYY-MM-DD): %v", err),
})
return
}
// Make end_date inclusive
endDate = parsed.AddDate(0, 0, 1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Validate and cap the normalized date window before querying.

Explicit start_date/end_date values can now span arbitrarily large ranges, and start_date=2024-01-02&end_date=2024-01-01 normalizes to an empty half-open window that bypasses endDate.Before(startDate). Reintroduce the previous/documented cap and require the normalized end to be after the start before hitting prow_job_run_tests.

As per path instructions, “Validate at trust boundaries with allow-lists, not deny-lists.”

Proposed hardening
+const maxPRTestResultsDateRange = 31 * 24 * time.Hour
+
 func PrintPRTestResultsJSON(w http.ResponseWriter, req *http.Request, dbc *db.DB) {
@@
-	if endDate.Before(startDate) {
+	if !endDate.After(startDate) {
 		RespondWithJSON(http.StatusBadRequest, w, map[string]any{
 			"code":    http.StatusBadRequest,
-			"message": "end_date must be after start_date",
+			"message": "end_date must be on or after start_date",
 		})
 		return
 	}
+
+	if endDate.Sub(startDate) > maxPRTestResultsDateRange {
+		RespondWithJSON(http.StatusBadRequest, w, map[string]any{
+			"code":    http.StatusBadRequest,
+			"message": "date range is too large",
+		})
+		return
+	}

Also applies to: 196-202

🤖 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/api/prtestresults.go` around lines 165 - 193, The date range handling in
prtestresults should validate the normalized window before querying, since
explicit start_date and end_date can now create arbitrarily large ranges or an
empty half-open interval after end_date is made inclusive. In the
request-handling logic around param.SafeRead, the time.Parse blocks, and the
prow_job_run_tests query setup, reintroduce the previous/documented maximum span
cap and reject requests where the normalized endDate is not after startDate
before continuing. Keep the existing inclusive end-date behavior, but ensure the
final normalized bounds are checked as a valid allow-listed window before any
query is executed.

Source: Path instructions

@dgoodwin

dgoodwin commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

/test lint

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@dgoodwin

dgoodwin commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

/test e2e

The sha param caused a server crash because it was not registered in the
param.SafeRead registry (which calls log.Fatal for unknown params).
Instead, use a latest_sha_only boolean param that filters results to
the SHA from the most recent prow job run, removing the burden from
the caller to know the exact SHA.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling required tests:
/test e2e

@openshift-ci

openshift-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

@dgoodwin: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants