Skip to content

Commit 8fad5c1

Browse files
authored
migration: add columns for hashed values on ApiToken (#65300)
In support of our improved API tokens initiative (getsentry/rfcs#32), this PR adds two null-able columns to the `ApiToken` model that will hold the hash values. Hashed values for token values will be implemented over several PRs to maintain backwards compatibility and to prevent broken state between versions.
1 parent 52466b4 commit 8fad5c1

File tree

8 files changed

+343
-332
lines changed

8 files changed

+343
-332
lines changed

migrations_lockfile.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ feedback: 0004_index_together
99
hybridcloud: 0011_add_hybridcloudapitoken_index
1010
nodestore: 0002_nodestore_no_dictfield
1111
replays: 0004_index_together
12-
sentry: 0646_create_notification_message_table
12+
sentry: 0647_apitoken_add_hashed_columns
1313
social_auth: 0002_default_auto_field

src/sentry/backup/comparators.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,9 @@ def get_default_comparators():
760760
list,
761761
{
762762
"sentry.apitoken": [
763-
HashObfuscatingComparator("refresh_token", "token"),
763+
HashObfuscatingComparator(
764+
"refresh_token", "token", "hashed_token", "hashed_refresh_token"
765+
),
764766
IgnoredComparator("token_last_characters"),
765767
UnorderedListComparator("scope_list"),
766768
],

src/sentry/migrations/0632_apitoken_backfill_last_chars.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88

99
def backfill_last_token_characters(apps, _):
10-
from sentry.models.apitoken import ApiToken
10+
ApiToken = apps.get_model("sentry", "ApiToken")
1111

1212
for api_token in RangeQuerySetWrapperWithProgressBar(ApiToken.objects.all()):
1313
if api_token.token_last_characters is None:
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Generated by Django 5.0.2 on 2024-02-16 00:23
2+
3+
from django.db import migrations, models
4+
5+
from sentry.new_migrations.migrations import CheckedMigration
6+
7+
8+
class Migration(CheckedMigration):
9+
# This flag is used to mark that a migration shouldn't be automatically run in production. For
10+
# the most part, this should only be used for operations where it's safe to run the migration
11+
# after your code has deployed. So this should not be used for most operations that alter the
12+
# schema of a table.
13+
# Here are some things that make sense to mark as dangerous:
14+
# - Large data migrations. Typically we want these to be run manually by ops so that they can
15+
# be monitored and not block the deploy for a long period of time while they run.
16+
# - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to
17+
# have ops run this and not block the deploy. Note that while adding an index is a schema
18+
# change, it's completely safe to run the operation after the code has deployed.
19+
is_dangerous = False
20+
21+
dependencies = [
22+
("sentry", "0646_create_notification_message_table"),
23+
]
24+
25+
operations = [
26+
migrations.AddField(
27+
model_name="apitoken",
28+
name="hashed_refresh_token",
29+
field=models.CharField(max_length=128, null=True),
30+
),
31+
migrations.AddField(
32+
model_name="apitoken",
33+
name="hashed_token",
34+
field=models.CharField(max_length=128, null=True),
35+
),
36+
]

src/sentry/models/apitoken.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ class ApiToken(ReplicatedControlModel, HasApiScopes):
4141
user = FlexibleForeignKey("sentry.User")
4242
name = models.CharField(max_length=255, null=True)
4343
token = models.CharField(max_length=64, unique=True, default=generate_token)
44+
hashed_token = models.CharField(max_length=128, null=True)
4445
token_last_characters = models.CharField(max_length=4, null=True)
4546
refresh_token = models.CharField(max_length=64, unique=True, null=True, default=generate_token)
47+
hashed_refresh_token = models.CharField(max_length=128, null=True)
4648
expires_at = models.DateTimeField(null=True, default=default_expiration)
4749
date_added = models.DateTimeField(default=timezone.now)
4850

0 commit comments

Comments
 (0)