# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR Free Software Foundation, Inc. # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2021-01-16 21:17+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: en_US\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: YAML Front Matter: title #: _docs/archives.md #, no-wrap msgid "Archive metadata" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Most archive formats record metadata that will capture details about the build environment if no care is taken. File last modification time is obvious, but file ordering, users, groups, numeric ids, and permissions can also be of concern. Tar will be used as the main example but these tips apply to other archive formats as well." msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "File modification times" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Most archive formats will, by default, record file last modification times, while some will also record file creation times." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Tar has a way to specify the modification time that is used for all archive members:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "{% highlight sh %} $ tar --mtime='2015-10-21 00:00Z' -cf product.tar build {% endhighlight %}" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "(Notice how `Z` is used to specify that time is in the UTC [timezone]({{ \"/docs/timezones/\" | relative_url }}).)" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "For other archive formats, it is always possible to use `touch` to reset the modification times to a [predefined value]({{ \"/docs/timestamps/\" | relative_url }}) before creating the archive:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "{% highlight sh %}\n" "$ find build -print0 |\n" " xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\n" "$ zip -r product.zip build\n" "{% endhighlight %}\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "In some cases, it is preferable to keep the original times for files that have not been created or modified during the build process:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "{% highlight sh %}\n" "$ find build -newermt \"@${SOURCE_DATE_EPOCH}\" -print0 |\n" " xargs -0r touch --no-dereference --date=\"@${SOURCE_DATE_EPOCH}\"\n" "$ zip -r product.zip build\n" "{% endhighlight %}\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "A patch has been written to simplify the latter operation with GNU Tar. It is currently available in Debian since [tar](https://packages.qa.debian.org/tar) version 1.28-1. Hopefully it will be integrated upstream soon, but you might want to use it with caution. It adds a new `--clamp-mtime` flag which will only set the time when the file is more recent than the value specified with `--mtime`:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "{% highlight sh %}" msgstr "" #. type: Title # #: _docs/archives.md #, markdown-text, no-wrap msgid "Only in Debian unstable for now" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "$ tar --mtime='2015-10-21 00:00Z' --clamp-mtime -cf product.tar build {% endhighlight %}" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "This has the benefit of leaving the original file modification time untouched." msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "File ordering" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "When asked to record directories, most archive formats will read their content in the order returned by the filesystem which is [likely to be different on every run]({{ \"/docs/stable-inputs/\" | relative_url }})." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "With version 1.28, GNU Tar has gained the `--sort=name` option which will sort filenames in a locale independent manner:" msgstr "" #. type: Title # #: _docs/archives.md #, markdown-text, no-wrap msgid "Works with GNU Tar 1.28" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "$ tar --sort=name -cf product.tar build {% endhighlight %}" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "For older versions or other archive formats, it is possible to use `find` and `sort` to achieve the same effect:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "{% highlight sh %}\n" "$ find build -print0 | LC_ALL=C sort -z |\n" " tar --no-recursion --null -T - -cf product.tar\n" "{% endhighlight %}\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Care must be taken to ensure that `sort` is called in the context of the C locale to avoid any surprises related to collation order." msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "Users, groups and numeric ids" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Depending on the archive format, the user and group owning the file can be recorded. Sometimes it will be using a string, sometimes using the associated numeric ids." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "When files belong to predefined system groups, this is not a problem, but builds are often performed with regular users. Recording of the account name or its associated ids might be a source of reproducibility issues." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Tar offers a way to specify the user and group owning the file. Using `0`/`0` and `--numeric-owner` is a safe bet, as it will effectively record 0 as values:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "{% highlight sh %} $ tar --owner=0 --group=0 --numeric-owner -cf product.tar build {% endhighlight %}" msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "PAX headers" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "GNU tar defaults to the pax format and if `POSIXLY_CORRECT` is set, that adds files' ctime, atime and the PID of the tar process as non-deterministic metadata." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "To avoid this, either `unset POSIXLY_CORRECT` (only works with [tar>1.32](https://git.savannah.gnu.org/cgit/tar.git/commit/?id=ef0f882382f6)) or add to the tar call\n" "`--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime` or `--format=gnu` (both only available in GNU tar)\n" "or use `--format=ustar` if the limitations in that format are not a problem.\n" msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "Full example" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "The recommended way to create a Tar archive is thus:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "
\n" "{% highlight sh %}\n" msgstr "" #. type: Title # #: _docs/archives.md #, markdown-text, no-wrap msgid "requires GNU Tar 1.28+" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "$ tar --sort=name \\\n" " --mtime=\"@${SOURCE_DATE_EPOCH}\" \\\n" " --owner=0 --group=0 --numeric-owner \\\n" " --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \\\n" " -cf product.tar build\n" "{% endhighlight %}\n" "
\n" msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "Post-processing" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "If tools do not support options to create reproducible archives, it is always possible to perform post-processing." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "[strip-nondeterminism](https://packages.debian.org/sid/strip-nondeterminism) already has support to normalize Zip and Jar archives (with [limitations](https://bugs.debian.org/859103)). Custom scripts like Tor Browser's [re-dzip.sh](https://gitweb.torproject.org/builders/tor-browser-bundle.git/tree/gitian/build-helpers/re-dzip.sh) might also be an option." msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "Static libraries" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Static libraries (`.a`) on Unix-like systems are *ar* archives. Like other archive formats, they contain metadata, namely timestamps, UIDs, GIDs, and permissions. None are actually required for using them as libraries." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "GNU `ar` and other tools from [binutils](https://www.gnu.org/software/binutils/) have a *deterministic mode* which will use zero for UIDs, GIDs, timestamps, and use consistent file modes for all files. It can be made the default by passing the `--enable-deterministic-archives` option to `./configure`. It is already enabled by default for some distributions[^distros-with-default] and so far it seems to be pretty safe [except for Makefiles](https://bugs.debian.org/798804) using targets like `archive.a(foo.o)`." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "When binutils is not built with deterministic archives by default, build systems have to be changed to pass the right options to `ar` and friends. `ARFLAGS` can be set to `Dcvr` with many build systems to turn on the deterministic mode. Care must also be taken to pass `-D` if `ranlib` is used to create the function index." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Another option is post-processing with [strip-nondeterminism](https://packages.debian.org/sid/strip-nondeterminism) or `objcopy`:" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid " objcopy --enable-deterministic-archives libfoo.a\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "The above does not fix [file ordering]({{ \"/docs/stable-inputs/\" | relative_url }})." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "[^distros-with-default]: Debian since [version 2.25-6](https://tracker.debian.org/news/675691)/stretch, Ubuntu since version 2.25-8ubuntu1/artful 17.10. It is the default for Fedora 22 and Fedora 23, but it seems this will be [reverted in Fedora 24](https://bugzilla.redhat.com/show_bug.cgi?id=1195883)." msgstr "" #. type: Title - #: _docs/archives.md #, markdown-text, no-wrap msgid "Initramfs images" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text, no-wrap msgid "" "*cpio* archives are commonly used for initramfs images. The *cpio* header\n" "format (see `man 5 cpio`) can contain device and inode numbers, which whilst\n" "deterministic, can vary from system to system.\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "One way to filter these is by piping through bsdtar." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Example of non-deterministic code:" msgstr "" #. type: Fenced code block #: _docs/archives.md #, no-wrap msgid "" "echo ucode.bin |\n" " bsdcpio -o -H newc -R 0:0 > ucode.img\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Example of deterministic code:" msgstr "" #. type: Fenced code block #: _docs/archives.md #, no-wrap msgid "" "echo ucode.bin |\n" " bsdtar --uid 0 --gid 0 -cnf - -T - |\n" " bsdtar --null -cf - --format=newc @- > ucode.img\n" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Note that other issues such as timestamps may still require rectification prior to archival." msgstr "" #. type: Title ## #: _docs/archives.md #, markdown-text, no-wrap msgid "GNU Libtool" msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "[GNU Libtool](https://www.gnu.org/software/libtool/) prior to `74c8993c` (first included in version 2.2.7b) did not sort the find output. It appears that many packages are bootstrapped with a version prior to this." msgstr "" #. type: Plain text #: _docs/archives.md #, markdown-text msgid "Confusingly, although [GNU GCC](https://gcc.gnu.org/)'s `ltmain.sh` claims to have been generated by libtool 2.2.7a, GNU GCC actually maintains their own version of `libtool.m4` and `ltmain.sh`, which fixed this issue independently in `d41cd173e23`. This aforementioned change was first included in version 9.1.0, meaning that the reproducibility issue remains in GCC versions below that." msgstr "" #. type: YAML Front Matter: title #: _docs/build_path.md #, no-wrap msgid "Build path" msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "Some tools will record the path of the source files in their output." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "Most compilers write the path of the source in the debug information in order to locate the associated source files." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "Some tools have flags (like gzip's `-n`) that prevent them from writing the path in their output. Proposing patches to add a similar feature in other tools might be sufficiently easy." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "In most cases however, post-processing is required to either remove the build path or to normalize it to a predefined value." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "For the specific case of [debug symbols](https://en.wikipedia.org/wiki/DWARF), there is currently no good post-processing tool to change them to a pre-determined value[^debugedit]. A work-around is to [define the build path as part of the build environment]({{ \"/docs/perimeter/\" | relative_url }}), however `reprotest` changes it so this makes it harder to assess reproducibility. Certain compiler flags can work around the issue:" msgstr "" #. type: Bullet: ' * ' #: _docs/build_path.md #, markdown-text msgid "[`-fdebug-prefix-map=OLD=NEW`](https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html#index-fdebug-prefix-map) can strip directory prefixes from debug info. (available in all GCC versions, Clang 3.8)" msgstr "" #. type: Bullet: ' * ' #: _docs/build_path.md #, markdown-text msgid "[`-fmacro-prefix-map=OLD=NEW`](https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html#index-fmacro-prefix-map) is similar to `-fdebug-prefix-map`, but addresses unreproducibility due to the use of `__FILE__` macros in `assert` calls for example. (available since GCC 8 and [Clang 10](https://bugs.llvm.org/show_bug.cgi?id=38135))" msgstr "" #. type: Bullet: ' * ' #: _docs/build_path.md #, markdown-text msgid "`-ffile-prefix-map=OLD=NEW` is an alias for both `-fdebug-prefix-map` and `-fmacro-prefix-map`. (available since GCC 8 and [Clang 10](https://bugs.llvm.org/show_bug.cgi?id=38135))" msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text, no-wrap msgid "" "With dpkg >= 1.19.1, first shipped with Debian Buster, packages can enable the\n" "`-ffile-prefix-map=OLD=NEW` flag by adding the `fixfilepath` [build\n" "flag](https://manpages.debian.org/dpkg-buildflags.1) to their `debian/rules`\n" "file. For example:\n" msgstr "" #. type: Fenced code block #: _docs/build_path.md #, no-wrap msgid "export DEB_BUILD_MAINT_OPTIONS = hardening=+all reproducible=+fixfilepath\n" msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "Note that some packages save the compile options in the build output." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "[^debugedit]: [debugedit](https://fedoraproject.org/wiki/Releases/FeatureBuildId) can replace the path used at build time by a predefined one but it does that by rewriting bytes in place. As this does not reorder the hash table of strings, the resulting bytes are still depending on the original build path." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "This is also problematic because this will also apply to intermediate source files that other tools generate. As they typically will use [random file names]({{ \"/docs/randomness/\" | relative_url }}), having a fixed build path is not enough in such cases." msgstr "" #. type: Plain text #: _docs/build_path.md #, markdown-text msgid "A [build-path-prefix-map](https://reproducible-builds.org/specs/build-path-prefix-map/) specification is in discussion with the GCC developers." msgstr "" #. type: YAML Front Matter: title #: _docs/build_toolchain_from_source.md #, no-wrap msgid "Building from source" msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "Building the tools that make the environment from source is one way to allow user to reproduce it. Using the source code directly makes it easier to rely on new features, and easily works on a variety of platforms. It might not scale well for a long list of dependencies, and asking users to rebuild GCC for every piece of software they use might make them slightly unhappy." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "What follows are suggestions on how to handle building the compilation tools from source." msgstr "" #. type: Title - #: _docs/build_toolchain_from_source.md #, markdown-text, no-wrap msgid "Building using external resources" msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "The source for the different components can be retrieved from online repositories. Using release tarballs might be preferable as they are easier to cache, [mirror, checksum and verify]({{ \"/docs/volatile-inputs/\" | relative_url }}). When retrieving the source from a version control system repository, it's best to have a precise reference to the code version. With Git, using a tag with a verified signature or a commit hash will work best." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "The compilation itself can be driven by shell scripts or an extra target in the project `Makefile`." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "coreboot is a good example. The build documentation mandates to first run `make crossgcc` before building coreboot itself." msgstr "" #. type: Title - #: _docs/build_toolchain_from_source.md #, markdown-text, no-wrap msgid "Check-in everything" msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "Another approach is to check the source of the entire toolchain in the project's version control system." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "This is how several integrated operating systems like \\*BSD are developed. “Building the world” will start by building the toolchain in the version control system before building the rest of the system." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "Also Google's internal projects operate in this way. They have released [Bazel](https://bazel.io/) which is based on their internal compilation tool. Bazel is designed to drive large scale builds with speed and reproducibility in mind." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "Outside of fully integrated operating systems or corporate environments, it might be hard to push the idea of adding ten or more times the actual code base in the toolchain…" msgstr "" #. type: Title - #: _docs/build_toolchain_from_source.md #, markdown-text, no-wrap msgid "Ship the toolchain as a build product" msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "As it might be hard to ask every user to spend time rebuilding a whole toolchain, OpenWrt gives a good example of a middle ground. An “SDK” that can be downloaded alongside the system images which contains everything that is needed to build—or rebuild—extra packages." msgstr "" #. type: Plain text #: _docs/build_toolchain_from_source.md #, markdown-text msgid "In that case the SDK becomes another build product, and it has to be possible to build it reproducibly." msgstr "" #. type: YAML Front Matter: title #: _docs/buy_in.md #, no-wrap msgid "Buy-in" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Working on *reproducible builds* might look like a lot of effort with little gain at first. While [this applies to many types of work related to security](https://www.schneier.com/blog/archives/2008/09/security_roi_1.html), there are already some good arguments and testimonies on why *reproducible builds* matter." msgstr "" #. type: Title - #: _docs/buy_in.md #, markdown-text, no-wrap msgid "Resisting attacks" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "In March 2015, The Intercept [published](https://theintercept.com/2015/03/10/ispy-cia-campaign-steal-apples-secrets/) from the Snowden leaks the abstract of a talk at an [internal CIA conference in 2012](https://theintercept.com/document/2015/03/10/tcb-jamboree-2012-invitation/) about [Strawhorse: Attacking the MacOS and iOS Software Development Kit](https://theintercept.com/document/2015/03/10/strawhorse-attacking-macos-ios-software-development-kit/). The abstract clearly explains how unnamed researchers have been creating a modified version of XCode that would — without any knowledge of the developer — watermark or insert spyware in the compiled applications." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "A few months later, a malware dubbed “XcodeGhost” has been found targeting developers to make them unknowingly distribute malware embedded in iOS applications. Palo Alto Networks [describes](http://researchcenter.paloaltonetworks.com/2015/09/novel-malware-xcodeghost-modifies-xcode-infects-apple-ios-apps-and-hits-app-store/) it as:" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text, no-wrap msgid "" "> XcodeGhost is the first compiler malware in OS X. Its malicious code is\n" "> located in a Mach-O object file that was repackaged into some versions\n" "> of Xcode installers. These malicious installers were then uploaded to\n" "> Baidu’s cloud file sharing service for use by Chinese iOS/OS X\n" "> developers\n" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "The purpose of *reproducible builds* is exactly to resist such attacks. Recompiling these applications with a clean compiler would have made the problem easily visible, especially given the size of the added payload." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text, no-wrap msgid "" "As Mike Perry and Seth Schoen explained in December 2014 during [a talk at\n" "31C3](https://media.ccc.de/events/31c3_-_6240_-_en_-_saal_g_-_201412271400_-_reproducible_builds_-_mike_perry_-_seth_schoen_-_hans_steiner),\n" "problematic changes might be more subtle, and a single bit\n" "might be the only thing required to create a remotely exploitable\n" "security hole. Seth Schoen also demonstrated a kernel-level\n" "malware that would compromise the source code while it is read by\n" "the compiler, without leaving any traces on disk. While to the best of\n" "our knowledge such attacks have not been observed in the wild,\n" "reproducible builds are the only way to detect them\n" "early.\n" msgstr "" #. type: Title - #: _docs/buy_in.md #, markdown-text, no-wrap msgid "Quality assurance" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Regular tests are required to make sure that the software can be built reproducibly in various environments. Debian and other free software distributions require that their users must be able to build the software they distribute. Such regular tests help in avoiding *fail to build from source* bugs and can uncover rare build problems such as timing problems, race conditions, or builds affected by locale." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Build environments may evolve after a project is no longer receiving major developments. While working on Debian, several high impact but hard to detect bugs were identified by testing builds in varying environments. To give some examples: [a library had a different application binary interface for every build](https://bugs.debian.org/773916), [garbled strings due to encoding mismatch](https://bugs.debian.org/801855), [missing translations](https://bugs.debian.org/778486), or [changing dependencies](https://bugs.debian.org/778707)." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "The constraint of having to reflect about the build environment also helps developers to think about the relationship with external software or data providers. Relying on external sources with no backup plans might cause serious troubles in the long term." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Reproducible builds also enable the recreation of matching [debug symbols](https://en.wikipedia.org/wiki/Debugging_data_format) for a distributed build which can help understanding issues in software used in production." msgstr "" #. type: Title - #: _docs/buy_in.md #, markdown-text, no-wrap msgid "Smaller Binary Differences" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Having reproducible builds means that only changes in source code or build environment (such as the compiler version) will lead to differences in the generated binaries. This minimizes the changes in artifacts which reduces storage requirements and network traffic for delta updates." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "With similar artifacts, testing can focus on parts that changed while still preserving confidence about unchanged code. This can speed up quality assurance and development speed." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Changes to the build system can be tested easily with reproducible builds: If the output artifacts are identical, the changes will not affect runtime behavior." msgstr "" #. type: Title - #: _docs/buy_in.md #, markdown-text, no-wrap msgid "Increased Development Speed" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Dependent packages do not need to be rebuilt and dependent tasks do not need to be rerun if a rebuild of a package does not yield different results. This can significantly reduce build times and lead to faster development speeds and lower cost." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "Build speeds can also be improved by showing that cross-compilation produces the same result as native compilation and then doing the majority of builds with cross-compilation on faster machines." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "“But how can I trust my compiler?”" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "A common question related to *reproducible builds* is how is it possible to know if the build environment is not compromised if everyone is using the same binaries? Or how can I trust that the compiler I just built was not compromised by a backdoor in the compiler I used to build it?" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "The latter is known in the academic literature since the [Reflections on trusting trust](https://dx.doi.org/10.1145%2F358198.358210) paper from Ken Thompson published in 1984. It's the paper mentioned in the description of the talk about “Strawhorse” mentioned earlier." msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "The technique known as [Diverse Double-Compilation](http://www.dwheeler.com/trusting-trust/), formally defined and researched by David A. Wheeler, can answer this question. To sum up quickly how it works: given two compilers, one trusted and one under test, the compiler under test is built twice, once with each compiler. Using the compilers created from this build, the compiler under test is built again. If the output is the same, then we have a proof that no backdoors have been inserted during the compilation. For this scheme to work, the output of the final compilations need to be the same. And that's exactly where *reproducible builds* are useful." msgstr "" #. type: Title - #: _docs/buy_in.md #, markdown-text, no-wrap msgid "Other resources" msgstr "" #. type: Plain text #: _docs/buy_in.md #, markdown-text msgid "The following articles might contain even more arguments:" msgstr "" #. type: Bullet: ' * ' #: _docs/buy_in.md #, markdown-text msgid "[Cyberwar and Global Compromise](https://blog.torproject.org/blog/deterministic-builds-part-one-cyberwar-and-global-compromise) by Mike Perry from the Tor Project, 2013-08-20" msgstr "" #. type: Bullet: ' * ' #: _docs/buy_in.md #, markdown-text msgid "[Software Transparency: Part 1](https://zyan.scripts.mit.edu/blog/software-transparency/) by yan, 2014-07-11." msgstr "" #. type: YAML Front Matter: title #: _docs/checksums.md #, no-wrap msgid "Cryptographic checksums" msgstr "" #. type: Plain text #: _docs/checksums.md #, markdown-text msgid "How can users know that the build they just made has successfully reproduced the original build?" msgstr "" #. type: Plain text #: _docs/checksums.md #, markdown-text msgid "The easiest way is to make sure that the build outputs are always byte-for-byte identical. Byte-for-byte comparison is a trivial operation and can be performed in many different environments." msgstr "" #. type: Plain text #: _docs/checksums.md #, markdown-text msgid "The other benefit of having identical bytes is that it makes it possible to use [cryptographic checksums](https://en.wikipedia.org/wiki/Cryptographic_hash_function). Such checksums are really tiny compared to the full build products. They are easily exchanged even in very low bandwidth situation." msgstr "" #. type: Plain text #: _docs/checksums.md #, markdown-text msgid "For example, it makes it possible to build a software release both on a well-connected (but hard to trust) server and on a laptop behind a bad mobile connection. The digital signature can be made locally on the laptop. As the build products will be identical, the signature will be valid for the files produced on the well-connected server." msgstr "" #. type: YAML Front Matter: title #: _docs/definition.md #, no-wrap msgid "Definitions" msgstr "" #. type: Title ## #: _docs/definition.md #, markdown-text, no-wrap msgid "When is a build reproducible?" msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text msgid "A build is **reproducible** if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts." msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text msgid "The relevant attributes of the build environment, the build instructions and the source code as well as the expected reproducible artifacts are defined by the authors or distributors. The artifacts of a build are the parts of the build results that are the desired primary output." msgstr "" #. type: Title ## #: _docs/definition.md #, markdown-text, no-wrap msgid "Explanations" msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text, no-wrap msgid "" "**Source code** is usually a checkout from version control at a specific\n" "revision or a source code archive.\n" msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text, no-wrap msgid "" "**Relevant attributes of the build environment** would usually include\n" "dependencies and their versions, build configuration flags and environment\n" "variables as far as they are used by the build system (eg. the locale). It is\n" "preferable to reduce this set of attributes.\n" msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text, no-wrap msgid "" "**Artifacts** would include executables, distribution packages or filesystem\n" "images. They would not usually include build logs or similar ancillary outputs.\n" msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text msgid "The reproducibility of artifacts is **verified** by bit-by-bit comparison. This is usually performed using cryptographically secure hash functions." msgstr "" #. type: Plain text #: _docs/definition.md #, markdown-text, no-wrap msgid "" "**Authors or distributors** means parties that claim reproducibility of a set\n" "of artifacts. These may be upstream authors, distribution maintainers or any\n" "other distributor.\n" msgstr "" #. type: YAML Front Matter: title #: _docs/definition_strategies.md #, no-wrap msgid "Definition strategies" msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "There are multiple ways to define the build environment in a way that it can be distributed. The following methods are not exclusive and multiple aspects can be used for a single project." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Defining the build environment as part of the development process has a very desirable aspect: changes in the build environment can be vetted like any other changes. Updating to a new compiler version can be subject to reviews, automatic testing, and—in case things break—rollback." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "{% comment %} XXX: maybe we want to add examples? Orig example in first paragraph One can specify a reference Linux distribution and build a specific compiler version from source. {% endcomment %}" msgstr "" #. type: Title - #: _docs/definition_strategies.md #, markdown-text, no-wrap msgid "Build from source" msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "One simple way to have users reproduce the tools that are used to perform the build is making them start building the right version of these tools from source." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Using `make` or any other compilation driver, the required tools will be downloaded, built, and locally installed before compiling the software." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Like any other [inputs from the network]({{ \"/docs/volatile-inputs/\" | relative_url }}), the content of the archive where the required source for the tools is stored should be backed up and verified using cryptographic checksums." msgstr "" #. type: Title - #: _docs/definition_strategies.md #, markdown-text, no-wrap msgid "Reference distribution" msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Using a specific version of a free software distribution is another viable option for a build environment." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Ideally, it should offer stable releases (like Debian, CentOS, or FreeBSD) to avoid having constant updates to the documentation or building scripts." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Recording the exact versions of the installed packages might be helpful to diagnose issues. Some distributions also keep a complete history of source packages or binary packages available for later reinstallation." msgstr "" #. type: Title - #: _docs/definition_strategies.md #, markdown-text, no-wrap msgid "Virtual machines / containers" msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "Some aspects of the build environment can be quite simplified by using virtual machines or containers. With a virtual machine you can easily perform the build in a more controlled environment. The build user, system hostname, network configuration, or other aspects can be enforced easily on all systems." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "The downside is that it can introduce a lot of software that has to be trusted somehow. For example, it's currently not possible to install Debian in a reproducible manner[^reproducible-install]. This makes it harder to compare different installations." msgstr "" #. type: Plain text #: _docs/definition_strategies.md #, markdown-text msgid "[^reproducible-install]: Some [preliminary work](https://wiki.debian.org/ReproducibleInstalls) has been done, mainly to identify the issues. Having byte-for-byte identical installations is a requirement to make *live* distributions build in a reproducible manner, so there is interest by multiple parties in fixing the problem." msgstr "" #. type: YAML Front Matter: title #: _docs/deterministic_build_systems.md #, no-wrap msgid "Deterministic build systems" msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "A software cannot easily be built reproducibly if the source varies depending on factors that are hard or impossible to control like the ordering of files on a filesystem or the current time." msgstr "" #. type: Title - #: _docs/deterministic_build_systems.md #, markdown-text, no-wrap msgid "Drawing the line" msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "Which aspect of the build system needs to be made deterministic is deeply linked to what is defined as part of the [build environment]({{ \"/docs/perimeter/\" | relative_url }})." msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "For example, we assume that different versions of a compiler will produce different output and so usage of a specific compiler version is mandated as part of the build environment. The same assumption does not necessarily hold for more simple tools like `grep` or `sed` where the requirement for the environment can be as loose as “any recent Unix-like system”." msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "But it's hardly a good idea to mandate that the system pseudo-random number generator be initialized with a given value before performing a build, so better not having randomness affect a build output." msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "Another concrete example on where to draw the line: there is no need to care about making the build system give constant output when run in different build paths when the build path is considered part of the build environment, and thus requiring rebuilds to be performed in the same directory as the original build." msgstr "" #. type: Title - #: _docs/deterministic_build_systems.md #, markdown-text, no-wrap msgid "In a nutshell" msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "The basics on how to make a build system deterministic can be summarized as:" msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Ensure stable inputs." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Ensure stable outputs." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Capture as little as possible from the environment." msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "What follows are some advices on common issues that can affect source code or build systems that make multiple builds from the exact same source different." msgstr "" #. type: Title - #: _docs/deterministic_build_systems.md #, markdown-text, no-wrap msgid "CMake notes" msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "The default configuration of CMake makes the build directory part of the build environment. Here are some known issues and recommendations:" msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "CMake sets a `RPATH` for binaries that link to a library in the the same project. Even when this is stripped at installation time, the build-id section will be different. Possible workarounds:" msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Users can set [`CMAKE_SKIP_RPATH=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_SKIP_RPATH.html) to disable the use of RPATH. Disadvantage: programs from the build directory cannot be run without setting `LD_LIBRARY_PATH`." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Projects can set [`CMAKE_BUILD_WITH_INSTALL_RPATH=ON`](https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_WITH_INSTALL_RPATH.html) to ensure a deterministic RPATH. Disadvantage: programs from the build directory cannot be run without setting `LD_LIBRARY_PATH`." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Set [`CMAKE_BUILD_RPATH_USE_ORIGIN=ON`](https://cmake.org/cmake/help/latest/prop_tgt/BUILD_RPATH_USE_ORIGIN.html) to enable the use of relative directories in RPATH (requires CMake 3.14). This is an appropriate option for both upstream projects and downstream distributions." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Qt projects can use [rcc](https://doc.qt.io/qt-5/rcc.html) to embed resources such as translations and images. Since Qt 5.8, rcc includes the file modification time of source files in the build output. This is especially problematic for translation files that are generated at build time. Possible workarounds:" msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "(Since Qt 5.9) If a project does not rely on an accurate [QFileInfo::lastModified](https://doc.qt.io/qt-5/qfileinfo.html#lastModified), pass `--format-version 1` to `rcc`. If [`AUTORCC`](https://cmake.org/cmake/help/latest/prop_tgt/AUTORCC.html) is enabled, this can be done by setting [`CMAKE_AUTORCC_OPTIONS`](https://cmake.org/cmake/help/latest/variable/CMAKE_AUTORCC_OPTIONS.html) to `--format-version;1`. Upstream projects are encouraged to do this after checking that Qt 5.9 or newer is in use." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "(Since Qt 5.11) Set the `QT_RCC_SOURCE_DATE_OVERRIDE` environment variable which behaves similar to [`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/specs/source-date-epoch/)." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "(Since Qt 5.13) Set the `SOURCE_DATE_EPOCH` environment variable." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Ensure that generated source files are touched with a fixed timestamp before rcc is called. See also ." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Qt projects that use `Q_OBJECT` macros require [moc](https://doc.qt.io/qt-5/moc.html) to generate additional C++ files. CMake will automatically do this when [`AUTOMOC`](https://cmake.org/cmake/help/latest/prop_tgt/AUTOMOC.html) is enabled, but then the relative path from the build directory to the source directory will become part of the build environment. For example, if the build directory is `/tmp/build` and the source file is at `/tmp/foo/widget.h`, then the generated file will include `../[...]/../foo/widget.h`. Possible workarounds:" msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Use the `-p` option to override the include prefix. This requires the prefix plus the header filename to be available from the include path. See also ." msgstr "" #. type: Bullet: ' * ' #: _docs/deterministic_build_systems.md #, markdown-text msgid "Ensure that the build directory and source directory remains fixed across builds. For example, if users always create a `build` directory in the source tree, then reproducibility won't be affected." msgstr "" #. type: Title - #: _docs/deterministic_build_systems.md #, markdown-text, no-wrap msgid "Disclaimer" msgstr "" #. type: Plain text #: _docs/deterministic_build_systems.md #, markdown-text msgid "Not all problems have solutions currently. Some tools that might be used in a build process might require fixes to become non-deterministic. The Debian effort keeps a list of [all issues found](https://reproducible.debian.net/index_issues.html) while investigating reproducibility problems in its 22,000+ source packages. While some require changes in the package source itself, some can be fixed by improving or fixing the tools used to perform the builds." msgstr "" #. type: YAML Front Matter: title #: _docs/embedded_signatures.md #, no-wrap msgid "Embedded signatures" msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "Software that is distributed using embedded cryptographic signatures can pose a challenge to allow users to reproduce identical results. By definition, they will not be able to generate an identical signature. This can either be solved by making the signature part of the build process input or by offering tools to transform the distributed binaries to pristine build results." msgstr "" #. type: Title - #: _docs/embedded_signatures.md #, markdown-text, no-wrap msgid "Pasting signatures" msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "One way to handle embedded cryptographic signatures is to make the signature an (optional) input of the build process. When a signature is available, it just gets copied at the right location." msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "This enables the following workflow:" msgstr "" #. type: Bullet: '1. ' #: _docs/embedded_signatures.md #, markdown-text msgid "An initial build is made by the developers who have access to the private key." msgstr "" #. type: Bullet: '2. ' #: _docs/embedded_signatures.md #, markdown-text msgid "The build result is signed to an external file." msgstr "" #. type: Bullet: '3. ' #: _docs/embedded_signatures.md #, markdown-text msgid "The signature is made part of the released source code." msgstr "" #. type: Bullet: '4. ' #: _docs/embedded_signatures.md #, markdown-text msgid "The build that is going to be distributed is made from the latter source." msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "The `wireless-regdb` package in Debian is an example on [how this can be be implemented](https://sources.debian.net/src/wireless-regdb/latest/debian/rules/)." msgstr "" #. type: Title - #: _docs/embedded_signatures.md #, markdown-text, no-wrap msgid "Ignoring signatures" msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "A specific comparison tool can be made available that is able to compare to builds skipping the signatures. Ideally, it should also be able to produce cryptographic checksums to make downloading the original build unneeded to solely compare the results." msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "Such a tool must be **very** easy to audit and understand. Otherwise, it's hard to trust that the script is not ignoring bytes that would make it behave differently." msgstr "" #. type: Title - #: _docs/embedded_signatures.md #, markdown-text, no-wrap msgid "Stripping signatures" msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "Another option is to ship a tool that can strip the signatures from the official releases. The result can then be compared byte-for-byte with the results from the user." msgstr "" #. type: Plain text #: _docs/embedded_signatures.md #, markdown-text msgid "This method has the downside that it requires a user to download the official releases to do the comparison. It's also harder to attest that the data that is being removed will not make the software behave differently." msgstr "" #. type: YAML Front Matter: title #: _docs/formal_definition.md #, no-wrap msgid "Formal definition" msgstr "" #. type: Plain text #: _docs/formal_definition.md #, markdown-text msgid "Most free software distributions are self-contained: all tools required to build their components are part of the distribution. In such cases, it's possible to specify the build environment in a machine readable format that can be later used to reinstall the environment." msgstr "" #. type: Plain text #: _docs/formal_definition.md #, markdown-text msgid "As example, the [.buildinfo control files used by Debian](https://wiki.debian.org/ReproducibleBuilds/BuildinfoSpecification) tie in the same file: the sources, the generated binaries, and all packages used to perform the build (with the exact version number)." msgstr "" #. type: Title ### #: _docs/jvm.md _docs/recording.md #, markdown-text, no-wrap msgid "JVM" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "The conventions for the JVM ecosystem are under active development, see how-to [contribute]({{ \"/contribute/\" | relative_url }})." msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "The JVM ecosystem provides many languages and build tools. Since the JVM is not reproducible-friendly from the beginning -- jar/zip files are a first natural source of variation, with files order and timestamp --, each build tool requires some work to provide Reproducible Builds." msgstr "" #. type: Title ## #: _docs/jvm.md #, markdown-text, no-wrap msgid "`.buildinfo` file" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Whatever the build tool is, binary JVM artifacts are generally published in artifact repositories that use the Maven2 repository format (using groupId/artifactId/version coordinates) like [Maven Central](https://search.maven.org/) or [Google's Android Repository](https://dl.google.com/dl/android/maven2/index.html)." msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Being able to rebuild artifacts published in these repositories will require some information: where to get the sources from? Which build environment to setup to rebuild the artifacts?" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "This is the purpose of JVM Buildinfo files: they are expected to be published alongside artifacts as separate `${artifactId}-${version}.buildinfo` file, with content in [Java properties format](https://en.wikipedia.org/wiki/.properties):" msgstr "" #. type: Fenced code block #: _docs/jvm.md #, no-wrap msgid "" "#### Work In Progress ####\n" "buildinfo.version=1.0-SNAPSHOT\n" "\n" "name=\n" "group-id=\n" "artifact-id=\n" "version=\n" "\n" "# source information for rebuilders, as source tarball artifact in repository and/or url and/or scm coordinates\n" "source.artifact=::::\n" "source.url=\n" "source.scm.uri=\n" "source.scm.tag=\n" "\n" "# build instructions\n" "build-tool=\n" "build.setup=\n" "\n" "# effective recorded build environment information\n" "java.version=\n" "java.vendor=\n" "os.name=\n" "source.used=\n" "\n" "# Each build tool or plugin is free to add additional entries to the buildinfo,\n" "# both for build instructions and effective recorded build environment.\n" "# For example, the sbt plugin may add the following for Scala:\n" "sbt.version=1.2.3\n" "scala.version=2.12.6\n" "\n" "# and Maven could add data on rebuild instructions and effective recorded environment:\n" "mvn.rebuild-args=-Dmaven.test.skip package\n" "mvn.build-root=::\n" "mvn.version=Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)\n" "mvn.minimum.version=\n" "\n" "# A buildinfo file can contain checksums for multiple output files, for\n" "# example for the main jar and the accompanying pom.xml (when generated):\n" "outputs.0.filename=\n" "outputs.0.length=\n" "outputs.0.checksums.sha512=\n" "outputs.1.filename=\n" "outputs.1.length=\n" "outputs.1.checksums.sha512=\n" "...\n" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Notice that `${artifactId}-${version}-sources.jar` files published in Maven repositories are not buildable sources, but [sources for IDEs](https://central.sonatype.org/pages/requirements.html#supply-javadoc-and-sources)." msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Source tarballs, intended for building, are not always published in repositories but only sometimes, with 2 classical naming conventions: - `${artifactId}-${version}-source-release.zip` (see [artifacts in Central providing such source tarballs](https://search.maven.org/search?q=l:source-release)) - `${artifactId}-${version}-src.zip` (see [artifacts in Central providing such source tarballs](https://search.maven.org/search?q=l:src))" msgstr "" #. type: Title ## #: _docs/jvm.md #, markdown-text, no-wrap msgid "Auditing a Build" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Builds that are publishing a Buildinfo file are expected to be reproducible and the Buildinfo file is expected to contain everything required to rebuild and get the same output: if you find a Buildinfo file that is not sufficient to rebuild or you don't get the same result, please get in contact with the project to help improve reproducibility." msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Without Buildinfo file, as explained on top of this page, by default, jars found in public repositories probably won't be reproducible. But you can try to rebuild them and measure how much they are not reproducible:" msgstr "" #. type: Bullet: '1. ' #: _docs/jvm.md #, markdown-text msgid "download the jar from a public repository," msgstr "" #. type: Bullet: '2. ' #: _docs/jvm.md #, markdown-text msgid "determine which major version of JDK was used to produce it: usually, the full Java version is found in `META-INF/MANIFEST.MF` by running `unzip -p xxx.jar META-INF/MANIFEST.MF`" msgstr "" #. type: Bullet: '3. ' #: _docs/jvm.md #, markdown-text msgid "find sources and build instructions on originating project site" msgstr "" #. type: Bullet: '4. ' #: _docs/jvm.md #, markdown-text msgid "rebuild with a JDK of the same major version than the version found on step 2" msgstr "" #. type: Bullet: '4. ' #: _docs/jvm.md #, markdown-text msgid "examine the differences using [diffoscope](https://diffoscope.org/)" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Usually, you'll find a few files that are different, in addition to zip content timestamp and order. Notice that if you didn't use the same JDK major version, you'll see many differences in .class files." msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Improving the build to get reproducible builds will then be specific to each build tool. You may discuss issues and fixes on the [Reproducible Builds mailing list]({{ \"/docs/contribute/\" | relative_url }})." msgstr "" #. type: Title ## #: _docs/jvm.md #, markdown-text, no-wrap msgid "Reproducible Builds for Maven" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Getting reproducible builds with Maven requires some plugins configuration: see [Maven - Guide to Configuring for Reproducible Builds](https://maven.apache.org/guides/mini/guide-reproducible-builds.html) for more details." msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Work is in progress also with [maven-buildinfo-plugin](https://github.com/apache/maven-studies/tree/maven-buildinfo-plugin) to easily provide Buildinfo files once a build has been made reproducible." msgstr "" #. type: Title ### #: _docs/jvm.md #, markdown-text, no-wrap msgid "source release archive" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "To create a source release archive, see [Apache Source Release Assembly Descriptor](https://maven.apache.org/apache-resource-bundles/#Source_Release_Assembly_Descriptor) that is commonly used. Nothing prevents you to create your own assembly descriptor or even use another plugin: don't hesitate to share recipes." msgstr "" #. type: Title ### #: _docs/jvm.md #, markdown-text, no-wrap msgid "rebuild arguments" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "A rebuilder does not need to execute integration tests or even unit tests, may even skip compiling unit tests. Classical arguments contain following patterns: - `package` phase: no need to `deploy` or even `install` - `-Dmaven.test.skip`: avoid running tests and even compiling tests - `-DskipTests`: avoid running tests, but still builds (necessary for some projects) - `-Dgpg.skip`: avoid PGP signing - `-Papache-release` or any release profile: activate release-specific tasks used by `maven-release-plugin` - `-Dline.separator=$'\\r\\n'`: define Windows line endings from an Unix environment" msgstr "" #. type: Title ### #: _docs/jvm.md #, markdown-text, no-wrap msgid "multi-module build" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "For multi-module builds, each produced artifact will have its own buildinfo file with `mvn.build-root` property defined, to know the root from which the rebuild must happen." msgstr "" #. type: Title ## #: _docs/jvm.md #, markdown-text, no-wrap msgid "Reproducible Builds for Gradle" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Gradle supports [reproducible archives](https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives) as of v3.4" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "Tasks which generate archives, such as ZIPs or JARs, can enforce preserved file timestamps and reproducible file order which fix two of the main sources of non-determinism in JVM artifacts." msgstr "" #. type: Title ## #: _docs/jvm.md #, markdown-text, no-wrap msgid "Reproducible Builds for `sbt`" msgstr "" #. type: Plain text #: _docs/jvm.md #, markdown-text msgid "When using [sbt](https://www.scala-sbt.org/), a build tool popular with Scala projects, you can use the [sbt-reproducible-builds](https://github.com/raboof/sbt-reproducible-builds) plugin to strip your artifacts and share buildinfo information." msgstr "" #. type: YAML Front Matter: title #: _docs/locales.md #, no-wrap msgid "Locales" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "The locale of the build system might affect the build products. While it is important that developers have access to error messages in the language of their choice, tools which output is influenced by the current locale can make locale a source of reproducibility issues." msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "There are many aspects regarding locales (see [GNU libc locale(1) manpage](https://manpages.debian.org/locale)). The ones that follow are the most important ones to consider in the context of reproducible builds." msgstr "" #. type: Title - #: _docs/locales.md #, markdown-text, no-wrap msgid "Time format" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "Several common time formatting functions will have output depending on the current locale. On a POSIX system the formatting will depend on the `LC_CTIME` environment variable, which can be overridden by `LC_ALL`." msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "For build systems, it's thus best to use `LC_ALL` directly:" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text, no-wrap msgid "" "
\n" "{% highlight sh %}\n" "$ LC_ALL=C date -u -d '2015-10-21'\n" "Wed Oct 21 00:00:00 UTC 2015\n" "{% endhighlight %}\n" "
\n" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "The system [timezone]({{ \"/docs/timezones/\" | relative_url }}) and `TZ` environment variable will also affect the output of time formatting functions." msgstr "" #. type: Title - #: _docs/locales.md #, markdown-text, no-wrap msgid "Collation order" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "Common sorting functions are affected by the `LC_COLLATE` environment variable, which can be overridden by `LC_ALL`. Some locales can be quite surprising." msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "This typically shows when using `sort`. The `fr_FR` locale will sort independently of the character case:" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text, no-wrap msgid "" "
\n" "{% highlight sh %}\n" "$ echo B a c | tr ' ' '\\n' | LC_ALL=fr_FR.UTF-8 sort\n" "a\n" "B\n" "c\n" "{% endhighlight %}\n" "
\n" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "The `C` locale will sort according to the byte values and is always available:" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text, no-wrap msgid "" "
\n" "{% highlight sh %}\n" "$ echo B a c | tr ' ' '\\n' | LC_ALL=C sort\n" "B\n" "a\n" "c\n" "{% endhighlight %}\n" "
\n" msgstr "" #. type: Title - #: _docs/locales.md #, markdown-text, no-wrap msgid "Default character encoding" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "The default system character encoding will affect both the input and output of many tools. It is defined using the `LC_CTYPE` environment variable, and can also be overridden using `LC_ALL`." msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "Here's an example when using `lynx` to convert HTML documentation into text:" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text, no-wrap msgid "" "
\n" "{% highlight sh %}\n" "LC_ALL=fr_FR lynx -dump -width 72 docs.html | file -\n" "/dev/stdin: ISO-8859 text\n" "{% endhighlight %}\n" "
\n" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text msgid "The `C.UTF-8` pseudo-locale can always be used to get the default strings with UTF-8 output:" msgstr "" #. type: Plain text #: _docs/locales.md #, markdown-text, no-wrap msgid "" "
\n" "{% highlight sh %}\n" "LC_ALL=C.UTF-8 lynx -dump -width 72 docs.html | file -\n" "/dev/stdin: UTF-8 Unicode text\n" "{% endhighlight %}\n" "
\n" msgstr "" #. type: YAML Front Matter: title #: _docs/perimeter.md #, no-wrap msgid "What's in a build environment?" msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "Reproducible builds does not mandate that a given piece of source code is turned into the same bytes in all situations. This would be unfeasible. The output of a compiler is likely to be different from one version to another as better optimizations are integrated all the time." msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "Instead, reproducible builds happen in the context of a *build environment*. It usually comprises the set of tools, required versions, and other assumptions about the operating system and its configuration. A description of this environment should typically be [recorded]({{ \"/docs/recording/\" | relative_url }}) and provided alongside any distributed binary package." msgstr "" #. type: Title - #: _docs/perimeter.md #, markdown-text, no-wrap msgid "Requirements" msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "What exactly makes up the build environment is going to be different for each project. There might even be several build environments for a single release to accommodate different target operating systems. But there are some important aspects common to all environments." msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "It should be **easy to install** a matching build environment on the users' systems. Ideally it should only be made of free software available on public Internet sites. The best way to provide the environment is probably using a documented and easily understood script." msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "It should be **auditable**. It must be easy to understand what tools are part of the build environment. And ideally it must be easy to review and rebuild them." msgstr "" #. type: Title - #: _docs/perimeter.md #, markdown-text, no-wrap msgid "Content" msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "{% comment %} XXX: Not really happy with this section. Please help! -- Lunar {% endcomment %}" msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "The scope of the build environment needs to be properly specified as this will determine how much of the build system needs to be [deterministic]({{ \"/docs/deterministic-build-systems/\" | relative_url }})." msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "At least the defined environment has a list of the tools used by the build process and their versions." msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "The rest can be different from one project to the next, as long as it can be reproduced by interested users. To give some examples:" msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "specific operating system (if cross-compiling is not supported)," msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "build system architecture (if cross-compiling is not supported)," msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "directory where the build must happen," msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "name of the user running the build," msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "locale," msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "timezone," msgstr "" #. type: Bullet: ' * ' #: _docs/perimeter.md #, markdown-text msgid "specific environment variables (like [`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/specs/source-date-epoch/))." msgstr "" #. type: Plain text #: _docs/perimeter.md #, markdown-text msgid "Using virtual machines or containers as the recommended build environment can make it easier to ensure a specific operating system or user configuration. But they might also hide some assumptions on the environment, like specific optimizations enabled because of the [system CPU type](https://trac.torproject.org/projects/tor/ticket/12238#comment:4)." msgstr "" #. type: YAML Front Matter: title #: _docs/plans.md #, no-wrap msgid "Making plans" msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "The idea of *reproducible builds* is to empower anyone to verify that no flaws have been introduced during the build process by reproducing byte-for-byte identical binary packages from a given source." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "Achieving reproducible builds requires cooperation from multiple roles involved in software production. On small projects, all these roles might be carried by a single person, but it helps to differentiate the responsibilities." msgstr "" #. type: Title - #: _docs/plans.md #, markdown-text, no-wrap msgid "Getting a deterministic build system" msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "In order to allow software to build reproducibly, the source code must not introduce uncontrollable variations in the build output." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "Things will work better if such variations are discovered before users are confronted with unreproducible binaries. Setting up a test protocol in which rebuilds are performed under variations in the environment (aspects like time, *username*, CPU, system version, filesystems, amongst many others) will greatly help." msgstr "" #. type: Title - #: _docs/plans.md #, markdown-text, no-wrap msgid "Defining a build environment" msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "As different versions of compilation tools are likely to produce different outputs, users must be able to recreate a build environment close enough to the original build. It is not required that the toolchain[^toolchain] itself is byte-for-byte identical, but its output has to stay the same." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "The build environment can either be defined while the software is being developed or it can be recorded at build time." msgstr "" #. type: Title - #: _docs/plans.md #, markdown-text, no-wrap msgid "Distributing the build environment" msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "Users need to be able to know what build environment needs to be set up to rebuild the software." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "If the build environment is defined ahead and part of the source code, then no further steps are required." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "In other cases, it needs to be made available alongside the binaries. The ideal form is a description that can be understood by both humans and machines to make automatic verification possible, while enabling people to review that the environment is sane." msgstr "" #. type: Title - #: _docs/plans.md #, markdown-text, no-wrap msgid "Providing a comparison protocol" msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "Users must have an easy way to recreate the build environment, get the source code, perform the build, and compare the results." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "Ideally, the comparison protocol to verify that resulting binaries are identical should be simple. Comparing bytes or cryptographic hash values is easy to do and understand." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "Other technologies might require removing cryptographic signatures or ignore specific parts. Such operations must be both documented and scripted. The rationale and code must be easy to understand by reviewers." msgstr "" #. type: Plain text #: _docs/plans.md #, markdown-text msgid "[^toolchain]: By *toolchain*, we mean all pieces of software needed to create the build output." msgstr "" #. type: YAML Front Matter: title #: _docs/proprietary_os.md #, no-wrap msgid "Proprietary operating systems" msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "On proprietary operating systems, it is hard to determine if they are tampered with. Typically, they also require non-free compilation tools that can be hard to obtain for users." msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "The good news is that for some cases, we have free software tools which are able to cross-compile software for proprietary operating systems on free operating systems. Both Bitcoin and Tor Browser have pioneered the technique to build their Windows and Mac OS X versions." msgstr "" #. type: Title - #: _docs/proprietary_os.md #, markdown-text, no-wrap msgid "Windows" msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "For Windows, [mingw-w64](https://mingw-w64.org/) will build Windows binaries on POSIX compatible operating systems." msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "[NSIS](http://nsis.sourceforge.net/) can be used to create integrated installation package." msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "Both are readily available in several free software distributions." msgstr "" #. type: Title - #: _docs/proprietary_os.md #, markdown-text, no-wrap msgid "Mac OS X" msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "crosstool-ng [should work](https://bugs.torproject.org/9711#comment:73) to build software for Mac OS X. Sadly this seems to require a non-redistributable part of the Apple SDK. It can be extracted from XCode which can be downloaded at no charge." msgstr "" #. type: Plain text #: _docs/proprietary_os.md #, markdown-text msgid "Software from Mac OS X is often distributed as disk images (`.dmg`) which can be created under GNU/Linux, but it seems to [require multiple tools at the moment](https://gitweb.torproject.org/builders/tor-browser-bundle.git/tree/gitian/build-helpers/ddmg.sh)." msgstr "" #. type: YAML Front Matter: title #: _docs/publications.md #, no-wrap msgid "Academic publications" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Trusting Trust - Reflections on Trusting Trust* (1984) — Ken Thompson. ([PDF](https://www.ece.cmu.edu/~ganger/712.fall02/papers/p761-thompson.pdf))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Fully Countering Trusting Trust through Diverse Double-Compiling* (2005/2009) — David A. Wheeler ([PDF](https://dwheeler.com/trusting-trust/dissertation/wheeler-trusting-trust-ddc.pdf), [...](https://dwheeler.com/trusting-trust/))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Functional Package Management with Guix* (2013) — Ludovic Courtès. [[...](https://hal.inria.fr/hal-00824004/en])]" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Reproducible and User-Controlled Software Environments in HPC with Guix* (2015) — Ludovic Courtès, Ricardo Wurmus [[...](https://hal.inria.fr/hal-01161771/en)]" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*in-toto: Providing farm-to-table guarantees for bits and bytes* (2019) — Santiago Torres-Arias, New York University; Hammad Afzali, New Jersey Institute of Technology; Trishank Karthik Kuppusamy, Datadog; Reza Curtmola, New Jersey Institute of Technology; Justin Cappos, New York University. ([PDF](https://www.usenix.org/system/files/sec19-torres-arias.pdf))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks* (2020) — Marc Ohm, Henrik Plate, Arnold Sykosch, Michael Meier. ([PDF](https://arxiv.org/pdf/2005.09535.pdf))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Automated Localization for Unreproducible Builds* (2018) — Zhilei Ren, He Jiang, Jifeng Xuan, Zijiang Yang. ([PDF](https://arxiv.org/pdf/1803.06766.pdf))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Reproducible Containers* (2020) — Navarro Leija, Omar S. and Shiptoski, Kelly and Scott, Ryan G. and Wang, Baojun and Renner, Nicholas and Newton, Ryan R. and Devietti, Joseph. ([...](https://dl.acm.org/doi/10.1145/3373376.3378519))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Towards detection of software supply chain attacks by forensic artifacts* — Marc Ohm, Arnold Sykosch, Michael Meier. ([Link](https://dl.acm.org/doi/10.1145/3407023.3409183))" msgstr "" #. type: Bullet: '* ' #: _docs/publications.md #, markdown-text msgid "*Automated Localization for Unreproducible Builds* — Zhilei Ren, He Jiang, Jifeng Xuan & Zijiang Yang. ([PDF](https://arxiv.org/pdf/1803.06766.pdf))" msgstr "" #. type: YAML Front Matter: title #: _docs/randomness.md #, no-wrap msgid "Randomness" msgstr "" #. type: Plain text #: _docs/randomness.md #, markdown-text msgid "Random data will make builds unreproducible and must be avoided." msgstr "" #. type: Plain text #: _docs/randomness.md #, markdown-text msgid "If random-like input is required, the solution is to use a predetermined value to seed a [pseudo-random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator). This value can be read from some file, a changelog or the version control system." msgstr "" #. type: Plain text #: _docs/randomness.md #, markdown-text msgid "When Link-Time Optimizations are turned on, GCC users will write random identifiers to binary objects they create. Using `-frandom-seed` can be used for this particular case. As it will hash arbitrary data, passing the file name should work in most cases." msgstr "" #. type: Plain text #: _docs/randomness.md #, markdown-text msgid "Some compilation tools will write intermediate temporary files. This might lead to reproducibility issues if paths get embedded in the final output. There's no general solutions for such cases, better fix the code directly. One way is to use the `.file` assembler directive [like it has been done in O'Caml](https://sources.debian.net/src/ocaml/4.02.3-5/debian/patches/0010-Add-a-.file-directive-to-generated-.s-files.patch/)." msgstr "" #. type: YAML Front Matter: redirect_from #: _docs/recording.md #, no-wrap msgid "/docs/buildinfo/" msgstr "" #. type: YAML Front Matter: title #: _docs/recording.md #, no-wrap msgid "Recording the build environment" msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "It is been customary in user facing software to provide a way for developers investigating bugs to learn how the software has been built. The “about dialog” or output of `--version` typically contains information about the build environment." msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "In the context of reproducible builds, we either actively make aspects of the [build environment]({{ \"/docs/perimeter/\" | relative_url }}) irrelevant to the build output, or ensure they are available to rebuild the software exactly as distributed." msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "All relevant information about the build environment should either be defined as part of the development process or recorded during the build process." msgstr "" #. type: Title ## #: _docs/recording.md #, markdown-text, no-wrap msgid "File Format" msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "Everything that is recorded is stored best as a separate build product that can be easily ignored or distributed separately. This will help identify which variation is irrelevant to the software itself." msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "This product is called the 'buildinfo', but its exact format and the way it is distributed differs across ecosystems." msgstr "" #. type: Title ### #: _docs/recording.md #, markdown-text, no-wrap msgid "[Debian](/who/#Debian)" msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "Debian shares its buildinfo files as plain text files following the [control file format](https://www.debian.org/doc/debian-policy/ch-controlfields.html), usually clearsigned with OpenPGP. A detailed description of the expected fields and values, as well as conventions around naming, can be found under [ReproducibleBuilds/BuildinfoFiles](https://wiki.debian.org/ReproducibleBuilds/BuildinfoFiles) on the [Debian wiki](https://wiki.debian.org). Examples can be found on [buildinfo.debian.net](https://buildinfo.debian.net)." msgstr "" #. type: Title ### #: _docs/recording.md #, markdown-text, no-wrap msgid "[Arch Linux](/who/#Arch Linux)" msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text, no-wrap msgid "" "The Arch Linux [makepkg](https://wiki.archlinux.org/index.php/makepkg) build\n" "tool produces a `.BUILDINFO` file consisting of ` = ` pairs.\n" msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "Unlike on Debian, this file is not independently signed and distributed, but included into the package (and thus signed as part of the package signature). An example can be found by downloading any Arch package built with a recent version of [makepkg](https://wiki.archlinux.org/index.php/makepkg), such as [archlinux-keyring]( https://www.archlinux.org/packages/core/any/archlinux-keyring)." msgstr "" #. type: Title ### #: _docs/recording.md #, markdown-text, no-wrap msgid "[Tails](/who/#Tails)" msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "Tails does not record a buildinfo file per se, but instead the [vagrant directory of the main git repo]( https://gitlab.com/Tails/tails/tree/master/vagrant) contains all information necessary to reproducibly rebuild that revision of Tails." msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "In the JVM ecosystem it is common to distribute libraries as binary (bytecode) jars uploaded to a repository like [Maven Central](https://search.maven.org/) or [Google's Android Repository](https://dl.google.com/dl/android/maven2/index.html)." msgstr "" #. type: Plain text #: _docs/recording.md #, markdown-text msgid "It is recommended that the buildinfo describing the build environment used for that official build is published alongside each artifact. Third party attestations can be shared in a separate sig-repo. For a detailed overview of the conventions so far see the separate [JVM page]({{ \"/docs/jvm/\" | relative_url }})." msgstr "" #. type: YAML Front Matter: title #: _docs/sharing_certifications.md #, no-wrap msgid "Sharing certifications" msgstr "" #. type: Plain text #: _docs/sharing_certifications.md #, markdown-text msgid "How could users gain trust that a build has not been compromised by exchanging certifications attesting that they all have been able to get the same build results?" msgstr "" #. type: Plain text #: _docs/sharing_certifications.md #, markdown-text msgid "Debian is thinking of allowing [multiple Debian Developers to upload signatures](https://wiki.debian.org/ReproducibleBuilds/BuildinfoSpecification#buildinfo_signatures) attesting that they have been able to reproduce a build." msgstr "" #. type: Plain text #: _docs/sharing_certifications.md #, markdown-text msgid "The question is also related to the work lead by Ben Laurie on [binary transparency](https://groups.google.com/forum/#!forum/binary-transparency). The idea is to have an append-only log similar to [Certificate Transparency](https://www.certificate-transparency.org/) which could be used to authenticate binaries." msgstr "" #. type: Plain text #: _docs/sharing_certifications.md #, markdown-text msgid "More research is required in this area to make reproducible builds more effective in detecting compromise early." msgstr "" #. type: YAML Front Matter: title #: _docs/source-date-epoch.md #, no-wrap msgid "SOURCE_DATE_EPOCH" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "`SOURCE_DATE_EPOCH` is a [standardised environment variable](https://reproducible-builds.org/specs/source-date-epoch/) that distributions can set centrally and have build tools consume this in order to produce reproducible output." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Before implementing this, you should scan through [our checklist](https://wiki.debian.org/ReproducibleBuilds/StandardEnvironmentVariables#Checklist) to see if you can avoid implementing it." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "If you find that it's ideal for your use-case, please feel free to jump straight to our **[published specification](https://reproducible-builds.org/specs/source-date-epoch/)**." msgstr "" #. type: Title ## #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Proposal" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Please read our [SOURCE_DATE_EPOCH specification](https://reproducible-builds.org/specs/source-date-epoch/) for details." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "See [Standard Environment Variables](https://wiki.debian.org/ReproducibleBuilds/StandardEnvironmentVariables) for more detailed discussion of the rationales behind this mechanism." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Below we also have more detailed discussion about this specific variable, as well as documentation on history and alternative proposals." msgstr "" #. type: Title ## #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Setting the variable" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Debian" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "In Debian, this is automatically set to the same time as the latest entry in `debian/changelog`, i.e. the same as the output of `dpkg-parsechangelog -SDate`." msgstr "" #. type: Bullet: ' 1. ' #: _docs/source-date-epoch.md #, markdown-text msgid "For packages using debhelper, versions >= 9.20151004 (Bug:791823) exports this variable during builds, so you probably don't need to change anything. One exception is if your `debian/rules` needs this variable in non-debhelper parts, in which case you can try (3) or (4)." msgstr "" #. type: Bullet: ' 2. ' #: _docs/source-date-epoch.md #, markdown-text msgid "For packages using CDBS, versions >= 0.4.131 (Bug:794241) exports this variable during builds, so no changes are needed." msgstr "" #. type: Bullet: ' 3. ' #: _docs/source-date-epoch.md #, markdown-text msgid "With dpkg >= 1.18.8 (Bug:824572) you can either `include /usr/share/dpkg/pkg-info.mk` or `include /usr/share/dpkg/default.mk`." msgstr "" #. type: Bullet: ' 4. ' #: _docs/source-date-epoch.md #, markdown-text msgid "If none of the above options are good (you should have a ''very good reason'') then package maintainers may set and export this variable manually in `debian/rules`:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid " export SOURCE_DATE_EPOCH ?= $(shell dpkg-parsechangelog -STimestamp)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid " If you need/want to support dpkg versions earlier than 1.18.8:\n" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid " export SOURCE_DATE_EPOCH ?= $(shell dpkg-parsechangelog -SDate | date -f- +%s)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid " If you need/want to support dpkg versions earlier than 1.17.0:\n" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid " export SOURCE_DATE_EPOCH ?= $(shell dpkg-parsechangelog | grep -Po '^Date: \\K.*' | date -f- +%s)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid " This snippet is believed to work on dpkg versions as far back as 2003.\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Git" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "To set SOURCE_DATE_EPOCH to the last modification of a git repository you can use 'git log', for example in shell:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)\n" msgstr "" #. type: Title ## #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Reading the variable" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "We are persuading upstream tools to support this directly. You may help by writing patches for these tools; please add links to the bug reports here so we know, and to act as an example resource for future patch writers." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "" " Pending:: [gettext](https://bugs.debian.org/792687), [qt4-x11](https://bugs.debian.org/794681)\n" " Complete::\n" " * [cmake](https://gitlab.kitware.com/cmake/cmake/merge_requests/432) (>= 3.8.0)\n" " * [debhelper](https://bugs.debian.org/791823) (>= 9.20151004)\n" " * [docbook-utils](https://bugs.debian.org/800797) (Debian >= 0.6.14-3.1, upstream TODO)\n" " * [doxygen](https://bugs.debian.org/792201) (>= [1.8.12](https://github.com/doxygen/doxygen/commit/9a2c7bbfb0c53b4532db7280e6804c7ce76d70a3), Debian pending)\n" " * [epydoc](https://bugs.debian.org/790899) (>= 3.0.1+dfsg-8, upstream [pending](https://sourceforge.net/p/epydoc/bugs/368/))\n" " * [gcc](https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=e3e8c48c4a494d9da741c1c8ea6c4c0b7c4ff934) (>= 7, Debian >= 5.3.1-17, Debian >= 6.1.1-1)\n" " * [ghostscript](https://bugs.debian.org/794004) (Debian >= 9.16~dfsg-1, upstream [unfortunately rejected](http://bugs.ghostscript.com/show_bug.cgi?id=696765) due to additional constraints they have)\n" " * [groff](https://bugs.debian.org/762854) (Debian >= 1.22.3-2, upstream [pending](https://lists.gnu.org/archive/html/groff/2015-11/msg00038.html))\n" " * [help2man](https://bugs.debian.org/787444) (>= 1.47.1)\n" " * [libxslt](https://bugs.debian.org/791815) (>= [1.1.29](https://bugzilla.gnome.org/show_bug.cgi?id=758148), Debian >= 1.1.28-3)\n" " * [man2html](https://bugs.debian.org/796130) (Debian >= 1.6g-8, [needs forwarding](https://sources.debian.net/src/man2html/1.6g-8/debian/patches/035-source-date-epoch.patch/))\n" " * [mkdocs](https://bugs.debian.org/824266) (>= [0.16](https://github.com/mkdocs/mkdocs/pull/939/commits/8b006bd7fda55e47e29412896c511c7244398f82), Debian pending)\n" " * [ocamldoc](https://bugs.debian.org/794586) (>= [4.03.0](https://github.com/ocaml/ocaml/commit/0319173b7d02008e4ce6b81dceaf7c32cf5f8a6f), Debian >= 4.02.3-1)\n" " * [pydoctor](https://bugs.debian.org/807166) (>= 0.5+git20151204)\n" " * [rpm upstream](https://github.com/rpm-software-management/rpm/pull/144) (>4.13 other relevant patches linked in there)\n" " * [sphinx](https://github.com/sphinx-doc/sphinx/pull/1954) (>= 1.4, Debian >= 1.3.1-3)\n" " * [texi2html](https://bugs.debian.org/783475) (Debian >= 1.82+dfsg1-4, [needs forwarding](https://sources.debian.net/src/texi2html/1.82%2Bdfsg1-5/debian/patches/05_reproducible-build/))\n" " * [texlive-bin](https://bugs.debian.org/792202) (>= 2016.20160512.41045)\n" " * [txt2man](https://bugs.debian.org/790801) (>= [1.5.7](https://github.com/mvertes/txt2man/pull/1), Debian >= 1.5.6-4)\n" " * [rcc](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=894476) (Qt5 >= [5.13.0](https://code.qt.io/cgit/qt/qtbase.git/commit/?id=1ffcca4cc208c48ddb06b6a23abf1756f9724351), Debian TODO)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Or search in all Debian sources: " msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Python" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "import os\n" "import time\n" "import datetime\n" "\n" "build_date = datetime.datetime.utcfromtimestamp(\n" " int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))\n" ")\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "or with less imports, rendering to a string:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "import os\n" "import time\n" "date_str = time.strftime(\n" " \"%Y-%m-%d\",\n" " time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))\n" ")\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Bash / POSIX shell" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "For GNU systems:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "BUILD_DATE=\"$(date --utc --date=\"@${SOURCE_DATE_EPOCH:-$(date +%s)}\" +%Y-%m-%d)\"\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "If you need to support BSD date as well you should fallback to trying ther `-r seconds` timestamp variant:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "DATE_FMT=\"+%Y-%m-%d\"\n" "SOURCE_DATE_EPOCH=\"${SOURCE_DATE_EPOCH:-$(date +%s)}\"\n" "BUILD_DATE=$(date -u -d \"@$SOURCE_DATE_EPOCH\" \"$DATE_FMT\" 2>/dev/null || date -u -r \"$SOURCE_DATE_EPOCH\" \"$DATE_FMT\" 2>/dev/null || date -u \"$DATE_FMT\")\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Perl" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "use POSIX qw(strftime);\n" "my $date = strftime(\"%Y-%m-%d\", gmtime($ENV{SOURCE_DATE_EPOCH} || time));\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Makefile" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "DATE_FMT = +%Y-%m-%d\n" "ifdef SOURCE_DATE_EPOCH\n" " BUILD_DATE ?= $(shell date -u -d \"@$(SOURCE_DATE_EPOCH)\" \"$(DATE_FMT)\" 2>/dev/null || date -u -r \"$(SOURCE_DATE_EPOCH)\" \"$(DATE_FMT)\" 2>/dev/null || date -u \"$(DATE_FMT)\")\n" "else\n" " BUILD_DATE ?= $(shell date \"$(DATE_FMT)\")\n" "endif\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "The above will work with either GNU or BSD date, and fallback to ignore `SOURCE_DATE_EPOCH` if both fails." msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "CMake" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "STRING(TIMESTAMP BUILD_DATE \"%Y-%m-%d\" UTC)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "... works with CMake versions 2.8.11 and higher, but it only respects `SOURCE_DATE_EPOCH` since version 3.8.0. If you do not have a modern CMake but need reproducibility you can use the less-preferred variant:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "if (DEFINED ENV{SOURCE_DATE_EPOCH})\n" " execute_process(\n" " COMMAND \"date\" \"-u\" \"-d\" \"@$ENV{SOURCE_DATE_EPOCH}\" \"+%Y-%m-%d\"\n" " OUTPUT_VARIABLE BUILD_DATE\n" " OUTPUT_STRIP_TRAILING_WHITESPACE)\n" "else ()\n" " execute_process(\n" " COMMAND \"date\" \"+%Y-%m-%d\"\n" " OUTPUT_VARIABLE BUILD_DATE\n" " OUTPUT_STRIP_TRAILING_WHITESPACE)\n" "endif ()\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "The above will work only with GNU `date`. See the POSIX shell example on how to support BSD date." msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Meson" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "By deliberate design, [Meson does not provide access to environment variables in build files](https://github.com/mesonbuild/meson/issues/9#issuecomment-543780613) which makes accessing `SOURCE_DATE_EPOCH` troublesome." msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "date_exe = find_program('date')\n" "cmd = run_command('sh', '-c', 'echo $SOURCE_DATE_EPOCH')\n" "source_date_epoch = cmd.stdout().strip()\n" "if source_date_epoch == ''\n" "\tsource_date_epoch = run_command(date_exe, '+%s').stdout().strip()\n" "endif\n" "\n" "formatted_date = run_command(date_exe, '-u', '-d', '@' + source_date_epoch, '+%Y-%m-%d').stdout().strip()\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "The above will work only with GNU `date`. See the POSIX shell example on how to support BSD date variants." msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "C" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "#include \n" "#include \n" "#include \n" "\n" "struct tm *build_time;\n" "time_t now;\n" "char *source_date_epoch;\n" "unsigned long long epoch;\n" "char *endptr;\n" "\n" "source_date_epoch = getenv(\"SOURCE_DATE_EPOCH\");\n" "if (source_date_epoch) {\n" "\terrno = 0;\n" "\tepoch = strtoull(source_date_epoch, &endptr, 10);\n" "\tif ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0))\n" "\t\t\t|| (errno != 0 && epoch == 0)) {\n" "\t\tfprintf(stderr, \"Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\\n\", strerror(errno));\n" "\t\texit(EXIT_FAILURE);\n" "\t}\n" "\tif (endptr == source_date_epoch) {\n" "\t\tfprintf(stderr, \"Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\\n\", endptr);\n" "\t\texit(EXIT_FAILURE);\n" "\t}\n" "\tif (*endptr != '\\0') {\n" "\t\tfprintf(stderr, \"Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\\n\", endptr);\n" "\t\texit(EXIT_FAILURE);\n" "\t}\n" "\tif (epoch > ULONG_MAX) {\n" "\t\tfprintf(stderr, \"Environment variable $SOURCE_DATE_EPOCH: value must be smaller than or equal to %lu but was found to be: %llu \\n\", ULONG_MAX, epoch);\n" "\t\texit(EXIT_FAILURE);\n" "\t}\n" "\tnow = epoch;\n" "} else {\n" "\tnow = time(NULL);\n" "}\n" "build_time = gmtime(&now);\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "If you want less verbose code and are happy with the assumptions stated below, you can use" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "#include \n" "\n" "time_t now;\n" "char *source_date_epoch;\n" "/* This assumes that the SOURCE_DATE_EPOCH environment variable will contain\n" " a correct, positive integer in the time_t range */\n" "if ((source_date_epoch = getenv(\"SOURCE_DATE_EPOCH\")) == NULL ||\n" " (now = (time_t)strtoll(source_date_epoch, NULL, 10)) <= 0)\n" " time(&now);\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "C++" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "#include \n" "#include \n" "#include \n" "#include \n" "\n" " time_t now;\n" " char *source_date_epoch = std::getenv(\"SOURCE_DATE_EPOCH\");\n" " if (source_date_epoch) {\n" " std::istringstream iss(source_date_epoch);\n" " iss >> now;\n" " if (iss.fail() || !iss.eof()) {\n" " std::cerr << \"Error: Cannot parse SOURCE_DATE_EPOCH as integer\\n\";\n" " exit(27);\n" " }\n" " } else {\n" " now = std::time(NULL);\n" " }\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Go" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "import (\n" " \"fmt\"\n" " \"os\"\n" " \"strconv\"\n" " \"time\"\n" ")\n" "\n" "[...]\n" "\n" "source_date_epoch := os.Getenv(\"SOURCE_DATE_EPOCH\")\n" "var build_date string\n" "if source_date_epoch == \"\" {\n" " build_date = time.Now().UTC().Format(http.TimeFormat)\n" "} else {\n" " sde, err := strconv.ParseInt(source_date_epoch, 10, 64)\n" " if err != nil {\n" " panic(fmt.Sprintf(\"Invalid SOURCE_DATE_EPOCH: %s\", err))\n" " }\n" " build_date = time.Unix(sde, 0).UTC().Format(http.TimeFormat)\n" "}\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "PHP" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "\\date('Y', (int)\\getenv('SOURCE_DATE_EPOCH') ?: \\time())\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Emacs-Lisp" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "(current-time-string\n" " (when (getenv \"SOURCE_DATE_EPOCH\")\n" " (seconds-to-time\n" " (string-to-number\n" " (getenv \"SOURCE_DATE_EPOCH\"))))))\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "OCaml" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "let build_date =\n" " try\n" " float_of_string (Sys.getenv \"SOURCE_DATE_EPOCH\")\n" " with\n" " Not_found -> Unix.time ()\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Java / gradle" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "def buildDate = System.getenv(\"SOURCE_DATE_EPOCH\") == null ?\n" " new java.util.Date() :\n" " new java.util.Date(1000 * Long.parseLong(System.getenv(\"SOURCE_DATE_EPOCH\")))\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Javascript / node.js" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "var timestamp = new Date(process.env.SOURCE_DATE_EPOCH ? (process.env.SOURCE_DATE_EPOCH * 1000) : new Date().getTime());\n" "\n" "// Alternatively, to ensure a fixed timezone:\n" "\n" "var now = new Date();\n" "if (process.env.SOURCE_DATE_EPOCH) {\n" " now = new Date((process.env.SOURCE_DATE_EPOCH * 1000) + (now.getTimezoneOffset() * 60000));\n" "}\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Ruby" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "if ENV['SOURCE_DATE_EPOCH'].nil?\n" " now = Time.now\n" "else\n" " now = Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime\n" "end\n" "\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Note that Ruby's Datetime.strftime is locale-independent by default." msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Scala" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "To get milliseconds since Epoch:" msgstr "" #. type: Fenced code block (scala) #: _docs/source-date-epoch.md #, no-wrap msgid "sys.env.get(\"SOURCE_DATE_EPOCH\").map(_.toLong * 1000)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "To get a `java.util.Date`:" msgstr "" #. type: Fenced code block (scala) #: _docs/source-date-epoch.md #, no-wrap msgid "" "sys.env.get(\"SOURCE_DATE_EPOCH\")\n" " .map(sde => new java.util.Date(sde.toLong * 1000))\n" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "Last-resort using faketime" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "''As a last resort to be avoided where possible'' (e.g. if the upstream tool is too hard to patch, or too time-consuming for you right now to patch, or if they are being uncooperative or unresponsive), package maintainers may try something like the following:" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "`debian/strip-nondeterminism/a2x`:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "" "#!/bin/sh\n" "# Depends: faketime\n" "# Eventually the upstream tool should support SOURCE_DATE_EPOCH internally.\n" "test -n \"$SOURCE_DATE_EPOCH\" || { echo >&2 \"$0: SOURCE_DATE_EPOCH not set\"; exit 255; }\n" "exec env NO_FAKE_STAT=1 faketime -f \"$(TZ=UTC date -d \"@$SOURCE_DATE_EPOCH\" +'%Y-%m-%d %H:%M:%S')\" /usr/bin/a2x \"$@\"\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "`debian/rules`:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "export PATH := $(CURDIR)/debian/strip-nondeterminism:$(PATH)\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "`debian/control`:" msgstr "" #. type: Fenced code block #: _docs/source-date-epoch.md #, no-wrap msgid "Build-Depends: faketime\n" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "But please be aware that this does not work out of the box with pbuilder on Debian 7 Wheezy, see [#778462](https://bugs.debian.org/778462) against faketime and [#700591](https://bugs.debian.org/700591) against pbuilder (fixed in Jessie, but not Wheezy). Adding an according hook to `/etc/pbuilder/hook.d` which mounts `/run/shm` inside the chroot should suffice as local workaround, though." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "TODO: document some other nicer options. Generally, all invocations of `date(1)` need to have a fixed `TZ` environment set." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "NOTE: faketime BREAKS builds on some archs, for example hurd. See #778462 for details." msgstr "" #. type: Title ## #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "More detailed discussion" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Sometimes developers of build tools do not want to support `SOURCE_DATE_EPOCH`, or they will tweak the suggestion to something related but different. We really do think the best approach is to use `SOURCE_DATE_EPOCH` exactly as-is described above in our proposal, without any variation. Here we explain our reasoning versus the arguments we have encountered." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "(See *Standard Environment Variables* for general arguments.)" msgstr "" #. type: Title ### #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "\"Lying about the time\" / \"violates language spec\"" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "This argument arises when the tool processes some input which contains a static instruction to the effect of \"get_current_time()\". The input has a specification that defines what this means. The tool executes this instruction, then embeds the result in the output. It is argued that `SOURCE_DATE_EPOCH` would break these semantics and violate the specification." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "In most cases, this argument places too much weight on the absoluteness of time. Regardless of what any specification says, the user can set their own system clock and achieve an effect similar to `SOURCE_DATE_EPOCH`. Note: Setting the system clock is not enough for ''reliable'' reproducible builds - we need `SOURCE_DATE_EPOCH` for long-running build processes that take varying amounts of time. If the tool was run near the end of the process, then merely setting the system clock would not make timestamps here reproducible. It is not up to the tool to judge whether the user is lying with their system clock, and likewise, it is not up to the tool to judge whether `SOURCE_DATE_EPOCH` is a \"lie\" or not." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "For all intents and purposes, if the user has set `SOURCE_DATE_EPOCH` then they are taking a position that \"this **is** the current time; please use this instead of whatever clock you normally use\". Yes, the project developer wrote \"get_current_time()\" but I as the user, by setting `SOURCE_DATE_EPOCH`, am choosing to override this with my own idea of what time it is. Please execute the build as if the current time was `SOURCE_DATE_EPOCH`. FOSS software should generally prefer to respect end-users' wishes rather than developers' wishes. (And in practise, we haven't seen ''any'' instance where a project developer really really prefers \"time of build\" over \"modtime of source\".)" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "In conclusion, the tool may choose to ignore `SOURCE_DATE_EPOCH` for other reasons, but to judge that this is a ''lie'' is to disrespect the user's wishes. Furthermore, choosing to support this is unlikely to ''actually'' violate any specifications, since they generally don't define \"current\". This does not take into account, if the specification needs to interoperate consistently with other programs in a strong cryptographic ledger protocol where time values ''must'' be consistent across multiple entities. However this scenario is unlikely to apply, in the context of build tools where `SOURCE_DATE_EPOCH` would be set.)" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Many tools allow the user to override the \"current\" date - e.g. `-D__TIME__=xxx`, `\\\\year=yyy`, etc. In these cases, it makes even less sense to ignore `SOURCE_DATE_EPOCH` for data integrity reasons - you ''already'' have a mechanism where the user can \"lie\" or \"break the spec\"; `SOURCE_DATE_EPOCH` would just be adding an extra mechanism that makes it easier to do this globally across all tools." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "If for some reason you're still conflicted on suddenly changing the meaning of your \"now()\" function and desire another switch other than `SOURCE_DATE_EPOCH` being set or not, the `texlive` project came up with the variable `FORCE_SOURCE_DATE`; when that environment variable is set to `1` cases that wouldn't normally obey `SOURCE_DATE_EPOCH` will do. We **strongly discourage** the usage of such variable; `SOURCE_DATE_EPOCH` is meant to be already a flag forcing a particular timestamp to be used." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "OTOH, one alternative we can agree with, that also avoids `SOURCE_DATE_EPOCH`, would be to translate the static instruction \"get_current_time()\" from the input format to ''an equivalent instruction'' in the output format, if the output format supports that." msgstr "" #. type: Title ## #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid "History and alternative proposals" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "[1](https://lists.alioth.debian.org/pipermail/reproducible-builds/Week-of-Mon-20150608/001823.html) and the surrounding messages describe the initial motivation behind this, including an evaluation of how different programming languages handle date formats." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "At present, we do not have a proposal that includes anything resembling a \"time zone\". Developing such a standard requires consideration of various issues:" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Intuitive and naive ways of handling human-readable dates, such as the POSIX date functions, are highly flawed and freely mix implicit not-well-defined calendars with absolute time. For example, they don't specify they mean the Gregorian calendar, and/or don't specify what to do with dates before when the Gregorian calendar was introduced, or use named time zones that require an up-to-date timezone database (e.g. with historical DST definitions) to parse properly." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "Since this is meant to be a universal standard that all tools and distributions can support, we need to keep things simple and precise, so that different groups of people cannot accidentally interpret it in different ways. So it is probably unwise to try to standardise anything that resembles a named time zone, since that is very very complex." msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text msgid "One likely candidate would be something similar to the git internal timestamp format, see `man git-commit`:" msgstr "" #. type: Plain text #: _docs/source-date-epoch.md #, markdown-text, no-wrap msgid " It is