simpleaudit-studio 0.2.0__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/.env.example +3 -3
  2. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/.env.local.example +3 -3
  3. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/Dockerfile +4 -4
  4. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/PKG-INFO +3 -3
  5. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/README.md +2 -2
  6. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/services.py +1 -4
  7. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/config/settings.py +1 -1
  8. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/deploy/e2e_smoke.py +4 -4
  9. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/deploy/seed_bulk.py +1 -1
  10. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/docker-compose.yml +1 -1
  11. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/e2e/test_ui.py +2 -2
  12. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/commands/bootstrap_platform.py +4 -4
  13. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/minimal_config.py +21 -4
  14. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/startup_checks.py +2 -2
  15. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_bootstrap.py +21 -1
  16. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_minimal_config.py +27 -3
  17. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_seed_platform.py +1 -1
  18. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/pyproject.toml +1 -1
  19. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/simpleaudit_studio/cli.py +5 -5
  20. simpleaudit_studio-0.2.2/uv.lock +2419 -0
  21. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/.dockerignore +0 -0
  22. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/.github/workflows/ci.yml +0 -0
  23. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/.github/workflows/publish.yml +0 -0
  24. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/.gitignore +0 -0
  25. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/LICENSE +0 -0
  26. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/Makefile +0 -0
  27. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/__init__.py +0 -0
  28. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/admin.py +0 -0
  29. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/apps.py +0 -0
  30. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/auth_urls.py +0 -0
  31. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/migrations/0001_initial.py +0 -0
  32. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/migrations/0002_user_workos_user_id.py +0 -0
  33. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/migrations/__init__.py +0 -0
  34. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/models.py +0 -0
  35. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/project_urls.py +0 -0
  36. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/serializers.py +0 -0
  37. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/views.py +0 -0
  38. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/accounts/workos_auth.py +0 -0
  39. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/__init__.py +0 -0
  40. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/admin.py +0 -0
  41. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/apps.py +0 -0
  42. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/comparison.py +0 -0
  43. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/events.py +0 -0
  44. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/migrations/0001_initial.py +0 -0
  45. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/migrations/0002_add_audit_run_archived.py +0 -0
  46. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/migrations/0003_auditrun_updated_at.py +0 -0
  47. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/migrations/__init__.py +0 -0
  48. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/models.py +0 -0
  49. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/serializers.py +0 -0
  50. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/services.py +0 -0
  51. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/urls.py +0 -0
  52. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/audits/views.py +0 -0
  53. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/config/__init__.py +0 -0
  54. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/config/asgi.py +0 -0
  55. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/config/urls.py +0 -0
  56. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/config/wsgi.py +0 -0
  57. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/deploy/compose/Dockerfile +0 -0
  58. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/deploy/mock_openai_server.py +0 -0
  59. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/deploy/postgres-init.sql +0 -0
  60. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/docs/architecture.md +0 -0
  61. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/docs/deployment.md +0 -0
  62. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/docs/domain-model.md +0 -0
  63. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/__init__.py +0 -0
  64. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/admin.py +0 -0
  65. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/apps.py +0 -0
  66. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/context_processors.py +0 -0
  67. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/engine.py +0 -0
  68. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/exceptions.py +0 -0
  69. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/fixtures/demo_audit_results.json +0 -0
  70. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/hashing.py +0 -0
  71. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/health.py +0 -0
  72. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/health_api.py +0 -0
  73. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/logging.py +0 -0
  74. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/__init__.py +0 -0
  75. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/commands/__init__.py +0 -0
  76. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/commands/purge_test_data.py +0 -0
  77. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/commands/run_worker.py +0 -0
  78. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/commands/seed_demo_audits.py +0 -0
  79. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/management/commands/seed_platform.py +0 -0
  80. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/middleware.py +0 -0
  81. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/permissions.py +0 -0
  82. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/readiness.py +0 -0
  83. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/seed.py +0 -0
  84. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/simpleaudit_package.py +0 -0
  85. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/__init__.py +0 -0
  86. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/factories.py +0 -0
  87. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_api_e2e.py +0 -0
  88. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_archive.py +0 -0
  89. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_clone.py +0 -0
  90. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_events.py +0 -0
  91. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_poll_results.py +0 -0
  92. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_rename.py +0 -0
  93. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_run_freeze.py +0 -0
  94. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_sse.py +0 -0
  95. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_submission.py +0 -0
  96. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_audit_timing.py +0 -0
  97. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_auth_projects.py +0 -0
  98. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_comparison.py +0 -0
  99. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_engine_integration.py +0 -0
  100. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_health.py +0 -0
  101. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_health_panel.py +0 -0
  102. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_middleware.py +0 -0
  103. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_model_registry.py +0 -0
  104. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_purge_test_data.py +0 -0
  105. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_scenario_import_export.py +0 -0
  106. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_scenarios.py +0 -0
  107. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_smoke_all_pages.py +0 -0
  108. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_workspaces.py +0 -0
  109. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/tests/test_workspaces_ui.py +0 -0
  110. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/ui.py +0 -0
  111. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/infra/worker.py +0 -0
  112. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/manage.py +0 -0
  113. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/__init__.py +0 -0
  114. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/admin.py +0 -0
  115. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/apps.py +0 -0
  116. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/migrations/0001_initial.py +0 -0
  117. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/migrations/__init__.py +0 -0
  118. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/models.py +0 -0
  119. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/serializers.py +0 -0
  120. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/services.py +0 -0
  121. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/urls.py +0 -0
  122. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/model_registry/views.py +0 -0
  123. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/requirements.txt +0 -0
  124. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/__init__.py +0 -0
  125. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/admin.py +0 -0
  126. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/apps.py +0 -0
  127. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/migrations/0001_initial.py +0 -0
  128. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/migrations/__init__.py +0 -0
  129. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/models.py +0 -0
  130. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/serializers.py +0 -0
  131. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/services.py +0 -0
  132. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/urls.py +0 -0
  133. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/scenarios/views.py +0 -0
  134. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/simpleaudit_studio/__init__.py +0 -0
  135. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/static/favicon-16x16.svg +0 -0
  136. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/static/favicon-32x32.svg +0 -0
  137. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/static/favicon.svg +0 -0
  138. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/static/js/diff.min.js +0 -0
  139. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/static/logo.png +0 -0
  140. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/static/logo.svg +0 -0
  141. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/404.html +0 -0
  142. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/audit_detail.html +0 -0
  143. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/auth/login.html +0 -0
  144. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/auth/register.html +0 -0
  145. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/auth/workos_login.html +0 -0
  146. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/auth/workos_verify.html +0 -0
  147. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/base.html +0 -0
  148. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/compare.html +0 -0
  149. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/dashboard.html +0 -0
  150. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/health.html +0 -0
  151. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/models.html +0 -0
  152. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/new_audit.html +0 -0
  153. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/scenario_result_detail.html +0 -0
  154. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/scenarios.html +0 -0
  155. {simpleaudit_studio-0.2.0 → simpleaudit_studio-0.2.2}/templates/workspaces.html +0 -0
