Secure your Rust builds with AppArmor
If you have a Linux system with AppArmor, you can use it to secure your Rust builds.
First install Rust with rustup in ~/.cargo/bin.
Then add this file to /etc/apparmor.d, replace ${HOME} with your home directory.
#include <tunables/global>
profile cargo-bin ${HOME}/{.cargo/bin/*,.local/share/JetBrains/IntelliJIdea*/intellij-rust/bin/linux/x64/*} {
#include <abstractions/base>
#include <abstractions/consoles>
@{PROC}** r,
/sys/** r,
/usr/bin/** ix,
/usr/include/** r,
/usr/libexec/** rix,
/usr/share/** r,
/tmp/ r,
/tmp/** rwkix,
owner @{HOME}/.gitconfig r,
owner @{HOME}/.gitignore r,
owner @{HOME}/.rustup/** r,
owner @{HOME}/.rustup/toolchains/** rix,
owner @{HOME}/.cargo/ r,
owner @{HOME}/.cargo/** rwkl,
owner @{HOME}/.cargo/bin/** rwklix,
owner @{HOME}/.local/share/JetBrains/IntelliJIdea*/intellij-rust/** r,
owner @{HOME}/.local/share/JetBrains/IntelliJIdea*/intellij-rust/bin/linux/x64/* rix,
owner @{HOME}/.cache/JetBrains/IntelliJIdea*/intellij-rust/** rwk,
owner @{HOME}/src/** rwklix,
/etc/resolv.conf r,
@{PROC}/sys/net/** r,
network,
/run/systemd/resolve/** r,
signal (receive) set=(int,term,kill),
}
profile rustup ${HOME}/.cargo/bin/rustup {
#include <abstractions/base>
#include <abstractions/consoles>
/etc/** r,
@{PROC}** r,
/sys/** r,
/usr/bin/** ix,
/usr/include/** r,
/usr/libexec/** rix,
/usr/share/** r,
/tmp/ r,
/tmp/** rwkix,
owner @{HOME}/.gitconfig r,
owner @{HOME}/.gitignore r,
owner @{HOME}/.rustup/** rwkl,
owner @{HOME}/.rustup/toolchains/** rwklix,
owner @{HOME}/.cargo/ r,
owner @{HOME}/.cargo/** rwkl,
owner @{HOME}/.cargo/bin/** rwklix,
owner @{HOME}/.local/share/JetBrains/IntelliJIdea*/intellij-rust/** r,
owner @{HOME}/.local/share/JetBrains/IntelliJIdea*/intellij-rust/bin/linux/x64/* rix,
owner @{HOME}/.cache/JetBrains/IntelliJIdea*/intellij-rust/** rwk,
owner @{HOME}/src/** rwklix,
/etc/resolv.conf r,
@{PROC}/sys/net/** r,
network,
/run/systemd/resolve/** r,
signal (receive) set=(int,term,kill),
}
Then run sudo service apparmor reload to activate it (it will be loaded automatically on boot). This is tested un Ubuntu desktop 24.04.
It will also enable use of the Rust plugin to IntelliJ IDEA.
Secure your Gradle builds with AppArmor
If you have a Linux system with AppArmor, you can use it to secure your Gradle builds.
Here is how I installed it on Ubuntu Linux:
-
Make sure you have a Java Development Kit installed.
-
Set the
JAVA_HOMEenvironment variable to point to your JDK by creating a file/etc/profile.d/java.shwith this content:#!/bin/sh export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 -
Make a manual installation of Gradle in
/opt/gradle. -
Make it available in PATH:
$ cd /usr/bin $ sudo ln -s ../../opt/gradle/gradle-8.14.3/bin/gradle .
Speed-up and secure your Maven builds with Maven Daemon
You can speed-up Maven builds considerably by using Maven Daemon.
Here is how I installed it on Ubuntu Linux:
-
Make sure you have a Java Development Kit installed.
-
Set the
JAVA_HOMEenvironment variable to point to your JDK by creating a file/etc/profile.d/java.shwith this content:#!/bin/sh export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 -
Unpack it into
/opt -
Make it available in PATH:
$ cd /usr/bin $ sudo ln -s ../../opt/maven-mvnd-1.0.2-linux-amd64/bin/mvnd . $ sudo ln -s mvnd mvn
You can configure IntelliJ IDEA to use it by setting Maven home path to /opt/maven-mvnd-1.0.2-linux-amd64.
You need to do this for all existing Maven projects you have. Also make sure that the
registry setting maven.use.scripts is true.
SQLite backup
As I mentioned earlier, it’s straightforward to use SQLite as the relational database in Go applications. Your data is stored in one single file with a well-defined format and there is no hassle with installing and configuring a separate database.
However, for any serious application you most likely want backup of your data. If your dataset is not very large, and it
is OK to lose updates since the last backup, there is a very simple option. Use the sqlite3 command line tool:
Simple web app with Go
I have been learning the Go programming language lately, and it’s remarkably easy to build simple web apps with it. In particular, with just a few simple tricks, you can make the deployment of such web apps super simple: just one single standalone statically linked binary which stores its data in one single file.
The Go standard library contains everything needed to build a basic web app:
- A production-ready HTTP server
- An URL router
- Interface for SQL databases
- Parsing command line options
- Simple logging
- HTML templating
- HTTP client
If you use the embed feature, you can embed templates and static resources (CSS, JavaScript, images) and produce one single self-contained binary.
Simple HTML DSL for Kotlin
As I wrote a while ago, I have been trying different approaches for server-side HTML generation in Kotlin, with focus on good support for generating partials without a single root element (which is important for htmx).
Given Kotlin’s good support for internal DSLs, I decided to explore that route, and try kotlinx.html and HtmlFlow. They both make great promises of encoding the entire HTML standard and enforce valid HTML at compile time. This sounds very nice in theory, but in practice they are quite a disappointment.
Server-side HTML generation
I have been trying out htmx with Kotlin and http4k.
To use htmx, you need some way of generating HTML on the server. In Kotlin, you have plenty of options, both Kotlin specific ones and everything from the broader Java/JVM ecosystem. There are two main categories here, template languages and internal DSLs.
Given Kotlin’s good support for internal DSLs, I decided to explore that route, and try kotlinx.html and HtmlFlow. They both make great promises of encoding the entire HTML standard and enforce valid HTML at compile time. This sounds very nice in theory, but in practice they are quite a disappointment.
No streaming with pgJDBC
I am using PostgreSQL from a Kotlin (JVM) application with the pgJDBC driver.
According to the documentation, you
can get results from a query based on a cursor
to avoid loading the whole result set into the application’s memory at once by calling the setFetchSize() method with
a positive value on the Statement before issuing the query.
I had a non-trivial query which generated a lot of rows (several thousands), and I only needed the first hundred or so. So I hoped I could activate the cursor, iterate through the result set until I had got all the data I needed and then close it long before reaching the end.
Linux in Linux with KVM
You can do quite a lot with Docker, but sometimes you want greater capabilities or increased security, then a proper virtual machine with KVM is a good alternative. An example is when you want to run Docker containers in the VM, it’s not easy to nest Docker without forgoing all security.
Just like Alpine Linux is suitable as a base for Docker images, it is also a good option as a guest in a virtual machine.
Leafpad with access to system files
As I have explained earlier, I am using Leafpad instead of gedit in my Ubuntu system.
However, recent versions of Ubuntu does not have Leafpad available through APT any longer, you have to install it with
Snap instead. This is quite annoying, since the Snap packaging of Leafpad is too restrictive, it cannot access hidden
files in your home directory, nor anything in ~/bin/. This is not good, since I often want to use Leafpad to edit
such files.