diff --git a/.fabro/rules.yaml b/.fabro/rules.yaml deleted file mode 100644 index 53e09f714..000000000 --- a/.fabro/rules.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Repository review rules for the code-review workflow (xhigh/max tiers -# audit the full set; medium audits these plus the AGENTS.md pack). -# -# Rules are read from a review's base revision, so a change here takes -# effect after it lands. Validate before committing: -# python3 .fabro/workflows/code-review/scripts/code_review.py lint-rules -version: 1 - -rules: - - id: project.generated-docs - description: > - Generated reference regions are owned by `cargo dev docs refresh`; - hand edits are overwritten on the next refresh and fail the - staleness check. - match: - paths: - - "docs/public/reference/cli.mdx" - - "docs/public/reference/user-configuration.mdx" - checks: - - id: generated-region-integrity - category: conventions - guidance: | - Content between a `{/* generated:... */}` marker and its closing - `{/* /generated:... */}` marker is generator output. Flag any - hand-written change inside those markers; anchor at the edited - line. The fix is to change the generator's source (the CLI's - clap definitions or the options source) and run - `cargo dev docs refresh`. Edits outside the markers are ordinary - documentation and are fine. - - - id: project.cli-reference-sync - description: > - The CLI reference is captured from the CLI's own help output. - match: - paths: - - "lib/apps/fabro-cli/src/args.rs" - checks: - - id: docs-refresh - category: conventions - guidance: | - A change that adds, removes, or renames a CLI argument or - subcommand, or changes its help text or default value, must - include the regenerated `docs/public/reference/cli.mdx` in the - same change (run `cargo dev docs refresh`). Anchor the finding - at the changed argument, not at the documentation file. Purely - internal changes that do not alter the CLI's help output need no - refresh. diff --git a/.fabro/workflows/code-review/code-review.fabro b/.fabro/workflows/code-review/code-review.fabro index e577ecd13..0300475b2 100644 --- a/.fabro/workflows/code-review/code-review.fabro +++ b/.fabro/workflows/code-review/code-review.fabro @@ -33,7 +33,7 @@ digraph CodeReview { timeout="300s", output_schema="routing", stdin_source="context.internal.run_id", - script="python3 -c \"import hashlib,sys; pairs=list(zip(sys.argv[1::2],sys.argv[2::2])); sys.exit(0 if pairs and all(hashlib.sha256(open(path,'rb').read()).hexdigest()==expected for path,expected in pairs) else 91)\" .fabro/workflows/code-review/scripts/code_review.py 961fe81afa6a5c80432d8e8a05791d6c12ccc724e9f945e7190bbac77a6121d2 .fabro/workflows/code-review/scripts/git_readonly.py bcd4364ba3aca2ee1e12d5909204f645c16bdf22e3753a39d74c79d8d37cf73e .fabro/workflows/code-review/scripts/publish_pr.py fe65b5c710e6f486bf0b4a0da4933b53b954c32481313efd8d60d34b3dcc3a44 .fabro/workflows/code-review/scripts/render_report.py 91ea86428ed4759fbb368b4fa90ca8f54f1ab05f09f18bc8a4e9ffa188ed2295 .fabro/workflows/code-review/scripts/rule_loader.py f885409c64c631075d7e31fcb6e7a100592430c5eba9a6e989222006061a9f52 .fabro/workflows/code-review/specs/report-spec.md 7a54f72ee46f09218d18854d184a1f36875f9011877e94779c6b1f0d5dd118a9 .fabro/workflows/code-review/templates/report.html 5def570da34ca186da31781378367d70fb9c58e82f7aeec4aaf420fd348a8e61 .fabro/workflows/code-review/schemas/findings.schema.json 2f4d0a9052d5af0dad92db12a1e9d49cc91a282c4dddda495791352bf1559ed8 .fabro/workflows/code-review/schemas/verdict.schema.json de13ce02c5fd0c088640542831cc732e35dee3ddb38f89d4412f6a46fea75567 .fabro/workflows/code-review/schemas/file-groups.schema.json b53c4e1c0bbd07bbf70e83f4f3b35fd96cb880c621c7c424e95b9aea34e13d7c .fabro/workflows/code-review/prompts/finder.md.j2 86c2e6a032f7c54c1bbab1c12496a8f0d6bf48703abe6017eb175330608cf223 .fabro/workflows/code-review/prompts/verify.md.j2 cb3866240077d1bc8993b2f012a8d66a6ea61d4a9f2e88a1fefc6ef375f630e2 .fabro/workflows/code-review/prompts/sweep.md.j2 e6f89b47b11c57030a6ef7d5896ccb37dbd2a2982e9fa7eb7f2e3df73acab82c .fabro/workflows/code-review/prompts/group-files.md.j2 5b291313a1266d1d658f80ea7989cdefcd8609b6893b7197b17914d553dab041 .fabro/workflows/code-review/prompts/partials/finding-fields.md.j2 a81ee5b0ac134eb121dbf503025387c64126d3276e4673ebc836cfb62a3689fb .fabro/workflows/code-review/prompts/partials/guidance.md.j2 53bc0c40bb917288708bed1f9ba478fbd89b9790c92497762224cc752f40bef5 .fabro/workflows/code-review/prompts/partials/output-schema.md.j2 811994bb357739f2562d84f66dc05075ebe3c7f8d58034f8c25ee1c36bee996b .fabro/workflows/code-review/prompts/partials/read-only-explorer.md.j2 44a0244e7aa62fdb0dbbfdbadcffbfb640af249bae3e96895dedd5c7a33bad10 .fabro/workflows/code-review/prompts/partials/review-target.md.j2 abffeeff0e16b89a0754cd53f1833b3744494cd54ff761798b782a80467446ea .fabro/workflows/code-review/prompts/partials/safe-git-history.md.j2 4ddd8d36d5c51d7e166a6b7f1dff51b72cce0e64108cc7e892002ca909af8b3a .fabro/workflows/code-review/rules/builtin-manifest.json 47e3123fb25c560e36216dc9b8323c86e8301f1868a4fa3219bfd59bda3a533a && python3 .fabro/workflows/code-review/scripts/code_review.py prepare --review-id-stdin --mode {{ inputs.mode }} --effort {{ inputs.effort }} --scope {{ inputs.scope }} --base {{ inputs.base }} --commit {{ inputs.commit }} --range {{ inputs.range }} --model {{ inputs.model }} --guidance {{ inputs.guidance }}" + script="python3 -c \"import hashlib,sys; pairs=list(zip(sys.argv[1::2],sys.argv[2::2])); sys.exit(0 if pairs and all(hashlib.sha256(open(path,'rb').read()).hexdigest()==expected for path,expected in pairs) else 91)\" .fabro/workflows/code-review/scripts/code_review.py 6770c5ea6673063ea63a9bbef178c37b5427f24476122a4333eff7c4d390bbc2 .fabro/workflows/code-review/scripts/git_readonly.py bcd4364ba3aca2ee1e12d5909204f645c16bdf22e3753a39d74c79d8d37cf73e .fabro/workflows/code-review/scripts/publish_pr.py b69d8ed821293f05cb56e1719c460ac69d5fa08f9ea3123c3fca6811309087da .fabro/workflows/code-review/scripts/render_report.py 79def74b4415f1a6d1d58cab6480450fed2ee9de11105db95e0996ed08057085 .fabro/workflows/code-review/scripts/rule_loader.py 6cb9c665db54d4dd799acd0867c9a68ad0a26e19de804d63b7781abbd43d60e6 .fabro/workflows/code-review/specs/report-spec.md 7a54f72ee46f09218d18854d184a1f36875f9011877e94779c6b1f0d5dd118a9 .fabro/workflows/code-review/templates/report.html 5def570da34ca186da31781378367d70fb9c58e82f7aeec4aaf420fd348a8e61 .fabro/workflows/code-review/schemas/findings.schema.json 2f4d0a9052d5af0dad92db12a1e9d49cc91a282c4dddda495791352bf1559ed8 .fabro/workflows/code-review/schemas/verdict.schema.json de13ce02c5fd0c088640542831cc732e35dee3ddb38f89d4412f6a46fea75567 .fabro/workflows/code-review/schemas/file-groups.schema.json b53c4e1c0bbd07bbf70e83f4f3b35fd96cb880c621c7c424e95b9aea34e13d7c .fabro/workflows/code-review/prompts/finder.md.j2 86c2e6a032f7c54c1bbab1c12496a8f0d6bf48703abe6017eb175330608cf223 .fabro/workflows/code-review/prompts/verify.md.j2 cb3866240077d1bc8993b2f012a8d66a6ea61d4a9f2e88a1fefc6ef375f630e2 .fabro/workflows/code-review/prompts/sweep.md.j2 e6f89b47b11c57030a6ef7d5896ccb37dbd2a2982e9fa7eb7f2e3df73acab82c .fabro/workflows/code-review/prompts/group-files.md.j2 5b291313a1266d1d658f80ea7989cdefcd8609b6893b7197b17914d553dab041 .fabro/workflows/code-review/prompts/partials/finding-fields.md.j2 a81ee5b0ac134eb121dbf503025387c64126d3276e4673ebc836cfb62a3689fb .fabro/workflows/code-review/prompts/partials/guidance.md.j2 53bc0c40bb917288708bed1f9ba478fbd89b9790c92497762224cc752f40bef5 .fabro/workflows/code-review/prompts/partials/output-schema.md.j2 811994bb357739f2562d84f66dc05075ebe3c7f8d58034f8c25ee1c36bee996b .fabro/workflows/code-review/prompts/partials/read-only-explorer.md.j2 44a0244e7aa62fdb0dbbfdbadcffbfb640af249bae3e96895dedd5c7a33bad10 .fabro/workflows/code-review/prompts/partials/review-target.md.j2 abffeeff0e16b89a0754cd53f1833b3744494cd54ff761798b782a80467446ea .fabro/workflows/code-review/prompts/partials/safe-git-history.md.j2 4ddd8d36d5c51d7e166a6b7f1dff51b72cce0e64108cc7e892002ca909af8b3a .fabro/workflows/code-review/rules/builtin-manifest.json 68f853c1624e6a14596d0d5b79501b8b4ba182ce65a7670af413c667fbd84fc8 && python3 .fabro/workflows/code-review/scripts/code_review.py prepare --review-id-stdin --mode {{ inputs.mode }} --effort {{ inputs.effort }} --scope {{ inputs.scope }} --base {{ inputs.base }} --commit {{ inputs.commit }} --range {{ inputs.range }} --model {{ inputs.model }} --guidance {{ inputs.guidance }}" ] grouping [ @@ -43,7 +43,7 @@ digraph CodeReview { output_schema="@schemas/file-groups.schema.json", output_retries=2, max_retries=2, - on_failure="succeed", + on_failure="route", timeout="1800s", project_memory=false ] @@ -140,7 +140,7 @@ digraph CodeReview { output_schema="@schemas/findings.schema.json", output_retries=2, max_retries=2, - on_failure="succeed", + on_failure="route", timeout="7200s", project_memory=false ] diff --git a/.fabro/workflows/code-review/fixtures/inventory_utils.py b/.fabro/workflows/code-review/fixtures/inventory_utils.py deleted file mode 100644 index d7b767d7f..000000000 --- a/.fabro/workflows/code-review/fixtures/inventory_utils.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Inventory helpers for the demo storefront. - -Deliberate review fixture: this module plants small correctness bugs for the -workflow's smoke run. Do not fix them; the smoke run expects to find them. -""" - -from __future__ import annotations - -import json -from pathlib import Path -from typing import Dict, List, Optional - - -def pick_discount( - user: Dict[str, object], - discounts: Dict[int, float], -) -> Optional[float]: - """Return the user's discount rate, or None when they have none.""" - discount_id = user.get("discount_id") - # Deliberate bug: discount id 0 is a valid catalog entry, but the falsy - # check treats it as "no discount configured". - if not discount_id: - return None - return discounts.get(int(discount_id)) # type: ignore[arg-type] - - -def total_in_stock(warehouse_counts: List[int]) -> int: - """Sum the units available across every warehouse.""" - total = 0 - # Deliberate bug: the off-by-one range never counts the last warehouse. - for index in range(len(warehouse_counts) - 1): - total += warehouse_counts[index] - return total - - -def load_price_overrides(path: str) -> Dict[str, float]: - """Read per-SKU price overrides, returning {} when the file is absent.""" - overrides: Dict[str, float] = {} - try: - raw = Path(path).read_text(encoding="utf-8") - for sku, price in json.loads(raw).items(): - overrides[str(sku)] = float(price) - except Exception: - # Deliberate bug: a corrupt overrides file is silently ignored, so - # every SKU quietly sells at the stale base price. - pass - return overrides diff --git a/.fabro/workflows/code-review/fixtures/override_probe.py b/.fabro/workflows/code-review/fixtures/override_probe.py deleted file mode 100644 index 682377630..000000000 --- a/.fabro/workflows/code-review/fixtures/override_probe.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Fixture matched by the repository override rule. - -The repository rule ``project.fixture-override`` uses ``mode: override``, -so the built-in Python checks are suppressed for this file and only the -``no-print`` check applies. The ``print`` call below is its planted -violation. -""" - - -def announce(message): - print("announce:", message) - return None diff --git a/.fabro/workflows/code-review/fixtures/publish_probe.py b/.fabro/workflows/code-review/fixtures/publish_probe.py deleted file mode 100644 index c70c0ed45..000000000 --- a/.fabro/workflows/code-review/fixtures/publish_probe.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Deliberately flawed fixture for the PR publisher's live acceptance run. - -Planted correctness bugs, so a refresh commit reviewed with post_pr -enabled is guaranteed inline-postable findings: - -- ``percentile`` indexes past the end of the list when fraction is 1.0. -- ``moving_average`` divides every window by the full window size, so the - tail averages are too small. -- ``collect_values`` reuses its default list across calls, so results leak - between otherwise independent calls. -""" - - -def percentile(values, fraction): - """Return the value at the given fraction of the sorted input.""" - ordered = sorted(values) - index = int(len(ordered) * fraction) - return ordered[index] - - -def moving_average(values, window): - """Average each window of the input, including the shorter tail.""" - averages = [] - for start in range(len(values)): - chunk = values[start:start + window] - averages.append(sum(chunk) / window) - return averages - - -def collect_values(values, collected=[]): - """Collect values for one independent operation.""" - collected.extend(values) - return collected diff --git a/.fabro/workflows/code-review/fixtures/rules_probe.py b/.fabro/workflows/code-review/fixtures/rules_probe.py deleted file mode 100644 index d8db1a5d2..000000000 --- a/.fabro/workflows/code-review/fixtures/rules_probe.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Deliberately flawed fixture for the xhigh rule verification run. - -Two planted violations: -- ``record_event`` uses a mutable default argument, which the built-in - Python rule pack flags. -- ``clear_events`` is missing from the Functions list below, which the - repository rule ``project.fixture-inventory/function-inventory`` flags. - -Functions: -- record_event -""" - - -def record_event(name, events=[]): - events.append(name) - return events - - -def clear_events(events): - events.clear() - return events diff --git a/.fabro/workflows/code-review/rules/builtin-manifest.json b/.fabro/workflows/code-review/rules/builtin-manifest.json index 3407a6eb3..d5743cf6d 100644 --- a/.fabro/workflows/code-review/rules/builtin-manifest.json +++ b/.fabro/workflows/code-review/rules/builtin-manifest.json @@ -6,7 +6,7 @@ }, { "path": "rules/builtin/format/bicep.yaml", - "sha256": "1b549eb4ea83a0fa23d0a1d139266dcc80cb1aeb514212602d5ad0fbd74473da" + "sha256": "0a4191dcbccec9a45c584d0796d00ffc9e857780b93d24f9edf3f060e80d77c2" }, { "path": "rules/builtin/format/build-gradle.yaml", @@ -58,7 +58,7 @@ }, { "path": "rules/builtin/format/pot.yaml", - "sha256": "f0ed089cfa808c2407066ed84da55b9359bdbac07754a43d1bcaf730405130a1" + "sha256": "223422af99eecfb72463d7f8e1de9095130eacfa302e7b1a4d3ea4a009922410" }, { "path": "rules/builtin/format/prisma.yaml", @@ -74,7 +74,7 @@ }, { "path": "rules/builtin/format/terraform.yaml", - "sha256": "bbfd40afa55f8131086c1a3d5f2a57dffd34879bfd17b12233f5cac9c61ffbd2" + "sha256": "81d83048def9ee11630242e3fb9129f27a3193bc469f62bcaf243c863e8992f0" }, { "path": "rules/builtin/format/thrift.yaml", @@ -106,7 +106,7 @@ }, { "path": "rules/builtin/language/freemarker.yaml", - "sha256": "4b71fdd2dacacbb4969687bb227e449683b0486035d902c763784cee13086367" + "sha256": "a4b7be672e84d5cb0fd335a02279542e96ad0ae880327ccd59d2566fc410a235" }, { "path": "rules/builtin/language/go.yaml", @@ -122,7 +122,7 @@ }, { "path": "rules/builtin/language/javascript-typescript.yaml", - "sha256": "a11a5ff6c37217ab7938cdf05b1dfbf71cfbd1ea3c7e78bb71adbd973f6aaed1" + "sha256": "ecdc07ad6a61db8f9d1ad8a80544831992c071a2c0eb54cf92ed391d6bf4eaab" }, { "path": "rules/builtin/language/jsonnet.yaml", @@ -134,7 +134,7 @@ }, { "path": "rules/builtin/language/kotlin.yaml", - "sha256": "c5ed824fbace28b161d1d0ac6c6e9b554ffed22085b2dd4a5c4fe1a9e4672160" + "sha256": "14a7545bf6f2817051a1c67d2266d4d5513c8a306f203300fc363a6da88e61a5" }, { "path": "rules/builtin/language/matlab.yaml", diff --git a/.fabro/workflows/code-review/rules/builtin/format/bicep.yaml b/.fabro/workflows/code-review/rules/builtin/format/bicep.yaml index 8209d1320..f852c41d2 100644 --- a/.fabro/workflows/code-review/rules/builtin/format/bicep.yaml +++ b/.fabro/workflows/code-review/rules/builtin/format/bicep.yaml @@ -32,7 +32,7 @@ rules: - id: insecure-resource-defaults category: correctness guidance: | - - A storage account without `minimumTlsVersion` set to a current version, or with `supportsHttpsTrafficOnly` explicitly set to `false` + - A storage account with `minimumTlsVersion` explicitly set to an outdated TLS version, or with `supportsHttpsTrafficOnly` explicitly set to `false` - A resource property that disables encryption-at-rest or transparent data encryption where the resource type supports enabling it - Do not flag a resource for merely omitting an optional hardening property when the diff gives no indication either way — only flag an explicit insecure value or an explicit disabling of a secure default - id: versioning-and-reproducibility diff --git a/.fabro/workflows/code-review/rules/builtin/format/pot.yaml b/.fabro/workflows/code-review/rules/builtin/format/pot.yaml index ee41ebba9..19dcf0e53 100644 --- a/.fabro/workflows/code-review/rules/builtin/format/pot.yaml +++ b/.fabro/workflows/code-review/rules/builtin/format/pot.yaml @@ -25,7 +25,7 @@ rules: - Unbalanced or unescaped quotes in `msgid`/`msgid_plural` strings, breaking the entry - Multi-line continuation strings concatenated incorrectly (missing trailing space/newline between fragments that changes the resulting text) - Orphaned `msgid_plural` or `msgstr` without a preceding `msgid` - - Duplicate `msgid` definitions within the file that conflict with each other (different `msgctxt`, comments, or placeholders) + - Duplicate entries with the same `msgctxt` and `msgid` that conflict in comments or placeholders; the same `msgid` under different `msgctxt` values is valid disambiguation - A non-empty `msgstr` in a template entry, which usually means a translation was accidentally committed into the template - id: placeholder-consistency category: correctness diff --git a/.fabro/workflows/code-review/rules/builtin/format/terraform.yaml b/.fabro/workflows/code-review/rules/builtin/format/terraform.yaml index e9b9ba78e..a26f8d202 100644 --- a/.fabro/workflows/code-review/rules/builtin/format/terraform.yaml +++ b/.fabro/workflows/code-review/rules/builtin/format/terraform.yaml @@ -12,6 +12,8 @@ rules: match: paths: - "**/*.{tf,hcl,tfvars}" + - "**/*.tfstate" + - "**/*.tfstate.backup" checks: - id: obvious-typos-or-spelling-errors category: conventions diff --git a/.fabro/workflows/code-review/rules/builtin/language/freemarker.yaml b/.fabro/workflows/code-review/rules/builtin/language/freemarker.yaml index f30fb3e6b..3b7cf2f60 100644 --- a/.fabro/workflows/code-review/rules/builtin/language/freemarker.yaml +++ b/.fabro/workflows/code-review/rules/builtin/language/freemarker.yaml @@ -20,7 +20,7 @@ rules: - id: output-escaping-and-xss category: correctness guidance: | - - Interpolations (`${...}`) that reach HTML without escaping: flag only when auto-escaping is not already active — i.e. the template lacks `<#ftl output_format="HTML">` (FreeMarker 2.3.24+) AND does not use the `.ftlh`/`.ftlx` extension (which auto-activate HTML/XML escaping via `recognize_standard_file_extensions`, on by default since 2.3.24) — and the value is not passed through `?html`/`?url`/`?js_string` appropriate to its sink (HTML body, attribute, URL, JS, CSS) + - Interpolations (`${...}`) that reach HTML without escaping: flag only when auto-escaping is not already active — for example through `<#ftl output_format="HTML">`, or through a `.ftlh`/`.ftlx` extension when `recognize_standard_file_extensions` is enabled (its default depends on `incompatible_improvements`) — and the value is not passed through `?html`/`?url`/`?js_string` appropriate to its sink (HTML body, attribute, URL, JS, CSS) - Explicit `?no_esc` or `<#noautoesc>` on values that carry user-controlled data — treat as a high-risk escape hatch; flag unless the source is clearly trusted or already sanitized - Escaping with the wrong context builtin (e.g. `?html` for a value placed inside a URL or inline `