"""ROUND 3 — auth POLICY vs auth MATERIAL, and the posture/enforcement agreement.

THE DEFECT ROUND 2 INTRODUCED WHILE CLOSING ITS OWN
---------------------------------------------------
Round 2 (D2) stopped the config plane from writing the auth switch, by refusing a family of names
from `apply_to_env`. The refusal list was a set of PREFIXES, and it swept up three names that are
not policy at all:

    OIDC_ISSUER  OIDC_JWKS_URL            half of `creds.settings_auth_configured()`
    ANDREA_SECRETS_ENV_FILES              the declaration of a tier-2 credential FILE

Refusing to DELIVER those does not harden anything. It REMOVES the credential — and the branch a
missing credential lands in is `ServiceKeyRequiredIfConfigured -> True`, i.e. **anonymous 200 on the
whole data plane**. The tree already contained the contradiction in plain sight:
`creds.AUTH_ENFORCEMENT_NAMES` lists OIDC_ISSUER/OIDC_JWKS_URL *because removing them opens the
service*, so creds.py refused to REMOVE precisely the names config.py refused to DELIVER.

    POLICY   (ANDREA_AUTH_MODE, the loader's own controls) — never from the config plane. Round 2
             is correct and every one of its controls is re-asserted here.
    MATERIAL (the key, the OIDC pair, the tier-2 file declaration) — DELIVERED, through
             ServiceSecrets, in memory, with provenance. Never through os.environ.

AND IT WAS SILENT, WHICH IS THE WORSE HALF
------------------------------------------
`auth_material_present()` reads the RESOLVED set, which DID hold the tier-1 OIDC pair, so posture
stayed "enforcing" while the permission class — reading `settings_auth_configured()`, which did not
— served anonymous callers. A fleet sweep of /health + /admin/creds-status answered "nobody is open"
about a service that was open. The invariant these tests pin down:

    **posture == "enforcing"  ⇒  an anonymous request is REFUSED.**

⚑ NO TEST HERE ASSERTS ON A CREDENTIAL VALUE (rm#206). Status codes, presence booleans, provenance
labels and digests only. Sentinels are obviously-not-real so a leak in a failure message would be
unmistakable.
"""
import json
import os
import subprocess
import sys

import pytest
from django.conf import settings as dj
from django.test import override_settings
from rest_framework.response import Response
from rest_framework.test import APIRequestFactory
from rest_framework.views import APIView

from andrea_svc_web import config as configmod
from andrea_svc_web import creds as credsmod
from andrea_svc_web import permissions as permmod
from andrea_svc_web.auth import ServiceKeyRequiredIfConfigured, ServiceOrOIDCAuthentication
from andrea_svc_web.creds import ServiceSecrets
from andrea_svc_web.middleware import CredsRefreshMiddleware

rf = APIRequestFactory()

# Obviously-not-real sentinels. `.invalid` is reserved by RFC 2606, so nothing here can resolve.
KEY = "policy-vs-material-sentinel-key"
ISSUER = "https://issuer.invalid/realms/andrea"
JWKS = "https://issuer.invalid/realms/andrea/protocol/openid-connect/certs"

PKG_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


class _DataPlaneView(APIView):
    """A service's ORDINARY endpoint: the shape every migrated service's business API has."""

    authentication_classes = [ServiceOrOIDCAuthentication]
    permission_classes = [ServiceKeyRequiredIfConfigured]

    def get(self, request):
        return Response({"business_data": "served"})


def _data_get(key=None, middleware=True):
    """One request through the REAL stack. `middleware=False` bypasses CredsRefreshMiddleware, which
    is how the posture tripwire is exercised: it answers "what does this process enforce RIGHT NOW",
    before anything gets a chance to repair the settings."""
    headers = {"X-Agent-Key": key} if key else {}
    req = rf.get("/data", **({"headers": headers} if headers else {}))
    if middleware:
        CredsRefreshMiddleware(lambda r: None)(req)
    return _DataPlaneView.as_view()(req)


def _tier1(monkeypatch, payload):
    """Point ServiceSecrets' tier-1 fetch at `payload` — a healthy config-service."""
    monkeypatch.setattr(credsmod, "fetch_config_result",
                        lambda *a, **k: configmod.ConfigFetch(status="ok", payload=dict(payload)))


