Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use hasha instead of crypto for sha256 in homebrew manager #4675

Merged
merged 1 commit into from
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 15 additions & 16 deletions lib/manager/homebrew/update.ts
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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();
});
});