summaryrefslogtreecommitdiff
path: root/README.md
blob: 808434863358ec18374c853da055bb7781053d5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# GitLab License Management

[![pipeline status](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/badges/master/pipeline.svg)](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/commits/master)
[![coverage report](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/badges/master/coverage.svg)](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/commits/master)

GitLab tool for detecting licenses of the dependencies used by the provided source.
It is currently based on [License Finder][license_finder]
only, but this may change in the future.

## How to use

1. `cd` into the directory of the source code you want to scan
1. Run the Docker image:

    ```sh
    docker run \
      --volume "$PWD":/code \
      --env=LM_REPORT_VERSION="2.1" \
      --env=CI_PROJECT_DIR=/code \
      registry.gitlab.com/gitlab-org/security-products/analyzers/license-finder:latest
    ```

1. The results will be stored in the `gl-license-scanning-report.json` file in the application directory.

## Development

### Getting Started

Install [Docker](https://docs.docker.com/engine/installation/).

```sh
$ git clone git@gitlab.com:gitlab-org/security-products/analyzers/license-finder.git
$ cd license-finder
```

Download the latest version of the Docker image.

```sh
$ ./bin/docker-pull
```

Launch a shell in the Docker container.

```sh
$ ./bin/docker-shell
```

### Running the application

License Management is a Docker image. You can build it like this from the project root:

```sh
$ ./bin/docker-build
```

You can then run License Management on some target directory:

```sh
$ docker run --rm --volume "/path/to/my/project":/code --env CI_PROJECT_DIR=/code
```

### Running the tests

You can run the tests from inside a docker container:

```sh
$ ./bin/docker-shell
$ ./bin/setup
$ ./bin/test [path to file]
```

If you need to debug any specific issues you can do this from within the docker container by
following these steps:

```sh
$ ./bin/docker-shell
$ enable_dev_mode
$ bundle open license_finder
```

The `docker-shell` script will mount the current project as a volume into `/builds/gitlab-org/security-products/analyzers/license-finder`.
This allows you to edit code from your host machine using your preferred editor and
see the affect of those changes from within the running docker container.

### Building Debian packages

Debian packages for each tool is built using [omnibus](https://github.com/chef/omnibus).
Read the [documentation](https://github.com/chef/omnibus#-omnibus) for more information.
The list of projects that can be built can be found in `config/projects/`.

E.g.

To build the `golang` package follow these steps:

```sh
$ ./bin/docker-omnibus
$ GOLANG_VERSION=1.15.3 ./bin/omnibus build golang
```

When a new version of a tool needs to be built, add
the new version to the tool file located in `./config/software/asdf_<tool>.rb`
and include the appropriate checksum.

### Updating the SPDX index

We will need to periodically update the SPDX index. This can be achieved with
the following command.

```bash
$ ./bin/update-spdx
```

## Supported languages and package managers

The following table shows which languages and package managers are supported.

| Language   | Package managers                                                  |
|------------|-------------------------------------------------------------------|
| .NET       | [.NET Core CLI][dotnet_core], [Nuget][nuget]                      |
| C/C++      | [Conan][conan]                                                    |
| Go         | [Go modules][gomod], [Godep][godep], go get                       |
| Java       | [Gradle][gradle], [Maven v3.2.5+][maven]                          |
| JavaScript | [npm][npm], [yarn][yarn], [Bower][bower]                          |
| PHP        | [composer][composer]                                              |
| Python     | [pip][pip], [pipenv][pipenv]                                      |
| Ruby       | [Bundler][bundler]                                                |

Inject `SETUP_CMD` to the docker command to override the given package managers
and run your custom command to setup your environment with a custom package manager.

```sh
docker run \
  --volume "$PWD":/code \
  --env "SETUP_CMD=./my-custom-install-script.sh" \
  --rm \
  registry.gitlab.com/gitlab-org/security-products/analyzers/license-finder:latest analyze /code
```

## Settings

The License Management tool can be customized with environments variables for some project types.

| Environment variable | Project type | Function |
|----------------------|--------------|----------|
| ADDITIONAL_CA_CERT_BUNDLE | * | Additional certificate chain to install in the trusted store. |
| MAVEN_CLI_OPTS       | Java (Maven) | Additional arguments for the mvn executable. If not supplied, defaults to `-DskipTests`. |
| LICENSE_FINDER_CLI_OPTS | * | Additional arguments for the `license_finder` executable. |
| LM_JAVA_VERSION      | Java (Maven) | Version of Java. If set to `11`, Maven and Gradle use Java 11 instead of Java 8. |
| LM_PYTHON_VERSION    | Python       | Version of Python. If set to `3`, dependencies are installed using Python 3 instead of Python 2.7. |
| LOG_LEVEL    | * | Control the verbosity of the logs. (`debug`, `info`, `warn` (default), `error`, `fatal`)  |
| LM_REPORT_FILE    | * | Name of the generated report. If not supplied, defaults to `gl-license-scanning-report.json`  |


Inject the required environment variables to the docker command using the [`--env` option flag](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file)
or its shorthand form (`--env MY_SETTING_VAR`) if the configuration comes from an external environment.

## Versioning and release process

Please check the [Release Process documentation](https://gitlab.com/gitlab-org/security-products/release/blob/master/docs/release_process.md).

## Upgrading to the latest version of LicenseFinder

1. Check for the latest version of `LicenseFinder` at [https://rubygems.org/gems/license_finder][license_finder]
1. Check the version of the `license_finder` gem that is currently being used in the [`Gemfile.lock`][gemfile_lock]
1. If an update is available, create a new branch
1. Bump the license management version in [CHANGELOG.md][changelog] and in [version.rb][version_rb]
1. Update the `license_finder` version constraint in the [gemspec][gemspec]
1. Run `bundle update license_finder`
1. Test the changes by following the instructions for [running the tests](#running-the-tests)
1. Submit a merge request.

## Step by Step: Detection

1. Run the Docker image:

    ```sh
    docker run \
      --volume "$PWD":/code \
      --env=LM_REPORT_VERSION="2.1" \
      --env=CI_PROJECT_DIR=/code \
      registry.gitlab.com/gitlab-org/security-products/analyzers/license-finder:latest
    ```

1. The `ENTRYPOINT` for the container will execute [run.sh](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/-/blob/191185c4303768c6d9a1431c35143501c06ee4d7/run.sh):

    ```Dockerfile
    ENTRYPOINT ["/run.sh"]
    ```

1. This shell script sets up the runtime environment then invokes the `license_management` executable:

    ```sh
    #!/bin/bash -l
    export LM_JAVA_VERSION=${LM_JAVA_VERSION:-"8"}
    export LM_PYTHON_VERSION=${LM_PYTHON_VERSION:-"3"}
    export LM_REPORT_FILE=${LM_REPORT_FILE:-'gl-license-scanning-report.json'}
    ...
    license_management report $@
    ```

1. The `license_management` executable loads monkey patches for [license_finder][license_finder] then invokes the CLI:

    ```ruby
    require 'license/management'

    LicenseFinder::CLI::Main.start(ARGV)
    ```

1. [license_finder][license_finder] searches for lockfiles in the project.

    ```ruby
    def active?
      project_path.join('pom.xml').exist?
    end
    ```

1. When a [license_finder][license_finder] determines that a package manager is active, it then invokes the `prepare` step for that package manager.

    ```ruby
    def prepare
      within_project_path do
        tool_box.install(tool: :java, version: java_version, env: default_env)
      end
    end
    ```

1. The `tool_box` determines the required version of tools (i.e Java, Ruby, Python etc) for the package manager and then installs it by looking in `/opt/toolcache/` for a matching `*.deb` file or falls back to `asdf` to install the tool from source.

    ```ruby
    def install(tool:, version: , env: {})
      Dir.chdir project_path do
        deb = deb_for(tool, version)
        shell.execute([:dpkg, '-i', deb]) if deb&.exist?
        shell.execute([:asdf, :install, tool.to_s, version], env: env)
      end
    end

    def deb_for(tool, version)
      Pathname.glob("/opt/toolcache/#{tool}-#{version}*.deb")[0]
    end
    ```

1. After the tool(s) are installed the package manager class builds a list of dependencies identified in the project. If an `install_path` is provided then the files in this directory are scanned for software licenses.

    ```ruby
    def current_packages
      within_project_path do
        return [] unless shell.execute(detect_licenses_command, env: default_env)[-1].success?

        resource_files.flat_map { |file| map_from(file.read) }.uniq
      end
    end
    ```

1. Once all the dependencies and their licenses are identified a JSON report is generated for the desired version of the report. The `Report` class is backwards compatible and able to generate any previous version of the report.

    ```ruby
    def to_s
      JSON.pretty_generate(version_for(report_version).to_h)
    end

    def version_for(version)
      VERSIONS.fetch(version.to_s).new(dependencies)
    end
    ```

1. The final JSON report is written to [gl-license-scanning-report.json](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/-/blob/191185c4303768c6d9a1431c35143501c06ee4d7/spec/fixtures/schema/v2.1.json) in the root of the project.

    ```json
    {
      "version": "2.1",
      "licenses": [
        {
          "id": "MPL-2.0",
          "name": "Mozilla Public License 2.0",
          "url": "https://opensource.org/licenses/MPL-2.0"
        }
      ],
      "dependencies": [
        {
          "name": "rhino",
          "version": "1.7.10",
          "package_manager": "maven",
          "path": "pom.xml",
          "licenses": [
            "MPL-2.0"
          ]
        }
      ]
    }
    ```

# Contributing

If you want to help, read the [contribution guidelines](CONTRIBUTING.md).

If an unknown license is detected, please consider updating the mapping defined
in [normalized-licenses.yml](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/blob/master/normalized-licenses.yml). A mapping can be for a detected name or url and must correspond to an SPDX identifier found in [spdx-licenses.json](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/blob/master/spdx-licenses.json).

[bower]: https://bower.io/
[bundler]: https://bundler.io/
[changelog]: https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/-/blob/master/CHANGELOG.md
[composer]: https://getcomposer.org
[conan]: https://conan.io/
[dotnet_core]: https://docs.microsoft.com/en-us/dotnet/core/tools/
[gemfile_lock]: https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/-/blob/master/Gemfile.lock
[gemspec]: https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/-/blob/master/license-management.gemspec
[godep]: https://github.com/tools/godep
[gomod]: https://github.com/golang/go/wiki/Modules
[gradle]: https://gradle.org/
[license_finder]: https://rubygems.org/gems/license_finder
[maven]: https://maven.apache.org/
[npm]: https://www.npmjs.com/
[nuget]: https://www.nuget.org/
[pip]: https://pip.pypa.io/en/stable/
[pipenv]: https://github.com/pypa/pipenv
[version_rb]: https://gitlab.com/gitlab-org/security-products/analyzers/license-finder/-/blob/master/lib/license/management/version.rb
[yarn]: https://yarnpkg.com/