Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.

NO-ISSUE: Add migration file list hash to prevent numbering collisions - #747

Merged
openshift-merge-bot[bot] merged 1 commit into
osac-project:mainfrom
jhernand:add_migration_file_list_hash
Jun 25, 2026
Merged

openshift-merge-bot[bot] merged 1 commit into
osac-project:mainfrom
jhernand:add_migration_file_list_hash

Conversation

@jhernand

@jhernand jhernand commented Jun 23, 2026 •

Copy link
Copy Markdown
Contributor

Add a migrations.sha256 file in internal/database/ containing the SHA-256 hash of the sorted
list of .up.sql migration filenames. Its purpose is to cause a git merge conflict when two pull
requests independently introduce migrations with the same number.

A unit test in database_migrations_test.go verifies that the stored hash matches the current
migration file list. When the hash is outdated the test failure message points to the
uv run dev.py update hashes command, which recomputes and writes the hash automatically.

Summary by CodeRabbit

Summary

  • New Features

    • Added a development CLI command to regenerate the database migrations SHA-256 checksum (with a hashes helper).
  • Bug Fixes

    • Added automated verification that the stored checksum matches the current set of migration files, failing tests when mismatched.
    • Updated the stored checksum value to the latest migrations.
  • Documentation

    • Documented the migration workflow and how to update the checksum when migrations are added or changed.

@openshift-ci
openshift-ci Bot requested review from rgolangh and ygalblum June 23, 2026 16:20
@coderabbitai

coderabbitai Bot commented Jun 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: a4773803-df6b-438d-9ec4-ba6c9b98a93a

📥 Commits

Reviewing files that changed from the base of the PR and between 21abe1d and 6a60b16.

📒 Files selected for processing (6)
  • dev.py
  • dev/__init__.py
  • dev/update.py
  • internal/database/README.md
  • internal/database/database_migrations_test.go
  • internal/database/migrations.sha256

Walkthrough

Adds a SHA-256 hash sentinel over sorted migration filenames. A new Python Click subcommand computes and writes the hash to migrations.sha256. A Go Ginkgo test recomputes the hash and fails when the stored value is stale. A README documents the workflow.

Changes

Migration collision guard

Layer / File(s) Summary
CLI wiring
dev/update.py, dev/__init__.py, dev.py
dev/update.py defines the update Click group and supporting imports, while dev/__init__.py re-exports the module and dev.py registers the new command on the top-level CLI.
Hash regeneration command
dev/update.py
Adds the hashes subcommand that gathers *.up.sql filenames, sorts them, computes a SHA-256 digest, compares it with migrations.sha256, and writes the new value when it differs.
Hash check and recorded digest
internal/database/database_migrations_test.go, internal/database/migrations.sha256, internal/database/README.md
Adds a Ginkgo check that recomputes the migration hash from sorted basenames and fails on mismatch. migrations.sha256 stores the recorded checksum, and README.md documents the migration layout and hash workflow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • larsks

Poem

A hash now guards the migration trail,
Sorted filenames set the scale.
Update it, or tests will sing,
A tidy checksum keeps its ring.

🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding a migration filename hash to catch numbering collisions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
No-Hardcoded-Secrets ✅ Passed No secret-like literals or credential URLs were added in the PR files; the only long string is the migration SHA-256 hash, not a secret.
No-Weak-Crypto ✅ Passed Touched code only uses SHA-256 for migration filename checksums; no weak algorithms, custom crypto, or secret comparisons found.
No-Injection-Vectors ✅ Passed Changed code only hashes local migration filenames and updates a file; no shell, eval, unsafe YAML/pickle, or user-influenced HTML/SQL paths added.
Container-Privileges ✅ Passed No added/modified container or K8s manifests are in the PR; the touched Python/Go/docs files contain no privileged settings.
No-Sensitive-Data-In-Logs ✅ Passed New logs are static or print only a migration filename hash; no passwords, tokens, PII, hostnames, or customer data are logged.
Ai-Attribution ✅ Passed HEAD commit includes Assisted-by: Cursor and no Co-Authored-By trailer; Red Hat AI attribution is present.

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

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

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

@jhernand jhernand changed the title Add migration file list hash to prevent numbering collisions NO-ISSUE: Add migration file list hash to prevent numbering collisions Jun 23, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@jhernand: This pull request explicitly references no jira issue.

