Skip to content
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

Added (mostly empty) skeleton for Codyze #1936

Merged
merged 9 commits into from
Jan 16, 2025
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Added compliance module with security-goals
  • Loading branch information
oxisto committed Jan 16, 2025
commit fe5dcd810b5cfde1a76562fb0a7628a45b28b7a1
2 changes: 1 addition & 1 deletion codyze-compliance/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@
*
*/
plugins {
id("cpg.common-conventions")
id("cpg.frontend-conventions")
}

publishing {
Original file line number Diff line number Diff line change
@@ -1,8 +1,40 @@
/*
* Copyright (c) 2025, Fraunhofer AISEC. All rights reserved.
*
* 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.
*
* $$$$$$\ $$$$$$$\ $$$$$$\
* $$ __$$\ $$ __$$\ $$ __$$\
* $$ / \__|$$ | $$ |$$ / \__|
* $$ | $$$$$$$ |$$ |$$$$\
* $$ | $$ ____/ $$ |\_$$ |
* $$ | $$\ $$ | $$ | $$ |
* \$$$$$ |$$ | \$$$$$ |
* \______/ \__| \______/
*
*/
package de.fraunhofer.aisec.cpg.codyze.compliance

import com.charleskorn.kaml.Yaml
import de.fraunhofer.aisec.cpg.graph.Component
import de.fraunhofer.aisec.cpg.graph.Name
import de.fraunhofer.aisec.cpg.graph.OverlayNode
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.Path
import kotlin.io.path.extension
import kotlin.io.path.readText
import kotlin.io.path.walk
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
@@ -11,33 +43,31 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.Path
import kotlin.io.path.extension
import kotlin.io.path.readText
import kotlin.io.path.walk

@Serializable
class SecurityGoal(
@Serializable(with = NameSerializer::class)
override var name: Name
) : OverlayNode() {
}

class SecurityObjective : OverlayNode() {

}

class SecurityStatement : OverlayNode() {
data class SecurityGoal(
@Serializable(with = NameSerializer::class) override var name: Name,
val description: String,
val components: List<@Serializable(with = ComponentSerializer::class) Component?> = listOf(),
val assumptions: List<String> = listOf(),
val restrictions: List<String> = listOf(),
val objectives: List<SecurityObjective>,
) : OverlayNode()

}
@Serializable
class SecurityObjective(
@Serializable(with = NameSerializer::class) override var name: Name,
val description: String,
val statements: List<String>,
val components: List<@Serializable(with = ComponentSerializer::class) Component?> = listOf(),
val assumptions: List<String> = listOf(),
val restrictions: List<String> = listOf(),
) : OverlayNode()

/**
* A custom serializer for the Name class.
*/
/** A custom serializer for the [Name] class. */
class NameSerializer : KSerializer<Name> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(Name::class.qualifiedName!!, PrimitiveKind.STRING)
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor(Name::class.qualifiedName!!, PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: Name) {
encoder.encodeString(value.localName)
@@ -46,22 +76,41 @@ class NameSerializer : KSerializer<Name> {
override fun deserialize(decoder: Decoder): Name {
return Name(decoder.decodeString())
}

}

@OptIn(ExperimentalPathApi::class)
fun loadSecurityGoals(directory: String): List<SecurityGoal> {
// Walk the directory and load all YAML files
Path(directory).walk().filter { it.extension == "yaml" }.forEach {
val goals = loadSecurityGoal(it)
/**
* A custom serializer for the [Component] class.
*/
class ComponentSerializer : KSerializer<Component?> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor(Component::class.qualifiedName!!, PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: Component?) {
if (value != null) {
encoder.encodeString(value.name.toString())
}
}

return listOf()
override fun deserialize(decoder: Decoder): Component? {
// TODO: find component by name somehow
return null
}
}

/**
* Load a single security goal from a file.
* Load all security goals from a directory.
*/
@OptIn(ExperimentalPathApi::class)
fun loadSecurityGoals(directory: String): List<SecurityGoal> {
// Walk the directory and load all YAML files
return Path(directory)
.walk()
.filter { it.extension == "yaml" }
.toList()
.map { loadSecurityGoal(it) }
}

/** Load a single security goal from a file. */
fun loadSecurityGoal(file: Path): SecurityGoal {
return Yaml.default.decodeFromString<SecurityGoal>(file.readText())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2025, Fraunhofer AISEC. All rights reserved.
*
* 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.
*
* $$$$$$\ $$$$$$$\ $$$$$$\
* $$ __$$\ $$ __$$\ $$ __$$\
* $$ / \__|$$ | $$ |$$ / \__|
* $$ | $$$$$$$ |$$ |$$$$\
* $$ | $$ ____/ $$ |\_$$ |
* $$ | $$\ $$ | $$ | $$ |
* \$$$$$ |$$ | \$$$$$ |
* \______/ \__| \______/
*
*/
package de.fraunhofer.aisec.cpg.codyze.compliance

import kotlin.test.*

class SecurityGoalTest {
@Test
fun testLoad() {
val goals = loadSecurityGoals("src/test/resources/security-goals")
val goal1 = goals.firstOrNull()
assertNotNull(goal1)

val objective1 = goal1.objectives.firstOrNull()
assertNotNull(objective1)
assertEquals("Good encryption", objective1.name.localName)
}
}
12 changes: 12 additions & 0 deletions codyze-compliance/src/test/resources/security-goals/goal1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Goal1
description: Make it very secure
components:
- auth
- webserver
assumptions:
- Third party code is very good
objectives:
- name: Good encryption
description: Encryption used is very good
statements:
- For each algorithm A, if A is used, then A must be a very good cryptographic algorithm
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ import org.neo4j.ogm.annotation.Relationship
* Represents an extra node added to the CPG. These nodes can live next to the regular nodes,
* typically having shared edges to extend the original graph.
*/
abstract class OverlayNode() : Node() {
abstract class OverlayNode : Node() {

init {
this.language = NoLanguage