Every CLI option that can carry a secret gets a `--<name>-file <path|->`
sibling ('-' reads stdin), so the value stays out of the process list and
shell history: --password-file (global), --primary-config-file /
--backup-config-file (data-connection create|update), --auth-config-file
(external-system create|update), --connection-string-file (db-connection
create|update), --credentials-file (notification smtp create|update) and
--auth-token-file (notification sms create|update). Follows the existing
--config-file convention; `@path` is avoided because System.CommandLine
expands @-tokens as response files.
The value is read at parse time; a missing/unreadable/empty source, or '-'
on a terminal stdin, is a parse error naming option + path only, never the
content. Inline and file forms are mutually exclusive, at most one option
may read stdin, and one trailing line break is stripped. Inline forms keep
working.
docker/seed-sites.sh and docker-env2/seed-sites.sh now write the MxGateway
config (windev gateway key) to a mode-600 temp file removed by an EXIT trap
and pass --primary-config-file; seed-flow-outbound-demo.sh pipes its rig
connection string via --connection-string-file -. CLI README (new "Secrets
from a file or stdin" section + per-command tables), Component-CLI.md and
both docker READMEs updated.
Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
docker/seed-sites.sh and docker-env2/seed-sites.sh hard-coded the windev
gateway API key. They now read MXGW_APIKEY from the environment, or from
a private file (default ~/.config/scadabridge/windev-mxgw-apikey,
override MXGW_APIKEY_FILE). With no key the MxGateway connection step is
skipped and the rest of the seed runs. READMEs note where to put it.
The key remains in git history (2 commits), so it should be rotated on
the windev gateway.
Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
Replace the generic 'MxGateway Shared' connection name with a per-site name
(site-a -> 'ScadaBridge Site A', env2 site-x -> 'ScadaBridge Site X') in both
docker/ and docker-env2/ seed scripts.
Test instances persistently emit Notify.To("Engineering Alerts").Send;
without the list at central a fresh cutover parks every notification
(observed 42k+ parked in a 3.5-min S&F drain after the rename).
Mirror the seed across docker/seed-sites.sh and docker-env2/seed-sites.sh.
A fresh ScadaBridgeConfig has only the Admin LdapGroupMappings row
(InitialSchema migration ships one row, SecurityConfiguration.HasData
declares four). docker-env2/seed-sites.sh already inserts the missing
three idempotently; docker/seed-sites.sh did not, so multi-role got
Admin only on a primary cutover. Mirror the env2 insert block.
SecurityConfiguration.HasData declares 4 LdapGroupMapping seed rows
(Admin / Design / Deployment-All / Deployment-SiteA) but the
InitialSchema migration only INSERTs the Admin row -- the other three
were never captured into a migration. A fresh ScadaLinkConfig2 starts
with multi-role getting Admin only, no Design or Deployment access.
(The same divergence exists on primary's ScadaLinkConfig, but it has
the rows from earlier history.)
Insert the missing three idempotently from seed-sites.sh so env2's
fresh deploys end up role-aligned with the running primary cluster.
The longer-term fix is a new EF migration that captures the HasData
diff -- intentionally not done here to avoid touching the primary
cluster's existing rows.