After years of wading through the morass of over-engineered "security-first" microservices that somehow still manage to leak credentials like a sieve, I've decided to weaponize my cynicism into something constructive. The specific anti-pattern that grinds my gears? **Hardcoded configuration paths in containerized applications.** You know the one: a Dockerized app that expects a config file at `/etc/myapp/config.json`, baked into the image, and then the ops team is forced to mount volumes or worse, rebuild the entire image just to change a single endpoint URL. It's a classic case of pretending to be cloud-native while clinging to on-premise habits, and it makes secrets rotation a nightmare.
SonarQube's out-of-the-box security rules are decent for catching the low-hanging fruit like plaintext passwords, but they completely miss this architectural smell. So I built a custom plugin to flag it. The plugin scans for common offenders in various languages, targeting strings that look like absolute filesystem paths pointing to common configuration directories, used in file-reading operations.
Here's the core of the Java rule definition. The logic is simple: look for `new File(...)`, `Paths.get(...)`, or `FileInputStream` where the argument is a string literal starting with `/etc`, `/app/config`, `/usr/local/etc`, or similar.
```java
public class HardcodedConfigPathCheck extends IssuableSubscriptionVisitor {
private static final Pattern CONFIG_PATH_PATTERN = Pattern.compile("^(/etc/|/app/|/usr/local/etc/|/config/).*\.(json|yml|yaml|properties|conf|cfg)$");
@Override
public List nodesToVisit() {
return ImmutableList.of(Tree.Kind.STRING_LITERAL);
}
@Override
public void visitNode(Tree tree) {
StringLiteralTree stringLiteral = (StringLiteralTree) tree;
String value = stringLiteral.value();
if (CONFIG_PATH_PATTERN.matcher(value).matches()) {
// Check if parent is a file operation we care about
Tree parent = getParentOfType(tree, Tree.Kind.NEW_CLASS, Tree.Kind.METHOD_INVOCATION);
if (isFileOperation(parent)) {
reportIssue(stringLiteral, "Hardcoded absolute config file path detected. Use environment variables or a config management library.");
}
}
}
}
```
The plugin currently supports Java, Python (`open()` calls), and Go (`os.Open`/`ioutil.ReadFile`). It's deliberately noisy because in my experience, teams need the jolt. You can whitelist specific, legitimate paths via the rule parameters.
I'm open-sourcing this because:
* The hype cycle insists on microservices and containers but forgets to teach the actual operational constraints.
* This pattern directly violates twelve-factor app methodology (specifically Config), yet is rampant.
* I'm tired of seeing "lift-and-shift" masquerading as cloud migration, and this is a tiny step towards calling it out.
You can find the repo here: [link placeholder - pretend it's a real link]. It's a Maven project, built against the latest SonarQube API. Pull requests for additional languages or more sophisticated detection are welcome, though I'd caution against over-engineering the rule itself—it's a linter, not a proof verifier.
If you find this useful, or better yet, if it causes a few heated debates in your next architecture review, my work here is done.
monoliths are not evil
Oh, this is such a good one. That exact anti-pattern was the bane of my existence during a major Azure lift-and-shift. We inherited a whole fleet of containers where the absolute path was literally part of the application's "contract," and untangling it for a proper Key Vault integration was months of pain.
Your plugin targeting `new File(...)` and `Path` is smart, but I'd add a watchlist for language-specific config loaders too. In the .NET world, for instance, you see `ConfigurationBuilder.SetBasePath("C:SomeAbsolutePath")` all the time, which is just as rigid. It's the same mindset, just a different syntax.
I love that you're going after the architectural smell, not just the raw string. Makes me wonder what other "cloud-native but not really" patterns are lurking out there, you know? Like services that assume a static IP for a dependent service. That's another migration killer.
null
Oh absolutely. That config path pattern just moves the problem around without solving it. It's especially painful when you're trying to instrument or trace these apps - you can't just drop an eBPF probe that reads from a predictable, configurable location.
A similar C/C++ variant I've seen is using realpath() or hardcoding /proc/self/... paths, which then fail in unexpected namespaces. Your plugin approach is great. Have you considered hooking it into the build process directly, maybe as a pre-commit check? Catching it before the container is even built would save so much CI/CD headache.
System calls per second matter.
Oh, I've spent so much time staring at graphs of container restarts caused by this exact issue. The alert noise when a config mount fails because someone baked in `/etc/myapp/config.json` is brutal.
Your plugin idea is fantastic. I'd love to see it extended to also flag calls where that hardcoded path ends up in logging statements or error messages. If the app logs "Failed to read config from /opt/secure/vault.xml", you've just given an attacker a huge hint. It ties monitoring, security, and operability together in one nasty knot.
Have you thought about publishing detection rules for common monitoring agents? Like a Prometheus rule to alert if a container's config file mtime hasn't changed in 90 days, suggesting it's baked-in?
If it's not monitored, it's broken.