Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
66b358f
security: redact settings logs and harden history file access
Mar 4, 2026
cdd0357
security: add 7-layer pipeline docs, workflow, and local tooling
Mar 4, 2026
7b2c0a4
Security/ship readiness 2026 03 04 (#1)
celstnblacc Mar 4, 2026
9c53bb7
docs: update custom additions with recent security and quality work
Mar 4, 2026
c2fdcc3
chore: update shortcut behavior, defaults, and project branding
Mar 4, 2026
922c55d
docs: update README custom additions and newblacc attribution
Mar 4, 2026
7176f6c
docs: update README custom additions and newblacc attribution (#2)
celstnblacc Mar 4, 2026
588596d
fix: improve Claude auto-submit reliability and refresh app icons (#3)
celstnblacc Mar 4, 2026
28ce606
fix: improve macOS paste reliability with AppleScript (#4)
celstnblacc Mar 4, 2026
6d796b8
fix: auto-submit focus, app icons refresh, and Parler→Phraser rebrand…
celstnblacc Mar 4, 2026
e03b5f1
fix: autosend focus improvements and icon refresh (#6)
celstnblacc Mar 4, 2026
6c08e98
chore: clean up upstream references, add landing page and release guide
Mar 5, 2026
ae6d1c7
fix: disable Apple code signing in release workflow
Mar 5, 2026
6a97a69
docs: update RELEASING.md with signing config and troubleshooting
Mar 5, 2026
084f7b5
Update build.yml
celstnblacc Mar 5, 2026
d0db18b
fix: avoid empty TAURI_SIGNING_PRIVATE_KEY when sign-binaries is false
celstnblacc Mar 5, 2026
415a541
refactor: extract helpers, fix clipboard restore, and add Gemini clie…
Mar 5, 2026
1262b5b
fix: always set TAURI_SIGNING_PRIVATE_KEY for updater artifact signing
celstnblacc Mar 5, 2026
467e90a
fix: resolve TS2345 type error for log_level in settingsStore
celstnblacc Mar 5, 2026
43feae0
fix: update actions.rs call sites to match refactored helper API
celstnblacc Mar 5, 2026
952b97c
fix: move macOS certificate env vars to conditional step to prevent c…
celstnblacc Mar 5, 2026
9fa8392
refactor: decouple postProcessStore from settingsStore and improve co…
celstnblacc Mar 5, 2026
3aae54f
fix: move Apple notarization env vars to conditional macOS step to pr…
celstnblacc Mar 5, 2026
e307f3f
fix: update testToggle descriptionMode type to match component props …
celstnblacc Mar 5, 2026
4fe381f
fix: update DropdownSettings test to use valid ClipboardHandling and …
celstnblacc Mar 5, 2026
a33354d
fix: update HistorySettings test SAMPLE_ENTRY timestamp to number type
celstnblacc Mar 5, 2026
1938e59
fix: add missing title field to HistorySettings test SAMPLE_ENTRY
celstnblacc Mar 5, 2026
9943d6d
chore: release macOS only, remove Linux targets from matrix
celstnblacc Mar 5, 2026
1cd21a7
feat: simplify Post Process actions, add Ollama provider, and full UI…
celstnblacc Mar 5, 2026
a8e73a0
release: bump version to 0.7.15
celstnblacc Mar 5, 2026
e947d33
chore(security): patch Rust advisories, pre-commit hook, and README u…
celstnblacc Mar 6, 2026
51b33fc
chore: merge main into chore/readme-ship-update-2026-03-04 and resolv…
Mar 6, 2026
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
50 changes: 18 additions & 32 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ on:
asset-prefix:
required: false
type: string
default: "parler"
default: "phraser"
asset-name-pattern:
required: false
type: string
Expand Down Expand Up @@ -80,7 +80,6 @@ jobs:
- name: Setup Bun (standard)
if: ${{ !(contains(inputs.platform, 'windows') && contains(inputs.target, 'aarch64')) }}
uses: oven-sh/setup-bun@v2

# Bun does not fully support Windows ARM64 yet, so we pin the baseline build.
# See https://github.com/oven-sh/bun/issues/9824 for details.
- name: Setup Bun (Windows ARM64 baseline)
Expand Down Expand Up @@ -263,22 +262,30 @@ jobs:
fi
echo "platform=${patched_platform}" >> $GITHUB_OUTPUT

- name: Set Tauri signing env vars
shell: bash
run: |
echo "TAURI_SIGNING_PRIVATE_KEY=${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}" >> $GITHUB_ENV
echo "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" >> $GITHUB_ENV

- name: Set macOS signing env vars
if: contains(inputs.platform, 'macos') && inputs.sign-binaries
shell: bash
run: |
echo "APPLE_CERTIFICATE=${{ secrets.APPLE_CERTIFICATE }}" >> $GITHUB_ENV
echo "APPLE_CERTIFICATE_PASSWORD=${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" >> $GITHUB_ENV
echo "APPLE_SIGNING_IDENTITY=${{ env.CERT_ID }}" >> $GITHUB_ENV
echo "APPLE_ID=${{ secrets.APPLE_ID }}" >> $GITHUB_ENV
echo "APPLE_ID_PASSWORD=${{ secrets.APPLE_ID_PASSWORD }}" >> $GITHUB_ENV
echo "APPLE_PASSWORD=${{ secrets.APPLE_PASSWORD }}" >> $GITHUB_ENV
echo "APPLE_TEAM_ID=${{ secrets.APPLE_TEAM_ID }}" >> $GITHUB_ENV
- name: Build with Tauri
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APPLE_ID: ${{ inputs.sign-binaries && secrets.APPLE_ID || '' }}
APPLE_ID_PASSWORD: ${{ inputs.sign-binaries && secrets.APPLE_ID_PASSWORD || '' }}
APPLE_PASSWORD: ${{ inputs.sign-binaries && secrets.APPLE_PASSWORD || '' }}
APPLE_TEAM_ID: ${{ inputs.sign-binaries && secrets.APPLE_TEAM_ID || '' }}
APPLE_CERTIFICATE: ${{ inputs.sign-binaries && secrets.APPLE_CERTIFICATE || '' }}
APPLE_CERTIFICATE_PASSWORD: ${{ inputs.sign-binaries && secrets.APPLE_CERTIFICATE_PASSWORD || '' }}
APPLE_SIGNING_IDENTITY: ${{ inputs.sign-binaries && env.CERT_ID || '' }}
AZURE_CLIENT_ID: ${{ inputs.sign-binaries && secrets.AZURE_CLIENT_ID || '' }}
AZURE_CLIENT_SECRET: ${{ inputs.sign-binaries && secrets.AZURE_CLIENT_SECRET || '' }}
AZURE_TENANT_ID: ${{ inputs.sign-binaries && secrets.AZURE_TENANT_ID || '' }}
TAURI_SIGNING_PRIVATE_KEY: ${{ inputs.sign-binaries && secrets.TAURI_SIGNING_PRIVATE_KEY || '' }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ inputs.sign-binaries && secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || '' }}
WHISPER_NO_AVX: ${{ contains(inputs.platform, 'ubuntu') && !contains(inputs.platform, 'arm') && 'ON' || '' }}
WHISPER_NO_AVX2: ${{ contains(inputs.platform, 'ubuntu') && !contains(inputs.platform, 'arm') && 'ON' || '' }}
with:
Expand Down Expand Up @@ -307,49 +314,29 @@ jobs:
- name: Remove libwayland-client.so from AppImage
if: contains(inputs.platform, 'ubuntu')
run: |
# Find the AppImage file
APPIMAGE_PATH=$(find src-tauri/target/${{ steps.build-profile.outputs.profile }}/bundle/appimage -name "*.AppImage" | head -1)

if [ -n "$APPIMAGE_PATH" ]; then
echo "Processing AppImage: $APPIMAGE_PATH"

# Make AppImage executable
chmod +x "$APPIMAGE_PATH"

# Extract AppImage
cd "$(dirname "$APPIMAGE_PATH")"
APPIMAGE_NAME=$(basename "$APPIMAGE_PATH")

# Extract using the AppImage itself
"./$APPIMAGE_NAME" --appimage-extract

# Remove libwayland-client.so files
echo "Removing libwayland-client.so files..."
find squashfs-root -name "libwayland-client.so*" -type f -delete

# List what was removed for verification
echo "Files remaining in lib directories:"
find squashfs-root -name "lib*" -type d | head -5 | while read dir; do
echo "Contents of $dir:"
ls "$dir" | grep -E "(wayland|fuse)" || echo " No wayland/fuse libraries found"
done

# Detect architecture and get appropriate appimagetool
if [[ "$(uname -m)" == "aarch64" ]]; then
APPIMAGETOOL_ARCH="aarch64"
else
APPIMAGETOOL_ARCH="x86_64"
fi

wget -q "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${APPIMAGETOOL_ARCH}.AppImage"
chmod +x "appimagetool-${APPIMAGETOOL_ARCH}.AppImage"

# Repackage AppImage with no-appstream to avoid warnings
ARCH="${APPIMAGETOOL_ARCH}" "./appimagetool-${APPIMAGETOOL_ARCH}.AppImage" --no-appstream squashfs-root "$APPIMAGE_NAME"

# Clean up
rm -rf squashfs-root "appimagetool-${APPIMAGETOOL_ARCH}.AppImage"

echo "libwayland-client.so removed from AppImage successfully"
else
echo "No AppImage found to process"
Expand All @@ -371,7 +358,6 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.asset-prefix }}-${{ inputs.target }}
# Default Windows builds place bundles under release/, but cross-compiles (ARM64) nest under target/<triple>/release.
path: |
src-tauri/target/${{ inputs.target != '' && inputs.target != 'x86_64-pc-windows-msvc' && format('{0}/{1}', inputs.target, steps.build-profile.outputs.profile) || steps.build-profile.outputs.profile }}/bundle/msi/*.msi
src-tauri/target/${{ inputs.target != '' && inputs.target != 'x86_64-pc-windows-msvc' && format('{0}/{1}', inputs.target, steps.build-profile.outputs.profile) || steps.build-profile.outputs.profile }}/bundle/nsis/*.exe
Expand Down
13 changes: 2 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,14 @@ jobs:
- platform: "macos-latest" # for Intel based macs.
args: "--target x86_64-apple-darwin"
target: "x86_64-apple-darwin"
- platform: "ubuntu-22.04" # Build .deb on 22.04
args: "--bundles deb"
target: "x86_64-unknown-linux-gnu"
- platform: "ubuntu-24.04" # Build AppImage and RPM on 24.04
args: "--bundles appimage,rpm"
target: "x86_64-unknown-linux-gnu"
- platform: "ubuntu-24.04-arm" # Build for ARM64 Linux
args: "--bundles appimage,deb,rpm"
target: "aarch64-unknown-linux-gnu"

uses: ./.github/workflows/build.yml
with:
platform: ${{ matrix.platform }}
target: ${{ matrix.target }}
build-args: ${{ matrix.args }}
sign-binaries: true
asset-prefix: "parler"
sign-binaries: false
asset-prefix: "phraser"
upload-artifacts: false
release-id: ${{ needs.create-release.outputs.release-id }}
secrets: inherit
98 changes: 98 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: security

on:
pull_request:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
security-events: write

jobs:
layer1-dependency-audit:
name: L1 Dependency Risk
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- uses: dtolnay/rust-toolchain@stable
- name: Install audit tools
run: cargo install cargo-audit --locked
- name: Bun audit
run: bun audit --production
- name: Cargo audit
working-directory: src-tauri
run: cargo audit

layer2-secrets:
name: L2 Secrets
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

layer3-sast:
name: L3 SAST
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- uses: dtolnay/rust-toolchain@stable
- name: Install frontend deps
run: bun install --frozen-lockfile
- name: Frontend lint
run: bun run lint
- name: Rust clippy
working-directory: src-tauri
run: cargo clippy --all-targets --all-features -- -D warnings

layer4-human-review:
name: L4 Human/AI Review Reminder
runs-on: ubuntu-24.04
steps:
- name: Reminder
run: |
echo "Review security-sensitive changes manually (settings, commands, tauri config, updater/network paths)."

layer5-runtime-checks:
name: L5 Runtime Checks Reminder
runs-on: ubuntu-24.04
steps:
- name: Reminder
run: |
echo "Run Playwright/runtime checks when user-facing command behavior changes."

layer6-supply-chain:
name: L6 Supply Chain Integrity
runs-on: ubuntu-24.04
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Lockfile-enforced install
run: bun install --frozen-lockfile
- name: Ensure lockfiles unchanged
run: |
git diff --exit-code -- bun.lock src-tauri/Cargo.lock

layer7-observability:
name: L7 Observability Reminder
runs-on: ubuntu-24.04
steps:
- name: Reminder
run: |
echo "Attach security evidence to PRs (audit outputs, key findings, remediation notes)."
34 changes: 34 additions & 0 deletions .pre-commit-config.yaml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.25.1
hooks:
- id: gitleaks

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-merge-conflict
- id: check-yaml
- id: check-json
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: local
hooks:
- id: bun-lint
name: bun lint
entry: bun run lint
language: system
pass_filenames: false

- id: rust-fmt-check
name: cargo fmt check
entry: bash -lc 'cd src-tauri && cargo fmt -- --check'
language: system
pass_filenames: false

- id: rust-clippy
name: cargo clippy
entry: bash -lc 'cd src-tauri && cargo clippy --all-targets --all-features -- -D warnings'
language: system
pass_filenames: false
19 changes: 19 additions & 0 deletions .project-hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"

echo "[pre-commit] Running format checks..."
bun run format:check

echo "[pre-commit] Running frontend lint..."
bun run lint

echo "[pre-commit] Running Rust checks..."
cargo check --manifest-path src-tauri/Cargo.toml

echo "[pre-commit] Running Rust tests..."
cargo test --manifest-path src-tauri/Cargo.toml --quiet

echo "[pre-commit] All checks passed."
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ curl -o src-tauri/resources/models/silero_vad_v4.onnx https://blob.handy.compute

## Architecture Overview

Handy is a cross-platform desktop speech-to-text app built with Tauri 2.x (Rust backend + React/TypeScript frontend).
Phraser is a cross-platform desktop speech-to-text app built with Tauri 2.x (Rust backend + React/TypeScript frontend).

### Backend Structure (src-tauri/src/)

Expand Down Expand Up @@ -121,7 +121,7 @@ Use conventional commits:

## CLI Parameters

Handy supports command-line parameters on all platforms for integration with scripts, window managers, and autostart configurations.
Phraser supports command-line parameters on all platforms for integration with scripts, window managers, and autostart configurations.

**Implementation files:**

Expand Down
74 changes: 74 additions & 0 deletions IMPLEMENTATION_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 7-Layer Security Pipeline Implementation Summary (Phraser Adaptation)

## Scope

Adapted from the RepoSec 7-layer model to this repository:

- Repo: `Phraser`
- Stack: Tauri (Rust backend) + React/TypeScript + Bun
- Date: 2026-03-04

## What Was Added

### 1. Security Framework Docs

- `docs/7_LAYER_SECURITY_MODEL.md`
- `docs/PIPELINE.md`

These documents map the seven layers to Phraser-specific tooling and risks, including settings/logging exposure, Tauri command boundaries, and lockfile integrity.

### 2. CI Security Workflow

- `.github/workflows/security.yml`

Adds layer-oriented CI jobs:

- L1: `bun audit`, `cargo audit`
- L2: `gitleaks`
- L3: `bun run lint`, `cargo clippy`
- L4/L5/L7: review/runtime/observability reminders
- L6: lockfile-enforced installs + lockfile drift check

### 3. Local Security Make Targets

- `Makefile`

Provides reproducible local commands:

- `make security`
- `make security-l1` … `make security-l7`

### 4. Pre-commit Template

- `.pre-commit-config.yaml.template`

Template includes:

- gitleaks
- standard file hygiene checks
- local Bun lint
- Rust fmt check
- Rust clippy

## Design Notes

- Keeps existing project workflows intact (no modifications to existing CI files).
- Uses tools aligned with current stack and prior repo usage.
- Avoids hardcoded local user paths.
- Keeps the 7-layer model practical for a desktop app (L5 via runtime/integration checks, not only web DAST).

## Recommended Next Steps

1. Run `make security` locally and resolve any findings.
2. Trigger `.github/workflows/security.yml` on a PR to validate CI execution.
3. Copy `.pre-commit-config.yaml.template` to `.pre-commit-config.yaml` and install hooks.
4. Optionally pin all workflow actions to immutable SHAs for stronger supply-chain guarantees.

## Files Added

- `docs/7_LAYER_SECURITY_MODEL.md`
- `docs/PIPELINE.md`
- `.github/workflows/security.yml`
- `Makefile`
- `.pre-commit-config.yaml.template`
- `IMPLEMENTATION_SUMMARY.md`
Loading