
    4j2                       d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlmZ  ee      j                         Zej"                  d   Zedz  dz  Zdd	d
dddZddZd Z e       \  ZZeduxr eduZdZ G d dej6                        Z ej:                  ee       G d dej6                               ZddZe dk(  r*es e!e        e!de d        ejD                  d       yy)uy  task-2553+34 TRACK C2 — independent adversarial regression for the policy profile engine.

Two-phase design (task md §3, 9-R.2):

  * Phase-A (engine-independent, ALWAYS runs): validates that the five adversarial
    fixtures are well-formed and internally consistent. This makes the suite
    non-vacuous even while C1 (task-2553+33) is unsettled.

  * Phase-B (engine-consuming): if the C1 core `anu_v3.policy_profile_engine`
    is importable with a usable decision entrypoint, drive every fixture through
    it and assert the fail-closed contract. If the engine is absent, the
    Phase-B tests SKIP (not fail) and the suite records DEFERRED_PENDING_C1.

C2 scope invariant: this file only READS C1 artifacts. It never imports for
side effects, never writes engine/schema files, never mutates the profile
registry. Absence of C1 ⇒ DEFERRED, never HOLD, never FAIL (task md §8).
    )annotationsN)Path   memoryfixturesz"task-2553+34.profile-mismatch.jsonz!task-2553+34.missing-profile.jsonztask-2553+34.stale-profile.jsonz$task-2553+34.forbidden-boundary.jsonz*task-2553+34.allow-vs-forbid-conflict.json)profile_mismatchmissing_profilestale_profileforbidden_boundaryallow_vs_forbid_conflictc                    t        t        t        |    z  dd      5 }t        j                  |      cd d d        S # 1 sw Y   y xY w)Nrzutf-8)encoding)openFIXTURE_DIRFIXTURESjsonload)namefhs     Y/home/jay/workspace/tests/regression/test_policy_profile_engine_adversarial_2553plus34.py_loadr   (   s9    	kHTN*C'	B byy}  s	   <Ac                     	 t        j                  d      } dD ]   }t        | |d      }t	        |      s| |fc S  t        | dd      }|| |fS | dfS # t        $ r Y yw xY w)a#  Return (module, callable) for the C1 policy profile engine, or (None, None).

    The exact public entrypoint name is owned by C1 (task-2553+33). We probe a
    set of plausible callables so Phase-B activates the moment C1 settles
    without this C2 file having to write into C1 scope.
    zanu_v3.policy_profile_engine)NN)evaluatedecideresolverunevaluate_goal_requestNPolicyProfileEngine)	importlibimport_module	Exceptiongetattrcallable)modattrfnclss       r   _discover_enginer)   0   s    %%&DE R S$%B<7N #,d
3C
Cx9  s   A 	AAu   DEFERRED_PENDING_C1: anu_v3.policy_profile_engine (task-2553+33 C1 core) not present / no usable entrypoint. Phase-B re-runs automatically once C1 settles. This is an explicit terminal deferral, NOT a HOLD and NOT a FAIL (task md §3/§8/9-R.2).c                  .    e Zd ZdZd Zd Zd Zd Zd Zy)PhaseAFixtureContractTestszBThe fixtures themselves must be well-formed adversarial contracts.c                    t         j                         D ]f  \  }}t        |z  }| j                  |j	                         d|        t        |      }| j                  |d   d       | j                  |d   d       h y )Nzmissing fixture file: taskztask-2553+34trackC2)r   itemsr   
assertTrueexistsr   assertEqual)selfkeyfnamepdatas        r   'test_all_fixtures_present_and_parseablezBPhaseAFixtureContractTests.test_all_fixtures_present_and_parseableT   ss    "..* 	2JCe#AOOAHHJ*@(HI:DT&\>:T']D1	2    c                8   t         D ]  }t        |      }|d   }| j                  |d   d| d       | j                  |d   d       | j                  |d   g | d       | j                  |d          | j                  t	        |d	         d
k\  | d        y )Nexpected_engine_behaviorgateHOLDz2: adversarial fixture must expect fail-closed HOLDdecision_statusallowed_actions_expansionz/: no privilege expansion permitted under attackforbidden_enforcedmust_not   z/: must enumerate explicit false-positive guards)r   r   r3   r1   len)r4   r5   r8   behs       r   2test_each_fixture_declares_fail_closed_expectationzMPhaseAFixtureContractTests.test_each_fixture_declares_fail_closed_expectation\   s     	C:D12CFV%IJ S!23V</0"%FG OOC 456OOC
O$)%FG	r:   c                    t         D ]q  }t        |      }| j                  d|       | j                  t	        |d         dk\  | d       |d   D ]&  }| j                  d|       | j                  d|       ( s y )Nphase_b_assertionsr   z: needs >=2 Phase-B predicates	predicate	rationale)r   r   assertInr1   rD   )r4   r5   r8   as       r   :test_each_fixture_has_machine_checkable_phase_b_assertionszUPhaseAFixtureContractTests.test_each_fixture_has_machine_checkable_phase_b_assertionso   s     		.C:DMM.5OOD-./14%56 ./ .k1-k1-.		.r:   c                z    t         D ch c]  }t        |      d    }}h d}| j                  ||d       y c c}w )Nadversarial_class>   forbidden_boundary_breachmissing_profile_fail_openprofile_identity_mismatchstale_profile_silent_consume#allow_vs_forbid_precedence_conflictu;   task md §2 mandates exactly these five adversarial classes)r   r   r3   )r4   kclassesrequireds       r   -test_required_adversarial_classes_are_coveredzHPhaseAFixtureContractTests.test_required_adversarial_classes_are_covered{   sD    :BCQ58/0CC
 	XI	
 Ds   8c                    t        d      }|d   d   }| j                  d|d          | j                  d|d          | j                  |d   d   d	       y )
