Skip to content

Commit b16ced2

Browse files
authored
Merge pull request #25 from DataDog/chore/codeql-arch-lints
chore(award-service): Try out CodeQL to enforce basic architecture constraints
2 parents deea6d3 + bddc2a8 commit b16ced2

23 files changed

Lines changed: 496 additions & 90 deletions

.github/workflows/sticker-award.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,30 @@ jobs:
4343
run: |
4444
cd sticker-award
4545
./mvnw verify -Dskip.unit.tests=true -DskipITs=false
46+
47+
- name: Install CodeQL CLI
48+
run: |
49+
# Download and install CodeQL CLI
50+
wget -q https://github.com/github/codeql-cli-binaries/releases/latest/download/codeql-linux64.zip
51+
unzip -q codeql-linux64.zip
52+
sudo mv codeql /opt/codeql
53+
echo "/opt/codeql" >> $GITHUB_PATH
54+
/opt/codeql/codeql version --format=text
55+
56+
- name: Create CodeQL Database
57+
run: |
58+
cd sticker-award
59+
codeql database create cql-db --language=java --source-root=.
60+
61+
- name: Install CodeQL Packs
62+
run: |
63+
cd sticker-award
64+
codeql pack install cql-queries/
65+
66+
- name: Validate Architecture Rules
67+
run: |
68+
cd sticker-award
69+
./scripts/validate-architecture.sh
4670
4771
push-image:
4872
runs-on: ubuntu-latest

sticker-award/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@ nb-configuration.xml
4343
/.quarkus/cli/plugins/
4444
# TLS Certificates
4545
.certs/
46+
cql-db
47+
build
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @name Sticker Repository Domain Boundary Violations
3+
* @description Finds violations where StickerRepository imports classes from the award domain
4+
* @kind problem
5+
* @problem.severity warning
6+
* @precision high
7+
* @id java/sticker-repository-domain-violation
8+
* @tags maintainability
9+
* architecture
10+
* domain-driven-design
11+
*/
12+
13+
import java
14+
15+
from CompilationUnit file, Import imp
16+
where
17+
// Match StickerRepository files by path
18+
file.getAbsolutePath().matches("%StickerRepository.java") and
19+
20+
// Find imports in these files
21+
imp.getCompilationUnit() = file and
22+
23+
// Check if import is specifically the problematic award domain types
24+
(
25+
imp.toString() = "import UserAssignmentDTO" or
26+
imp.toString() = "import StickerAssignment"
27+
)
28+
29+
select imp,
30+
"StickerRepository file '" + file.getBaseName() +
31+
"' should not import '" + imp.toString() +
32+
"' from the award domain. Use DTOs or events instead."
33+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @name REST API classes should not import entity types (simple)
3+
* @description Finds REST API classes that import database entity types
4+
* @kind problem
5+
* @problem.severity error
6+
* @precision high
7+
* @id java/rest-api-entity-import-simple
8+
*/
9+
10+
import java
11+
12+
from CompilationUnit file, Import imp
13+
where
14+
// Match REST API files by path (anything ending in Resource.java)
15+
file.getAbsolutePath().matches("%Resource.java") and
16+
17+
// Find imports in these files
18+
imp.getCompilationUnit() = file and
19+
20+
// Check if import text contains 'entity'
21+
imp.toString().matches("%entity%")
22+
23+
select imp,
24+
"REST API file '" + file.getBaseName() +
25+
"' should not import entity type '" + imp.toString() +
26+
"'. Use DTOs instead."
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @name REST API classes should not import entity types
3+
* @description Finds REST API classes that import database entity types
4+
* @kind problem
5+
* @problem.severity error
6+
* @precision high
7+
* @id java/rest-api-entity-import
8+
* @tags maintainability
9+
* architecture
10+
* separation-of-concerns
11+
*/
12+
13+
import java
14+
15+
from Class restClass, RefType entityType, Element reference
16+
where
17+
// Match REST API classes by fully qualified package name
18+
(
19+
restClass.getQualifiedName() = "com.datadoghq.stickerlandia.stickeraward.sticker.StickerResource" or
20+
restClass.getQualifiedName() = "com.datadoghq.stickerlandia.stickeraward.award.StickerAwardResource"
21+
) and
22+
23+
// Check if the class references entity types
24+
entityType.getQualifiedName().matches("%.entity.%") and
25+
26+
// Find references to entity types in fields, methods, or parameters
27+
(
28+
exists(Field f | f.getDeclaringType() = restClass and f.getType() = entityType and reference = f) or
29+
exists(Method m | m.getDeclaringType() = restClass and m.getReturnType() = entityType and reference = m) or
30+
exists(Parameter p | p.getCallable().getDeclaringType() = restClass and p.getType() = entityType and reference = p)
31+
)
32+
33+
select reference,
34+
"REST API class '" + restClass.getName() +
35+
"' should not reference entity type '" + entityType.getQualifiedName() +
36+
"'. Use DTOs instead."
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
lockVersion: 1.0.0
3+
dependencies:
4+
codeql/controlflow:
5+
version: 2.0.8
6+
codeql/dataflow:
7+
version: 2.0.8
8+
codeql/java-all:
9+
version: 7.3.0
10+
codeql/mad:
11+
version: 1.0.24
12+
codeql/quantum:
13+
version: 0.0.2
14+
codeql/rangeanalysis:
15+
version: 1.0.24
16+
codeql/regex:
17+
version: 1.0.24
18+
codeql/ssa:
19+
version: 2.0.0
20+
codeql/threat-models:
21+
version: 1.0.24
22+
codeql/tutorial:
23+
version: 1.0.24
24+
codeql/typeflow:
25+
version: 1.0.24
26+
codeql/typetracking:
27+
version: 2.0.8
28+
codeql/util:
29+
version: 2.0.11
30+
codeql/xml:
31+
version: 1.0.24
32+
compiled: false
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import java
2+
3+
from Class c
4+
where
5+
// Only include classes from the stickerlandia project
6+
c.getPackage().getName().matches("com.datadoghq.stickerlandia.%")
7+
select c.getName() as name,
8+
c.getDoc().getJavadoc() as doc,
9+
c.getNumberOfLinesOfCode() as loc
10+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import java
2+
3+
from CompilationUnit file, Import imp
4+
where
5+
imp.getCompilationUnit() = file and
6+
file.getAbsolutePath().matches("%stickerlandia%")
7+
select file.getBaseName(), imp.toString()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import java
2+
3+
from Class c, Method m
4+
where
5+
// Only include classes from the stickerlandia project
6+
c.getPackage().getName().matches("com.datadoghq.stickerlandia.%") and
7+
m.getDeclaringType() = c
8+
9+
select c.getName(), m.getName(), m.getDoc().getJavadoc()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import java
2+
3+
predicate isStickerDomain(Package p) {
4+
p.getName().matches("%.sticker") or p.getName().matches("%.sticker.%")
5+
}
6+
7+
predicate isAwardDomain(Package p) {
8+
p.getName().matches("%.award") or p.getName().matches("%.award.%")
9+
}
10+
11+
from Class c, Package p
12+
where c.getName().matches("%Repository%") and p = c.getPackage()
13+
select c.getName(), p.getName()

0 commit comments

Comments
 (0)