# frozen_string_literal: true module Api class RulesController < ApplicationController # NOTE: This controller is now SECONDARY/UNUSED for primary agent synchronization # Agents get rule updates via event responses (see Api::EventsController) # These endpoints are kept for administrative/debugging purposes only skip_before_action :verify_authenticity_token allow_unauthenticated_access # Skip normal session auth, use project key auth instead before_action :authenticate_project! before_action :check_project_enabled # GET /api/:public_key/rules/version # Quick version check - returns latest updated_at timestamp def version current_sampling = HubLoad.current_sampling response.headers['X-Sample-Rate'] = current_sampling[:allowed_requests].to_s render json: { version: Rule.latest_version, count: Rule.active.count, sampling: current_sampling } end # GET /api/:public_key/rules?since=1730646186 # Incremental sync - returns rules updated since timestamp (Unix timestamp in seconds) # GET /api/:public_key/rules # Full sync - returns all active rules def index rules = if params[:since].present? # Incremental sync since_time = parse_timestamp(params[:since]) Rule.since(since_time) else # Full sync - only return enabled rules Rule.active.sync_order end current_sampling = HubLoad.current_sampling response.headers['X-Sample-Rate'] = current_sampling[:allowed_requests].to_s render json: { version: Rule.latest_version, sampling: current_sampling, rules: rules.map(&:to_agent_format) } rescue ArgumentError => e render json: { error: "Invalid timestamp format: #{e.message}" }, status: :bad_request end private def authenticate_project! public_key = params[:public_key] || params[:project_id] @project = Project.find_by(public_key: public_key) unless @project render json: { error: "Invalid project key" }, status: :unauthorized return end end def check_project_enabled unless @project.enabled? render json: { error: "Project is disabled" }, status: :forbidden end end def parse_timestamp(timestamp_str) # Parse Unix timestamp in seconds unless timestamp_str.match?(/^\d+$/) raise ArgumentError, "Invalid timestamp format. Expected Unix timestamp in seconds (e.g., 1730646186)" end Time.at(timestamp_str.to_i) rescue ArgumentError => e raise ArgumentError, "Invalid timestamp format: #{e.message}. Use Unix timestamp in seconds (e.g., 1730646186)" end end end