Skip to content

Ensure deploy tokens `expires_at` does not accept invalid dates

What does this MR do and why?

This merge request ensures that deploy tokens expires_at does not accept invalid inputs (i.e. not in iso8601 format).

This also fixes the bug in which an invalid input would become null before the token is persisted, resulting in the following exception:

ActiveRecord::NotNullViolation: PG::NotNullViolation: ERROR: null value in column "expires_at" violates not-null constraint

Please note:

  • The bug is currently not reproducible via the UI (as the date picker only allows valid dates).
  • However, it can still be reproduced when creating deploy tokens via the API.

Resolves #372090.

How to set up and validate locally

  • In your local GDK setup, create a project if you don't have one already.
  • Make note of the id of the new project.

Validate through the API

With invalid input:

  • Send a request to create a deploy token:
    • Replace PROJECT_ID with the id of your project.
    • Replace USE_YOUR_OWN_TOKEN_HERE with your access token.
curl -H "PRIVATE-TOKEN: USE_YOUR_OWN_TOKEN_HERE" -X GET "http://gdk.test:3000/api/v4/projects/PROJECT_ID/deploy_tokens" -D '{"expires_at": "text", "name": "New token", "username": "custom-user", "scopes": ["read_repository"]}'
  • Verify the request returns 400 bad request as status with the following message: expires_at is invalid.
  • Verify that you have not received a 500 internal server error as status.

With valid input:

  • Do the same, replacing expires_at with a date in the future (e.g. 2023-01-01).
curl -H "PRIVATE-TOKEN: USE_YOUR_OWN_TOKEN_HERE" -X GET "http://gdk.test:3000/api/v4/projects/PROJECT_ID/deploy_tokens" -D '{"expires_at": "2023-01-01", "name": "new token", "username": "custom user", "scopes": ["read_repository"]}'
  • Verify the request returns 201 created as status with the body containing the new deploy token data.

Validate through rails console

You could also verify this in the rails console. Do not forget to replace PROJECT_ID with the id of the project you created.

pry(main)> project = Project.find(PROJECT_ID)
pry(main)> deploy_token = project.deploy_tokens.create(name: 'new token', expires_at: 'text', read_repository: true)
pry(main)> deploy_token.errors
pry(main)> => #<ActiveModel::Errors:0x0000000163464330
 @base=
  #<DeployToken:0x000000016240f9a8
   id: nil,
   revoked: false,
   read_repository: true,
   read_registry: false,
   expires_at: nil,
   created_at: nil,
   name: "new",
   username: nil,
   token_encrypted: nil,
   deploy_token_type: "project_type",
   write_registry: false,
   read_package_registry: false,
   write_package_registry: false,
   creator_id: nil>,
 @errors=[#<ActiveModel::Error attribute=base, type=expires_at must be in ISO 8601 format, options={}>]>

Please note: the two errors returned from the API and the rails console is different because grape validates if expires_at is a datetime and yields an is invalid error before we even get to the model validation.

However, trying to create an object of DeployToken with a datetime that cannot be parsed as iso8601 (e.g. output of 1.day.from_now which is a ActiveSupport::TimeWithZone object) is when the model validation comes in handy!

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Ahmed Hemdan

Merge request reports

Loading