Files
Bitsy 876122ff98 Audit fixes: security hardening, index correctness, performance, UX
Security
- Elevated copies: root only reads the original; the copy is written by
  the user (sudo -u tee), so root never chowns / chmods a user-controlled
  path. Staging folder forced to 0700.
- Service logs moved from fixed /tmp names to /Library/Logs/Allofit
  (root-owned) and ~/Library/Logs/Allofit; Diagnostics reveals instead of
  opening the log.
- Index files are owner-only (0600; the root daemon's belongs to the
  installing user), set on the temp file before an atomic rename.
- Root install passes the plist inline (base64, plutil -lint) instead of a
  user-writable temp file; the binary comes from Bundle.main.
- Cache loader caps and checks the declared payload size; each save uses
  its own temp file.
- Release action pinned to a commit; non-system LC_RPATHs stripped.

Correctness
- Move to Trash removes the files from the index (the watcher ignores the
  app's own operations) and registers Undo (Put Back); trashed folders are
  matched with the original URLs; failures are shown.
- The saved event id stays below pending subtree walks (GUI and service).
- Roots / exclusions changes restart the watcher from the snapshot's id.
- Case-only renames no longer leave a ghost entry.
- Service mode is saved only after a successful install; a saved but
  missing service falls back to the in-process indexer.

Performance
- New folders are merged without the O(n) removal pass.
- Size / date sorts use a compact key array (539 -> 47 ms for 630k).
- Selection, preview and actions use the selected records directly.
- Service saves at most every 15 s; reader reloads pause while hidden and
  are deferred instead of dropped; window close saves only when dirty.

Usability
- Results appear during the first index; empty-list explanations.
- Down arrow moves to the results, Up on the first row back; history on
  Up / Option-Up / Option-Down.
- Search syntax popover and Help menu; shortcuts shown in the context menu;
  confirmations for Clear Cache and Uninstall; privacy usage strings;
  Group Containers excluded by default; wording, VoiceOver labels, plural.
2026-10-02 14:44:49 +02:00

76 lines
2.5 KiB
YAML

name: Release
# Fires on any tag push. Both `0.0.1` and `v0.0.1` style tags work - the
# build step strips the optional leading 'v' before stamping the Info.plist.
on:
push:
tags:
- '*'
# Needed for softprops/action-gh-release to create / upload to releases
permissions:
contents: write
jobs:
release:
name: Build .app + DMG and publish release
runs-on: macos-15
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Show toolchain
run: |
sw_vers
swift --version
xcodebuild -version
- name: Derive version from tag
id: version
run: |
tag="${GITHUB_REF_NAME}"
version="${tag#v}"
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "Building Allofit ${version} from tag ${tag}"
- name: Build Allofit.app
env:
ALLOFIT_VERSION: ${{ steps.version.outputs.version }}
ALLOFIT_BUILD: ${{ github.run_number }}
run: ./scripts/build-app.sh
- name: Zip Allofit.app (ditto preserves bundle metadata + signatures)
working-directory: outputs
run: |
ditto -c -k --keepParent --sequesterRsrc \
"Allofit-${{ steps.version.outputs.version }}.app" \
"Allofit-${{ steps.version.outputs.version }}.zip"
- name: Build DMG (drag-to-install with /Applications shortcut)
env:
ALLOFIT_VERSION: ${{ steps.version.outputs.version }}
run: ./scripts/build-dmg.sh --skip-build
- name: SHA-256 checksums
working-directory: outputs
run: |
shasum -a 256 \
"Allofit-${{ steps.version.outputs.version }}.zip" \
"Allofit-${{ steps.version.outputs.version }}.dmg" \
| tee "Allofit-${{ steps.version.outputs.version }}.sha256"
- name: Publish GitHub release
# pinned to a commit: this step holds a write token for the repo
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
with:
tag_name: ${{ steps.version.outputs.tag }}
name: Allofit ${{ steps.version.outputs.version }}
generate_release_notes: true
fail_on_unmatched_files: true
files: |
outputs/Allofit-${{ steps.version.outputs.version }}.zip
outputs/Allofit-${{ steps.version.outputs.version }}.dmg
outputs/Allofit-${{ steps.version.outputs.version }}.sha256