Details

In response to this:

Summary

The existing test that checks for duplicate migration numbers works well as long as the unit tests
run immediately before merging. However, if another pull request merges between the moment the
tests pass and the actual merge, it is still possible to land two migrations with the same number
in the repository.

This change adds a SHA-256 hash of the sorted list of .up.sql filenames to
migrations/README.md. The test suite recomputes the hash and writes it into the README every
time it runs, so developers commit the updated value alongside their new migration. Because two
PRs that add different migrations will each write a different hash to the same line, Git will flag
a merge conflict that forces the second author to renumber their migration before merging,
regardless of when the tests last ran.

Developers don't need to do anything special to keep the hash up to date: just running the unit
tests, which they should already be doing before committing, will update the README automatically.

Test plan

  • Verified the mechanism by creating two branches from main, each adding a migration numbered 60
    with different names. Merging the first succeeded; merging the second produced a conflict in
    README.md as expected.

Summary by CodeRabbit

  • Chores
  • Enhanced database migration test suite with automated verification.
  • Added database migrations directory documentation.

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 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

🤖 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 `@internal/database/migrations/migrations_suite_test.go`:
- Around line 80-87: The regex pattern `[0-9a-f]{64}` is too generic and will
match any 64-character hex string in the file, potentially replacing unintended
hashes if the README includes other examples. Modify the `hashPattern` variable
to include surrounding context that uniquely identifies the migration hash, such
as code fence delimiters (triple backticks) or other structural markers from the
README format. This ensures that `ReplaceAllString` only targets the actual
migration hash location and not any other 64-hex strings that might exist
elsewhere in the file.
- Around line 74-89: The test currently extracts the storedHash from README.md
and then unconditionally replaces it with computedHash without verifying they
match first. After finding storedHash using the hashPattern regex and before
calling hashPattern.ReplaceAllString to replace the hash in readmeText, add an
Expect assertion that verifies storedHash equals computedHash. If the hashes
don't match, the test must fail with a clear error message indicating that the
migration file list has changed and the README.md hash needs to be updated and
committed. This ensures developers cannot merge without committing the updated
hash.
🪄 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: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 03cf95f0-c85d-416f-87e4-2200dc9d449c

📥 Commits

Reviewing files that changed from the base of the PR and between aa1fde0 and f839b01.

📒 Files selected for processing (2)
  • internal/database/migrations/README.md
  • internal/database/migrations/migrations_suite_test.go

Comment thread internal/database/migrations/migrations_suite_test.go Outdated
Comment thread internal/database/migrations/migrations_suite_test.go Outdated
@ygalblum

Copy link
Copy Markdown
Contributor

As long as we're using the merge queue that runs the E2E tests before merging, this error will be checked there anyhow. But, I do understand the advantage of having it here.

I agree with this comment: #747 (comment). You want to fail the test to ensure that the change to the README is not forgotten. Alternatively, just have it fail and print the expected value, forcing the user to update the value in the README. Yes, it's extra work for the user, but I'm not sure that tests with side effects are the right thing to do.

@jhernand

Copy link
Copy Markdown
Contributor Author

/hold

@jhernand
jhernand force-pushed the add_migration_file_list_hash branch from f839b01 to c5fa796 Compare June 24, 2026 12:34
@jhernand

jhernand commented Jun 24, 2026 •

Copy link
Copy Markdown
Contributor Author

As long as we're using the merge queue that runs the E2E tests before merging, this error will be checked there anyhow. But, I do understand the advantage of having it here.

I agree with this comment: #747 (comment). You want to fail the test to ensure that the change to the README is not forgotten. Alternatively, just have it fail and print the expected value, forcing the user to update the value in the README. Yes, it's extra work for the user, but I'm not sure that tests with side effects are the right thing to do.

The new version of the patch should address these concerns: the unit tests only verifies that the hash is correct, and suggest the user to either fix the file manually or else use the uv run dev.py update hashes command that updates it automatically.

@jhernand

Copy link
Copy Markdown
Contributor Author

/unhold

Comment thread internal/database/database_migrations_test.go Outdated
Comment thread internal/database/database_migrations_test.go Outdated
Comment thread dev/update.py Outdated
@jhernand
jhernand force-pushed the add_migration_file_list_hash branch from c5fa796 to 21abe1d Compare June 24, 2026 13:56

