Skip to content

Add rule engine with schedule and interactive buttons - #6

Open
dgrieser wants to merge 37 commits into
mainfrom
feat/rules-triggers-conditions-actions-buttons
Open

Add rule engine with schedule and interactive buttons#6
dgrieser wants to merge 37 commits into
mainfrom
feat/rules-triggers-conditions-actions-buttons

Conversation

@dgrieser

Copy link
Copy Markdown
Collaborator
  • Introduced trigger, condition, and action concepts for configs, defaulting to classic message behavior.
  • Added support for schedule triggers (cron) with timezone handling and button timeout functionality.
  • Implemented Outlook calendar condition stub with environment‑based event source.
  • Expanded configuration schema with new fields: trigger, schedule_cron, schedule_timezone, condition, condition_negate, outlook patterns, action, action_target, buttons, button_timeout, button_timeout_target.
  • Added commands to set triggers, cron expressions, timezones, conditions, outlook patterns, actions, targets, button management, and immediate run.
  • Implemented interactive button blocks, pending button tracking, timeout handling, and persistence cache.
  • Developed scheduler to evaluate cron schedules, respect conditions, and execute actions.
  • Updated README with usage details for the new features.
  • Modified Helm chart deployment to expose new cache files via environment variables.
  • Updated requirements to include croniter and added new outlook.py stub module.
  • Extended tests to cover new setters, condition evaluation, actions, button handling, and scheduler behavior.

dgrieser added 30 commits June 24, 2026 06:13
- Introduced trigger, condition, and action concepts for configs, defaulting to classic message behavior.
- Added support for schedule triggers (cron) with timezone handling and button timeout functionality.
- Implemented Outlook calendar condition stub with environment‑based event source.
- Expanded configuration schema with new fields: trigger, schedule_cron, schedule_timezone, condition, condition_negate, outlook patterns, action, action_target, buttons, button_timeout, button_timeout_target.
- Added commands to set triggers, cron expressions, timezones, conditions, outlook patterns, actions, targets, button management, and immediate run.
- Implemented interactive button blocks, pending button tracking, timeout handling, and persistence cache.
- Developed scheduler to evaluate cron schedules, respect conditions, and execute actions.
- Updated README with usage details for the new features.
- Modified Helm chart deployment to expose new cache files via environment variables.
- Updated requirements to include `croniter` and added new `outlook.py` stub module.
- Extended tests to cover new setters, condition evaluation, actions, button handling, and scheduler behavior.
- schedule_reply now respects `action` config and presence of `buttons`, delegating to `run_action` for non‑reply actions or when buttons are defined
- classic plain threaded reply retained for default `ACTION_REPLY` without buttons
- action_reply validates `thread_ts` against the target channel, preventing invalid thread references across conversations
- added comprehensive tests covering routing to actions, button handling, classic reply behavior, and channel‑specific threading constraints
…ndling

- Update .gitignore to include button state persistence file.
- Expand README with detailed button syntax, examples, and OpsGenie integration.
- Introduce new button action constants (config, ack, message, alert, delay) and escalation types.
- Extend DEFAULT_CONFIG with `default_button` and normalize legacy button format during migration.
- Refactor command parsing to support typed button specifications and default‑button commands.
- Implement add, clear, set, and clear default button commands with validation.
- Rewrite schedule_reply to always use the unified action engine and forward replies when configured.
- Add escalation registration, task handling, and auto‑press of default button on timeout.
- Enhance button press handling to support ack, message, alert, delay, and rescheduling.
- Provide helper functions for button normalization, finding buttons, and determining escalation kind.
- Update tests to cover new button actions, migration, default button behavior, and refactored logic.
…config property

