Skip to content

Commit

Permalink
fix(homebrew): Use hasha instead of crypto for sha256 (#4675)
Browse files Browse the repository at this point in the history
  • Loading branch information
nchashch authored and rarkins committed Oct 18, 2019
1 parent 7f916f4 commit 661cb95
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 55 deletions.
31 changes: 15 additions & 16 deletions lib/manager/homebrew/update.ts
@@ -1,4 +1,4 @@
import { createHash } from 'crypto';
import { fromStream } from 'hasha';
import { coerce } from 'semver';
import { parseUrlPath } from './extract';
import { skip, isSpace, removeComments } from './util';
Expand All @@ -13,12 +13,10 @@ export async function updateDependency(
): Promise<string> {
logger.trace('updateDependency()');
/*
1. Update url field
2. Update sha256 field
1. Update url field 2. Update sha256 field
*/
let newContent = content;
let newUrl: string;
let file: string;
// Example urls:
// "https://github.com/bazelbuild/bazel-watcher/archive/v0.8.2.tar.gz"
// "https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz"
Expand All @@ -29,29 +27,38 @@ export async function updateDependency(
);
return content;
}
let newSha256;
try {
newUrl = `https://github.com/${upgrade.managerData.ownerName}/${
upgrade.managerData.repoName
}/releases/download/${upgrade.newValue}/${
upgrade.managerData.repoName
}-${coerce(upgrade.newValue)}.tar.gz`;
file = (await got(newUrl, {
encoding: null,
})).body;
newSha256 = await fromStream(got.stream(newUrl), {
algorithm: 'sha256',
});
} catch (errOuter) {
logger.debug(
`Failed to download release download for ${upgrade.depName} - trying archive instead`
);
try {
newUrl = `https://github.com/${upgrade.managerData.ownerName}/${upgrade.managerData.repoName}/archive/${upgrade.newValue}.tar.gz`;
file = (await got(newUrl, { encoding: null })).body;
newSha256 = await fromStream(got.stream(newUrl), {
algorithm: 'sha256',
});
} catch (errInner) {
logger.debug(
`Failed to download archive download for ${upgrade.depName} - update failed`
);
return content;
}
}
if (!newSha256) {
logger.debug(
`Failed to generate new sha256 for ${upgrade.depName} - update failed`
);
return content;
}
const newParsedUrlPath = parseUrlPath(newUrl);
if (!newParsedUrlPath) {
logger.debug(`Failed to update url for dependency ${upgrade.depName}`);
Expand All @@ -61,14 +68,6 @@ export async function updateDependency(
logger.debug(`Failed to update url for dependency ${upgrade.depName}`);
return content;
}
let newSha256;
try {
newSha256 = createHash('sha256')
.update(file)
.digest('hex');
} catch (err) /* istanbul ignore next */ {
logger.warn({ err }, 'Failed to generate new sha256 for homebrew');
}
newContent = updateUrl(content, upgrade.managerData.url, newUrl);
if (!newContent) {
logger.debug(`Failed to update url for dependency ${upgrade.depName}`);
Expand Down
67 changes: 65 additions & 2 deletions test/manager/homebrew/__snapshots__/update.spec.ts.snap
@@ -1,5 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`manager/homebrew/update returns unchanged content if both got requests fail 1`] = `
"=begin
url \\"https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz\\"
sha256 \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\"
=end
# url \\"https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz\\"
# sha256 \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\"
$sha256 = \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\"
class Aide < Formula
desc \\"File and directory integrity checker\\"
homepage \\"https://aide.github.io/\\"
url \\"https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz\\"
sha256 \\"0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7\\"
bottle do
cellar :any
sha256 \\"53b1dfabc76d6e54db56ec24f7f91b6cc9dcdd18210d17d2df92f86225fb9c9f\\" => :mojave
sha256 \\"79a2d4ce92526516891c844a4852161d39421f9dc31d2eba5ea0e48d79496053\\" => :high_sierra
sha256 \\"b626fcf7e52a0ea66fbed58bdc00cb08484f7bce8e84e61edf6740fbad7fabc5\\" => :sierra
end
head do
url \\"https://github.com/aide/aide.git\\"
depends_on \\"autoconf\\" => :build
depends_on \\"automake\\" => :build
end
depends_on \\"libgcrypt\\"
depends_on \\"libgpg-error\\"
depends_on \\"pcre\\"
def install
system \\"sh\\", \\"./autogen.sh\\" if build.head?
system \\"./configure\\", \\"--disable-lfs\\",
\\"--disable-static\\",
\\"--with-curl\\",
\\"--with-zlib\\",
\\"--sysconfdir=#{etc}\\",
\\"--prefix=#{prefix}\\"
system \\"make\\", \\"install\\"
end
test do
(testpath/\\"aide.conf\\").write <<~EOS
database = file:/var/lib/aide/aide.db
database_out = file:/var/lib/aide/aide.db.new
database_new = file:/var/lib/aide/aide.db.new
gzip_dbout = yes
summarize_changes = yes
grouped = yes
verbose = 7
database_attrs = sha256
/etc p+i+u+g+sha256
EOS
system \\"#{bin}/aide\\", \\"--config-check\\", \\"-c\\", \\"aide.conf\\"
end
end
"
`;
exports[`manager/homebrew/update updates "archive" github dependency 1`] = `
"# Copyright 2018 The Bazel Authors. All rights reserved.
#
Expand Down Expand Up @@ -30,7 +93,7 @@ class Ibazel < Formula
# To generate run:
# curl https://codeload.github.com/bazelbuild/bazel-watcher/tar.gz/v0.8.2 | sha256sum
sha256 '9c96cc68155bd283282123413ecaafe52b12ea5f2585c3c383ce6141f779a58f'
sha256 'new_hash_value'
bottle :unneeded
Expand Down Expand Up @@ -64,7 +127,7 @@ class Aide < Formula
desc \\"File and directory integrity checker\\"
homepage \\"https://aide.github.io/\\"
url \\"https://github.com/aide/aide/releases/download/v0.17.7/aide-0.17.7.tar.gz\\"
sha256 \\"337c78a56c8dde1a42eb767bf89f16eb3ee4207e4817954899a3f0f293c6ad6b\\"
sha256 \\"new_hash_value\\"
bottle do
cellar :any
Expand Down
77 changes: 40 additions & 37 deletions test/manager/homebrew/update.spec.ts
@@ -1,10 +1,11 @@
import fs from 'fs';
import { fromStream as _fromStream } from 'hasha';
import { updateDependency } from '../../../lib/manager/homebrew/update';
import _got from '../../../lib/util/got';

jest.mock('hasha');
jest.mock('../../../lib/util/got');

const got: any = _got;
const fromStream: jest.Mock<Promise<string>> = _fromStream as any;

const aide = fs.readFileSync('test/manager/homebrew/_fixtures/aide.rb', 'utf8');
const ibazel = fs.readFileSync(
Expand All @@ -30,7 +31,7 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.17.7',
};
got.mockReturnValueOnce({ body: 'some_content_1' });
fromStream.mockResolvedValueOnce('new_hash_value');
const newContent = await updateDependency(aide, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).not.toBe(aide);
Expand All @@ -50,13 +51,13 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockReturnValueOnce({ body: 'some_content_2' });
fromStream.mockResolvedValueOnce('new_hash_value');
const newContent = await updateDependency(ibazel, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).not.toBe(ibazel);
expect(newContent).toMatchSnapshot();
});
it('returns unchanged content if got function throws errors', async () => {
it('returns unchanged content if fromStream promise rejects', async () => {
const upgrade = {
currentValue: 'v0.8.2',
depName: 'Ibazel',
Expand All @@ -70,9 +71,7 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockImplementationOnce(() => {
throw new Error('Request failed');
});
fromStream.mockRejectedValueOnce('Request failed');
const newContent = await updateDependency(ibazel, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(ibazel);
Expand All @@ -91,9 +90,7 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
Expand All @@ -113,13 +110,9 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got
.mockImplementationOnce(() => {
throw Error('Request failed');
})
.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream
.mockRejectedValueOnce('Request failed')
.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
Expand All @@ -139,13 +132,9 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got
.mockImplementationOnce(() => {
throw Error('Request failed');
})
.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream
.mockRejectedValueOnce('Request failed')
.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
Expand All @@ -172,9 +161,7 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
Expand All @@ -200,9 +187,7 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
Expand All @@ -229,9 +214,7 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
Expand All @@ -257,11 +240,31 @@ describe('manager/homebrew/update', () => {
},
newValue: 'v0.9.3',
};
got.mockImplementationOnce(() => {
return { body: 'some_content' };
});
fromStream.mockResolvedValueOnce('some_content');
const newContent = await updateDependency(content, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(content);
});
it('returns unchanged content if both got requests fail', async () => {
const upgrade = {
currentValue: 'v0.16.1',
depName: 'Aide',
managerData: {
ownerName: 'aide',
repoName: 'aide',
sha256:
'0f2b7cecc70c1a27d35c06c98804fcdb9f326630de5d035afc447122186010b7',
url:
'https://github.com/aide/aide/releases/download/v0.16.1/aide-0.16.1.tar.gz',
},
newValue: 'v0.17.7',
};
fromStream
.mockRejectedValueOnce('Request failed.')
.mockRejectedValueOnce('Request failed.');
const newContent = await updateDependency(aide, upgrade);
expect(newContent).not.toBeNull();
expect(newContent).toBe(aide);
expect(newContent).toMatchSnapshot();
});
});

0 comments on commit 661cb95

Please sign in to comment.