Skip to content

docker: comprehensive config template pass - #58

Draft
MrLenin wants to merge 9 commits into
evilnet:masterfrom
MrLenin:docker-template-completions
Draft

docker: comprehensive config template pass#58
MrLenin wants to merge 9 commits into
evilnet:masterfrom
MrLenin:docker-template-completions

Conversation

@MrLenin

@MrLenin MrLenin commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Expands the Docker config template from 19 env placeholders to 63, so real deployments can configure X3 without shipping a hand-edited conf. Grew out of two stragglers from #52 (ldap_writeback was never templatized — the LDAP Docker support couldn't actually enable write-back from env) into a full audit of x3.conf-dist vs x3.conf.example.

Fixes (behavior-affecting):

  • server.type was hardcoded 8 (Nefarious 1.3.x protocol mode) — now X3_SERVER_TYPE, so Nefarious 2.0.x deployments can run type 9 as documented.
  • qserver.password "hello" shipped a literal credential — now generated randomly at container start unless overridden.
  • mail.enable claimed 1 while the image ships no MTA at /usr/sbin/sendmail — defaults to 0 now; mailer/smtp_server/smtp_service are templatized for images that add one.
  • sockcheck's bogus bind_address 192.168.0.10 commented out.
  • Entrypoint sed substitution escaped only / and & while using | as delimiter — a value containing | (e.g. an LDAP filter) silently corrupted the conf. Backslash/delimiter escaping fixed; verified with (|(a=b)(c=d))-style adversarial values.

Templatized (defaults = previous literals, zero behavior change): server host-hiding type/keys/prefix (with a change-in-production warning on the stock keys), all service nicks, nickserv limits + email settings + password policy + auto_oper(+privs), the rest of the LDAP block incl. the previously-missing ldap_field_oslevel/ldap_filter keys, opserv channels + hostname + clone_gline_duration, chanserv off_channel/limits/support_channel, modules (sockcheck, snoop, track, memoserv, blacklist), mail branding (now derives consistently from the domain instead of leftover "AfterNET.Org"/"NET" literals), db save frequency, log channel targets.

Every commit was gated by a harness that regenerates the conf with default env and asserts byte-identity to the pre-pass output except the intended changes above.

🤖 Generated with Claude Code

…docker)

nickserv.c register gates ldap_do_add on ldap_enable && ldap_admin_dn &&
ldap_writeback. The LDAP-docker templatization (b38ab2e) set ldap_enable etc. but
never ldap_writeback, so it defaulted off — registrations landed in saxdb only
(credential-less) and LDAP-authoritative SASL failed. Add %X3_LDAP_WRITEBACK%
placeholder + X3_LDAP_WRITEBACK:=0 default.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@MrLenin
MrLenin force-pushed the docker-template-completions branch from 2de9699 to 4476eb0 Compare August 1, 2026 06:43
MrLenin and others added 7 commits August 1, 2026 02:54
untrusted_max was hardcoded to 6 in x3.conf-dist, so any deployment using
the docker template inherits the stock clone-G-line: a host exceeding 6
connections is auto-G-lined for clone_gline_duration (2h).  On a testbed
where a harness opens many connections from a single host, this auto-G-lines
that host and the network appears dead (SASL/oper/link attempts all rejected)
until the G-line expires — recurring on every heavy test run.

Make it env-templated like the other X3_* settings: x3.conf-dist uses
%X3_UNTRUSTED_MAX%, dockerentrypoint.sh defaults it to 6 (stock behavior
preserved for normal deployments).  A testbed sets X3_UNTRUSTED_MAX=0
(0 disables the clone-G-line entirely, per opserv.c) in its env so harness
connection volume from one host is no longer auto-G-lined.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The substitution loop uses '|' as the sed s/// delimiter but only escaped
'/' and '&' in replacement values.  A value containing '|' (any non-trivial
LDAP filter, e.g. "(|(a=b)(c=d))") terminated the replacement early and
corrupted the generated conf silently; a backslash was mis-handled too.

