curtain/Sources/Curtain/Log.swift
Aric Camarata 8c19e960d2 Detection root-cause fix + audit batch: netstat path, UDP activator, settings coherence, refactor, docs
Detection: netstat lives at /usr/sbin/netstat, not /usr/bin — the hardcoded wrong
path silently killed the ESTABLISHED-TCP activator (root cause of the failed live
test). Fixed and live-verified. Added peered-UDP activator (5900-5902) for
High-Performance sessions, per-signal transition logging, unconditional error
logging for dead probe helpers, and probe v2 with full CGSession dictionary
diffing. 7 new parser tests (32 total).

Fixes from a full audit + adversarial review: idle source setting honored
(default now Remote session activity), cover scope reduced to a coherent
two-mode model with legacy migration (per-display toggle was inverted in
onlyMarked and dead in all), curtain test no longer schedules a teardown over a
live session, specific-display password box placement gets a real picker,
refuse-to-arm enforced, activation notification posts a real banner, menu
password gate bypassed when the event tap is dead, shared single-decoder aerial
player with stale-task guard and async playability check, password buffer zeroed
on successful unlock and Esc, XPC interruption/invalidation handlers, modern
Accessibility settings URL, launchPath modernized, codesign failures now abort
release.sh, monotonic CFBundleVersion, install.sh temp cleanup, dead
armDisarmHotkey setting removed.

Refactor: Curtain.swift and PreferencesWindow.swift split into focused files
(largest now 479 lines). Wiki, README, and contributing docs updated to match.
Build clean at 0 warnings, 32/32 tests pass.
2026-06-09 20:36:30 -04:00

27 lines
1.4 KiB
Swift

import os
/// Purpose: One-line diagnostic logging for live testing, gated by the
/// diagnostics-logging setting so it stays silent in normal use.
/// Inputs: a short, greppable message string. Never pass secrets or passwords.
/// Outputs: a `.public` os.Logger line under subsystem io.acamarata.curtain so it
/// shows in `log stream` / Console without redaction. No-op when disabled.
/// Constraints: only log state transitions, never per-keystroke or per-tick events,
/// to avoid spam. os.Logger is Sendable, so the static instance is safe
/// under Swift 6 strict concurrency.
/// SPORT: MASTER-LOG
enum Log {
private static let logger = Logger(subsystem: "io.acamarata.curtain", category: "curtain")
static func event(_ message: String) {
guard Settings.diagnosticsLoggingEnabled else { return }
logger.log("CURTAIN \(message, privacy: .public)") // .public so it shows in log stream
}
/// Unconditional error logging NOT gated by the diagnostics setting. Reserved
/// for failures that would otherwise be silent (e.g. a detection probe that can
/// no longer launch its helper tool). Errors are rare by definition, so this
/// never spams; callers must still rate-limit anything that can repeat.
static func error(_ message: String) {
logger.error("CURTAIN ERROR \(message, privacy: .public)")
}
}