feat: add challenge and red-blue competitions across API and web
This commit is contained in:
parent
f5161d9add
commit
8fd3c4bb64
77 changed files with 5355 additions and 24 deletions
|
|
@ -0,0 +1,170 @@
|
|||
"""add challenge & red/blue tables
|
||||
|
||||
Revision ID: 183e2d30fb4e
|
||||
Revises: 68519ad5cd18
|
||||
Create Date: 2025-09-30 08:22:31.223257
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import models as models
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '183e2d30fb4e'
|
||||
down_revision = '68519ad5cd18'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('challenge_attempts',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('challenge_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('end_user_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('account_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('workflow_run_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('succeeded', sa.Boolean(), server_default=sa.text('false'), nullable=False),
|
||||
sa.Column('score', sa.Float(), nullable=True),
|
||||
sa.Column('judge_rating', sa.Integer(), nullable=True),
|
||||
sa.Column('judge_feedback', sa.Text(), nullable=True),
|
||||
sa.Column('judge_output_raw', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('tokens_total', sa.Integer(), nullable=True),
|
||||
sa.Column('elapsed_ms', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='challenge_attempts_pkey')
|
||||
)
|
||||
with op.batch_alter_table('challenge_attempts', schema=None) as batch_op:
|
||||
batch_op.create_index('challenge_attempts_challenge_id_idx', ['challenge_id'], unique=False)
|
||||
batch_op.create_index('challenge_attempts_tenant_id_idx', ['tenant_id'], unique=False)
|
||||
|
||||
op.create_table('challenges',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('app_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('workflow_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('name', sa.Text(), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('goal', sa.Text(), nullable=True),
|
||||
sa.Column('success_type', sa.String(length=64), server_default=sa.text("'regex'"), nullable=False),
|
||||
sa.Column('success_pattern', sa.Text(), nullable=True),
|
||||
sa.Column('secret_ref', sa.Text(), nullable=True),
|
||||
sa.Column('evaluator_type', sa.String(length=32), server_default=sa.text("'rules'"), nullable=False),
|
||||
sa.Column('evaluator_plugin_id', sa.Text(), nullable=True),
|
||||
sa.Column('evaluator_entrypoint', sa.Text(), nullable=True),
|
||||
sa.Column('evaluator_config', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('scoring_strategy', sa.String(length=64), server_default=sa.text("'first'"), nullable=False),
|
||||
sa.Column('scoring_plugin_id', sa.Text(), nullable=True),
|
||||
sa.Column('scoring_entrypoint', sa.Text(), nullable=True),
|
||||
sa.Column('scoring_config', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default=sa.text('true'), nullable=False),
|
||||
sa.Column('created_by', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_by', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='challenges_pkey')
|
||||
)
|
||||
with op.batch_alter_table('challenges', schema=None) as batch_op:
|
||||
batch_op.create_index('challenges_app_id_idx', ['app_id'], unique=False)
|
||||
batch_op.create_index('challenges_tenant_id_idx', ['tenant_id'], unique=False)
|
||||
|
||||
op.create_table('red_blue_challenges',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('app_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('workflow_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('name', sa.Text(), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('judge_suite', postgresql.JSONB(astext_type=sa.Text()), nullable=False),
|
||||
sa.Column('defense_selection_policy', sa.String(length=64), server_default=sa.text("'latest_best'"), nullable=False),
|
||||
sa.Column('attack_selection_policy', sa.String(length=64), server_default=sa.text("'latest_best'"), nullable=False),
|
||||
sa.Column('scoring_strategy', sa.String(length=64), server_default=sa.text("'red_blue_ratio'"), nullable=False),
|
||||
sa.Column('theme', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('instructions_md', sa.Text(), nullable=True),
|
||||
sa.Column('is_active', sa.Boolean(), server_default=sa.text('true'), nullable=False),
|
||||
sa.Column('created_by', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_by', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='red_blue_challenges_pkey')
|
||||
)
|
||||
with op.batch_alter_table('red_blue_challenges', schema=None) as batch_op:
|
||||
batch_op.create_index('red_blue_challenges_app_id_idx', ['app_id'], unique=False)
|
||||
batch_op.create_index('red_blue_challenges_tenant_id_idx', ['tenant_id'], unique=False)
|
||||
|
||||
op.create_table('team_pairings',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('red_blue_challenge_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('attack_submission_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('defense_submission_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('judge_output_raw', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('categories', postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('judge_rating', sa.Integer(), nullable=True),
|
||||
sa.Column('judge_feedback', sa.Text(), nullable=True),
|
||||
sa.Column('red_points', sa.Float(), server_default=sa.text('0'), nullable=False),
|
||||
sa.Column('blue_points', sa.Float(), server_default=sa.text('0'), nullable=False),
|
||||
sa.Column('tokens_total', sa.Integer(), nullable=True),
|
||||
sa.Column('elapsed_ms', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='team_pairings_pkey')
|
||||
)
|
||||
with op.batch_alter_table('team_pairings', schema=None) as batch_op:
|
||||
batch_op.create_index('team_pairings_challenge_id_idx', ['red_blue_challenge_id'], unique=False)
|
||||
batch_op.create_index('team_pairings_tenant_id_idx', ['tenant_id'], unique=False)
|
||||
|
||||
op.create_table('team_submissions',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('red_blue_challenge_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('tenant_id', models.types.StringUUID(), nullable=False),
|
||||
sa.Column('account_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('end_user_id', models.types.StringUUID(), nullable=True),
|
||||
sa.Column('team', sa.String(length=16), nullable=False),
|
||||
sa.Column('prompt', sa.Text(), nullable=False),
|
||||
sa.Column('active', sa.Boolean(), server_default=sa.text('true'), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='team_submissions_pkey')
|
||||
)
|
||||
with op.batch_alter_table('team_submissions', schema=None) as batch_op:
|
||||
batch_op.create_index('team_submissions_challenge_id_idx', ['red_blue_challenge_id'], unique=False)
|
||||
batch_op.create_index('team_submissions_tenant_id_idx', ['tenant_id'], unique=False)
|
||||
|
||||
with op.batch_alter_table('providers', schema=None) as batch_op:
|
||||
batch_op.drop_column('credential_status')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('providers', schema=None) as batch_op:
|
||||
batch_op.add_column(sa.Column('credential_status', sa.VARCHAR(length=20), server_default=sa.text("'active'::character varying"), autoincrement=False, nullable=True))
|
||||
|
||||
with op.batch_alter_table('team_submissions', schema=None) as batch_op:
|
||||
batch_op.drop_index('team_submissions_tenant_id_idx')
|
||||
batch_op.drop_index('team_submissions_challenge_id_idx')
|
||||
|
||||
op.drop_table('team_submissions')
|
||||
with op.batch_alter_table('team_pairings', schema=None) as batch_op:
|
||||
batch_op.drop_index('team_pairings_tenant_id_idx')
|
||||
batch_op.drop_index('team_pairings_challenge_id_idx')
|
||||
|
||||
op.drop_table('team_pairings')
|
||||
with op.batch_alter_table('red_blue_challenges', schema=None) as batch_op:
|
||||
batch_op.drop_index('red_blue_challenges_tenant_id_idx')
|
||||
batch_op.drop_index('red_blue_challenges_app_id_idx')
|
||||
|
||||
op.drop_table('red_blue_challenges')
|
||||
with op.batch_alter_table('challenges', schema=None) as batch_op:
|
||||
batch_op.drop_index('challenges_tenant_id_idx')
|
||||
batch_op.drop_index('challenges_app_id_idx')
|
||||
|
||||
op.drop_table('challenges')
|
||||
with op.batch_alter_table('challenge_attempts', schema=None) as batch_op:
|
||||
batch_op.drop_index('challenge_attempts_tenant_id_idx')
|
||||
batch_op.drop_index('challenge_attempts_challenge_id_idx')
|
||||
|
||||
op.drop_table('challenge_attempts')
|
||||
# ### end Alembic commands ###
|
||||
Loading…
Add table
Add a link
Reference in a new issue