Skip to content
Merged
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
15 changes: 15 additions & 0 deletions .env.docker-dev.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ OAUTHLIB_INSECURE_TRANSPORT=1
# See: https://docs.docker.com/compose/how-tos/profiles/
COMPOSE_PROFILES=optional

# The "ai" profile starts the services the AI assistant needs (embeddings):
# COMPOSE_PROFILES=optional,ai
# Add the "ai-evals" profile to also run Phoenix (LLM tracing/evals UI) and
# point the assistant at it:
# COMPOSE_PROFILES=optional,ai,ai-evals
# BASEROW_ASSISTANT_PHOENIX_URL=http://phoenix:6006
# Only needed when pointing at an auth-enabled (team) Phoenix instance:
# BASEROW_ASSISTANT_PHOENIX_API_KEY=

SECRET_KEY=baserow # CHANGE THIS IN PRODUCTION!
DATABASE_PASSWORD=baserow
REDIS_PASSWORD=baserow
Expand Down Expand Up @@ -52,6 +61,8 @@ MEDIA_URL=http://localhost:4000/media/
# BASEROW_MAILHOG_WEB_PORT=8025
# BASEROW_OTEL_COLLECTOR_PORT=4318
# BASEROW_EMBEDDINGS_PORT=7999
# BASEROW_PHOENIX_PORT=6060
# BASEROW_EVAL_RUNNER_PORT=8090
# BASEROW_KEYCLOAK_PORT=8081
# BASEROW_BACKEND_DEBUGGER_PORT=5678
#
Expand All @@ -76,6 +87,8 @@ MEDIA_URL=http://localhost:4000/media/
# BASEROW_MAILHOG_WEB_PORT=8035
# BASEROW_OTEL_COLLECTOR_PORT=4328
# BASEROW_EMBEDDINGS_PORT=8009
# BASEROW_PHOENIX_PORT=6070
# BASEROW_EVAL_RUNNER_PORT=8100
# BASEROW_KEYCLOAK_PORT=8091
# BASEROW_BACKEND_DEBUGGER_PORT=5679
#
Expand All @@ -96,6 +109,8 @@ MEDIA_URL=http://localhost:4000/media/
# BASEROW_MAILHOG_WEB_PORT=8045
# BASEROW_OTEL_COLLECTOR_PORT=4338
# BASEROW_EMBEDDINGS_PORT=8019
# BASEROW_PHOENIX_PORT=6080
# BASEROW_EVAL_RUNNER_PORT=8110
# BASEROW_KEYCLOAK_PORT=8101
# BASEROW_BACKEND_DEBUGGER_PORT=5680

Expand Down
9 changes: 9 additions & 0 deletions .env.local-dev.example
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ PRIVATE_BACKEND_URL=http://localhost:8000
# BASEROW_CELERY_FLOWER_PORT=5555
# BASEROW_OTEL_COLLECTOR_PORT=4318
# BASEROW_EMBEDDINGS_PORT=7999
# BASEROW_PHOENIX_PORT=6060
# BASEROW_EVAL_RUNNER_PORT=8090
# BASEROW_ASSISTANT_PHOENIX_URL=http://localhost:6060
# BASEROW_KEYCLOAK_PORT=8081
# BASEROW_BACKEND_DEBUGGER_PORT=5678
# BASEROW_LOCAL_DEV_PREFIX=/tmp/baserow
Expand Down Expand Up @@ -101,6 +104,9 @@ PRIVATE_BACKEND_URL=http://localhost:8000
# BASEROW_CELERY_FLOWER_PORT=5565
# BASEROW_OTEL_COLLECTOR_PORT=4328
# BASEROW_EMBEDDINGS_PORT=8009
# BASEROW_PHOENIX_PORT=6070
# BASEROW_EVAL_RUNNER_PORT=8100
# BASEROW_ASSISTANT_PHOENIX_URL=http://localhost:6070
# BASEROW_KEYCLOAK_PORT=8091
# BASEROW_BACKEND_DEBUGGER_PORT=5679
# BASEROW_LOCAL_DEV_PREFIX=/tmp/baserow-second
Expand Down Expand Up @@ -129,6 +135,9 @@ PRIVATE_BACKEND_URL=http://localhost:8000
# BASEROW_CELERY_FLOWER_PORT=5575
# BASEROW_OTEL_COLLECTOR_PORT=4338
# BASEROW_EMBEDDINGS_PORT=8019
# BASEROW_PHOENIX_PORT=6080
# BASEROW_EVAL_RUNNER_PORT=8110
# BASEROW_ASSISTANT_PHOENIX_URL=http://localhost:6080
# BASEROW_KEYCLOAK_PORT=8101
# BASEROW_BACKEND_DEBUGGER_PORT=5680
# BASEROW_LOCAL_DEV_PREFIX=/tmp/baserow-third
Expand Down
32 changes: 32 additions & 0 deletions backend/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,38 @@ test-regenerate-ci-durations: _check-dev
{{ _load_env }}
{{ _pytest }} {{ backend_tests_dirs }} --store-durations

# Sync assistant eval datasets to Phoenix
[group('3 - testing')]
eval-sync *ARGS: _check-dev
#!/usr/bin/env bash
set -euo pipefail
{{ _load_env }}
{{ uv_run }} baserow assistant_eval_sync {{ ARGS }}

