Omahub
← All plugins
A

Itsy Calendar

by Ajan Raj

A pinnable calendar, agenda, and meeting-aware replacement for the Omarchy clock

Security review

Potentially dangerous behavior detected · 5 findings

Deterministic scan — not a security guarantee

High
Risk level
High
Analyzed commit
6c98758
Scanned
1 month ago
  • high destructive_filesystem …/setup/test_setup.sh:125

    Destructive operation on the root filesystem or a block device.

    rm -rf /' >/dev/null 2>"$TEST_ROOT/shortcut.err"; then
  • medium package_manager …/workflows/ci.yml:25

    System package manager operation.

    apt-get update
  • medium package_manager …/workflows/ci.yml:26

    System package manager operation.

    apt-get install --yes jq shellcheck qt6-base-dev qt6-declarative-dev qt6-declarative-dev-tools qml6-module-qtqml qml6-module-qtqml-workerscript qml6-module-qtquick qml6-module-qtquick-window qml6-modu
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo apt-get update
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo apt-get install --yes jq shellcheck qt6-base-dev qt6-declarative-dev qt6-declarative-dev-tools qml6-module-qtqml qml6-module-qtqml-workerscript qml6-module-qtquick qml6-module-qtquick-window qml6

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
6c98758
Reviewed
1 month ago

The deterministic scan's high-risk finding is a false positive: the `rm -rf /` string is in a setup test as a negative input that verifies the `shortcut` command rejects unsafe chords, so it is never executed during normal install or plugin runtime. The CI `apt-get`/`sudo` findings are confined to GitHub Actions and do not affect end-user machines. The actual setup flow is user-invoked, checksum-pinned, and journals/rolls back its configuration changes, so I see no malicious or dangerous code.

How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/ajanraj/itsy-calendar --enable
Widgets #bar #quickshell

Itsy Calendar

Itsy Calendar is an Omarchy clock replacement with a local-vdir calendar store, a short-lived Rust calendar engine, and a pinnable calendar panel. It creates a writable Personal calendar on first startup. CalDAV accounts and provider credentials remain outside the plugin.

Prerequisites

  • Omarchy 4 with the Omarchy shell and Hyprland running.
  • jq, sha256sum, and curl for engine downloads, update checks, and URL calendar subscriptions.
  • A supported x86_64 or aarch64 Linux machine. The engine is a static musl release; Cargo and Python are not runtime prerequisites.
  • vdirsyncer is recommended for CalDAV sync; khal is useful for inspecting the resulting vdirs. Itsy Calendar does not install or configure either.

For example, after configuring vdirsyncer yourself:

vdirsyncer discover
vdirsyncer sync
khal list

The panel can create more writable local calendars and add read-only HTTPS or webcal subscriptions. URL calendars refresh at startup, every 15 minutes, and when Sync Now is selected. The source URL is stored with mode 0600 inside Itsy Calendar's XDG data directory. Sync failures never hide records already present locally.

For a read-only subscription, add an empty .itsy-calendar-read-only marker to its calendar directory. The sync tool can still update the directory, while Itsy Calendar hides mutation actions and rejects writes to that calendar.

Install and review

Omarchy plugins run unsandboxed inside the long-lived omarchy-shell process. Review the repository, especially manifest.json, QML entry points, setup, and scripts/, before enabling it:

omarchy plugin add https://github.com/ajanraj/itsy-calendar.git
less ~/.config/omarchy/plugins/io.github.ajanraj.itsy-calendar/README.md
~/.config/omarchy/plugins/io.github.ajanraj.itsy-calendar/setup doctor
~/.config/omarchy/plugins/io.github.ajanraj.itsy-calendar/setup install

omarchy plugin add validates the manifest but does not run setup. The explicit setup step downloads the architecture-specific engine only after the user asks for installation and enables the reviewed plugin as the final step. It verifies the digest pinned in scripts/engine-checksums.json before placing the executable at:

${XDG_DATA_HOME:-$HOME/.local/share}/itsy-calendar/bin/itsy-calendar-engine

The released checksum map is deliberately fail-closed. A source checkout can contain UNRELEASED entries until the two-phase release process has committed the real digests. For local development, use the explicit, network-free override (never with an unreviewed binary):

./setup install --engine-path /absolute/path/to/itsy-calendar-engine

This hashes and atomically copies that file but is not a release trust path.

Release provenance

Engine releases use a tag-only workflow with every action pinned to a full commit SHA, fixed Rust and cross versions, and digest-pinned build images. Before tagging, the release candidate and a second CI build must match byte-for-byte; the matching digests are then committed. The workflow checks that the tag, source commit, package version, and those committed engine digests agree before it publishes anything. It also creates build-provenance attestations for both engine binaries. Before tagging, the release maintainer must verify that repository release immutability is enabled; after publication, the workflow verifies the resulting signed immutable release. From v0.2.1 onward, GitHub locks the tag and assets after that publication.

To verify the release and an engine binary:

gh release verify v0.2.1 --repo ajanraj/itsy-calendar
gh release download v0.2.1 --repo ajanraj/itsy-calendar \
  --pattern 'itsy-calendar-engine-x86_64-unknown-linux-musl'