- Updated README to clarify button syntax, button‑gated OpsGenie workflow, and added docs for `opsgenie-message`.
- Added `opsgenie_message` field to default config and commands to set/clear it.
- Refactored button handling: removed the dedicated `alert` action, treated OpsGenie as a regular config property.
- Implemented `_render_template`, `maybe_post_opsgenie_alert`, and context handling so any config with OpsGenie enabled can fire alerts using the original message or a custom template.
- Adjusted escalation logic to use config‑level OpsGenie and pass original message context to target configs.
- Updated `show_config`, help output, and related UI messages to reflect new behavior.
- Modified tests to reflect removal of the `alert` button action and new context propagation for OpsGenie alerts.
- Updated the news message text to highlight new capabilities:
- Triggers, actions, and interactive buttons now supported.
- Rules can run on a schedule (cron), DM users or groups, post to channels, and include auto‑press defaults with timeout escalation.
- Provides users with a concise overview of these features directly in the `/hutbot help` output.
- Expose HTTP port 8080 in Dockerfile and enable optional UI via env vars
- Document UI setup, endpoints, and Helm chart configuration in README
- Implement UI backend helpers in `bot.py` for validation, channel membership, and config CRUD
- Add `maybe_start_web_ui` to launch aiohttp UI when enabled
- Extend Helm chart (Chart.yaml bump to 0.1.3) with UI service, ingress, and network policy resources
- Include new Helm values under `ui:` to configure enablement, port, host, headers, service, and ingress
- Add `webui.py` aiohttp server with routes, security headers, and UI context bridging
- Provide static assets (`app.js`, `index.html`, `styles.css`) for the single‑page UI
- Add tests for UI helper functions and CRUD operations
- Adjust main loop to start and clean up the UI runner
- Minor updates to other files to integrate the new functionality.
- Document UI security considerations in README and explain `ui.allowedIngress`.
- Extend Helm chart values and NetworkPolicy to configure allowed ingress sources for the UI.
- Set default `allowedIngress` to an empty list (back‑compat insecure) with example.
- Introduce `get_user_by_email_strict` for exact‑email lookups and use it in the web UI backend.
- Update OpsGenie alert handling to use the posted message timestamp when the original ts is missing.
- Snapshot button definitions at posting time, store them, and strip interactive buttons after a press.
- Resolve button actions against the snapshot to prevent edited configs from affecting old messages.
- Preserve the original author in the context for config‑running buttons.
- Fix escalation task cleanup logic to avoid removing a rescheduled timer.
- Add comprehensive tests covering the new UI auth, allowedIngress, button snapshotting, alert aliasing, and escalation behavior.
Exclude the development environment file from version control.
Define a second 'dev' environment in helmfile to allow running an
independent Hutbot instance alongside production in the same namespace.
The dev release uses its own name, PVC, and secrets, ensuring complete
isolation. Documentation updated to explain deployment steps, including
environment variable configuration and image override support.
- Update Helm chart version to 0.2.0 and appVersion to v1.0.9
- Modify deployment template to reject empty or floating image tags
- Set default image tag to empty string in values.yaml
- Pin specific release tags (v1.0.9) in helmfile environments
- Update GitHub Actions workflow to publish immutable release tags
- Document the new tagging strategy and deployment constraints in README
- Add deploy-dev.sh to deploy the hutbot dev instance using .env-dev
- Add deploy-prod.sh to deploy the production instance with confirmation prompts
- Both scripts enforce pinned image tags and require helmfile
- Support custom helmfile arguments via extra positional parameters
Allow different deployments (e.g., dev vs production) to listen on
distinct Slack slash commands by introducing the HUTBOT_SLASH_COMMAND
environment variable. This resolves conflicts where multiple instances
cannot share the same command registration.

Changes include:
- Add `slashCommand` field to Helm values and environment definitions
- Update routing, help messages, and error texts to use the configured
command dynamically
- Normalize command input to ensure consistent formatting
- Bump chart version to 0.3.0
- Add tests for command normalization and routing configuration
Introduce `HUTBOT_BOT_NAME` environment variable to allow different
deployments (e.g. dev vs prod) to identify themselves distinctly in
user-facing text.

Key changes:
- Add `botName` Helm value and `HUTBOT_BOT_NAME` env var support.
- Update help, news, and forwarding messages to use the configured name.
- Use Slack handle from `auth.test` for `@mention` examples to ensure
they work regardless of the display name.
- Derive OpsGenie alias from a slugified version of the name to prevent
deduplication conflicts between instances.
- Pass bot name to Web UI via `/api/meta` for client-side branding.
- Add hutbot.png
- Add hutbot.xcf
- Add hutbot_large.png
- Add hutbot_large_bg.png
- Add hutbot_medium.png
Added assets/hutbot_dev_large_bg.png to support the new visual requirements for the hutbot development environment.
- Add link to Hutbot_DEV Slack App in README
- Clarify that dev bot uses same variable names as `.env`
- Update documentation for registering second Slack app credentials
- Reject 'latest' and 'main' tags in Helm chart and deploy scripts
- Fix race condition in button press handling with atomic claim logic
- Split Slack messages and action blocks to respect API size limits
- Prevent legacy forwarding for non-reply scheduled actions
- Validate config rule existence during UI updates
- Guard against stale channel selection in WebUI
Introduce a backward-compatible launcher script (`bot.py`) that delegates
to the package entry point, allowing legacy invocations to continue
working. Update documentation to reflect this change.

