Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

scanner: Add Nomos plugin #10631

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

Open
Prakash-Mishra-9ghz wants to merge 1 commit into oss-review-toolkit:main
base: main
Choose a base branch
Loading
from Prakash-Mishra-9ghz:nomos
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.versions
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CONAN_VERSION=1.66.0
CONAN2_VERSION=2.14.0
DART_VERSION=2.18.4
DOTNET_VERSION=6.0
FOSSOLOGY_NOMOSSA_VERSION=4.5.1
GO_VERSION=1.24.5
HASKELL_STACK_VERSION=2.13.1
JAVA_VERSION=21
Expand Down
10 changes: 10 additions & 0 deletions Dockerfile
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,16 @@ COPY --from=ruby --chown=$USER:$USER $RBENV_ROOT $RBENV_ROOT

COPY --from=scancode-license-data --chown=$USER:$USER /opt/scancode-license-data /opt/scancode-license-data

#FOSSology-nomossa
ARG FOSSOLOGY_NOMOSSA_VERSION

RUN mkdir -p /opt/FOSSology-nomossa/bin && \
wget -q https://github.com/fossology/fossology/releases/download/$FOSSOLOGY_NOMOSSA_VERSION/FOSSology-nomossa \
-O /opt/FOSSology-nomossa/bin/FOSSology-nomossa \
&& chmod +x /opt/FOSSology-nomossa/bin/FOSSology-nomossa

ENV PATH=$PATH:/opt/FOSSology-nomossa/bin

#------------------------------------------------------------------------
# Container with all supported package managers.
FROM minimal-tools AS all-tools
Expand Down
1 change: 1 addition & 0 deletions NOTICE
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Copyright (C) 2023-2024 Double Open Oy
Copyright (C) 2024 Robert Bosch GmbH
Copyright (C) 2024 Cariad SE
Copyright (C) 2025 Quartett mobile GmbH
Copyright (C) 2025 Prakash Mishra
42 changes: 42 additions & 0 deletions plugins/scanners/fossologynomossa/build.gradle.kts
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* 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
*
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

plugins {
// Apply precompiled plugins.
id("ort-plugin-conventions")

// Apply third-party plugins.
alias(libs.plugins.kotlinSerialization)
}

dependencies {
api(projects.model)
api(projects.scanner)

implementation(projects.utils.commonUtils)
implementation(projects.utils.ortUtils)
implementation(projects.utils.spdxUtils)

implementation(libs.kotlinx.serialization.json)

ksp(projects.scanner)

funTestApi(testFixtures(projects.scanner))

}
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* 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
*
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.ossreviewtoolkit.plugins.scanners.fossologynomossa

import org.ossreviewtoolkit.model.LicenseFinding
import org.ossreviewtoolkit.model.TextLocation
import org.ossreviewtoolkit.scanner.AbstractPathScannerWrapperFunTest

class FossologyNomossaFunTest : AbstractPathScannerWrapperFunTest() {
override val scanner = NomossaFactory.create()

override val expectedFileLicenses = listOf(
LicenseFinding("Apache-2.0", TextLocation("LICENSE", 1, 195), 100.0f)
)

override val expectedDirectoryLicenses = listOf(
LicenseFinding("Apache-2.0", TextLocation("COPYING", 1, 195), 100.0f),
LicenseFinding("Apache-2.0", TextLocation("LICENCE", 1, 195), 100.0f),
LicenseFinding("Apache-2.0", TextLocation("LICENSE", 1, 195), 100.0f)
)
}
126 changes: 126 additions & 0 deletions plugins/scanners/fossologynomossa/src/main/kotlin/Nomossa.kt
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* 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
*
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.ossreviewtoolkit.plugins.scanners.fossologynomossa

import java.io.File
import java.time.Instant

import kotlin.math.max

import org.apache.logging.log4j.kotlin.logger

import org.ossreviewtoolkit.model.ScanSummary
import org.ossreviewtoolkit.plugins.api.OrtPlugin
import org.ossreviewtoolkit.plugins.api.PluginDescriptor
import org.ossreviewtoolkit.scanner.LocalPathScannerWrapper
import org.ossreviewtoolkit.scanner.ScanContext
import org.ossreviewtoolkit.scanner.ScannerMatcher
import org.ossreviewtoolkit.scanner.ScannerWrapperFactory
import org.ossreviewtoolkit.utils.common.CommandLineTool
import org.ossreviewtoolkit.utils.common.ProcessCapture

object NomossaCommand : CommandLineTool {
override fun command(workingDir: File?) =
listOfNotNull(workingDir, "FOSSology-nomossa").joinToString(File.separator)

override fun transformVersion(output: String) =
// Example output:
// nomos build version: 4.5.1.1 r(ff4fa7)
output.removePrefix("nomos build version: ").substringBefore(' ') // Returns 4.5.1

override fun getVersionArguments() = "-V"
}

