Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: Apache-2.0

[tool.bumpversion]
current_version = "0.19.6"
current_version = "0.20.0"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)((?P<pre_l>a|b|rc)(?P<pre_n>\\d+))?"
serialize = [
"{major}.{minor}.{patch}{pre_l}{pre_n}",
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/security_vulnerability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ body:
attributes:
label: Zenzic version
description: Output of `zenzic --version`
placeholder: "0.19.6"
placeholder: "0.20.0"
validations:
required: true

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
# Legacy draft vaults
.draft/
/drafts/
docs/.drafts/

zenzic.code-workspace
.gemini/
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#
# repos:
# - repo: https://github.com/PythonWoods/zenzic
# rev: v0.19.6
# rev: v0.20.0
# hooks:
# - id: zenzic-verify # quality gate — corrisponde a `just verify` lato zenzic
# - id: zenzic-guard # fast staged-file credential scan
Expand Down
11 changes: 10 additions & 1 deletion .zenzic.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
# docs_dir = "."

strict = true
fail_under = 100
fail_under = 99
# -1 pt: docs/blog/posts/2026-04-28-welcome.md [Z104] — RSS/Atom build artifacts (per_file_ignores)
# exit_zero = false
# respect_vcs_ignore = true
# validate_same_page_anchors = true
Expand Down Expand Up @@ -55,3 +56,11 @@ excluded_file_patterns = []
"docs/blog/rss.xsl" = ["Z405"]
"docs/tutorials/examples/z1xx-links/**" = ["Z107"]
"docs/tutorials/examples/z5xx-content/**" = ["Z506", "Z503"]
# Exempt reference file from syntax checks because it contains intentionally incorrect examples
"docs/reference/finding-codes.md" = ["Z503"]

[governance.per_file_ignores]
# RSS/Atom feed files are generated build artifacts (MkDocs blog plugin output).
# They are not present in the docs/ source tree, so Z104 fires on the relative paths.
# This is intentional: the links are correct at serve time but unresolvable at lint time.
"docs/blog/posts/2026-04-28-welcome.md" = ["Z104"]
107 changes: 36 additions & 71 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,85 +11,50 @@ Versions follow [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [0.19.6] - 2026-07-04
## [0.20.0] — 2026-07-04

### 🔒 Security Advisory
### ✨ The Extensibility Update

This patch release resolves three vulnerabilities identified during Red Team adversarial audits. All users are advised to update to ensure DQS integrity and CI stability.

### Fixed

- **Security (DQS Evasion):** Resolved the "Ghost Policy" bypass where developers could evade the Suppression Cap and DQS penalties by injecting leading spaces (e.g., `" Z101"`) into `.zenzic.toml` policies. The scoring engine now strictly sanitizes inputs.
- **Security (DoS via TOML Bomb):** Hardened the configuration parser against mixed-type arrays. Malformed arrays no longer cause unhandled Python tracebacks (crashing the CI runner) but are safely caught and reported as `Z001` (Fatal Config Error).
- **Security (Z603 Evasion):** Fixed a logical flaw where duplicate inline suppressions on the same line were all marked as "consumed" by a single finding. Duplicates now correctly trigger `Z603` (Dead Suppression) to prevent hidden debt.

## [0.19.5] - 2026-07-04

### Fixed

- **Core (Validator):** Hardened the Polyglot Extractor by masking HTML and MD/MDX comments to ignore tags within comments, preventing false-positive diagnostics and aligning with Markdown link scanning.
- **Core (Validator):** Aligned code fence detection in the Polyglot Extractor with `SuppressionTracker` by ignoring closing fences with trailing characters (e.g. ```` ```extra ````), preventing premature code block closure.

## [0.19.4] - 2026-07-04

### Fixed

- **Core (Mutator):** Hardened the Atomic Write Barrier to correctly follow symlinks during auto-fix operations, preventing the accidental overwriting of the symlink file itself.
- **Core (Mutator):** Implemented a robust `try...finally` cleanup routine to guarantee the removal of transient `.zenzic-tmp-*` files even if the process receives a `KeyboardInterrupt` (SIGINT) during an atomic write.
- **Diagnostics (Z108):** Enhanced the Z108 (Empty Link Text) regex and AST mutator to correctly detect and patch "formatted empty links" (e.g., `[**](url)` or `` [` `](url) ``), eliminating an AST drift edge-case.

## [0.19.3] — 2026-07-02

### 🔒 Security Advisory

This patch release addresses a security vulnerability in the Polyglot Extractor introduced in `v0.19.0`. All users utilizing Zenzic as a CI security gate are strongly advised to update immediately.

### Fixed

- **Security (Z205 Bypass):** Resolved a parser differential vulnerability where attackers could evade the `Z205` (Forbidden Scheme) security gate. The extractor now correctly adheres to the HTML5 "first-wins" attribute parsing rule, preventing "Double Href" injection attacks.
- **Security (Encoding Evasion):** The engine now correctly unescapes HTML entities and strips obfuscating control characters before evaluating URI schemes, preventing bypasses using encoded `javascript:` or `data:` payloads.

### Technical Details

- **Performance:** The security hardening maintains the strict $O(N)$ (RE2/DFA-pure) execution time invariant.
- **DQS Invariant:** Repository Documentation Quality Score remains verified at 100/100.

## [0.19.2] — 2026-07-02

### Fixed

- **Performance (LCP):** Optimized Critical Rendering Path by injecting `<link rel="preconnect">` resource hints for the GitHub API, significantly reducing latency for client-side widgets.
- **Performance (CSS):** Implemented strict Tailwind CSS purging via `tailwind.config.js`, removing unused utility classes and minimizing the frontend payload.

### Technical Details

- **DQS Invariant:** Repository Documentation Quality Score remains verified at 100/100.

## [0.19.1] - 2026-07-02

### Fixed

- **Accessibility:** Resolved WCAG 2.1 AA contrast failures across homepage templates by shifting light mode secondary text to `zinc-600` and dark mode secondary text to `zinc-400`.
- **Accessibility:** Added accessible name via `aria-label="Search dialog"` to the search dialog component for screen readers and agentic navigation.
- **Performance:** Self-hosted Google Font files (Inter, IBM Plex Mono, Barlow Condensed, JetBrains Mono) for offline compliance and LCP optimization.

## [0.19.0] - 2026-07-01
This minor release opens the Zenzic AST to user-defined Python rules via the **Custom Rules API v2**
and expands the auto-fix engine to cover two additional codes.

### Added

- Lossless AST parser and serializer (Composite Pattern) for Markdown blocks and inline elements.
- O(N) character-by-character state machine for inline tokenization, eliminating regex backtracking.
- Mutator engine for non-destructive in-memory AST modifications.
- Atomic File Writer implementing a strict write barrier with `tempfile` and `os.replace`.
- `zenzic fix` CLI command with `--dry-run` and `--apply` modes.
- `Z108 (EMPTY_LINK_TEXT)` auto-fix support, injecting the `TODO` keyword to transition structural errors into content debt.

### Fixed

- **Z501 (Placeholder Content):** Fixed context-blindness that caused placeholders inside fenced code blocks to trigger false positives. Restored default placeholder patterns in standard configurations.
- **Custom Rules API v2 (AST Walker):** Users can now write custom analysis rules in Python by
subclassing `BaseASTRule` from `zenzic.rules`. Rules are auto-discovered from `.zenzic/rules/*.py`
at scan startup — no registration or entry-point wiring required.
- **Deterministic Visitation Budget Sandbox (Z901 / Z902):** Every custom rule executes inside a
single-threaded visitation counter guard (`max_visits`, default 10 000). Exceeding the budget
raises `ZenzicRuleTimeout`, which is caught and emitted as **Z902 (RULE_TIMEOUT)** without halting
the scan. Any other unhandled exception is caught and emitted as **Z901 (RULE_ENGINE_ERROR)**.
- **`fixable` metadata field:** `CodeDefinition` now carries a `fixable: bool` attribute surfaced in
`zenzic explain` output and as **Fixable: Yes/No** badges in `finding-codes.md`.
- **Auto-Fix: Z121 → Z122 (MISSING_OR_EMPTY_HREF):** `zenzic fix` now rewrites `<a>` tags with a
missing or empty `href` attribute to `href="#"`, converting the Error to a Warning (`Z122`).
- **Auto-Fix: Z603 (DEAD_SUPPRESSION):** `zenzic fix` cleanly removes dead
`<!-- zenzic:ignore: Zxxx -->` comments and `data-zenzic-ignore` HTML attributes without
corrupting surrounding text.

### Changed

- `src/zenzic/rules.py` (compatibility stub) replaced by the `zenzic.rules` package
(`src/zenzic/rules/__init__.py` + `src/zenzic/rules/base.py`). The public SDK surface is
unchanged; all previously exported symbols remain available.
- `zenzic fix` now runs a per-file scan pass before applying mutations in order to collect dead
suppression line numbers for Z603 auto-fix targeting.

### Hardened

- **Suppression Tracker:** `SuppressionTracker._parse()` now also registers `data-zenzic-ignore`
HTML attributes (via `PolyglotExtractor`) as suppressions, enabling Z603 detection for dead
HTML-level suppressions with distinct diagnostic messaging.
- **Validator:** Removed the silent early-exit bypass for `data-zenzic-ignore` nodes in the
Polyglot Extractor pipeline; suppression is now delegated to the `SuppressionTracker` for
consistent tracking.

## Historical Releases

- v0.19.x archive: [changelogs/v0.19.x.md](./changelogs/v0.19.x.md)
- v0.18.x archive: [changelogs/v0.18.x.md](./changelogs/v0.18.x.md)
- v0.17.x archive: [changelogs/v0.17.x.md](./changelogs/v0.17.x.md)
- v0.16.x archive: [changelogs/v0.16.x.md](./changelogs/v0.16.x.md)
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract: >-
performs deterministic static analysis using a two-pass reference
pipeline and a RE2-backed credential scanner, with zero subprocess
calls and full SARIF 2.1.0 support for CI/CD integration.
version: 0.19.6
version: 0.20.0
date-released: 2026-07-04
url: "https://zenzic.dev"
repository-code: "https://github.com/PythonWoods/zenzic"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ SPDX-License-Identifier: Apache-2.0
<!-- zenzic:audit-badge -->
<img src="https://img.shields.io/badge/%F0%9F%9B%A1%EF%B8%8F_zenzic--audit-passing-22c55e?style=flat-square" alt="zenzic-audit">
<!-- zenzic:score-badge -->
<img src="https://img.shields.io/badge/%F0%9F%9B%A1%EF%B8%8F_zenzic--score-100_%2F_100-4f46e5?style=flat-square" alt="zenzic-score">
<img src="https://img.shields.io/badge/%F0%9F%9B%A1%EF%B8%8F_zenzic--score-99_%2F_100-f59e0b?style=flat-square" alt="zenzic-score">
<a href="https://reuse.software/">
<img src="https://img.shields.io/badge/REUSE-3.x%20compliant-0d9488?style=flat-square" alt="REUSE 3.x compliant">
</a>
Expand Down
8 changes: 4 additions & 4 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

| Field | Value |
| :------- | :--------- |
| Version | v0.19.6 |
| Version | v0.20.0 |
| Codename | Magnetite |
| Date | 2026-07-04 |
| Status | Stable |
Expand All @@ -21,7 +21,7 @@ Before tagging, every item must be green:
- [ ] `zenzic lab all` — all 20 scenarios exit with expected code
- [ ] `zenzic score --stamp` committed — badge in README.md reflects current score
- [ ] `zenzic check all .` — zero findings in the repo root
- [ ] `pyproject.toml` version matches the tag (`0.19.6`)
- [ ] `pyproject.toml` version matches the tag (`0.20.0`)
- [ ] `CITATION.cff` version and date updated
- [ ] Parità bilingue Z602 verificata (docs vs i18n/it/)
- [ ] `CHANGELOG.md` — `[Unreleased]` section moved to the new version heading
Expand Down Expand Up @@ -55,11 +55,11 @@ git checkout main
git pull origin main

# 3. Tag the main branch and push
git tag v0.19.6
git tag v0.20.0
git push origin main --tags
```

- [ ] Create GitHub Release from the tag, using the `## [0.19.6]` CHANGELOG section as the release body.
- [ ] Create GitHub Release from the tag, using the `## [0.20.0]` CHANGELOG section as the release body.

## Changelog Reference

Expand Down
38 changes: 32 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ For the current release history, see [CHANGELOG.md](CHANGELOG.md).

---

## [v0.20.0] - The Extensibility Update (Planned)
### [v0.20.0] - The Extensibility Update (Completed)

*Expanding the core mutation and governance infrastructure.*
*Custom Rules API v2, deterministic visitation sandbox, auto-fix expansion.*

- **Custom Rules API v2 (AST Walker):** Exposing the internal AST to allow users to write custom Python plugins for bespoke document governance.
- *Constraint:* To protect the $O(N)$ performance invariant, custom rules will be executed within a strict sandbox. Any rule exceeding a 50ms execution budget will be terminated, emitting a `Z902 RULE_TIMEOUT` governance warning.
- **Auto-Fix Expansion:** Broadening the `zenzic fix` pipeline to support semantic repair semantics for additional `Z1xx` and `Z3xx` findings.
- **Custom Rules API v2 (AST Walker):** Users subclass `BaseASTRule` from `zenzic.rules`. Rules are auto-discovered from `.zenzic/rules/*.py` — no registration required.
- **Deterministic Visitation Budget Sandbox (Z901 / Z902):** Single-threaded visitation counter guard (`max_visits = 10 000`) replaces thread-based or signal-based timeouts, preserving Windows compatibility and the $O(N)$ invariant.
- **Auto-Fix Expansion:** `zenzic fix` now auto-repairs **Z121** (MISSING_OR_EMPTY_HREF → `href="#"`) and **Z603** (DEAD_SUPPRESSION comment/attribute removal).
- **`fixable` metadata field:** `CodeDefinition` exposes `fixable: bool`, surfaced in `zenzic explain` and `finding-codes.md`.

---

Expand Down Expand Up @@ -74,4 +75,29 @@ These constraints apply across every future release:

---

Roadmap last updated: 2026-07-01
## Known Bugs & Deferred Work

### Bug: `data-zenzic-ignore` does not suppress Z104 on raw HTML `<a>` tags (deferred → v0.20.1)

**Discovered during:** v0.20.0 dogfooding (`zenzic check all --strict` on own docs).

**Symptom:** Placing `data-zenzic-ignore` (with or without a value) on a raw HTML `<a>` tag
does not suppress `Z104 (FILE_NOT_FOUND)` when the link resolver is invoked by the Uniform
Resolver Pipeline (URP). The `data-zenzic-ignore` attribute correctly suppresses HTML hygiene
codes (Z12x) via the Polyglot Extractor, but the URP resolves the `href` value independently
in a second pass — after suppression has already been evaluated. As a result, Z104 still fires,
and `data-zenzic-ignore` is simultaneously flagged as dead by Z603.

**Root Cause:** Architectural leak between the Polyglot Extractor pipeline (HTML hygiene) and
the Markdown link resolver (URP). Suppression state is not propagated across pipeline stages.

**Workaround (current):** Use `per_file_ignores` or `directory_policies` in `.zenzic.toml` to
suppress Z104 for files containing links to build-time artifacts (e.g., RSS/Atom feeds generated
by MkDocs plugins). See [Configuration Strategy — Build-time Artifacts](docs/how-to/configuration-strategy.md).

**Resolution scope:** Requires a structural patch to the URP to carry suppression context from
the Extractor stage through the resolver pass. Scheduled for **v0.20.1**.

---

Roadmap last updated: 2026-07-04
Loading
Loading