You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Refactor platform table to enable custom domains #293
in order to support flexible platform support, the current platform table needs to not act like an enum (which it currently is) and instead act more like a form of data storage for specific user defined platforms (instances) of forges that are supported by CollectOSS.
Currently this table is referred to in these tables:
message
issue event
pr event
pr review
there may be a platform frontend api too but i cant find it
in all cases this just refers to the platform_id, which essentially is the same platform type flag that ContributorUUID uses.
This issue is for schema planning and migration to a better platform table that can adequately support the parent issue
Additionally, (cross references notwithstanding) it seems like this table is likely only useful during collection, and should be in the operations schema
That, oddly, makes migration easy, as a new table can be spun up in that location independently. once the old referring tables are divorced from the foreign keys and are instead using those referring columns to denote the platform type (via an enum in the codebase *), that would allow the old platform table to be removed entirely.
Now all we need is the schema for it
* not in the database because they are hard to migrate in postgres.
To get this rolling, id like to create a new table in the operations schema
id like to call it instances (or similar) to more clearly define its purpose.
The new table needs (first draft):
platform_type (the same integer being referred to by the tables mentioned above) - this would denote which API implementation gets used for the platform
platform_name - user-defined name for the platform, i.e. "my cool forgejo instance"/"homelab"
enabled - denotes whether to collect for that platform (up for debate as to whether we can add this later, this idea was from the linked issue discussed below)
while #71 is a decent start for this, that issue was written with a different vision for the platform table in mind (i.e. continuing using it like an enum) which differs from the current one.
I see this issue as being the modern replacement of/superseding that issue.
This is because I believe the _platform_s (AKA APIs) that are supported should be defined in the code. It makes no sense to allow a new platform to be added with a database table because it would ALSO require code changes to support that platform's APIs anyway - so why not have both in the same place.
this is why, what #71 calls "platform", i call "platform type", an identifier managed in code, alongside/integrated with the platform implementations.
this is also why id prefer the term "instances" for the table above (at least internally), since platform seems like it can be interpereted both ways
key limiting:
#71 suggests we add a "platform features" column to the worker_oauth table where we store API keys. This would be for storing key pseudo-platforms (IE: the different request limits for each key type - gor github, these would be rest and graphql) these values would be used by keyman for rate limiting.
For the purposes of this issue, I would call this "rate limit groups" instead, and i think they belong in the internal implementation, alongside other information like the platform name/type, rather than in a DB table, since they are basically fixed information that changes with the API (and should therefore live in the implementation code).
key storage:
I generally agree with #71 on this last point. worker_oauth needs to be the only place we store API keys.
5 instances of the string : platform_id, in data_parse.py (connecting the models to the DB schema)
IssueEvent, PullRequestEvent, PullRequestReview and Message schemas make explicit foreign key references to the platform ID (which is really a type)
What do we do about it?
this is an expansion under what is fundamentally step 3 in the previous comment: detaching foreign key references
Introduce enum for forge platform type to replace the magic numbers
Create a non-enum structure in postgres for this type with a check constraint to limit the values to mirror the existing python enum so that we can consistently enforce constraints everywhere its referenced.
- option 1: Domain. This is a bit of a bodge with maybe a postgres specific feature to avoid using an ENUM type, which cannot store values as integer and requires a more complex migration of every column thats currently FKed to the old platform table to translate its values to integers stored as strings.
- option 2: https://michaelcho.me/article/using-python-enums-in-sqlalchemy-models/ (integer column) + check constraint check=f"VALUE IN ({', '.join(str(e.value) for e in OrderStatus)})",
populate the forge_instances table at startup and update platform_type on operations.forge_instance to this new domain type
replace the foreign key that refer to this platform id (all the ones listed in the prior section of this comment) in the DB with a foreign key to the forge_instances table - that is the closest match for what they are trying to be, and they preserve the domain association, while also keeping a reference to the type. This would not be possible if not for the coincidence that, for gh.com / gl.com, the type id and the instance id happen to match. As part of this step the enums need to be removed in the places where it was added in step 1 (anti magic number) and replaced with a number derived from the actual Instance entry identifier (which we can maybe invent out of thin air until we have proper passing of instance objects happening in collection)
rename the columns that refer to this platform_id (which are actually platform_type) (can be deferred for later)
All FKs to the old platform table should be gone, we can do a final check for usage and delete it.
We will then be ready to:
populate forge_instance with the default values (github.com and gitlab.com) at startup for instances that would otherwise start with an empty forge_instances table
start relying on the forge_instances table as part of collection (key fetching, etc) and refactoring collection to be instance-aware
problem:
I realize we cant swap the foreign keys (step 4) until we populate the forge instances table, but the FK swap is an alembic migration and the populating with defaults is done at app startup. and i cant block migrations until that startup script runs, and i dont reallllly want to put data/defaults inside an alembic migration
Resolution: this might be a case where we have to allow alembic to be used to populate data. the alembic migrations are explicitly for existing instances moving over. the startup scripts are intended to simply populate data on first run
populate it with initial data (via migration - unavoidable)
add Reference to worker_oauth for api key
create migration to re-target the foreign keys to the platform table to point at the forge_instance table (this is what requires populating it with initial data)
Activity
MoralCode commentedon May 5, 2026
Additionally, (cross references notwithstanding) it seems like this table is likely only useful during collection, and should be in the operations schema
That, oddly, makes migration easy, as a new table can be spun up in that location independently. once the old referring tables are divorced from the foreign keys and are instead using those referring columns to denote the platform type (via an enum in the codebase *), that would allow the old platform table to be removed entirely.
Now all we need is the schema for it
* not in the database because they are hard to migrate in postgres.
MoralCode commentedon May 5, 2026
To get this rolling, id like to create a new table in the operations schema
id like to call it
instances(or similar) to more clearly define its purpose.The new table needs (first draft):
MoralCode commentedon May 5, 2026
Comparison with related issue
while #71 is a decent start for this, that issue was written with a different vision for the platform table in mind (i.e. continuing using it like an enum) which differs from the current one.
I see this issue as being the modern replacement of/superseding that issue.
This is because I believe the _platform_s (AKA APIs) that are supported should be defined in the code. It makes no sense to allow a new platform to be added with a database table because it would ALSO require code changes to support that platform's APIs anyway - so why not have both in the same place.
this is why, what #71 calls "platform", i call "platform type", an identifier managed in code, alongside/integrated with the platform implementations.
this is also why id prefer the term "instances" for the table above (at least internally), since platform seems like it can be interpereted both ways
key limiting:
#71 suggests we add a "platform features" column to the worker_oauth table where we store API keys. This would be for storing key pseudo-platforms (IE: the different request limits for each key type - gor github, these would be
restandgraphql) these values would be used by keyman for rate limiting.For the purposes of this issue, I would call this "rate limit groups" instead, and i think they belong in the internal implementation, alongside other information like the platform name/type, rather than in a DB table, since they are basically fixed information that changes with the API (and should therefore live in the implementation code).
key storage:
I generally agree with #71 on this last point. worker_oauth needs to be the only place we store API keys.
MoralCode commentedon May 7, 2026
This issue essentially has three phases to the refactor:
Create a new table in augur_operations for the forge instance data as described aboveDoneMoralCode commentedon Oct 3, 2026
Where is this used?
Github
there are lines declaring
platform_id = 1intasks/github:existing uses of platform IDs (foreign key or no):
issue_events:
CollectOSS/collectoss/tasks/github/events.py
Lines 192 to 193 in 8eb003b
pr_events:
CollectOSS/collectoss/tasks/github/events.py
Lines 226 to 229 in 8eb003b
PR reviews:
CollectOSS/collectoss/tasks/github/pull_requests/tasks.py
Lines 531 to 534 in 8eb003b
Gitlab
there are lines declaring
platform_id = 2intasks.gitlab:issue and PR events
CollectOSS/collectoss/tasks/gitlab/events_task.py
Lines 149 to 151 in 8eb003b
CollectOSS/collectoss/tasks/gitlab/events_task.py
Lines 199 to 202 in 8eb003b
Generic
5 instances of the string
: platform_id,in data_parse.py (connecting the models to the DB schema)IssueEvent,PullRequestEvent,PullRequestReviewandMessageschemas make explicit foreign key references to the platform ID (which is really a type)What do we do about it?
this is an expansion under what is fundamentally step 3 in the previous comment: detaching foreign key references
- option 1: Domain. This is a bit of a bodge with maybe a postgres specific feature to avoid using an ENUM type, which cannot store values as integer and requires a more complex migration of every column thats currently FKed to the old platform table to translate its values to integers stored as strings.
- option 2: https://michaelcho.me/article/using-python-enums-in-sqlalchemy-models/ (integer column) + check constraint
check=f"VALUE IN ({', '.join(str(e.value) for e in OrderStatus)})",platform_typeonoperations.forge_instanceto this new domain typeforge_instancestable - that is the closest match for what they are trying to be, and they preserve the domain association, while also keeping a reference to the type. This would not be possible if not for the coincidence that, for gh.com / gl.com, the type id and the instance id happen to match. As part of this step the enums need to be removed in the places where it was added in step 1 (anti magic number) and replaced with a number derived from the actual Instance entry identifier (which we can maybe invent out of thin air until we have proper passing of instance objects happening in collection)We will then be ready to:
MoralCode commentedon Oct 4, 2026
problem:
I realize we cant swap the foreign keys (step 4) until we populate the forge instances table, but the FK swap is an alembic migration and the populating with defaults is done at app startup. and i cant block migrations until that startup script runs, and i dont reallllly want to put data/defaults inside an alembic migration
Resolution: this might be a case where we have to allow alembic to be used to populate data. the alembic migrations are explicitly for existing instances moving over. the startup scripts are intended to simply populate data on first run
MoralCode commentedon Oct 6, 2026
Completion criteria:
forge_instancestable for assisting with compliance auditing #519 )forge_instancestable for assisting with compliance auditing #519