Nr   profile_registry_stateresolved_profile_bodymerge_prallowed_actionsforbidden_actionsr<   precedence_rule_appliedFORBID_DOMINATES_ALLOW)r   rK   r3   )r4   r8   bodys      r   ,test_conflict_fixture_pins_forbid_precedencezGPhaseAFixtureContractTests.test_conflict_fixture_pins_forbid_precedence   sf    /0,-.EFj$'8"9:j$':";<+,-FG$	
r:   N)	__name__
__module____qualname____doc__r9   rF   rM   rX   rb    r:   r   r+   r+   Q   s    L2&
.

r:   r+   c                  @    e Zd ZdZd
dZdddZd Zd Zd Zd Z	d	 Z
y)PhaseBEngineAdversarialTestsa  Drive each adversarial fixture through the real C1 engine.

    These assertions are intentionally strict: a true positive requires the
    SPECIFIC hold reason, not merely any HOLD, so a precedence/coverage bug
    cannot hide behind an unrelated failure.
    c                   |d   d   }||j                  d      |d   j                  d      |d   j                  d      d}t        }|| j                  t               t	        |t
              rJ |       }dD ]-  }t        ||d       }t        |      st         ||            c S  | j                  d       t         ||            S )	Ninputgoal_requestrZ   planned_effective_actionseffective_diff_files)rl   rZ   rm   rn   )r   r   r   r   z=engine class present but no decision method (DEFERRED-shaped))	get_ENGINE_ENTRYskipTestDEFER_REASON
isinstancetyper#   r$   
_normalize)r4   fixturegrctxentryinstmr'   s           r   _decidez$PhaseBEngineAdversarialTests._decide   s    Wn-&-kk2J&K)0)9)=)=>Y)Z$+G$4$8$89O$P	
 =MM,'eT"7D= /T1d+B<%bg../ MMYZ%*%%r:   Nc                    dD ]g  }|9| j                  |j                  |g       g d| d|j                  |              >| j                  ||j                  |g       d| d| d       i y)zCodex MED resolution: a fail-closed HOLD must not leak permission
        through ANY resolved permission surface, not just `allowed_actions`.)r]   effective_allowed_actionsresolved_allowed_actionsexpanded_actionsNz)fail-closed HOLD leaked permissions via 'z': zforbidden token 'z' leaked via '')r3   ro   assertNotIn)r4   dtokensurfaces       r   _assert_no_residual_permissionz;PhaseBEngineAdversarialTests._assert_no_residual_permission   s    H 	G}  EE'2&?yAEERYNK[\
   155"-'wnWIQG	r:   c                    t        d      }| j                  |      }| j                  |d   d       | j                  d|j	                  dg              | j                  |       y )Nr   statusr>   rR   hold_reasonsr   r|   r3   rK   ro   r   r4   fr   s      r   'test_profile_mismatch_holds_fail_closedzDPhaseBEngineAdversarialTests.test_profile_mismatch_holds_fail_closed   sV    $%LLO8f-11553LM++A.r:   c                   t        d      }| j                  |      }| j                  |d   d       | j                  d|j	                  dg              | j                  |       | j                  |j	                  dd      d       | j                  |j	                  dd      d	       |j	                  d
      xs |j	                  d      xs g }| j                  t        |      g d       y )Nr	   r   r>   r   registry_mutatedFz<missing-profile HOLD must not mutate/create a registry entryprofile_createdz3missing-profile HOLD must not auto-create a profilecreated_profilesregistry_writesz>missing-profile HOLD must leave the profile registry unchanged)r   r|   r3   rK   ro   r   assertFalselist)r4   r   r   createds       r   0test_missing_profile_fails_closed_no_side_effectzMPhaseBEngineAdversarialTests.test_missing_profile_fails_closed_no_side_effect   s    #$LLO8f-'~r)BC++A. 	EE$e,J	
 	EE#U+A	
 %%*+Mquu5F/GM2M2L	
