Skip to content

ProtectionAI v1.8.0

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 13:42

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,056 tests. Ribbon: 17 tabs, 85 groups, 144 controls. No module, tool or test count moves — the
minor version reflects a change to where the operator's most-used control lives and a type ramp that
now governs the whole front end.

Changed

  • Search moved to the centre of the title bar, where Outlook puts it. It sat at the right end of
    the ribbon tab row, competing with seventeen tabs for the same strip.

    A note in the XAML had claimed true title-bar centring was impractical and would mean fighting the
    window-drag hit test. That was wrong, but only just: RibbonTitleBar is a HeaderedItemsControl
    whose Header is positioned by HeaderAlignment, and Center is one of the values it supports, so
    the search box simply becomes the header the window title used to occupy. Two things in the stock
    control had to be undone first, and finding them is the work:

    • the style applies a HeaderTemplate that renders the header as text, so assigning a
      UIElement printed its type name — the running app showed a title bar reading
      ProtectionAI.App.Views.RibbonSearchHost, and because the host never entered the visual tree the
      search box disappeared from the automation tree entirely;
    • PART_HeaderHolder is IsHitTestVisible="False", which is correct for a caption you drag the
      window by and fatal for a text box.

    Both are corrected at runtime. The cost is that this strip of the caption no longer drags the
    window, which is exactly how Outlook behaves around its own search box; the rest of the caption
    still drags. Every failure path leaves the box where it used to be, at the right end of the tab
    row, and says so in the log — a search box that silently vanished would be worse than one that is
    merely not centred.

    Because the box no longer shares a row with the tabs, the ribbon fit engine no longer shrinks it to
    buy the tab strip width — that step bought nothing once they stopped competing. It is now sized
    against the window, and the whole tab row is available to tabs, so fewer are ever parked into the
    overflow menu.

    Verified on the running app: centred, correctly themed (#252526 on dark), ShellSearchBox
    findable in the automation tree, click-to-focus working, typing dist opening the results popup.

  • Every font size in the front end is now a named step on one ramp. An audit found 356
    hard-coded sizes across 217 files in twenty distinct values
    — 9, 9.5, 10, 10.5, 11, 11.5, 12,
    12.5, 13, 13.5, 14, 15, 16, 17, 18, 20, 22, 24, 26 and 28 — where the house idiom describes about
    five. Half-steps that differ by half a pixel are not a design decision; they are drift, and their
    existence means the next contributor picks a number rather than a meaning. Fifty-four were below
    11 px
    , which on a field laptop in sunlight is where text stops being readable and starts being
    decoration.

    Ui.Size now names the ramp — Micro 11, Body 12, Strong 13, Subtitle 14, Title 16,
    SectionHeader 18, Page 22, Display 24, Hero 28 — and 280 call sites across 83 files were
    converted. Near-duplicates were snapped to the step they were already pretending to be and
    everything below 11 was raised: 9/9.5/10/10.5/11.5 → 11, 12.5 → 12, 13.5 → 13, 15 → 14, 17 → 16,
    20 → 22, 26 → 24. Sizes already on a step kept their value and gained a name. The intent was to
    remove invisible variation and raise unreadable text, not to resize the product.

    Chart text is deliberately not on this ramp: OxyPlot renders through its own pipeline and
    ChartTheme.cs remains its single source of truth. Ten OxyPlot annotation sizes were identified
    and left alone rather than converted by pattern-matching on the property name.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

0939d9d5c1e6bcc6f83c652f70869544a2a4fcf6139acaa949f35d341b616c08  protectionai-1.8.0-cyclonedx.json
dfdc44708ed73388f1029f06dbab0411db35b42613d7586510ecd86d28fa5d90  protectionai-1.8.0-cyclonedx.json.sha256
b571ec50562c436a3f9b9181db8c2708a42e13c66b4331e9a744bc60bc561ebf  ProtectionAI-Setup.msi
1188ee0caa22d0af4b6670889768c3d15cc250c4cea54b376b147bef3f464602  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.8.0-cyclonedx.json) and its checksum sidecar (protectionai-1.8.0-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.8.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.8.0 \
  --certificate-github-workflow-sha 1f8ca994a45dd8ed1997d68ac36aacdc62b05e2c

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.8.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.8.0 \
  --certificate-github-workflow-sha 1f8ca994a45dd8ed1997d68ac36aacdc62b05e2c

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@1f8ca99. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.