Fix configuration migration logic in `persistence.py` to correctly
identify legacy flat formats. The previous check incorrectly assumed
that any key matching `DEFAULT_CONFIG` indicated a flat structure.
This caused issues when users had custom configurations named after
newly added default fields (e.g., `trigger`, `action`). The updated
logic verifies that values are not dictionaries to accurately detect
flat vs. nested formats.

Add tests for the new entry point delegation and the corrected
migration behavior.
Track when the bot is removed from or added back to a Slack channel.
When removed, automatically disable all enabled configurations for that
channel and cancel pending scheduled replies and button escalations.
Mark these configurations with a specific `disabled_reason` so they can
be identified later.

When the bot re-joins the channel, post a message listing the
configurations that were disabled by the removal. These are not
re-enabled automatically; users must explicitly enable them via slash
command or web UI. Ensure explicit user actions (enable/disable) always
override the automatic disable marker.
- Group settings by topic (triggers, conditions, timing, buttons, alerting)
in the `/info` output for better readability.
- Replace generic "Action target" with descriptive destination labels per
action type (reply, post, DM, group DM).
- Resolve and display the server's local timezone name and locale for
orientation when no explicit config is set.
- Use `datetimefmt.describe_*` to show timezone offsets and locale status
clearly in config output.
- Pass config dicts to `is_work_day` and `is_work_time` so work hours/days
are evaluated in the configured timezone rather than the server's.
- Add helper functions to detect server timezone/locale names from
environment variables and system paths.
Configure `time.timezone` and `time.locale` in the Helm chart to set
instance-wide defaults for date/time formatting. These values are passed
to the container via environment variables (`TZ` and
`HUTBOT_DEFAULT_DATETIME_LOCALE`).

- Add new `time` section to Helm values with `timezone` and `locale` keys
- Update deployment template to inject env vars when values are set
- Update `helmfile` template to support these settings
- Implement fallback logic in Python: configs without their own locale
now use the instance default
- Update UI hints to clarify that blank fields use server local time or
instance defaults
- Add tests for deployment validation and locale fallback behavior
- Replace `<None>` with `<none>` for consistent lowercase null representation
- Remove colons from action destination labels (e.g., "Replied to:" -> "Replied in")
- Update tests to reflect new string formatting in info command output
- Allow `set_wait_time` to accept string input and validate it locally.
- Return user-friendly error message for non-numeric or out-of-range wait times.
- Wrap command processing in try/except to prevent crashes from unexpected errors.
- Log errors using centralized logging and notify users of failures.
- Add tests for invalid wait time values and error reporting.
- Allow setting work hours to "all day" via the `set work-hours all day`
command, which is stored internally as `0:00 0:00`.
- Reorganize the help message into logical groups (Configurations, Trigger,
Condition, etc.) to improve readability and match the order of rule execution.
- Update tests to verify the new command syntax and help message structure.
- Store the initial `wait_time` in the persistence cache when scheduling
a reply to track the config value at creation time.
- Pass the original wait time through to the rescheduling logic.
- Update logging during restoration to distinguish between the remaining
time, the original configured wait, and any subsequent config changes.
- Add tests to verify logging behavior for new and legacy cache entries.
Pass the deployed image tag via `HUTBOT_VERSION` environment variable from
the Helm chart to the bot container. The application reads this value at
startup and displays it in `help` and `news` command outputs.

A normalization function ensures consistent version formatting (e.g.,
prefixed with `v`). A fallback version is used when the environment
variable is unset, such as during local development. Tests verify both
the Helm chart configuration and the bot's message generation.
Introduce `{{date}}`, `{{time}}`, and `{{datetime}}` template variables that
render the triggering message's timestamp or the current time for scheduled
and manual triggers. These variables support the same formatting, timezone,
and locale arguments as existing Opsgenie datetime variables.

