@@ -144,7 +144,6 @@ impl traverse::Visitor for PolicyExtractionVisitor<'_> {
144
144
node : & executable:: Field ,
145
145
) -> Result < ( ) , BoxError > {
146
146
self . get_policies_from_field ( field_def) ;
147
-
148
147
traverse:: field ( self , field_def, node)
149
148
}
150
149
@@ -1334,6 +1333,140 @@ mod tests {
1334
1333
}
1335
1334
"# ;
1336
1335
1336
+ #[ test]
1337
+ fn interface_with_implementor_not_defining_field_level_policy ( ) {
1338
+ static SCHEMA : & str = r#"
1339
+ schema
1340
+ @link(url: "https://specs.apollo.dev/link/v1.0")
1341
+ @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1342
+ @link(url: "https://specs.apollo.dev/policy/v0.1", for: SECURITY)
1343
+ {
1344
+ query: Query
1345
+ }
1346
+ directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
1347
+ directive @policy(policies: [[String!]!]!) on OBJECT | FIELD_DEFINITION | INTERFACE | SCALAR | ENUM
1348
+ scalar link__Import
1349
+ enum link__Purpose {
1350
+ """
1351
+ `SECURITY` features provide metadata necessary to securely resolve fields.
1352
+ """
1353
+ SECURITY
1354
+
1355
+ """
1356
+ `EXECUTION` features provide metadata necessary for operation execution.
1357
+ """
1358
+ EXECUTION
1359
+ }
1360
+ type Query {
1361
+ idList(id: ID!): IList
1362
+ }
1363
+ interface IList {
1364
+ activeId: Int @policy(policies: [["read"]])
1365
+ }
1366
+
1367
+ type BidList implements IList {
1368
+ activeId: Int @policy(policies: [["read"]])
1369
+ }
1370
+
1371
+ type PublisherList implements IList {
1372
+ activeId: Int @policy(policies: [["read"]])
1373
+ }
1374
+
1375
+ # NOTE: this doesn't have a field-level @policy
1376
+ type FrequencyBidList implements IList {
1377
+ activeId: Int
1378
+ }
1379
+ "# ;
1380
+
1381
+ static QUERY : & str = r#"
1382
+ query TestIssue {
1383
+ idList(id: "1") {
1384
+ activeId
1385
+ }
1386
+ }
1387
+ "# ;
1388
+ let extracted_policies = extract ( SCHEMA , QUERY ) ;
1389
+ // should have a duplicate test that provides the `read` policy instead of `HashSet::new()`,
1390
+ // which should result in `successful_policies` to contain `read` as well
1391
+ let read_policy: HashSet < String > = [ "read" . to_string ( ) ] . into_iter ( ) . collect ( ) ;
1392
+ let ( doc, paths) = filter ( SCHEMA , QUERY , read_policy) ;
1393
+ insta:: assert_snapshot!( TestResult {
1394
+ query: QUERY ,
1395
+ // this should have `read` as the extracted policy
1396
+ extracted_policies: & extracted_policies,
1397
+ successful_policies: vec![ "read" . to_string( ) ] ,
1398
+ result: doc,
1399
+ paths
1400
+ } ) ;
1401
+ }
1402
+
1403
+ #[ test]
1404
+ fn interface_with_implementor_not_defining_type_level_policy ( ) {
1405
+ static SCHEMA : & str = r#"
1406
+ schema
1407
+ @link(url: "https://specs.apollo.dev/link/v1.0")
1408
+ @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
1409
+ @link(url: "https://specs.apollo.dev/policy/v0.1", for: SECURITY)
1410
+ {
1411
+ query: Query
1412
+ }
1413
+ directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
1414
+ directive @policy(policies: [[String!]!]!) on OBJECT | FIELD_DEFINITION | INTERFACE | SCALAR | ENUM
1415
+ scalar link__Import
1416
+ enum link__Purpose {
1417
+ """
1418
+ `SECURITY` features provide metadata necessary to securely resolve fields.
1419
+ """
1420
+ SECURITY
1421
+
1422
+ """
1423
+ `EXECUTION` features provide metadata necessary for operation execution.
1424
+ """
1425
+ EXECUTION
1426
+ }
1427
+ type Query {
1428
+ idList(id: ID!): IList
1429
+ }
1430
+ interface IList {
1431
+ activeId: Int @policy(policies: [["read"]])
1432
+ }
1433
+
1434
+ type BidList implements IList @policy(policies: [["read"]]){
1435
+ activeId: Int @policy(policies: [["read"]])
1436
+ }
1437
+
1438
+ type PublisherList implements IList @policy(policies: [["read"]]){
1439
+ activeId: Int @policy(policies: [["read"]])
1440
+ }
1441
+
1442
+ # NOTE: this doesn't have a type-level @policy
1443
+ type FrequencyBidList implements IList {
1444
+ activeId: Int
1445
+ }
1446
+ "# ;
1447
+
1448
+ static QUERY : & str = r#"
1449
+ query TestIssue {
1450
+ idList(id: "1") {
1451
+ activeId
1452
+ }
1453
+ }
1454
+ "# ;
1455
+ let extracted_policies = extract ( SCHEMA , QUERY ) ;
1456
+ // should have a duplicate test that provides the `read` policy instead of `HashSet::new()`,
1457
+ // which should result in `successful_policies` to contain `read` as well
1458
+ let read_policy: HashSet < String > = [ "read" . to_string ( ) ] . into_iter ( ) . collect ( ) ;
1459
+ let ( doc, paths) = filter ( SCHEMA , QUERY , read_policy) ;
1460
+ insta:: assert_snapshot!( TestResult {
1461
+ query: QUERY ,
1462
+ // this should have `read` as the extracted policy
1463
+ extracted_policies: & extracted_policies,
1464
+ successful_policies: vec![ "read" . to_string( ) ] ,
1465
+ result: doc,
1466
+ paths
1467
+ } ) ;
1468
+ }
1469
+
1337
1470
#[ test]
1338
1471
fn interface_field ( ) {
1339
1472
static QUERY : & str = r#"
0 commit comments