test(mail): lock in password_ref resolution-failure fail-safe for hot… #107
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Config Validation | |
| on: | |
| pull_request: | |
| paths: | |
| - ".github/workflows/config-validation.yml" | |
| - "config/**" | |
| - "src/cli.rs" | |
| - "src/commands/config.rs" | |
| - "src/config/**" | |
| - "src/contract/vault/integration/vault_core.rs" | |
| - "docs/refactoring/config.md" | |
| - "docs/refactoring/mail.md" | |
| - "docs/refactoring/vault.md" | |
| - "README.md" | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - ".github/workflows/config-validation.yml" | |
| - "config/**" | |
| - "src/cli.rs" | |
| - "src/commands/config.rs" | |
| - "src/config/**" | |
| - "src/contract/vault/integration/vault_core.rs" | |
| - "docs/refactoring/config.md" | |
| - "docs/refactoring/mail.md" | |
| - "docs/refactoring/vault.md" | |
| - "README.md" | |
| jobs: | |
| validate-config: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout monoengine | |
| uses: actions/checkout@v5 | |
| with: | |
| path: monoengine | |
| - name: Validate orbit checkout token | |
| env: | |
| ORBIT_CHECKOUT_TOKEN: ${{ secrets.ORBIT_CHECKOUT_TOKEN }} | |
| run: | | |
| if [ -z "${ORBIT_CHECKOUT_TOKEN}" ]; then | |
| echo "::error title=Missing ORBIT_CHECKOUT_TOKEN::Config validation needs to checkout the private gitmono-dev/orbit sibling repository. Add an Actions secret named ORBIT_CHECKOUT_TOKEN with read-only contents access to gitmono-dev/orbit." | |
| exit 1 | |
| fi | |
| - name: Checkout orbit sibling | |
| uses: actions/checkout@v5 | |
| with: | |
| repository: gitmono-dev/orbit | |
| ref: main | |
| path: orbit | |
| token: ${{ secrets.ORBIT_CHECKOUT_TOKEN }} | |
| - name: Install Rust toolchains | |
| run: | | |
| rustup toolchain install stable --profile minimal | |
| rustup default stable | |
| rustup toolchain install nightly --profile minimal --component rustfmt | |
| - name: Check formatting | |
| working-directory: monoengine | |
| run: cargo +nightly fmt --all --check | |
| - name: Mask test secrets in logs | |
| run: | | |
| echo "::add-mask::mono_test_password" | |
| echo "::add-mask::smtp-test-password" | |
| - name: Start test services (PostgreSQL, Redis, Mailpit) | |
| working-directory: monoengine | |
| run: | | |
| docker compose -f docker-compose.test.yml up -d --wait | |
| docker compose -f docker-compose.test.yml ps | |
| - name: Run config sample tests | |
| working-directory: monoengine | |
| run: | | |
| cargo test config::template -- --nocapture | |
| cargo test config::loader -- --nocapture | |
| cargo test placeholder_expansion_error_is_returned_instead_of_panicking -- --nocapture | |
| cargo test placeholder_substitution_error_redacts_context_values -- --nocapture | |
| cargo test reload_applies_subscribers_before_publishing_snapshot -- --nocapture | |
| cargo test reload_rolls_back_subscribers_and_keeps_snapshot_when_apply_fails -- --nocapture | |
| cargo test reload_reports_static_consumer_fields_as_restart_required_without_publishing_snapshot -- --nocapture | |
| cargo test test_new_with_profile_merges_profile_before_env -- --nocapture | |
| cargo test config_init_template_has_no_unconsumed_fields -- --nocapture | |
| cargo test config_validate_rejects_invalid_monorepo_settings -- --nocapture | |
| cargo test config_validate_rejects_invalid_pack_settings -- --nocapture | |
| cargo test config_validate_rejects_invalid_blame_settings -- --nocapture | |
| cargo test config_validate_rejects_object_storage_secret_ref_values_without_leaking_ref -- --nocapture | |
| cargo test config_validate_rejects_invalid_sidebar_items -- --nocapture | |
| cargo test config_validate_rejects_invalid_artifact_gc_settings -- --nocapture | |
| cargo test source_diagnostics_collects_base_profile_and_env_warnings -- --nocapture | |
| cargo test source_diagnostics_collects_cross_source_overrides_without_values -- --nocapture | |
| cargo test source_diagnostics_collects_field_source_graph_without_values -- --nocapture | |
| cargo test known_unconsumed_fields_warns_for_deprecated_mail_password_without_value -- --nocapture | |
| cargo test unconsumed_environment_fields_warns_for_unknown_ignored_and_legacy_keys -- --nocapture | |
| cargo test test_bad_environment_type_reports_variable_name_without_value -- --nocapture | |
| cargo test config_validate_uses_raw_sources_load_mode -- --nocapture | |
| cargo test config_validate_accepts_deny_warnings_flag -- --nocapture | |
| cargo test validate_config_denies_source_warnings_when_requested -- --nocapture | |
| cargo test validate_config_denies_deprecated_mail_password_source_without_leaking_value -- --nocapture | |
| cargo test show_sources_lines_include_source_warnings_without_values -- --nocapture | |
| cargo test secret_ref_from_args_rejects_wrong_mail_namespace_without_leaking_path -- --nocapture | |
| cargo test mail_validate_rejects_password_ref_outside_mail_namespace_without_leaking_ref -- --nocapture | |
| cargo test config_validate_reports_bad_env_type_without_cli_preload -- --nocapture | |
| cargo test test_profile_type_error_reports_profile_source_without_value -- --nocapture | |
| cargo test resolve_config_secrets_reports_missing_mail_password_ref_without_leaking_ref -- --nocapture | |
| cargo test resolve_config_secrets_reports_permission_denied_without_leaking_ref -- --nocapture | |
| cargo test vault_secret_resolver_reports_missing_field_without_leaking_ref -- --nocapture | |
| cargo test vault_secret_resolver_reports_non_string_field_without_leaking_ref -- --nocapture | |
| cargo test test_config_secret_acl_is_not_granted_to_generic_token -- --nocapture | |
| - name: Validate bundled config | |
| working-directory: monoengine | |
| run: cargo run -p monoengine -- --config config/config.toml config validate | |
| - name: Validate generated config | |
| working-directory: monoengine | |
| run: | | |
| config_path="${RUNNER_TEMP}/monoengine.generated.toml" | |
| cargo run -p monoengine -- config init --output "${config_path}" --force | |
| cargo run -p monoengine -- --config "${config_path}" config validate | |
| cargo run -p monoengine -- --config "${config_path}" config validate --deny-warnings | |
| - name: Validate profile merge | |
| working-directory: monoengine | |
| run: | | |
| config_dir="${RUNNER_TEMP}/monoengine-profile" | |
| mkdir -p "${config_dir}" | |
| cp config/config.toml "${config_dir}/config.toml" | |
| cat > "${config_dir}/config.prod.toml" <<'EOF' | |
| [log] | |
| level = "debug" | |
| [monorepo] | |
| root_dirs = ["profile-root"] | |
| EOF | |
| cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile prod config validate | |
| source_output="${config_dir}/source-diagnostics.out" | |
| MEGA_DATABASE__DB_URL="postgres://ci.example.invalid:5432/ci" cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile prod config validate --show-sources >"${source_output}" 2>&1 | |
| grep -F "source field:" "${source_output}" | |
| grep -F "source override:" "${source_output}" | |
| grep -F "log.level" "${source_output}" | |
| grep -F "database.db_url" "${source_output}" | |
| grep -F "sensitive values are omitted" "${source_output}" | |
| grep -F "deployment/environment secrets" "${source_output}" | |
| grep -F "monorepo.root_dirs" "${source_output}" | |
| grep -F "arrays replace lower-precedence values rather than append" "${source_output}" | |
| ! grep -F "postgres://ci.example.invalid" "${source_output}" | |
| ! grep -F "profile-root" "${source_output}" | |
| ! grep -F "base-root" "${source_output}" | |
| - name: Validate bad config diagnostics | |
| working-directory: monoengine | |
| run: | | |
| set -euo pipefail | |
| config_dir="${RUNNER_TEMP}/monoengine-bad-configs" | |
| mkdir -p "${config_dir}" | |
| cp config/config.toml "${config_dir}/config.toml" | |
| { | |
| printf '%s\n' '[mail]' | |
| printf '%s = "%s%s\n' 'password' 'plain-text' '-password' | |
| } > "${config_dir}/config.bad-toml.toml" | |
| bad_toml_output="${config_dir}/bad-toml.out" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile bad-toml config validate >"${bad_toml_output}" 2>&1; then | |
| cat "${bad_toml_output}" | |
| echo "bad TOML config unexpectedly validated" | |
| exit 1 | |
| fi | |
| grep -F "TOML parse error" "${bad_toml_output}" | |
| grep -F "config.bad-toml.toml" "${bad_toml_output}" | |
| grep -F "value is redacted" "${bad_toml_output}" | |
| ! grep -F "plain-text-password" "${bad_toml_output}" | |
| cat > "${config_dir}/config.bad-placeholder.toml" <<'EOF' | |
| base_dir = "/tmp/${missing_config_root}" | |
| EOF | |
| placeholder_output="${config_dir}/bad-placeholder.out" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile bad-placeholder config validate >"${placeholder_output}" 2>&1; then | |
| cat "${placeholder_output}" | |
| echo "bad placeholder config unexpectedly validated" | |
| exit 1 | |
| fi | |
| grep -F "unresolved placeholder" "${placeholder_output}" | |
| grep -F "base_dir" "${placeholder_output}" | |
| grep -F "value is redacted" "${placeholder_output}" | |
| cat > "${config_dir}/config.bad-secret-ref.toml" <<'EOF' | |
| [mail] | |
| enabled = false | |
| smtp_host = "smtp.example.com" | |
| from = "no-reply@example.com" | |
| password_ref = "vault://secret/config/test/mail/password" | |
| EOF | |
| secret_ref_output="${config_dir}/bad-secret-ref.out" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile bad-secret-ref config validate >"${secret_ref_output}" 2>&1; then | |
| cat "${secret_ref_output}" | |
| echo "bad SecretRef config unexpectedly validated" | |
| exit 1 | |
| fi | |
| grep -F "secret ref must include a #field suffix" "${secret_ref_output}" | |
| grep -F "mail.password_ref" "${secret_ref_output}" | |
| cat > "${config_dir}/config.bad-secret-ref-namespace.toml" <<'EOF' | |
| [mail] | |
| enabled = false | |
| smtp_host = "smtp.example.com" | |
| from = "no-reply@example.com" | |
| password_ref = "vault://secret/config/prod/database/password#value" | |
| EOF | |
| secret_ref_namespace_output="${config_dir}/bad-secret-ref-namespace.out" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile bad-secret-ref-namespace config validate >"${secret_ref_namespace_output}" 2>&1; then | |
| cat "${secret_ref_namespace_output}" | |
| echo "bad SecretRef namespace config unexpectedly validated" | |
| exit 1 | |
| fi | |
| grep -F "mail.password_ref" "${secret_ref_namespace_output}" | |
| grep -F "vault://secret/config/<profile>/mail/password#<field>" "${secret_ref_namespace_output}" | |
| grep -F "value is redacted" "${secret_ref_namespace_output}" | |
| ! grep -F "config/prod/database/password" "${secret_ref_namespace_output}" | |
| cat > "${config_dir}/config.bad-redis.toml" <<'EOF' | |
| [redis] | |
| url = "http://localhost:6379" | |
| EOF | |
| redis_output="${config_dir}/bad-redis.out" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile bad-redis config validate >"${redis_output}" 2>&1; then | |
| cat "${redis_output}" | |
| echo "bad Redis config unexpectedly validated" | |
| exit 1 | |
| fi | |
| grep -F "redis.url scheme" "${redis_output}" | |
| grep -F "'redis' or 'rediss'" "${redis_output}" | |
| { | |
| printf '%s\n' '[mail]' | |
| printf '%s = "plain-text-password"\n' 'password' | |
| } > "${config_dir}/config.deprecated-mail-password.toml" | |
| mail_password_output="${config_dir}/deprecated-mail-password.out" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile deprecated-mail-password config validate --deny-warnings >"${mail_password_output}" 2>&1; then | |
| cat "${mail_password_output}" | |
| echo "deprecated mail.password config unexpectedly passed --deny-warnings" | |
| exit 1 | |
| fi | |
| grep -F "mail.password" "${mail_password_output}" | |
| grep -F "mail.password_ref" "${mail_password_output}" | |
| ! grep -F "plain-text-password" "${mail_password_output}" | |
| cat > "${config_dir}/config.profile-source-warning.toml" <<'EOF' | |
| [mail] | |
| smtp_tls = false | |
| EOF | |
| profile_warning_output="${config_dir}/profile-source-warning.out" | |
| cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile profile-source-warning config validate --show-sources >"${profile_warning_output}" 2>&1 | |
| grep -F "source warning: file" "${profile_warning_output}" | |
| grep -F "config.profile-source-warning.toml" "${profile_warning_output}" | |
| grep -F "mail.smtp_tls" "${profile_warning_output}" | |
| grep -F "mail.starttls" "${profile_warning_output}" | |
| if cargo run -p monoengine -- --config "${config_dir}/config.toml" --profile profile-source-warning config validate --deny-warnings >"${profile_warning_output}" 2>&1; then | |
| cat "${profile_warning_output}" | |
| echo "profile source warning unexpectedly passed --deny-warnings" | |
| exit 1 | |
| fi | |
| grep -F "source diagnostics produced" "${profile_warning_output}" | |
| - name: Run integration tests (vault CLI + mail/notification dispatcher) | |
| working-directory: monoengine | |
| env: | |
| MEGA_DATABASE__DB_URL: postgres://mono:mono_test_password@127.0.0.1:15432/monoengine_it | |
| MEGA_REDIS__URL: redis://127.0.0.1:16379 | |
| MAILPIT_API_URL: http://127.0.0.1:18025 | |
| run: | | |
| # Black-box CLI integration tests (config secret ref/set/check, validate). | |
| # The integration test lives in the `monoengine` binary crate (bin/tests/). | |
| cargo test -p monoengine --test integration_vault -- --test-threads=1 | |
| # Mail/notification dispatcher delivery against the real Mailpit + Postgres, | |
| # plus the NotificationService end-to-end delivery and the CL-comment | |
| # trigger enqueue/render path. These live in the monoengine-core library. | |
| cargo test -p monoengine-core 'notification::dispatcher::tests::integration_mail_dispatcher' | |
| cargo test -p monoengine-core 'notification::service::tests' | |
| cargo test -p monoengine-core 'notification::triggers::tests' | |
| - name: Stop test services | |
| if: always() | |
| working-directory: monoengine | |
| run: docker compose -f docker-compose.test.yml down -v |