Enforce Liquid tag/filter/operator subset at template publish #67
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Source: Audit section 1.3 (high impact).
Spec:
specs/template.alliuminvariants LiquidTagSubset / LiquidFilterSubset / LiquidOperatorSubset explicitly state the subset is "Enforced at publish/validation time; any other filter/operator is rejected even though the engine would otherwise apply it." Allowed: tags if/elsif/else/endif, for, assign, render (named params), whitespace variants; filters escape, url_encode, default, append + custom i18n, markdown, slugify; operators ==, >, and, or, bare truthiness, blank; dot/.size/bracket access.bDS2 behaviour:
../bDS2/lib/bds/rendering/liquid_parser.exreturns e.g.{:error, "unsupported filter: upcase"};publish_templaterefuses and the template stays draft. Tests:../bDS2/test/bds/templates_test.exs(~lines 330-400) cover rejected tags, rejected filters (upcase, downcase, date, truncate, split, reverse), allowed filters (escape, url_encode, slugify), rejected operators (!=, <, >=, <=, contains).Current behaviour (RuDS):
crates/bds-core/src/engine/template.rsfnvalidate_template(line 138) only checks{{ }}/{% %}bracket balance and if/for block matching (validate_liquid_brackets,validate_liquid_blocks). Unsupported constructs publish fine.Task: Extend
validate_templateto parse tags, filters, and comparison operators and reject anything outside the subset with bDS2-compatible messages ("unsupported filter: {name}", "unsupported tag: {name}", "unsupported operator: {op}"). Port the bDS2 test matrix to Rust tests. The same validation runs forbds.templates.validatein the scripting host and MCP propose_template — verify those paths usevalidate_template.Acceptance: All ported bDS2 cases pass; publishing a template with
{{ title | upcase }}fails and leaves it draft.Implemented in
3ac7a8band pushed to origin/main. Template validation now enforces the exact Allium/bDS2 Liquid surface: if/elsif/else, for, assign, render with named parameters, whitespace-control variants; escape, url_encode, default, append, i18n, markdown, slugify; and only ==/> comparisons with and/or, truthiness, blank, dot/.size, and bracket access. Unsupported constructs return the bDS2-compatible messages unsupported tag/filter/operator: name. Validation now also runs through the same real Liquid parser configuration used by rendering. Publish failure leaves the template draft, preserves DB content, and writes no file. Tests port the bDS2 rejection/allowance matrix, validate all bundled starter templates, verify bds.templates.validate returns the same error, and verify MCP propose_template creates no proposal on rejection. Verification: cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo build --workspace, cargo test --workspace (bds-core 487 passed/1 ignored; bds-ui 170 passed; all integration/doc tests passed), git diff --check, allium check specs, and allium analyse specs. A neutral issue/bDS2/spec/code-path review found no remaining gap.