From 0e9effdf17e74702b9521966243b8830bbb6e12e Mon Sep 17 00:00:00 2001 From: Thane Gill Date: Tue, 9 Jun 2026 19:53:55 -0700 Subject: [PATCH 1/3] spec: add ingate model unit test Ingate is an HTTP model, so it can't use the ATOMS simulation fixtures (those are SSH/telnet only). Add a custom spec (mirroring ivanti_spec) that mocks the node and input, stubs the config download with a representative SIParator export, and asserts the volatile "# Timestamp:" line is stripped while the configuration is kept. --- spec/model/ingate_spec.rb | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 spec/model/ingate_spec.rb diff --git a/spec/model/ingate_spec.rb b/spec/model/ingate_spec.rb new file mode 100644 index 000000000..b5419379f --- /dev/null +++ b/spec/model/ingate_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require_relative 'model_helper' +require 'oxidized/model/ingate' + +describe 'Model Ingate' do + before(:each) do + init_model_helper + + @mock_node = mock('Oxidized::Node') + @mock_node.stubs(:name).returns('ingate-1') + @mock_node.stubs(:ip).returns('192.0.2.10') + @mock_node.stubs(:group).returns('default') + + @mock_input = mock('Oxidized::Input') + @mock_input.stubs(:output).returns(nil) + + # The config is downloaded over HTTP (a "config to CLI file"). The values + # below are fabricated; the format mirrors a real SIParator export. The + # command is an anonymous lambda, so the stub matches any argument. + @config = <<~CONFIG + # Unitname: example-sbc + # Product: Software SIParator/Firewall + # Version: 6.4.4 + # Timestamp: 2024-01-01 00:00:00 + + load-factory --all + modify-row snmp.snmp 1 community=public + add-row qturn.default_password {id 1} password=s3cr3tpw + add-row cert.acme_accounts {id 1} eabhmackey=FAKEHMACKEY1234567890 key="-----BEGIN PRIVATE KEY----- + FAKEACMEKEYLINE + -----END PRIVATE KEY-----" + add-row cert.cert {id 1} cert_key="-----BEGIN PRIVATE KEY----- + FAKECERTKEYLINE + -----END PRIVATE KEY-----" + CONFIG + @mock_input.stubs(:cmd).returns(@config) + + @model = Ingate.new + @model.input = @mock_input + @model.node = @mock_node + end + + it 'removes the volatile Timestamp line and keeps the configuration' do + @model.stubs(:vars).returns(nil) + + result = @model.get.to_cfg + + _(result).wont_match(/^# Timestamp:/) + _(result).must_match(/^load-factory --all$/) + _(result).must_match(/^add-row qturn\.default_password /) + end +end From 3723306890150c0f9875142388e1d38c45101906 Mon Sep 17 00:00:00 2001 From: Thane Gill Date: Tue, 9 Jun 2026 19:54:07 -0700 Subject: [PATCH 2/3] ingate: simplify the model Replace the in-place `gsub!` plus redundant `cfg` return with a single `gsub` in the config command block. Behavior-preserving (covered by the model unit test). --- lib/oxidized/model/ingate.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/oxidized/model/ingate.rb b/lib/oxidized/model/ingate.rb index 7f228148d..87212c789 100644 --- a/lib/oxidized/model/ingate.rb +++ b/lib/oxidized/model/ingate.rb @@ -22,8 +22,7 @@ class Ingate < Oxidized::Model end cmd cfg_cb do |cfg| - cfg.gsub! /^# Timestamp:.*$/, '' - cfg + cfg.gsub(/^# Timestamp:.*$/, '') end cfg :http do From d4fc35c89239bb8d52873abc69cb86e71acd28ec Mon Sep 17 00:00:00 2001 From: Thane Gill Date: Tue, 9 Jun 2026 19:54:37 -0700 Subject: [PATCH 3/3] ingate: redact secrets when remove_secret is set The downloaded SIParator config stores credentials across many fields, so match by suffix to cover them all: passwords (trunkuserpassword, snmppassword, ...), secrets (radiussecret, ...), passphrases (configencpassphrase, ...), pre-shared keys (xauth_psk), HMAC and API tokens (eabhmackey, api_token), the SNMP community, and PEM private keys (cert_key, ...). Lookalikes such as passwordtimeout and enable_psk_rw are left untouched. Field names come from the Ingate reference guide. Covered by the model unit test. --- CHANGELOG.md | 1 + lib/oxidized/model/ingate.rb | 15 +++++++++++++++ spec/model/ingate_spec.rb | 30 +++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1147701eb..e8f99d765 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Changed ### Fixed +- ingate: redact secrets (private keys, passwords, secrets, passphrases, pre-shared keys, tokens and the SNMP community) when remove_secret is set (@thanegill) ## [0.37.0 - 2026-05-20] ### Added diff --git a/lib/oxidized/model/ingate.rb b/lib/oxidized/model/ingate.rb index 87212c789..13b97b362 100644 --- a/lib/oxidized/model/ingate.rb +++ b/lib/oxidized/model/ingate.rb @@ -25,6 +25,21 @@ class Ingate < Oxidized::Model cfg.gsub(/^# Timestamp:.*$/, '') end + cmd :secret do |cfg| + # Private keys: any *key field whose quoted value is a PEM private key block + # (the value spans multiple lines). + cfg.gsub!(/\b([a-z_]*key)="-----BEGIN [A-Z ]*PRIVATE KEY-----.*?-----END [A-Z ]*PRIVATE KEY-----"/m, + '\1="