diff --git a/help/file.txt b/help/file.txt index 6eb92a456b..4604b36cf4 100644 --- a/help/file.txt +++ b/help/file.txt @@ -26,6 +26,8 @@ looking for files in following order: packages.config paket.dependencies composer.lock + Podfile + Podfile.lock If more than one file exists it will use the first order-wise. If you wish to specify manually, you can point the --file parameter to force using what you specify, for example: diff --git a/help/help.txt b/help/help.txt index b483129d09..5948fbc9f0 100644 --- a/help/help.txt +++ b/help/help.txt @@ -95,6 +95,10 @@ Yarn options: --strict-out-of-sync= Prevent testing out of sync lockfiles. Defaults to true. +CocoaPods options: + --strict-out-of-sync= + Prevent testing out of sync lockfiles. Defaults to false. + Python options: --command= Python interpreter to use. Default: "python", set to "python2" or "python3" to use a specific version. diff --git a/package.json b/package.json index a9324d79d4..04800991b2 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@snyk/cli-interface": "2.2.0", "@snyk/dep-graph": "1.13.1", "@snyk/gemfile": "1.2.0", - "@snyk/snyk-cocoapods-plugin": "1.0.3", + "@snyk/snyk-cocoapods-plugin": "2.0.1", "@types/agent-base": "^4.2.0", "@types/restify": "^4.3.6", "abbrev": "^1.1.1", diff --git a/src/lib/detect.ts b/src/lib/detect.ts index c9558bfa20..a1478f6b1b 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -27,6 +27,8 @@ const DETECTABLE_FILES: string[] = [ 'packages.config', 'paket.dependencies', 'composer.lock', + 'Podfile', + 'Podfile.lock', ]; // when file is specified with --file, we look it up here diff --git a/test/acceptance/cli.acceptance.test.ts b/test/acceptance/cli.acceptance.test.ts index 5f4d8acce8..6d765f9872 100644 --- a/test/acceptance/cli.acceptance.test.ts +++ b/test/acceptance/cli.acceptance.test.ts @@ -3843,27 +3843,74 @@ test('`monitor golang-app --file=vendor/vendor.json`', async (t) => { ); }); -test('`monitor cocoapods-app`', async (t) => { +test('`test cocoapods-app (autodetect)`', async (t) => { chdirWorkspaces(); - try { - await cli.test('cocoapods-app'); - t.fail('should have failed'); - } catch (err) { - t.pass('throws err'); - t.match( - err.message, - 'Could not detect supported target files in cocoapods-app.' + - '\nPlease see our documentation for supported' + - ' languages and target files: ' + - 'https://support.snyk.io/hc/en-us/articles/360000911957-Language-support' + - ' and make sure you' + - ' are in the right directory.', - ); - } + + await cli.test('cocoapods-app'); + + const req = server.popRequest(); + t.equal(req.method, 'POST', 'makes POST request'); + t.equal( + req.headers['x-snyk-cli-version'], + versionNumber, + 'sends version number', + ); + t.match(req.url, '/test-dep-graph', 'posts to correct url'); + + const depGraph = req.body.depGraph; + t.equal(depGraph.pkgManager.name, 'cocoapods'); + t.same( + depGraph.pkgs.map((p) => p.id).sort(), + ['cocoapods-app@0.0.0', 'Reachability@3.1.0'].sort(), + 'depGraph looks fine', + ); +}); + +test('`monitor cocoapods-app (autodetect)`', async (t) => { + chdirWorkspaces('cocoapods-app'); + const plugin = { + async inspect() { + return { + plugin: { + targetFile: 'Podfile', + name: 'snyk-cocoapods-plugin', + runtime: 'cocoapods', + }, + package: {}, + }; + }, + }; + const spyPlugin = sinon.spy(plugin, 'inspect'); + + const loadPlugin = sinon.stub(plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + loadPlugin.withArgs('cocoapods').returns(plugin); + + await cli.monitor('./'); + const req = server.popRequest(); + t.equal(req.method, 'PUT', 'makes PUT request'); + t.equal( + req.headers['x-snyk-cli-version'], + versionNumber, + 'sends version number', + ); + t.match(req.url, '/monitor/cocoapods', 'puts at correct url'); + t.equal(req.body.targetFile, 'Podfile', 'sends the targetFile'); + t.same( + spyPlugin.getCall(0).args, + [ + './', + 'Podfile', + { + args: null, + }, + ], + 'calls CocoaPods plugin', + ); }); test('`monitor cocoapods-app --file=Podfile`', async (t) => { - chdirWorkspaces(); + chdirWorkspaces('cocoapods-app'); const plugin = { async inspect() { return { @@ -3882,7 +3929,7 @@ test('`monitor cocoapods-app --file=Podfile`', async (t) => { t.teardown(loadPlugin.restore); loadPlugin.withArgs('cocoapods').returns(plugin); - await cli.monitor('cocoapods-app', { + await cli.monitor('./', { file: 'Podfile', }); const req = server.popRequest(); @@ -3893,11 +3940,11 @@ test('`monitor cocoapods-app --file=Podfile`', async (t) => { 'sends version number', ); t.match(req.url, '/monitor/cocoapods', 'puts at correct url'); - t.equal(req.body.targetFile, 'Podfile', 'sends the targetFile'); + t.equal(req.body.targetFile, 'Podfile', 'sends the targetFile (Podfile)'); t.same( spyPlugin.getCall(0).args, [ - 'cocoapods-app', + './', 'Podfile', { args: null, @@ -3908,6 +3955,52 @@ test('`monitor cocoapods-app --file=Podfile`', async (t) => { ); }); +test('`monitor cocoapods-app --file=Podfile.lock`', async (t) => { + chdirWorkspaces('cocoapods-app'); + const plugin = { + async inspect() { + return { + plugin: { + targetFile: 'Podfile', + name: 'snyk-cocoapods-plugin', + runtime: 'cocoapods', + }, + package: {}, + }; + }, + }; + const spyPlugin = sinon.spy(plugin, 'inspect'); + + const loadPlugin = sinon.stub(plugins, 'loadPlugin'); + t.teardown(loadPlugin.restore); + loadPlugin.withArgs('cocoapods').returns(plugin); + + await cli.monitor('./', { + file: 'Podfile.lock', + }); + const req = server.popRequest(); + t.equal(req.method, 'PUT', 'makes PUT request'); + t.equal( + req.headers['x-snyk-cli-version'], + versionNumber, + 'sends version number', + ); + t.match(req.url, '/monitor/cocoapods', 'puts at correct url'); + t.equal(req.body.targetFile, 'Podfile', 'sends the targetFile (Podfile)'); + t.same( + spyPlugin.getCall(0).args, + [ + './', + 'Podfile.lock', + { + args: null, + file: 'Podfile.lock', + }, + ], + 'calls CocoaPods plugin', + ); +}); + test('`monitor composer-app ruby-app` works on multiple params', async (t) => { chdirWorkspaces(); let results = await cli.monitor('composer-app', 'ruby-app', { json: true }); @@ -4413,7 +4506,7 @@ after('teardown', async (t) => { } }); -function chdirWorkspaces(subdir: string = '') { +function chdirWorkspaces(subdir = '') { process.chdir(__dirname + '/workspaces' + (subdir ? '/' + subdir : '')); }