@@ -43,6 +43,30 @@ import (
4343 "github.com/tonistiigi/fsutil"
4444)
4545
46+ var provenanceTests = integration .TestFuncs (
47+ testProvenanceAttestation ,
48+ testGitProvenanceAttestation ,
49+ testMultiPlatformProvenance ,
50+ testClientFrontendProvenance ,
51+ testClientLLBProvenance ,
52+ testSecretSSHProvenance ,
53+ testOCILayoutProvenance ,
54+ testNilProvenance ,
55+ testDuplicatePlatformProvenance ,
56+ testDockerIgnoreMissingProvenance ,
57+ testCommandSourceMapping ,
58+ testFrontendDeduplicateSources ,
59+ testDuplicateLayersProvenance ,
60+ testProvenanceExportLocal ,
61+ testProvenanceExportLocalForceSplit ,
62+ testProvenanceExportLocalMultiPlatform ,
63+ testProvenanceExportLocalMultiPlatformNoSplit ,
64+ )
65+
66+ func init () {
67+ allTests = append (allTests , provenanceTests ... )
68+ }
69+
4670func testProvenanceAttestation (t * testing.T , sb integration.Sandbox ) {
4771 workers .CheckFeatureCompat (t , sb , workers .FeatureDirectPush , workers .FeatureProvenance )
4872 ctx := sb .Context ()
@@ -1735,3 +1759,238 @@ RUN date +%s > /b.txt
17351759 require .NotNil (t , layers )
17361760 require .Len (t , layers , 1 )
17371761}
1762+
1763+ func testProvenanceExportLocal (t * testing.T , sb integration.Sandbox ) {
1764+ integration .SkipOnPlatform (t , "windows" )
1765+ workers .CheckFeatureCompat (t , sb , workers .FeatureProvenance )
1766+ ctx := sb .Context ()
1767+
1768+ c , err := client .New (ctx , sb .Address ())
1769+ require .NoError (t , err )
1770+ defer c .Close ()
1771+
1772+ f := getFrontend (t , sb )
1773+
1774+ dockerfile := []byte (`
1775+ FROM busybox:latest AS base
1776+ COPY <<EOF /out/foo
1777+ ok
1778+ EOF
1779+
1780+ FROM scratch
1781+ COPY --from=base /out /
1782+ ` )
1783+ dir := integration .Tmpdir (
1784+ t ,
1785+ fstest .CreateFile ("Dockerfile" , dockerfile , 0600 ),
1786+ )
1787+
1788+ destDir := t .TempDir ()
1789+ _ , err = f .Solve (sb .Context (), c , client.SolveOpt {
1790+ LocalMounts : map [string ]fsutil.FS {
1791+ dockerui .DefaultLocalNameDockerfile : dir ,
1792+ dockerui .DefaultLocalNameContext : dir ,
1793+ },
1794+ FrontendAttrs : map [string ]string {
1795+ "attest:provenance" : "mode=max" ,
1796+ },
1797+ Exports : []client.ExportEntry {
1798+ {
1799+ Type : client .ExporterLocal ,
1800+ OutputDir : destDir ,
1801+ },
1802+ },
1803+ }, nil )
1804+ require .NoError (t , err )
1805+
1806+ dt , err := os .ReadFile (filepath .Join (destDir , "foo" ))
1807+ require .NoError (t , err )
1808+ require .Equal (t , "ok\n " , string (dt ))
1809+
1810+ dt , err = os .ReadFile (filepath .Join (destDir , "provenance.json" ))
1811+ require .NoError (t , err )
1812+ require .NotEqual (t , 0 , len (dt ))
1813+
1814+ var pred provenancetypes.ProvenancePredicateSLSA02
1815+ require .NoError (t , json .Unmarshal (dt , & pred ))
1816+ }
1817+
1818+ func testProvenanceExportLocalForceSplit (t * testing.T , sb integration.Sandbox ) {
1819+ integration .SkipOnPlatform (t , "windows" )
1820+ workers .CheckFeatureCompat (t , sb , workers .FeatureProvenance )
1821+ ctx := sb .Context ()
1822+
1823+ c , err := client .New (ctx , sb .Address ())
1824+ require .NoError (t , err )
1825+ defer c .Close ()
1826+
1827+ f := getFrontend (t , sb )
1828+
1829+ dockerfile := []byte (`
1830+ FROM busybox:latest AS base
1831+ COPY <<EOF /out/foo
1832+ ok
1833+ EOF
1834+
1835+ FROM scratch
1836+ COPY --from=base /out /
1837+ ` )
1838+ dir := integration .Tmpdir (
1839+ t ,
1840+ fstest .CreateFile ("Dockerfile" , dockerfile , 0600 ),
1841+ )
1842+
1843+ destDir := t .TempDir ()
1844+ _ , err = f .Solve (sb .Context (), c , client.SolveOpt {
1845+ LocalMounts : map [string ]fsutil.FS {
1846+ dockerui .DefaultLocalNameDockerfile : dir ,
1847+ dockerui .DefaultLocalNameContext : dir ,
1848+ },
1849+ FrontendAttrs : map [string ]string {
1850+ "attest:provenance" : "mode=max" ,
1851+ },
1852+ Exports : []client.ExportEntry {
1853+ {
1854+ Type : client .ExporterLocal ,
1855+ OutputDir : destDir ,
1856+ Attrs : map [string ]string {
1857+ "platform-split" : "true" ,
1858+ },
1859+ },
1860+ },
1861+ }, nil )
1862+ require .NoError (t , err )
1863+
1864+ expPlatform := strings .ReplaceAll (platforms .FormatAll (platforms .DefaultSpec ()), "/" , "_" )
1865+
1866+ dt , err := os .ReadFile (filepath .Join (destDir , expPlatform , "foo" ))
1867+ require .NoError (t , err )
1868+ require .Equal (t , "ok\n " , string (dt ))
1869+
1870+ dt , err = os .ReadFile (filepath .Join (destDir , expPlatform , "provenance.json" ))
1871+ require .NoError (t , err )
1872+ require .NotEqual (t , 0 , len (dt ))
1873+
1874+ var pred provenancetypes.ProvenancePredicateSLSA02
1875+ require .NoError (t , json .Unmarshal (dt , & pred ))
1876+ }
1877+
1878+ func testProvenanceExportLocalMultiPlatform (t * testing.T , sb integration.Sandbox ) {
1879+ integration .SkipOnPlatform (t , "windows" )
1880+ workers .CheckFeatureCompat (t , sb , workers .FeatureMultiPlatform , workers .FeatureProvenance )
1881+ ctx := sb .Context ()
1882+
1883+ c , err := client .New (ctx , sb .Address ())
1884+ require .NoError (t , err )
1885+ defer c .Close ()
1886+
1887+ f := getFrontend (t , sb )
1888+
1889+ dockerfile := []byte (`
1890+ FROM busybox:latest AS base
1891+ COPY <<EOF /out/foo
1892+ ok
1893+ EOF
1894+
1895+ FROM scratch
1896+ COPY --from=base /out /
1897+ ` )
1898+ dir := integration .Tmpdir (
1899+ t ,
1900+ fstest .CreateFile ("Dockerfile" , dockerfile , 0600 ),
1901+ )
1902+
1903+ destDir := t .TempDir ()
1904+ _ , err = f .Solve (sb .Context (), c , client.SolveOpt {
1905+ LocalMounts : map [string ]fsutil.FS {
1906+ dockerui .DefaultLocalNameDockerfile : dir ,
1907+ dockerui .DefaultLocalNameContext : dir ,
1908+ },
1909+ FrontendAttrs : map [string ]string {
1910+ "attest:provenance" : "mode=max" ,
1911+ "platform" : "linux/amd64,linux/arm64" ,
1912+ },
1913+ Exports : []client.ExportEntry {
1914+ {
1915+ Type : client .ExporterLocal ,
1916+ OutputDir : destDir ,
1917+ },
1918+ },
1919+ }, nil )
1920+ require .NoError (t , err )
1921+
1922+ for _ , platform := range []string {"linux_amd64" , "linux_arm64" } {
1923+ dt , err := os .ReadFile (filepath .Join (destDir , platform , "foo" ))
1924+ require .NoError (t , err )
1925+ require .Equal (t , "ok\n " , string (dt ))
1926+
1927+ dt , err = os .ReadFile (filepath .Join (destDir , platform , "provenance.json" ))
1928+ require .NoError (t , err )
1929+ require .NotEqual (t , 0 , len (dt ))
1930+
1931+ var pred provenancetypes.ProvenancePredicateSLSA02
1932+ require .NoError (t , json .Unmarshal (dt , & pred ))
1933+ }
1934+ }
1935+
1936+ func testProvenanceExportLocalMultiPlatformNoSplit (t * testing.T , sb integration.Sandbox ) {
1937+ integration .SkipOnPlatform (t , "windows" )
1938+ workers .CheckFeatureCompat (t , sb , workers .FeatureMultiPlatform , workers .FeatureProvenance )
1939+ ctx := sb .Context ()
1940+
1941+ c , err := client .New (ctx , sb .Address ())
1942+ require .NoError (t , err )
1943+ defer c .Close ()
1944+
1945+ f := getFrontend (t , sb )
1946+
1947+ dockerfile := []byte (`
1948+ FROM busybox:latest AS base
1949+ ARG TARGETARCH
1950+ COPY <<EOF /out/foo_${TARGETARCH}
1951+ ok
1952+ EOF
1953+
1954+ FROM scratch
1955+ COPY --from=base /out /
1956+ ` )
1957+ dir := integration .Tmpdir (
1958+ t ,
1959+ fstest .CreateFile ("Dockerfile" , dockerfile , 0600 ),
1960+ )
1961+
1962+ destDir := t .TempDir ()
1963+ _ , err = f .Solve (sb .Context (), c , client.SolveOpt {
1964+ LocalMounts : map [string ]fsutil.FS {
1965+ dockerui .DefaultLocalNameDockerfile : dir ,
1966+ dockerui .DefaultLocalNameContext : dir ,
1967+ },
1968+ FrontendAttrs : map [string ]string {
1969+ "attest:provenance" : "mode=max" ,
1970+ "platform" : "linux/amd64,linux/arm64" ,
1971+ },
1972+ Exports : []client.ExportEntry {
1973+ {
1974+ Type : client .ExporterLocal ,
1975+ OutputDir : destDir ,
1976+ Attrs : map [string ]string {
1977+ "platform-split" : "false" ,
1978+ },
1979+ },
1980+ },
1981+ }, nil )
1982+ require .NoError (t , err )
1983+
1984+ for _ , arch := range []string {"amd64" , "arm64" } {
1985+ dt , err := os .ReadFile (filepath .Join (destDir , "foo_" + arch ))
1986+ require .NoError (t , err )
1987+ require .Equal (t , "ok\n " , string (dt ))
1988+
1989+ dt , err = os .ReadFile (filepath .Join (destDir , "provenance.linux_" + arch + ".json" ))
1990+ require .NoError (t , err )
1991+ require .NotEqual (t , 0 , len (dt ))
1992+
1993+ var pred provenancetypes.ProvenancePredicateSLSA02
1994+ require .NoError (t , json .Unmarshal (dt , & pred ))
1995+ }
1996+ }
0 commit comments