def _secrets(tmp_path, *, tier1=None, monkeypatch=None, body=None, **kw):
    """A loaded ServiceSecrets. `tier1` opts into the config-service overlay with that payload."""
    if tier1 is not None:
        _tier1(monkeypatch, tier1)
        kw["config_service"] = True
    if body is not None:
        f = tmp_path / "svc.env"
        f.write_text(body)
        kw.setdefault("env_files", [str(f)])
    kw.setdefault("env", {})
    s = ServiceSecrets("policy-material-svc", state_path=str(tmp_path / "stamp.json"), **kw)
    s.load()
    return s


@pytest.fixture(autouse=True)
def _isolate():
    """apply_to_env() writes the REAL os.environ, and creds/permissions carry one-shot announcement
    flags. Reset both so no test can leak state into the next one (a leaked auth-control key would
    itself be a fail-open, and a stuck one-shot flag would silently disarm a tripwire)."""
    before = dict(os.environ)
    credsmod._open_divergence_announced = False
    permmod._dev_open_ignored_announced = False
    yield
    for k in set(os.environ) - set(before):
        os.environ.pop(k, None)
    os.environ.update(before)
    credsmod._open_divergence_announced = False
    permmod._dev_open_ignored_announced = False


# ══════════════════════════════════════════════════════════════════════════════════════════════
# THE REAL PATH — django.setup() executing andrea_svc_web/settings.py, against a real
# config-service, with a real DRF cycle. The unit suite's settings.configure() NEVER runs that
# file, so nothing else in this repo can see a defect that lives in it.
# ══════════════════════════════════════════════════════════════════════════════════════════════
def _probe(payload: dict, extra_env: dict | None = None) -> dict:
    """Run `tests/realpath_probe.py` in a FRESH interpreter with a SCRUBBED environment.

    ⚑ The environment is built from scratch, not inherited. This host's own shell exports
    ANDREA_SVC_API_KEY and OIDC_ISSUER; inheriting them would hand the probe a credential from
    tier 3 and every assertion about "the config plane delivered this" would be measuring the
    ambient environment instead. A negative control that passes for the wrong reason is not a
    control."""
    env = {
        "PATH": os.environ.get("PATH", "/usr/bin:/bin"),
        "HOME": os.environ.get("HOME", "/root"),
        "LANG": os.environ.get("LANG", "C.UTF-8"),
        "PYTHONPATH": PKG_DIR,
        "PYTHONDONTWRITEBYTECODE": "1",
    }
    proc = subprocess.run(
        [sys.executable, "-m", "tests.realpath_probe", json.dumps(payload),
         json.dumps(extra_env or {})],
        cwd=PKG_DIR, env=env, capture_output=True, text=True, timeout=120)
    lines = [ln for ln in proc.stdout.splitlines() if ln.startswith("PROBE ")]
    assert lines, f"probe produced no verdict (rc={proc.returncode}):\n{proc.stderr[-4000:]}"
    return json.loads(lines[-1][len("PROBE "):])