Escape backslash FIRST (so the escapes added next are not re-escaped),
then '&' and the '|' delimiter.  '/' needs no escaping under a '|'
delimiter.  The empty-value warning behavior is unchanged, and the script
stays bash -n clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Templatize the remaining hardcoded server-block identity settings:

  type             -> %X3_SERVER_TYPE%        (default 8)
  hidden_host_type -> %X3_HIDDEN_HOST_TYPE%   (default 1)
  key1/key2/key3   -> %X3_HIDDEN_HOST_KEY1/2/3% (defaults 45432/76934/98336)
  prefix           -> %X3_HIDDEN_HOST_PREFIX% (default NETWORK)

Defaults preserve the shipped literals, so generated output is unchanged
apart from two new comments: the type line now notes 8 = Nefarious 1.3.x /
9 = Nefarious 2.0.x (must match your ircd), and the key lines warn that
they MUST match the ircd's HOST_HIDING_KEY* F:lines and that stock keys
make style-2 cloaks predictable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Templatize the remaining hardcoded nickserv (AuthServ) settings:

  nick                -> %X3_NICKSERV_NICK%      (AuthServ)
  default_maxlogins   -> %X3_DEFAULT_MAXLOGINS%  (3)
  hard_maxlogins      -> %X3_HARD_MAXLOGINS%     (10)
  auto_oper           -> %X3_AUTO_OPER%          (+oxwgs)
  auto_oper_privs     -> %X3_AUTO_OPER_PRIVS%    (current literal, verbatim)
  password_min_length -> %X3_PASSWD_MIN_LENGTH%  (4)
  password_min_digits/_upper/_lower -> %X3_PASSWD_MIN_DIGITS/UPPER/LOWER% (0/0/0)
  email_enabled       -> %X3_EMAIL_ENABLED%      (0)
  email_required      -> %X3_EMAIL_REQUIRED%     (0)
  cookie_timeout      -> %X3_COOKIE_TIMEOUT%     (2d)
  accounts_per_email  -> %X3_ACCOUNTS_PER_EMAIL% (1)
  titlehost_suffix    -> %X3_TITLEHOST_SUFFIX%   (derives from X3_GENERAL_DOMAIN,
                         replacing the hardcoded AfterNET.Org branding)
  ldap_autocreate     -> %X3_LDAP_AUTOCREATE%    (1)
  ldap_timeout        -> %X3_LDAP_TIMEOUT%       (10)

Also ADD two LDAP keys that exist in x3.conf.example but were missing from
the dist, so their env vars actually take effect:

  "ldap_field_oslevel" "%X3_LDAP_FIELD_OSLEVEL%";  (X3AccountLevel)
  "ldap_filter"        "%X3_LDAP_FILTER%";         ((objectClass=inetOrgPerson))

