Secure Quarkus Java Applications with GitHub Actions & Apps
Leveraging GitHub’s Developer Tools for Automated Vulnerability Scanning in Enterprise Java Projects
As an Enterprise Java developer you might have looked at Quarkus for your cloud-native applications. But GitHub Actions and GitHub Apps have emerged as powerful developer tools to automate CI/CD and integrate security into the development workflow. In this article, I’ll walk you through what GitHub Actions and Apps are, and show you how to use them to build secure applications – with a focus on vulnerability scanning for a Quarkus-based Java project. The goal is to show how you can catch security issues early and often, enhancing your team’s confidence in the code you deploy. Let’s start!
What Are GitHub Actions and GitHub Apps? (And Why Java Devs Should Care)
GitHub Actions are essentially GitHub’s built-in automation and CI/CD service. Think of Actions as a replacement for Jenkins or other CI servers, fully integrated into your GitHub repository. This tight integration means developers can define workflow pipelines (as YAML files in the repo) that run on GitHub’s infrastructure on events like pushes or pull requests. The big benefit is that your CI feedback (builds, tests, scans, etc.) appears right alongside your code and pull requests, making it easy to manage everything in one place (The Rise of Quarkus and GitHub Actions | Juliano Mohr). In enterprise Java projects, this means you can automate build and test of your Quarkus applications on every commit, enforce quality gates, and run security checks before merging code. GitHub Actions also provide built-in secret management to handle credentials safely (for example, API keys for third-party services) (Deciding when to build a GitHub App - GitHub Enterprise Cloud Docs) – critical for automating deployment and security tasks without exposing sensitive info. In short, Actions let you shift left on CI/CD and security, bringing these processes into your development flow seamlessly.
GitHub Apps, on the other hand, are a way to extend and integrate with GitHub’s platform. A GitHub App is an application that uses GitHub’s APIs and webhooks to perform actions, often running on a separate server or cloud service. Unlike Actions (which run ephemeral tasks in response to repo events), GitHub Apps run persistently and can react to events across multiple repositories or organizations. GitHub Apps operate with fine-grained permissions and independent identities, making them a really good fit for enterprise use. Instead of broad access tokens, a GitHub App can be granted minimal read/write permissions only to specific resources it needs. For example, an enterprise might use a GitHub App to monitor many repos for policy compliance or to open issues when certain vulnerabilities are found, all without tying the function to a specific user account. GitHub Apps though offer a secure, scalable way to integrate custom tools or services (security scanners, CI bots, etc.) into your workflow. In our context of securing a Java project, you’ll see that some security tools (like dependency scanners) are available as GitHub Apps, and you could even build a custom app to enforce organization-specific security checks.
In summary: Use GitHub Actions for repository-scoped automation (build, test, deploy, scan on each commit/PR), and use GitHub Apps for broader integrations or long-running services that need to interact with GitHub with fine-grained access. Now, let’s look at how these tools help improve security in an enterprise Java project.
Automating Security Checks with GitHub’s CI/CD (Shift-Left Security)
Security is a major concern in enterprise development. The good news is GitHub Actions and Apps can significantly improve your security posture by automating vulnerability scanning and other checks. This aligns with the “shift-left” DevSecOps approach – catching issues as early as possible in the development lifecycle.
Vulnerability scanning typically involves two aspects: scanning your code for security bugs (e.g., SQL injection, misuse of APIs) and scanning your dependencies for known vulnerabilities (outdated libraries with CVEs). We’ll tackle both using GitHub’s tools.
Code Scanning with CodeQL – GitHub’s code scanning feature (powered by CodeQL) analyzes your source code for common vulnerabilities and errors. Using a GitHub Actions workflow, CodeQL can automatically scan a Java (or Kotlin) codebase and report issues. What’s powerful is that any security alerts found can surface directly in your pull requests as comments or “checks.” For example, if a new commit introduces a SQL injection flaw in a Quarkus REST endpoint, the CodeQL Action will flag it and GitHub will annotate the PR with a warning before the code is merged. The Quarkus team’s own CI pipeline includes such a code scanning action, which demonstrates how PR-level feedback is given for security issues – a brilliant application of shift-left security. In practice, this means your team can catch and discuss vulnerabilities during code review rather than after the fact.
Dependency Scanning – Besides your own code, it’s important to monitor third-party libraries (e.g. Maven dependencies) for known vulnerabilities. Enterprise Java apps often rely on dozens of open-source libraries, and new CVEs are disclosed frequently. GitHub offers Dependabot (a built-in GitHub App) that continuously checks your dependency graph against GitHub’s Advisory Database. If a known vulnerable library is detected (say an older version of a logging framework with a CVE), GitHub will raise a Dependabot alert on your repository’s Security tab, and even create an automatic pull request to update the dependency to a safe version. This is mostly configuration-free – by enabling Dependabot alerts, you get daily checks and PRs for security updates. Additionally, you can integrate a Maven plugin like OWASP Dependency Check into your build process for immediate feedback. The Quarkus team recommends using the OWASP Dependency Check Maven plugin to detect vulnerabilities at build time using the NVD (National Vulnerability Database) feed (Security vulnerability detection and reporting in Quarkus - Quarkus). This plugin can fail your build if a high-severity CVE is present in your dependencies, preventing a vulnerable artifact from being packaged.
By combining code scanning and dependency scanning, you cover both code flaws and library risks. Next, let’s walk through a real example of setting up these security checks on a Quarkus project using GitHub Actions.
Example: Securing a Quarkus Application with GitHub Actions
To make this concrete, imagine we have a simple Quarkus REST API project. We want to automatically scan this application for vulnerabilities whenever code changes occur. We’ll use GitHub Actions for automation and leverage both CodeQL (for code scanning) and the OWASP dependency check plugin. Below, we’ll outline the steps and provide configuration snippets so you can replicate the setup.
Step 1: Set Up a Quarkus Project – If you don’t have a Quarkus app already, you can quickly bootstrap one. For example, using the Quarkus Maven plugin:
mvn io.quarkus.platform:quarkus-maven-plugin:<version>:create \
-DprojectGroupId=com.example \
-DprojectArtifactId=my-secure-quarkus-app \
-Dextensions='resteasy-reactive'
This will generate a Quarkus project with a RESTEasy Reactive extension (for JAX-RS). In the generated code (or your existing app), ensure there’s at least one endpoint to scan. Here’s a basic resource class from Quarkus’s getting-started guide (Creating Your First Application - Quarkus):
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Hello from Quarkus REST";
}
}
This is a simple endpoint that our pipeline will build and scan. (In a real app, you’d have more complex logic — and possibly some security weaknesses to catch!) The code above should compile and run in Quarkus; it’s just standard JAX-RS annotations on a POJO.
Step 2: Add CodeQL Code Scanning Workflow – Next, we set up GitHub Actions to run CodeQL analysis on our repository. Create a file .github/workflows/codeql-analysis.yml
in your repo with the following content:
name: "CodeQL Security Scan"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 3 * * 0' # weekly scan on Sunday at 3AM
permissions:
contents: read
security-events: write # allow uploading results to code scanning
jobs:
analyze:
name: Analyze Code
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ['java'] # analyze Java code
- name: Build project
run: mvn install -DskipTests
- name: Analyze with CodeQL
uses: github/codeql-action/analyze@v3
Let’s break down what this workflow does. It triggers on pull requests and pushes to the main
branch, as well as on a weekly schedule (so even dormant code gets scanned periodically). The workflow sets minimal permissions for the GitHub token, following the principle of least privilege – we only grant security-events: write
so that the action can upload scan results to GitHub Security tab. In the job steps, we check out the code, set up Java (using JDK 17, which is the minimum Java version that Quarkus requires), then initialize the CodeQL analysis. The init
step configures the languages to scan (just Java in our case). We then build the project using Maven – this is important because CodeQL needs to compile the code to understand it. We skip tests for speed, but ensure all production code is compiled (you could run tests too if you want). Finally, the analyze
step runs the CodeQL analysis and uploads results.
When this workflow runs, GitHub will list a "CodeQL" check on your pull request. If any high-severity issues are found in the changed code, the check will fail (you can customize the severity levels that cause failure). Even if it doesn’t fail the check, any new security alerts will be shown as comments on the PR diff – for instance, pointing out a risky use of an API, along with details on the vulnerability. You can click through to the Security tab to see all detected alerts across the branch. This tight integration means your team can treat security findings just like code review comments, addressing them as part of the normal PR process. (In an enterprise setting, you might even make the CodeQL check a required status check to prevent merging code with critical vulnerabilities unless explicitly overridden.)
Step 3: Integrate Dependency Vulnerability Checks – CodeQL focuses on code logic, but what about known vulnerable libraries? As mentioned, GitHub Dependabot is one way to passively monitor and update dependencies. Additionally, we can fail the build if a severe vulnerability is present. We’ll use the OWASP Dependency Check Maven plugin for this. Add the plugin to your Maven pom.xml
(under the <plugins>
section), for example:
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.3.1</version> <!-- use the latest version available -->
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
<configuration>
<failBuildOnCVSS>7</failBuildOnCVSS>
</configuration>
</plugin>
This configuration instructs the plugin to run during the Maven build and to fail the build if any dependency with a CVSS score ≥ 7 (high severity) is found. You can tune the failBuildOnCVSS
threshold or add suppression files to ignore false positives, but the default is a good start (Security vulnerability detection and reporting in Quarkus - Quarkus). With this in place, our earlier CodeQL workflow will also perform a dependency scan as part of the mvn install
. If a high-severity vulnerable library is present, the Maven build will exit with an error, causing the GitHub Actions job to fail. The GitHub Actions log will show which dependency triggered the failure and which CVE was detected, giving developers immediate insight.
Alternatively, instead of embedding this in the build, you could run the dependency check as a separate step or job in the workflow (e.g., using the official Dependency-Check Action or CLI). But using the Maven plugin is convenient for Java projects since it runs wherever you build the project (locally or CI). The Quarkus documentation itself highlights this plugin as a best practice for build-time vulnerability detection.
Step 4: Review and Respond to Alerts – With both CodeQL and dependency checks in place, every pull request to your Quarkus app will undergo a gauntlet of security checks automatically. As a developer, you might see a “Code scanning results” check on your PR turn red, indicating a new alert. By clicking “Details” or viewing the PR Conversation, you can see exactly what the issue is (for example, “SQL Injection risk: unsanitized input used in SQL query on line 42”). Similarly, if a dependency is flagged, the Maven build log (accessible via the Actions tab for that workflow run) will list the library and vulnerability identifier. The development team can then fix the issue – maybe by using a Quarkus API in a safer way, or upgrading a dependency. Thanks to the automation, these problems are caught before the code is merged or shipped. And remember, if you’ve enabled Dependabot alerts, you’ll also get notifications (and even PRs) whenever new vulnerabilities in your dependencies are discovered in the future – keeping your project secure over time without manual effort.
Going Further: Continuous Security with GitHub Apps and Integrations
The example above shows how GitHub Actions can be used to enforce security in an enterprise Java project’s CI/CD pipeline. But you can extend this approach even more with GitHub Apps and other integrations:
Dependabot App for Updates – We discussed Dependabot alerts; you can also enable Dependabot security updates via a GitHub App that automatically opens pull requests to bump dependency versions. This App runs with only read access to your code and write access to dependency files, following the fine-grained permission model. It’s a great built-in tool to keep your libraries up-to-date and fix known vulnerabilities proactively.
Code Analysis Apps – GitHub’s own code scanning is one option, but there are third-party GitHub Apps (and accompanying Actions) like SonarQube, Snyk, and Checkmarx that can be integrated for additional scanning. For instance, Snyk offers a GitHub App that monitors your repo for vulnerable dependencies and can comment on PRs or issues when problems are found. These Apps often complement GitHub Actions by performing periodic scans or providing detailed dashboards of vulnerabilities. Because they run externally (often as a service) but hook into GitHub via webhooks, they exemplify how GitHub Apps can act on events (like a new push) in a broader context – sometimes running longer or more complex scans than would be ideal in a CI job.
Custom GitHub Apps – Larger organizations might build their own GitHub App to enforce security policies. For example, a custom app could listen for pull request events and ensure certain compliance checks have passed (maybe interacting with an internal security system), then add a PR comment or block merging if not compliant. With the GitHub App approach, such an app could be given access only to metadata (statuses, checks, etc.) and not the code itself, if it doesn’t need it, thereby adhering to internal security requirements. GitHub Apps can act on behalf of the organization rather than an individual user, and they remain operational even if specific people leave the team (Deciding when to build a GitHub App - GitHub Enterprise Cloud Docs). This makes them robust for long-term automation like security governance across many projects.
In summary, GitHub’s ecosystem provides a large set of tools to continuously improve your software’s security. Actions are fantastic for in-repo, on-the-fly checks and enforcement, while Apps allow for persistent, wide-reaching integrations and monitoring.
Final Thoughts
Modern enterprise Java development is not just about writing code – it’s about delivering secure, reliable applications. GitHub Actions and GitHub Apps empower developers to embed security into their workflow in practical ways. I showed you how a Quarkus Java application can be augmented with automated vulnerability scans: using GitHub Actions to run CodeQL static analysis and dependency vulnerability checks on each commit. This approach catches issues early (in pull requests) and provides developers with actionable feedback, all integrated into the familiar GitHub interface. By leveraging these developer tools, enterprise teams can save time, reduce the burden of manual security reviews, and significantly lower the risk of deploying vulnerable code.
As you implement these practices, start small – maybe enable code scanning on one critical service or set up Dependabot on a few repositories – and then expand. The payoff is a tighter feedback loop and greater confidence in the security of your Java applications. With Quarkus enabling fast and lightweight Java services, and GitHub providing the automation muscle, you have a potent combination to build secure applications from code to cloud. Happy secure coding!