@@ -1463,6 +1463,151 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
1463
1463
require .Equal (t , http .StatusOK , resp .StatusCode )
1464
1464
assertWorkspaceLastUsedAtUpdated (t , appDetails )
1465
1465
})
1466
+
1467
+ t .Run ("CORS" , func (t * testing.T ) {
1468
+ t .Parallel ()
1469
+
1470
+ // Set up test headers that should be returned by the app
1471
+ testHeaders := http.Header {
1472
+ "Access-Control-Allow-Origin" : []string {"*" },
1473
+ "Access-Control-Allow-Methods" : []string {"GET, POST, OPTIONS" },
1474
+ }
1475
+
1476
+ unauthenticatedClient := func (t * testing.T , appDetails * Details ) * codersdk.Client {
1477
+ c := appDetails .AppClient (t )
1478
+ c .SetSessionToken ("" )
1479
+ return c
1480
+ }
1481
+
1482
+ authenticatedClient := func (t * testing.T , appDetails * Details ) * codersdk.Client {
1483
+ uc , _ := coderdtest .CreateAnotherUser (t , appDetails .SDKClient , appDetails .FirstUser .OrganizationID , rbac .RoleMember ())
1484
+ c := appDetails .AppClient (t )
1485
+ c .SetSessionToken (uc .SessionToken ())
1486
+ return c
1487
+ }
1488
+
1489
+ ownerClient := func (t * testing.T , appDetails * Details ) * codersdk.Client {
1490
+ return appDetails .SDKClient
1491
+ }
1492
+
1493
+ tests := []struct {
1494
+ name string
1495
+ shareLevel codersdk.WorkspaceAgentPortShareLevel
1496
+ behavior codersdk.AppCORSBehavior
1497
+ client func (t * testing.T , appDetails * Details ) * codersdk.Client
1498
+ expectedStatusCode int
1499
+ expectedCORSHeaders bool
1500
+ }{
1501
+ // Public
1502
+ {
1503
+ name : "Default/Public" ,
1504
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelPublic ,
1505
+ behavior : codersdk .AppCORSBehaviorSimple ,
1506
+ expectedCORSHeaders : false ,
1507
+ client : unauthenticatedClient ,
1508
+ expectedStatusCode : http .StatusOK ,
1509
+ },
1510
+ {
1511
+ name : "Passthru/Public" ,
1512
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelPublic ,
1513
+ behavior : codersdk .AppCORSBehaviorPassthru ,
1514
+ expectedCORSHeaders : true ,
1515
+ client : unauthenticatedClient ,
1516
+ expectedStatusCode : http .StatusOK ,
1517
+ },
1518
+ // Authenticated
1519
+ {
1520
+ name : "Default/Authenticated" ,
1521
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelAuthenticated ,
1522
+ behavior : codersdk .AppCORSBehaviorSimple ,
1523
+ expectedCORSHeaders : false ,
1524
+ client : authenticatedClient ,
1525
+ expectedStatusCode : http .StatusOK ,
1526
+ },
1527
+ {
1528
+ name : "Passthru/Authenticated" ,
1529
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelAuthenticated ,
1530
+ behavior : codersdk .AppCORSBehaviorPassthru ,
1531
+ expectedCORSHeaders : true ,
1532
+ client : authenticatedClient ,
1533
+ expectedStatusCode : http .StatusOK ,
1534
+ },
1535
+ {
1536
+ // The CORS behavior will not affect unauthenticated requests.
1537
+ // The request will be redirected to the login page.
1538
+ name : "Passthru/Unauthenticated" ,
1539
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelAuthenticated ,
1540
+ behavior : codersdk .AppCORSBehaviorPassthru ,
1541
+ expectedCORSHeaders : false ,
1542
+ client : unauthenticatedClient ,
1543
+ expectedStatusCode : http .StatusSeeOther ,
1544
+ },
1545
+ // Owner
1546
+ {
1547
+ name : "Default/Owner" ,
1548
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelAuthenticated , // Owner is not a valid share level for ports.
1549
+ behavior : codersdk .AppCORSBehaviorSimple ,
1550
+ expectedCORSHeaders : false ,
1551
+ client : ownerClient ,
1552
+ expectedStatusCode : http .StatusOK ,
1553
+ },
1554
+ {
1555
+ name : "Passthru/Owner" ,
1556
+ shareLevel : codersdk .WorkspaceAgentPortShareLevelAuthenticated , // Owner is not a valid share level for ports.
1557
+ behavior : codersdk .AppCORSBehaviorPassthru ,
1558
+ expectedCORSHeaders : true ,
1559
+ client : ownerClient ,
1560
+ expectedStatusCode : http .StatusOK ,
1561
+ },
1562
+ }
1563
+
1564
+ for _ , tc := range tests {
1565
+ t .Run (tc .name , func (t * testing.T ) {
1566
+ t .Parallel ()
1567
+
1568
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
1569
+ defer cancel ()
1570
+
1571
+ appDetails := setupProxyTest (t , & DeploymentOptions {
1572
+ headers : testHeaders ,
1573
+ })
1574
+ port , err := strconv .ParseInt (appDetails .Apps .Port .AppSlugOrPort , 10 , 32 )
1575
+ require .NoError (t , err )
1576
+
1577
+ // Update the template CORS behavior.
1578
+ b := codersdk .AppCORSBehavior (tc .behavior )
1579
+ template , err := appDetails .SDKClient .UpdateTemplateMeta (ctx , appDetails .Workspace .TemplateID , codersdk.UpdateTemplateMeta {
1580
+ CORSBehavior : & b ,
1581
+ })
1582
+ require .NoError (t , err )
1583
+ require .Equal (t , tc .behavior , template .CORSBehavior )
1584
+
1585
+ // Set the port we have to be shared.
1586
+ _ , err = appDetails .SDKClient .UpsertWorkspaceAgentPortShare (ctx , appDetails .Workspace .ID , codersdk.UpsertWorkspaceAgentPortShareRequest {
1587
+ AgentName : proxyTestAgentName ,
1588
+ Port : int32 (port ),
1589
+ ShareLevel : tc .shareLevel ,
1590
+ Protocol : codersdk .WorkspaceAgentPortShareProtocolHTTP ,
1591
+ })
1592
+ require .NoError (t , err )
1593
+
1594
+ client := tc .client (t , appDetails )
1595
+
1596
+ resp , err := requestWithRetries (ctx , t , client , http .MethodGet , appDetails .SubdomainAppURL (appDetails .Apps .Port ).String (), nil )
1597
+ require .NoError (t , err )
1598
+ defer resp .Body .Close ()
1599
+ require .Equal (t , tc .expectedStatusCode , resp .StatusCode )
1600
+
1601
+ if tc .expectedCORSHeaders {
1602
+ require .Equal (t , testHeaders .Get ("Access-Control-Allow-Origin" ), resp .Header .Get ("Access-Control-Allow-Origin" ))
1603
+ require .Equal (t , testHeaders .Get ("Access-Control-Allow-Methods" ), resp .Header .Get ("Access-Control-Allow-Methods" ))
1604
+ } else {
1605
+ require .Empty (t , resp .Header .Get ("Access-Control-Allow-Origin" ))
1606
+ require .Empty (t , resp .Header .Get ("Access-Control-Allow-Methods" ))
1607
+ }
1608
+ })
1609
+ }
1610
+ })
1466
1611
})
1467
1612
1468
1613
t .Run ("AppSharing" , func (t * testing.T ) {
0 commit comments