# Run assistant eval experiments against Phoenix
[group('3 - testing')]
eval-run *ARGS: _check-dev
#!/usr/bin/env bash
set -euo pipefail
{{ _load_env }}
{{ uv_run }} baserow assistant_eval_run {{ ARGS }}

# Export UI-added Phoenix dataset examples as ready-to-paste eval code
[group('3 - testing')]
eval-export *ARGS: _check-dev
#!/usr/bin/env bash
set -euo pipefail
{{ _load_env }}
{{ uv_run }} baserow assistant_eval_export {{ ARGS }}

# Capture or import the committed eval baseline snapshot (capture|import)
[group('3 - testing')]
eval-baseline *ARGS: _check-dev
#!/usr/bin/env bash
set -euo pipefail
{{ _load_env }}
{{ uv_run }} baserow assistant_eval_baseline {{ ARGS }}

# =============================================================================
# CI Commands (used by docker-entrypoint.sh in CI pipelines)
# =============================================================================
Expand Down
2 changes: 2 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ dev = [
"build",
"rust-just>=1.46.0",
"syrupy==5.1.0",
"openinference-instrumentation-pydantic-ai==0.1.20",
"arize-phoenix-client==3.3.0",
]
changelog = [
"typer==0.24.1",
Expand Down
1 change: 0 additions & 1 deletion backend/pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,3 @@ markers =
workspace_search: All tests related to workspace search functionality
enable_all_signals: Disables signal deferral for this test (all signals enabled)
enable_signals: Enables specific signals for this test (accepts dotted callable paths)
eval: mark test as an eval test (requires LLM API key)
19 changes: 19 additions & 0 deletions backend/src/baserow/api/user/jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@
from rest_framework_simplejwt.tokens import AccessToken, Token


def user_is_valid_for_token(user: AbstractUser, token: Token) -> bool:
"""
Check an already loaded user against a token without touching the database.

Mirrors, in Python, the filters :meth:`UserHandler.get_active_user` applies
in SQL plus the token checks :func:`get_user_from_token` makes afterwards.

:param user: A user whose profile is already loaded.
:param token: The decoded JWT token to validate the user against.
:return: Whether the user may be authenticated with this token.
"""

return (
user.is_active
and not user.profile.to_be_deleted
and user.profile.is_jwt_token_valid(token)
)


def get_user_from_token(
token: str,
token_class: Optional[Type[Token]] = None,
Expand Down
4 changes: 4 additions & 0 deletions backend/src/baserow/contrib/database/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ def ready(self):
from .workflow_actions.workflow_action_types import (
CoreHTTPRequestWorkflowActionType,
CoreSMTPEmailWorkflowActionType,
CoreStartWorkflowWorkflowActionType,
LocalBaserowCreateRowWorkflowActionType,
LocalBaserowDeleteRowWorkflowActionType,
LocalBaserowUpdateRowWorkflowActionType,
Expand All @@ -296,6 +297,9 @@ def ready(self):
database_workflow_action_type_registry.register(
SlackWriteMessageWorkflowActionType()
)
database_workflow_action_type_registry.register(
CoreStartWorkflowWorkflowActionType()
)

from .fields.field_aggregations import (
AverageFieldAggregationType,
Expand Down
18 changes: 17 additions & 1 deletion backend/src/baserow/contrib/database/fields/field_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8248,6 +8248,8 @@ def after_update(
if isinstance(from_field, ButtonField):
return

# `user` is checked against the restored actions (ADR 006 section 5),
# so a credential or workflow they may not read is dropped.
self._recreate_workflow_actions(
to_field, to_field_kwargs.get("workflow_actions") or [], user=user
)
Expand All @@ -8270,6 +8272,16 @@ def _recreate_workflow_actions(
"database_fields": UnchangedIdMapping(),
}

# Marked as a duplicate so the action types keep references outside
# the copied scope: the data never leaves the workspace.
import_export_config = ImportExportConfig(
include_permission_data=True,
reduce_disk_space_usage=False,
is_duplicate=True,
exclude_sensitive_data=False,
copied_by=user,
)

# Opened only because the action import registers a deferred callback,
# which raises when no context is active.
with deferred_callback_context():
Expand All @@ -8278,5 +8290,9 @@ def _recreate_workflow_actions(
serialized_action["type"]
)
action_type.import_serialized(
field, serialized_action, id_mapping, copied_by=user
field,
serialized_action,
id_mapping,
import_export_config=import_export_config,
copied_by=user,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.2.16 on 2026-09-06 14:12

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0118_aiproviderworkspaceoverride_and_more'),
('database', '0221_databaseworkflowaction_trashed'),
]

operations = [
migrations.CreateModel(
name='CoreStartWorkflowWorkflowAction',
fields=[
('databaseworkflowaction_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='database.databaseworkflowaction')),
('service', models.ForeignKey(help_text='The service which this action is associated with.', on_delete=django.db.models.deletion.CASCADE, related_name='%(app_label)s_%(class)s_set', to='core.service')),
],
options={
'abstract': False,
},
bases=('database.databaseworkflowaction',),
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,6 @@ class CoreSMTPEmailWorkflowAction(DatabaseWorkflowServiceAction): ...


class SlackWriteMessageWorkflowAction(DatabaseWorkflowServiceAction): ...


class CoreStartWorkflowWorkflowAction(DatabaseWorkflowServiceAction): ...
Loading
Loading