Return 400 when a release update sends an empty released_at

What does this MR do and why?

PUT /projects/:id/releases/:tag_name answers 500 Internal Server Error when released_at is an empty string or null, and the release keeps its date. Grape coerces "" to nil for the DateTime param, Releases::UpdateService passes released_at: nil to Release#update, and the NOT NULL constraint on releases.released_at raises ActiveRecord::NotNullViolation.

This MR declares the update param with allow_blank: false, so the API refuses both values with 400 Bad Request before the service runs. The GraphQL releaseUpdate mutation already refuses a null releasedAt. Creating a release is unchanged: there an absent released_at still defaults to the current time.

Only requests that answered 500 change, so this is a bug fix under the API style guide rather than a breaking change, and it needs no feature flag. The committed OpenAPI document does not change: its generator does not see allow_blank, so it still marks the parameter nullable.

References

Closes #637896

I found this while working on gitlab-mcp-server, probing the release update route on GitLab EE 19.5.0. I found no issue or MR about it.

Screenshots or screen recordings

No UI change. What the update answers:

Body Before After
{"released_at": ""} 500 Internal Server Error 400 {"error":"released_at is empty"}
{"released_at": null} 500 Internal Server Error 400 {"error":"released_at is empty"}

How to set up and validate locally

  1. As a Developer of a project that has a release for the tag v1.0, run:

    curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
      --header "Content-Type: application/json" --data '{"released_at": ""}' \
      --url "http://gdk.test:3000/api/v4/projects/<id>/releases/v1.0"
  2. On master it answers 500 and log/exceptions_json.log has the NotNullViolation; on this branch it answers 400 with {"error":"released_at is empty"}.

  3. Repeat with {"released_at": null}: the same answers. The release keeps its released_at every time.

I sent both bodies to a GitLab EE 19.5.0 Docker instance as an administrator: each got 500, and exceptions_json.log has PG::NotNullViolation: ERROR: null value in column "released_at" of relation "releases" violates not-null constraint for both. The new examples in spec/requests/api/releases_spec.rb send the same bodies as JSON: on master's code both get 500, on this branch 400, and the release keeps its date.

Checks I ran (Ruby 3.3.11)
  • With master's lib/api/releases.rb and this branch's spec/requests/api/releases_spec.rb: 284 examples, 2 failures, 14 pending. The two failures are the new examples, each answered 500 with the NotNullViolation.
  • On this branch, that spec with ee/spec/requests/api/releases_spec.rb, spec/services/releases/update_service_spec.rb and spec/requests/api/graphql/mutations/releases/update_spec.rb: 363 examples, 0 failures, 17 pending. The CE request spec again with FOSS_ONLY=1: 284 examples, 0 failures, 14 pending.
  • bundle exec rake gitlab:openapi:v3:check_docs: OpenAPI v3 documentation is up to date.
  • RuboCop on the two files: no offenses. The commit message linter, and Danger's commit and title linters: no problems.
  • Left to the pipeline: Ruby 3.3.12 and every job beyond these specs.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by José M. Requena Plens

Merge request reports

Loading
Loading