@@ -13,9 +13,11 @@ import (
13
13
"time"
14
14
15
15
ctestutil "github.com/hashicorp/consul/testutil"
16
+ "github.com/hashicorp/nomad/client/allocdir"
16
17
"github.com/hashicorp/nomad/client/config"
17
18
"github.com/hashicorp/nomad/client/taskenv"
18
19
"github.com/hashicorp/nomad/helper"
20
+ "github.com/hashicorp/nomad/helper/testlog"
19
21
"github.com/hashicorp/nomad/helper/uuid"
20
22
"github.com/hashicorp/nomad/nomad/mock"
21
23
"github.com/hashicorp/nomad/nomad/structs"
@@ -1455,6 +1457,255 @@ func TestTaskTemplateManager_Config_VaultNamespace(t *testing.T) {
1455
1457
assert .Equal (testNS , * ctconf .Vault .Namespace , "Vault Namespace Value" )
1456
1458
}
1457
1459
1460
+ // TestTaskTemplateManager_Escapes asserts that when sandboxing is enabled
1461
+ // interpolated paths are not incorrectly treated as escaping the alloc dir.
1462
+ func TestTaskTemplateManager_Escapes (t * testing.T ) {
1463
+ t .Parallel ()
1464
+
1465
+ clientConf := config .DefaultConfig ()
1466
+ require .False (t , clientConf .TemplateConfig .DisableSandbox , "expected sandbox to be disabled" )
1467
+
1468
+ // Set a fake alloc dir to make test output more realistic
1469
+ clientConf .AllocDir = "/fake/allocdir"
1470
+
1471
+ clientConf .Node = mock .Node ()
1472
+ alloc := mock .Alloc ()
1473
+ task := alloc .Job .TaskGroups [0 ].Tasks [0 ]
1474
+ logger := testlog .HCLogger (t )
1475
+ allocDir := allocdir .NewAllocDir (logger , filepath .Join (clientConf .AllocDir , alloc .ID ))
1476
+ taskDir := allocDir .NewTaskDir (task .Name )
1477
+
1478
+ containerEnv := func () * taskenv.Builder {
1479
+ // To emulate a Docker or exec tasks we must copy the
1480
+ // Set{Alloc,Task,Secrets}Dir logic in taskrunner/task_dir_hook.go
1481
+ b := taskenv .NewBuilder (clientConf .Node , alloc , task , clientConf .Region )
1482
+ b .SetAllocDir (allocdir .SharedAllocContainerPath )
1483
+ b .SetTaskLocalDir (allocdir .TaskLocalContainerPath )
1484
+ b .SetSecretsDir (allocdir .TaskSecretsContainerPath )
1485
+ return b
1486
+ }
1487
+
1488
+ rawExecEnv := func () * taskenv.Builder {
1489
+ // To emulate a unisolated tasks we must copy the
1490
+ // Set{Alloc,Task,Secrets}Dir logic in taskrunner/task_dir_hook.go
1491
+ b := taskenv .NewBuilder (clientConf .Node , alloc , task , clientConf .Region )
1492
+ b .SetAllocDir (taskDir .SharedAllocDir )
1493
+ b .SetTaskLocalDir (taskDir .LocalDir )
1494
+ b .SetSecretsDir (taskDir .SecretsDir )
1495
+ return b
1496
+ }
1497
+
1498
+ cases := []struct {
1499
+ Name string
1500
+ Config func () * TaskTemplateManagerConfig
1501
+
1502
+ // Set to skip a test; remove once bugs are fixed
1503
+ Skip bool
1504
+
1505
+ // Expected paths to be returned if Err is nil
1506
+ SourcePath string
1507
+ DestPath string
1508
+
1509
+ // Err is the expected error to be returned or nil
1510
+ Err error
1511
+ }{
1512
+ {
1513
+ Name : "ContainerOk" ,
1514
+ Config : func () * TaskTemplateManagerConfig {
1515
+ return & TaskTemplateManagerConfig {
1516
+ ClientConfig : clientConf ,
1517
+ TaskDir : taskDir .Dir ,
1518
+ EnvBuilder : containerEnv (),
1519
+ Templates : []* structs.Template {
1520
+ {
1521
+ SourcePath : "${NOMAD_TASK_DIR}/src" ,
1522
+ DestPath : "${NOMAD_SECRETS_DIR}/dst" ,
1523
+ },
1524
+ },
1525
+ }
1526
+ },
1527
+ SourcePath : filepath .Join (taskDir .Dir , "local/src" ),
1528
+ DestPath : filepath .Join (taskDir .Dir , "secrets/dst" ),
1529
+ },
1530
+ {
1531
+ Name : "ContainerSrcEscapesErr" ,
1532
+ Config : func () * TaskTemplateManagerConfig {
1533
+ return & TaskTemplateManagerConfig {
1534
+ ClientConfig : clientConf ,
1535
+ TaskDir : taskDir .Dir ,
1536
+ EnvBuilder : containerEnv (),
1537
+ Templates : []* structs.Template {
1538
+ {
1539
+ SourcePath : "/etc/src_escapes" ,
1540
+ DestPath : "${NOMAD_SECRETS_DIR}/dst" ,
1541
+ },
1542
+ },
1543
+ }
1544
+ },
1545
+ Err : sourceEscapesErr ,
1546
+ },
1547
+ {
1548
+ Name : "ContainerSrcEscapesOk" ,
1549
+ Config : func () * TaskTemplateManagerConfig {
1550
+ unsafeConf := clientConf .Copy ()
1551
+ unsafeConf .TemplateConfig .DisableSandbox = true
1552
+ return & TaskTemplateManagerConfig {
1553
+ ClientConfig : unsafeConf ,
1554
+ TaskDir : taskDir .Dir ,
1555
+ EnvBuilder : containerEnv (),
1556
+ Templates : []* structs.Template {
1557
+ {
1558
+ SourcePath : "/etc/src_escapes_ok" ,
1559
+ DestPath : "${NOMAD_SECRETS_DIR}/dst" ,
1560
+ },
1561
+ },
1562
+ }
1563
+ },
1564
+ SourcePath : "/etc/src_escapes_ok" ,
1565
+ DestPath : filepath .Join (taskDir .Dir , "secrets/dst" ),
1566
+ },
1567
+ {
1568
+ Name : "ContainerDstAbsoluteOk" ,
1569
+ Config : func () * TaskTemplateManagerConfig {
1570
+ return & TaskTemplateManagerConfig {
1571
+ ClientConfig : clientConf ,
1572
+ TaskDir : taskDir .Dir ,
1573
+ EnvBuilder : containerEnv (),
1574
+ Templates : []* structs.Template {
1575
+ {
1576
+ SourcePath : "${NOMAD_TASK_DIR}/src" ,
1577
+ DestPath : "/etc/absolutely_relative" ,
1578
+ },
1579
+ },
1580
+ }
1581
+ },
1582
+ SourcePath : filepath .Join (taskDir .Dir , "local/src" ),
1583
+ DestPath : filepath .Join (taskDir .Dir , "etc/absolutely_relative" ),
1584
+ },
1585
+ {
1586
+ Name : "ContainerDstAbsoluteEscapesErr" ,
1587
+ Config : func () * TaskTemplateManagerConfig {
1588
+ return & TaskTemplateManagerConfig {
1589
+ ClientConfig : clientConf ,
1590
+ TaskDir : taskDir .Dir ,
1591
+ EnvBuilder : containerEnv (),
1592
+ Templates : []* structs.Template {
1593
+ {
1594
+ SourcePath : "${NOMAD_TASK_DIR}/src" ,
1595
+ DestPath : "../escapes" ,
1596
+ },
1597
+ },
1598
+ }
1599
+ },
1600
+ Err : destEscapesErr ,
1601
+ },
1602
+ {
1603
+ Name : "ContainerDstAbsoluteEscapesOk" ,
1604
+ Config : func () * TaskTemplateManagerConfig {
1605
+ unsafeConf := clientConf .Copy ()
1606
+ unsafeConf .TemplateConfig .DisableSandbox = true
1607
+ return & TaskTemplateManagerConfig {
1608
+ ClientConfig : unsafeConf ,
1609
+ TaskDir : taskDir .Dir ,
1610
+ EnvBuilder : containerEnv (),
1611
+ Templates : []* structs.Template {
1612
+ {
1613
+ SourcePath : "${NOMAD_TASK_DIR}/src" ,
1614
+ DestPath : "../escapes" ,
1615
+ },
1616
+ },
1617
+ }
1618
+ },
1619
+ SourcePath : filepath .Join (taskDir .Dir , "local/src" ),
1620
+ DestPath : filepath .Join (taskDir .Dir , ".." , "escapes" ),
1621
+ },
1622
+ //TODO: Fix this test. I *think* it should pass. The double
1623
+ // joining of the task dir onto the destination seems like
1624
+ // a bug. https://github.com/hashicorp/nomad/issues/9389
1625
+ {
1626
+ Skip : true ,
1627
+ Name : "RawExecOk" ,
1628
+ Config : func () * TaskTemplateManagerConfig {
1629
+ return & TaskTemplateManagerConfig {
1630
+ ClientConfig : clientConf ,
1631
+ TaskDir : taskDir .Dir ,
1632
+ EnvBuilder : rawExecEnv (),
1633
+ Templates : []* structs.Template {
1634
+ {
1635
+ SourcePath : "${NOMAD_TASK_DIR}/src" ,
1636
+ DestPath : "${NOMAD_SECRETS_DIR}/dst" ,
1637
+ },
1638
+ },
1639
+ }
1640
+ },
1641
+ SourcePath : filepath .Join (taskDir .Dir , "local/src" ),
1642
+ DestPath : filepath .Join (taskDir .Dir , "secrets/dst" ),
1643
+ },
1644
+ {
1645
+ Name : "RawExecSrcEscapesErr" ,
1646
+ Config : func () * TaskTemplateManagerConfig {
1647
+ return & TaskTemplateManagerConfig {
1648
+ ClientConfig : clientConf ,
1649
+ TaskDir : taskDir .Dir ,
1650
+ EnvBuilder : rawExecEnv (),
1651
+ Templates : []* structs.Template {
1652
+ {
1653
+ SourcePath : "/etc/src_escapes" ,
1654
+ DestPath : "${NOMAD_SECRETS_DIR}/dst" ,
1655
+ },
1656
+ },
1657
+ }
1658
+ },
1659
+ Err : sourceEscapesErr ,
1660
+ },
1661
+ {
1662
+ Name : "RawExecDstAbsoluteOk" ,
1663
+ Config : func () * TaskTemplateManagerConfig {
1664
+ return & TaskTemplateManagerConfig {
1665
+ ClientConfig : clientConf ,
1666
+ TaskDir : taskDir .Dir ,
1667
+ EnvBuilder : rawExecEnv (),
1668
+ Templates : []* structs.Template {
1669
+ {
1670
+ SourcePath : "${NOMAD_TASK_DIR}/src" ,
1671
+ DestPath : "/etc/absolutely_relative" ,
1672
+ },
1673
+ },
1674
+ }
1675
+ },
1676
+ SourcePath : filepath .Join (taskDir .Dir , "local/src" ),
1677
+ DestPath : filepath .Join (taskDir .Dir , "etc/absolutely_relative" ),
1678
+ },
1679
+ }
1680
+
1681
+ for i := range cases {
1682
+ tc := cases [i ]
1683
+ t .Run (tc .Name , func (t * testing.T ) {
1684
+ if tc .Skip {
1685
+ t .Skip ("FIXME: Skipping broken test" )
1686
+ }
1687
+ config := tc .Config ()
1688
+ mapping , err := parseTemplateConfigs (config )
1689
+ if tc .Err == nil {
1690
+ // Ok path
1691
+ require .NoError (t , err )
1692
+ require .NotNil (t , mapping )
1693
+ require .Len (t , mapping , 1 )
1694
+ for k := range mapping {
1695
+ require .Equal (t , tc .SourcePath , * k .Source )
1696
+ require .Equal (t , tc .DestPath , * k .Destination )
1697
+ t .Logf ("Rendering %s => %s" , * k .Source , * k .Destination )
1698
+ }
1699
+ } else {
1700
+ // Err path
1701
+ assert .EqualError (t , err , tc .Err .Error ())
1702
+ require .Nil (t , mapping )
1703
+ }
1704
+
1705
+ })
1706
+ }
1707
+ }
1708
+
1458
1709
func TestTaskTemplateManager_BlockedEvents (t * testing.T ) {
1459
1710
t .Parallel ()
1460
1711
require := require .New (t )
0 commit comments