Skip to content

[BUG] Dynamic rules, agent wiring and the custom response modifier diverge from the reference #83

Closed

Description

@rennf93

Value this delivers

A dashboard dynamic rule changes protection in PHP exactly as it does in the Python reference, and the agent wiring and the response modifier work from config alone.

What happened

I compared the PHP engine with the Python reference (guard-core master at 859ac345, which includes guard-core #169) for dynamic rules, the agent wiring and custom_response_modifier. They diverge:

  • ip_blacklist IPs are merged into the static blacklist and ip_whitelist IPs into the static whitelist (src/Rules/DynamicRuleManager.php, ruleFields). The reference bans the blacklist IPs for ip_ban_duration seconds and unbans the whitelist IPs (_dynamic_rule_application.py, _apply_ip_bans and _apply_ip_whitelist). ip_ban_duration is parsed and never applied.
  • block_cloud_providers, blocked_user_agents and endpoint_rate_limits are appended or merged with the base values and unknown providers are not filtered. The reference replaces them with the validated list (an all-invalid list empties it) and drops unknown providers.
  • global_rate_window is applied without a global_rate_limit. Emergency mode only halves the auto-ban threshold when the whitelist is empty or the rule carries a threshold; the reference always halves it. Country rules with no geo resolver fail the whole rule; the reference warns and skips them.
  • A failed application restores the base config instead of the previously active version, and suspicious_patterns already in the pool are added again on every version (guard-core #169).
  • The emergency_mode_activated event is never sent, and the dynamic_rule_updated and dynamic_rule_applied envelopes do not match the reference (handler name, reason, metadata).
  • SecurityConfig::with() drops enableAgent, enableDynamicRules, agentEnableEvents, agentEnableMetrics and dynamicRulesCachePath, so every installed dynamic config silently loses them, and consecutive candidates carry the same revision so the pipeline is not rebuilt.
  • Wiring: nothing in src instantiates DynamicRuleManager, so enableDynamicRules is inert. enableAgent is accepted and never stored, and the reference validation (enable_dynamic_rules and enable_enrichment need enable_agent) is missing. There is no dynamic_rule_interval. GuardResponseFactory takes a modifier that nothing passes, and SecurityConfig has no custom_response_modifier field. The guard-agent-php DynamicRules object is not accepted by the manager.
  • The last-known snapshot renders the timestamp as +00:00 instead of Z and an empty endpoint_rate_limits as a list.
  • Docs and examples still say enableAgent fails config validation and that dynamic rules are unsupported, and docs/usage.md says the metrics collector persists to Redis although the engine builds it without a Redis handler.

Steps to reproduce

  1. Build new SecurityConfig(enableAgent: true, enableDynamicRules: true) and a GuardEngine, attach an agent handler with setAgentHandler(), and call initialize(): no manager exists and no rule is ever fetched.
  2. Drive a DynamicRuleManager by hand with emergency rules v1 to v3 over a base autoBanThreshold of 16 and fail a later version: the config falls back to the base, not to the last applied version.
  3. Deliver ip_blacklist with ip_ban_duration: the IP is in $config->blacklist, not banned for the duration.

Versions

guard-core-php master at fcbbb30, PHP 8.5 on macOS (the divergences are version independent).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: engineTouches src/Engine/, src/Config/, or src/Routing/bugConfirmed defect

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions