# frozen_string_literal: true module Api class RulesController < ApplicationController skip_before_action :verify_authenticity_token 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 render json: { version: Rule.latest_version, count: Rule.active.count, sampling: HubLoad.current_sampling } end # GET /api/:public_key/rules?since=2024-11-03T12:00:00.000Z # Incremental sync - returns rules updated since timestamp # 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 render json: { version: Rule.latest_version, sampling: HubLoad.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) Time.parse(timestamp_str) rescue ArgumentError => e raise ArgumentError, "Invalid timestamp format. Expected ISO8601 format (e.g., 2024-11-03T12:00:00.000Z)" end end end