gh attestation verify ./itsy-calendar-engine-x86_64-unknown-linux-musl \
  --repo ajanraj/itsy-calendar \
  --signer-workflow ajanraj/itsy-calendar/.github/workflows/release.yml \
  --source-ref refs/tags/v0.2.1

What setup changes

./setup install performs a narrow transaction:

  1. verifies and atomically installs the pinned engine;
  2. changes exactly one omarchy.clock bar entry's id to io.github.ajanraj.itsy-calendar, preserving its section, index, and every other property;
  3. changes bar.centerAnchor only when it was omarchy.clock;
  4. adds a uniquely marked hypr.itsy-calendar fragment and a marked include in hypr/bindings.lua, overriding the existing Super+Ctrl+Alt+D binding;
  5. reloads the Omarchy shell and Hyprland when their commands are available.

The original bytes, modes, and hashes are journaled outside the checkout at ${XDG_STATE_HOME:-$HOME/.local/state}/itsy-calendar/setup.json. Temporary files are created beside their target and renamed atomically. Setup never evaluates a user-provided command string; executable-plus-argument-array settings belong to the runtime, not this installer.

The URI handler is opt-in:

./setup install --register-uri

This registers itsycal:// through the fixed xdg-mime argv interface and records the previous handler. Uninstall restores that handler only while it still points to Itsy Calendar. No URI association is changed by a normal install. The handler accepts only itsycal://date/now and strict Gregorian itsycal://date/YYYY-MM-DD links; malformed links are ignored, and valid links are dispatched directly to the running Calendar service.

Capabilities

The Calendar Engine speaks protocol 1 and reads one JSON request, writes one JSON response, logs only to stderr, and exits nonzero for errors. It supports:

  • doctor: discover local vdir calendars and report capabilities/diagnostics;
  • snapshot: inclusive-start, exclusive-end occurrence snapshots;
  • apply: create an item or delete one occurrence / all future occurrences;
  • manage: ensure the Personal calendar, create local calendars, and add or refresh URL subscriptions.

The engine preserves date-only, floating, named-timezone, recurrence, detached-override, unknown-property, and malformed-item boundaries. It does not authenticate to providers, run vdirsyncer/khal, invoke a shell, or provide an event-edit UI. URL downloads execute curl with a fixed argument list and an HTTPS-only redirect policy. Creation requires the explicitly selected writable Creation Calendar.

The resident Omarchy service owns snapshots, polling, alerts, hourly sound, and IPC once the plugin is enabled. The bar remains presentation-only, so a multi-monitor shell does not duplicate engine work or notifications.

In Advanced settings, optional My calendar emails identify which ICS attendee is you. This enables accurate declined filtering and pending/tentative styling; when left empty, Itsy Calendar does not guess. The panel follows the global Omarchy theme. Its source-derived row shortcuts are Ctrl+Shift+J to add a row and Ctrl+K to remove one; Ctrl+J remains Join because macOS's separate Command-J and Control-J both map to Ctrl on Linux.

Setup commands

./setup install [--register-uri] [--engine-path PATH]
./setup install-engine [--engine-path PATH]
./setup check-update
./setup doctor
./setup shortcut 'SUPER + CTRL + ALT + D'
./setup disable
./setup uninstall

check-update is non-mutating and prints exactly one protocol-1 JSON envelope, for example:

{"protocol":1,"ok":true,"data":{"current":"0.2.1","latest":"0.2.1","available":false}}

The UI checks every four days and on demand. An update is reviewed through Omarchy's plugin-update flow; the engine is never silently replaced. The UI must obtain confirmation before calling install-engine.

disable restores the stock clock and binding while retaining inline plugin settings, the Calendar Store, runtime alert history, and the engine. A later install restores the saved plugin entry, including settings changed while it was enabled or disabled. uninstall removes only unchanged setup-owned integration and the unchanged setup-owned engine; it does not delete Calendar Store data or runtime.json. For a shell file with normal user edits, setup replaces only the uniquely identified plugin/stock clock entry and preserves its current settings, section/index, and unrelated bar edits. Use disable when you want to keep those plugin settings for a future reinstall.

After explicit review/confirmation, shortcut rewrites only the managed Hypr fragment. It accepts one normalized chord with one or more of SUPER, CTRL, ALT, and SHIFT, plus one letter, digit, or F1–F12 key, then reloads Hyprland and checks for configuration errors. Rejected or failed changes leave the prior fragment and journal ownership intact.

Recovery and ownership safety

Shell layout ownership is structural: disable/uninstall require exactly one known plugin entry and no stock clock while enabled, or exactly one stock clock and no plugin while disabled. Normal plugin setting edits, entry moves, and unrelated bar edits are preserved. Duplicate, missing, or mixed clock entries are ambiguous and refuse the operation. Hypr include/fragment files, the opt-in URI desktop entry, and the engine use whole-file compare-and-swap ownership; setup refuses to restore those paths after edits rather than clobbering them. It also refuses symlinks, incomplete markers, and foreign or malformed journals.

Start with:

./setup doctor

If it reports edited or ambiguous state, preserve the diagnostic and review the specific file and journal backup before making a manual choice. Do not delete the journal or backup directory to force an uninstall. A transaction failure attempts a compare-and-swap rollback; if rollback itself encounters an edit, the journal is left for manual recovery and doctor remains non-mutating.