@ygalblum ygalblum 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.

/approve
/lgtm

@openshift-ci

openshift-ci Bot commented Jun 24, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jhernand, ygalblum

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

@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 `@internal/database/database_migrations_test.go`:
- Around line 119-120: The hash loop in the database migrations test is ignoring
the error return from fmt.Fprintf, which violates the Go error-handling rule.
Update the loop that writes names into computedHashSource to capture the
returned error, assert it in the test, and fail immediately if the write does
not succeed so the hashing setup is validated reliably.
🪄 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: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 46392613-41db-4667-bb16-843a52eabd1d

📥 Commits

Reviewing files that changed from the base of the PR and between c5fa796 and 21abe1d.

📒 Files selected for processing (6)
  • dev.py
  • dev/__init__.py
  • dev/update.py
  • internal/database/README.md
  • internal/database/database_migrations_test.go
  • internal/database/migrations.sha256

Comment thread internal/database/database_migrations_test.go Outdated
Add a `migrations.sha256` file in `internal/database/` containing the
SHA-256 hash of the sorted list of `.up.sql` migration filenames. Its
purpose is to cause a git merge conflict when two pull requests
independently introduce migrations with the same number.

A unit test in `database_migrations_test.go` verifies that the stored
hash matches the current migration file list. When the hash is outdated
the test failure message points to the `uv run dev.py update hashes`
command, which recomputes and writes the hash automatically.

Assisted-by: Cursor
Signed-off-by: Juan Hernandez <juan.hernandez@redhat.com>
@jhernand
jhernand force-pushed the add_migration_file_list_hash branch from 21abe1d to 6a60b16 Compare June 24, 2026 14:25
@openshift-ci openshift-ci Bot removed the lgtm label Jun 24, 2026

@ygalblum ygalblum 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.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm label Jun 24, 2026
@omer-vishlitzky

Copy link
Copy Markdown
Contributor

💀 CI Triage: broken_main | Category: BOOT

Root cause: Helm upgrade fails during the boot/refresh phase because of a strategic merge patch conflict on the osac-operator deployment's OSAC_AAP_TOKEN environment variable.

Explanation: Recently merged PR #328 in osac-installer configured the operator to load its AAP token from a secret via secretKeyRef (using the new aap.tokenSecret Helm value introduced in osac-operator PR #316). However, the pre-built cluster snapshot flavor (vmaas-helm) still contains the older deployment of osac-operator where OSAC_AAP_TOKEN is set as a literal value. During the snapshot boot refresh phase, refresh-after-snapshot.py executes helm upgrade, which attempts to patch the existing deployment. Because Kubernetes strategic merge patch merges the new valueFrom field into the existing environment variable element without clearing the existing value field, the resulting spec contains both value and valueFrom for OSAC_AAP_TOKEN, which is invalid and rejected by the API server.

Evidence:

build-log.txt:

Error: UPGRADE FAILED: cannot patch "osac-operator" with kind Deployment: Deployment.apps "osac-operator" is invalid: spec.template.spec.containers[0].env[1].valueFrom: Invalid value: "": may not be specified when `value` is not empty

build-log.txt:

ERROR: command failed (exit 1): helm upgrade osac charts/osac/ --namespace osac-e2e-ci --values values/vmaas-ci/values.yaml --set service.externalHostname=fulfillment-api-osac-e2e-ci.apps.test-infra-cluster-vmaas-helm.redhat.com --set service.internalHostname=fulfillment-internal-api-osac-e2e-ci.apps.test-infra-cluster-vmaas-helm.redhat.com --set aap.bootstrap.enabled=false --set clusterFulfillment.config.HOSTED_CLUSTER_BASE_DOMAIN=hosted.test-infra-cluster-vmaas-helm.redhat.com --timeout 15m

Suggestion: To fix this, either: (1) update the osac-operator Helm chart deployment template to explicitly set value: null when aap.tokenSecret is used, which will clear the existing literal value during strategic merge patch, or (2) modify refresh-after-snapshot.py to delete the existing osac-operator deployment before running helm upgrade so it is recreated cleanly from scratch.


Prow job | Build 2069866775721283584 | 🤖 triagent

For deeper investigation, use the /osac-debug-e2e skill with this build ID.

@omer-vishlitzky

Copy link
Copy Markdown
Contributor

/retest

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants