|
42 | 42 | #include "nix/util/signals.hh"
|
43 | 43 |
|
44 | 44 | #include "store-config-private.hh"
|
| 45 | +#include "build/derivation-check.hh" |
45 | 46 |
|
46 | 47 | namespace nix {
|
47 | 48 |
|
@@ -335,13 +336,6 @@ class DerivationBuilderImpl : public DerivationBuilder, public DerivationBuilder
|
335 | 336 | */
|
336 | 337 | SingleDrvOutputs registerOutputs();
|
337 | 338 |
|
338 |
| - /** |
339 |
| - * Check that an output meets the requirements specified by the |
340 |
| - * 'outputChecks' attribute (or the legacy |
341 |
| - * '{allowed,disallowed}{References,Requisites}' attributes). |
342 |
| - */ |
343 |
| - void checkOutputs(const std::map<std::string, ValidPathInfo> & outputs); |
344 |
| - |
345 | 339 | public:
|
346 | 340 |
|
347 | 341 | void deleteTmpDir(bool force) override;
|
@@ -1810,7 +1804,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
1810 | 1804 | }
|
1811 | 1805 |
|
1812 | 1806 | /* Apply output checks. */
|
1813 |
| - checkOutputs(infos); |
| 1807 | + checkOutputs(store, drvPath, drvOptions.outputChecks, infos); |
1814 | 1808 |
|
1815 | 1809 | /* Register each output path as valid, and register the sets of
|
1816 | 1810 | paths referenced by each of them. If there are cycles in the
|
@@ -1849,149 +1843,6 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
1849 | 1843 | return builtOutputs;
|
1850 | 1844 | }
|
1851 | 1845 |
|
1852 |
| -void DerivationBuilderImpl::checkOutputs(const std::map<std::string, ValidPathInfo> & outputs) |
1853 |
| -{ |
1854 |
| - std::map<Path, const ValidPathInfo &> outputsByPath; |
1855 |
| - for (auto & output : outputs) |
1856 |
| - outputsByPath.emplace(store.printStorePath(output.second.path), output.second); |
1857 |
| - |
1858 |
| - for (auto & output : outputs) { |
1859 |
| - auto & outputName = output.first; |
1860 |
| - auto & info = output.second; |
1861 |
| - |
1862 |
| - /* Compute the closure and closure size of some output. This |
1863 |
| - is slightly tricky because some of its references (namely |
1864 |
| - other outputs) may not be valid yet. */ |
1865 |
| - auto getClosure = [&](const StorePath & path) { |
1866 |
| - uint64_t closureSize = 0; |
1867 |
| - StorePathSet pathsDone; |
1868 |
| - std::queue<StorePath> pathsLeft; |
1869 |
| - pathsLeft.push(path); |
1870 |
| - |
1871 |
| - while (!pathsLeft.empty()) { |
1872 |
| - auto path = pathsLeft.front(); |
1873 |
| - pathsLeft.pop(); |
1874 |
| - if (!pathsDone.insert(path).second) |
1875 |
| - continue; |
1876 |
| - |
1877 |
| - auto i = outputsByPath.find(store.printStorePath(path)); |
1878 |
| - if (i != outputsByPath.end()) { |
1879 |
| - closureSize += i->second.narSize; |
1880 |
| - for (auto & ref : i->second.references) |
1881 |
| - pathsLeft.push(ref); |
1882 |
| - } else { |
1883 |
| - auto info = store.queryPathInfo(path); |
1884 |
| - closureSize += info->narSize; |
1885 |
| - for (auto & ref : info->references) |
1886 |
| - pathsLeft.push(ref); |
1887 |
| - } |
1888 |
| - } |
1889 |
| - |
1890 |
| - return std::make_pair(std::move(pathsDone), closureSize); |
1891 |
| - }; |
1892 |
| - |
1893 |
| - auto applyChecks = [&](const DerivationOptions::OutputChecks & checks) { |
1894 |
| - if (checks.maxSize && info.narSize > *checks.maxSize) |
1895 |
| - throw BuildError( |
1896 |
| - "path '%s' is too large at %d bytes; limit is %d bytes", |
1897 |
| - store.printStorePath(info.path), |
1898 |
| - info.narSize, |
1899 |
| - *checks.maxSize); |
1900 |
| - |
1901 |
| - if (checks.maxClosureSize) { |
1902 |
| - uint64_t closureSize = getClosure(info.path).second; |
1903 |
| - if (closureSize > *checks.maxClosureSize) |
1904 |
| - throw BuildError( |
1905 |
| - "closure of path '%s' is too large at %d bytes; limit is %d bytes", |
1906 |
| - store.printStorePath(info.path), |
1907 |
| - closureSize, |
1908 |
| - *checks.maxClosureSize); |
1909 |
| - } |
1910 |
| - |
1911 |
| - auto checkRefs = [&](const StringSet & value, bool allowed, bool recursive) { |
1912 |
| - /* Parse a list of reference specifiers. Each element must |
1913 |
| - either be a store path, or the symbolic name of the output |
1914 |
| - of the derivation (such as `out'). */ |
1915 |
| - StorePathSet spec; |
1916 |
| - for (auto & i : value) { |
1917 |
| - if (store.isStorePath(i)) |
1918 |
| - spec.insert(store.parseStorePath(i)); |
1919 |
| - else if (auto output = get(outputs, i)) |
1920 |
| - spec.insert(output->path); |
1921 |
| - else { |
1922 |
| - std::string outputsListing = |
1923 |
| - concatMapStringsSep(", ", outputs, [](auto & o) { return o.first; }); |
1924 |
| - throw BuildError( |
1925 |
| - "derivation '%s' output check for '%s' contains an illegal reference specifier '%s'," |
1926 |
| - " expected store path or output name (one of [%s])", |
1927 |
| - store.printStorePath(drvPath), |
1928 |
| - outputName, |
1929 |
| - i, |
1930 |
| - outputsListing); |
1931 |
| - } |
1932 |
| - } |
1933 |
| - |
1934 |
| - auto used = recursive ? getClosure(info.path).first : info.references; |
1935 |
| - |
1936 |
| - if (recursive && checks.ignoreSelfRefs) |
1937 |
| - used.erase(info.path); |
1938 |
| - |
1939 |
| - StorePathSet badPaths; |
1940 |
| - |
1941 |
| - for (auto & i : used) |
1942 |
| - if (allowed) { |
1943 |
| - if (!spec.count(i)) |
1944 |
| - badPaths.insert(i); |
1945 |
| - } else { |
1946 |
| - if (spec.count(i)) |
1947 |
| - badPaths.insert(i); |
1948 |
| - } |
1949 |
| - |
1950 |
| - if (!badPaths.empty()) { |
1951 |
| - std::string badPathsStr; |
1952 |
| - for (auto & i : badPaths) { |
1953 |
| - badPathsStr += "\n "; |
1954 |
| - badPathsStr += store.printStorePath(i); |
1955 |
| - } |
1956 |
| - throw BuildError( |
1957 |
| - "output '%s' is not allowed to refer to the following paths:%s", |
1958 |
| - store.printStorePath(info.path), |
1959 |
| - badPathsStr); |
1960 |
| - } |
1961 |
| - }; |
1962 |
| - |
1963 |
| - /* Mandatory check: absent whitelist, and present but empty |
1964 |
| - whitelist mean very different things. */ |
1965 |
| - if (auto & refs = checks.allowedReferences) { |
1966 |
| - checkRefs(*refs, true, false); |
1967 |
| - } |
1968 |
| - if (auto & refs = checks.allowedRequisites) { |
1969 |
| - checkRefs(*refs, true, true); |
1970 |
| - } |
1971 |
| - |
1972 |
| - /* Optimization: don't need to do anything when |
1973 |
| - disallowed and empty set. */ |
1974 |
| - if (!checks.disallowedReferences.empty()) { |
1975 |
| - checkRefs(checks.disallowedReferences, false, false); |
1976 |
| - } |
1977 |
| - if (!checks.disallowedRequisites.empty()) { |
1978 |
| - checkRefs(checks.disallowedRequisites, false, true); |
1979 |
| - } |
1980 |
| - }; |
1981 |
| - |
1982 |
| - std::visit( |
1983 |
| - overloaded{ |
1984 |
| - [&](const DerivationOptions::OutputChecks & checks) { applyChecks(checks); }, |
1985 |
| - [&](const std::map<std::string, DerivationOptions::OutputChecks> & checksPerOutput) { |
1986 |
| - if (auto outputChecks = get(checksPerOutput, outputName)) |
1987 |
| - |
1988 |
| - applyChecks(*outputChecks); |
1989 |
| - }, |
1990 |
| - }, |
1991 |
| - drvOptions.outputChecks); |
1992 |
| - } |
1993 |
| -} |
1994 |
| - |
1995 | 1846 | void DerivationBuilderImpl::deleteTmpDir(bool force)
|
1996 | 1847 | {
|
1997 | 1848 | if (topTmpDir != "") {
|
|
0 commit comments