From 0ee22f8fb06853ebd78cf65397d8fc26c0161ad9 Mon Sep 17 00:00:00 2001 From: ZdenekSrotyr Date: Sat, 2 May 2026 20:59:25 +0200 Subject: [PATCH] docs: add setup-banner.md + rename migration test to test_db_schema_version.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add docs/setup-banner.md: placeholder table, autoescape semantics, security note on post-render stripping, diff table vs welcome-template (M-9). - Update CHANGELOG.md to reference docs/setup-banner.md. - Rename tests/test_db_migration_v20.py → tests/test_db_schema_version.py (file tested SCHEMA_VERSION==22, not just the v20 step; clearer name) (M-10). --- CHANGELOG.md | 2 +- docs/setup-banner.md | 94 +++++++++++++++++++ ...ation_v20.py => test_db_schema_version.py} | 0 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 docs/setup-banner.md rename tests/{test_db_migration_v20.py => test_db_schema_version.py} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82fa0ed..7ea27f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C ### Added -- Admin-editable banner on `/setup` page — admins can author a Jinja2/HTML banner displayed above the auto-generated bootstrap commands. Empty by default (no banner shown). Edit at `/admin/setup-banner`. Endpoints: `GET /api/admin/setup-banner` (returns content + audit), `PUT` to set, `DELETE` to clear, `POST /api/admin/setup-banner/preview` for live preview. Useful for org-specific notes: VPN requirements, support channel, data classification, platform prerequisites. +- Admin-editable banner on `/setup` page — admins can author a Jinja2/HTML banner displayed above the auto-generated bootstrap commands. Empty by default (no banner shown). Edit at `/admin/setup-banner`. Endpoints: `GET /api/admin/setup-banner` (returns content + audit), `PUT` to set, `DELETE` to clear, `POST /api/admin/setup-banner/preview` for live preview. Useful for org-specific notes: VPN requirements, support channel, data classification, platform prerequisites. See `docs/setup-banner.md` for the full placeholder reference and security notes. - DuckDB schema v22: `setup_banner` singleton table for the per-instance banner. Auto-migration v21→v22 on first start. - Customizable analyst welcome prompt (`CLAUDE.md` generated by `da analyst setup`). Default ships at `config/claude_md_template.txt` (now Jinja2 syntax). Admins override per instance via the `/admin/welcome` editor or `PUT /api/admin/welcome-template`. New endpoint `GET /api/welcome` returns the rendered prompt for the calling user, with `marketplaces` filtered by RBAC. See `docs/welcome-template.md` for the full placeholder reference. - `POST /api/admin/welcome-template/preview` — renders arbitrary template content against the calling admin's live context without persisting. Backs the editor's Preview button. diff --git a/docs/setup-banner.md b/docs/setup-banner.md new file mode 100644 index 0000000..4aa11f7 --- /dev/null +++ b/docs/setup-banner.md @@ -0,0 +1,94 @@ +# Setup page banner + +The setup banner is a block of HTML (or plain text) shown **above** the +auto-generated bootstrap commands on the `/setup` page. Use it for +org-specific operational notes that analysts need before they install the +client: VPN requirements, support channel, data-classification policy, +platform prerequisites, etc. + +The banner is empty by default — no content is shown until an admin sets one. + +## How to edit + +- **Admin UI:** `/admin/setup-banner` — split-pane editor with a placeholder + cheatsheet and a live HTML preview. Click **Save banner** to persist, + **Remove banner** to clear. +- **REST API:** + - `GET /api/admin/setup-banner` — returns `{content, updated_at, updated_by}`. + `content` is `null` when no banner is set. + - `PUT /api/admin/setup-banner` with body `{"content": "..."}` — validates + Jinja2 syntax and stores the banner. + - `DELETE /api/admin/setup-banner` — clears the banner; `/setup` shows no + banner until one is set again. + - `POST /api/admin/setup-banner/preview` with body `{"content": "..."}` — + renders arbitrary content against the calling admin's context without + persisting. Backs the editor's live preview. + +The banner lives in `system.duckdb` (table `setup_banner`, singleton row id=1). + +## Available placeholders + +| Placeholder | Type | Notes | +|---|---|---| +| `instance.name` | string | `instance.name` in `instance.yaml` | +| `instance.subtitle` | string | `instance.subtitle` in `instance.yaml` | +| `server.url` | string | full origin of the Agnes server | +| `server.hostname` | string | host part only (no port or path) | +| `user.email` | string | logged-in user, or `null` for anonymous visitors | +| `user.name` | string | logged-in user display name | +| `user.is_admin` | bool | `true` when the visitor is in the Admin group | +| `now` | datetime (UTC, tz-aware) | server time at render | +| `today` | string (`YYYY-MM-DD`) | server date at render | + +> **`user` may be `null`** — `/setup` is partly public (anonymous visitors +> get the install one-liner). Always guard user-specific placeholders: +> +> ```jinja2 +> {% if user %}Welcome back, {{ user.name }}!{% endif %} +> ``` + +## Autoescape semantics + +The Jinja2 environment runs with `autoescape=True`, which means template +**variable output** (`{{ ... }}`) is HTML-escaped automatically. Literal HTML +in the template source is passed through unchanged — that is how the banner +outputs `

` tags, ``, etc. + +To output a literal `<` or `&` from a variable, use the `| safe` filter only +when you are certain the value is trusted: + +```jinja2 +{# Safe — admin-authored constant: #} +{{ "VPN required" | safe }} + +{# Dangerous — never pipe user-controlled values through | safe: #} +{{ user.name | safe }} {# do NOT do this #} +``` + +## Security note + +Admin-authored banner content is rendered for **all `/setup` visitors**, +including anonymous users. As a defense-in-depth measure, inline `