Spec:specs/template.allium invariants 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.
Current behaviour (RuDS):crates/bds-core/src/engine/template.rs fn validate_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_template to 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 for bds.templates.validate in the scripting host and MCP propose_template — verify those paths use validate_template.
Acceptance: All ported bDS2 cases pass; publishing a template with {{ title | upcase }} fails and leaves it draft.
**Source:** Audit section 1.3 (high impact).
**Spec:** `specs/template.allium` invariants 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.ex` returns e.g. `{:error, "unsupported filter: upcase"}`; `publish_template` refuses 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.rs` fn `validate_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_template` to 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 for `bds.templates.validate` in the scripting host and MCP propose_template — verify those paths use `validate_template`.
**Acceptance:** All ported bDS2 cases pass; publishing a template with `{{ title | upcase }}` fails and leaves it draft.
hugo
added the bug label 2026-07-20 19:43:56 +00:00
Implemented in 3ac7a8b and 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.
Implemented in 3ac7a8b and 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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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.