@@ -3,7 +3,6 @@ package dev.protsenko.securityLinter.dockerCompose
33import com.intellij.codeInspection.LocalInspectionTool
44import com.intellij.codeInspection.ProblemHighlightType
55import com.intellij.codeInspection.ProblemsHolder
6- import com.intellij.psi.PsiElement
76import com.intellij.psi.PsiElementVisitor
87import com.intellij.psi.PsiFile
98import dev.protsenko.securityLinter.core.DockerFileConstants.PROHIBITED_PORTS
@@ -16,16 +15,15 @@ import dev.protsenko.securityLinter.dockerCompose.DockerComposeConstants.PRIVILE
1615import dev.protsenko.securityLinter.dockerCompose.DockerComposeConstants.USER_KEY_LITERAL
1716import dev.protsenko.securityLinter.dockerCompose.DockerComposeConstants.supportedAttributes
1817import dev.protsenko.securityLinter.utils.PortUtils
18+ import dev.protsenko.securityLinter.utils.YamlPath
1919import dev.protsenko.securityLinter.utils.image.ImageAnalyzer
2020import dev.protsenko.securityLinter.utils.image.ImageDefinitionCreator
21- import org.jetbrains.yaml.navigation.YAMLQualifiedNameProvider
2221import org.jetbrains.yaml.psi.YAMLFile
2322import org.jetbrains.yaml.psi.YAMLKeyValue
23+ import org.jetbrains.yaml.psi.YAMLMapping
2424import org.jetbrains.yaml.psi.YAMLSequenceItem
2525
2626class DockerComposeInspection : LocalInspectionTool () {
27- val provider = YAMLQualifiedNameProvider ()
28-
2927 override fun buildVisitor (
3028 holder : ProblemsHolder ,
3129 isOnTheFly : Boolean ,
@@ -34,81 +32,88 @@ class DockerComposeInspection : LocalInspectionTool() {
3432 override fun visitFile (file : PsiFile ) {
3533 if (file !is YAMLFile ) return
3634 if (! file.name.startsWith(" docker" , ignoreCase = true )) return
37- super .visitFile(file)
38- }
3935
40- /* *
41- * For more information about service attributes: https://docs.docker.com/reference/compose-file/services
42- */
43- override fun visitElement (element : PsiElement ) {
44- if (element is YAMLKeyValue ) {
45- val fqn = provider.getQualifiedName(element) ? : return
46- if (! fqn.startsWith(" services" )) return
36+ val documents = file.documents
4737
48- val attributeName = element.key?.text ? : return
49- if (attributeName !in supportedAttributes) return
50- val attributeValue = element.value?.text?.trim() ? : return
38+ for (document in documents) {
39+ val serviceMapping = YamlPath .findByYamlPath(" services" , document) as ? YAMLMapping ? : return
40+ val serviceDefinitions =
41+ serviceMapping
42+ .children
43+ .filterIsInstance<YAMLKeyValue >()
44+ .map { it.value }
45+ .filterIsInstance<YAMLMapping >()
5146
52- when (attributeName ) {
53- // Analyzing image definition
54- IMAGE_KEY_LITERAL -> {
55- val imageDefinition = ImageDefinitionCreator .fromString(attributeValue, emptyMap())
56- ImageAnalyzer .analyzeAndHighlight(imageDefinition, holder, element, emptyMap())
57- }
47+ for (serviceDefinition in serviceDefinitions ) {
48+ val serviceAttributes = serviceDefinition.children.filterIsInstance< YAMLKeyValue >()
49+ for (serviceAttribute in serviceAttributes) {
50+ val attributeName = serviceAttribute.key?.text ? : continue
51+ if (attributeName !in supportedAttributes) continue
52+ val attributeValue = serviceAttribute.value?.text ? : continue
5853
59- USER_KEY_LITERAL -> {
60- if (PROHIBITED_USERS .contains(attributeValue.trim())) {
61- val descriptor =
62- HtmlProblemDescriptor (
63- element,
64- SecurityPluginBundle .message(" dfs002.documentation" ),
65- SecurityPluginBundle .message(" dfs002.root-user-is-used" ),
66- ProblemHighlightType .ERROR ,
67- )
54+ when (attributeName) {
55+ // Analyzing image definition
56+ IMAGE_KEY_LITERAL -> {
57+ val imageDefinition = ImageDefinitionCreator .fromString(attributeValue, emptyMap())
58+ ImageAnalyzer .analyzeAndHighlight(imageDefinition, holder, serviceAttribute, emptyMap())
59+ }
6860
69- holder.registerProblem(descriptor)
70- }
71- }
61+ USER_KEY_LITERAL -> {
62+ if (PROHIBITED_USERS .contains(attributeValue.trim())) {
63+ val descriptor =
64+ HtmlProblemDescriptor (
65+ serviceAttribute,
66+ SecurityPluginBundle .message(" dfs002.documentation" ),
67+ SecurityPluginBundle .message(" dfs002.root-user-is-used" ),
68+ ProblemHighlightType .ERROR ,
69+ )
7270
73- PRIVILEGED_LITERAL -> {
74- if (attributeValue == " true" ) {
75- holder.registerProblem(
76- element,
77- SecurityPluginBundle .message(" ds033.using-privileged" ),
78- ProblemHighlightType .ERROR ,
79- )
80- }
81- }
71+ holder.registerProblem(descriptor)
72+ }
73+ }
74+
75+ PRIVILEGED_LITERAL -> {
76+ if (attributeValue == " true" ) {
77+ holder.registerProblem(
78+ serviceAttribute,
79+ SecurityPluginBundle .message(" ds033.using-privileged" ),
80+ ProblemHighlightType .ERROR ,
81+ )
82+ }
83+ }
8284
83- PORTS_LITERAL -> {
84- element.value?.children?.forEach {
85- if (it is YAMLSequenceItem ) {
86- var portsDefinitions = it.value?.text ? : return @forEach
87- // quotes at start and end should be trimmed
88- if (portsDefinitions.length > 2 ) {
89- portsDefinitions = portsDefinitions.substring(1 , portsDefinitions.length - 1 )
90- val containerPorts = PortUtils .parseContainerPorts(portsDefinitions)
91- containerPorts.forEach { containerPort ->
92- if (PROHIBITED_PORTS .contains(containerPort)) {
93- val descriptor =
94- HtmlProblemDescriptor (
95- it,
96- SecurityPluginBundle .message(" dfs011.documentation" ),
97- SecurityPluginBundle .message(" dfs011.ssh-port-exposed" ),
98- ProblemHighlightType .ERROR ,
99- emptyArray(),
100- )
85+ PORTS_LITERAL -> {
86+ serviceAttribute.value?.children?.forEach {
87+ if (it is YAMLSequenceItem ) {
88+ var portsDefinitions = it.value?.text ? : return @forEach
89+ // quotes at start and end should be trimmed
90+ if (portsDefinitions.length > 2 ) {
91+ portsDefinitions =
92+ portsDefinitions.substring(1 , portsDefinitions.length - 1 )
93+ val containerPorts = PortUtils .parseContainerPorts(portsDefinitions)
94+ containerPorts.forEach { containerPort ->
95+ if (PROHIBITED_PORTS .contains(containerPort)) {
96+ val descriptor =
97+ HtmlProblemDescriptor (
98+ it,
99+ SecurityPluginBundle .message(" dfs011.documentation" ),
100+ SecurityPluginBundle .message(" dfs011.ssh-port-exposed" ),
101+ ProblemHighlightType .ERROR ,
102+ emptyArray(),
103+ )
101104
102- holder.registerProblem(descriptor)
105+ holder.registerProblem(descriptor)
106+ }
107+ }
103108 }
104109 }
105- }
110+ return @forEach
111+ } ? : return
106112 }
107- return @forEach
108- } ? : return
109- }
110113
111- else -> return
114+ else -> return
115+ }
116+ }
112117 }
113118 }
114119 }
0 commit comments