Deliberately NOT added: ldap_oper_group_dn / ldap_oper_group_level /
ldap_field_group_member — they are commented in the example and their
empty-default semantics are unclear; adding them with a bogus default
could enable oper-group writeback unintentionally.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Templatize the remaining service-identity settings and their companion
limits (defaults preserve the shipped literals; generated output is
byte-identical):

  opserv nick          -> %X3_OPSERV_NICK%          (O3)
  opserv hostname      -> %X3_OPSERV_HOSTNAME%      (X3.Services)
  debug_channel        -> %X3_DEBUG_CHANNEL%        (#TheOps)
  alert_channel        -> %X3_ALERT_CHANNEL%        (#TheOps)
  staff_auth_channel   -> %X3_STAFF_AUTH_CHANNEL%   (#OperServ)
  clone_gline_duration -> %X3_CLONE_GLINE_DURATION% (2h) — companion to the
                          already-templatized untrusted_max
  chanserv nick        -> %X3_CHANSERV_NICK%        (X3)
  off_channel          -> %X3_OFF_CHANNEL%          (no)
  max_owned            -> %X3_MAX_OWNED%            (2)
  max_chan_users       -> %X3_MAX_CHAN_USERS%       (512)
  support_channel      -> (%X3_SUPPORT_CHANNEL%)    ("#Operations", "#Help" —
                          the value is the list body, channels stay quoted)
  global nick          -> %X3_GLOBAL_NICK%          (Global)

The logs targets follow the channels they feed: irc:#TheOps ->
irc:%X3_DEBUG_CHANNEL% and irc:#MrSnoopy -> irc:%X3_SNOOP_CHANNEL%.
X3_SNOOP_CHANNEL's entrypoint default (#MrSnoopy) lands here so the logs
reference resolves at this commit; the snoop module itself is templatized
with the other modules.

Channel MODES stay hardcoded.  valid_channel_regex stays hardcoded on
purpose: regex metacharacters through sed substitution are a foot-gun.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ential

Templatize the module settings (defaults preserve shipped literals unless
noted):

  sockcheck max_sockets    -> %X3_SOCKCHECK_MAX_SOCKETS%    (0)
  sockcheck gline_duration -> %X3_SOCKCHECK_GLINE_DURATION% (1d)
  snoop channel            -> %X3_SNOOP_CHANNEL%            (#MrSnoopy)
  snoop bot                -> %X3_OPSERV_NICK%              (reused)
  track channel            -> %X3_TRACK_CHANNEL%            (#MrPeanuts)
  memoserv bot             -> %X3_MEMOSERV_BOT%             (MemoServ)
  memoserv message_expiry  -> %X3_MEMO_EXPIRY%              (30d)
  memoserv limit           -> %X3_MEMO_LIMIT%               (30)
  qserver password         -> %X3_QSERVER_PASSWORD%
  blacklist gline_duration -> %X3_BLACKLIST_GLINE_DURATION% (1h)

The qserver password shipped as the literal credential "hello"; the
entrypoint now generates a random 16-char password when the deployment
doesn't provide one, so no image ever runs with a known qserver secret.

The bogus sockcheck "bind_address" "192.168.0.10" is commented out — set
only if you need a specific source IP; the shipped default was garbage
that broke proxy checks on any host not owning that address.

The webtv module is left alone (niche, mark-gated, nothing worth
parameterizing).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Templatize the mail block and the mondo DB save interval:

  enable       -> %X3_MAIL_ENABLE%       (0 — BEHAVIOR CHANGE, see below)
  mailer       -> %X3_MAIL_MAILER%       (/usr/sbin/sendmail)
  smtp_server  -> %X3_MAIL_SMTP_SERVER%  (localhost)
  smtp_service -> %X3_MAIL_SMTP_SERVICE% (smtp)
  dbs mondo frequency -> %X3_DB_SAVE_FREQUENCY% (30m)

The enable default flips 1 -> 0 deliberately: the image ships no MTA at
/usr/sbin/sendmail, so mail was enabled-but-dead — every cookie/verify
mail silently failed at mailer exec time.  Deployments with a real
mailer or SMTP relay set X3_MAIL_ENABLE=1 explicitly.

Branding coherence: the mail body strings mixed %X3_GENERAL_DOMAIN% with
leftover literals — "NET Support" / "NET IRC Network" now derive from
the domain, and the odd "Network-Services: x3" extra header becomes a
neutral "X-Mailer: X3-Services".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MrLenin MrLenin changed the title docker: complete the LDAP template (ldap_writeback) + env-template OpServ untrusted_max docker: comprehensive config template pass Aug 1, 2026
@MrLenin MrLenin self-assigned this Aug 1, 2026
@MrLenin
MrLenin requested a review from rubinlinux August 1, 2026 07:19
The entrypoint skipped generation whenever /x3/data/x3.conf existed, which
freezes the config at first container start forever: with x3.conf on a
persistent volume, every later env-var change, template update, or image
rebuild was silently inert. (Deployments hit exactly this: a conf generated
once in June still driving the container in August.)

New policy, keyed on a marker comment stamped as the first line of every
conf this script generates:
  - no x3.conf                 -> generate (with marker)
  - x3.conf WITH the marker    -> regenerate: env + template are the source
                                  of truth, config changes land on restart
  - x3.conf WITHOUT the marker -> user-managed (volume-mounted, hand-rolled)
                                  -> never touched

This preserves both documented workflows (env-templated and bring-your-own
x3.conf) while making the env-templated one actually track its inputs.
Generation substitutes into a temp file and stamps the marker on the final
move, so a mid-generation crash can't leave a half-substituted marker-less
conf that would then be mistaken for user-managed.

Migration note: confs generated by the OLD entrypoint carry no marker and
are therefore treated as user-managed after upgrade; delete the stale
x3.conf once (the volume's x3.db is unaffected) to opt into regeneration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant