Skip to content

Commit 7df6a99

Browse files
authored
Merge pull request #5 from NordCoderd/wget-without-recommended-flags
2 parents 7a5a03d + 4d55d68 commit 7df6a99

11 files changed

Lines changed: 122 additions & 4 deletions

File tree

AGENTS.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## General rules
2+
1. Add only new files to git. Do not modify the existing staging unless explicitly required.
3+
4+
## Verification development stages
5+
6+
1. Implement everything in pure Kotlin, making full use of IDE-assisted language features and inspections.
7+
2. Add inspection messages and tooltips to [SecurityPluginBundle.properties](src/main/resources/messages/SecurityPluginBundle.properties).
8+
3. Create the inspection draft in the technology-specific folder under [securityLinter](src/main/kotlin/dev/protsenko/securityLinter).
9+
4. Add tests covering the inspection:
10+
- Example of a Docker inspection: [DS003SshPortExposed.kt](src/test/kotlin/dev/protsenko/securityLinter/docker/DS003SshPortExposed.kt)
11+
- Example of test data for Docker inspections: [DS003](src/test/testData/docker/DS003)
12+
- Example of extended test data with additional cases: [DS029](src/test/testData/docker/DS029)
13+
5. Create an inspection description in HTML using the same filename as the inspection class in [inspectionDescriptions](src/main/resources/inspectionDescriptions).
14+
6. Register the inspection in XML:
15+
- For YAML-based inspections: [dev.protsenko.security-linter-yaml.xml](src/main/resources/META-INF/dev.protsenko.security-linter-yaml.xml)
16+
- For general and Docker-based inspections: [plugin.xml](src/main/resources/META-INF/plugin.xml)
17+
7. If the inspection validates Docker RUN commands, follow the rules defined in [RunCommandValidator.kt](src/main/kotlin/dev/protsenko/securityLinter/docker/checker/core/RunCommandValidator.kt).
18+
- Register the required extension points in [plugin.xml](src/main/resources/META-INF/plugin.xml).
19+
8. If the inspection is YAML-based, use the bundled helper classes such as [YamlPath.kt](src/main/kotlin/dev/protsenko/securityLinter/utils/YamlPath.kt).
20+
9. Ensure that all tests pass.
21+
10. If the plugin version has not been updated in [gradle.properties](gradle.properties), update it.
22+
11. Update the changelog in [CHANGELOG.md](CHANGELOG.md).
23+
12. Perform a full build and run the complete test suite for the plugin.
24+
25+
## Summary for verification development
26+
27+
1. All inspections must be registered and covered by tests.
28+
2. All inspections must leverage Kotlin and IDE capabilities effectively.
29+
3. All reusable helper utilities should be covered by JUnit 3 tests.
30+
4. All inspections must cover corner cases and include extended test scenarios.

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
# Cloud (IaC) Security Changelog
44