@@ -19,9 +19,9 @@ DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
19
19
  LOG_LEVEL=INFO
20
20
 
21
21
  # --- Bootstrap (idempotent; run automatically by the web container) ----------
22
- BOOTSTRAP_ADMIN_USERNAME=admin
23
- BOOTSTRAP_ADMIN_EMAIL=admin@example.local
24
- BOOTSTRAP_ADMIN_PASSWORD=change-me
22
+ BOOTSTRAP_USERNAME=studio
23
+ BOOTSTRAP_EMAIL=admin@example.local
24
+ BOOTSTRAP_PASSWORD=change-me
25
25
  BOOTSTRAP_PROJECT_NAME=Default
26
26
 
27
27
  # --- First-run seed (idempotent; run automatically by the web container) -----
@@ -22,9 +22,9 @@ LOG_LEVEL=DEBUG
22
22
 
23
23
  # --- Bootstrap ----------------------------------------------------------------
24
24
  # `python manage.py bootstrap_platform` reads these on first run (idempotent).
25
- BOOTSTRAP_ADMIN_USERNAME=admin
26
- BOOTSTRAP_ADMIN_EMAIL=admin@example.local
27
- BOOTSTRAP_ADMIN_PASSWORD=localdevpass123
25
+ BOOTSTRAP_USERNAME=studio
26
+ BOOTSTRAP_EMAIL=admin@example.local
27
+ BOOTSTRAP_PASSWORD=localdevpass123
28
28
  BOOTSTRAP_PROJECT_NAME=Default