def test_an_oidc_pair_from_the_config_service_makes_the_service_ENFORCE():
    """⚑ THE NEGATIVE CONTROL. A service whose ONLY auth material is an OIDC issuer+JWKS pair served
    by the config plane. Pre-round-3 this answered **200 with the business payload** to an
    anonymous caller — `apply_to_env` refused the OIDC_ prefix, settings.py read the pair from
    os.environ, both came back empty, `settings_auth_configured()` said False, and
    `ServiceKeyRequiredIfConfigured` opened the data plane.

    And the same run reported `posture: enforcing`, because the resolved set DID hold the pair."""
    out = _probe({"OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS, "CFG_BENIGN": "9"})

    assert out["anon_status"] == 401                      # enforcing, on the wire
    assert out["anon_served_business_data"] is False      # and the payload never left
    assert out["settings_auth_configured"] is True        # the credential reached the auth layer
    assert out["oidc_issuer_present"] and out["oidc_jwks_present"]
    assert out["oidc_issuer_source"] == "config-service"  # PROVENANCE, never a value
    assert out["auth_kind"] == "oidc"

    # DELIVERED, BUT NOT THROUGH os.environ. The round-2 rule stands: the config plane never writes
    # auth material into the process environment — it is resolved in memory, with provenance.
    assert out["oidc_in_os_environ"] is False
    assert out["benign_in_os_environ"] == "9"             # ordinary knobs still overlay: no cost

    # the observability spine agrees with what is enforced
    assert out["posture"] == "enforcing" and out["health_posture"] == "enforcing"
    assert out["enforcing"] is True


def test_a_tier2_file_declared_by_the_config_service_is_actually_read(tmp_path):
    """⚑ THE SECOND NEGATIVE CONTROL, same shape. `ANDREA_SECRETS_ENV_FILES` matched the
    `ANDREA_SECRETS_` prefix, so a centrally-declared credential FILE was never declared, the key
    inside it never loaded, and the service resolved `unconfigured` -> open.

    It is consumed EARLY — before tier 2 can be read at all — so it cannot be resolved like a
    value; `_sync_env_files` runs at the top of `_resolve`, before a single file is opened."""
    f = tmp_path / "central.env"
    f.write_text(f"ANDREA_SVC_API_KEY={KEY}\n")

    out = _probe({"ANDREA_SECRETS_ENV_FILES": str(f)})

    assert str(f) in out["env_files"]                     # the declaration was honoured
    assert out["svc_key_present"] is True                 # presence, never the value
    assert out["svc_key_source"] == str(f)                # and it came from THAT file
    assert out["svc_key_in_os_environ"] is False          # still not via the process environment
    assert out["anon_status"] == 401
    assert out["posture"] == "enforcing" and out["enforcing"] is True


def test_the_config_service_still_cannot_set_the_auth_mode_on_the_real_path():
    """ROUND-2 REGRESSION GUARD, on the path that actually runs in production. A payload carrying
    the kill switch alongside real material: the material lands, the switch does not. dev-open must
    not reach `permissions.auth_mode()` by any route — os.environ, settings, or SECRETS."""
    out = _probe({"ANDREA_AUTH_MODE": "dev-open", "OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS})

    assert out["auth_mode"] == "auto"                     # the switch was never flipped
    assert out["auth_mode_in_os_environ"] is False
    assert out["anon_status"] == 401                      # so the data plane stayed closed
    assert out["settings_auth_configured"] is True


# ══════════════════════════════════════════════════════════════════════════════════════════════
# POLICY vs MATERIAL, at the classification boundary
# ══════════════════════════════════════════════════════════════════════════════════════════════
def test_material_is_delivered_and_policy_is_refused():
    """The classifier itself. Every name on the left removes a credential when withheld; every name
    on the right decides whether the credential is CHECKED. One list cannot serve both."""
    for material in ("ANDREA_SVC_KEYS", "ANDREA_SVC_API_KEY", "OIDC_ISSUER", "OIDC_JWKS_URL",
                     "OIDC_AUDIENCE", "ANDREA_SECRETS_ENV_FILES"):
        assert configmod.is_credential_material(material) is True, material
        assert configmod.is_auth_control(material) is False, material
        # material is delivered — but through SECRETS, never by writing os.environ
        assert configmod.may_overlay_env(material) is False, material

    for policy in ("ANDREA_AUTH_MODE", "ANDREA_API_KEY_HEADER", "CONFIG_SERVICE_URL",
                   "ANDREA_SECRETS_IGNORE", "ANDREA_SECRETS_REQUIRED", "ANDREA_SECRETS_STRICT",
                   "ANDREA_CREDS_HONOR_WITHDRAWAL", "ANDREA_CREDS_STATE", "ANDREA_CREDS_DB_PROBE",
                   "ANDREA_CONFIG_ENV_ALLOW", "ANDREA_CONFIG_SERVICE", "OIDC_JWKS_TTL"):
        assert configmod.is_auth_control(policy) is True, policy
        assert configmod.is_credential_material(policy) is False, policy

    # the PREFIX floor still holds for names nobody has enumerated yet — a new knob is refused by
    # default, which is the property that made prefixes the right shape in the first place
    for unknown in ("ANDREA_CREDS_SOMETHING_NEW", "ANDREA_SECRETS_FUTURE", "ANDREA_AUTHZ_MODE"):
        assert configmod.is_auth_control(unknown) is True, unknown


def test_auth_policy_never_even_enters_the_resolved_set(tmp_path, monkeypatch):
    """Defence in depth for round 2: policy is dropped at RESOLVE, not merely at the two call sites
    that consume it. There is no `ANDREA_AUTH_MODE` in `_values` for a future `SECRETS.get()` to
    find — the guarantee becomes a property of the data instead of of every reader."""
    s = _secrets(tmp_path, monkeypatch=monkeypatch, tier1={
        "ANDREA_AUTH_MODE": "dev-open",
        "ANDREA_CREDS_HONOR_WITHDRAWAL": "1",
        "ANDREA_SECRETS_IGNORE": "ANDREA_SVC_API_KEY",
        "OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS,
        "CFG_BENIGN": "9",
    })
    assert s.get("ANDREA_AUTH_MODE") is None
    assert s.get("ANDREA_CREDS_HONOR_WITHDRAWAL") is None
    assert s.get("ANDREA_SECRETS_IGNORE") is None
    assert s.honor_withdrawal is False                    # the knob was not armed remotely either
    # ...while the MATERIAL in the very same payload arrived, with provenance
    assert s.source_of("OIDC_ISSUER") == credsmod.CONFIG_SERVICE
    assert s.get("CFG_BENIGN") == "9"                     # ordinary knobs unaffected


# ══════════════════════════════════════════════════════════════════════════════════════════════
# THE MIRROR — material must reach the settings the auth layer reads, and never be blanked there
# ══════════════════════════════════════════════════════════════════════════════════════════════
def test_the_middleware_refresh_carries_the_oidc_pair_not_just_the_key(tmp_path, monkeypatch):
    """⚑ NEGATIVE CONTROL. `refresh_auth_settings()` only ever mirrored ANDREA_SVC_KEYS, so the
    per-request repair could not fix an OIDC service: `settings_auth_configured()` is satisfied by
    the key OR the pair, and half a refresh is half a contract. Same §4c bootstrap as the key —
    material that lands in a source goes live on the next request, no POST, no restart."""
    s = _secrets(tmp_path, monkeypatch=monkeypatch,
                 tier1={"OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS})
    with override_settings(SECRETS=s, ANDREA_SVC_KEYS=None, OIDC_ISSUER="", OIDC_JWKS_URL=""):
        assert credsmod.settings_auth_configured() is False        # the pre-refresh (open) state
        assert credsmod.refresh_auth_settings() is True
        assert credsmod.settings_auth_configured() is True
        assert bool(dj.OIDC_ISSUER) and bool(dj.OIDC_JWKS_URL)     # presence, never the value
        assert _data_get(middleware=False).status_code == 401


def test_a_reload_rotates_the_oidc_pair_but_can_never_blank_it(tmp_path):
    """The mirror is ROTATE-ONLY. An empty resolution is never written, so enforcement cannot be
    switched off by a value that failed to resolve, a truncated file, or a config-plane blip —
    the same guard that has always protected the service key, extended to the other half of the
    predicate it protects."""
    f = tmp_path / "svc.env"
    f.write_text(f"OIDC_ISSUER={ISSUER}\nOIDC_JWKS_URL={JWKS}\n")
    s = ServiceSecrets("policy-material-svc", env_files=[str(f)], env={},
                       state_path=str(tmp_path / "stamp.json"))
    s.load()
    with override_settings(SECRETS=s, ANDREA_SVC_KEYS=None, OIDC_ISSUER=ISSUER, OIDC_JWKS_URL=JWKS):
        rotated = ISSUER + "/rotated"
        f.write_text(f"OIDC_ISSUER={rotated}\nOIDC_JWKS_URL={JWKS}\n")
        s.reload()
        assert credsmod.digest_of(dj.OIDC_ISSUER) == s.digest("OIDC_ISSUER")   # rotation landed
        assert _data_get(middleware=False).status_code == 401

        before = s.digest("OIDC_ISSUER")
        f.write_text("")                                   # caught mid-truncation / withdrawn
        s.reload()
        assert bool(dj.OIDC_ISSUER) and bool(dj.OIDC_JWKS_URL)   # NOT blanked
        assert s.digest("OIDC_ISSUER") == before
        assert _data_get(middleware=False).status_code == 401    # still closed


def test_the_mirror_never_blanks_an_oidc_pair_the_service_declared_in_its_own_settings(tmp_path):
    """⚑ THE HAZARD THE NEW MIRROR CREATES, and the guard that closes it. `refresh_auth_settings()`
    now runs on EVERY request and writes the OIDC settings — so a service that configures its
    Keycloak issuer in its own `settings.py` (in code, not via env, which is how pod-gem and
    logsmith-cite do it) has auth material that `_values` does not contain. A mirror without the
    `if val` guard would `setattr(settings, "OIDC_ISSUER", "")` on the very first request and turn
    a correctly-configured OIDC service into an open one — the fix re-creating the defect it fixes.

    Writing a credential and blanking one are opposite operations; only the first is allowed."""
    s = ServiceSecrets("policy-material-svc", env={},        # NOTHING resolves — no OIDC in _values
                       state_path=str(tmp_path / "stamp.json"))
    s.load()
    assert s.get("OIDC_ISSUER") is None and s.get("OIDC_JWKS_URL") is None
    with override_settings(SECRETS=s, ANDREA_SVC_KEYS=None, OIDC_ISSUER=ISSUER, OIDC_JWKS_URL=JWKS):
        assert _data_get().status_code == 401              # through the middleware, i.e. the mirror
        assert bool(dj.OIDC_ISSUER) and bool(dj.OIDC_JWKS_URL)
        assert credsmod.settings_auth_configured() is True
        assert s.posture == "enforcing"                     # reported, and true


def test_the_mirror_does_not_un_normalise_an_issuer_a_service_derived_from_the_env(tmp_path):
    """FLEET-COMPATIBILITY guard for the new mirror. docwell, logsmith-cite and pod-gem all do
    `os.environ.get("OIDC_ISSUER", <default>).rstrip("/")` after the star-import, so their settings
    value is legitimately DIFFERENT from the raw tier-3 string this object holds. Re-mirroring the
    raw one every request would silently un-normalise a LIVE issuer — an `iss` mismatch that 401s
    every legitimate user. Tier 3 is a frozen snapshot that cannot rotate, so there is never
    anything new to deliver from it; the mirror is for the re-readable tiers."""
    raw = ISSUER + "/"                                       # the un-normalised spawn value
    s = ServiceSecrets("policy-material-svc", env={"OIDC_ISSUER": raw, "OIDC_JWKS_URL": JWKS},
                       state_path=str(tmp_path / "stamp.json"))
    s.load()
    assert s.source_of("OIDC_ISSUER") == credsmod.PROCESS_ENV
    with override_settings(SECRETS=s, ANDREA_SVC_KEYS=None,
                           OIDC_ISSUER=ISSUER, OIDC_JWKS_URL=JWKS):   # the service's .rstrip("/")
        assert _data_get().status_code == 401                # a full cycle THROUGH the middleware
        assert dj.OIDC_ISSUER == ISSUER                      # the normalised form survived
        assert s.posture == "enforcing"


def test_a_withdrawal_still_refuses_to_remove_the_oidc_pair(tmp_path):
    """D3 regression guard, on the OIDC half. Losing a credential is the one change that cannot
    fail closed, so it is the one change a live reload may not make — opt-in or not."""
    f = tmp_path / "svc.env"
    f.write_text(f"OIDC_ISSUER={ISSUER}\nOIDC_JWKS_URL={JWKS}\nOTHER=1\n")
    s = ServiceSecrets("policy-material-svc", env_files=[str(f)],
                       env={"ANDREA_CREDS_HONOR_WITHDRAWAL": "1"},
                       state_path=str(tmp_path / "stamp.json"))
    s.load()
    before = s.digest("OIDC_ISSUER")
    f.write_text("OTHER=2\n")                              # a real, evidenced removal upstream
    report = s.reload()
    assert "OIDC_ISSUER" in report.withdrawn               # VISIBLE
    assert s.digest("OIDC_ISSUER") == before               # but NOT removed
    assert s.auth_material_present() is True


# ══════════════════════════════════════════════════════════════════════════════════════════════
# ⚑ THE POSTURE LIE — what we REPORT must agree with what we ENFORCE
# ══════════════════════════════════════════════════════════════════════════════════════════════
_MATERIAL = {
    "none": {},
    "keys": {"ANDREA_SVC_API_KEY": KEY},
    "oidc": {"OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS},
    "both": {"ANDREA_SVC_API_KEY": KEY, "OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS},
    "half-oidc": {"OIDC_ISSUER": ISSUER},                  # issuer without JWKS is NOT material
}
_SETTINGS_VIEW = {
    "blind": dict(ANDREA_SVC_KEYS=None, OIDC_ISSUER="", OIDC_JWKS_URL=""),
    "keys": dict(ANDREA_SVC_KEYS=KEY, OIDC_ISSUER="", OIDC_JWKS_URL=""),
    "oidc": dict(ANDREA_SVC_KEYS=None, OIDC_ISSUER=ISSUER, OIDC_JWKS_URL=JWKS),
}


def test_no_combination_yields_posture_enforcing_with_an_anonymous_200(tmp_path):
    """⚑ THE INVARIANT, swept: **posture == "enforcing" ⇒ an anonymous request is REFUSED.**

    Pre-round-3 the (material=oidc|both, settings=blind) cells reported `enforcing` and served
    anonymous 200 — because `posture` asked `auth_material_present()` (the RESOLVED set, which held
    the pair) while the permission class asked `settings_auth_configured()` (the settings, which did
    not). Two predicates, one question, opposite answers; the reporting one won the fleet sweep.

    Both halves are exercised WITHOUT the refresh middleware, deliberately: the middleware repairs
    the divergence, and a tripwire that only fires when nothing has repaired it must be tested in
    exactly that state. `posture` must be able to tell the truth on its own."""
    violations = []
    for m_name, material in sorted(_MATERIAL.items()):
        for v_name, view in sorted(_SETTINGS_VIEW.items()):
            for mode in ("auto", "enforce", "dev-open"):
                s = ServiceSecrets("policy-material-svc", env=dict(material),
                                   state_path=str(tmp_path / f"{m_name}-{v_name}-{mode}.json"))
                s.load()
                with override_settings(SECRETS=s, ANDREA_AUTH_MODE=mode, **view):
                    posture = s.posture
                    status = _data_get(middleware=False).status_code
                    # getattr: this sweep must be able to RUN against a tree without the fix, or an
                    # AttributeError would abort it and hide the violation it exists to find.
                    enforcing = getattr(s, "enforcing", None)
                if posture == "enforcing" and status == 200:
                    violations.append(f"{m_name}/{v_name}/{mode}: posture=enforcing anon=200")
                if enforcing and status == 200:
                    violations.append(f"{m_name}/{v_name}/{mode}: enforcing=True anon=200")
    assert violations == []


def test_holding_material_the_auth_layer_cannot_see_reports_open_not_enforcing(tmp_path):
    """The tripwire itself, named. `open` is deliberately NOT `unconfigured`: one is a dev service
    behaving exactly as intended, the other is a provisioned service with a hole, and they need
    opposite responses. A fleet sweep that cannot tell them apart cannot act on either."""
    s = ServiceSecrets("policy-material-svc", env={"OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS},
                       state_path=str(tmp_path / "stamp.json"))
    s.load()
    with override_settings(SECRETS=s, ANDREA_SVC_KEYS=None, OIDC_ISSUER="", OIDC_JWKS_URL=""):
        assert s.auth_material_present() is True           # we HOLD a credential
        assert credsmod.settings_auth_configured() is False  # the auth layer cannot see it
        assert _data_get(middleware=False).status_code == 200      # ⚑ it IS open, on the wire
        assert s.posture == "open"                         # and we SAY SO
        assert s.status()["counters"]["creds_unconfigured"] == 1   # the fleet metric counts it open
        assert s.enforcing is False
        assert s.status()["enforcing"] is False

    # ...and a genuinely unconfigured service is still plain "unconfigured", not a false alarm
    t = ServiceSecrets("policy-material-svc", env={}, state_path=str(tmp_path / "t.json"))
    t.load()
    with override_settings(SECRETS=t, ANDREA_SVC_KEYS=None, OIDC_ISSUER="", OIDC_JWKS_URL=""):
        assert t.posture == "unconfigured"


def test_creds_status_reports_the_provenance_of_every_auth_material_name(tmp_path, monkeypatch):
    """The one thing delivering OIDC material from the config plane genuinely adds is an ADDITIVE
    issuer — silent, where a swapped service key is noisy (the operator's own key stops working).
    The answer is provenance: `source: config-service` on OIDC_ISSUER is the line that makes it
    not silent. Digests, never values."""
    s = _secrets(tmp_path, monkeypatch=monkeypatch,
                 tier1={"OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS})
    with override_settings(SECRETS=s, ANDREA_SVC_KEYS=None, OIDC_ISSUER=ISSUER, OIDC_JWKS_URL=JWKS):
        body = s.status()
    assert body["creds"]["OIDC_ISSUER"]["source"] == credsmod.CONFIG_SERVICE
    assert body["creds"]["OIDC_JWKS_URL"]["source"] == credsmod.CONFIG_SERVICE
    assert len(body["creds"]["OIDC_ISSUER"]["digest"]) == 16
    blob = json.dumps(body, default=str)
    assert ISSUER not in blob and JWKS not in blob and KEY not in blob
    assert "auth-source=config-service" in s.announce(force=True)


# ══════════════════════════════════════════════════════════════════════════════════════════════
# ROUND-2 REGRESSION GUARDS — every control D1/D2/D3 bought must still hold
# ══════════════════════════════════════════════════════════════════════════════════════════════
def test_apply_to_env_still_refuses_the_auth_mode_and_still_withholds_material():
    """The floor: policy REFUSED, material NOT OVERLAID. Both stay out of os.environ — the
    difference is that material is delivered elsewhere and policy is delivered nowhere."""
    for k in ("ANDREA_AUTH_MODE", "ANDREA_SVC_KEYS", "ANDREA_SVC_API_KEY", "OIDC_ISSUER",
              "OIDC_JWKS_URL", "ANDREA_SECRETS_ENV_FILES", "ANDREA_CREDS_HONOR_WITHDRAWAL",
              "CFG_BENIGN"):
        os.environ.pop(k, None)
    applied = configmod.apply_to_env("svc", prefetched={
        "ANDREA_AUTH_MODE": "dev-open",
        "ANDREA_SVC_API_KEY": "attacker-chosen",
        "OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS,
        "ANDREA_SECRETS_ENV_FILES": "/tmp/attacker.env",
        "ANDREA_CREDS_HONOR_WITHDRAWAL": "1",
        "CFG_BENIGN": "9",
    })
    for name in ("ANDREA_AUTH_MODE", "ANDREA_SVC_API_KEY", "OIDC_ISSUER", "OIDC_JWKS_URL",
                 "ANDREA_SECRETS_ENV_FILES", "ANDREA_CREDS_HONOR_WITHDRAWAL"):
        assert name not in os.environ, name
    assert os.environ.get("CFG_BENIGN") == "9"
    assert applied == 1


def test_dev_open_still_cannot_open_an_oidc_configured_service():
    """D1, on the OIDC half. `configured` is consulted FIRST: no statement about posture may
    override the FACT that a credential exists."""
    perm = ServiceKeyRequiredIfConfigured()
    req = rf.get("/data")
    req.user = None
    with override_settings(ANDREA_SVC_KEYS=None, OIDC_ISSUER=ISSUER, OIDC_JWKS_URL=JWKS,
                           ANDREA_AUTH_MODE="dev-open"):
        assert perm.has_permission(req, None) is False


def test_the_legacy_reload_path_delivers_oidc_material_but_never_blanks_it(monkeypatch):
    """The unmigrated services (no settings.SECRETS) have os.environ as their ONLY delivery path.
    Material must arrive there — and an EMPTY row must never be written over a live credential,
    because two empty strings IS `settings_auth_configured() -> False`."""
    from andrea_svc_web import reload as reloadmod

    for k in ("OIDC_ISSUER", "OIDC_JWKS_URL", "ANDREA_AUTH_MODE"):
        os.environ.pop(k, None)
    configmod.record_applied({})
    monkeypatch.setattr(reloadmod, "fetch_config",
                        lambda *a, **k: {"OIDC_ISSUER": ISSUER, "OIDC_JWKS_URL": JWKS,
                                         "ANDREA_AUTH_MODE": "dev-open"})
    with override_settings(ANDREA_SVC_KEYS=None, OIDC_ISSUER="", OIDC_JWKS_URL=""):
        out = reloadmod.reload_config()
        assert bool(dj.OIDC_ISSUER) and bool(dj.OIDC_JWKS_URL)     # delivered
        assert credsmod.settings_auth_configured() is True
        assert out["refused_auth_control"] == ["ANDREA_AUTH_MODE"]  # policy did not
        assert "ANDREA_AUTH_MODE" not in os.environ

        monkeypatch.setattr(reloadmod, "fetch_config",
                            lambda *a, **k: {"OIDC_ISSUER": "", "OIDC_JWKS_URL": ""})
        out = reloadmod.reload_config()
        assert bool(dj.OIDC_ISSUER) and bool(dj.OIDC_JWKS_URL)     # an empty row blanks NOTHING
        assert credsmod.settings_auth_configured() is True
        # ...and it is REPORTED under its own label — "policy refused" and "credential not erased"
        # are different events, and one label for both is how a fail-open reads as a protection
        assert out["withheld_blank_material"] == ["OIDC_ISSUER", "OIDC_JWKS_URL"]
        assert "refused_auth_control" not in out
