@@ -367,3 +367,256 @@ async fn policy_directive_interfaces_with_different_implementors_without_policy_
367
367
368
368
Ok ( ( ) )
369
369
}
370
+
371
+ #[ tokio:: test( flavor = "multi_thread" ) ]
372
+ async fn policy_directive_interfaces_with_different_implementors_disallowed ( ) -> Result < ( ) , BoxError >
373
+ {
374
+ // GIVEN
375
+ // * a schema with @policy
376
+ // * an interface using the @policy with implementors that have different policies
377
+ // * see the fixture for notes
378
+ // * requesting the interface directly, not one of its implementors
379
+ // * a mock coprocessor that marks the admin policy as false (unused, see note above)
380
+ // * a mock subgraph serving both public and private data
381
+ // * a context object with the admin policy set to false
382
+ // * the supergraph service layer
383
+ // * a request for a policy-gated field
384
+
385
+ let mock_coprocessor = MockServer :: start ( ) . await ;
386
+ let coprocessor_address = mock_coprocessor. uri ( ) ;
387
+
388
+ Mock :: given ( method ( "POST" ) )
389
+ . and ( path ( "/" ) )
390
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( serde_json:: json!( {
391
+ "version" : 1 ,
392
+ "stage" : "SupergraphRequest" ,
393
+ "control" : "continue" ,
394
+ "context" : {
395
+ "entries" : {
396
+ "apollo::authorization::required_policies" : {
397
+ // NOTE: see the note above, but this shouldn't govern how the test
398
+ // behaves; it's the context object that does the dirt for the TestHarness.
399
+ // Change this value if you use it with the IntegrationTest builder
400
+ "admin" : false
401
+ }
402
+ }
403
+ }
404
+ } ) ) )
405
+ . mount ( & mock_coprocessor)
406
+ . await ;
407
+
408
+ let mut subgraphs = MockedSubgraphs :: default ( ) ;
409
+ subgraphs. insert (
410
+ "subgraph_a" ,
411
+ MockSubgraph :: builder ( )
412
+ . with_json (
413
+ serde_json:: json!( { "query" : "{private{id}}" } ) ,
414
+ serde_json:: json!( { "data" : { "private" : { "id" : "123" } } } ) ,
415
+ )
416
+ . with_json (
417
+ serde_json:: json!( { "query" : "{public{id}}" } ) ,
418
+ serde_json:: json!( { "data" : { "public" : { "id" : "456" } } } ) ,
419
+ )
420
+ . with_json (
421
+ serde_json:: json!( { "query" : "{opensecret{id}}" } ) ,
422
+ serde_json:: json!( { "data" : { "opensecret" : { "id" : "789" } } } ) ,
423
+ )
424
+ . with_json (
425
+ serde_json:: json!( { "query" : "{secure{id}}" } ) ,
426
+ serde_json:: json!( { "data" : { "secure" : { "id" : "000" } } } ) ,
427
+ )
428
+ . build ( ) ,
429
+ ) ;
430
+
431
+ let supergraph_harness = TestHarness :: builder ( )
432
+ . configuration_json ( serde_json:: json!( {
433
+ "coprocessor" : {
434
+ "url" : coprocessor_address,
435
+ "supergraph" : {
436
+ "request" : {
437
+ "context" : "all"
438
+ }
439
+ }
440
+ } ,
441
+ "include_subgraph_errors" : {
442
+ "all" : true
443
+ }
444
+ } ) )
445
+ . unwrap ( )
446
+ . schema ( include_str ! (
447
+ "../../fixtures/directives/policy/policy_schema_with_interfaces.graphql"
448
+ ) )
449
+ . extra_plugin ( subgraphs)
450
+ . build_supergraph ( )
451
+ . await
452
+ . unwrap ( ) ;
453
+
454
+ let context = Context :: new ( ) ;
455
+ context
456
+ // NOTE: there is no `admin` policy in the context
457
+ . insert ( "apollo::authorization::required_policies" , json ! { [ ] } )
458
+ . unwrap ( ) ;
459
+
460
+ // WHEN
461
+ // * we make a request with the interface itself off of Query
462
+ let request = supergraph:: Request :: fake_builder ( )
463
+ . query ( r#"{ secure { id } }"# )
464
+ . context ( context)
465
+ . method ( Method :: POST )
466
+ . build ( )
467
+ . unwrap ( ) ;
468
+
469
+ // THEN
470
+ // * we don't get data
471
+
472
+ let response = supergraph_harness
473
+ . oneshot ( request)
474
+ . await
475
+ . unwrap ( )
476
+ . next_response ( )
477
+ . await
478
+ . unwrap ( )
479
+ . data
480
+ . unwrap ( ) ;
481
+
482
+ let response = response. as_object ( ) . unwrap ( ) ;
483
+
484
+ assert ! ( response. is_empty( ) ) ;
485
+ Ok ( ( ) )
486
+ }
487
+
488
+ // NOTE: this is the test to pay attention to for a recent customer question
489
+ #[ tokio:: test( flavor = "multi_thread" ) ]
490
+ async fn policy_directive_interfaces_with_different_implementors_open_question ( )
491
+ -> Result < ( ) , BoxError > {
492
+ // GIVEN
493
+ // * a schema with @policy
494
+ // * an interface using the @policy with implementors that have different policies
495
+ // * see the fixture for notes
496
+ // * requesting the interface directly, not one of its implementors
497
+ // * a mock coprocessor that marks the admin policy as true (unused, see note above)
498
+ // * a mock subgraph serving both public and private data
499
+ // * a context object with the admin policy set to true
500
+ // * the supergraph service layer
501
+ // * a request for a policy-gated field
502
+
503
+ let mock_coprocessor = MockServer :: start ( ) . await ;
504
+ let coprocessor_address = mock_coprocessor. uri ( ) ;
505
+
506
+ Mock :: given ( method ( "POST" ) )
507
+ . and ( path ( "/" ) )
508
+ . respond_with ( ResponseTemplate :: new ( 200 ) . set_body_json ( serde_json:: json!( {
509
+ "version" : 1 ,
510
+ "stage" : "SupergraphRequest" ,
511
+ "control" : "continue" ,
512
+ "context" : {
513
+ "entries" : {
514
+ "apollo::authorization::required_policies" : {
515
+ // NOTE: see the note above, but this shouldn't govern how the test
516
+ // behaves; it's the context object that does the dirt for the TestHarness.
517
+ // Change this value if you use it with the IntegrationTest builder
518
+ "admin" : true
519
+ }
520
+ }
521
+ }
522
+ } ) ) )
523
+ . mount ( & mock_coprocessor)
524
+ . await ;
525
+
526
+ let mut subgraphs = MockedSubgraphs :: default ( ) ;
527
+ subgraphs. insert (
528
+ "subgraph_a" ,
529
+ MockSubgraph :: builder ( )
530
+ . with_json (
531
+ serde_json:: json!( { "query" : "{private{id}}" } ) ,
532
+ serde_json:: json!( { "data" : { "private" : { "id" : "123" } } } ) ,
533
+ )
534
+ . with_json (
535
+ serde_json:: json!( { "query" : "{public{id}}" } ) ,
536
+ serde_json:: json!( { "data" : { "public" : { "id" : "456" } } } ) ,
537
+ )
538
+ . with_json (
539
+ serde_json:: json!( { "query" : "{opensecret{id}}" } ) ,
540
+ serde_json:: json!( { "data" : { "opensecret" : { "id" : "789" } } } ) ,
541
+ )
542
+ . with_json (
543
+ serde_json:: json!( { "query" : "{secure{id}}" } ) ,
544
+ serde_json:: json!( { "data" : { "secure" : { "id" : "000" } } } ) ,
545
+ )
546
+ . build ( ) ,
547
+ ) ;
548
+
549
+ let supergraph_harness = TestHarness :: builder ( )
550
+ . configuration_json ( serde_json:: json!( {
551
+ "coprocessor" : {
552
+ "url" : coprocessor_address,
553
+ "supergraph" : {
554
+ "request" : {
555
+ "context" : "all"
556
+ }
557
+ }
558
+ } ,
559
+ "include_subgraph_errors" : {
560
+ "all" : true
561
+ }
562
+ } ) )
563
+ . unwrap ( )
564
+ . schema ( include_str ! (
565
+ "../../fixtures/directives/policy/policy_schema_with_interfaces.graphql"
566
+ ) )
567
+ . extra_plugin ( subgraphs)
568
+ . build_supergraph ( )
569
+ . await
570
+ . unwrap ( ) ;
571
+
572
+ let context = Context :: new ( ) ;
573
+ context
574
+ . insert (
575
+ "apollo::authorization::required_policies" ,
576
+ json ! { [ "admin" ] } ,
577
+ )
578
+ . unwrap ( ) ;
579
+
580
+ // WHEN
581
+ // * we make a request with the interface itself off of Query
582
+ let request = supergraph:: Request :: fake_builder ( )
583
+ . query ( r#"{ secure { id } }"# )
584
+ . context ( context)
585
+ . method ( Method :: POST )
586
+ . build ( )
587
+ . unwrap ( ) ;
588
+
589
+ // THEN
590
+ // * we... get the data? expected? not sure
591
+
592
+ let response = supergraph_harness
593
+ . oneshot ( request)
594
+ . await
595
+ . unwrap ( )
596
+ . next_response ( )
597
+ . await
598
+ . unwrap ( )
599
+ . data
600
+ . unwrap ( ) ;
601
+
602
+ // NOTE: we're failing here; the response is null, and the expectations for this test are
603
+ // unclear: should there be data returned if an interface is queried that has a policy when
604
+ // that policy is in the context and the coprocessor returns `true` for it?
605
+ println ! ( "AWA :: response: {response:?}" ) ;
606
+
607
+ let response = response
608
+ . as_object ( )
609
+ . unwrap ( )
610
+ . get_key_value ( "secure" )
611
+ . unwrap ( )
612
+ . 1
613
+ . as_object ( )
614
+ . unwrap ( )
615
+ . get_key_value ( "id" )
616
+ . unwrap ( )
617
+ . 1 ;
618
+
619
+ assert_eq ! ( response, "000" ) ;
620
+
621
+ Ok ( ( ) )
622
+ }
0 commit comments