r:   c                    t        d      }| j                  |      }| j                  |d   d       | j                  d|j	                  dg              | j                  |       y )Nr
   r   r>   r   r   r   s      r   *test_stale_profile_holds_with_refresh_hintzGPhaseBEngineAdversarialTests.test_stale_profile_holds_with_refresh_hint   sT    /"LLO8f-oquu^R'@A++A.r:   c           	     N   t        d      }| j                  |      }| j                  |d   d       | j                  d|j	                  dg              dj                  t        t        |j	                  dg                   }|d   d	   D ]  }| j                  ||d
|         y )Nr   r   r>   rP   r    boundary_violationsrk   rn   z,forbidden file not surfaced as a violation: )r   r|   r3   rK   ro   joinmapstr)r4   r   r   
violationsforbidden_files        r   6test_forbidden_boundary_breach_all_violations_reportedzSPhaseBEngineAdversarialTests.test_forbidden_boundary_breach_all_violations_reported   s    &'LLO8f-11553LMXXc#quu-BB'GHI
j)?@ 	NMM
>~>NO	r:   c                   t        d      }| j                  |      }| j                  |d   d       | j                  d|j	                  dg       d       | j                  |j	                  d      dd       | j                  |d	
       y )Nr   r   r>   r   zythe action-axis ALLOW/FORBID collision must be an explicit hold cause, not masked by the co-located forbidden-path breachprecedence_ruler`   z=precedence must be an explicit deterministic fail-closed ruler\   )r   r   r   s      r   .test_allow_vs_forbid_conflict_forbid_dominateszKPhaseBEngineAdversarialTests.test_allow_vs_forbid_conflict_forbid_dominates   s    ,-LLO8f- 	&nb(AH	
 	EE#$&>K	
 	++AZ+@r:   )rv   dictreturnr   )N)r   r   r   z
str | None)rc   rd   re   rf   r|   r   r   r   r   r   r   rg   r:   r   ri   ri      s+    &( /
./
Ar:   ri   c                   t        | t              r| S dD ]B  }t        | |d      }t        |      s |       }t        |t              r|c S t        |      c S  i }dD ]  }t	        | |      st        | |      ||<     |S )zCoerce a variety of plausible engine return shapes into a dict view.

    C1 owns the exact decision schema; we accept dicts, objects with a
    `to_dict`/`as_dict`, or attribute-style decision objects.
    )to_dictas_dictasdictN)r   r   r]   r~   r   )rs   r   r#   r$   hasattr)decisionr{   r'   resoutrU   s         r   ru   ru     s     (D!- ?Xq$'B<$C$S$/3>T#Y>	?
 C * 8QXq)CF* Jr:   __main__zengine_present=z(  (Phase-A still runs; Phase-B deferred))	verbosity)r   r   r   r   )r   r   )#rf   
__future__r   builtins@py_builtins_pytest.assertion.rewrite	assertionrewrite
@pytest_arr    r   unittestpathlibr   __file__r   _THISparentsWS_ROOTr   r   r   r)   _ENGINE_MODrp   ENGINE_PRESENTrr   TestCaser+   
skipUnlessri   ru   rc   printmainrg   r:   r   <module>r      s-  $ #        	X 
--
 :- =:6@ L* ./ ]D(F]$-F` @
!2!2 @
L ^\2sA8#4#4 sA 3sAl4 zl//WXYHMMA	 r:   