@rakay-technology/kraft 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -0
- package/dist/bare-HL2GUYE2.js +27 -0
- package/dist/bowser-HNOTPGJO.js +2825 -0
- package/dist/chunk-3CJLKL6E.js +124 -0
- package/dist/chunk-3NQQXMDR.js +2098 -0
- package/dist/chunk-42WQABXM.js +439 -0
- package/dist/chunk-5GPXMTE4.js +25 -0
- package/dist/chunk-AJ4QZLZ2.js +1069 -0
- package/dist/chunk-AO252K7Z.js +137 -0
- package/dist/chunk-BQMFIXHI.js +975 -0
- package/dist/chunk-DM3PKWDC.js +2453 -0
- package/dist/chunk-DOD2BXHQ.js +1364 -0
- package/dist/chunk-DRK3MEDS.js +2870 -0
- package/dist/chunk-EW4PHKB2.js +13914 -0
- package/dist/chunk-HMJUFZK7.js +340 -0
- package/dist/chunk-I2TOOF2A.js +517 -0
- package/dist/chunk-I3DPMTSF.js +29 -0
- package/dist/chunk-JSCZT76F.js +2588 -0
- package/dist/chunk-MNV2QFHW.js +138 -0
- package/dist/chunk-MOLPYPVH.js +2529 -0
- package/dist/chunk-N4OALTFK.js +295 -0
- package/dist/chunk-OFXBNFNL.js +458 -0
- package/dist/chunk-ONKEYSMY.js +1388 -0
- package/dist/chunk-PDW4L3NV.js +17 -0
- package/dist/chunk-PNNXWA2A.js +1947 -0
- package/dist/chunk-PNRPKRJU.js +11105 -0
- package/dist/chunk-PVOWHIND.js +26781 -0
- package/dist/chunk-PXKCZB2I.js +46 -0
- package/dist/chunk-PZVKPCKE.js +475 -0
- package/dist/chunk-QWHBRY2K.js +4945 -0
- package/dist/chunk-RFOBMHQ7.js +338 -0
- package/dist/chunk-RHLNVZMS.js +28 -0
- package/dist/chunk-RVER2EOO.js +577 -0
- package/dist/chunk-S3QBGGVP.js +81 -0
- package/dist/chunk-TAML5WMA.js +198 -0
- package/dist/chunk-THTEUDBC.js +3188 -0
- package/dist/chunk-WYNM7L22.js +329 -0
- package/dist/chunk-XGCG4MD5.js +102 -0
- package/dist/chunk-XVKUFMIB.js +148 -0
- package/dist/chunk-XZYFZ6A5.js +50 -0
- package/dist/chunk-Y7PVJUXJ.js +2275 -0
- package/dist/chunk-YRSZPVMB.js +306 -0
- package/dist/chunk-YZUKHG3S.js +362 -0
- package/dist/chunk-ZVFS4LUA.js +116 -0
- package/dist/chunk-ZWLDLTJP.js +1417 -0
- package/dist/detect-676SNZK4.js +48 -0
- package/dist/dist-es-2YRDXMUU.js +73 -0
- package/dist/dist-es-CCVZEFRZ.js +91 -0
- package/dist/dist-es-EDUSMF6Q.js +488 -0
- package/dist/dist-es-IOH6G4GM.js +380 -0
- package/dist/dist-es-KWSMDPIP.js +26 -0
- package/dist/dist-es-UYDDOVZ3.js +173 -0
- package/dist/dist-es-XUOR4NQN.js +321 -0
- package/dist/docker-GOT3Q7DJ.js +41 -0
- package/dist/docker-edge-executor-VO6JHHW2.js +19 -0
- package/dist/edge-import-NFCHIW7G.js +50 -0
- package/dist/edge-preflight-QUJ757C6.js +45 -0
- package/dist/ensure-container-edge-Q7IZXHGM.js +38 -0
- package/dist/event-streams-TR4GAC53.js +46 -0
- package/dist/executor-GKXKN52K.js +42 -0
- package/dist/host-channel-preflight-Z6HYSPKO.js +48 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9469 -0
- package/dist/loadSso-UGF4JMRK.js +581 -0
- package/dist/local-executor-OMMDKXCM.js +13 -0
- package/dist/nginx-VITTWZZU.js +42 -0
- package/dist/node-bootstrap.js +277 -0
- package/dist/node-entry.js +55 -0
- package/dist/noop-CLLJHCPL.js +11 -0
- package/dist/openresty-lua-6I3Z6PEQ.js +90 -0
- package/dist/privilege-UQAI2HV4.js +20 -0
- package/dist/server/engine/ChangeLog +2289 -0
- package/dist/server/engine/Documentations +5 -0
- package/dist/server/engine/LICENSE +674 -0
- package/dist/server/engine/README.md +34 -0
- package/dist/server/engine/conf/amavisd +150 -0
- package/dist/server/engine/conf/clamav +71 -0
- package/dist/server/engine/conf/core +632 -0
- package/dist/server/engine/conf/dovecot +151 -0
- package/dist/server/engine/conf/fail2ban +72 -0
- package/dist/server/engine/conf/global +698 -0
- package/dist/server/engine/conf/iredapd +52 -0
- package/dist/server/engine/conf/logwatch +28 -0
- package/dist/server/engine/conf/postfix +97 -0
- package/dist/server/engine/conf/postgresql +93 -0
- package/dist/server/engine/conf/spamassassin +39 -0
- package/dist/server/engine/dialog/config_via_dialog.sh +258 -0
- package/dist/server/engine/dialog/optional_components.sh +122 -0
- package/dist/server/engine/dialog/pgsql_config.sh +52 -0
- package/dist/server/engine/dialog/virtual_domain_config.sh +94 -0
- package/dist/server/engine/functions/amavisd.sh +267 -0
- package/dist/server/engine/functions/backend.sh +85 -0
- package/dist/server/engine/functions/clamav.sh +100 -0
- package/dist/server/engine/functions/cleanup.sh +393 -0
- package/dist/server/engine/functions/dovecot.sh +583 -0
- package/dist/server/engine/functions/fail2ban.sh +209 -0
- package/dist/server/engine/functions/iredapd.sh +356 -0
- package/dist/server/engine/functions/optional_components.sh +24 -0
- package/dist/server/engine/functions/packages.sh +522 -0
- package/dist/server/engine/functions/packages_freebsd.sh +179 -0
- package/dist/server/engine/functions/postfix.sh +457 -0
- package/dist/server/engine/functions/postgresql.sh +239 -0
- package/dist/server/engine/functions/spamassassin.sh +49 -0
- package/dist/server/engine/functions/system_accounts.sh +128 -0
- package/dist/server/engine/iRedMail.sh +144 -0
- package/dist/server/engine/pkgs/get_all.sh +338 -0
- package/dist/server/engine/pkgs/pkgs.freebsd.sha256 +3 -0
- package/dist/server/engine/pkgs/pkgs.openbsd.sha256 +6 -0
- package/dist/server/engine/pkgs/pkgs.sha256 +1 -0
- package/dist/server/engine/samples/amavisd/amavisd.conf +702 -0
- package/dist/server/engine/samples/amavisd/amavisd.mysql +278 -0
- package/dist/server/engine/samples/amavisd/amavisd.pgsql +253 -0
- package/dist/server/engine/samples/amavisd/amavisd.schema +942 -0
- package/dist/server/engine/samples/amavisd/default_spam_policy.sql +46 -0
- package/dist/server/engine/samples/dovecot/dovecot-2.4-mariadb.conf +758 -0
- package/dist/server/engine/samples/dovecot/dovecot-2.4-openldap.conf +767 -0
- package/dist/server/engine/samples/dovecot/dovecot-2.4-pgsql.conf +762 -0
- package/dist/server/engine/samples/dovecot/dovecot-last-login.conf +50 -0
- package/dist/server/engine/samples/dovecot/dovecot-ldap.conf +21 -0
- package/dist/server/engine/samples/dovecot/dovecot-share-folder.conf +22 -0
- package/dist/server/engine/samples/dovecot/dovecot-sql.conf +28 -0
- package/dist/server/engine/samples/dovecot/dovecot-used-quota.conf +13 -0
- package/dist/server/engine/samples/dovecot/dovecot.conf +484 -0
- package/dist/server/engine/samples/dovecot/dovecot.sieve +7 -0
- package/dist/server/engine/samples/dovecot/dovecot2-quota-warning.sh +38 -0
- package/dist/server/engine/samples/dovecot/sql/imap_share_folder.mysql +16 -0
- package/dist/server/engine/samples/dovecot/sql/last_login.mysql +12 -0
- package/dist/server/engine/samples/dovecot/sql/used_quota.mysql +26 -0
- package/dist/server/engine/samples/dovecot/systemd/override.conf +3 -0
- package/dist/server/engine/samples/fail2ban/action.d/banned_db.conf +9 -0
- package/dist/server/engine/samples/fail2ban/bin/fail2ban_banned_db +268 -0
- package/dist/server/engine/samples/fail2ban/fail2ban.local +17 -0
- package/dist/server/engine/samples/fail2ban/filter.d/dovecot.iredmail.conf +5 -0
- package/dist/server/engine/samples/fail2ban/filter.d/postfix-pregreet.iredmail.conf +16 -0
- package/dist/server/engine/samples/fail2ban/filter.d/postfix.iredmail.conf +18 -0
- package/dist/server/engine/samples/fail2ban/filter.d/roundcube.iredmail.conf +9 -0
- package/dist/server/engine/samples/fail2ban/jail.d/dovecot.local +8 -0
- package/dist/server/engine/samples/fail2ban/jail.d/nginx-http-auth.local +8 -0
- package/dist/server/engine/samples/fail2ban/jail.d/postfix-pregreet.local +9 -0
- package/dist/server/engine/samples/fail2ban/jail.d/postfix.local +8 -0
- package/dist/server/engine/samples/fail2ban/jail.d/roundcube.local +9 -0
- package/dist/server/engine/samples/fail2ban/jail.d/sogo.local +8 -0
- package/dist/server/engine/samples/fail2ban/jail.d/sshd.local +11 -0
- package/dist/server/engine/samples/fail2ban/jail.local +6 -0
- package/dist/server/engine/samples/fail2ban/openbsd/rc +27 -0
- package/dist/server/engine/samples/fail2ban/sql/fail2ban.mysql +49 -0
- package/dist/server/engine/samples/fail2ban/sql/fail2ban.pgsql +48 -0
- package/dist/server/engine/samples/firewall/firewalld/services/ssh.xml +6 -0
- package/dist/server/engine/samples/firewall/firewalld/zones/iredmail.xml +15 -0
- package/dist/server/engine/samples/firewall/iptables/ip6tables.init.debian +362 -0
- package/dist/server/engine/samples/firewall/iptables/ip6tables.rules +53 -0
- package/dist/server/engine/samples/firewall/iptables/iptables.init.debian +363 -0
- package/dist/server/engine/samples/firewall/iptables/iptables.rules +54 -0
- package/dist/server/engine/samples/firewall/nftables.conf +58 -0
- package/dist/server/engine/samples/freebsd/newsyslog.conf.d/dovecot.conf +3 -0
- package/dist/server/engine/samples/freebsd/newsyslog.conf.d/iredapd.conf +1 -0
- package/dist/server/engine/samples/freebsd/newsyslog.conf.d/mlmmjadmin.conf +1 -0
- package/dist/server/engine/samples/freebsd/newsyslog.conf.d/php-fpm.conf +2 -0
- package/dist/server/engine/samples/freebsd/newsyslog.conf.d/slapd.conf +1 -0
- package/dist/server/engine/samples/freebsd/syslog.d/dovecot.conf +2 -0
- package/dist/server/engine/samples/freebsd/syslog.d/fail2ban.conf +2 -0
- package/dist/server/engine/samples/freebsd/syslog.d/iredapd.conf +2 -0
- package/dist/server/engine/samples/freebsd/syslog.d/mlmmjadmin.conf +2 -0
- package/dist/server/engine/samples/freebsd/syslog.d/php-fpm.conf +2 -0
- package/dist/server/engine/samples/freebsd/syslog.d/slapd.conf +2 -0
- package/dist/server/engine/samples/iredmail/iredmail.mysql +491 -0
- package/dist/server/engine/samples/iredmail/iredmail.pgsql +465 -0
- package/dist/server/engine/samples/iredmail/iredmail.schema +456 -0
- package/dist/server/engine/samples/iredmail/used_quota_triggers_dovecot_2.3.pgsql +40 -0
- package/dist/server/engine/samples/iredmail/used_quota_triggers_dovecot_2.4.pgsql +18 -0
- package/dist/server/engine/samples/logrotate/dovecot +13 -0
- package/dist/server/engine/samples/logrotate/iredapd +13 -0
- package/dist/server/engine/samples/logrotate/mlmmjadmin +13 -0
- package/dist/server/engine/samples/logrotate/openldap +19 -0
- package/dist/server/engine/samples/logrotate/php-fpm +13 -0
- package/dist/server/engine/samples/openbsd/ldapd.conf +58 -0
- package/dist/server/engine/samples/openbsd/pf.conf +28 -0
- package/dist/server/engine/samples/postfix/command_filter.pcre +3 -0
- package/dist/server/engine/samples/postfix/freebsd/mailer.conf +9 -0
- package/dist/server/engine/samples/postfix/helo_access.pcre +180 -0
- package/dist/server/engine/samples/postfix/ldap/catchall_maps.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/recipient_bcc_maps_domain.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/recipient_bcc_maps_user.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/relay_domains.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/sender_bcc_maps_domain.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/sender_bcc_maps_user.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/sender_dependent_relayhost_maps_domain.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/sender_dependent_relayhost_maps_user.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/sender_login_maps.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/transport_maps_domain.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/transport_maps_user.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/virtual_alias_maps.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/virtual_group_maps.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/virtual_group_members_maps.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/virtual_mailbox_domains.cf +11 -0
- package/dist/server/engine/samples/postfix/ldap/virtual_mailbox_maps.cf +12 -0
- package/dist/server/engine/samples/postfix/main.cf +282 -0
- package/dist/server/engine/samples/postfix/main.cf.amavisd +7 -0
- package/dist/server/engine/samples/postfix/main.cf.dovecot +8 -0
- package/dist/server/engine/samples/postfix/main.cf.ldap +39 -0
- package/dist/server/engine/samples/postfix/main.cf.mlmmj +5 -0
- package/dist/server/engine/samples/postfix/main.cf.mysql +39 -0
- package/dist/server/engine/samples/postfix/main.cf.pgsql +39 -0
- package/dist/server/engine/samples/postfix/main.cf.postscreen +30 -0
- package/dist/server/engine/samples/postfix/master.cf +101 -0
- package/dist/server/engine/samples/postfix/mysql/catchall_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/domain_alias_catchall_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/domain_alias_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/recipient_bcc_maps_domain.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/recipient_bcc_maps_user.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/relay_domains.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/sender_bcc_maps_domain.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/sender_bcc_maps_user.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/sender_dependent_relayhost_maps.cf +6 -0
- package/dist/server/engine/samples/postfix/mysql/sender_login_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/transport_maps_domain.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/transport_maps_maillist.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/transport_maps_user.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/virtual_alias_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/virtual_mailbox_domains.cf +5 -0
- package/dist/server/engine/samples/postfix/mysql/virtual_mailbox_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/catchall_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/domain_alias_catchall_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/domain_alias_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/recipient_bcc_maps_domain.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/recipient_bcc_maps_user.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/relay_domains.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/sender_bcc_maps_domain.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/sender_bcc_maps_user.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/sender_dependent_relayhost_maps.cf +6 -0
- package/dist/server/engine/samples/postfix/pgsql/sender_login_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/transport_maps_domain.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/transport_maps_maillist.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/transport_maps_user.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/virtual_alias_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/virtual_mailbox_domains.cf +5 -0
- package/dist/server/engine/samples/postfix/pgsql/virtual_mailbox_maps.cf +5 -0
- package/dist/server/engine/samples/postfix/postscreen_access.cidr +6 -0
- package/dist/server/engine/samples/postgresql/sql/add_first_domain_and_user.sql +34 -0
- package/dist/server/engine/samples/postgresql/sql/grant_permissions.sql +14 -0
- package/dist/server/engine/samples/postgresql/sql/init_vmail_db.sql +15 -0
- package/dist/server/engine/samples/rsyslog.d/1-iredmail-dovecot.conf +23 -0
- package/dist/server/engine/samples/rsyslog.d/1-iredmail-fail2ban.conf +2 -0
- package/dist/server/engine/samples/rsyslog.d/1-iredmail-iredapd.conf +12 -0
- package/dist/server/engine/samples/rsyslog.d/1-iredmail-mlmmjadmin.conf +12 -0
- package/dist/server/engine/samples/rsyslog.d/1-iredmail-openldap.conf +2 -0
- package/dist/server/engine/samples/rsyslog.d/1-iredmail-phpfpm.conf +3 -0
- package/dist/server/engine/samples/spamassassin/local.cf +186 -0
- package/dist/server/engine/samples/spamassassin/razor.conf +1 -0
- package/dist/server/engine/samples/systemd/clamd.service.d/override.conf +2 -0
- package/dist/server/engine/samples/systemd/mariadb.service.d/override.conf +3 -0
- package/dist/server/engine/samples/systemd/slapd.service.d/override.conf +6 -0
- package/dist/server/engine/samples/yum/CentOS-Linux-AppStream.repo +6 -0
- package/dist/server/engine/samples/yum/CentOS-Linux-PowerTools.repo +6 -0
- package/dist/server/engine/samples/yum/CentOS-Stream-AppStream.repo +7 -0
- package/dist/server/engine/samples/yum/CentOS-Stream-PowerTools.repo +7 -0
- package/dist/server/engine/samples/yum/symas-openldap.repo +6 -0
- package/dist/server/engine/tools/add_enabled_service.py +60 -0
- package/dist/server/engine/tools/backup_mysql.sh +238 -0
- package/dist/server/engine/tools/backup_openldap.sh +230 -0
- package/dist/server/engine/tools/backup_pgsql.sh +217 -0
- package/dist/server/engine/tools/backup_sogo.sh +156 -0
- package/dist/server/engine/tools/create_mail_user_OpenLDAP.py +335 -0
- package/dist/server/engine/tools/create_mail_user_OpenLDAP.sh +287 -0
- package/dist/server/engine/tools/create_mail_user_SQL.sh +127 -0
- package/dist/server/engine/tools/enable_postscreen.sh +144 -0
- package/dist/server/engine/tools/fail2ban_unban_ip.sh +39 -0
- package/dist/server/engine/tools/find_sasl_login_ip.sh +20 -0
- package/dist/server/engine/tools/find_top_sasl_usernames.sh +28 -0
- package/dist/server/engine/tools/generate_ssl_keys.sh +85 -0
- package/dist/server/engine/tools/kill_high_cpu_sogo_process.sh +32 -0
- package/dist/server/engine/tools/ldap_assign_user_to_groups.py +151 -0
- package/dist/server/engine/tools/ldap_move_members_to_another_group.py +129 -0
- package/dist/server/engine/tools/migrate_sql_alias_table.py +177 -0
- package/dist/server/engine/update/0.9.8/amavisd.mysql +29 -0
- package/dist/server/engine/update/0.9.8/amavisd.pgsql +39 -0
- package/dist/server/engine/update/0.9.8/iredmail.mysql +53 -0
- package/dist/server/engine/update/0.9.8/iredmail.pgsql +61 -0
- package/dist/server/engine/update/0.9.9/iredmail.mysql +2 -0
- package/dist/server/engine/update/0.9.9/iredmail.pgsql +2 -0
- package/dist/server/engine/update/1.0/iredmail.mysql +2 -0
- package/dist/server/engine/update/1.0/iredmail.pgsql +2 -0
- package/dist/server/engine/update/1.2/last_login.mysql +16 -0
- package/dist/server/engine/update/1.4.0/iredmail.mysql +22 -0
- package/dist/server/engine/update/1.4.0/iredmail.pgsql +20 -0
- package/dist/server/engine/update/1.4.1/iredmail.mysql +3 -0
- package/dist/server/engine/update/1.4.1/iredmail.pgsql +3 -0
- package/dist/server/engine/update/1.4.1/sogo.mysql +11 -0
- package/dist/server/engine/update/1.4.1/sogo.pgsql +30 -0
- package/dist/server/engine/update/1.4.1/update-ldap.py +66 -0
- package/dist/server/engine/update/1.4.2/iredmail.mysql +9 -0
- package/dist/server/engine/update/1.4.2/iredmail.pgsql +9 -0
- package/dist/server/engine/update/1.4.2/sogo.pgsql +30 -0
- package/dist/server/engine/update/1.6.0/sogo_view.pgsql +27 -0
- package/dist/server/engine/update/1.6.3/iredmail.mysql +1 -0
- package/dist/server/engine/update/1.7.0/fail2ban.mysql +11 -0
- package/dist/server/engine/update/1.7.0/fail2ban.pgsql +12 -0
- package/dist/server/engine/update/1.7.1/amavisd.mysql +1 -0
- package/dist/server/engine/update/1.7.2/vmail.mysql +30 -0
- package/dist/server/engine/update/1.7.3/deleted_mailboxes.mysql +43 -0
- package/dist/server/engine/update/1.7.3/iredadmin.mysql +26 -0
- package/dist/server/engine/update/1.7.3/vmail.mysql +79 -0
- package/dist/server/engine/update/1.7.3/vmail.pgsql +9 -0
- package/dist/server/engine/update/README.md +1 -0
- package/dist/server/engine/update/ldap/README.md +39 -0
- package/dist/server/engine/update/ldap/update-ldap-dovecot-2.3.py +69 -0
- package/dist/server/index.js +349016 -0
- package/dist/server/lua/geo_country.lua +127 -0
- package/dist/server/lua/maxminddb.lua +403 -0
- package/dist/server/lua/mgmt_api.lua +654 -0
- package/dist/server/lua/pipe_stream.lua +103 -0
- package/dist/server/lua/rules_guard.lua +132 -0
- package/dist/server/lua/rules_lib.lua +176 -0
- package/dist/server/lua/site_logger.lua +405 -0
- package/dist/server/lua/webhook_handler.lua +126 -0
- package/dist/server/migrations/0000_init.sql +666 -0
- package/dist/server/migrations/0001_brief_tomorrow_man.sql +47 -0
- package/dist/server/migrations/0002_funny_dazzler.sql +2 -0
- package/dist/server/migrations/0003_third_killer_shrike.sql +1 -0
- package/dist/server/migrations/0004_session_active_org_not_null.sql +10 -0
- package/dist/server/migrations/0005_warm_amazoness.sql +3 -0
- package/dist/server/migrations/0006_lumpy_joystick.sql +1 -0
- package/dist/server/migrations/0007_outgoing_maginty.sql +2 -0
- package/dist/server/migrations/0008_frozen_cutover.sql +3 -0
- package/dist/server/migrations/0009_credits_billing.sql +142 -0
- package/dist/server/migrations/0010_credit_grant_dedupe.sql +14 -0
- package/dist/server/migrations/0011_remove_credit_ledger.sql +23 -0
- package/dist/server/migrations/0012_smart_deploys_and_git_rollback.sql +81 -0
- package/dist/server/migrations/0013_fix_check_run_rollup_unique.sql +38 -0
- package/dist/server/migrations/0014_default_rollback_git.sql +9 -0
- package/dist/server/migrations/0015_billing_idempotency_grants.sql +41 -0
- package/dist/server/migrations/0016_github_auth_high_findings.sql +30 -0
- package/dist/server/migrations/0017_spooky_rumiko_fujikawa.sql +6 -0
- package/dist/server/migrations/0018_calm_shatterstar.sql +1 -0
- package/dist/server/migrations/0019_rename_workspace_install_to_prepare.sql +1 -0
- package/dist/server/migrations/0020_uneven_the_renegades.sql +13 -0
- package/dist/server/migrations/0021_shiny_firestar.sql +2 -0
- package/dist/server/migrations/0022_version_on_success_backfill.sql +6 -0
- package/dist/server/migrations/0023_productive_gorilla_man.sql +17 -0
- package/dist/server/migrations/0024_sleepy_peter_quill.sql +2 -0
- package/dist/server/migrations/0025_smooth_blue_shield.sql +1 -0
- package/dist/server/migrations/0026_mail_backup_source.sql +11 -0
- package/dist/server/migrations/0027_opposite_anthem.sql +6 -0
- package/dist/server/migrations/0028_stale_rogue.sql +18 -0
- package/dist/server/migrations/0029_bouncy_loners.sql +16 -0
- package/dist/server/migrations/0030_bright_darkstar.sql +6 -0
- package/dist/server/migrations/0031_conscious_catseye.sql +13 -0
- package/dist/server/migrations/0032_wet_mimic.sql +51 -0
- package/dist/server/migrations/0033_eminent_molly_hayes.sql +2 -0
- package/dist/server/migrations/0034_nervous_surge.sql +1 -0
- package/dist/server/migrations/0035_thankful_morgan_stark.sql +1 -0
- package/dist/server/migrations/0036_gorgeous_scalphunter.sql +17 -0
- package/dist/server/migrations/0037_clever_makkari.sql +28 -0
- package/dist/server/migrations/0038_young_magneto.sql +1 -0
- package/dist/server/migrations/0039_secret_lady_ursula.sql +15 -0
- package/dist/server/migrations/0040_sharp_red_wolf.sql +16 -0
- package/dist/server/migrations/0041_round_spyke.sql +4 -0
- package/dist/server/migrations/0042_dapper_havok.sql +1 -0
- package/dist/server/migrations/0043_fast_sharon_ventura.sql +15 -0
- package/dist/server/migrations/0044_amused_shape.sql +8 -0
- package/dist/server/migrations/0045_amusing_korath.sql +1 -0
- package/dist/server/migrations/0046_white_harrier.sql +35 -0
- package/dist/server/migrations/0047_sloppy_strong_guy.sql +2 -0
- package/dist/server/migrations/0048_funny_emma_frost.sql +2 -0
- package/dist/server/migrations/0049_nappy_piledriver.sql +3 -0
- package/dist/server/migrations/0050_add_service_deployment_image_digest.sql +1 -0
- package/dist/server/migrations/0051_add_update_status.sql +19 -0
- package/dist/server/migrations/0052_add_notice_target.sql +2 -0
- package/dist/server/migrations/0053_colossal_sandman.sql +14 -0
- package/dist/server/migrations/0054_add_instance_smtp.sql +5 -0
- package/dist/server/migrations/0055_rainy_klaw.sql +22 -0
- package/dist/server/migrations/0056_moaning_daredevil.sql +2 -0
- package/dist/server/migrations/0057_complete_prism.sql +18 -0
- package/dist/server/migrations/0058_add_server_is_local.sql +1 -0
- package/dist/server/migrations/0059_legal_fixer.sql +18 -0
- package/dist/server/migrations/0060_add_route_strategy_host_port.sql +3 -0
- package/dist/server/migrations/0061_notification_default_multi_kind.sql +3 -0
- package/dist/server/migrations/0062_add_incoming_webhook.sql +21 -0
- package/dist/server/migrations/0063_add_migration_logs.sql +1 -0
- package/dist/server/migrations/0064_add_migration_partial.sql +2 -0
- package/dist/server/migrations/0065_custom_app_template.sql +14 -0
- package/dist/server/migrations/0066_ensure_migration_partial_columns.sql +2 -0
- package/dist/server/migrations/0067_webhook_delivery.sql +28 -0
- package/dist/server/migrations/0068_add_migration_target_volumes.sql +1 -0
- package/dist/server/migrations/0069_add_project_composite_routes.sql +1 -0
- package/dist/server/migrations/0070_forward_git_to_server.sql +1 -0
- package/dist/server/migrations/0071_gh_device_token.sql +3 -0
- package/dist/server/migrations/0072_gh_device_token_method.sql +1 -0
- package/dist/server/migrations/0073_project_volumes_object_storage.sql +3 -0
- package/dist/server/migrations/0074_project_compose_path.sql +1 -0
- package/dist/server/migrations/0075_service_command_argv.sql +1 -0
- package/dist/server/migrations/0076_rollback_retention.sql +17 -0
- package/dist/server/migrations/0077_domain_redirect.sql +13 -0
- package/dist/server/migrations/0078_grant_source_scope.sql +30 -0
- package/dist/server/migrations/0079_project_readiness.sql +18 -0
- package/dist/server/migrations/0080_deployment_error_classification.sql +26 -0
- package/dist/server/migrations/0081_project_readiness_repair.sql +34 -0
- package/dist/server/migrations/0082_edge_target_verification.sql +39 -0
- package/dist/server/migrations/0083_service_incident.sql +84 -0
- package/dist/server/migrations/0084_analytics_daily_rollup.sql +72 -0
- package/dist/server/migrations/0085_resource_usage.sql +68 -0
- package/dist/server/migrations/0086_remote_infra_updates.sql +41 -0
- package/dist/server/migrations/0087_server_container_version_columns.sql +17 -0
- package/dist/server/migrations/0088_audit_source_and_settings.sql +27 -0
- package/dist/server/migrations/0089_auto_scan_infra.sql +7 -0
- package/dist/server/migrations/0090_project_collect_paths.sql +18 -0
- package/dist/server/migrations/0091_project_server_id.sql +26 -0
- package/dist/server/migrations/0092_project_internal_alias.sql +13 -0
- package/dist/server/migrations/0093_service_incident_org_index.sql +13 -0
- package/dist/server/migrations/0094_backup_restore_meta.sql +15 -0
- package/dist/server/migrations/0095_backup_restore_cancel.sql +19 -0
- package/dist/server/migrations/0096_backup_policy_retention_defaults.sql +20 -0
- package/dist/server/migrations/0097_update_status_upstream_only.sql +35 -0
- package/dist/server/migrations/0098_instance_product_mode.sql +12 -0
- package/dist/server/migrations/0099_mail_webmail_project.sql +24 -0
- package/dist/server/migrations/0100_server_ssh_private_key.sql +11 -0
- package/dist/server/migrations/0101_mail_resume_step.sql +12 -0
- package/dist/server/migrations/0102_project_workload_axes.sql +19 -0
- package/dist/server/migrations/0103_dns_credential.sql +41 -0
- package/dist/server/migrations/0104_instance_host_control.sql +15 -0
- package/dist/server/migrations/0105_mail_inbound_rules.sql +80 -0
- package/dist/server/migrations/0106_mcp_call_tracking.sql +23 -0
- package/dist/server/migrations/0107_build_minute_metering_indexes.sql +20 -0
- package/dist/server/migrations/0108_credential.sql +68 -0
- package/dist/server/migrations/0109_service_build_args.sql +9 -0
- package/dist/server/migrations/0110_service_deployment_host_ports.sql +18 -0
- package/dist/server/migrations/0111_host_port_claim.sql +381 -0
- package/dist/server/migrations/0112_backup_run_execution_lease.sql +12 -0
- package/dist/server/migrations/0113_docker_migration_execution_lease.sql +11 -0
- package/dist/server/migrations/0114_build_session_execution_lease_index.sql +6 -0
- package/dist/server/migrations/0115_orphan_target_key.sql +3 -0
- package/dist/server/migrations/0116_domain_ssl_challenge.sql +2 -0
- package/dist/server/migrations/0117_github_installation_workspace_scope.sql +24 -0
- package/dist/server/migrations/0118_git_sources.sql +66 -0
- package/dist/server/migrations/0119_backup_run_batch.sql +8 -0
- package/dist/server/migrations/0120_domain_primary_unique.sql +24 -0
- package/dist/server/migrations/0121_host_port_claim_overlap.sql +14 -0
- package/dist/server/migrations/0122_data_transfer_staging.sql +45 -0
- package/dist/server/migrations/0123_drop_cloud_infra.sql +7 -0
- package/dist/server/migrations/0124_mail_dmarc_report.sql +23 -0
- package/dist/server/migrations/0125_server_security_snapshot.sql +22 -0
- package/dist/server/migrations/meta/0000_snapshot.json +4848 -0
- package/dist/server/migrations/meta/0001_snapshot.json +4991 -0
- package/dist/server/migrations/meta/0002_snapshot.json +5013 -0
- package/dist/server/migrations/meta/0003_snapshot.json +5020 -0
- package/dist/server/migrations/meta/0004_snapshot.json +5020 -0
- package/dist/server/migrations/meta/0005_snapshot.json +5039 -0
- package/dist/server/migrations/meta/0006_snapshot.json +5045 -0
- package/dist/server/migrations/meta/0007_snapshot.json +5057 -0
- package/dist/server/migrations/meta/0016_snapshot.json +6053 -0
- package/dist/server/migrations/meta/0017_snapshot.json +6091 -0
- package/dist/server/migrations/meta/0018_snapshot.json +6098 -0
- package/dist/server/migrations/meta/0019_snapshot.json +6098 -0
- package/dist/server/migrations/meta/0020_snapshot.json +6201 -0
- package/dist/server/migrations/meta/0021_snapshot.json +6213 -0
- package/dist/server/migrations/meta/0022_snapshot.json +6213 -0
- package/dist/server/migrations/meta/0023_snapshot.json +6331 -0
- package/dist/server/migrations/meta/0024_snapshot.json +6343 -0
- package/dist/server/migrations/meta/0025_snapshot.json +6350 -0
- package/dist/server/migrations/meta/0026_snapshot.json +6440 -0
- package/dist/server/migrations/meta/0027_snapshot.json +6447 -0
- package/dist/server/migrations/meta/0028_snapshot.json +6581 -0
- package/dist/server/migrations/meta/0029_snapshot.json +6710 -0
- package/dist/server/migrations/meta/0030_snapshot.json +6748 -0
- package/dist/server/migrations/meta/0031_snapshot.json +6859 -0
- package/dist/server/migrations/meta/0032_snapshot.json +7222 -0
- package/dist/server/migrations/meta/0033_snapshot.json +7249 -0
- package/dist/server/migrations/meta/0034_snapshot.json +7255 -0
- package/dist/server/migrations/meta/0035_snapshot.json +7262 -0
- package/dist/server/migrations/meta/0036_snapshot.json +7392 -0
- package/dist/server/migrations/meta/0037_snapshot.json +7602 -0
- package/dist/server/migrations/meta/0038_snapshot.json +7609 -0
- package/dist/server/migrations/meta/0039_snapshot.json +7714 -0
- package/dist/server/migrations/meta/0040_snapshot.json +7820 -0
- package/dist/server/migrations/meta/0041_snapshot.json +7833 -0
- package/dist/server/migrations/meta/0042_snapshot.json +7839 -0
- package/dist/server/migrations/meta/0043_snapshot.json +7938 -0
- package/dist/server/migrations/meta/0044_snapshot.json +7982 -0
- package/dist/server/migrations/meta/0045_snapshot.json +7989 -0
- package/dist/server/migrations/meta/0046_snapshot.json +8263 -0
- package/dist/server/migrations/meta/0047_snapshot.json +8275 -0
- package/dist/server/migrations/meta/0048_snapshot.json +8289 -0
- package/dist/server/migrations/meta/0049_snapshot.json +8308 -0
- package/dist/server/migrations/meta/0050_snapshot.json +8314 -0
- package/dist/server/migrations/meta/0051_snapshot.json +8460 -0
- package/dist/server/migrations/meta/0052_snapshot.json +8472 -0
- package/dist/server/migrations/meta/0053_snapshot.json +8556 -0
- package/dist/server/migrations/meta/0054_snapshot.json +8586 -0
- package/dist/server/migrations/meta/0055_snapshot.json +8756 -0
- package/dist/server/migrations/meta/0056_snapshot.json +8777 -0
- package/dist/server/migrations/meta/0057_snapshot.json +8904 -0
- package/dist/server/migrations/meta/0058_snapshot.json +8911 -0
- package/dist/server/migrations/meta/0059_snapshot.json +9061 -0
- package/dist/server/migrations/meta/0060_snapshot.json +9081 -0
- package/dist/server/migrations/meta/_journal.json +888 -0
- package/dist/server/pglite/pglite.data +0 -0
- package/dist/server/pglite/pglite.wasm +0 -0
- package/dist/setup-JWKZIECM.js +25 -0
- package/dist/signin-3M3UPB6K.js +667 -0
- package/dist/ssh-client-NWQVRCV7.js +29 -0
- package/dist/sso-oidc-3VDIYOEJ.js +834 -0
- package/dist/sts-B3WIYLXR.js +1426 -0
- package/dist/up-P5DMQ5YO.js +55 -0
- package/package.json +58 -0
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
-- site_logger.lua
|
|
2
|
+
-- OpenResty log_by_lua - runs AFTER the response is sent.
|
|
3
|
+
-- Pure shared-dict analytics. No Redis, no timers for counters, no batching.
|
|
4
|
+
-- Every incr() is atomic across workers.
|
|
5
|
+
--
|
|
6
|
+
-- Shared dict key schema (analytics zone):
|
|
7
|
+
-- s:{domain}:{epoch_min}:r request count (TTL 24h)
|
|
8
|
+
-- s:{domain}:{epoch_min}:i bandwidth in bytes (TTL 24h)
|
|
9
|
+
-- s:{domain}:{epoch_min}:o bandwidth out bytes (TTL 24h)
|
|
10
|
+
-- s:{domain}:{epoch_min}:t response time sum (seconds) (TTL 24h)
|
|
11
|
+
-- s:{domain}:{epoch_min}:u page (non-static) requests (TTL 24h)
|
|
12
|
+
-- c:{domain}:{epoch_min}:{CC} country per minute (TTL 24h)
|
|
13
|
+
-- t:{domain}:r / :i / :o lifetime totals (no TTL)
|
|
14
|
+
-- d:{domain} domain index marker (no TTL)
|
|
15
|
+
--
|
|
16
|
+
-- Daily rollup, all under one `g:{domain}:{YYYYMMDD}:` prefix so mgmt_api's
|
|
17
|
+
-- /analytics/geo serves the whole day in a SINGLE dict scan:
|
|
18
|
+
-- g:{domain}:{YYYYMMDD}:{CC} country hit count (TTL 48h)
|
|
19
|
+
-- g:{domain}:{YYYYMMDD}:v distinct visitors (TTL 48h)
|
|
20
|
+
-- g:{domain}:{YYYYMMDD}:p:{path} path hit count (TTL 48h)
|
|
21
|
+
-- g:{domain}:{YYYYMMDD}:s:{code} status-code count (TTL 48h)
|
|
22
|
+
--
|
|
23
|
+
-- Shared dict key schema (visitors zone):
|
|
24
|
+
-- vsalt:{YYYYMMDD} per-day hash salt (TTL 48h)
|
|
25
|
+
-- vd:{domain}:{YYYYMMDD}:{hash} distinct-visitor marker (TTL 48h)
|
|
26
|
+
--
|
|
27
|
+
-- Shared dict key schema (request_data zone):
|
|
28
|
+
-- rlog:{domain}:seq monotonic write pointer
|
|
29
|
+
-- rlog:{domain}:{slot} JSON entry (ring buf) (TTL 1h)
|
|
30
|
+
--
|
|
31
|
+
-- The ring is ALSO the live source: pipe_stream.lua's SSE endpoint reads these
|
|
32
|
+
-- slots by a per-connection cursor, so there is no separate live queue or
|
|
33
|
+
-- subscriber flag — every watcher sees the full stream and steals from none.
|
|
34
|
+
--
|
|
35
|
+
-- NOTE on `:u` — it counts non-static REQUESTS, not people. It was surfaced as
|
|
36
|
+
-- "unique IPs" all the way to the dashboard, which it never was. Real distinct
|
|
37
|
+
-- visitors are the `vd:`/`:v` pair below.
|
|
38
|
+
|
|
39
|
+
local cjson = require "cjson.safe"
|
|
40
|
+
|
|
41
|
+
-- SAFE LOAD: GeoIP Module (per-worker, cached by require)
|
|
42
|
+
local geo_ok, geo = pcall(require, "kraft.geo_country")
|
|
43
|
+
if not geo_ok then
|
|
44
|
+
geo = nil
|
|
45
|
+
ngx.log(ngx.WARN, "[site_logger] geo_country module not available. GeoIP disabled.")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
local analytics = ngx.shared.analytics
|
|
49
|
+
local request_data = ngx.shared.request_data
|
|
50
|
+
-- Per-host edge config, pushed by the API (see mgmt_api's /analytics/config).
|
|
51
|
+
--
|
|
52
|
+
-- The `rules` zone, NOT `analytics`: this holds a handful of small config values and is
|
|
53
|
+
-- never under eviction pressure, whereas the analytics zone is a 256 MB churn of counters.
|
|
54
|
+
-- An evicted flag there would silently stop path collection with nothing to explain why.
|
|
55
|
+
local rules_dict = ngx.shared.rules
|
|
56
|
+
-- Optional: a box whose nginx.conf predates this zone keeps working, just without
|
|
57
|
+
-- distinct-visitor counts. Never assume a dict exists.
|
|
58
|
+
local visitors = ngx.shared.visitors
|
|
59
|
+
if not analytics or not request_data then return end
|
|
60
|
+
|
|
61
|
+
-- ── Helpers ──────────────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
local function normalize(host)
|
|
64
|
+
if not host then return nil end
|
|
65
|
+
local h = host:lower()
|
|
66
|
+
if h:sub(1, 4) == "www." then h = h:sub(5) end
|
|
67
|
+
return h
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
local _day = { str = "", ts = 0 }
|
|
71
|
+
local function today()
|
|
72
|
+
local now = ngx.now()
|
|
73
|
+
if now - _day.ts > 60 then
|
|
74
|
+
_day.str = os.date("!%Y%m%d", now)
|
|
75
|
+
_day.ts = now
|
|
76
|
+
end
|
|
77
|
+
return _day.str
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
-- Fast check if URI is a static asset (for unique_requests counter)
|
|
81
|
+
local function is_static_asset(u)
|
|
82
|
+
local lower = u:lower()
|
|
83
|
+
|
|
84
|
+
-- Static file extensions
|
|
85
|
+
if lower:match("%.js$") or lower:match("%.css$") or
|
|
86
|
+
lower:match("%.jpg$") or lower:match("%.jpeg$") or
|
|
87
|
+
lower:match("%.png$") or lower:match("%.gif$") or
|
|
88
|
+
lower:match("%.svg$") or lower:match("%.webp$") or
|
|
89
|
+
lower:match("%.ico$") or lower:match("%.bmp$") or
|
|
90
|
+
lower:match("%.woff2?$") or lower:match("%.ttf$") or
|
|
91
|
+
lower:match("%.eot$") or lower:match("%.otf$") or
|
|
92
|
+
lower:match("%.mp4$") or lower:match("%.webm$") or
|
|
93
|
+
lower:match("%.mp3$") or lower:match("%.wav$") or
|
|
94
|
+
lower:match("%.pdf$") or lower:match("%.zip$") or
|
|
95
|
+
lower:match("%.tar$") or lower:match("%.gz$") or
|
|
96
|
+
lower:match("%.xml$") or lower:match("%.json$") or
|
|
97
|
+
lower:match("%.txt$") or lower:match("%.map$") then
|
|
98
|
+
return true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
-- Common static paths
|
|
102
|
+
if lower:match("^/_next/static/") or
|
|
103
|
+
lower:match("^/static/") or
|
|
104
|
+
lower:match("^/assets/") or
|
|
105
|
+
lower:match("^/public/") or
|
|
106
|
+
lower:match("/favicon%.ico") then
|
|
107
|
+
return true
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
return false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
-- Collapse a request URI into a low-cardinality bucket suitable as a dict key.
|
|
114
|
+
-- Without this, "top paths" is unbounded: every ?token=, every /orders/48219, and
|
|
115
|
+
-- every 404 a scanner probes mints a permanent key, and the analytics zone
|
|
116
|
+
-- LRU-evicts real counters to store junk.
|
|
117
|
+
local function normalize_path(u)
|
|
118
|
+
-- Query string carries ids/tokens and never identifies the route.
|
|
119
|
+
local path = u:match("^([^?#]*)") or u
|
|
120
|
+
if path == "" then return "/" end
|
|
121
|
+
-- Numeric and UUID/hex segments are ids, not routes: /orders/48219 and
|
|
122
|
+
-- /orders/48220 are one path.
|
|
123
|
+
path = path:gsub("/%d+", "/:id")
|
|
124
|
+
path = path:gsub("/%x%x%x%x%x%x%x%x%-?%x*%-?%x*%-?%x*%-?%x*", "/:id")
|
|
125
|
+
-- Bound the key itself — a long URI must not become a long key.
|
|
126
|
+
if #path > 120 then path = path:sub(1, 120) .. "…" end
|
|
127
|
+
return path
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
-- Raw request telemetry must never retain credentials from a URL. Query
|
|
131
|
+
-- strings routinely carry OAuth codes, signed URLs and tokens, so exclude them
|
|
132
|
+
-- completely. Invitation claim ids are bearer credentials in the path itself;
|
|
133
|
+
-- collapse those two known routes before either top-path aggregation or the
|
|
134
|
+
-- one-hour request ring can observe them.
|
|
135
|
+
local function telemetry_uri(u)
|
|
136
|
+
local path = u:match("^([^?#]*)") or "/"
|
|
137
|
+
if path == "" then return "/" end
|
|
138
|
+
if path:match("^/accept%-invite/[^/]+") then
|
|
139
|
+
return "/accept-invite/:token"
|
|
140
|
+
end
|
|
141
|
+
if path:match("^/api/auth/invitation%-preview/[^/]+") then
|
|
142
|
+
return "/api/auth/invitation-preview/:token"
|
|
143
|
+
end
|
|
144
|
+
return path
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
-- ── Enumerable sets, without a zone scan ─────────────────────────────────────
|
|
148
|
+
--
|
|
149
|
+
-- Reading these counters back used to need key DISCOVERY, and a shared dict offers exactly
|
|
150
|
+
-- one mechanism for that: `get_keys`, which walks EVERY key in the zone holding its lock.
|
|
151
|
+
-- Cost scaled with how much was in the 256 MB zone, not with what was being asked for, and
|
|
152
|
+
-- it ran on the mgmt path four different ways.
|
|
153
|
+
--
|
|
154
|
+
-- So every unbounded set now carries its own index: a counter plus numbered slots.
|
|
155
|
+
--
|
|
156
|
+
-- <counter> how many distinct members
|
|
157
|
+
-- <prefix><n> the n-th member
|
|
158
|
+
--
|
|
159
|
+
-- A reader reads the counter and then reads slots 1..n. Bounded by the answer.
|
|
160
|
+
--
|
|
161
|
+
-- The write only happens on a member's FIRST sighting, so steady state costs nothing: the
|
|
162
|
+
-- millionth request from Germany today takes the plain `incr` path and touches no index.
|
|
163
|
+
local function index_add(counter_key, slot_prefix, member, ttl)
|
|
164
|
+
local n = analytics:incr(counter_key, 1, 0, ttl)
|
|
165
|
+
if n then analytics:set(slot_prefix .. n, member, ttl) end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
--- Add 1 to a counter, creating it (with TTL) and indexing it on first sighting.
|
|
169
|
+
--
|
|
170
|
+
-- `incr` with no `init` returns nil for an absent key, which doubles as the existence
|
|
171
|
+
-- probe — so the common case is ONE hash operation. TTL is set by the creating `safe_add`
|
|
172
|
+
-- rather than passed to `incr`: shdict rejects `init_ttl` without `init`, and that raises a
|
|
173
|
+
-- Lua error which aborts the whole log handler (it has silently zeroed every counter below
|
|
174
|
+
-- it before).
|
|
175
|
+
local function bump_indexed(key, ttl, counter_key, slot_prefix, member)
|
|
176
|
+
if analytics:incr(key, 1) then return end
|
|
177
|
+
if analytics:safe_add(key, 1, ttl) then
|
|
178
|
+
index_add(counter_key, slot_prefix, member, ttl)
|
|
179
|
+
else
|
|
180
|
+
-- Another worker created it between our probe and our add; our +1 still counts.
|
|
181
|
+
analytics:incr(key, 1)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
local RING = 1000
|
|
186
|
+
local D24H = 86400
|
|
187
|
+
local D48H = 172800
|
|
188
|
+
local D1H = 3600
|
|
189
|
+
|
|
190
|
+
-- Distinct paths tracked per domain per day. Past this the tail folds into
|
|
191
|
+
-- "other" rather than growing the zone — a URL-fuzzing bot is capped at one
|
|
192
|
+
-- extra key, not thousands.
|
|
193
|
+
local PATH_CARDINALITY_CAP = 2000
|
|
194
|
+
|
|
195
|
+
-- ── Capture ──────────────────────────────────────────────────────────────────
|
|
196
|
+
|
|
197
|
+
local host = normalize(ngx.var.host)
|
|
198
|
+
if not host then return end
|
|
199
|
+
|
|
200
|
+
local ip = ngx.var.remote_addr or "0.0.0.0"
|
|
201
|
+
local ts = ngx.now()
|
|
202
|
+
local ua = ngx.var.http_user_agent or ""
|
|
203
|
+
local uri = telemetry_uri(ngx.var.request_uri or "/")
|
|
204
|
+
local req_len = tonumber(ngx.var.request_length) or 0
|
|
205
|
+
local bytes = tonumber(ngx.var.bytes_sent) or 0
|
|
206
|
+
local rt = tonumber(ngx.var.request_time) or 0 -- seconds (float)
|
|
207
|
+
local method = ngx.var.request_method or "GET"
|
|
208
|
+
local status = ngx.var.status or "0"
|
|
209
|
+
|
|
210
|
+
-- Client country, resolved ONCE per request.
|
|
211
|
+
--
|
|
212
|
+
-- Hoisted out of the geo block because both the daily/per-minute rollups and the raw
|
|
213
|
+
-- ring buffer need it. The ring is the single source for the request log — /logs/recent
|
|
214
|
+
-- reads it directly and the live SSE stream (pipe_stream.lua) reads the same slots by
|
|
215
|
+
-- cursor — so resolving the country here means every row carries its flag no matter
|
|
216
|
+
-- which path delivered it. An earlier split (looked up in the rollup, again in a
|
|
217
|
+
-- separate live pipe) left the ring with no country at all.
|
|
218
|
+
--
|
|
219
|
+
-- pcall'd because a corrupt or partially-written mmdb makes the lookup raise, and an
|
|
220
|
+
-- error here would abort every counter below it (see the section header).
|
|
221
|
+
local cc = nil
|
|
222
|
+
if geo and geo.get_country_code then
|
|
223
|
+
local ok_cc, res = pcall(geo.get_country_code, ip)
|
|
224
|
+
if ok_cc and type(res) == "string" and res ~= "" then cc = res end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
-- ── 1. Minute-bucket counters ────────────────────────────────────────────────
|
|
228
|
+
|
|
229
|
+
local minute = math.floor(ts / 60)
|
|
230
|
+
local p = "s:" .. host .. ":" .. minute
|
|
231
|
+
|
|
232
|
+
analytics:incr(p .. ":r", 1, 0, D24H)
|
|
233
|
+
analytics:incr(p .. ":i", req_len, 0, D24H)
|
|
234
|
+
analytics:incr(p .. ":o", bytes, 0, D24H)
|
|
235
|
+
|
|
236
|
+
-- Response time as float seconds (matches original precision)
|
|
237
|
+
if rt > 0 then
|
|
238
|
+
-- safe_add initializes, incr adds - emulate HINCRBYFLOAT with integer micros
|
|
239
|
+
local rt_us = math.floor(rt * 1000000)
|
|
240
|
+
analytics:incr(p .. ":t", rt_us, 0, D24H)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
-- Unique (non-static) request counter
|
|
244
|
+
if not is_static_asset(uri) then
|
|
245
|
+
analytics:incr(p .. ":u", 1, 0, D24H)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
-- ── 2. Lifetime totals ──────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
analytics:incr("t:" .. host .. ":r", 1, 0)
|
|
251
|
+
analytics:incr("t:" .. host .. ":i", req_len, 0)
|
|
252
|
+
analytics:incr("t:" .. host .. ":o", bytes, 0)
|
|
253
|
+
|
|
254
|
+
-- Domain index. `safe_add` returning true means this is the first request this box has
|
|
255
|
+
-- ever seen for the host, which is exactly when the enumerable index needs appending —
|
|
256
|
+
-- so domain discovery no longer costs a zone scan either.
|
|
257
|
+
if analytics:safe_add("d:" .. host, 1) then
|
|
258
|
+
index_add("dn", "di:", host)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
-- ── 3. Daily rollup: geo, visitors, paths, statuses ──────────────────────────
|
|
262
|
+
--
|
|
263
|
+
-- Each sub-block is pcall'd SEPARATELY, and that is load-bearing rather than
|
|
264
|
+
-- defensive habit. A raised error in log_by_lua aborts the remainder of the
|
|
265
|
+
-- handler, so one bad shdict call silently zeroes every counter written after it —
|
|
266
|
+
-- which is exactly what an `incr(..., nil, ttl)` here did: paths AND statuses read
|
|
267
|
+
-- as "no traffic" while requests and bandwidth looked perfect. Isolating them
|
|
268
|
+
-- means a future edit can lose at most its own metric.
|
|
269
|
+
|
|
270
|
+
local day = today()
|
|
271
|
+
local gpfx = "g:" .. host .. ":" .. day .. ":"
|
|
272
|
+
|
|
273
|
+
-- 3a. GeoIP. `cc` was resolved once above and is reused by the ring buffer and the
|
|
274
|
+
-- live pipe, so a request costs exactly one mmdb lookup no matter how many consumers
|
|
275
|
+
-- report its country.
|
|
276
|
+
if cc then
|
|
277
|
+
pcall(function()
|
|
278
|
+
-- Daily geo (for /analytics/geo endpoint)
|
|
279
|
+
bump_indexed(gpfx .. cc, D48H, gpfx .. "cn", gpfx .. "ci:", cc)
|
|
280
|
+
-- Per-minute geo (for the time-series country breakdown). Indexed per MINUTE, so
|
|
281
|
+
-- the scraper reads only the minutes in its window.
|
|
282
|
+
local mpfx = "c:" .. host .. ":" .. minute .. ":"
|
|
283
|
+
bump_indexed(mpfx .. cc, D24H, mpfx .. "n", mpfx .. "i:", cc)
|
|
284
|
+
end)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
-- 3b. Distinct visitors — a COUNT, never an identity.
|
|
288
|
+
--
|
|
289
|
+
-- The address is hashed with a salt that is generated on this box, rotates daily,
|
|
290
|
+
-- and is never written anywhere but this shared dict, so the marker keys are not
|
|
291
|
+
-- reversible to an IP and are worthless the next day. Only the resulting counter
|
|
292
|
+
-- is ever flushed to Postgres; no per-visitor row exists at any layer. That is
|
|
293
|
+
-- what lets us report real visitor numbers while still not collecting behavioural
|
|
294
|
+
-- analytics on anyone's end users.
|
|
295
|
+
--
|
|
296
|
+
-- Per DAY, not per minute: a per-minute set is ~1440x the keys for a number
|
|
297
|
+
-- nobody reads, and would evict the counters it exists to annotate.
|
|
298
|
+
pcall(function()
|
|
299
|
+
if visitors then
|
|
300
|
+
local salt_key = "vsalt:" .. day
|
|
301
|
+
local salt = visitors:get(salt_key)
|
|
302
|
+
if not salt then
|
|
303
|
+
-- First writer wins; a racing worker's safe_add fails and it re-reads. The
|
|
304
|
+
-- salt only has to be unpredictable and stable for the day.
|
|
305
|
+
salt = tostring(ngx.now()) .. tostring(math.random(1, 2147483647))
|
|
306
|
+
local ok = visitors:safe_add(salt_key, salt, D48H)
|
|
307
|
+
if not ok then salt = visitors:get(salt_key) or salt end
|
|
308
|
+
end
|
|
309
|
+
-- safe_add is the dedup: it succeeds ONLY on this visitor's first request
|
|
310
|
+
-- today, so the counter below increments exactly once per distinct visitor.
|
|
311
|
+
local marker = "vd:" .. host .. ":" .. day .. ":" .. ngx.crc32_long(salt .. ip)
|
|
312
|
+
if visitors:safe_add(marker, 1, D48H) then
|
|
313
|
+
analytics:incr(gpfx .. "v", 1, 0, D48H)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end)
|
|
317
|
+
|
|
318
|
+
-- 3c. Top paths — OPT-IN, non-static only, normalized and cardinality-capped.
|
|
319
|
+
--
|
|
320
|
+
-- Off unless the project turned it on, because this one block is the most expensive thing
|
|
321
|
+
-- the log handler does. Measured on the shipped edge image, per request:
|
|
322
|
+
--
|
|
323
|
+
-- paths (whole block) 1.72 us <- 57% of the counter path
|
|
324
|
+
-- of which string work 1.38 us normalize_path + is_static_asset
|
|
325
|
+
-- minute buckets (5 incr) 0.61 us
|
|
326
|
+
-- country (2 incr) 0.24 us
|
|
327
|
+
-- status (1 incr) 0.14 us
|
|
328
|
+
-- this flag read (1 get) 0.07 us
|
|
329
|
+
--
|
|
330
|
+
-- So the gate costs 0.07 us and saves 1.72 us — the counter path drops from ~3.0 us to
|
|
331
|
+
-- ~1.35 us with paths off. It is also the highest-cardinality dimension (up to
|
|
332
|
+
-- PATH_CARDINALITY_CAP keys per domain per day, against ~200 countries and a few dozen
|
|
333
|
+
-- statuses) and the largest column in the daily rollup.
|
|
334
|
+
--
|
|
335
|
+
-- Absent flag = off. A box whose dict was just restarted therefore collects nothing until
|
|
336
|
+
-- the API re-pushes, which is the safe direction: no data beats data nobody asked to pay
|
|
337
|
+
-- for. The DB is the source of truth and re-pushes on every route apply.
|
|
338
|
+
local collect_paths = rules_dict and rules_dict:get("cfg:" .. host .. ":paths")
|
|
339
|
+
|
|
340
|
+
pcall(function()
|
|
341
|
+
if collect_paths and not is_static_asset(uri) then
|
|
342
|
+
-- Hoisted: normalize_path is the single most expensive call in this handler (~1.4 us
|
|
343
|
+
-- of string work), so it runs exactly once even though both the counter key and the
|
|
344
|
+
-- index slot need its result.
|
|
345
|
+
local norm = normalize_path(uri)
|
|
346
|
+
local path_key = gpfx .. "p:" .. norm
|
|
347
|
+
-- incr-then-add: the hot path is ONE hash hit on an existing key. `incr` with
|
|
348
|
+
-- no init returns nil for an absent key, which doubles as the existence probe,
|
|
349
|
+
-- so only a path unseen today reaches the cap check below.
|
|
350
|
+
--
|
|
351
|
+
-- Deliberately no init_ttl here: shdict rejects init_ttl unless init is also
|
|
352
|
+
-- given ("'init_ttl' must be used with 'init'"), and that raises a Lua error
|
|
353
|
+
-- which aborts the whole log handler — taking the status counters below down
|
|
354
|
+
-- with it. The TTL is set by the safe_add on the creating request instead.
|
|
355
|
+
if not analytics:incr(path_key, 1) then
|
|
356
|
+
local distinct = analytics:incr(gpfx .. "pn", 1, 0, D48H) or 0
|
|
357
|
+
if distinct > PATH_CARDINALITY_CAP then
|
|
358
|
+
analytics:incr(gpfx .. "p:other", 1, 0, D48H)
|
|
359
|
+
else
|
|
360
|
+
-- `pn` was already the distinct-path counter, so the slots just give it an
|
|
361
|
+
-- enumerable side. Stored WITHOUT the "p:" prefix; the reader adds it back.
|
|
362
|
+
if analytics:safe_add(path_key, 1, D48H) then
|
|
363
|
+
analytics:set(gpfx .. "pi:" .. distinct, norm, D48H)
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
end)
|
|
369
|
+
|
|
370
|
+
-- 3d. Status-code mix. Bounded by construction (a few dozen codes).
|
|
371
|
+
pcall(function()
|
|
372
|
+
bump_indexed(gpfx .. "s:" .. status, D48H, gpfx .. "sn", gpfx .. "si:", status)
|
|
373
|
+
end)
|
|
374
|
+
|
|
375
|
+
-- ── 4. Raw request ring buffer (also the live SSE source) ────────────────────
|
|
376
|
+
--
|
|
377
|
+
-- `seq` is claimed BEFORE encoding so the stored JSON can carry a deterministic
|
|
378
|
+
-- id (`{host}:{seq}`). That id is the dedup key everywhere downstream: /logs/recent
|
|
379
|
+
-- returns these entries verbatim, and pipe_stream.lua streams the same slots live,
|
|
380
|
+
-- so the same request reaches the client with one stable id instead of a fresh
|
|
381
|
+
-- random one per source. `incr` with init 0 never returns nil here; guard anyway
|
|
382
|
+
-- so a shdict hiccup can't index a nil into the slot key.
|
|
383
|
+
|
|
384
|
+
pcall(function()
|
|
385
|
+
local seq = request_data:incr("rlog:" .. host .. ":seq", 1, 0)
|
|
386
|
+
if not seq then return end
|
|
387
|
+
local ok_j, j = pcall(cjson.encode, {
|
|
388
|
+
id = host .. ":" .. seq,
|
|
389
|
+
ip = ip,
|
|
390
|
+
-- nil is simply omitted by cjson, so a box with no GeoIP writes the same shape
|
|
391
|
+
-- minus this key rather than a null the reader has to special-case.
|
|
392
|
+
country = cc,
|
|
393
|
+
ts = ts,
|
|
394
|
+
method = method,
|
|
395
|
+
status = status,
|
|
396
|
+
uri = uri,
|
|
397
|
+
ua = ua,
|
|
398
|
+
bw_in = req_len,
|
|
399
|
+
bw_out = bytes,
|
|
400
|
+
rt = rt,
|
|
401
|
+
})
|
|
402
|
+
if ok_j and j then
|
|
403
|
+
request_data:set("rlog:" .. host .. ":" .. (seq % RING), j, D1H)
|
|
404
|
+
end
|
|
405
|
+
end)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
-- webhook_handler.lua
|
|
2
|
+
-- Handles incoming webhook events forwarded from the SaaS edge.
|
|
3
|
+
-- Internal management port only (127.0.0.1:9145).
|
|
4
|
+
--
|
|
5
|
+
-- Routes:
|
|
6
|
+
-- POST /_hooks/push - receive a forwarded GitHub push event
|
|
7
|
+
-- GET /_hooks/pending - fetch stored events (for local app polling)
|
|
8
|
+
-- POST /_hooks/ack - acknowledge consumed events
|
|
9
|
+
--
|
|
10
|
+
-- Behavior on POST /_hooks/push:
|
|
11
|
+
-- 1. Try to proxy to a local Kraft API (configurable via X-Kraft-Url header)
|
|
12
|
+
-- 2. If Kraft is not reachable, store the event in shared dict for later polling
|
|
13
|
+
|
|
14
|
+
local cjson = require "cjson.safe"
|
|
15
|
+
|
|
16
|
+
local webhook_events = ngx.shared.webhook_events
|
|
17
|
+
local uri = ngx.var.uri
|
|
18
|
+
local method = ngx.req.get_method()
|
|
19
|
+
|
|
20
|
+
local function json_response(data, code)
|
|
21
|
+
ngx.status = code or 200
|
|
22
|
+
ngx.header["Content-Type"] = "application/json"
|
|
23
|
+
ngx.say(cjson.encode(data))
|
|
24
|
+
return ngx.exit(ngx.status)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
-- ── POST /_hooks/push ────────────────────────────────────────────────────────
|
|
28
|
+
-- Receives forwarded webhook payload from SaaS.
|
|
29
|
+
-- Headers:
|
|
30
|
+
-- X-Kraft-Url: http://127.0.0.1:3456 (if Kraft runs on this server)
|
|
31
|
+
-- X-Hook-Id: the subscription hookId (for correlation)
|
|
32
|
+
|
|
33
|
+
if uri == "/_hooks/push" and method == "POST" then
|
|
34
|
+
ngx.req.read_body()
|
|
35
|
+
local body = ngx.req.get_body_data()
|
|
36
|
+
if not body then
|
|
37
|
+
return json_response({ error = "empty body" }, 400)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
local kraft_url = ngx.req.get_headers()["x-kraft-url"]
|
|
41
|
+
|
|
42
|
+
-- If Kraft runs on this server, proxy directly
|
|
43
|
+
if kraft_url and kraft_url ~= "" then
|
|
44
|
+
local http = require "resty.http"
|
|
45
|
+
local httpc = http.new()
|
|
46
|
+
httpc:set_timeout(5000)
|
|
47
|
+
|
|
48
|
+
local target = kraft_url .. "/api/webhooks/push"
|
|
49
|
+
local res, err = httpc:request_uri(target, {
|
|
50
|
+
method = "POST",
|
|
51
|
+
body = body,
|
|
52
|
+
headers = {
|
|
53
|
+
["Content-Type"] = "application/json",
|
|
54
|
+
["X-Hook-Id"] = ngx.req.get_headers()["x-hook-id"] or "",
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if res and res.status < 500 then
|
|
59
|
+
-- Kraft handled it (2xx or 4xx)
|
|
60
|
+
return json_response({ ok = true, proxied = true, status = res.status })
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
-- Kraft unreachable or errored - fall through to store
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
-- Store for later polling by local/desktop app
|
|
67
|
+
local event_id = ngx.now() .. ":" .. math.random(100000, 999999)
|
|
68
|
+
local event = cjson.encode({
|
|
69
|
+
id = event_id,
|
|
70
|
+
hook_id = ngx.req.get_headers()["x-hook-id"] or "",
|
|
71
|
+
payload = body,
|
|
72
|
+
received = ngx.now(),
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
-- Use a slot-based ring buffer (max 200 events)
|
|
76
|
+
local max_events = 200
|
|
77
|
+
local idx = webhook_events:incr("_idx", 1, 0) or 0
|
|
78
|
+
local slot = (idx % max_events)
|
|
79
|
+
webhook_events:set("evt:" .. slot, event, 3600) -- 1h TTL
|
|
80
|
+
webhook_events:set("_count", math.min(idx, max_events))
|
|
81
|
+
|
|
82
|
+
return json_response({ ok = true, stored = true, event_id = event_id })
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
-- ── GET /_hooks/pending ──────────────────────────────────────────────────────
|
|
86
|
+
-- Returns stored webhook events for local app to consume.
|
|
87
|
+
|
|
88
|
+
if uri == "/_hooks/pending" and method == "GET" then
|
|
89
|
+
if not webhook_events then
|
|
90
|
+
return json_response({ events = {} })
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
local count = webhook_events:get("_count") or 0
|
|
94
|
+
local idx = webhook_events:get("_idx") or 0
|
|
95
|
+
local events = {}
|
|
96
|
+
|
|
97
|
+
-- Read all stored events (newest first)
|
|
98
|
+
local max_events = 200
|
|
99
|
+
local start = math.max(0, idx - count)
|
|
100
|
+
for i = start, idx - 1 do
|
|
101
|
+
local slot = i % max_events
|
|
102
|
+
local raw = webhook_events:get("evt:" .. slot)
|
|
103
|
+
if raw then
|
|
104
|
+
local parsed = cjson.decode(raw)
|
|
105
|
+
if parsed then
|
|
106
|
+
events[#events + 1] = parsed
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
return json_response({ events = events })
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
-- ── POST /_hooks/ack ─────────────────────────────────────────────────────────
|
|
115
|
+
-- Acknowledge events have been consumed - clears the store.
|
|
116
|
+
|
|
117
|
+
if uri == "/_hooks/ack" and method == "POST" then
|
|
118
|
+
if webhook_events then
|
|
119
|
+
webhook_events:flush_all()
|
|
120
|
+
webhook_events:flush_expired()
|
|
121
|
+
end
|
|
122
|
+
return json_response({ ok = true })
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
-- ── Fallback ─────────────────────────────────────────────────────────────────
|
|
126
|
+
return json_response({ error = "not found" }, 404)
|