-
Notifications
You must be signed in to change notification settings - Fork 474
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Added probe for permissive licenses (#3838)
* Added check for permissive licenses Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Regenerated docs and added more permissive licenses to check Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Added e2e tests Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Corrected copyright dates and missing newlines Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Corrected copyright dates Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Adjustments after review Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Added file location in case a permissive license was found and adjusted tests Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * Removed code for check, adjusted probe code to be invocated independently Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> * add remediate on outcome detail Signed-off-by: Spencer Schrock <sschrock@google.com> * avoid memory aliasing Signed-off-by: Spencer Schrock <sschrock@google.com> --------- Signed-off-by: Felix Hoeborn <f.hoeborn@gmail.com> Signed-off-by: Felix Hoeborn <98820380+fhoeborn@users.noreply.github.com> Signed-off-by: Spencer Schrock <sschrock@google.com> Co-authored-by: Spencer Schrock <sschrock@google.com>
- Loading branch information
1 parent
b77f248
commit 21d53ce
Showing
4 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright 2024 OpenSSF Scorecard Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
id: hasPermissiveLicense | ||
short: Check that the project has an permissive license. | ||
motivation: > | ||
A permissive license allows users to use the analyzed component to be used in derivative works. Non-permissive licenses (as copyleft licenses) might be a legal risk for potential users. | ||
implementation: > | ||
The implementation checks whether a permissive license is present | ||
outcome: | ||
- If a license file is found and is permissive, the probe returns a single OutcomeTrue. | ||
- If a license file is missing the probe returns a single OutcomeFalse. | ||
- If the license is not permissive, the probe returns a single OutcomeFalse. | ||
remediation: | ||
onOutcome: False | ||
effort: High | ||
text: | ||
- A relicensing is necessary, or the component should not be used by the user for this purpose. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// Copyright 2024 OpenSSF Scorecard Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//nolint:stylecheck | ||
package hasPermissiveLicense | ||
|
||
import ( | ||
"embed" | ||
"fmt" | ||
|
||
"github.com/ossf/scorecard/v4/checker" | ||
"github.com/ossf/scorecard/v4/finding" | ||
"github.com/ossf/scorecard/v4/internal/probes" | ||
"github.com/ossf/scorecard/v4/probes/internal/utils/uerror" | ||
) | ||
|
||
//go:embed *.yml | ||
var fs embed.FS | ||
|
||
func init() { | ||
probes.MustRegister(Probe, Run, []probes.CheckName{probes.License}) | ||
} | ||
|
||
const Probe = "hasPermissiveLicense" | ||
|
||
func Run(raw *checker.RawResults) ([]finding.Finding, string, error) { | ||
if raw == nil { | ||
return nil, "", fmt.Errorf("%w: raw", uerror.ErrNil) | ||
} | ||
|
||
if len(raw.LicenseResults.LicenseFiles) == 0 { | ||
f, err := finding.NewWith(fs, Probe, | ||
"project does not have a license file", nil, | ||
finding.OutcomeFalse) | ||
if err != nil { | ||
return nil, Probe, fmt.Errorf("create finding: %w", err) | ||
} | ||
return []finding.Finding{*f}, Probe, nil | ||
} | ||
|
||
for i := range raw.LicenseResults.LicenseFiles { | ||
licenseFile := raw.LicenseResults.LicenseFiles[i] | ||
spdxID := licenseFile.LicenseInformation.SpdxID | ||
switch spdxID { | ||
case | ||
"Unlicense", | ||
"Beerware", | ||
"Apache-2.0", | ||
"MIT", | ||
"0BSD", | ||
"BSD-1-Clause", | ||
"BSD-2-Clause", | ||
"BSD-3-Clause", | ||
"BSD-4-Clause", | ||
"APSL-1.0", | ||
"APSL-1.1", | ||
"APSL-1.2", | ||
"APSL-2.0", | ||
"ECL-1.0", | ||
"ECL-2.0", | ||
"EFL-1.0", | ||
"EFL-2.0", | ||
"Fair", | ||
"FSFAP", | ||
"WTFPL", | ||
"Zlib", | ||
"CNRI-Python", | ||
"ISC", | ||
"Intel": | ||
// Store the license name in the msg | ||
msg := licenseFile.LicenseInformation.Name | ||
loc := &finding.Location{ | ||
Type: licenseFile.File.Type, | ||
Path: licenseFile.File.Path, | ||
LineStart: &licenseFile.File.Offset, | ||
LineEnd: &licenseFile.File.EndOffset, | ||
Snippet: &licenseFile.File.Snippet, | ||
} | ||
f, err := finding.NewWith(fs, Probe, | ||
msg, loc, | ||
finding.OutcomeTrue) | ||
if err != nil { | ||
return nil, Probe, fmt.Errorf("create finding: %w", err) | ||
} | ||
return []finding.Finding{*f}, Probe, nil | ||
} | ||
} | ||
|
||
f, err := finding.NewWith(fs, Probe, | ||
"", nil, | ||
finding.OutcomeFalse) | ||
if err != nil { | ||
return nil, Probe, fmt.Errorf("create finding: %w", err) | ||
} | ||
return []finding.Finding{*f}, Probe, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// Copyright 2024 OpenSSF Scorecard Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//nolint:stylecheck | ||
package hasPermissiveLicense | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/google/go-cmp/cmp/cmpopts" | ||
|
||
"github.com/ossf/scorecard/v4/checker" | ||
"github.com/ossf/scorecard/v4/finding" | ||
"github.com/ossf/scorecard/v4/probes/internal/utils/test" | ||
) | ||
|
||
func Test_Run(t *testing.T) { | ||
t.Parallel() | ||
//nolint:govet | ||
tests := []struct { | ||
name string | ||
raw *checker.RawResults | ||
outcomes []finding.Outcome | ||
err error | ||
}{ | ||
{ | ||
name: "License file found and is permissive: outcome should be positive", | ||
raw: &checker.RawResults{ | ||
LicenseResults: checker.LicenseData{ | ||
LicenseFiles: []checker.LicenseFile{ | ||
{ | ||
File: checker.File{ | ||
Path: "LICENSE.md", | ||
}, | ||
LicenseInformation: checker.License{ | ||
SpdxID: "Apache-2.0", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
outcomes: []finding.Outcome{ | ||
finding.OutcomeTrue, | ||
}, | ||
}, | ||
{ | ||
name: "License file found and is not permissive: outcome should be negative", | ||
raw: &checker.RawResults{ | ||
LicenseResults: checker.LicenseData{ | ||
LicenseFiles: []checker.LicenseFile{ | ||
{ | ||
File: checker.File{ | ||
Path: "LICENSE.md", | ||
}, | ||
LicenseInformation: checker.License{ | ||
SpdxID: "AGPL-3.0", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
outcomes: []finding.Outcome{ | ||
finding.OutcomeFalse, | ||
}, | ||
}, | ||
{ | ||
name: "License file not found and outcome should be negative", | ||
raw: &checker.RawResults{ | ||
LicenseResults: checker.LicenseData{ | ||
LicenseFiles: []checker.LicenseFile{}, | ||
}, | ||
}, | ||
outcomes: []finding.Outcome{ | ||
finding.OutcomeFalse, | ||
}, | ||
}, | ||
{ | ||
name: "nil license files and outcome should be negative", | ||
raw: &checker.RawResults{ | ||
LicenseResults: checker.LicenseData{ | ||
LicenseFiles: nil, | ||
}, | ||
}, | ||
outcomes: []finding.Outcome{ | ||
finding.OutcomeFalse, | ||
}, | ||
}, | ||
{ | ||
name: "0 license files and outcome should be negative", | ||
raw: &checker.RawResults{ | ||
LicenseResults: checker.LicenseData{ | ||
LicenseFiles: []checker.LicenseFile{}, | ||
}, | ||
}, | ||
outcomes: []finding.Outcome{ | ||
finding.OutcomeFalse, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
tt := tt // Re-initializing variable so it is not changed while executing the closure below | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
findings, s, err := Run(tt.raw) | ||
if !cmp.Equal(tt.err, err, cmpopts.EquateErrors()) { | ||
t.Errorf("mismatch (-want +got):\n%s", cmp.Diff(tt.err, err, cmpopts.EquateErrors())) | ||
} | ||
if err != nil { | ||
return | ||
} | ||
if diff := cmp.Diff(Probe, s); diff != "" { | ||
t.Errorf("mismatch (-want +got):\n%s", diff) | ||
} | ||
test.AssertOutcomes(t, findings, tt.outcomes) | ||
}) | ||
} | ||
} |