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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ Human-readable summary of user-facing changes. **Detailed release notes:** [docs

---

## 1.7.4.post5 (pending PyPI dispatch)

> Post-release on the **`1.7.4`** public line. **`[project] version = 1.7.4.post5`** and **`[tool.databoar] maturity_build = 240`** (`N=14` `fix(` commits since post4 merge `656fdc3d`, ADR-0073). **PyPI-only** — no Git tag, no GitHub Release, no container.

### Fixed / hardened (post5)

- **Archives (.7z):** content scan via py7zr `BytesIOFactory` + pre-budget member extract (#1250, #1248).
- **Sessions:** orphan `running` reaper (PID liveness, TOCTOU-safe conditional UPDATE) + interrupt → `interrupted` (#1251).
- **CLI:** `--validate-config` **WARN** when optional SQL driver deps are missing (offline probe) (#1246).
- **Security:** standalone HTML form CSRF (#1231); Dataverse `org_url` / `token_url` SSRF guards (#1232); aggregate archive decompression budgets (#1233); secret-by-identity lock + reachable JWT GRACE (#1210, #1212); non-numeric / non-finite license/budget hardening; drop `Invoke-Expression` from `external-review-pack.ps1` (#1192).
- **Integrity:** honest `build_digest_matched` (no `signature_ok` overclaim) + legacy migrate zeroing (#1211).
- **OPSEC / lint:** LICENSING_SPEC evasion-vector redaction (#1234, #1235); markdown-lint git-tracked only (#1240); skills OPSEC / ATS footer path (#1191).

### Notes (post5)

- Full `N=14` fix set and `postN` ↔ `maturity_build` map: [docs/releases/1.7.4.post5.md](docs/releases/1.7.4.post5.md).

---

## 1.7.4.post4 (pending PyPI dispatch)

> Post-release on the **`1.7.4`** public line. **`[project] version = 1.7.4.post4`** and **`[tool.databoar] maturity_build = 225`** (`N=14` fixes since post3 baseline, ADR-0073 dual counter policy).
Expand Down
2 changes: 1 addition & 1 deletion core/about.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def _package_version() -> str:

return version("data-boar")
except Exception:
return "1.7.4.post4"
return "1.7.4.post5"


def get_http_user_agent() -> str:
Expand Down
106 changes: 106 additions & 0 deletions docs/releases/1.7.4.post5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Release 1.7.4.post5 (PyPI publish counter)

**Status:** Pending PyPI upload after merge (operator **`publish-pypi`** `workflow_dispatch`: build → TestPyPI → PyPI).

**Public line (marketing):** **`1.7.4`** — README, man pages, stakeholder copy unchanged.

**Build / PyPI / About:** **`1.7.4.post5`** — PEP 440 post-release (publish counter per [ADR-0073](../adr/ADR-0073-version-scheme-octet-maturity-and-roadmap.md) § *PyPI dual counters*).

**Not in this drop:** Git tag · GitHub Release · Docker / container image (PyPI-only `.postN`).

---

## Mandatory map: `postN` ↔ `maturity_build`

Per ADR-0073: **`postN`** counts **PyPI uploads**; **`maturity_build`** counts **discrete fixes** and may run ahead. This map is the mandatory audit trail.

| PyPI / `[project] version` | `maturity_build` (octet) | Notes |
| --- | --- | --- |
| **`1.7.4`** | **`.201`** | GA on PyPI (immutable); release PR **#1024** |
| **`1.7.4.post1`** | **`.202`** | SQL drivers → optional extras ([#1047](https://github.com/DataBoar/data-boar/issues/1047)) — published |
| *(fix, unpublished on PyPI)* | **`.203`** | [#1026](https://github.com/DataBoar/data-boar/pull/1026) |
| *(fix, unpublished on PyPI)* | **`.204`** | [#1028](https://github.com/DataBoar/data-boar/pull/1028) |
| *(fix, unpublished on PyPI)* | **`.205`** | Deploy / packaging fix train |
| *(fix, unpublished on PyPI)* | **`.206`** | `main.py --version` without config |
| *(fix, unpublished on PyPI)* | **`.207`** | `fix(connectors)` symlink / reparse-point loop guard ([#1080](https://github.com/DataBoar/data-boar/pull/1080)) |
| **`1.7.4.post2`** | **`.208`** | Prior upload on this line |
| *(fix, unpublished on PyPI)* | **`.209`** | SQL sampling failures now surface in `scan_failures` ([#1140](https://github.com/DataBoar/data-boar/issues/1140), [#1144](https://github.com/DataBoar/data-boar/pull/1144)) |
| *(fix, unpublished on PyPI)* | **`.210`** | Encrypted/corrupt archive members now surface in `scan_failures` (open-core slice of [#828](https://github.com/DataBoar/data-boar/issues/828), [#1146](https://github.com/DataBoar/data-boar/pull/1146)) |
| **`1.7.4.post3`** | **`.211`** | Published with `soupsieve` CVE fix ([#1177](https://github.com/DataBoar/data-boar/pull/1177)) |
| *(fix, unpublished on PyPI)* | **`.212`** | RBAC now defaults to deny on the full route map (#1133). |
| *(fix, unpublished on PyPI)* | **`.213`** | API key comparison now uses UTF-8 byte-safe `compare_digest` (#1150). |
| *(fix, unpublished on PyPI)* | **`.214`** | Operator-gated reopen workflow pins were restored to keep governance automation stable. |
| *(fix, unpublished on PyPI)* | **`.215`** | SQL sampling transaction scope is now isolated per connection (#1194). |
| *(fix, unpublished on PyPI)* | **`.216`** | One-class compliance profiles now preserve declared-term detections (#1195). |
| *(fix, unpublished on PyPI)* | **`.217`** | XLSX exports now neutralize formula-leading cells to prevent spreadsheet injection (#1201). |
| *(fix, unpublished on PyPI)* | **`.218`** | Web exposure defaults now enforce a safe-by-default posture for remote surface (#1202). |
| *(fix, unpublished on PyPI)* | **`.219`** | Follow-up CodeQL logging and import-cycle hardening landed on the web-exposure path (#1202). |
| *(fix, unpublished on PyPI)* | **`.220`** | Remaining routes-context import cycle was removed to stabilize route wiring. |
| *(fix, unpublished on PyPI)* | **`.221`** | Config redaction now masks DSN/URL embedded credentials in `/config` (#1137). |
| *(fix, unpublished on PyPI)* | **`.222`** | Prefilter now preserves recall parity with active profile terms/regexes (#1198). |
| *(fix, unpublished on PyPI)* | **`.223`** | Help output now aligns dev invocation and installed command contract (#1130). |
| *(fix, unpublished on PyPI)* | **`.224`** | Demo sessions now resolve audit trail correctly via `/logs/{session_id}` (#1218). |
| *(fix, unpublished on PyPI)* | **`.225`** | Logs fallback hardening removed the CodeQL path-injection sink in demo retrieval (#1218, `4bd3e5bc`). |
| **`1.7.4.post4`** | **`.226`** | Pillow `12.2.0` → `12.3.0` (PYSEC-2026-2253..2257); baseline post3 + `N=15`. |
| *(fix, unpublished on PyPI)* | **`.227`** | Align ATS import footer skill path to private (#1191). |
| *(fix, unpublished on PyPI)* | **`.228`** | Standalone HTML form CSRF without WebAuthn (#1231). |
| *(fix, unpublished on PyPI)* | **`.229`** | Dataverse `org_url` / `token_url` SSRF guards (#1232). |
| *(fix, unpublished on PyPI)* | **`.230`** | Aggregate archive decompression budgets (#1233). |
| *(fix, unpublished on PyPI)* | **`.231`** | Reject non-finite `max_expansion_ratio` (nan/inf). |
| *(fix, unpublished on PyPI)* | **`.232`** | Secret-by-identity lock + reachable JWT GRACE (#1210, #1212). |
| *(fix, unpublished on PyPI)* | **`.233`** | Fail-closed on non-numeric license `exp` claim. |
| *(fix, unpublished on PyPI)* | **`.234`** | Honest `build_digest_matched` (no `signature_ok` overclaim) (#1211). |
| *(fix, unpublished on PyPI)* | **`.235`** | Zero legacy `build_digest_matched` bit on migrate (#1211). |
| *(fix, unpublished on PyPI)* | **`.236`** | Drop `Invoke-Expression` from `external-review-pack.ps1` (#1192). |
| *(fix, unpublished on PyPI)* | **`.237`** | Read `.7z` members via py7zr `BytesIOFactory` (#1250, #1248). |
| *(fix, unpublished on PyPI)* | **`.238`** | Extract pre-budget `.7z` members on budget stop (#1250, #1248). |
| *(fix, unpublished on PyPI)* | **`.239`** | Orphan session reaper (PID liveness) + interrupt → `interrupted` (#1251). |
| **`1.7.4.post5`** | **`.240`** | **This upload** — TOCTOU-safe reaper UPDATE + post5 wave; baseline `1.7.4.post4` + `N=14` `fix(` commits. |

---

## Appendix — Fix set used for `N` (`N=14`) (git-literal)

**Boundary:** merge of release PR **#1224** (`656fdc3d` — `chore(release): 1.7.4.post4`).

```bash
git log 656fdc3d..HEAD --format='%h %s' | rg '^[0-9a-f]+ fix\('
# COUNT=14 → maturity_build = 226 + 14 = 240
```

Commits counted (newest first, as returned by `git log`):

1. `68119f93` — `fix(session): conditional UPDATE in orphan reaper (TOCTOU)`
2. `ecefa7c2` — `fix(session): reap orphan running sessions and mark interrupts`
3. `0755f6b9` — `fix(archives): extract pre-budget .7z members on budget stop`
4. `707549ed` — `fix(archives): read .7z members via py7zr BytesIOFactory`
5. `c80e2046` — `fix(security): drop Invoke-Expression from external-review-pack.ps1`
6. `a4b5d9fe` — `fix(integrity): zero legacy build_digest_matched bit on migrate`
7. `026f17ad` — `fix(integrity): honest build_digest_matched instead of signature_ok overclaim`
8. `72ad6d75` — `fix(security): fail-closed on non-numeric license exp claim`
9. `f3313c4a` — `fix(security): lock secret-by-identity and reachable JWT GRACE (#1210 #1212)`
10. `7e714b68` — `fix(security): reject non-finite max_expansion_ratio (nan/inf)`
11. `30cd501c` — `fix(security): aggregate archive decompression budgets (#1233)`
12. `451580a1` — `fix(security): guard Dataverse org_url and token_url against SSRF (#1232)`
13. `69bb082f` — `fix(security): enforce standalone HTML form CSRF without WebAuthn (#1231)`
14. `e64ad41e` — `fix(scripts): align ATS import footer skill path to private (#1191)`

**Not counted toward `N` (not `fix(`):** `feat(cli)` validate-config optional-driver WARN (#1246 / #1255); `docs(security)` LICENSING_SPEC (#1234/#1235); `chore` markdown-lint (#1240); `security(cursor)` skills OPSEC harness commits under #1191 that are not `fix(`.

---

## Highlights (why post5)

- Demo-relevant archive and session reliability: `.7z` content scanning restored; orphan `running` sessions reaped safely under concurrent scans.
- Trust-floor / security train from post4 follow-ups now packaged: CSRF, Dataverse SSRF, archive bomb budgets, JWT GRACE / secret-by-identity, integrity digest honesty.
- Operator hygiene: external-review-pack without `Invoke-Expression`; optional SQL driver absence visible in `--validate-config` (bundled feat, not in `N`).

---

## Install

```bash
pip install 'data-boar==1.7.4.post5'
```

See [USAGE.md](../USAGE.md), [QUICKSTART.md](../QUICKSTART.md), and [TROUBLESHOOTING.md](../TROUBLESHOOTING.md).
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "data-boar"
version = "1.7.4.post4"
version = "1.7.4.post5"
description = "Data Boar — compliance-aware discovery and mapping of personal and sensitive data across databases, files, and APIs (LGPD, GDPR, CCPA, and configurable frameworks)."
readme = "README.md"
requires-python = ">=3.12"
Expand Down Expand Up @@ -302,6 +302,6 @@ dev = [
]

# Operator-only maturity octet (ADR-0073). Never copy into [project].version.
# postN <-> maturity_build map: docs/releases/1.7.4.post3.md (canonical; includes post1/post2 rows).
# postN <-> maturity_build map: docs/releases/1.7.4.post5.md (canonical; includes post1–post4 rows).
[tool.databoar]
maturity_build = 226
maturity_build = 240
4 changes: 2 additions & 2 deletions tests/test_pyproject_sql_extras.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ def test_sql_optional_extras_present() -> None:
def test_maturity_build_bumped_for_packaging_fix() -> None:
data = _load_pyproject()
maturity = data.get("tool", {}).get("databoar", {}).get("maturity_build")
assert maturity == 226
assert maturity == 240


def test_version_is_174_post_release_not_semver_bump() -> None:
version = _load_pyproject().get("project", {}).get("version")
assert version == "1.7.4.post4"
assert version == "1.7.4.post5"
assert not str(version).startswith("1.7.5")
assert not str(version).startswith("1.8.")
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading