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
idof the new project.
Validate through the API
With invalid input:
- Send a request to create a deploy token:
- Replace
PROJECT_IDwith the id of your project. - Replace
USE_YOUR_OWN_TOKEN_HEREwith your access token.
- Replace
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 requestas status with the following message:expires_at is invalid. -
Verify that you have not received a
500 internal server erroras status.
With valid input:
- Do the same, replacing
expires_atwith 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 createdas 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.
-
I have evaluated the MR acceptance checklist for this MR.