Skip to content

Commit 84c258a

Browse files
committed
feat(Extractor): add copyright to evidence collection
closes: CycloneDX#1310 Signed-off-by: frozen_byte <[email protected]>
1 parent 1952e99 commit 84c258a

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/extractor.ts

+44
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ export class Extractor {
111111
component.evidence = new CDX.Models.ComponentEvidence({
112112
licenses: new CDX.Models.LicenseRepository(this.getLicenseEvidence(dirname(pkg.path), logger))
113113
})
114+
for (const line of this.getCopyrightEvidence(dirname(pkg.path), logger)) {
115+
component.evidence.copyright.add(line)
116+
}
114117
}
115118

116119
component.purl = this.#purlFactory.makeFromComponent(component)
@@ -130,6 +133,46 @@ export class Extractor {
130133
}
131134
}
132135

136+
readonly #COPYRIGHT_FILENAME_PATTERN = /^(?:UN)?LICEN[CS]E|.\.LICEN[CS]E$|^NOTICE$|^COPYRIGHTNOTICE$/i
137+
138+
public * getCopyrightEvidence (packageDir: string, logger?: WebpackLogger): Generator<string> {
139+
let pcis
140+
try {
141+
pcis = readdirSync(packageDir, {withFileTypes: true})
142+
} catch (e) {
143+
logger?.warn('collecting license evidence in', packageDir, 'failed:', e)
144+
return
145+
}
146+
for (const pci of pcis) {
147+
if (
148+
!pci.isFile() ||
149+
!this.#COPYRIGHT_FILENAME_PATTERN.test(pci.name)
150+
) {
151+
continue
152+
}
153+
const fp = join(packageDir, pci.name)
154+
try {
155+
// Add copyright evidence
156+
const linesStartingWithCopyright = readFileSync(fp).toString('utf-8')
157+
.split(/\r\n?|\n/)
158+
.map(line => line.trimStart())
159+
.filter(trimmedLine => {
160+
return trimmedLine.startsWith('opyright', 1) && // include copyright statements
161+
!trimmedLine.startsWith('opyright notice', 1) && // exclude lines from license text
162+
!trimmedLine.startsWith('opyright and related rights', 1) &&
163+
!trimmedLine.startsWith('opyright license to reproduce', 1)
164+
})
165+
.filter((value, index, list) => index === 0 || value !== list[0]) // remove duplicates
166+
167+
for (const line of linesStartingWithCopyright) {
168+
yield line
169+
}
170+
} catch (e) { // may throw if `readFileSync()` fails
171+
logger?.warn('collecting copyright evidences from', fp, 'failed:', e)
172+
}
173+
}
174+
}
175+
133176
readonly #LICENSE_FILENAME_PATTERN = /^(?:UN)?LICEN[CS]E|.\.LICEN[CS]E$|^NOTICE$/i
134177

135178
public * getLicenseEvidence (packageDir: string, logger?: WebpackLogger): Generator<CDX.Models.License> {
@@ -150,6 +193,7 @@ export class Extractor {
150193

151194
const contentType = getMimeForTextFile(pci.name)
152195
if (contentType === undefined) {
196+
logger?.warn(`could not determine content-type for ${pci.name}`)
153197
continue
154198
}
155199

0 commit comments

Comments
 (0)