Projects
home:rottame:yggdra_agents
mail_agent
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 22
View file
rubygem-mail_agent.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Thu Jan 15 13:56:02 UTC 2026 - Angelo Grossini <rottame@intercom.it> + +- update to 1.2.3 + +------------------------------------------------------------------- Tue Dec 2 14:43:27 UTC 2025 - Angelo Grossini <rottame@intercom.it> - update dependencies
View file
rubygem-mail_agent.spec
Changed
@@ -1,4 +1,4 @@ -%define package_version 1.2.2 +%define package_version 1.2.3 %define mod_name mail_agent %define mod_full_name %{mod_name}-%{version} @@ -18,6 +18,7 @@ BuildRequires: systemd-rpm-macros BuildRequires: %{ruby >= 1.9} BuildRequires: %{rubygem gem2rpm} +BuildRequires: sysuser-tools BuildRoot: %{_tmppath}/%{mod_full_name}-build %description
View file
mail_agent-1.2.2.gem/data/build/gem2rpm.yml
Deleted
@@ -1,4 +0,0 @@ ---- -:disable_docs: true -:patches: -:sources: \ No newline at end of file
View file
mail_agent-1.2.2.gem/data/build/mail_agent.service
Deleted
@@ -1,15 +0,0 @@ -Unit -Description=hel mail database agent - -Service -Type=simple -User=tomte -Group=tomte -PIDFile=/run/mail_agent/mail_agent.pid -ExecStart=/usr/bin/mail_agent --pidfile /run/mail_agent/mail_agent.pid -e production --no-daemonize -WorkingDirectory=/var/lib/tomte -Restart=always - -Install -WantedBy=multi-user.target -
View file
mail_agent-1.2.2.gem/data/build/mail_agent.tempfiles
Deleted
@@ -1,1 +0,0 @@ -d /run/mail_agent 0755 tomte tomte - - \ No newline at end of file
View file
mail_agent-1.2.2.gem/data/build/mail_agent.yml
Deleted
@@ -1,138 +0,0 @@ -_common: - mail: - rpc_exchange: 'ygg.email.rpc.db.api' -development: - core: - log_level: debug - debug: false - hel: - host: HEL_ADDRESS - username: HEL_USERNAME - password: HEL_PASSWORD - raven: - dsn: - database: - email: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - policyd: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - cluebringer: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - amavis: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - -production: - core: - log_level: info - debug: false - hel: - host: HEL_ADDRESS - username: HEL_USERNAME - password: HEL_PASSWORD - raven: - dsn: - database: - email: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - policyd: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - cluebringer: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - amavis: - adapter: mysql2 - encoding: utf8 - database: DATABASE - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - -test: - core: - log_level: debug - debug: false - hel: - host: HEL_ADDRESS - username: HEL_USERNAME - password: HEL_PASSWORD - raven: - dsn: - database: - email: - adapter: mysql2 - encoding: utf8 - database: mail - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock - policyd: - adapter: mysql2 - encoding: utf8 - database: smtp_out_ng - pool: 5 - host: DATABASE_ADDRESS - username: DATABASE_USERNAME - password: DATABASE_PASSWORD - #reconnect: false - #socket: /tmp/mysql.sock
View file
mail_agent-1.2.2.gem/data/build/rubygem-mail_agent.spec
Deleted
@@ -1,85 +0,0 @@ -%define package_version 1.2.2 -%define mod_name mail_agent -%define mod_full_name %{mod_name}-%{version} - -Name: rubygem-mail_agent -Version: %{package_version} -Release: 0 -Summary: Mail Database Agent -License: Apache-2.0 -Group: Development/Languages/Ruby -URL: https://intercom.it -Source: %{mod_full_name}.gem -Source1: mail_agent.service -Source2: mail_agent.tempfiles -Source2: tomte.yml -Source4: mail_agent.yml -BuildRequires: ruby-macros >= 5 -BuildRequires: systemd-rpm-macros -BuildRequires: %{ruby >= 1.9} -BuildRequires: %{rubygem gem2rpm} -BuildRoot: %{_tmppath}/%{mod_full_name}-build - -%description -Mail agent DB provisioning agent - -%package -n mail_agent -Summary: Mail Database Agent -Group: System/Daemons -Requires: rubygem(%{mod_name}) = %{version} - -%description -n mail_agent -Mail agent DB provisioning agent - -%prep - -%build - -%install -%gem_install -f --symlink-binaries --no-ri --no-rdoc -install -d %{buildroot}%{_localstatedir}/lib/mail_agent -install -D -m 0644 %{SOURCE1} %{buildroot}%{_tmpfilesdir}/mail_agent.conf -install -D -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/mail_agent.service -install -D -m 0644 %{SOURCE3} %{buildroot}%{_sysconfdir}/mail_agent/mail_agent.yml -install -D -m 0644 %{SOURCE4} %{buildroot}%{_sysconfdir}/mail_agent/tomte.yml -install -d %{buildroot}%{_sbindir} -ln -s /usr/sbin/service %{buildroot}%{_sbindir}/rcmail_agent - -%gem_packages - - -%files -n mail_agent -%defattr(-, root, root) -%ghost /run/mail_agent -%dir %{_sysconfdir}/mail_agent -%config(noreplace) %{_sysconfdir}/mail_agent/mail_agent.yml -%config(noreplace) %{_sysconfdir}/mail_agent/tomte.yml - -%attr(0700, tomte, tomte) %dir %{_localstatedir}/lib/mail_agent - -%{_unitdir}/mail_agent.service -%{_tmpfilesdir}/mail_agent.conf - -%{_sbindir}/rcmail_agent - - -%pre -n mail_agent -%{_bindir}/getent group mail_agent >/dev/null || %{_sbindir}/groupadd -r mail_agent -%{_bindir}/getent passwd mail_agent >/dev/null || %{_sbindir}/useradd -r -d %{_localstatedir}/lib/tomte -s /bin/false -c "intercom mail policyd" -g mail_agent mail_agent -%service_add_pre mail_agent.service -exit 0 - -%preun -n mail_agent -%service_del_preun mail_agent.service -exit 0 - -%post -n mail_agent -%tmpfiles_create %_tmpfilesdir/mailserver_agent.conf -%service_add_post mail_agent.service -exit 0 - -%postun -n mail_agent -%service_del_postun mail_agent.service -exit 0 - -%changelog
View file
mail_agent-1.2.2.gem/data/build/tomte.yml
Deleted
@@ -1,27 +0,0 @@ -_common: - # - # Core configuration parameters - # - protocol: - heartbeat: 30 - serialization: bson - - # Asynchronous clients - # Message buses to connect to - # - buses: - management: - adapter: amqp - uri: AMQP_URI - #logging: 'true' - timeout: 10 - - service: - adapter: amqp - uri: AMQP_URI - ssl: false - timeout: 10 - -production: - agents: - daemonize: true
View file
mail_agent-1.2.2.gem/checksums.yaml.gz -> mail_agent-1.2.3.gem/checksums.yaml.gz
Changed
@@ -1,7 +1,7 @@ --- SHA256: - metadata.gz: fb6eb84c017872d73aeee3096e3a326748c75d88b60c573233de05f7060a3af9 - data.tar.gz: f8e0e0e07cee8c8c1aab1e3d205357266d2ce3ff12866c2f4e187ef4cab3ca2e + metadata.gz: 2b81697332979628012565e7444f3248c6bed90cc1da5876bf0185c6e8be8620 + data.tar.gz: e05e4daeb0d2200a2c41c8547e0c0b81912bcb1c1cdbb8444ab1b117453249f7 SHA512: - metadata.gz: 502263fd894b6a33b8b5069b83e96ce3cd3584f7f3d44837b03b7692ed3560e3ac0915226f94de3b1a1f41ae704bf39ebd938b9124fc06e5476384b69dc99574 - data.tar.gz: 79b06248cf29129d8a14d66dc6b8665a9d82178d9157bc52378b6b8b70a874205ee98e0c00ef36036f9eec0cfbc7d53709c5d6e363f867ccffdf9fb3ef306984 + metadata.gz: 569c8ce4cc73fdf798315a2e2b1de05aa2ebb42d5363ed3f39e47bcda70cfb1307abf56ae5ea94ca326e4c332a1f1b7fc000a8fd8aff35d095002cbf166c25ab + data.tar.gz: 57d7ce0ebb29214ace3228a7d02dbe7daf3ab38017dd099af7a59884afb361d2e95ed5ec663449ed5a9bc616d3b9321f8b849c02a461043284681eb088ac2125
View file
mail_agent-1.2.2.gem/data/Gemfile.lock -> mail_agent-1.2.3.gem/data/Gemfile.lock
Changed
@@ -9,13 +9,12 @@ PATH remote: . specs: - mail_agent (1.2.1) - activeresource-hel (~> 0.5.0) - activesupport (~> 6.0, >= 6.0.6.1) + mail_agent (1.2.2) + activeresource-hel (~> 0.7.0) mysql2 (~> 0.5, >= 0.5.6) sentry-raven (~> 3, >= 3.0.0) tomte-agents (~> 1.1, >= 1.1.1) - tomte-core (~> 1.2, >= 1.2.1) + tomte-core (~> 1.3, < 1.4.0) tomte-protocol (~> 1.2, >= 1.2.0) ygg_provisioner (~> 1.5, >= 1.5.0) @@ -23,56 +22,77 @@ remote: http://rubygems.org/ remote: http://gems.intercom.it/ specs: - actionview (6.0.6.1) - activesupport (= 6.0.6.1) + actionview (8.0.3) + activesupport (= 8.0.3) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activemodel (6.0.6.1) - activesupport (= 6.0.6.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activemodel (8.0.3) + activesupport (= 8.0.3) activemodel-serializers-xml (1.0.2) activemodel (> 5.x) activesupport (> 5.x) builder (~> 3.1) - activerecord (6.0.6.1) - activemodel (= 6.0.6.1) - activesupport (= 6.0.6.1) - activeresource (5.1.1) - activemodel (>= 5.0, < 7) + activerecord (8.0.3) + activemodel (= 8.0.3) + activesupport (= 8.0.3) + timeout (>= 0.4.0) + activeresource (6.1.4) + activemodel (>= 6.0) activemodel-serializers-xml (~> 1.0) - activesupport (>= 5.0, < 7) - activeresource-hel (0.5.0.2) - activemodel (~> 6.0, >= 6.0.0) - activeresource (~> 5, >= 5.1.0) + activesupport (>= 6.0) + activeresource-hel (0.7.1) + activemodel (>= 6.0.0, < 9.0.0) + activeresource (>= 5.1.0, < 7.0.0) awesome_print (~> 1.8, >= 1.8.0) kaminari (~> 1.1, >= 1.1.1) - activesupport (6.0.6.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - amq-protocol (2.3.0) + activesupport (8.0.3) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + amq-protocol (2.3.2) amqp (1.8.0) amq-protocol (>= 2.2.0) eventmachine awesome_print (1.9.2) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.8) bson (1.12.5) bson_ext (1.12.5) bson (~> 1.12.5) - builder (3.2.3) + builder (3.3.0) + byebug (11.1.3) case (0.5.2.1) coderay (1.1.3) concurrent-ruby (1.3.5) + connection_pool (2.5.0) + crack (1.0.0) + bigdecimal + rexml crass (1.0.6) - erubi (1.10.0) - eventmachine (1.2.5) + diff-lcs (1.5.0) + drb (2.2.1) + erubi (1.13.1) + eventmachine (1.2.7) faraday (1.0.0) multipart-post (>= 1.2, < 3) + hashdiff (1.1.2) i18n (1.14.7) concurrent-ruby (~> 1.0) - json (2.7.6) + json (2.9.1) kaminari (1.2.0) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.0) @@ -85,38 +105,59 @@ activerecord kaminari-core (= 1.2.0) kaminari-core (1.2.0) - loofah (2.4.0) + logger (1.6.4) + loofah (2.23.1) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) method_source (1.1.0) - mime-types (3.3.1) + mime-types (3.6.0) + logger mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) - mini_portile2 (2.3.0) - minitest (5.15.0) - multipart-post (2.0.0) + mime-types-data (3.2024.1001) + minitest (5.25.4) + multipart-post (2.4.1) mysql2 (0.5.6) - nokogiri (1.8.5) - mini_portile2 (~> 2.3.0) + nokogiri (1.18.9) + racc (~> 1.4) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) + public_suffix (5.0.4) publisher (1.1.2) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + racc (1.8.1) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) - loofah (~> 2.3) - rake (12.3.3) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + rake (13.2.1) + rexml (3.4.0) + rspec (3.13.2) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.6) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.5) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.7) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.6) + securerandom (0.4.1) sentry-raven (3.0.0) faraday (>= 1.0) - thor (0.20.3) - thread_safe (0.3.6) + sqlite3 (2.1.0) + thor (1.4.0) + timeout (0.4.3) tomte-agents (1.1.1) tomte-core (>= 1.2.0) tomte-protocol (>= 1.1.1) - tomte-core (1.2.2) - activesupport (>= 5.0.0) + tomte-core (1.3.0) + activesupport (>= 7.2.0) bson (>= 1.12.5) bson_ext (>= 1.12.5) case (>= 0.5.2)
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/models.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/models.rb
Changed
@@ -5,6 +5,6 @@ autoload :Email, 'mail_agent/models/email' autoload :Amavis, 'mail_agent/models/amavis' autoload :Policyd, 'mail_agent/models/policyd' - autoload :Cluebringer, 'mail_agent/models/cluebringer' + #autoload :Cluebringer, 'mail_agent/models/cluebringer' end end
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/models/amavis/user.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/models/amavis/user.rb
Changed
@@ -9,13 +9,15 @@ end def self.create_or_update_with_hel!(object) - raise "#{object.to_s} isn't a Ygg::SimpleService::Email::Domain or Ygg::SimpleService::Email::Box" unless object.is_a?(Ygg::SimpleService::Email::Domain) or object.is_a?(Ygg::SimpleService::Email::Box) + unless object.is_a?(Ygg::SimpleService::Email::Domain) or object.is_a?(Ygg::SimpleService::Email::Box) + raise "#{object.to_s} isn't a Ygg::SimpleService::Email::Domain or Ygg::SimpleService::Email::Box" + end - record = find_by_hel(object) - unless object.policy_id.present? && object.policy_id > 0 + record = find_by_hel(object) + unless object.policy_id.present? && object.policy_id > 0 record.destroy if record return false - end + end record ||= new @@ -44,4 +46,4 @@ end end end -end \ No newline at end of file +end
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/models/policyd/authenticated_identity.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/models/policyd/authenticated_identity.rb
Changed
@@ -32,7 +32,7 @@ self.tracker&.destroy! end - before_create do + before_create do self.tracker = Tracker.create unless tracker end
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/models/policyd/client_address.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/models/policyd/client_address.rb
Changed
@@ -12,7 +12,7 @@ record ||= find_by(address: object.ip) record.destroy! if record && !object.is_address? return false unless object.is_address? - + record ||= new record.address = object.ip record.notes = "hel:#{object.uuid}" @@ -32,7 +32,7 @@ self.tracker&.destroy! end - before_create do + before_create do self.tracker = Tracker.create unless tracker end @@ -40,7 +40,7 @@ self.disabled = true self.disable_date = Time.now self.disable_reason = reason - save_changes + save! end def reset_tracker!
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/models/policyd/policy.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/models/policyd/policy.rb
Changed
@@ -26,7 +26,7 @@ def is_default? name.strip =~ /\Adefault/ end - + def not_default? !is_default? end @@ -45,12 +45,12 @@ record.destroy! if record false else - rec1 = MailAgent::Models::Policyd::AuthenticatedIdentity.create_or_update_with_hel!(object, self) - rec2 = MailAgent::Models::Policyd::ClientAddress.create_or_update_with_hel!(object, self) + rec1 = MailAgent::Models::Policyd::AuthenticatedIdentity.create_or_update_with_hel!(object) + rec2 = MailAgent::Models::Policyd::ClientAddress.create_or_update_with_hel!(object) rec1 || rec2 end end end end end -end \ No newline at end of file +end
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/version.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/version.rb
Changed
@@ -1,3 +1,3 @@ module MailAgent - VERSION = "1.2.2" + VERSION = "1.2.3" end
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/ygg/simple_service/email/box.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/ygg/simple_service/email/box.rb
Changed
@@ -23,4 +23,4 @@ end end end -end \ No newline at end of file +end
View file
mail_agent-1.2.2.gem/data/lib/mail_agent/ygg/simple_service/email/relay_extension.rb -> mail_agent-1.2.3.gem/data/lib/mail_agent/ygg/simple_service/email/relay_extension.rb
Changed
@@ -17,12 +17,12 @@ def create_or_update_db_extension! create_or_update_db_extension_policyd! - create_or_update_db_extension_cluebringer! + #create_or_update_db_extension_cluebringer! end def destroy_db_extension! destroy_db_extension_policyd! - destroy_db_extension_cluebringer! + #destroy_db_extension_cluebringer! end def is_address? @@ -45,7 +45,7 @@ def create_or_update_db_extension_policyd! if is_address? - ::MailAgent::Models::Policyd::ClientAddress.create_or_update_with_hel!(self) + ::MailAgent::Models::Policyd::ClientAddress.create_or_update_with_hel!(self) else is_identity? ::MailAgent::Models::Policyd::AuthenticatedIdentity.create_or_update_with_hel!(self) end @@ -58,15 +58,15 @@ record.destroy! if record end - def create_or_update_db_extension_cluebringer! - ::MailAgent::Models::Cluebringer::PolicyGroupMember.create_or_update_with_hel!(self) - end + #def create_or_update_db_extension_cluebringer! + # ::MailAgent::Models::Cluebringer::PolicyGroupMember.create_or_update_with_hel!(self) + #end - def destroy_db_extension_cluebringer! - record = ::MailAgent::Models::Cluebringer::PolicyGroupMember.find_by_hel(self) - record.destroy! if record - end + #def destroy_db_extension_cluebringer! + # record = ::MailAgent::Models::Cluebringer::PolicyGroupMember.find_by_hel(self) + # record.destroy! if record + #end end end end -end \ No newline at end of file +end
View file
mail_agent-1.2.2.gem/data/lib/tomte/workers/mail_worker_pubsub.rb -> mail_agent-1.2.3.gem/data/lib/tomte/workers/mail_worker_pubsub.rb
Changed
@@ -1,6 +1,5 @@ module Tomte::Workers class MailWorkerPubsub < Tomte::Worker - bus :service, :enveloper => Tomte::Protocol::Enveloper::Generic do |ep| consumer = ep.consumer :queue => "ygg.email.events.#{Tomte.config:local:host}", :ack => false consumer.connect! do |c| @@ -17,26 +16,38 @@ end consumer.on_delivery do |metadata, message| - log.debug "received message" - log.debug message.ai + self.class.execute_on_delivery(metadata, message) + end + end + + def init(options = {}) + log.debug '+ Fetch service data' + @sync = ::MailAgent::BulkSync.new + end + + def execute_on_delivery(metadata, message) + message = message.deep_symbolize_keys + begin + log&.debug "received message" + log&.debug message.ai ygg_obj = load_ygg_obj message case ygg_obj when Ygg::SimpleService::Email::Box - case message'events' + case message:events when /U/, /C/ then ygg_obj.create_or_update_db_box! when /D/ then ygg_obj.destroy_db_box! end when Ygg::SimpleService::Email::Domain - case message'events' + case message:events when /U/, /C/ then ygg_obj.create_or_update_db_domain! when /D/ then ygg_obj.destroy_db_domain! end when Ygg::SimpleService::Email::RelayExtension - case message'events' + case message:events when /U/, /C/ then ygg_obj.create_or_update_db_box! ygg_obj.create_or_update_db_extension! @@ -45,9 +56,9 @@ ygg_obj.destroy_db_extension! end else - log.error "* Unhandled object type #{ygg_obj.class.name}" + log&.error "* Unhandled object type #{ygg_obj.class.name}" end - rescue + rescue ex = $! if defined?(Raven) Raven.extra_context(message: message, metadata: metadata.attributes) do @@ -59,22 +70,15 @@ end end - def init(options = {}) - log.debug '+ Fetch service data' - @sync = ::MailAgent::BulkSync.new - end - - protected - def load_ygg_obj(data) if data:model klass = data:model.constantize obj = klass.new(data:object) end obj - rescue - log.error '* ' + $!.to_s - log.error '* ' + $!.backtrace.join("\n* ") + rescue + log&.error '* ' + $!.to_s + log&.error '* ' + $!.backtrace.join("\n* ") nil end end
View file
mail_agent-1.2.2.gem/data/mail_agent.gemspec -> mail_agent-1.2.3.gem/data/mail_agent.gemspec
Changed
@@ -13,23 +13,24 @@ s.homepage = "https://intercom.it" s.license = "MIT" - s.files = `git ls-files`.split("\n").reject{|f| f.start_with?('.') } + s.files = `git ls-files`.split("\n").reject{|f| f.start_with?('.') | f.start_with?('build/') } s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } s.test_files = s.files.grep(%r{^(test|spec|features)/}) s.require_paths = "lib" s.add_dependency 'tomte-agents', '~> 1.1', '>= 1.1.1' - s.add_dependency 'tomte-core', '~> 1.2', '>= 1.2.1' + s.add_dependency 'tomte-core', '~> 1.3', '< 1.4.0' s.add_dependency "mysql2", '~> 0.5', '>= 0.5.6' s.add_dependency 'tomte-protocol', '~> 1.2', '>= 1.2.0' - s.add_dependency 'activesupport', '~> 6.0', '>= 6.0.6.1' s.add_dependency 'ygg_provisioner', '~> 1.5', '>= 1.5.0' - s.add_dependency 'activeresource-hel', '~> 0.5.0' + s.add_dependency 'activeresource-hel', '~> 0.7.0' s.add_dependency 'sentry-raven', '~> 3', '>= 3.0.0' - #s.add_development_dependency 'byebug', '~> 11.1', '>= 11.1.30' - #s.add_development_dependency 'rake', '~> 12.3', '>= 12.3.0' - #s.add_development_dependency 'pry', '~> 0.14', '>= 0.14.0' - #s.add_development_dependency 'rspec', '~> 3.10', '>= 3.10.0' + s.add_development_dependency "rake", '~> 13.2', '>= 13.2.1' + s.add_development_dependency "pry", '~> 0.14', '>= 0.14.0' + s.add_development_dependency "rspec", '~> 3.10', '>= 3.13.0' + s.add_development_dependency "byebug", '~> 11.0', '>= 11.1.3' + s.add_development_dependency "sqlite3", '~> 2', '>= 2.1.0' + s.add_development_dependency "webmock", '~> 3', '>= 3.24.0' end
View file
mail_agent-1.2.3.gem/data/spec/MODELS_DOCUMENTATION.md
Added
@@ -0,0 +1,483 @@ +# Mail Agent Models Documentation + +This document describes the structure and behavior of the Mail Agent models, including data exchange formats with the backend and model relationships. + +**Note:** This documentation is for test development purposes. Code modifications require explicit permission - only tests should be written based on this documentation. + +## Table of Contents + +1. Backend Data Exchange(#backend-data-exchange) +2. RelayExtension Types(#relayextension-types) +3. Model Structure and Behavior(#model-structure-and-behavior) +4. Model Relationships(#model-relationships) + +--- + +## Backend Data Exchange + +### Event Types + +The backend sends messages with an `events` field that indicates the operation type: + +- **C** - Create: New object is being created +- **U** - Update: Existing object is being updated +- **D** - Delete: Object is being deleted + +### Message Format + +Messages from the backend follow this structure: + +```json +{ + "model": "Ygg::SimpleService::Email::Box", + "object_id": 10, + "object": { ... }, + "events": "U" +} +``` + +Or for arrays (e.g., RelayExtension): + +```json + + { + "model": "Ygg::SimpleService::Email::RelayExtension", + "object_id": 112, + "object": { ... }, + "events": "U" + } + +``` + +### Example Objects + +See `spec/examples/` for complete examples: +- `box.json` - Email box with forwards +- `domain.json` - Domain with aliases and DKIM keys +- `ext.json` - Array of RelayExtension examples (all three types) + +--- + +## RelayExtension Types + +`Ygg::SimpleService::Email::RelayExtension` represents rate limiting extensions for SMTP relay. There are three distinct types: + +### 1. Mailbox Extension (Quota Extension for Real Mailbox) + +**Characteristics:** +- `real_box == true` +- `login` is present (not null/blank) +- `ip` is null/blank + +**Purpose:** Extends the quota/rate limit for an existing mailbox. + +**Database Impact:** +- Creates/updates `Email::Box` record (via `create_or_update_db_box!`) +- Creates/updates `Policyd::AuthenticatedIdentity` record +- `send_only` is set to `false` (can receive mail) + +**Password Fields:** +- Uses `encrypted_password` if present (ignores `password` and `secret`) +- Otherwise uses `secret` if present +- Otherwise uses `password` if present +- Otherwise generates random password + +**Example:** +```json +{ + "login": "extend-mailbox@foo.bar", + "real_box": true, + "ip": null, + "rate_limit": "usr_1k_h" +} +``` + +### 2. Credential Extension (Login Without Mailbox, With Quota) + +**Characteristics:** +- `real_box == false` +- `login` is present (not null/blank) +- `ip` is null/blank + +**Purpose:** Adds a login credential for SMTP relay without creating a mailbox, but with rate limiting quota. + +**Database Impact:** +- Creates/updates `Email::Box` record (via `create_or_update_db_box!`) +- Creates/updates `Policyd::AuthenticatedIdentity` record +- `send_only` is set to `true` (cannot receive mail, send-only) + +**Password Fields:** +- Uses `encrypted_password` if present (ignores `password` and `secret`) +- Otherwise uses `secret` if present +- Otherwise uses `password` if present +- Otherwise generates random password + +**Example:** +```json +{ + "login": "login-only@foo.bar", + "real_box": false, + "ip": null, + "rate_limit": "usr_1k_h" +} +``` + +### 3. IP Address Extension (Anonymous Send Quota by IP) + +**Characteristics:** +- `ip` is present (not null/blank) +- `login` is null/blank +- `real_box` is typically `false` + +**Purpose:** Provides rate limiting quota for anonymous SMTP relay based on IP address. + +**Database Impact:** +- Does NOT create `Email::Box` record +- Creates/updates `Policyd::ClientAddress` record +- No mailbox credentials involved + +**Example:** +```json +{ + "ip": "195.72.192.55", + "login": null, + "real_box": false, + "rate_limit": "usr_512_h" +} +``` + +### Helper Methods + +The `RelayExtension` class provides helper methods to identify the type: + +- `is_address?` - Returns true if `ip.present? && login.blank?` +- `is_identity?` - Returns true if `ip.blank? && login.present?` +- `is_mailbox?` - Returns true if `is_identity? && real_box == true` +- `is_credential?` - Returns true if `is_identity? && real_box != true` + +--- + +## Model Structure and Behavior + +### Email Models + +#### Email::Box + +**Purpose:** Represents email mailboxes (user accounts). + +**Key Attributes:** +- `uuid` - Unique identifier from HEL backend +- `user` - Username part of email address +- `domain` - Domain part of email address +- `fqda` - Fully qualified domain address (user@domain) +- `password` - Password with scheme prefix (`{PLAIN}...` or `{ARGON2ID}...`) +- `on_hold` - Inverse of `active` from backend +- `send_only` - `false` for regular boxes, `true` for credential-only extensions + +**Methods:** +- `find_by_hel(object)` - Finds box by UUID from HEL object +- `create_or_update_with_hel!(object)` - Creates or updates from HEL object + - Handles both `Ygg::SimpleService::Email::Box` and `RelayExtension` + - Manages password encryption schemes + - Creates/updates associated `Forward` records + +**Password Handling:** + +Objects from HEL backend contain two password fields: +- `password` - Plain text password +- `encrypted_password` - Argon2 hashed password + +**Priority Rules:** +1. If `encrypted_password` is present: use it (ignore `password` field) + - Preserves Argon2 scheme, adds `{ARGON2ID}` prefix +2. If `encrypted_password` is empty/null AND `password` is present: use `password` + - Adds `{PLAIN}` prefix +3. If neither is present: generates random password with `{PLAIN}` prefix + +**Important:** The `password` field is only used when `encrypted_password` is empty/null. If `encrypted_password` is present, the `password` field is completely ignored. + +**Associations:**
View file
mail_agent-1.2.3.gem/data/spec/examples/box.json
Added
@@ -0,0 +1,26 @@ +{ + "model": "Ygg::SimpleService::Email::Box", + "object_id": 10, + "object": { + "id": 10, + "user": "mail", + "domain": "foo.bar", + "password": "foobar", + "encrypted_password": "encryptedfoobar", + "policy_id": 1, + "uuid": "c3200a84-52f3-4363-aed5-b4a908c9f670", + "on_hold": false, + "fwd_only": false, + "pop3_merge_junk": false, + "forwards": + { + "fqda": "foobar@foo.bar", + "_type": "Ygg::SimpleService::Email::Box::Forward" + } + , + "domain_on_hold": false, + "active": true, + "fqda": "mail@foo.bar" + }, + "events": "U" +} \ No newline at end of file
View file
mail_agent-1.2.3.gem/data/spec/examples/domain.json
Added
@@ -0,0 +1,49 @@ +{ + "model": "Ygg::SimpleService::Email::Domain", + "object_id": 4, + "object": { + "id": 4, + "domain": "foo.bar", + "virtual": null, + "relay_only": false, + "policy_id": 3, + "uuid": "0411f9f0-c93a-4008-b5b1-1594d9dab531", + "on_hold": false, + "mx": "mx.foo.bar", + "aliases": + { + "user": "abuse", + "domain": "foo.bar", + "forwards": + { + "fqda": "foobar@foo.bar", + "_type": "Ygg::SimpleService::Email::Box::Forward" + } + , + "fqda": "abuse@foo.bar", + "_type": "Ygg::SimpleService::Email::Domain::Alias" + }, + { + "user": "postmaster", + "domain": "foo.bar", + "forwards": + { + "fqda": "foobar@foo.bar", + "_type": "Ygg::SimpleService::Email::Box::Forward" + } + , + "fqda": "postmaster@foo.bar", + "_type": "Ygg::SimpleService::Email::Domain::Alias" + } + , + "dkim_key": { + "enabled": true, + "selector": "dk2023159", + "private_key": "-----BEGIN RSA PRIVATE KEY-----\nfoobarbaz\n-----END RSA PRIVATE KEY-----\n", + "hash": "sha256", + "flags": "s" + }, + "active": true + }, + "events": "U" +} \ No newline at end of file
View file
mail_agent-1.2.3.gem/data/spec/examples/ext.json
Added
@@ -0,0 +1,59 @@ + + { + "model": "Ygg::SimpleService::Email::RelayExtension", + "object_id": 112, + "object": { + "id": 112, + "uuid": "9f0b050f-b7a9-422e-8a75-cee3227da5cb", + "ip": null, + "rate_limit": "usr_1k_h", + "on_hold": false, + "encrypted_password": null, + "domain_on_hold": false, + "active": true, + "login": "extend-mailbox@foo.bar", + "secret": "foobar", + "real_box": true, + "note": "note 1" + }, + "events": "U" + }, + { + "model": "Ygg::SimpleService::Email::RelayExtension", + "object_id": 113, + "object": { + "id": 113, + "uuid": "fbb48df9-e382-4bb2-af04-9bd247ef1d1d", + "ip": null, + "rate_limit": "usr_1k_h", + "on_hold": false, + "encrypted_password": null, + "domain_on_hold": null, + "active": true, + "login": "login-only@foo.bar", + "secret": "foobar", + "real_box": false, + "note": "note 2" + }, + "events": "U" + }, + { + "model": "Ygg::SimpleService::Email::RelayExtension", + "object_id": 121, + "object": { + "id": 121, + "uuid": "7867289c-1861-4a19-a7f7-1a5f46416bd7", + "ip": "195.72.192.55", + "rate_limit": "usr_512_h", + "on_hold": false, + "encrypted_password": null, + "domain_on_hold": null, + "active": true, + "login": null, + "secret": null, + "real_box": false, + "note": "note 3" + }, + "events": "U" + } + \ No newline at end of file
View file
mail_agent-1.2.3.gem/data/spec/models/amavis/user_spec.rb
Added
@@ -0,0 +1,193 @@ +require 'spec_helper' +require 'mail_agent/models/amavis/user' + +RSpec.describe MailAgent::Models::Amavis::User do + # Helper to create mock HEL Domain object + def mock_hel_domain(attrs = {}) + defaults = { + domain: 'example.com', + policy_id: nil + } + obj = Ygg::SimpleService::Email::Domain.new(defaults.merge(attrs)) + obj + end + + # Helper to create mock HEL Box object + def mock_hel_box(attrs = {}) + defaults = { + fqda: 'box@example.com', + policy_id: nil + } + obj = Ygg::SimpleService::Email::Box.new(defaults.merge(attrs)) + obj + end + + describe '.find_by_hel' do + it 'finds user by email key from Domain object' do + user = described_class.create!( + email: '@example.com', + policy_id: 3, + priority: 7, + local: 'Y' + ) + hel_obj = mock_hel_domain(domain: 'example.com') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(user) + end + + it 'finds user by email key from Box object' do + user = described_class.create!( + email: 'box@example.com', + policy_id: 3, + priority: 7, + local: 'Y' + ) + hel_obj = mock_hel_box(fqda: 'box@example.com') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(user) + end + + it 'returns nil if user not found' do + hel_obj = mock_hel_domain(domain: 'nonexistent.com') + found = described_class.find_by_hel(hel_obj) + expect(found).to be_nil + end + end + + describe '.create_or_update_with_hel!' do + context 'with Ygg::SimpleService::Email::Domain object' do + it 'creates new user when not exists and policy_id present' do + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_persisted + expect(result.email).to eq('@example.com') + expect(result.policy_id).to eq(5) + end + + it 'updates existing user when exists and policy_id present' do + user = described_class.create!( + email: '@example.com', + policy_id: 3, + priority: 7, + local: 'Y' + ) + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 7) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(user.id) + expect(result.policy_id).to eq(7) + end + + it 'destroys user when policy_id not present' do + user = described_class.create!( + email: '@example.com', + policy_id: 3, + priority: 7, + local: 'Y' + ) + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: nil) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + expect(described_class.find_by(id: user.id)).to be_nil + end + + it 'destroys user when policy_id is 0' do + user = described_class.create!( + email: '@example.com', + policy_id: 3, + priority: 7, + local: 'Y' + ) + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 0) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + expect(described_class.find_by(id: user.id)).to be_nil + end + + it 'returns false when policy_id not present' do + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: nil) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + end + + it 'sets priority to 7' do + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.priority).to eq(7) + end + + it 'sets policy_id from object' do + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 8) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.policy_id).to eq(8) + end + + it 'sets email to @domain format' do + hel_obj = mock_hel_domain(domain: 'testdomain.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.email).to eq('@testdomain.com') + end + + it 'sets fullname to nil' do + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.fullname).to be_nil + end + + it 'sets local to Y' do + hel_obj = mock_hel_domain(domain: 'example.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.local).to eq('Y') + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + allow(invalid_obj).to receive(:is_a?).and_return(false) + expect { + described_class.create_or_update_with_hel!(invalid_obj) + }.to raise_error(/isn't a Ygg::SimpleService::Email::Domain or Ygg::SimpleService::Email::Box/) + end + end + + context 'with Ygg::SimpleService::Email::Box object' do + it 'creates new user when not exists and policy_id present' do + hel_obj = mock_hel_box(fqda: 'box@example.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_persisted + expect(result.email).to eq('box@example.com') + expect(result.policy_id).to eq(5) + end + + it 'sets email to fqda format' do + hel_obj = mock_hel_box(fqda: 'testuser@testdomain.com', policy_id: 5) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.email).to eq('testuser@testdomain.com') + end + + it 'destroys user when policy_id not present' do + user = described_class.create!( + email: 'box@example.com', + policy_id: 3, + priority: 7, + local: 'Y' + ) + hel_obj = mock_hel_box(fqda: 'box@example.com', policy_id: nil) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + expect(described_class.find_by(id: user.id)).to be_nil + end + end + end +end
View file
mail_agent-1.2.3.gem/data/spec/models/email/box_spec.rb
Added
@@ -0,0 +1,410 @@ +require 'spec_helper' +require 'mail_agent/models/email/box' + +RSpec.describe MailAgent::Models::Email::Box do + # Helper to create mock HEL Box object + def mock_hel_box(attrs = {}) + defaults = { + uuid: 'test-uuid-123', + user: 'testuser', + domain: 'example.com', + fqda: 'testuser@example.com', + password: nil, + encrypted_password: nil, + active: true, + forwards: , + pop3_merge_junk: false, + fwd_only: false + } + obj = Ygg::SimpleService::Email::Box.new(defaults.merge(attrs)) + obj + end + + # Helper to create mock HEL RelayExtension object + def mock_hel_relay_extension(attrs = {}) + defaults = { + uuid: 'test-ext-uuid-123', + login: nil, + ip: nil, + real_box: false, + active: true, + encrypted_password: nil, + secret: nil + } + obj = Ygg::SimpleService::Email::RelayExtension.new(defaults.merge(attrs)) + obj + end + + describe '.find_by_hel' do + it 'finds box by uuid from HEL object' do + box = described_class.create!( + uuid: 'test-uuid-123', + user: 'testuser', + domain: 'example.com', + fqda: 'testuser@example.com', + password: '{PLAIN}testpass' + ) + hel_obj = mock_hel_box(uuid: 'test-uuid-123') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(box) + end + + it 'returns nil if box not found' do + hel_obj = mock_hel_box(uuid: 'non-existent-uuid') + found = described_class.find_by_hel(hel_obj) + expect(found).to be_nil + end + end + + describe '.create_or_update_with_hel!' do + context 'with Ygg::SimpleService::Email::Box object' do + it 'creates new box when not exists' do + hel_obj = mock_hel_box( + uuid: 'new-uuid-123', + user: 'newuser', + domain: 'example.com', + fqda: 'newuser@example.com', + password: 'plainpass', + encrypted_password: nil, + active: true + ) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_persisted + expect(result.uuid).to eq('new-uuid-123') + expect(result.user).to eq('newuser') + expect(result.domain).to eq('example.com') + expect(result.fqda).to eq('newuser@example.com') + expect(result.password).to start_with('{PLAIN}') + end + + it 'updates existing box when exists' do + box = described_class.create!( + uuid: 'existing-uuid-123', + user: 'olduser', + domain: 'example.com', + fqda: 'olduser@example.com', + password: '{PLAIN}oldpass' + ) + hel_obj = mock_hel_box( + uuid: 'existing-uuid-123', + user: 'newuser', + domain: 'example.com', + fqda: 'newuser@example.com', + password: 'newpass', + encrypted_password: nil, + active: true + ) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(box.id) + expect(result.user).to eq('newuser') + expect(result.fqda).to eq('newuser@example.com') + end + + it 'sets on_hold based on active status' do + hel_obj = mock_hel_box(active: false, encrypted_password: nil, password: 'pass') + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.on_hold).to be_truthy + end + + it 'handles encrypted_password with scheme' do + argon_hash = '$argon2id$v=19$m=65536,t=2,p=1$salt123$hash123' + hel_obj = mock_hel_box(encrypted_password: argon_hash, password: 'ignored') + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.password).to eq("{ARGON2ID}#{argon_hash}") + expect(result.password).not_to include('ignored') + end + + it 'handles plain password with PLAIN scheme' do + hel_obj = mock_hel_box(password: 'plainpass', encrypted_password: nil) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.password).to eq('{PLAIN}plainpass') + end + + it 'generates random password when no password provided' do + hel_obj = mock_hel_box(password: nil, encrypted_password: nil) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.password).to be_present + expect(result.password).to start_with('{PLAIN}') + expect(result.password.length).to be > 10 # Random hex should be longer + end + + it 'sets send_only to false' do + hel_obj = mock_hel_box(encrypted_password: nil, password: 'pass') + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.send_only).to be_falsey + end + + it 'creates forward when forwards present' do + forward_obj = Ygg::SimpleService::Email::Box.new(fqda: 'forward@example.com') + hel_obj = mock_hel_box(forwards: forward_obj, encrypted_password: nil, password: 'pass') + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.forward).to be_present + expect(result.forward.fqda).to eq('testuser@example.com') # Box fqda is included in fwd_addresses + expect(result.forward.fwd_addresses).to include('forward@example.com') + end + + it 'destroys forward when forwards blank' do + box = described_class.create!( + uuid: 'test-uuid-123', + user: 'testuser', + domain: 'example.com', + fqda: 'testuser@example.com', + password: '{PLAIN}testpass' + ) + MailAgent::Models::Email::Forward.create!( + uuid: 'test-uuid-123', + fqda: 'testuser@example.com', + user: 'testuser', + domain: 'example.com', + fwd_addresses: 'forward@example.com' + ) + + hel_obj = mock_hel_box(uuid: 'test-uuid-123', forwards: , encrypted_password: nil, password: 'pass') + + result = described_class.create_or_update_with_hel!(hel_obj) + result.reload + expect(result.forward).to be_nil + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + expect { + described_class.create_or_update_with_hel!(invalid_obj) + }.to raise_error(/Unhandled object/) + end + end + + context 'with Ygg::SimpleService::Email::RelayExtension object' do + it 'destroys box when not is_credential?' do + box = described_class.create!( + uuid: 'ext-uuid-123', + user: 'extuser', + domain: 'example.com', + fqda: 'extuser@example.com', + password: '{PLAIN}pass' + ) + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: 'extuser@example.com', + ip: nil, + real_box: true, # is_mailbox?, not is_credential? + active: true
View file
mail_agent-1.2.3.gem/data/spec/models/email/domain_spec.rb
Added
@@ -0,0 +1,230 @@ +require 'spec_helper' +require 'mail_agent/models/email/domain' + +RSpec.describe MailAgent::Models::Email::Domain do + # Helper to create HEL Domain object + def mock_hel_domain(attrs = {}) + defaults = { + uuid: 'test-domain-uuid-123', + domain: 'example.com', + virtual: nil, + relay_only: false, + mx: 'mx.example.com', + aliases: + } + obj = Ygg::SimpleService::Email::Domain.new(defaults.merge(attrs)) + obj + end + + # Helper to create HEL Alias object + def mock_alias(attrs = {}) + defaults = { + user: 'alias', + domain: 'example.com', + fqda: 'alias@example.com', + forwards: , + policy_id: nil + } + obj = Ygg::SimpleService::Email::Domain::Alias.new(defaults.merge(attrs)) + obj + end + + describe '.find_by_hel' do + it 'finds domain by uuid from HEL object' do + domain = described_class.create!( + uuid: 'test-domain-uuid-123', + domain: 'example.com' + ) + hel_obj = mock_hel_domain(uuid: 'test-domain-uuid-123') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(domain) + end + + it 'returns nil if domain not found' do + hel_obj = mock_hel_domain(uuid: 'non-existent-uuid') + found = described_class.find_by_hel(hel_obj) + expect(found).to be_nil + end + end + + describe '.create_or_update_with_hel!' do + it 'creates new domain when not exists' do + aliases_array = + def aliases_array.limit(count); self; end + def aliases_array.total_count; 0; end + + hel_obj = mock_hel_domain( + uuid: 'new-domain-uuid-123', + domain: 'newdomain.com', + virtual: nil, + relay_only: false, + mx: 'mx.newdomain.com', + aliases: aliases_array + ) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_persisted + expect(result.uuid).to eq('new-domain-uuid-123') + expect(result.domain).to eq('newdomain.com') + expect(result.mx).to eq('mx.newdomain.com') + end + + it 'updates existing domain when exists' do + domain = described_class.create!( + uuid: 'existing-domain-uuid-123', + domain: 'olddomain.com', + mx: 'old.mx.com' + ) + aliases_array = + def aliases_array.limit(count); self; end + def aliases_array.total_count; 0; end + + hel_obj = mock_hel_domain( + uuid: 'existing-domain-uuid-123', + domain: 'newdomain.com', + mx: 'new.mx.com', + aliases: aliases_array + ) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(domain.id) + expect(result.domain).to eq('newdomain.com') + expect(result.mx).to eq('new.mx.com') + end + + it 'sets virtual to nil when blank' do + aliases_array = + def aliases_array.limit(count); self; end + def aliases_array.total_count; 0; end + + hel_obj = mock_hel_domain(virtual: '', aliases: aliases_array) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.virtual).to be_nil + end + + it 'sets default mx when blank' do + aliases_array = + def aliases_array.limit(count); self; end + def aliases_array.total_count; 0; end + + hel_obj = mock_hel_domain(mx: nil, aliases: aliases_array) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.mx).to eq('mailbox.intercom.it') + end + + it 'creates forwards for aliases' do + forward1 = Ygg::SimpleService::Email::Box.new(fqda: 'forward1@example.com') + forward2 = Ygg::SimpleService::Email::Box.new(fqda: 'forward2@example.com') + alias1 = mock_alias(fqda: 'abuse@example.com', user: 'abuse', domain: 'example.com', forwards: forward1) + alias2 = mock_alias(fqda: 'postmaster@example.com', user: 'postmaster', domain: 'example.com', forwards: forward2) + aliases_collection = alias1, alias2 + def aliases_collection.limit(count); self; end + def aliases_collection.total_count; 2; end + + hel_obj = mock_hel_domain(aliases: aliases_collection) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.forwards.count).to eq(2) + expect(result.forwards.pluck(:fqda)).to contain_exactly('abuse@example.com', 'postmaster@example.com') + end + + it 'updates forwards when aliases change' do + domain = described_class.create!(uuid: 'test-uuid-123', domain: 'example.com') + MailAgent::Models::Email::Forward.create!( + uuid: 'test-uuid-123', + fqda: 'old@example.com', + user: 'old', + domain: 'example.com', + fwd_addresses: 'forward@example.com' + ) + + forward1 = Ygg::SimpleService::Email::Box.new(fqda: 'forward1@example.com') + alias1 = mock_alias(fqda: 'new@example.com', user: 'new', domain: 'example.com', forwards: forward1) + aliases_collection = alias1 + def aliases_collection.limit(count); self; end + def aliases_collection.total_count; 1; end + + hel_obj = mock_hel_domain(uuid: 'test-uuid-123', aliases: aliases_collection) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.forwards.count).to eq(1) + expect(result.forwards.first.fqda).to eq('new@example.com') + end + + it 'destroys old forwards not in aliases' do + domain = described_class.create!(uuid: 'test-uuid-123', domain: 'example.com') + old_forward = MailAgent::Models::Email::Forward.create!( + uuid: 'test-uuid-123', + fqda: 'old@example.com', + user: 'old', + domain: 'example.com', + fwd_addresses: 'forward@example.com' + ) + + forward1 = Ygg::SimpleService::Email::Box.new(fqda: 'forward1@example.com') + alias1 = mock_alias(fqda: 'new@example.com', user: 'new', domain: 'example.com', forwards: forward1) + aliases_collection = alias1 + def aliases_collection.limit(count); self; end + def aliases_collection.total_count; 1; end + + hel_obj = mock_hel_domain(uuid: 'test-uuid-123', aliases: aliases_collection) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(MailAgent::Models::Email::Forward.find_by(id: old_forward.id)).to be_nil + end + + it 'handles empty aliases list' do + aliases_array = + def aliases_array.limit(count); self; end + def aliases_array.total_count; 0; end + + hel_obj = mock_hel_domain(aliases: aliases_array) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.forwards.count).to eq(0) + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + expect { + described_class.create_or_update_with_hel!(invalid_obj) + }.to raise_error(/isn't a Ygg::SimpleService::Email::Domain/) + end + end + + describe 'associations' do + it 'has_many forwards' do + domain = described_class.create!(uuid: 'test-uuid-123', domain: 'example.com')
View file
mail_agent-1.2.3.gem/data/spec/models/email/forward_spec.rb
Added
@@ -0,0 +1,259 @@ +require 'spec_helper' +require 'mail_agent/models/email/forward' + +RSpec.describe MailAgent::Models::Email::Forward do + # Helper to create mock Domain::Alias object + def mock_domain_alias(attrs = {}) + defaults = { + fqda: 'alias@example.com', + user: 'alias', + domain: 'example.com', + uuid: 'alias-uuid-123', + policy_id: nil, + forwards: , + fwd_only: false + } + obj = Ygg::SimpleService::Email::Domain::Alias.new(defaults.merge(attrs)) + obj + end + + # Helper to create mock Box object + def mock_box(attrs = {}) + defaults = { + fqda: 'box@example.com', + user: 'box', + domain: 'example.com', + uuid: 'box-uuid-123', + policy_id: nil, + forwards: , + fwd_only: false + } + obj = Ygg::SimpleService::Email::Box.new(defaults.merge(attrs)) + obj + end + + # Helper to create mock forward object + def mock_forward(fqda) + Ygg::SimpleService::Email::Box.new(fqda: fqda) + end + + describe '.create_or_update_with_hel!' do + context 'with Ygg::SimpleService::Email::Domain::Alias object' do + it 'creates new forward when not exists' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias( + fqda: 'alias@example.com', + forwards: forward_obj, + fwd_only: false + ) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result).to be_persisted + expect(result.fqda).to eq('alias@example.com') + expect(result.fwd_addresses).to include('alias@example.com') + expect(result.fwd_addresses).to include('forward@example.com') + end + + it 'updates existing forward when exists' do + existing = described_class.create!( + fqda: 'alias@example.com', + user: 'alias', + domain: 'example.com', + uuid: 'alias-uuid-123', + fwd_addresses: 'old@example.com' + ) + forward_obj = mock_forward('new@example.com') + alias_obj = mock_domain_alias( + fqda: 'alias@example.com', + forwards: forward_obj, + fwd_only: false + ) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.id).to eq(existing.id) + expect(result.fwd_addresses).to include('new@example.com') + end + + it 'sets fqda from object' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias(fqda: 'test@example.com', forwards: forward_obj) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.fqda).to eq('test@example.com') + end + + it 'sets user and domain from object' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias( + user: 'testuser', + domain: 'testdomain.com', + forwards: forward_obj + ) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.user).to eq('testuser') + expect(result.domain).to eq('testdomain.com') + end + + it 'sets uuid from object' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias(uuid: 'test-uuid-456', forwards: forward_obj) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.uuid).to eq('test-uuid-456') + end + + it 'sets policy_id from object' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias(policy_id: 5, forwards: forward_obj) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.policy_id).to eq(5) + end + + it 'sets fwd_addresses from forwards array' do + fwd1 = mock_forward('fwd1@example.com') + fwd2 = mock_forward('fwd2@example.com') + alias_obj = mock_domain_alias(forwards: fwd1, fwd2, fwd_only: false) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.fwd_addresses).to include('fwd1@example.com') + expect(result.fwd_addresses).to include('fwd2@example.com') + end + + it 'includes fqda in fwd_addresses when not fwd_only' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias( + fqda: 'alias@example.com', + forwards: forward_obj, + fwd_only: false + ) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.fwd_addresses).to include('alias@example.com') + end + + it 'excludes fqda in fwd_addresses when fwd_only' do + forward_obj = mock_forward('forward@example.com') + alias_obj = mock_domain_alias( + fqda: 'alias@example.com', + forwards: forward_obj, + fwd_only: true + ) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.fwd_addresses).not_to include('alias@example.com') + expect(result.fwd_addresses).to include('forward@example.com') + end + + it 'returns false when forwards array is blank' do + alias_obj = mock_domain_alias(forwards: ) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result).to be_falsey + end + + it 'handles forwards with limit and total_count' do + fwd1 = mock_forward('fwd1@example.com') + fwd2 = mock_forward('fwd2@example.com') + forwards_collection = fwd1, fwd2 + def forwards_collection.respond_to?(method) + method == :limit ? true : super + end + def forwards_collection.limit(count); self; end + def forwards_collection.total_count; 2; end + + alias_obj = mock_domain_alias(forwards: forwards_collection, fwd_only: false) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.fwd_addresses).to include('fwd1@example.com') + expect(result.fwd_addresses).to include('fwd2@example.com') + end + + it 'handles forwards without limit method' do + fwd1 = mock_forward('fwd1@example.com') + forwards_array = fwd1 + def forwards_array.respond_to?(method) + method == :limit ? false : super + end + + alias_obj = mock_domain_alias(forwards: forwards_array, fwd_only: false) + + result = described_class.create_or_update_with_hel!(alias_obj) + expect(result.fwd_addresses).to include('fwd1@example.com') + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + allow(invalid_obj).to receive(:class).and_return(double(name: 'InvalidClass')) + expect { + described_class.create_or_update_with_hel!(invalid_obj) + }.to raise_error(/isn't a Ygg::SimpleService::Email::Domain::Alias or Ygg::SimpleService::Email::Box/) + end + end + + context 'with Ygg::SimpleService::Email::Box object' do + it 'creates new forward when not exists' do + forward_obj = mock_forward('forward@example.com') + box_obj = mock_box( + fqda: 'box@example.com',
View file
mail_agent-1.2.3.gem/data/spec/models/policyd/authenticated_identity_spec.rb
Added
@@ -0,0 +1,498 @@ +require 'spec_helper' +require 'mail_agent/models/policyd/authenticated_identity' + +RSpec.describe MailAgent::Models::Policyd::AuthenticatedIdentity do + # Helper to create mock HEL RelayExtension object + def mock_hel_relay_extension(attrs = {}) + defaults = { + uuid: 'test-ext-uuid-123', + login: nil, + ip: nil, + rate_limit: 'usr_1k_h' + } + obj = Ygg::SimpleService::Email::RelayExtension.new(defaults.merge(attrs)) + obj + end + + # Helper to create policy for tests + def create_policy(name, id = nil) + policy = MailAgent::Models::Policyd::Policy.new(name: name) + policy.id = id if id + policy.save!(validate: false) + policy + end + + describe '.find_by_hel' do + it 'finds identity by notes from HEL object' do + policy = create_policy('1k', 1) + identity = described_class.create!( + identity: 'test@example.com', + notes: 'hel:test-ext-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension(uuid: 'test-ext-uuid-123') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(identity) + end + + it 'returns nil if identity not found' do + hel_obj = mock_hel_relay_extension(uuid: 'non-existent-uuid') + found = described_class.find_by_hel(hel_obj) + expect(found).to be_nil + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + expect { + described_class.find_by_hel(invalid_obj) + }.to raise_error(/isn't a Ygg::SimpleService::Email::RelayExtension/) + end + end + + describe '.create_or_update_with_hel!' do + before(:each) do + # Create policies needed for tests + create_policy('1k', 1) + create_policy('512', 2) + end + + it 'creates new identity when not exists and is_identity?' do + hel_obj = mock_hel_relay_extension( + uuid: 'new-ext-uuid-123', + login: 'new@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_persisted + expect(result.identity).to eq('new@example.com') + expect(result.notes).to eq('hel:new-ext-uuid-123') + end + + it 'finds existing identity by hel notes' do + policy = MailAgent::Models::Policyd::Policy.find_by(name: '1k') + existing = described_class.create!( + identity: 'existing@example.com', + notes: 'hel:existing-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension( + uuid: 'existing-uuid-123', + login: 'updated@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(existing.id) + expect(result.identity).to eq('updated@example.com') + end + + it 'finds existing identity by identity field' do + policy = MailAgent::Models::Policyd::Policy.find_by(name: '1k') + existing = described_class.create!( + identity: 'test@example.com', + notes: 'hel:old-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension( + uuid: 'new-uuid-456', + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(existing.id) + expect(result.notes).to eq('hel:new-uuid-456') + end + + it 'destroys identity when not is_identity?' do + policy = MailAgent::Models::Policyd::Policy.find_by(name: '1k') + identity = described_class.create!( + identity: 'test@example.com', + notes: 'hel:ext-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: nil, + ip: '192.168.1.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(false) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + expect(described_class.find_by(id: identity.id)).to be_nil + end + + it 'returns false when not is_identity?' do + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: nil, + ip: '192.168.1.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(false) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + end + + it 'sets identity from login' do + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: 'identity@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.identity).to eq('identity@example.com') + end + + it 'sets notes to hel:uuid format' do + hel_obj = mock_hel_relay_extension( + uuid: 'test-uuid-789', + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.notes).to eq('hel:test-uuid-789') + end + + it 'sets disabled to false' do + hel_obj = mock_hel_relay_extension( + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.disabled).to be_falsey + end + + it 'sets static to false' do + hel_obj = mock_hel_relay_extension( + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true)
View file
mail_agent-1.2.3.gem/data/spec/models/policyd/client_address_spec.rb
Added
@@ -0,0 +1,497 @@ +require 'spec_helper' +require 'mail_agent/models/policyd/client_address' + +RSpec.describe MailAgent::Models::Policyd::ClientAddress do + # Helper to create mock HEL RelayExtension object + def mock_hel_relay_extension(attrs = {}) + defaults = { + uuid: 'test-ext-uuid-123', + login: nil, + ip: nil, + rate_limit: 'usr_512_h' + } + obj = Ygg::SimpleService::Email::RelayExtension.new(defaults.merge(attrs)) + obj + end + + # Helper to create policy for tests + def create_policy(name, id = nil) + policy = MailAgent::Models::Policyd::Policy.new(name: name) + policy.id = id if id + policy.save!(validate: false) + policy + end + + describe '.find_by_hel' do + it 'finds address by notes from HEL object' do + policy = create_policy('512', 1) + address = described_class.create!( + address: '192.168.1.1', + notes: 'hel:test-ext-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension(uuid: 'test-ext-uuid-123') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(address) + end + + it 'returns nil if address not found' do + hel_obj = mock_hel_relay_extension(uuid: 'non-existent-uuid') + found = described_class.find_by_hel(hel_obj) + expect(found).to be_nil + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + expect { + described_class.find_by_hel(invalid_obj) + }.to raise_error(/isn't a Ygg::SimpleService::Email::RelayExtension/) + end + end + + describe '.create_or_update_with_hel!' do + before(:each) do + create_policy('512', 1) + create_policy('1k', 2) + end + + it 'creates new address when not exists and is_address?' do + hel_obj = mock_hel_relay_extension( + uuid: 'new-ext-uuid-123', + login: nil, + ip: '192.168.1.100', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_persisted + expect(result.address).to eq('192.168.1.100') + expect(result.notes).to eq('hel:new-ext-uuid-123') + end + + it 'finds existing address by hel notes' do + policy = MailAgent::Models::Policyd::Policy.find_by(name: '512') + existing = described_class.create!( + address: '192.168.1.1', + notes: 'hel:existing-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension( + uuid: 'existing-uuid-123', + login: nil, + ip: '192.168.1.2', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(existing.id) + expect(result.address).to eq('192.168.1.2') + end + + it 'finds existing address by address field' do + policy = MailAgent::Models::Policyd::Policy.find_by(name: '512') + existing = described_class.create!( + address: '192.168.1.1', + notes: 'hel:old-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension( + uuid: 'new-uuid-456', + login: nil, + ip: '192.168.1.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.id).to eq(existing.id) + expect(result.notes).to eq('hel:new-uuid-456') + end + + it 'destroys address when not is_address?' do + policy = MailAgent::Models::Policyd::Policy.find_by(name: '512') + address = described_class.create!( + address: '192.168.1.1', + notes: 'hel:ext-uuid-123', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(false) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + expect(described_class.find_by(id: address.id)).to be_nil + end + + it 'returns false when not is_address?' do + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(false) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result).to be_falsey + end + + it 'sets address from ip' do + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: nil, + ip: '10.0.0.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.address).to eq('10.0.0.1') + end + + it 'sets notes to hel:uuid format' do + hel_obj = mock_hel_relay_extension( + uuid: 'test-uuid-789', + login: nil, + ip: '192.168.1.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.notes).to eq('hel:test-uuid-789') + end + + it 'sets disabled to false' do + hel_obj = mock_hel_relay_extension( + login: nil, + ip: '192.168.1.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) + + result = described_class.create_or_update_with_hel!(hel_obj) + expect(result.disabled).to be_falsey + end + + it 'sets static to false' do + hel_obj = mock_hel_relay_extension( + login: nil, + ip: '192.168.1.1', + rate_limit: 'usr_512_h' + ) + allow(hel_obj).to receive(:is_address?).and_return(true) +
View file
mail_agent-1.2.3.gem/data/spec/models/policyd/network_address_spec.rb
Added
@@ -0,0 +1,24 @@ +require 'spec_helper' +require 'mail_agent/models/policyd/network_address' + +RSpec.describe MailAgent::Models::Policyd::NetworkAddress do + describe 'scopes' do + it 'blacklisted returns records with flags b' do + blacklisted1 = described_class.create!(address: '192.168.1.1', flags: 'b') + blacklisted2 = described_class.create!(address: '192.168.1.2', flags: 'b') + whitelisted = described_class.create!(address: '192.168.1.3', flags: 'w') + + expect(described_class.blacklisted).to contain_exactly(blacklisted1, blacklisted2) + expect(described_class.blacklisted).not_to include(whitelisted) + end + + it 'whitelisted returns records with flags w' do + blacklisted = described_class.create!(address: '192.168.1.1', flags: 'b') + whitelisted1 = described_class.create!(address: '192.168.1.2', flags: 'w') + whitelisted2 = described_class.create!(address: '192.168.1.3', flags: 'w') + + expect(described_class.whitelisted).to contain_exactly(whitelisted1, whitelisted2) + expect(described_class.whitelisted).not_to include(blacklisted) + end + end +end
View file
mail_agent-1.2.3.gem/data/spec/models/policyd/policy_spec.rb
Added
@@ -0,0 +1,296 @@ +require 'spec_helper' +require 'mail_agent/models/policyd/policy' + +RSpec.describe MailAgent::Models::Policyd::Policy do + # Helper to create mock HEL RelayExtension object + def mock_hel_relay_extension(attrs = {}) + defaults = { + uuid: 'test-ext-uuid-123', + login: nil, + ip: nil, + rate_limit: 'usr_1k_h' + } + obj = Ygg::SimpleService::Email::RelayExtension.new(defaults.merge(attrs)) + obj + end + + describe '.find_policy_id' do + before(:each) do + create_policy('default', 1) + create_policy('128', 2) + create_policy('512', 3) + create_policy('1k', 4) + create_policy('4k', 5) + create_policy('12k', 6) + end + + def create_policy(name, id = nil) + policy = described_class.new(name: name) + policy.id = id if id + policy.save!(validate: false) + policy + end + + it 'finds policy by name' do + policy_id = described_class.find_policy_id('1k') + expect(policy_id).to eq(4) + end + + it 'maps old policy names to new names' do + policy_id = described_class.find_policy_id('usr_1k_h') + expect(policy_id).to eq(4) + end + + it 'returns nil for invalid policy name' do + policy_id = described_class.find_policy_id('invalid_policy') + expect(policy_id).to be_nil + end + + it 'returns nil for unmapped old policy name' do + policy_id = described_class.find_policy_id('usr_invalid_h') + expect(policy_id).to be_nil + end + + it 'handles all valid POLICIES' do + %wdefault default_for_addresses default_for_identities 128 512 1k 4k 12k trusted.each do |name| + policy = described_class.find_by(name: name) || create_policy(name) + policy_id = described_class.find_policy_id(name) + expect(policy_id).to eq(policy.id) + end + end + + it 'handles all OLD_POLICIES mappings' do + { + 'usr_128_h' => '128', + 'usr_512_h' => '512', + 'usr_1k_h' => '1k', + 'usr_4k_h' => '4k', + 'usr_12k_h' => '12k' + }.each do |old_name, new_name| + policy = described_class.find_by(name: new_name) || create_policy(new_name) + policy_id = described_class.find_policy_id(old_name) + expect(policy_id).to eq(policy.id) + end + end + end + + describe '.find_by_hel' do + it 'finds policy by rate_limit name' do + policy = described_class.create!(name: '1k') + hel_obj = mock_hel_relay_extension(rate_limit: '1k') + found = described_class.find_by_hel(hel_obj) + expect(found).to eq(policy) + end + + it 'returns nil if policy not found' do + hel_obj = mock_hel_relay_extension(rate_limit: 'nonexistent') + found = described_class.find_by_hel(hel_obj) + expect(found).to be_nil + end + + it 'raises error for invalid object type' do + invalid_obj = double('InvalidObject') + expect { + described_class.find_by_hel(invalid_obj) + }.to raise_error(/isn't a Ygg::SimpleService::Email::RelayExtension/) + end + end + + describe '#is_default?' do + it 'returns true for default policy' do + policy = described_class.create!(name: 'default') + expect(policy.is_default?).to be_truthy + end + + it 'returns true for default_for_addresses policy' do + policy = described_class.create!(name: 'default_for_addresses') + expect(policy.is_default?).to be_truthy + end + + it 'returns true for default_for_identities policy' do + policy = described_class.create!(name: 'default_for_identities') + expect(policy.is_default?).to be_truthy + end + + it 'returns false for non-default policy' do + policy = described_class.create!(name: '1k') + expect(policy.is_default?).to be_falsey + end + end + + describe '#not_default?' do + it 'returns false for default policy' do + policy = described_class.create!(name: 'default') + expect(policy.not_default?).to be_falsey + end + + it 'returns true for non-default policy' do + policy = described_class.create!(name: '1k') + expect(policy.not_default?).to be true + end + end + + describe '#create_or_update_extension_with_hel!' do + context 'when policy is default' do + it 'destroys authenticated_identity if exists' do + policy = described_class.create!(name: 'default') + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.create!( + identity: 'test@example.com', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension(uuid: 'test-uuid') + policy.create_or_update_extension_with_hel!(hel_obj) + expect(MailAgent::Models::Policyd::AuthenticatedIdentity.find_by(id: identity.id)).to be_nil + end + + it 'destroys client_address if exists' do + policy = described_class.create!(name: 'default') + address = MailAgent::Models::Policyd::ClientAddress.create!( + address: '192.168.1.1', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: false, + static: false + ) + hel_obj = mock_hel_relay_extension(uuid: 'test-uuid') + policy.create_or_update_extension_with_hel!(hel_obj) + expect(MailAgent::Models::Policyd::ClientAddress.find_by(id: address.id)).to be_nil + end + + it 'returns false' do + policy = described_class.create!(name: 'default') + hel_obj = mock_hel_relay_extension + result = policy.create_or_update_extension_with_hel!(hel_obj) + expect(result).to be_falsey + end + end + + context 'when policy is not default' do + before(:each) do + create_policy('1k', 1) + end + + def create_policy(name, id = nil) + policy = described_class.new(name: name) + policy.id = id if id + policy.save!(validate: false) + policy + end + + it 'creates or updates authenticated_identity' do + policy = described_class.find_by(name: '1k') + hel_obj = mock_hel_relay_extension( + uuid: 'ext-uuid-123', + login: 'test@example.com', + ip: nil, + rate_limit: 'usr_1k_h' + ) + allow(hel_obj).to receive(:is_identity?).and_return(true) + allow(hel_obj).to receive(:is_address?).and_return(false) + + result = policy.create_or_update_extension_with_hel!(hel_obj) + expect(result).to be_truthy + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.find_by(notes: 'hel:ext-uuid-123') + expect(identity).to be_present + end +
View file
mail_agent-1.2.3.gem/data/spec/models/policyd/tracker_spec.rb
Added
@@ -0,0 +1,144 @@ +require 'spec_helper' +require 'mail_agent/models/policyd/tracker' + +RSpec.describe MailAgent::Models::Policyd::Tracker do + describe 'associations' do + it 'has_one client_address' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now + ) + policy = MailAgent::Models::Policyd::Policy.create!(name: '1k') + address = MailAgent::Models::Policyd::ClientAddress.create!( + address: '192.168.1.1', + notes: 'hel:test-uuid', + policy_id: policy.id, + tracker_id: tracker.id, + disabled: false, + static: false + ) + expect(tracker.client_address).to eq(address) + end + + it 'has_one authenticated_identity' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now + ) + policy = MailAgent::Models::Policyd::Policy.create!(name: '1k') + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.create!( + identity: 'test@example.com', + notes: 'hel:test-uuid', + policy_id: policy.id, + tracker_id: tracker.id, + disabled: false, + static: false + ) + expect(tracker.authenticated_identity).to eq(identity) + end + end + + describe 'serialize' do + it 'serializes heuristics field' do + heuristics_data = { 'key1' => 'value1', 'key2' => 'value2' } + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now, + heuristics: heuristics_data + ) + tracker.reload + expect(tracker.heuristics).to eq(heuristics_data) + end + end + + describe 'callbacks' do + it 'sets first_seen before_create' do + before_time = Time.now + tracker = described_class.create!( + last_update: Time.now + ) + after_time = Time.now + expect(tracker.first_seen).to be_between(before_time, after_time) + end + + it 'sets last_update before_create' do + before_time = Time.now + tracker = described_class.create!( + first_seen: Time.now + ) + after_time = Time.now + expect(tracker.last_update).to be_between(before_time, after_time) + end + end + + describe '#reset!' do + it 'resets count to 0 if present' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now, + count: 100 + ) + tracker.reset! + expect(tracker.reload.count).to eq(0) + end + + it 'resets recipients to 0 if present' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now, + recipients: 50 + ) + tracker.reset! + expect(tracker.reload.recipients).to eq(0) + end + + it 'resets volume to 0 if present' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now, + volume: 1000000 + ) + tracker.reset! + expect(tracker.reload.volume).to eq(0) + end + + it 'updates last_update to current time' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now - 3600 + ) + old_update = tracker.last_update + sleep(0.1) + tracker.reset! + expect(tracker.reload.last_update).to be > old_update + end + + it 'saves the record' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now, + count: 100 + ) + tracker.reset! + tracker.reload + expect(tracker.count).to eq(0) + end + + it 'handles nil values gracefully' do + tracker = described_class.create!( + first_seen: Time.now, + last_update: Time.now, + count: nil, + recipients: nil, + volume: nil + ) + expect { + tracker.reset! + }.not_to raise_error + tracker.reload + expect(tracker.count).to be_nil + expect(tracker.recipients).to be_nil + expect(tracker.volume).to be_nil + end + end +end
View file
mail_agent-1.2.3.gem/data/spec/schemas/box.json
Added
@@ -0,0 +1,432 @@ +{ + "type": "Ygg::SimpleService::Email::Box", + "attrs": { + "id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "simple_email_domain_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "user": { + "type": "string", + "human_name": "", + "default": "", + "notnull": true, + "writable": true, + "readable": true + }, + "domain": { + "type": "string", + "human_name": "", + "default": "", + "notnull": true, + "writable": true, + "readable": true + }, + "password": { + "type": "string", + "human_name": "", + "writable": false, + "readable": true + }, + "encrypted_password": { + "type": "string", + "human_name": "", + "writable": false, + "readable": true + }, + "quota_count": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "quota_space": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "policy_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "created_at": { + "type": "timestamp", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "updated_at": { + "type": "timestamp", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "uuid": { + "type": "string", + "human_name": "", + "writable": false, + "readable": true + }, + "on_hold": { + "type": "boolean", + "human_name": "", + "notnull": true, + "writable": true, + "readable": true + }, + "fwd_only": { + "type": "boolean", + "human_name": "", + "writable": true, + "readable": true + }, + "pop3_merge_junk": { + "type": "boolean", + "human_name": "", + "writable": true, + "readable": true + }, + "quick_search": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "portal_legacy_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "log_entry_details": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::LogEntry::Detail", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "log_entries": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::LogEntry" + }, + "notifications": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::Notification", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "recent_notifications": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::Notification", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "agreement_service_instance": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Shop::Agreement::Service::Instance" + }, + "agreement": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Shop::Agreement" + }, + "email_domain": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::SimpleService::Email::Domain", + "foreign_key": "simple_email_domain_id" + }, + "forwards": { + "type": "uniform_models_collection", + "human_name": "", + "writable": true, + "readable": true, + "class_name": "Ygg::SimpleService::Email::Box::Forward", + "schema": { + "type": "Ygg::SimpleService::Email::Box::Forward", + "attrs": { + "id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "obj_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "obj_type": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true
View file
mail_agent-1.2.3.gem/data/spec/schemas/domain.json
Added
@@ -0,0 +1,647 @@ +{ + "type": "Ygg::SimpleService::Email::Domain", + "attrs": { + "id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "domain": { + "type": "string", + "human_name": "", + "default": "", + "notnull": true, + "writable": true, + "readable": true + }, + "virtual": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "relay_only": { + "type": "boolean", + "human_name": "", + "notnull": true, + "writable": true, + "readable": true + }, + "generic": { + "type": "boolean", + "human_name": "", + "notnull": true, + "writable": true, + "readable": true + }, + "policy_id": { + "type": "integer", + "human_name": "", + "default": 2, + "notnull": true, + "writable": true, + "readable": true + }, + "created_at": { + "type": "timestamp", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "updated_at": { + "type": "timestamp", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "uuid": { + "type": "string", + "human_name": "", + "writable": false, + "readable": true + }, + "pop3_merge_junk": { + "type": "boolean", + "human_name": "", + "writable": true, + "readable": true + }, + "quick_search": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "on_hold": { + "type": "boolean", + "human_name": "", + "writable": true, + "readable": true + }, + "mx": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "log_entry_details": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::LogEntry::Detail", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "log_entries": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::LogEntry" + }, + "notifications": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::Notification", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "recent_notifications": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::Notification", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "agreement_service_instance": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Shop::Agreement::Service::Instance" + }, + "agreement": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Shop::Agreement" + }, + "boxes": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::SimpleService::Email::Box", + "foreign_key": "simple_email_domain_id" + }, + "aliases": { + "type": "uniform_models_collection", + "human_name": "", + "writable": true, + "readable": true, + "class_name": "Ygg::SimpleService::Email::Domain::Alias", + "schema": { + "type": "Ygg::SimpleService::Email::Domain::Alias", + "attrs": { + "id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "simple_email_domain_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "user": { + "type": "string", + "human_name": "", + "default": "", + "notnull": true, + "writable": true, + "readable": true + }, + "domain": { + "type": "string", + "human_name": "", + "default": "", + "notnull": true, + "writable": true, + "readable": true + }, + "policy_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "created_at": { + "type": "timestamp", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true
View file
mail_agent-1.2.3.gem/data/spec/schemas/relay_extension.json
Added
@@ -0,0 +1,347 @@ +{ + "type": "Ygg::SimpleService::Email::RelayExtension", + "attrs": { + "id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "uuid": { + "type": "string", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "fqda": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "password": { + "type": "string", + "human_name": "", + "writable": false, + "readable": true + }, + "simple_email_box_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "ip": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "rate_limit": { + "type": "string", + "human_name": "", + "default": "default_for_identities", + "notnull": true, + "writable": true, + "readable": true + }, + "created_at": { + "type": "timestamp", + "human_name": "", + "writable": false, + "readable": true + }, + "updated_at": { + "type": "timestamp", + "human_name": "", + "writable": false, + "readable": true + }, + "quick_search": { + "type": "string", + "human_name": "", + "writable": true, + "readable": true + }, + "policy_group_member_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "on_hold": { + "type": "boolean", + "human_name": "", + "writable": true, + "readable": true + }, + "simple_email_domain_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "encrypted_password": { + "type": "string", + "human_name": "", + "writable": false, + "readable": true + }, + "log_entry_details": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::LogEntry::Detail", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "log_entries": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::LogEntry" + }, + "notifications": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::Notification", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "recent_notifications": { + "type": "uniform_references_collection", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Core::Notification", + "foreign_key": "obj_id", + "foreign_type": "obj_type", + "as": "obj" + }, + "agreement_service_instance": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Shop::Agreement::Service::Instance" + }, + "agreement": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::Shop::Agreement" + }, + "box": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::SimpleService::Email::Box", + "foreign_key": "simple_email_box_id" + }, + "email_domain": { + "type": "reference", + "human_name": "", + "writable": true, + "readable": true, + "referenced_class": "Ygg::SimpleService::Email::Domain", + "foreign_key": "simple_email_domain_id" + }, + "acl_entries": { + "type": "uniform_models_collection", + "human_name": "", + "writable": true, + "readable": true, + "class_name": "Ygg::SimpleService::Email::RelayExtension::AclEntry", + "schema": { + "type": "Ygg::SimpleService::Email::RelayExtension::AclEntry", + "attrs": { + "id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": false, + "readable": true + }, + "obj_id": { + "type": "integer", + "human_name": "", + "notnull": true, + "writable": true, + "readable": true + }, + "identity_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "group_id": { + "type": "integer", + "human_name": "", + "writable": true, + "readable": true + }, + "capability": { + "type": "string", + "human_name": "", + "notnull": true, + "writable": true, + "readable": true
View file
mail_agent-1.2.3.gem/data/spec/spec_helper.rb
Added
@@ -0,0 +1,382 @@ +require 'active_record' +require 'sqlite3' +require 'fileutils' +require 'tmpdir' +require 'webmock/rspec' +require 'byebug' + +# Load mail_agent +$:.unshift File.dirname(__FILE__) + '/../lib' +require 'mail_agent/models' +require 'mail_agent/ygg' + +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration + +# Database configuration for tests +TEST_DB_DIR = File.join(Dir.tmpdir, 'mail_agent_test') +FileUtils.mkdir_p(TEST_DB_DIR) + +TEST_DB_CONFIG = { + email: { adapter: 'sqlite3', database: File.join(TEST_DB_DIR, 'email_test.db') }, + amavis: { adapter: 'sqlite3', database: File.join(TEST_DB_DIR, 'amavis_test.db') }, + policyd: { adapter: 'sqlite3', database: File.join(TEST_DB_DIR, 'policyd_test.db') } +} + +RSpec.configure do |config| + # Setup database connections before suite + config.before(:suite) do + # Establish connections + MailAgent::Models::Email::Base.establish_connection(TEST_DB_CONFIG:email) + MailAgent::Models::Amavis::Base.establish_connection(TEST_DB_CONFIG:amavis) + MailAgent::Models::Policyd::Base.establish_connection(TEST_DB_CONFIG:policyd) + + # Enable foreign keys for SQLite3 + MailAgent::Models::Policyd::Base.connection.execute("PRAGMA foreign_keys = ON") + + ActiveResource::Hel::Resource.configurations = { + test: { + site: 'https://hel.test', + identity: 'foo@hel.test', + secret: 'foobar' + } + } + ActiveResource::Hel::Resource.use_configuration :test + + # Create tables + create_email_tables + create_amavis_tables + create_policyd_tables + + RSpec::Matchers.define_negated_matcher :not_change, :change + end + + # Clean database before each test + config.before(:each) do + clean_email_tables + clean_amavis_tables + clean_policyd_tables + + stub_request(:post, "https://hel.test/ygg/session/authenticate_by_fqda_and_password"). + with( + body: "{\"fqda\":\"foo@hel.test\",\"password\":\"foobar\"}", + headers: { + 'Accept'=>'application/json', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type'=>'application/json', + 'User-Agent'=>'Ruby' + }). + to_return(status: 200, + body: { + "id": "foo", "active": true, "authenticated": true, "status": "authenticated", "capabilities": "superuser", + "started_at": Time.new, "valid_until": 1.hours.from_now}.to_json, + headers: {}) + + root = Pathname.new(File::expand_path('..', __FILE__)).join('schemas') + schema = root.join('domain.json') + stub_request(:get, "https://hel.test/ygg/simple_service/email/domains/schema"). + with( + headers: { + 'Accept'=>'application/json', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Authorization'=>'Bearer foo', + 'User-Agent'=>'ActiveResource::Hel 0.7.1', + 'X-Rest-Client'=>'ActiveResource::Hel 0.7.1' + }). + to_return(status: 200, body: schema, headers: {}) + + schema = root.join('box.json') + stub_request(:get, "https://hel.test/ygg/simple_service/email/boxes/schema"). + with( + headers: { + 'Accept'=>'application/json', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Authorization'=>'Bearer foo', + 'User-Agent'=>'ActiveResource::Hel 0.7.1', + 'X-Rest-Client'=>'ActiveResource::Hel 0.7.1' + }). + to_return(status: 200, body: schema, headers: {}) + + schema = root.join('relay_extension.json') + stub_request(:get, "https://hel.test/ygg/simple_service/email/relay_extensions/schema"). + with( + headers: { + 'Accept'=>'application/json', + 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Authorization'=>'Bearer foo', + 'User-Agent'=>'ActiveResource::Hel 0.7.1', + 'X-Rest-Client'=>'ActiveResource::Hel 0.7.1' + }). + to_return(status: 200, body: schema, headers: {}) + end + + # Cleanup after suite + config.after(:suite) do + FileUtils.rm_rf(TEST_DB_DIR) if File.exist?(TEST_DB_DIR) + end + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/ + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an
View file
mail_agent-1.2.3.gem/data/spec/workers/mail_worker_pubsub_spec.rb
Added
@@ -0,0 +1,370 @@ +require 'spec_helper' +require 'ostruct' + +# Mock Tomte framework for testing +module Tomte + def self.config + @config ||= OpenStruct.new(mail: OpenStruct.new(rpc_exchange: 'test')) + end + + class Worker + attr_accessor :log + + def self.bus(*args, &block) + # Mock bus method + end + + def self.api(*args, &block) + # Mock api method + end + + def self.config + Tomte.config + end + + def initialize + end + end + + module Protocol + module Enveloper + module Generic + end + end + end +end + +require 'tomte/workers/mail_worker_pubsub' + +RSpec.describe Tomte::Workers::MailWorkerPubsub do + let(:metadata) { double('Metadata', attributes: {}) } + let(:mock_log) { double(debug: nil, info: nil, error: nil, ai: nil) } + + subject do + sub = described_class.new + sub.log = mock_log + sub + end + + before do + # Create policies needed for RelayExtension tests + MailAgent::Models::Policyd::Policy.find_or_create_by!(name: '1k') + MailAgent::Models::Policyd::Policy.find_or_create_by!(name: '512') + + #ActiveRecord::Base.logger = Logger.new(STDOUT) + end + + describe '#execute_on_delivery' do + context 'with Ygg::SimpleService::Email::Box' do + context 'with C (create) event' do + it 'creates a new email box' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/box.json'))) + message'events' = 'C' + + expect { + subject.execute_on_delivery(metadata, message) + }.to change{MailAgent::Models::Email::Box.count}.by(1) + .and change{MailAgent::Models::Email::Forward.count}.by(1) + .and change{MailAgent::Models::Amavis::User.count}.by(1) + end + end + + context 'with U (update) event' do + it 'creates an email box' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/box.json'))) + message'events' = 'U' + + expect { + subject.execute_on_delivery(metadata, message) + }.to change{MailAgent::Models::Email::Box.count}.by(1) + .and change{MailAgent::Models::Email::Forward.count}.by(1) + .and change{MailAgent::Models::Amavis::User.count}.by(1) + end + + it 'updates an email box' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/box.json'))) + message'events' = 'U' + + user = MailAgent::Models::Amavis::User.create(email: 'mail@foo.bar', policy_id: 99) + box = MailAgent::Models::Email::Box.create(user: 'mail', domain: 'foo.bar', fqda: 'mail@foo.bar', password: '{PLAIN}barfoo', uuid: 'c3200a84-52f3-4363-aed5-b4a908c9f670') + + expect { + subject.execute_on_delivery(metadata, message) + user.reload + box.reload + }.to change{MailAgent::Models::Email::Forward.count}.by(1) + .and change{box.password}.from('{PLAIN}barfoo').to('{PLAIN}encryptedfoobar') + .and change{user.policy_id}.from(99).to(1) + end + end + + context 'with D (delete) event' do + it 'deletes an email box' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/box.json'))) + message'events' = 'C' + + subject.execute_on_delivery(metadata, message) + + message'events' = 'D' + + expect { + subject.execute_on_delivery(metadata, message) + }.to change{MailAgent::Models::Email::Box.count}.by(-1) + .and change{MailAgent::Models::Email::Forward.count}.by(-1) + .and change{MailAgent::Models::Amavis::User.count}.by(-1) + end + + it 'should do nothing when the box does not exist' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/box.json'))) + message'events' = 'D' + + other = JSON.parse(File.read(File.join(__dir__, '../examples/box.json'))) + other'object_id' = 11 + other'object''id' = 11 + other'object''user' = 'xxxx' + other'object''fqda' = 'xxxx@foo.bar' + other'object''uuid' = 'nopenopenope' + other'object''events' = 'C' + + subject.execute_on_delivery(metadata, other) + + expect { + subject.execute_on_delivery(metadata, message) + }.to not_change{MailAgent::Models::Email::Box.count} + .and not_change{MailAgent::Models::Email::Forward.count} + .and not_change{MailAgent::Models::Amavis::User.count} + end + end + end + + context 'with Ygg::SimpleService::Email::Domain' do + context 'with C (create) event' do + it 'creates a new domain' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/domain.json'))) + message'events' = 'C' + + expect { + subject.execute_on_delivery(metadata, message) + }.to change{MailAgent::Models::Email::Domain.count}.by(1) + .and change{MailAgent::Models::Amavis::User.count}.by(1) + .and change{MailAgent::Models::Email::Forward.count}.by(2) + end + end + + context 'with U (update) event' do + it 'creates a domain' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/domain.json'))) + message'events' = 'U' + + expect { + subject.execute_on_delivery(metadata, message) + }.to change{MailAgent::Models::Email::Domain.count}.by(1) + .and change{MailAgent::Models::Amavis::User.count}.by(1) + .and change{MailAgent::Models::Email::Forward.count}.by(2) + end + + it 'updates a domain' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/domain.json'))) + message'events' = 'C' + subject.execute_on_delivery(metadata, message) + + message'object''mx' = 'new.mx.foo.bar' + message'events' = 'U' + + domain = MailAgent::Models::Email::Domain.find_by(uuid: message'object''uuid') + + expect { + subject.execute_on_delivery(metadata, message) + domain.reload + }.to change{domain.mx}.from('mx.foo.bar').to('new.mx.foo.bar') + end + + it 'updates forwards when aliases change' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/domain.json'))) + message'events' = 'C' + subject.execute_on_delivery(metadata, message) + + # Remove one alias + message'object''aliases'.pop + message'events' = 'U' + + expect { + subject.execute_on_delivery(metadata, message) + }.to change{MailAgent::Models::Email::Forward.count}.by(-1) + end + end + + context 'with D (delete) event' do + it 'deletes a domain' do + message = JSON.parse(File.read(File.join(__dir__, '../examples/domain.json')))
View file
mail_agent-1.2.3.gem/data/spec/workers/mail_worker_rpc_spec.rb
Added
@@ -0,0 +1,263 @@ +require 'spec_helper' +require 'ostruct' + +# Mock Tomte framework for testing +module Tomte + def self.config + @config ||= OpenStruct.new(mail: OpenStruct.new(rpc_exchange: 'test')) + end + + class Worker + attr_accessor :log + + def self.bus(*args, &block) + # Mock bus method + end + + def self.api(*args, &block) + # Mock api method + end + + def self.config + Tomte.config + end + + def initialize + end + end + + module Network + module API + class BasicServer + end + end + end +end + +require 'tomte/workers/mail_worker_rpc' + +RSpec.describe Tomte::Workers::MailWorkerRPC::RPC do + let(:mock_log) { double(debug: nil, info: nil, error: nil, ai: nil) } + + subject do + described_class.new + end + + describe '#quotas' do + context 'with identity' do + it 'returns quotas for AuthenticatedIdentity' do + policy = MailAgent::Models::Policyd::Policy.create!( + name: 'test_policy', + count: 100, + recipients: 200, + volume: 300 + ) + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.create!( + identity: 'test@example.com', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: 0, + static: 0 + ) + tracker = identity.tracker + tracker.update!(count: 50, recipients: 100, volume: 150) + + result = subject.quotas('identity' => 'test@example.com') + + expect(result:policy).to eq('test_policy') + expect(result:disabled).to be false + expect(result:disable_reason).to be_nil + expect(result:disable_date).to be_nil + expect(result:count).to eq({ quota: 100, count: 50 }) + expect(result:recipients).to eq({ quota: 200, count: 100 }) + expect(result:volume).to eq({ quota: 300, count: 150 }) + expect(result:addresses).to eq() + expect(result:last_update).to be_present + end + + it 'returns disabled status when identity is disabled' do + policy = MailAgent::Models::Policyd::Policy.create!( + name: 'test_policy', + count: 100, + recipients: 200, + volume: 300 + ) + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.create!( + identity: 'test@example.com', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: 1, + disable_reason: 'Rate limit exceeded', + disable_date: Time.now, + static: 0 + ) + + result = subject.quotas('identity' => 'test@example.com') + + expect(result:disabled).to be true + expect(result:disable_reason).to eq('Rate limit exceeded') + expect(result:disable_date).to be_present + end + + + it 'returns heuristics addresses when tracker has them' do + policy = MailAgent::Models::Policyd::Policy.create!( + name: 'test_policy', + count: 100, + recipients: 200, + volume: 300 + ) + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.create!( + identity: 'test@example.com', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: 0, + static: 0 + ) + tracker = identity.tracker + tracker.update!(heuristics: { addresses: { '192.168.1.1' => { count: 10 }, '192.168.1.2' => { count: 20 } } }) + + result = subject.quotas('identity' => 'test@example.com') + + expect(result:addresses).to be_an(Array) + expect(result:addresses.length).to eq(2) + expect(result:addresses.find { |a| a:address == '192.168.1.1' }).to be_present + expect(result:addresses.find { |a| a:address == '192.168.1.2' }).to be_present + end + end + + context 'with address' do + it 'returns quotas for ClientAddress' do + policy = MailAgent::Models::Policyd::Policy.create!( + name: 'test_policy', + count: 100, + recipients: 200, + volume: 300 + ) + address = MailAgent::Models::Policyd::ClientAddress.create!( + address: '192.168.1.1', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: 0, + static: 0 + ) + tracker = address.tracker + tracker.update!(count: 50, recipients: 100, volume: 150) + + result = subject.quotas('address' => '192.168.1.1') + + expect(result:policy).to eq('test_policy') + expect(result:disabled).to be false + expect(result:count).to eq({ quota: 100, count: 50 }) + expect(result:recipients).to eq({ quota: 200, count: 100 }) + expect(result:volume).to eq({ quota: 300, count: 150 }) + end + end + + context 'with neither identity nor address' do + it 'raises ArgumentError' do + expect { + subject.quotas({}) + }.to raise_error(ArgumentError, "Must specify an identity or an address") + end + end + + context 'when object does not exist' do + it 'returns unknown policy and zero counts' do + result = subject.quotas('identity' => 'nonexistent@example.com') + + expect(result:policy).to eq('unknown') + expect(result:disabled).to be false + expect(result:count).to eq({ quota: 0, count: 0 }) + expect(result:recipients).to eq({ quota: 0, count: 0 }) + expect(result:volume).to eq({ quota: 0, count: 0 }) + expect(result:addresses).to eq() + expect(result:last_update).to be_nil + end + end + end + + describe '#reset_quotas!' do + context 'with identity' do + it 'calls reset_tracker! on AuthenticatedIdentity' do + policy = MailAgent::Models::Policyd::Policy.create!( + name: 'test_policy', + count: 100, + recipients: 200, + volume: 300 + ) + identity = MailAgent::Models::Policyd::AuthenticatedIdentity.create!( + identity: 'test@example.com', + notes: 'hel:test-uuid', + policy_id: policy.id, + disabled: 1, + disable_reason: 'Test reason', + disable_date: Time.now, + static: 0 + ) + tracker = identity.tracker + tracker.update!(count: 50, recipients: 100, volume: 150)
View file
mail_agent-1.2.3.gem/data/sql/amavis-new-relays-in.sql
Added
@@ -0,0 +1,302 @@ +-- MariaDB dump 10.19 Distrib 10.6.15-MariaDB, for Linux (x86_64) +-- +-- Host: localhost Database: amavis-new-relays-in +-- ------------------------------------------------------ +-- Server version 10.6.15-MariaDB-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `maddr` +-- + +DROP TABLE IF EXISTS `maddr`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `maddr` ( + `partition_tag` int(11) DEFAULT 0, + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `email` varbinary(255) NOT NULL, + `domain` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `part_email` (`partition_tag`,`email`) +) ENGINE=InnoDB AUTO_INCREMENT=6739316 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `maddr_old` +-- + +DROP TABLE IF EXISTS `maddr_old`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `maddr_old` ( + `partition_tag` int(11) DEFAULT 0, + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `email` varbinary(255) NOT NULL, + `domain` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `part_email` (`partition_tag`,`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `mailaddr` +-- + +DROP TABLE IF EXISTS `mailaddr`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `mailaddr` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `priority` int(11) NOT NULL DEFAULT 7, + `email` varbinary(255) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `mailaddr_idx_email` (`email`), + KEY `email` (`email`) +) ENGINE=MyISAM AUTO_INCREMENT=73 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `msgrcpt` +-- + +DROP TABLE IF EXISTS `msgrcpt`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `msgrcpt` ( + `partition_tag` int(11) NOT NULL DEFAULT 0, + `mail_id` varbinary(16) NOT NULL, + `rseqnum` int(11) NOT NULL DEFAULT 0, + `rid` bigint(20) unsigned NOT NULL, + `is_local` char(1) NOT NULL DEFAULT '', + `content` char(1) NOT NULL DEFAULT '', + `ds` char(1) NOT NULL, + `rs` char(1) NOT NULL, + `bl` char(1) DEFAULT '', + `wl` char(1) DEFAULT '', + `bspam_level` float DEFAULT NULL, + `smtp_resp` varchar(255) DEFAULT '', + PRIMARY KEY (`partition_tag`,`mail_id`,`rseqnum`), + KEY `msgrcpt_idx_mail_id` (`mail_id`), + KEY `msgrcpt_idx_rid` (`rid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `msgrcpt_old` +-- + +DROP TABLE IF EXISTS `msgrcpt_old`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `msgrcpt_old` ( + `partition_tag` int(11) NOT NULL DEFAULT 0, + `mail_id` varbinary(16) NOT NULL, + `rseqnum` int(11) NOT NULL DEFAULT 0, + `rid` bigint(20) unsigned NOT NULL, + `is_local` char(1) NOT NULL DEFAULT '', + `content` char(1) NOT NULL DEFAULT '', + `ds` char(1) NOT NULL, + `rs` char(1) NOT NULL, + `bl` char(1) DEFAULT '', + `wl` char(1) DEFAULT '', + `bspam_level` float DEFAULT NULL, + `smtp_resp` varchar(255) DEFAULT '', + PRIMARY KEY (`partition_tag`,`mail_id`,`rseqnum`), + KEY `msgrcpt_idx_mail_id` (`mail_id`), + KEY `msgrcpt_idx_rid` (`rid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `msgs` +-- + +DROP TABLE IF EXISTS `msgs`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `msgs` ( + `partition_tag` int(11) NOT NULL DEFAULT 0, + `mail_id` varbinary(16) NOT NULL, + `secret_id` varbinary(16) DEFAULT '', + `am_id` varchar(20) NOT NULL, + `time_num` int(10) unsigned NOT NULL, + `time_iso` char(16) NOT NULL, + `sid` bigint(20) unsigned NOT NULL, + `policy` varchar(255) DEFAULT '', + `client_addr` varchar(255) DEFAULT '', + `size` int(10) unsigned NOT NULL, + `originating` char(1) NOT NULL DEFAULT '', + `content` char(1) DEFAULT NULL, + `quar_type` char(1) DEFAULT NULL, + `quar_loc` varbinary(255) DEFAULT '', + `dsn_sent` char(1) DEFAULT NULL, + `spam_level` float DEFAULT NULL, + `message_id` varchar(255) DEFAULT '', + `from_addr` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '', + `subject` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '', + `host` varchar(255) NOT NULL, + PRIMARY KEY (`partition_tag`,`mail_id`), + KEY `msgs_idx_sid` (`sid`), + KEY `msgs_idx_mess_id` (`message_id`), + KEY `msgs_idx_time_num` (`time_num`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `msgs_old` +-- + +DROP TABLE IF EXISTS `msgs_old`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `msgs_old` ( + `partition_tag` int(11) NOT NULL DEFAULT 0, + `mail_id` varbinary(16) NOT NULL, + `secret_id` varbinary(16) DEFAULT '', + `am_id` varchar(20) NOT NULL, + `time_num` int(10) unsigned NOT NULL, + `time_iso` char(16) NOT NULL, + `sid` bigint(20) unsigned NOT NULL, + `policy` varchar(255) DEFAULT '', + `client_addr` varchar(255) DEFAULT '', + `size` int(10) unsigned NOT NULL, + `originating` char(1) NOT NULL DEFAULT '', + `content` char(1) DEFAULT NULL, + `quar_type` char(1) DEFAULT NULL, + `quar_loc` varbinary(255) DEFAULT '', + `dsn_sent` char(1) DEFAULT NULL, + `spam_level` float DEFAULT NULL, + `message_id` varchar(255) DEFAULT '', + `from_addr` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '', + `subject` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin DEFAULT '', + `host` varchar(255) NOT NULL, + PRIMARY KEY (`partition_tag`,`mail_id`), + KEY `msgs_idx_sid` (`sid`), + KEY `msgs_idx_mess_id` (`message_id`), + KEY `msgs_idx_time_num` (`time_num`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `policy` +-- + +DROP TABLE IF EXISTS `policy`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `policy` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
View file
mail_agent-1.2.3.gem/data/sql/mailserver.sql
Added
@@ -0,0 +1,287 @@ +-- MariaDB dump 10.19 Distrib 10.6.15-MariaDB, for Linux (x86_64) +-- +-- Host: localhost Database: mailserver +-- ------------------------------------------------------ +-- Server version 10.6.15-MariaDB-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `boxes` +-- + +DROP TABLE IF EXISTS `boxes`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `boxes` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user` varchar(255) NOT NULL, + `domain` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `on_hold` tinyint(1) NOT NULL DEFAULT 0, + `send_only` tinyint(1) NOT NULL DEFAULT 0, + `pop3_merge_junk` tinyint(1) NOT NULL DEFAULT 0, + `fqda` varchar(255) NOT NULL, + `uuid` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `user` (`user`,`domain`), + UNIQUE KEY `fqda` (`fqda`), + UNIQUE KEY `uuid` (`uuid`), + KEY `send_only_on_hold` (`send_only`,`on_hold`), + KEY `send_only` (`send_only`), + KEY `on_hold` (`on_hold`) +) ENGINE=InnoDB AUTO_INCREMENT=3568 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `domains` +-- + +DROP TABLE IF EXISTS `domains`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `domains` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `domain` varchar(255) NOT NULL, + `virtual` varchar(255) DEFAULT NULL, + `relay_only` tinyint(1) NOT NULL DEFAULT 0, + `mx` varchar(255) DEFAULT NULL, + `uuid` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `domain` (`domain`), + UNIQUE KEY `uuid` (`uuid`), + KEY `virtual` (`virtual`), + KEY `relay_only` (`relay_only`), + KEY `mx` (`mx`) +) ENGINE=InnoDB AUTO_INCREMENT=414 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `forwards` +-- + +DROP TABLE IF EXISTS `forwards`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `forwards` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user` varchar(255) NOT NULL, + `domain` varchar(255) NOT NULL, + `policy_id` int(11) DEFAULT NULL, + `fwd_addresses` longtext NOT NULL, + `fqda` varchar(255) NOT NULL, + `uuid` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `fqda` (`fqda`), + KEY `uuid` (`uuid`), + KEY `user` (`user`,`domain`) +) ENGINE=InnoDB AUTO_INCREMENT=2508 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Temporary table structure for view `mailbox_boxes` +-- + +DROP TABLE IF EXISTS `mailbox_boxes`; +/*!50001 DROP VIEW IF EXISTS `mailbox_boxes`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE VIEW `mailbox_boxes` AS SELECT + 1 AS `user`, + 1 AS `domain`, + 1 AS `pop3_merge_junk` */; +SET character_set_client = @saved_cs_client; + +-- +-- Temporary table structure for view `mailbox_domains` +-- + +DROP TABLE IF EXISTS `mailbox_domains`; +/*!50001 DROP VIEW IF EXISTS `mailbox_domains`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE VIEW `mailbox_domains` AS SELECT + 1 AS `domain` */; +SET character_set_client = @saved_cs_client; + +-- +-- Temporary table structure for view `mailbox_logins` +-- + +DROP TABLE IF EXISTS `mailbox_logins`; +/*!50001 DROP VIEW IF EXISTS `mailbox_logins`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE VIEW `mailbox_logins` AS SELECT + 1 AS `user`, + 1 AS `domain`, + 1 AS `password` */; +SET character_set_client = @saved_cs_client; + +-- +-- Temporary table structure for view `smtp_in_relay` +-- + +DROP TABLE IF EXISTS `smtp_in_relay`; +/*!50001 DROP VIEW IF EXISTS `smtp_in_relay`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE VIEW `smtp_in_relay` AS SELECT + 1 AS `domain`, + 1 AS `mx` */; +SET character_set_client = @saved_cs_client; + +-- +-- Temporary table structure for view `smtp_in_virtual_domains` +-- + +DROP TABLE IF EXISTS `smtp_in_virtual_domains`; +/*!50001 DROP VIEW IF EXISTS `smtp_in_virtual_domains`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE VIEW `smtp_in_virtual_domains` AS SELECT + 1 AS `domain`, + 1 AS `destination_domain` */; +SET character_set_client = @saved_cs_client; + +-- +-- Temporary table structure for view `smtp_out_logins` +-- + +DROP TABLE IF EXISTS `smtp_out_logins`; +/*!50001 DROP VIEW IF EXISTS `smtp_out_logins`*/; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +/*!50001 CREATE VIEW `smtp_out_logins` AS SELECT + 1 AS `user`, + 1 AS `domain`, + 1 AS `password` */; +SET character_set_client = @saved_cs_client; + +-- +-- Final view structure for view `mailbox_boxes` +-- + +/*!50001 DROP VIEW IF EXISTS `mailbox_boxes`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = utf8mb4 */; +/*!50001 SET character_set_results = utf8mb4 */; +/*!50001 SET collation_connection = utf8mb4_general_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`rottame`@`%` SQL SECURITY DEFINER */ +/*!50001 VIEW `mailbox_boxes` AS select `boxes`.`user` AS `user`,`boxes`.`domain` AS `domain`,`boxes`.`pop3_merge_junk` AS `pop3_merge_junk` from `boxes` where `boxes`.`send_only` = 0 */; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; + +-- +-- Final view structure for view `mailbox_domains` +-- + +/*!50001 DROP VIEW IF EXISTS `mailbox_domains`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = utf8mb4 */; +/*!50001 SET character_set_results = utf8mb4 */; +/*!50001 SET collation_connection = utf8mb4_general_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */
View file
mail_agent-1.2.3.gem/data/sql/policyd.sql
Added
@@ -0,0 +1,142 @@ +-- MariaDB dump 10.19 Distrib 10.6.15-MariaDB, for Linux (x86_64) +-- +-- Host: localhost Database: policyd +-- ------------------------------------------------------ +-- Server version 10.6.15-MariaDB-log + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `authenticated_identities` +-- + +DROP TABLE IF EXISTS `authenticated_identities`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `authenticated_identities` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `identity` varchar(128) DEFAULT NULL, + `notes` varchar(255) DEFAULT NULL, + `disabled` tinyint(1) NOT NULL DEFAULT 0, + `static` tinyint(1) NOT NULL DEFAULT 0, + `disable_reason` varchar(255) DEFAULT NULL, + `disable_date` datetime DEFAULT NULL, + `policy_id` int(11) NOT NULL, + `tracker_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `identity` (`identity`), + KEY `policy_id` (`policy_id`), + KEY `tracker_id` (`tracker_id`), + CONSTRAINT `authenticated_identities_ibfk_1` FOREIGN KEY (`policy_id`) REFERENCES `policies` (`id`), + CONSTRAINT `authenticated_identities_ibfk_2` FOREIGN KEY (`tracker_id`) REFERENCES `trackers` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=1624 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `client_addresses` +-- + +DROP TABLE IF EXISTS `client_addresses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `client_addresses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `address` varchar(64) DEFAULT NULL, + `notes` varchar(255) DEFAULT NULL, + `disabled` tinyint(1) NOT NULL DEFAULT 0, + `static` tinyint(1) NOT NULL DEFAULT 0, + `disable_reason` varchar(255) DEFAULT NULL, + `disable_date` datetime DEFAULT NULL, + `policy_id` int(11) NOT NULL, + `tracker_id` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `address` (`address`), + KEY `policy_id` (`policy_id`), + KEY `tracker_id` (`tracker_id`), + CONSTRAINT `client_addresses_ibfk_1` FOREIGN KEY (`policy_id`) REFERENCES `policies` (`id`), + CONSTRAINT `client_addresses_ibfk_2` FOREIGN KEY (`tracker_id`) REFERENCES `trackers` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=4693 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `network_addresses` +-- + +DROP TABLE IF EXISTS `network_addresses`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `network_addresses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `address` varchar(64) DEFAULT NULL, + `flags` char(2) NOT NULL DEFAULT 'b', + `notes` varchar(255) DEFAULT NULL, + `inserted` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `address` (`address`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `policies` +-- + +DROP TABLE IF EXISTS `policies`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `policies` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(64) NOT NULL, + `description` varchar(255) DEFAULT NULL, + `interval` int(11) NOT NULL DEFAULT 86400, + `heuristics` tinyint(1) NOT NULL DEFAULT 1, + `count` int(11) DEFAULT NULL, + `recipients` int(11) DEFAULT NULL, + `volume` bigint(20) DEFAULT NULL, + `h_max_addresses` int(11) NOT NULL DEFAULT 5, + `h_activity_threshold` int(11) NOT NULL DEFAULT 14400, + `h_interval` int(11) NOT NULL DEFAULT 1800, + `h_interval_count` int(11) NOT NULL DEFAULT 50, + `h_grace_threshold` int(11) NOT NULL DEFAULT 1296000, + PRIMARY KEY (`id`), + UNIQUE KEY `name` (`name`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `trackers` +-- + +DROP TABLE IF EXISTS `trackers`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `trackers` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `count` double DEFAULT NULL, + `recipients` double DEFAULT NULL, + `volume` bigint(20) DEFAULT NULL, + `last_update` datetime NOT NULL, + `first_seen` datetime NOT NULL, + `heuristics` text DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6316 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2026-01-14 9:30:49
View file
mail_agent-1.2.2.gem/metadata.gz -> mail_agent-1.2.3.gem/metadata.gz
Changed
@@ -1,14 +1,14 @@ --- !ruby/object:Gem::Specification name: mail_agent version: !ruby/object:Gem::Version - version: 1.2.2 + version: 1.2.3 platform: ruby authors: - Angelo Grossini -autorequire: +autorequire: bindir: bin cert_chain: -date: 2025-12-02 00:00:00.000000000 Z +date: 2026-01-15 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: tomte-agents @@ -36,20 +36,20 @@ requirements: - - "~>" - !ruby/object:Gem::Version - version: '1.2' - - - ">=" + version: '1.3' + - - "<" - !ruby/object:Gem::Version - version: 1.2.1 + version: 1.4.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: '1.2' - - - ">=" + version: '1.3' + - - "<" - !ruby/object:Gem::Version - version: 1.2.1 + version: 1.4.0 - !ruby/object:Gem::Dependency name: mysql2 requirement: !ruby/object:Gem::Requirement @@ -91,61 +91,161 @@ - !ruby/object:Gem::Version version: 1.2.0 - !ruby/object:Gem::Dependency - name: activesupport + name: ygg_provisioner requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: '6.0' + version: '1.5' - - ">=" - !ruby/object:Gem::Version - version: 6.0.6.1 + version: 1.5.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: '6.0' + version: '1.5' - - ">=" - !ruby/object:Gem::Version - version: 6.0.6.1 + version: 1.5.0 - !ruby/object:Gem::Dependency - name: ygg_provisioner + name: activeresource-hel requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: '1.5' + version: 0.7.0 + type: :runtime + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: 0.7.0 +- !ruby/object:Gem::Dependency + name: sentry-raven + requirement: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '3' - - ">=" - !ruby/object:Gem::Version - version: 1.5.0 + version: 3.0.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: '1.5' + version: '3' - - ">=" - !ruby/object:Gem::Version - version: 1.5.0 + version: 3.0.0 - !ruby/object:Gem::Dependency - name: activeresource-hel + name: rake requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: 0.5.0 - type: :runtime + version: '13.2' + - - ">=" + - !ruby/object:Gem::Version + version: 13.2.1 + type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version - version: 0.5.0 + version: '13.2' + - - ">=" + - !ruby/object:Gem::Version + version: 13.2.1 - !ruby/object:Gem::Dependency - name: sentry-raven + name: pry + requirement: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '0.14' + - - ">=" + - !ruby/object:Gem::Version + version: 0.14.0 + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '0.14' + - - ">=" + - !ruby/object:Gem::Version + version: 0.14.0 +- !ruby/object:Gem::Dependency + name: rspec + requirement: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '3.10' + - - ">=" + - !ruby/object:Gem::Version + version: 3.13.0 + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '3.10' + - - ">=" + - !ruby/object:Gem::Version + version: 3.13.0 +- !ruby/object:Gem::Dependency + name: byebug + requirement: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '11.0' + - - ">=" + - !ruby/object:Gem::Version + version: 11.1.3 + type: :development + prerelease: false + version_requirements: !ruby/object:Gem::Requirement + requirements: + - - "~>" + - !ruby/object:Gem::Version + version: '11.0' + - - ">=" + - !ruby/object:Gem::Version + version: 11.1.3 +- !ruby/object:Gem::Dependency + name: sqlite3 + requirement: !ruby/object:Gem::Requirement
View file
mail_agent.yml
Changed
@@ -55,6 +55,8 @@ production: core: + core: + log_path: /var/log/tomte/mail_agent log_level: info debug: false hel:
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.