5+
## [2.0.17] 15-03-2026
6+
7+
### Added
8+
9+
- Inspection: [wget without recommended flags](https://protsenko.dev/infrastructure-security/avoid-wget-without-progress-or-quiet/)
10+
511
## [2.0.16] 07-02-2026
612

713
### Fixed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pluginGroup = dev.protsenko.securityLinter
22
pluginName = Cloud (IaC) Security
33
pluginRepositoryUrl = https://github.com/NordCoderd/cloud-security-plugin
4-
pluginVersion = 2.0.16
4+
pluginVersion = 2.0.17
55

66
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
77
pluginSinceBuild = 231
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package dev.protsenko.securityLinter.docker.checker
2+
3+
import dev.protsenko.securityLinter.docker.checker.core.RunCommandValidator
4+
5+
object WgetProgressBarValidator : RunCommandValidator {
6+
private val wgetPattern = Regex("""\bwget\b""", RegexOption.IGNORE_CASE)
7+
private val separators = Regex("""\s*(?:&&|;|\n)\s*""")
8+
private val recommendedWgetOptionsPattern =
9+
Regex(
10+
pattern = """(?:^|\s)(--progress=dot:giga|--quiet|--no-verbose|-q(?:\S*)|-nv(?:\S*))(?=\s|$)""",
11+
options = setOf(RegexOption.IGNORE_CASE),
12+
)
13+
14+
override fun isValid(command: String): Boolean {
15+
if (!wgetPattern.containsMatchIn(command)) return true
16+
17+
val cmd = command.removePrefix("RUN").trim()
18+
val individualCommands = separators.split(cmd)
19+
20+
for (individualCommand in individualCommands) {
21+
val cmdTrimmed = individualCommand.trim()
22+
if (!wgetPattern.containsMatchIn(cmdTrimmed)) continue
23+
if (!recommendedWgetOptionsPattern.containsMatchIn(cmdTrimmed)) {
24+
return false
25+
}
26+
}
27+
28+
return true
29+
}
30+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package dev.protsenko.securityLinter.docker.inspection.run.impl
2+
3+
import com.intellij.codeInspection.ProblemHighlightType
4+
import com.intellij.codeInspection.ProblemsHolder
5+
import com.intellij.psi.PsiElement
6+
import dev.protsenko.securityLinter.core.HtmlProblemDescriptor
7+
import dev.protsenko.securityLinter.core.SecurityPluginBundle
8+
import dev.protsenko.securityLinter.docker.checker.WgetProgressBarValidator
9+
import dev.protsenko.securityLinter.docker.inspection.run.core.DockerfileRunAnalyzer
10+
11+
class WgetWithoutRecommendedFlagsAnalyzer : DockerfileRunAnalyzer {
12+
override fun handle(
13+
runCommand: String,
14+
psiElement: PsiElement,
15+
holder: ProblemsHolder,
16+
) {
17+
if (!WgetProgressBarValidator.isValid(runCommand)) {
18+
val descriptor =
19+
HtmlProblemDescriptor(
20+
psiElement,
21+
SecurityPluginBundle.message("dfs032.documentation"),
22+
SecurityPluginBundle.message("dfs032.problem-text"),
23+
ProblemHighlightType.WARNING,
24+
)
25+
26+
holder.registerProblem(descriptor)
27+
}
28+
}
29+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
<dockerFileRunAnalyzer implementation="dev.protsenko.securityLinter.docker.inspection.run.impl.UserAddAnalyzer"/>
9999
<dockerFileRunAnalyzer implementation="dev.protsenko.securityLinter.docker.inspection.run.impl.ApkNoCacheValidatorAnalyzer"/>
100100
<dockerFileRunAnalyzer implementation="dev.protsenko.securityLinter.docker.inspection.run.impl.PipNoCacheDirAnalyzer"/>
101+
<dockerFileRunAnalyzer implementation="dev.protsenko.securityLinter.docker.inspection.run.impl.WgetWithoutRecommendedFlagsAnalyzer"/>
101102

102103
<dockerFileExposeAnalyzer implementation="dev.protsenko.securityLinter.docker.inspection.expose.impl.SshPortExposedAnalyzer"/>
103104
<dockerFileExposeAnalyzer implementation="dev.protsenko.securityLinter.docker.inspection.expose.impl.ExposedPortOutOfRangeAnalyzer"/>
@@ -116,4 +117,4 @@
116117
interface="dev.protsenko.securityLinter.docker.inspection.copyAndAdd.core.DockerfileCopyOrAddAnalyzer"/>
117118
</extensionPoints>
118119

119-
</idea-plugin>
120+
</idea-plugin>

src/main/resources/messages/SecurityPluginBundle.properties

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ dfs030.problem-text=Alpine package installation without --no-cache, consider usi
115115
### dfs031
116116
dfs031.documentation=using-pip-install-without-no-cache-dir
117117
dfs031.problem-text=The pip package installations without --no-cache-dir, consider using it to reduce image size.
118+
### dfs032
119+
dfs032.documentation=avoid-wget-without-progress-or-quiet
120+
dfs032.problem-text=Avoid using wget without a progress/quiet option. Use --progress=dot:giga or consider -q/-nv (--quiet/--no-verbose).
118121

119122
### dcs001 [only docker-compose]
120123
ds033.using-privileged=Using privileged: true grants full root access to the host, bypassing isolation mechanisms.
@@ -178,4 +181,4 @@ kube012.problem-text=This volume type may expose the node or bypass pod isolatio
178181
# Not implemented
179182
ds029.missing-healthcheck=Missing HEALTHCHECK instruction
180183
ds023.multiple-exposed-port=Port {0} exposed more than one time.
181-
ds024.wrong-port-definition=Port {0} is incorrect.
184+
ds024.wrong-port-definition=Port {0} is incorrect.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dev.protsenko.securityLinter.docker
2+
3+
import com.intellij.codeInspection.LocalInspectionTool
4+
import dev.protsenko.securityLinter.core.DockerHighlightingBaseTest
5+
import dev.protsenko.securityLinter.docker.inspection.run.DockerfileRunInspection
6+
7+
class DS036WgetWithoutProgressOrQuietInspectionTest(
8+
override val ruleFolderName: String = "DS036",
9+
override val customFiles: Set<String> = emptySet<String>(),
10+
override val targetInspection: LocalInspectionTool = DockerfileRunInspection()
11+
) : DockerHighlightingBaseTest()

src/test/testData/docker/DS013/Dockerfile.denied

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM debian:stable-20210621
22
<warning descr="RUN using 'wget' and 'curl'
3-
Avoid using both 'wget' and 'curl' since these tools have the same effect.">RUN wget http://bing.com</warning>
3+
Avoid using both 'wget' and 'curl' since these tools have the same effect.">RUN wget -q http://bing.com</warning>
44

55
FROM baseimage:1.0
66
USER mike
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM ubuntu:24.04
2+
RUN wget --progress=dot:giga https://example.com/archive.tar.gz && \
3+
wget --quiet https://example.com/archive2.tar.gz && \
4+
wget --no-verbose https://example.com/archive3.tar.gz && \
5+
wget -qO /tmp/archive4.tar.gz https://example.com/archive4.tar.gz && \
6+
wget -nv https://example.com/archive5.tar.gz

0 commit comments

Comments
 (0)