Update bot handle resolution to fetch the profile display name via the Slack
API, ensuring correct @mention examples in help text across different app
configurations.

Add tests for the new templating features and bot handle fetching logic.
Slack splits oversized messages arbitrarily, which can break code fences and
display incomplete output. This change introduces `pack_message_chunks` to
gently group message parts while keeping individual blocks (like config
sections or command table rows) intact.

Key changes:
- Enforce a 3800 character limit on outgoing messages.
- Split the `show config` command into multiple messages if it contains
several configurations, ensuring each config block remains whole.
- Split the help command's command table into chunks, labeling subsequent
parts as "(continued)".
- Update bot handle resolution to prioritize `real_name` for better
display names in mentions.
- Add `sent_messages` test helper to aggregate split messages for easier
assertions.
Merge the separate `set target` and `set forward-channel` commands into
`set action <action> [<target>]`. This ensures a config always has a
valid destination for its chosen action, preventing runtime failures.
Legacy forwarding is removed in favor of the `post_channel` action.

- Require target when setting non-reply actions like `dm-user`,
`group-dm`, or `post-channel`.
- Remove `forward_channel` field and related commands.
- Update button specs to require an explicit action keyword.
- Add migration logic to warn about dropped legacy forward channels.
- Update help text, documentation, and tests accordingly.
Remove the dedicated `schedule_timezone` configuration option. Cron
schedules now fire using the config's `datetime_timezone`, falling back
o server local time if not set. Existing configurations are migrated:
if only a schedule timezone was defined, it is moved to the date/time
field; if both were defined and differ, the date/time timezone takes
precedence.
Rename the `schedule` trigger to `cron` and integrate the cron expression directly into the trigger command. The cron expression is now mandatory for the `cron` trigger, preventing rules from being left in a state where they never fire. This simplifies the configuration model by removing the separate `set cron` command and consolidating schedule settings with the trigger definition.
Introduce `clear pattern`, `clear default-button`, and `clear opsgenie-message` commands to reset configuration values to their defaults. This allows users to easily revert specific settings without manually re-entering other configurations.

Update help documentation to reflect new commands and clarify existing descriptions for conditions, datetime formats, and on-call lookups. Add tests to verify the new clearing functionality and ensure help output includes all documented commands.
Update command patterns in `patterns.py` to make the leading word `set` optional for all setter commands. This allows users to run commands like `wait-time 5` or `trigger cron ...` without explicitly typing `set`.

Refactor `dispatch.py` to resolve ambiguity between config names and command words:
- Prioritize existing config names over command matching (e.g., `trigger message` uses the `trigger` config).
- Prevent reserved command words (like `set`, `enable`) from being used as config names.
- Add `RESERVED_CONFIG_NAMES` constant to define these protected words.
- Update help text to reflect the optional `set` keyword.

Add tests to verify that setter commands work with and without `set`, that existing configs take precedence in ambiguous cases, and that reserved words cannot create new configurations.
…etting

Replace the separate `button-timeout`, `button-timeout-target`, and
`default-button` commands with a single `set escalation <minutes> <kind>
<target>` command. This ensures a timer always has a defined action to
fire, preventing silent no-ops.

Key changes:
- Merge timeout duration and target into one atomic setting stored as
`escalation_timeout`, `escalation_kind`, and `escalation_target`.
- Button `message` and `ack` actions now support template rendering
(variables and @mentions) against the original message context.
- Update Web UI to reflect the new escalation structure.
- Remove deprecated commands and update tests accordingly.
Refactor the command for disabling escalations to use a dedicated
`clear escalation` command instead of the `set escalation none` syntax.
This improves clarity and consistency with other configuration commands.

- Update command patterns and dispatch logic to handle `clear/unset/remove
escalation`.
- Add `clear_escalation` setter function.
- Modify `set_escalation` to guide users toward the new command when
attempting to disable escalation.
- Update button delay logic to gracefully handle presses on messages
without active escalations, keeping buttons functional.
- Update documentation, help text, and tests to reflect the change.
Delay buttons now validate that an active escalation exists before being
added, preventing stranded buttons. Clearing an escalation now warns
users if any delay buttons remain in the configuration.

- Enforce escalation requirement in `add_button` command
- Add warning to `clear_escalation` when delay buttons are present
- Update documentation and help text
- Add tests for validation and warning behavior
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.

1 participant