/**
* A wrapper for [Nomossa](https://github.com/fossology/fossology/tree/master/src/nomos).
*
* This plugin integrates FOSSology's Nomossa scanner into ORT by calling its CLI
* and mapping its output to ORT's scan result format.
*/
@OrtPlugin(
id = "Nomossa",
displayName = "Nomossa (FOSSology)",
description = "A wrapper for [Nomossa](https://github.com/fossology/fossology/tree/master/src/nomos).",
factory = ScannerWrapperFactory::class
)
class Nomossa(
override val descriptor: PluginDescriptor = NomossaFactory.descriptor,
private val config: NomossaConfig
) : LocalPathScannerWrapper() {
private val commandLineOptions by lazy { getCommandLineOptions() }

internal fun getCommandLineOptions() =
buildList {
addAll(config.additionalOptions)
}

override val configuration by lazy {
config.additionalOptions.joinToString(" ")
}

override val matcher by lazy { ScannerMatcher.create(details, config) }

override val version by lazy {
require(NomossaCommand.isInPath()) {
"The '${NomossaCommand.command()}' command is not available in the PATH environment."
}

NomossaCommand.getVersion()
}

override val readFromStorage = config.readFromStorage
override val writeToStorage = config.writeToStorage

override fun runScanner(path: File, context: ScanContext): String {
val process = runNomossa(path)

return with(process) {
if (isError && stdout.isNotBlank()) logger.debug { stdout }
if (stderr.isNotBlank()) logger.debug { stderr }

stdout
}
}

override fun createSummary(result: String, startTime: Instant, endTime: Instant): ScanSummary =
parseNomossaResult(result).toScanSummary(startTime, endTime)

/**
* Execute Nomossa with the configured arguments to scan the given [path].
*/
internal fun runNomossa(path: File): ProcessCapture {
val options = mutableListOf<String>()
options.addAll(commandLineOptions)

if (path.isDirectory) {
options += listOf(
"-n", max(2, Runtime.getRuntime().availableProcessors() - 1).toString(),
"-d", path.absolutePath
)
} else {
options += path.absolutePath
}

return ProcessCapture(
NomossaCommand.command(),
*options.toTypedArray()
)
}
}
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* 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
*
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.ossreviewtoolkit.plugins.scanners.fossologynomossa

import org.ossreviewtoolkit.plugins.api.OrtPluginOption
import org.ossreviewtoolkit.scanner.ScannerMatcherCriteria

/**
* Configuration options for the Nomossa scanner.
*/
data class NomossaConfig(
/**
* Command line options that affect scan results. These are used when matching stored results.
*/
@OrtPluginOption(defaultValue = "-J,-S,-l")
val additionalOptions: List<String>,

/**
* The scanner name pattern used when looking up scan results from storage.
*/
override val regScannerName: String?,

/**
* The minimum version of scan results to use from storage.
*/
override val minVersion: String?,

/**
* The maximum version of scan results to use from storage.
*/
override val maxVersion: String?,

/**
* The configuration string for identifying matching scan results in storage.
*/
override val configuration: String?,

/**
* Whether to read scan results from storage.
*/
@OrtPluginOption(defaultValue = "false")
val readFromStorage: Boolean,

/**
* Whether to write scan results to storage.
*/
@OrtPluginOption(defaultValue = "false")
val writeToStorage: Boolean
) : ScannerMatcherCriteria
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2025 The ORT Project Authors (see <https://github.com/oss-review-toolkit/ort/blob/main/NOTICE>)
*
* 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
*
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

package org.ossreviewtoolkit.plugins.scanners.fossologynomossa

import java.io.File
import java.time.Instant

import org.ossreviewtoolkit.model.LicenseFinding
import org.ossreviewtoolkit.model.ScanSummary
import org.ossreviewtoolkit.model.TextLocation
import org.ossreviewtoolkit.utils.spdx.SpdxConstants
import org.ossreviewtoolkit.utils.spdx.SpdxExpression

internal fun NomossaResult.toScanSummary(startTime: Instant, endTime: Instant): ScanSummary {
val licenseFindings = results.flatMap { fileResult ->
val fileContent = File(fileResult.file).readText()

Copy link
Member

@sschuberth sschuberth Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Omit this superfluous blank line.

fileResult.licenses.map { licenseInfo ->
val licenseExpression = runCatching { SpdxExpression.parse(licenseInfo.license) }.getOrNull()

val safeLicense = when {
licenseExpression == null -> SpdxConstants.NOASSERTION
licenseExpression.isValid() -> licenseInfo.license
else -> "LicenseRef-Nomossa-${licenseInfo.license.replace(Regex("[^A-Za-z0-9.+-]"), "-")}"
}
val (startLine, endLine) = byteOffsetsToLineNumbers(fileContent, licenseInfo.start, licenseInfo.end)

Triple(fileResult.file, safeLicense, startLine to endLine)
}
}.groupBy { (file, license, _) -> file to license }
.map { (fileAndLicense, entries) ->
val (file, license) = fileAndLicense
val startLine = entries.minOf { it.third.first }
val endLine = entries.maxOf { it.third.second }

LicenseFinding(
license = license,
location = TextLocation(
path = file,
startLine = startLine,
endLine = endLine
),
score = 100.0f
)
}.toSet()

return ScanSummary(
startTime = startTime,
endTime = endTime,
licenseFindings = licenseFindings,
issues = emptyList(),
copyrightFindings = sortedSetOf()
)
}

internal fun byteOffsetsToLineNumbers(fileContent: String, startOffset: Int, endOffset: Int): Pair<Int, Int> {
var startLine = 1
var endLine = 1

for ((index, char) in fileContent.withIndex()) {
if (index >= startOffset && index > endOffset) break

if (char == '\n') {
if (index < startOffset) startLine++
if (index < endOffset) endLine++
}
}

return Pair(startLine, endLine)
}
Loading
Loading

AltStyle によって変換されたページ (->オリジナル) /