Skip to content

Commit

Permalink
Allow for reproducible .vsix packages
Browse files Browse the repository at this point in the history
Running the same build produces .vsix package that have the same
content, but are not bit for bit the same, making it somewhat
complicated to verify reproducible builds. Two changes are needed to fix
this:

1. The mtime of each file added to the .vsix archive is included in each
   archive entry, so builds that happen at different times will have
   different entry timestamps. To fix this, if the SOURCE_DATE_EPOCH
   environment variable is defined, it it now used as entry timestamp
   value instead. Builds will now be reproducible as long as they set
   the same SOURCE_DATE_EPOCH value. If the environment variable is not
   defined or is not an integer, the current behavior is used.
2. The order that files are collected in preparation for packaging into
   the .vsix file is non-deterministic, which can lead to archives with
   the same content but in different orders. To fix this, files are
   sorted by archive entry name prior to adding.

Fixes #906
  • Loading branch information
stevedlawrence committed Dec 5, 2024
1 parent 1939270 commit f53c67e
Showing 1 changed file with 14 additions and 6 deletions.
20 changes: 14 additions & 6 deletions src/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1800,13 +1800,21 @@ function writeVsix(files: IFile[], packagePath: string): Promise<void> {
() =>
new Promise((c, e) => {
const zip = new yazl.ZipFile();
files.forEach(f =>

const sde = process.env.SOURCE_DATE_EPOCH;
const epoch = sde ? parseInt(sde) : undefined;
const mtime = epoch ? new Date(epoch * 1000) : undefined;

files.sort((a, b) => a.path.localeCompare(b.path)).forEach(f => {
let options = {
mode: f.mode,
} as any;
if (mtime) options.mtime = mtime;

isInMemoryFile(f)
? zip.addBuffer(typeof f.contents === 'string' ? Buffer.from(f.contents, 'utf8') : f.contents, f.path, {
mode: f.mode,
})
: zip.addFile(f.localPath, f.path, { mode: f.mode })
);
? zip.addBuffer(typeof f.contents === 'string' ? Buffer.from(f.contents, 'utf8') : f.contents, f.path, options)
: zip.addFile(f.localPath, f.path, options)
});
zip.end();

const zipStream = fs.createWriteStream(packagePath);
Expand Down

0 comments on commit f53c67e

Please sign in to comment.