Skip to content

feat(capture): support per-app/per-URL capture exclusions - #30

Open
rogerdigital wants to merge 3 commits into
Einsia:mainfrom
rogerdigital:fix-capture-exclusion
Open

feat(capture): support per-app/per-URL capture exclusions#30
rogerdigital wants to merge 3 commits into
Einsia:mainfrom
rogerdigital:fix-capture-exclusion

Conversation

@rogerdigital

Copy link
Copy Markdown
Contributor

Summary

  • Add three optional [capture] config fields: excluded_window_title_patterns, excluded_app_names, excluded_bundle_ids
  • Matching windows are skipped entirely — no AX query, no screenshot, no JSON, no FTS row
  • Title patterns: case-insensitive substring match; app names and bundle IDs: case-insensitive exact match
  • All default to empty lists, behaviour unchanged unless opted in

Usage

[capture]
excluded_window_title_patterns = ["Incognito", "Private Browsing", "InPrivate", "1Password"]
excluded_app_names             = ["Signal"]
excluded_bundle_ids            = ["com.apple.keychainaccess"]

Tests

  • test_excluded_app_name_skips_capture — exact app name match
  • test_excluded_bundle_id_skips_capture — exact bundle ID match
  • test_excluded_title_pattern_skips_capture — substring title match
  • test_non_excluded_window_proceeds — non-matching windows pass through
  • test_exclusion_is_case_insensitive — case-insensitive matching
  • test_exclusion_with_empty_title_does_not_match_pattern — empty title doesn't trigger pattern match

All 111 tests pass, ruff clean.

Closes #27

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces privacy exclusion rules to skip window captures based on application names, bundle IDs, or window title patterns. It also improves datetime handling by ensuring that timestamps retrieved from the database or used in timeline aggregation are consistently timezone-aware. Feedback includes a suggestion to prevent empty strings in title patterns from matching all windows and a recommendation to omit window titles from logs when a capture is excluded to maintain privacy.

Comment thread src/openchronicle/capture/scheduler.py Outdated
return True
if cfg.excluded_window_title_patterns and meta.title:
title_lower = meta.title.lower()
if any(p.lower() in title_lower for p in cfg.excluded_window_title_patterns):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If excluded_window_title_patterns contains an empty string, the any(p.lower() in title_lower ...) check will return True for any non-empty window title, effectively excluding all windows from capture. It is safer to ensure the pattern p is non-empty before performing the substring match.

Suggested change
if any(p.lower() in title_lower for p in cfg.excluded_window_title_patterns):
if any(p and p.lower() in title_lower for p in cfg.excluded_window_title_patterns):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b119274 — empty patterns are now skipped via p and p.lower() in title_lower.

Comment on lines +68 to +71
logger.info(
"capture skipped (excluded): app=%r title=%r bundle=%r",
meta.app_name, meta.title[:60], meta.bundle_id,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Logging the window title of an excluded window may inadvertently leak sensitive information that the user specifically intended to keep private by using the exclusion feature. Since these rules are often used for privacy-sensitive contexts (e.g., Incognito windows, password managers), it is safer to omit the title from the logs or only log the app name and bundle ID.

Suggested change
logger.info(
"capture skipped (excluded): app=%r title=%r bundle=%r",
meta.app_name, meta.title[:60], meta.bundle_id,
)
logger.info(
"capture skipped (excluded): app=%r bundle=%r",
meta.app_name, meta.bundle_id,
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b119274 — removed title from the exclusion log, only app_name and bundle_id are logged.

Add three optional [capture] config fields —
excluded_window_title_patterns, excluded_app_names, excluded_bundle_ids
— that cause matching windows to be skipped entirely before any AX
query, screenshot, or disk write. Title patterns use case-insensitive
substring match; app names and bundle IDs use case-insensitive exact
match. All default to empty lists so behaviour is unchanged unless
opted in.

Closes Einsia#27
…on log

- Skip empty strings in excluded_window_title_patterns so they don't
  match every window ("" in "anything" is True)
- Don't log the window title on exclusion — the user excluded it for
  privacy, logging it defeats the purpose
@rogerdigital
rogerdigital force-pushed the fix-capture-exclusion branch from b119274 to 6334eb6 Compare May 9, 2026 16:07
@Xiao-ao-jiang-hu

Copy link
Copy Markdown
Member

Please add documentation for the newly introduced configuration items in docs/config.md.

Add a 'Privacy exclusions' subsection under [capture] in docs/config.md
covering excluded_window_title_patterns, excluded_app_names, and
excluded_bundle_ids — match semantics, defaults, and logging behavior.
@rogerdigital

rogerdigital commented May 11, 2026

Copy link
Copy Markdown
Contributor Author

Added in c297321 — documented all three fields under a new "Privacy exclusions" subsection in docs/config.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Privacy: support per-app / per-URL capture exclusions

2 participants