Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions .env.test

This file was deleted.

2 changes: 1 addition & 1 deletion .env.test.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ API_BASE_URL=http://localhost:8000

# Postgres
POSTGRES_SERVER=localhost
POSTGRES_DB=kaapi_guardrails_testing
POSTGRES_PORT=5432
POSTGRES_DB=kaapi-guardrails
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres

Expand Down
6 changes: 3 additions & 3 deletions backend/app/alembic/versions/001_added_request_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

# revision identifiers, used by Alembic.
revision: str = '001'
down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
down_revision: str | None = None
branch_labels = None
depends_on = None


def upgrade() -> None:
Expand Down
6 changes: 3 additions & 3 deletions backend/app/alembic/versions/002_added_validator_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

# revision identifiers, used by Alembic.
revision: str = '002'
down_revision: Union[str, Sequence[str], None] = '001'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
down_revision: str = '001'
branch_labels = None
depends_on = None


def upgrade() -> None:
Expand Down
50 changes: 50 additions & 0 deletions backend/app/alembic/versions/003_added_validator_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""Added validator_config table

Revision ID: 003
Revises: 002
Create Date: 2026-02-05 09:42:54.128852

"""
from typing import Sequence, Union

from alembic import op
from sqlalchemy.dialects import postgresql
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision: str = '003'
down_revision: str = '002'
branch_labels = None
depends_on = None


def upgrade() -> None:
op.create_table('validator_config',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('organization_id', sa.Integer(), nullable=False),
sa.Column('project_id', sa.Integer(), nullable=False),
sa.Column('type', sa.String(), nullable=False),
sa.Column('stage', sa.String(), nullable=False),
sa.Column('on_fail_action', sa.String(), nullable=False),
sa.Column(
"config",
postgresql.JSONB(astext_type=sa.Text()),
nullable=False,
server_default=sa.text("'{}'::jsonb"),
),
sa.Column('is_enabled', sa.Boolean(), nullable=False, server_default=sa.true()),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),

sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('organization_id', 'project_id', 'type', 'stage', name='uq_validator_identity')
)

op.create_index("idx_validator_organization", "validator_config", ["organization_id"])
op.create_index("idx_validator_project", "validator_config", ["project_id"])
op.create_index("idx_validator_type", "validator_config", ["type"])
op.create_index("idx_validator_stage", "validator_config", ["stage"])


def downgrade() -> None:
op.drop_table('validator_config')
39 changes: 39 additions & 0 deletions backend/app/alembic/versions/004_added_ban_list_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Added ban_list table

Revision ID: 004
Revises: 003
Create Date: 2026-02-05 09:42:54.128852

"""
from typing import Sequence, Union

from alembic import op
from sqlalchemy.dialects import postgresql
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision: str = '004'
down_revision: Union[str, Sequence[str], None] = "003"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.create_table('ban_list',
sa.Column('id', sa.Uuid(), nullable=False),
sa.Column('name', sa.String(), nullable=False),
sa.Column('description', sa.String(), nullable=False),
sa.Column('org_id', sa.Integer(), nullable=False),
sa.Column('project_id', sa.Integer(), nullable=False),
sa.Column('domain', sa.String(), nullable=False),
sa.Column('is_public', sa.Boolean(), nullable=False, server_default=sa.false()),
sa.Column("banned_words", postgresql.ARRAY(sa.String()), nullable=False, server_default="{}"),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),

sa.PrimaryKeyConstraint('id'),
)


def downgrade() -> None:
op.drop_table('validator_config')
4 changes: 3 additions & 1 deletion backend/app/api/main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from fastapi import APIRouter

from app.api.routes import utils, guardrails
from app.api.routes import ban_list_configs, guardrails, utils, validator_configs

api_router = APIRouter()
api_router.include_router(utils.router)
api_router.include_router(guardrails.router)
api_router.include_router(validator_configs.router)
api_router.include_router(ban_list_configs.router)

# if settings.ENVIRONMENT == "local":
# api_router.include_router(private.router)
118 changes: 118 additions & 0 deletions backend/app/api/routes/ban_list_configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from typing import List, Optional
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session

from app.api.deps import AuthDep, SessionDep
from app.crud.ban_list_crud import ban_list_crud
from app.schemas.ban_list_config import (
BanListCreate,
BanListUpdate,
BanListResponse
)

router = APIRouter(
prefix="/guardrails/ban-lists",
tags=["Ban Lists"]
)


def check_owner(obj, org_id, project_id):
if obj.org_id != org_id or obj.project_id != project_id:
raise HTTPException(status_code=403, detail="Not owner")


@router.post(
"/",
response_model=BanListResponse
)
def create_ban_list(
payload: BanListCreate,
session: SessionDep,
org_id: int,
project_id: int,
_: AuthDep,
):
return ban_list_crud.create(
session,
data=payload,
org_id=org_id,
project_id=project_id,
)


@router.get(
"/",
response_model=list[BanListResponse]
)
def list_ban_lists(
org_id: int,
project_id: int,
session: SessionDep,
_: AuthDep,
domain: Optional[str] = None,
):
return ban_list_crud.list(
session,
org_id=org_id,
project_id=project_id,
domain=domain,
)


@router.get(
"/{id}",
response_model=BanListResponse
)
def get_ban_list(
id: UUID,
org_id: int,
project_id: int,
session: SessionDep,
_: AuthDep,
):
obj = ban_list_crud.get(session, id)
if not obj:
raise HTTPException(404)

if not obj.is_public:
check_owner(obj, org_id, project_id)
return obj


@router.patch(
"/{id}",
response_model=BanListResponse
)
def update_ban_list(
id: UUID,
org_id: int,
project_id: int,
payload: BanListUpdate,
session: SessionDep,
_: AuthDep,
):
obj = ban_list_crud.get(session, id)
if not obj:
raise HTTPException(404)

check_owner(obj, org_id, project_id)
return ban_list_crud.update(session, obj=obj, data=payload)


@router.delete("/{id}")
def delete_ban_list(
id: UUID,
org_id: int,
project_id: int,
session: SessionDep,
_: AuthDep,
):
obj = ban_list_crud.get(session, id)
if not obj:
raise HTTPException(404)

check_owner(obj, org_id, project_id)
ban_list_crud.delete(session, obj)
return {"success": True}
6 changes: 3 additions & 3 deletions backend/app/api/routes/guardrails.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
from app.core.guardrail_controller import build_guard, get_validator_config_models
from app.crud.request_log import RequestLogCrud
from app.crud.validator_log import ValidatorLogCrud
from app.models.guardrail_config import GuardrailRequest, GuardrailResponse
from app.models.logging.request import RequestLogUpdate, RequestStatus
from app.models.logging.validator import ValidatorLog, ValidatorOutcome
from app.models.logging.request_log import RequestLogUpdate, RequestStatus
from app.models.logging.validator_log import ValidatorLog, ValidatorOutcome
from app.schemas.guardrail_config import GuardrailRequest, GuardrailResponse
from app.utils import APIResponse

router = APIRouter(prefix="/guardrails", tags=["guardrails"])
Expand Down
Loading