29
29
 
30
30
  # --- Database -----------------------------------------------------------------
@@ -53,12 +53,12 @@ ENV SIMPLEAUDIT_MINIMAL=1 \
53
53
  DJANGO_SECRET_KEY=hf-space-demo-secret-key-change-in-production \
54
54
  DJANGO_DEBUG=false \
55
55
  DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,.hf.space,.huggingface.co \
56
- BOOTSTRAP_ADMIN_USERNAME=admin \
57
- BOOTSTRAP_ADMIN_EMAIL=admin@example.local \
58
- BOOTSTRAP_ADMIN_PASSWORD=admin123 \
56
+ BOOTSTRAP_USERNAME=studio \
57
+ BOOTSTRAP_EMAIL=studio@example.local \
58
+ BOOTSTRAP_PASSWORD=admin123 \
59
59
  BOOTSTRAP_PROJECT_NAME=Default \
60
60
  DEMO_MODE=true \
61
- DEMO_USERNAME=admin \
61
+ DEMO_USERNAME=studio \
62
62
  DEMO_PASSWORD=admin123 \
63
63
  MAX_CONCURRENT_AUDITS=1 \
64
64
  MAX_SCENARIOS_PER_RUN=50
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: simpleaudit-studio
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Production AI model audit platform — one-liner demo mode via uvx
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -52,7 +52,7 @@ A self-hostable platform for running reproducible AI model audits using the [Sim
52
52
  uvx simpleaudit-studio
53
53
  ```
54
54
 
55
- [`uvx`](https://docs.astral.sh/uv/#uvx) installs the [`simpleaudit-studio`](https://pypi.org/project/simpleaudit-studio/) package and runs it in an isolated environment. No Docker, no Postgres, no manual setup. Opens at http://localhost:8000 (login: `admin` / `admin12345`). A mock model server is pre-seeded so you can run an audit immediately.
55
+ [`uvx`](https://docs.astral.sh/uv/#uvx) installs the [`simpleaudit-studio`](https://pypi.org/project/simpleaudit-studio/) package and runs it in an isolated environment. No Docker, no Postgres, no manual setup. Opens at http://localhost:8000 (login: `admin` / `admin12345`). A mock model server is pre-seeded so you can start exploring audit results immediately.
56
56
 
57
57
  🌐 Or skip the setup entirely — try the live demo: <a href="https://sushantgautam-simpleaudit-studio.hf.space" target="_blank" rel="noopener noreferrer">sushantgautam-simpleaudit-studio.hf.space</a>
58
58
 
@@ -78,7 +78,7 @@ For teams, multi-user setups, or GPU worker pools, use Docker Compose:
78
78
  git clone https://github.com/SushantGautam/SimpleAuditStudio
79
79
  cd SimpleAuditStudio
80
80
  cp .env.example .env
81
- # edit POSTGRES_PASSWORD and BOOTSTRAP_ADMIN_PASSWORD at minimum
81
+ # edit POSTGRES_PASSWORD and BOOTSTRAP_PASSWORD at minimum
82
82
  docker compose up -d
83
83
  ```
84
84
 
@@ -25,7 +25,7 @@ A self-hostable platform for running reproducible AI model audits using the [Sim
25
25
  uvx simpleaudit-studio
26
26
  ```
27
27
 
28
- [`uvx`](https://docs.astral.sh/uv/#uvx) installs the [`simpleaudit-studio`](https://pypi.org/project/simpleaudit-studio/) package and runs it in an isolated environment. No Docker, no Postgres, no manual setup. Opens at http://localhost:8000 (login: `admin` / `admin12345`). A mock model server is pre-seeded so you can run an audit immediately.
28
+ [`uvx`](https://docs.astral.sh/uv/#uvx) installs the [`simpleaudit-studio`](https://pypi.org/project/simpleaudit-studio/) package and runs it in an isolated environment. No Docker, no Postgres, no manual setup. Opens at http://localhost:8000 (login: `admin` / `admin12345`). A mock model server is pre-seeded so you can start exploring audit results immediately.
29
29
 
30
30
  🌐 Or skip the setup entirely — try the live demo: <a href="https://sushantgautam-simpleaudit-studio.hf.space" target="_blank" rel="noopener noreferrer">sushantgautam-simpleaudit-studio.hf.space</a>
31
31
 
@@ -51,7 +51,7 @@ For teams, multi-user setups, or GPU worker pools, use Docker Compose:
51
51
  git clone https://github.com/SushantGautam/SimpleAuditStudio
52
52
  cd SimpleAuditStudio
53
53
  cp .env.example .env
54
- # edit POSTGRES_PASSWORD and BOOTSTRAP_ADMIN_PASSWORD at minimum
54
+ # edit POSTGRES_PASSWORD and BOOTSTRAP_PASSWORD at minimum
55
55
  docker compose up -d
56
56
  ```
57
57
 
@@ -24,7 +24,7 @@ def bootstrap_admin_and_default_project(
24
24
  """Idempotently create the initial admin user and default project."""
25
25
  user, created = User.objects.get_or_create(
26
26
  username=username,
27
- defaults={"email": email, "is_staff": True, "is_superuser": True},
27
+ defaults={"email": email, "is_staff": True},
28
28
  )
29
29
  # Always ensure the admin password matches the configured value. This makes
30
30
  # the bootstrap idempotent across container restarts where the Postgres data
@@ -39,9 +39,6 @@ def bootstrap_admin_and_default_project(
39
39
  if not user.is_staff:
40
40
  user.is_staff = True
41
41
  user.save(update_fields=["is_staff"])
42
- if not user.is_superuser:
43
- user.is_superuser = True
44
- user.save(update_fields=["is_superuser"])
45
42
 
46
43
  slug = slugify(project_name) or "default"
47
44
  default_description = "Public common workspaces visible to all users, used for demo"
@@ -237,7 +237,7 @@ WORKOS_ENABLED = bool(WORKOS_CLIENT_ID and WORKOS_API_KEY)
237
237
  APP_BASE_URL = os.environ.get("APP_BASE_URL", "http://localhost:8000").rstrip("/")
238
238
 
239
239
  DEMO_MODE = env_bool("DEMO_MODE", False)
240
- DEMO_USERNAME = os.environ.get("DEMO_USERNAME", "admin")
240
+ DEMO_USERNAME = os.environ.get("DEMO_USERNAME", "studio")
241
241
  DEMO_PASSWORD = os.environ.get("DEMO_PASSWORD", "admin123")
242
242
 
243
243
  # Framing policy:
@@ -9,7 +9,7 @@ no real API keys (the mock-model service stands in for all three endpoints).
9
9
 
10
10
  Usage:
11
11
  python deploy/e2e_smoke.py [base_url] # default http://localhost:8000
12
- Reads BOOTSTRAP_ADMIN_USERNAME/EMAIL/PASSWORD from .env.
12
+ Reads BOOTSTRAP_USERNAME/EMAIL/PASSWORD from .env.
13
13
  """
14
14
  from __future__ import annotations
15
15
 
@@ -70,10 +70,10 @@ class Client:
70
70
  def main():
71
71
  base_url = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:8000"
72
72
  env = _load_env()
73
- username = env.get("BOOTSTRAP_ADMIN_USERNAME", "admin")
74
- password = env.get("BOOTSTRAP_ADMIN_PASSWORD", "")
73
+ username = env.get("BOOTSTRAP_USERNAME", "studio")
74
+ password = env.get("BOOTSTRAP_PASSWORD", "")
75
75
  if not password:
76
- print("FATAL: BOOTSTRAP_ADMIN_PASSWORD not set in .env")
76
+ print("FATAL: BOOTSTRAP_PASSWORD not set in .env")
77
77
  sys.exit(2)
78
78
 
79
79
  c = Client(base_url)
@@ -133,7 +133,7 @@ RUN_STATUS_DISTRIBUTION = (
133
133
 
134
134
  def main():
135
135
  project = Project.objects.get(id=1)
136
- admin = User.objects.get(username="admin")
136
+ admin = User.objects.get(username="studio")
137
137
 
138
138
  # ─── 1. Model Endpoints (15) ───────────────────────────────────────────────
139
139
  print(f"Model endpoints before: {ModelEndpoint.objects.count()}")
@@ -177,7 +177,7 @@ services:
177
177
  # collection, then serve with gunicorn. The seed is safe on every start:
178
178
  # it skips anything already present. Set SEED_ON_BOOT=false to opt out.
179
179
  # Set SEED_DEMO_AUDITS=false to skip demo audit runs only.
180
- command: 'sh -c "python manage.py migrate --noinput && python manage.py bootstrap_platform --username ${BOOTSTRAP_ADMIN_USERNAME:-admin} --email ${BOOTSTRAP_ADMIN_EMAIL:-admin@example.local} --password ${BOOTSTRAP_ADMIN_PASSWORD:?Set BOOTSTRAP_ADMIN_PASSWORD in .env} --project-name ${BOOTSTRAP_PROJECT_NAME:-Default} && if [ "${SEED_ON_BOOT:-true}" != "false" ]; then SEED_ARGS=\"\"; if [ \"${SEED_DEMO_AUDITS:-true}\" = \"false\" ]; then SEED_ARGS=\"--skip-demo-audits\"; fi; python manage.py seed_platform $SEED_ARGS || echo ''WARNING: seed_platform failed - continuing without seed data''; fi && python manage.py collectstatic --noinput && gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 2"'
180
+ command: 'sh -c "python manage.py migrate --noinput && python manage.py bootstrap_platform --username ${BOOTSTRAP_USERNAME:-studio} --email ${BOOTSTRAP_EMAIL:-admin@example.local} --password ${BOOTSTRAP_PASSWORD:?Set BOOTSTRAP_PASSWORD in .env} --project-name ${BOOTSTRAP_PROJECT_NAME:-Default} && if [ "${SEED_ON_BOOT:-true}" != "false" ]; then SEED_ARGS=\"\"; if [ \"${SEED_DEMO_AUDITS:-true}\" = \"false\" ]; then SEED_ARGS=\"--skip-demo-audits\"; fi; python manage.py seed_platform $SEED_ARGS || echo ''WARNING: seed_platform failed - continuing without seed data''; fi && python manage.py collectstatic --noinput && gunicorn config.wsgi:application --bind 0.0.0.0:8000 --workers 2"'
181
181
  healthcheck:
182
182
  test: ["CMD", "curl", "-fsS", "http://localhost:8000/healthz"]
183
183
  interval: 30s
@@ -7,7 +7,7 @@ with bootstrap_platform already run.
7
7
  Run locally:
8
8
  docker compose up -d
9
9
  docker compose exec web python manage.py bootstrap_platform \
10
- --username admin --email admin@example.com --password e2etestpass123 \
10
+ --username studio --email studio@example.local --password e2etestpass123 \
11
11
  --project-name Research
12
12
  .venv/bin/python e2e/test_ui.py
13
13
  """
@@ -22,7 +22,7 @@ except ImportError:
22
22
  sys.exit(1)
23
23
 
24
24
  BASE_URL = "http://localhost:8000"
25
- ADMIN_USER = "admin"
25
+ ADMIN_USER = "studio"
26
26
  ADMIN_PASS = "e2etestpass123"
27
27
 
28
28
 
@@ -11,9 +11,9 @@ class Command(BaseCommand):
11
11
  help = "Create initial admin user and default project if missing."
12
12
 
13
13
  def add_arguments(self, parser):
14
- parser.add_argument("--username", default=os.environ.get("BOOTSTRAP_ADMIN_USERNAME", "admin"))
15
- parser.add_argument("--email", default=os.environ.get("BOOTSTRAP_ADMIN_EMAIL", "admin@example.local"))
16
- parser.add_argument("--password", default=os.environ.get("BOOTSTRAP_ADMIN_PASSWORD", ""))
14
+ parser.add_argument("--username", default=os.environ.get("BOOTSTRAP_USERNAME", "studio"))
15
+ parser.add_argument("--email", default=os.environ.get("BOOTSTRAP_EMAIL", "admin@example.local"))
16
+ parser.add_argument("--password", default=os.environ.get("BOOTSTRAP_PASSWORD", ""))
17
17
  parser.add_argument("--project-name", default=os.environ.get("BOOTSTRAP_PROJECT_NAME", "Default"))
18
18
 
19
19
  def handle(self, *args, **options):
@@ -25,7 +25,7 @@ class Command(BaseCommand):
25
25
  raise CommandError("Refusing to bootstrap with unsafe configuration.")
26
26
  if not password:
27
27
  raise CommandError(
28
- "Bootstrap password is required. Set BOOTSTRAP_ADMIN_PASSWORD or pass --password."
28
+ "Bootstrap password is required. Set BOOTSTRAP_PASSWORD or pass --password."
29
29
  )
30
30
  user, project = bootstrap_admin_and_default_project(
31
31
  username=options["username"],
@@ -10,9 +10,9 @@ config:
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import atexit
13
14
  import logging
14
15
  import os
15
- import tempfile
16
16
  import threading
17
17
  from typing import Any
18
18
 
@@ -28,11 +28,25 @@ def is_minimal_config() -> bool:
28
28
  return os.environ.get("SIMPLEAUDIT_MINIMAL", "").strip() == "1"
29
29
 
30
30
 
31
+ def _data_dir() -> str:
32
+ """Return (and create) the persistent data dir for the embedded Postgres.
33
+
34
+ A fixed location avoids re-running initdb (~218M, ~15s) on every start.
35
+ Override with SIMPLEAUDIT_EMBEDDED_PG_DIR if needed.
36
+ """
37
+ d = os.path.expanduser(
38
+ os.environ.get("SIMPLEAUDIT_EMBEDDED_PG_DIR", "~/.simpleaudit-studio/embedded-pg")
39
+ )
40
+ os.makedirs(d, exist_ok=True)
41
+ return d
42
+
43
+
31
44
  def start_embedded_hatchet() -> Any:
32
45
  """Start an embedded Hatchet engine and return the client.
33
46
 
34
47
  The sidecar binary downloads on first use (~53 MB) and caches at
35
- ~/.hatchet/embedded/. Subsequent starts are faster.
48
+ ~/.hatchet/embedded/. The Postgres cluster persists in
49
+ ~/.simpleaudit-studio/embedded-pg/, so only the first start is slow.
36
50
 
37
51
  Returns the Hatchet client instance. Raises on failure.
38
52
  """
@@ -43,8 +57,7 @@ def start_embedded_hatchet() -> Any:
43
57
 
44
58
  from hatchet_sdk import ClientConfig, EmbeddedHatchetConfig, Hatchet
45
59
 
46
- # Use a fresh temp dir per session to avoid stale postmaster.pid locks
47
- data_dir = tempfile.mkdtemp(prefix="simpleaudit-hatchet-pg-")
60
+ data_dir = _data_dir()
48
61
  logger.info("Embedded Hatchet data dir: %s", data_dir)
49
62
 
50
63
  config = ClientConfig(
@@ -76,3 +89,7 @@ def stop_embedded_hatchet() -> None:
76
89
  def get_embedded_client() -> Any | None:
77
90
  """Return the running embedded Hatchet client, or None."""
78
91
  return _embedded_client
92
+
93
+
94
+ # Best-effort clean shutdown even if the caller forgets to stop explicitly.
95
+ atexit.register(stop_embedded_hatchet)
@@ -47,8 +47,8 @@ def validate_startup_environment(bootstrap_password: str | None = None) -> list[
47
47
  if minio_access_key in {"", "change-me"} or minio_secret_key in {"", "change-me"}:
48
48
  errors.append("MINIO_ACCESS_KEY and MINIO_SECRET_KEY must be set when MINIO_ENDPOINT is configured.")
49
49
 
50
- effective_bootstrap_password = bootstrap_password if bootstrap_password is not None else os.environ.get("BOOTSTRAP_ADMIN_PASSWORD", "")
50
+ effective_bootstrap_password = bootstrap_password if bootstrap_password is not None else os.environ.get("BOOTSTRAP_PASSWORD", "")
51
51
  if effective_bootstrap_password in {"", "change-me"}:
52
- errors.append("BOOTSTRAP_ADMIN_PASSWORD must be set and must not be change-me.")
52
+ errors.append("BOOTSTRAP_PASSWORD must be set and must not be change-me.")
53
53
 
54
54
  return errors
@@ -1,11 +1,14 @@
1
1
  import os
2
2
  from contextlib import contextmanager
3
3
 
4
+ from django.contrib.auth import get_user_model
4
5
  from django.core.management import call_command
5
6
  from django.test import TestCase
6
7
 
7
8
  from accounts.models import Project, ProjectMembership
8
9
 
10
+ User = get_user_model()
11
+
9
12
 
10
13
  @contextmanager
11
14
  def _safe_env():
@@ -36,7 +39,7 @@ class BootstrapTests(TestCase):
36
39
  for _ in range(2):
37
40
  call_command(
38
41
  "bootstrap_platform",
39
- username="admin",
42
+ username="studio",
40
43
  email="admin@example.local",
41
44
  password="admin-pass-123",
42
45
  project_name="Default",
@@ -46,3 +49,20 @@ class BootstrapTests(TestCase):
46
49
  memberships = ProjectMembership.objects.filter(project=project)
47
50
  self.assertEqual(memberships.count(), 1)
48
51
  self.assertEqual(memberships.first().role, ProjectMembership.Role.ADMIN)
52
+
53
+ def test_bootstrap_admin_is_not_superuser(self):
54
+ """The bootstrap admin must be a normal account (is_staff only), not a
55
+ Django superuser. Superuser status bypasses all workspace membership
56
+ checks, making the admin appear as owner of every workspace."""
57
+ with _safe_env():
58
+ call_command(
59
+ "bootstrap_platform",
60
+ username="studio",
61
+ email="admin@example.local",
62
+ password="admin-pass-123",
63
+ project_name="Default",
64
+ )
65
+
66
+ user = User.objects.get(username="studio")
67
+ self.assertFalse(user.is_superuser)
68
+ self.assertTrue(user.is_staff)
@@ -26,12 +26,12 @@ class TestDemoBootSequence(TestCase):
26
26
  from model_registry.models import ModelEndpoint
27
27
 
28
28
  user, project = bootstrap_admin_and_default_project(
29
- username="admin",
29
+ username="studio",
30
30
  email="admin@localhost",
31
31
  password="admin12345",
32
32
  project_name="Demo Project",
33
33
  )
34
- self.assertEqual(user.username, "admin")
34
+ self.assertEqual(user.username, "studio")
35
35
  self.assertEqual(project.name, "Demo Project")
36
36
 
37
37
  call_command("seed_platform", project=project.id, verbosity=0)
@@ -56,7 +56,7 @@ class TestDemoBootSequence(TestCase):
56
56
  from model_registry.models import ModelEndpoint
57
57
 
58
58
  _, project = bootstrap_admin_and_default_project(
59
- username="admin", email="admin@localhost", password="admin12345",
59
+ username="studio", email="admin@localhost", password="admin12345",
60
60
  project_name="Demo Project",
61
61
  )
62
62
  call_command("seed_platform", project=project.id, verbosity=0)
@@ -85,6 +85,30 @@ class TestEmbeddedHatchetLifecycle(TestCase):
85
85
  (~15s first run) but verify the full lifecycle works.
86
86
  """
87
87
 
88
+ def test_data_dir_is_persistent(self):
89
+ """The embedded Postgres data dir is a fixed location, not a temp dir."""
90
+ from infra.minimal_config import _data_dir
91
+
92
+ d1 = _data_dir()
93
+ d2 = _data_dir()
94
+ self.assertEqual(d1, d2)
95
+ self.assertTrue(os.path.isdir(d1))
96
+ # Must not be a per-run temp dir (the old leak: 37 x 218M in $TMPDIR)
97
+ self.assertNotIn("simpleaudit-hatchet-pg-", os.path.basename(d1))
98
+
99
+ def test_data_dir_env_override(self):
100
+ """SIMPLEAUDIT_EMBEDDED_PG_DIR overrides the default location."""
101
+ import tempfile as _tempfile
102
+
103
+ from infra.minimal_config import _data_dir
104
+
105
+ with patch.dict(os.environ, {"SIMPLEAUDIT_EMBEDDED_PG_DIR": "/tmp/custom-pg-dir-test"}):
106
+ d = _data_dir()
107
+ self.assertEqual(d, "/tmp/custom-pg-dir-test")
108
+ self.assertTrue(os.path.isdir(d))
109
+ import shutil
110
+ shutil.rmtree("/tmp/custom-pg-dir-test", ignore_errors=True)
111
+
88
112
  def test_start_and_stop(self):
89
113
  from infra.minimal_config import start_embedded_hatchet, stop_embedded_hatchet
90
114
 
@@ -35,7 +35,7 @@ def _safe_env():
35
35
  class SeedPlatformTests(TestCase):
36
36
  def setUp(self):
37
37
  self.user = User.objects.create_superuser(
38
- username="admin", email="admin@example.local", password="pass12345"
38
+ username="studio", email="admin@example.local", password="pass12345"
39
39
  )
40
40
  self.project = Project.objects.create(name="Default", slug="default")
41
41
  ProjectMembership.objects.create(
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "simpleaudit-studio"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Production AI model audit platform — one-liner demo mode via uvx"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -99,8 +99,8 @@ def main() -> None:
99
99
  # Give the web server a moment to bind
100
100
  time.sleep(1)
101
101
 
102
- username = os.environ.get("BOOTSTRAP_ADMIN_USERNAME", "admin")
103
- password = os.environ.get("BOOTSTRAP_ADMIN_PASSWORD", "admin12345")
102
+ username = os.environ.get("BOOTSTRAP_USERNAME", "studio")
103
+ password = os.environ.get("BOOTSTRAP_PASSWORD", "admin12345")
104
104
 
105
105
  print("┌─────────────────────────────────────────────────────────┐")
106
106
  print("│ │")
@@ -140,9 +140,9 @@ def _seed_demo_data() -> None:
140
140
  from django.core.management import call_command
141
141
 
142
142
  # Respect env vars (set by Dockerfile for HF Space, or defaults for local)
143
- username = os.environ.get("BOOTSTRAP_ADMIN_USERNAME", "admin")
144
- email = os.environ.get("BOOTSTRAP_ADMIN_EMAIL", "admin@localhost")
145
- password = os.environ.get("BOOTSTRAP_ADMIN_PASSWORD", "admin12345")
143
+ username = os.environ.get("BOOTSTRAP_USERNAME", "studio")
144
+ email = os.environ.get("BOOTSTRAP_EMAIL", "admin@localhost")
145
+ password = os.environ.get("BOOTSTRAP_PASSWORD", "admin12345")
146
146
  project_name = os.environ.get("BOOTSTRAP_PROJECT_NAME", "Demo Project")
147
147
 
148
148
  user, project = bootstrap_admin_and_default_project(