JCON EUROPE

Lights, Camera, GitHub Actions! | Andres Almiray (EN)

44:51 · 20 Apr 2026 – 23 Apr 2026 · YouTube

About this talk

This talk covers the use of GitHub Actions for continuous integration and deployment, particularly for Java projects. The speaker, Andres Almiray, discusses how GitHub Actions can be leveraged to create workflows that automate the building, testing, and deployment processes. He introduces the concept of reusable workflows and matrices to simplify and manage complex CI configurations. The session also highlights best practices for developing custom actions and ensuring the security of workflows. Practical examples demonstrate how to set up jobs, utilize triggers, and manage dependencies effectively within GitHub Actions.

Full transcript

Let's see with the none. Yeah, that's how I can get your attention. Thank you for coming this early morning on the last day of J Con. Welcome. And so I started with with this word because I am currently living in Switzerland, but I definitely don't speak Swiss Deutsch. The topic of today is lights, camera, GitHub actions and also let's see how it goes. I hope I assume

that most of you already working with GitHub in some way or another and or maybe looking for alternatives. So obviously the name of the technology is because it runs on on GitHub whether you want to use it for a public repositories or for private repositories as well is pretty much the same. You may or may not have access to additional features. Well, basically the idea behind GitHub

actions is kind of like it's for some people think of it or refer to it as its own language for defining pipelines that run on CI jobs. Some of you may be familiar with Jenkins or other solutions that may have some of those or similar features. But now for those of you that may be considering other options for reasons, know that there is for Jiyo and Codeberg

that runs on for Jiyo. They also make use of GitHub actions. They are They say there is about 80 to 90% compatibility with all the actions that you find on the GitHub actions marketplace. There are for Jiyo specific actions as well, but the idea is that you can pretty much move from one to another whenever you need to. So know that you have options. You are not

just tied to just one single vendor. Now, the agenda that we're going to see today is this. I hope that I can make it as hands-on as possible. So, I'm going to jump into code very soon. Feel free to stop me at any time if you have any questions. Of course, we're going to have time afterwards for any questions that you may have. Does that sound okay?

Okay, good. Did you guys have coffee? Not enough. Okay. Good answer. Well, kind of. So, we're going to cover the the basics for those of you who haven't seen before. Then, we're going to jump into making our workflows do more stuff, maybe a little more complex, not necessarily more complicated. And that's kind of the things that I wanted to make sure that that we can distill the

behavior of our CI pipelines to the minimum and not try to make also with so many duplications. That's where the matrix feature can help us do some sort of refactoring. We can also move out common pieces of different workflows into what is known as reusable workflows. So, you can call them different locations at different times. this all these things are going to see are great, but we

it depends on that someone has already built a feature or an action for us to consume. But, what if we need a custom action, something that is unique to us? Or if we want to create our own actions? Well, there are a few options and I'm going to showcase one that is good for us Java developers. And finally, we're going to cover how we can ensure that

our actions are secure and that have no more redundancy and a few other best practices. All right. So, the code that I'm going to show lives currently in that repository. It is public. There is a QR code that can you can use to browse to this project. I'll try to keep this information updated as time goes by. It's it's completely open source. Feel free to just read

it, study it, modify it. It's it's it's for you. let's get into the code. Um, I'm going to show So, the repository is right there. Uh, it has a readme and a couple of two Java-based projects that I'm going to use as an example. And, uh, just to to know to tell you that typically you will set, uh, maybe just one project and you will use the

GitHub workflows that affect this the project directly from the root. You will notice that in some of the examples I change into a specific directory because I want to do work on one project or the other, but normally this is not what you would do. Okay. So, we'll start with the first one, the basics. And, uh, the first thing that we can see about a GitHub workflow

is that you can rename, uh, well, you you give it any name. Uh, it's up to you. It's free text. You can make it as long or as short as possible. Um, or needed. In this case, I just said, "This is build number one." We have the next item, the next block is triggers. This is where you tell GitHub how you want your particular workflow to be

run. I commented out this setting right here because that means that whenever someone makes a push to the main branch or makes a merge commit into the main branch, then this workflow will trigger. Because I want to run this manually using the UI, I set this to workflow dispatch. But, you can combine this and have multiple workflows. For example, if I wanted this build to be triggered

anytime I go into the UI, but also anytime that someone makes a commit to the, uh, to the main branch, and I can have a list of different items here. Then, that can happen. I can also say whenever someone sends a pull request, I want this build to happen. Or, whenever there's another event, for example, like a release was created or finalized. Uh, there are so many

other events that GitHub sends that that you can use as triggers. I would say that workflow dispatch and push, whether it's branches or tags, also, are one of the most common triggers that you will find. So, I'm going to go back to what it was before. Then the next thing is we're going to define the set of jobs. I'll start with just a single job. This will

be the name of the job. If you don't supply an additional name, that's fine, but I could also say something like custom name, built from J Kon 2026. So, whenever I run this particular workflow, build number one, and the step whose whose identifier is built, I will see in the UI also this name. So, you are not constrained to the tokens that you can find on YAML.

By the way, who loves writing YAML? Only two hands. Yeah, okay. Good. You can run different platforms or nodes. These are nodes known as runners. GitHub offers by default managed runners on Linux Intel, Windows Intel, Mac Intel, Linux ARM, and Mac OS ARM. They don't offer Windows ARM at the moment. If that is not enough for you, if you need additional privacy or you need to set

up additional software in the nodes, you have to have more control, that's possible. It's known as self-hosted runners. So, you will have to have a server or a node running on somewhere that you can point your workflow to be run on that particular server. And again, you have the distinction of using the five different OS architectures that I I you about. So, for now, I'm going to

run on whatever um um Linux defines as the latest versions of Linux. I think this is Ubuntu 24, maybe updated, uh but right now, I don't care too much how specific this is. Then, I'm going to set up a list of a steps. For every job, you can have a list steps. And here is where you can either consume pre-existing actions that they have uh they deliver

a certain behavior that you want, and that behavior can be customizable with different parameters, or you can run custom actions with it's like a scripts that you define ad hoc, whether that's in the workflow file, as it is in this case, or you call into a scripts, they whether it's bash or PowerShell or some other scripting language that lives in your current repository. So, the first thing

to see here is we can this thing is optional. You can give it a name or not, if you want to. I always like to do names. And because this is YAML, you can write as many words as you want, and you can even put it on quotes, if you want. So, what this action is going to do is check out your project. And I'm going to

use the default, so that's whenever What is the current head? The the hash that is current point pointing to the head of my repository, it's going to have it. It's going to have the the default credentials and the default permissions, all that. I'm just going with the with with the default settings. Then, I'm going to ensure that I have a particular version of Java to be able

to uh compile my project. So, I call into another action. Notice that we don't have to specify the HTTP URL to for a particular action. If you want to know where to find the actions, there's this thing called the GitHub Actions Marketplace. But if you happen to encounter uh a name like this, you can just copy this, go into github.com, and paste that, and that turns out

I do I don't have Oh, GitHub. That's why, typo. GitHub. So, this points out to a And this is the the place where you can find the code for that particular action, which I believe is implemented uh using uh TypeScript. Uh we can check that in this descriptor later. Okay, so we go back to this. So, that's how you know you can tell this one way or

another or using the marketplace. For this particular action, I do have some parameters that I want to uh pass in. I don't recall I think that the Java version is one of those required parameters. You have to tell it which version you want. Uh the default distribution is Temurin. I prefer to use a different distribution. That's why I have it there. And the last thing is I

also cache for the particular build tool that I want to use. The two that are currently supported is Maven and Gradle. Why you want to do this? Because what is one of the most things that people uh complain about Maven whenever you use it? Downloads a copy of the internet every single time, right? Because it has to populate your local Maven repository. Well, if you use this

cache setting, the next time you make a build, then the whatever you downloaded before in your local Maven repository is going to be reused again. So, be careful with this setting. If you're building a lot of snapshots, you will be publishing those snapshots to your Maven local repository on CI, and then your cache will grow and grow and grow until it just burst into it gets into

the limit. So, watch out for that. And the last thing is we have another step uh named build where we are running a custom uh script. By default, uh this is bash when we're running on uh on Linux. So, we're doing here is changing into that project directory. We're going to build our trivial Hello World application as a as a Java uh distribution, and then we invoke

Maven. How do you build a Maven project. No one said Maven clean style. Thank you. You use Maven verify. Well, in this case, I'm also using uh the wrapper. Whatever instructions you need to build your project, you can define those exactly as you see it there in a script, you can move these instructions into uh separate external script, and then refer that from within your project from

from the workflow. So, it's up to you. So, for now, this I think this is quite simple. There is not much uh complication here. We also not taking advantage of additional information that may be coming from your project. For example, uh secret information like tokens or environmental variables or information that may may be coming from other uh repositories under your control. Okay. So, the next one is

So so far, so good? All right? Okay. So, the next one I'm going to show how you can make a thing uh have uh more steps and more jobs. So, say for example that I would like uh the build step uh or my build workflow to only be invoked when my project is a snapshot. Or I want to post a release whenever I know that my project

is has a final version. Or if I'm using the Maven release project, then I need to know that my current state is a snapshot because the Maven release plugin, by default, will usually just move your version number from a snapshot to final, perform the release process that you have configured, and then move the the the the version that you made final into the next snapshot. So, you

have to have a particular state to begin with. So, you can do these kind of things, validate certain conditions, and then define if the following job or the following set of steps should be run or not. So, I have the same thing uh workflow In this case, I have a job that I gave it the name precheck and I'm going to run on Linux. And notice that

I'm also doing something here extra. I'm I'm going to compute some values during this job and I'm going to expose those to other jobs. So, I need to tell to to define to the outside world within my workflow what are the possible outputs that I'm going to to provide. So, in this case, the name of my output is version. I will see where we're going to use

this. And notice this expression. This is part of the what is known kind of as the GitHub Actions language. This expression tells me uh that we have a let's say this kind of like a container of things. Let's call it like that. And this is an identi vars is an ID. Whoop, that I should not do that. This is an ID. This the set of outputs that

that belong to that particular step. We'll see who has this particular ID. And this is a value that is coming from a special location that is called the GitHub output. So, as we saw before, we're going to check out the project. We set up Java with whatever particular parameters that you want to use. And then we're going to run a another step. This is the one that

has an ID vars, which matches what we saw here earlier. And we're going to run it on bash. Then we change into that directory, we invoke Maven to grab the version of the project. And then the last line is important one. We create a shell variable with this value, which is what we read from the Maven pom.xml and then we pass it to the GitHub output. This

is how we can pass this value here into this location. And then whoever reads this version will have access to what we have what we read from the palm file. So who is going to be that one? Let's look into the build step, which is similar to what we had before. Now we have What do we have here? We have an additional block, which is needs. This

is a list of uh steps or it's a list of jobs that you can depend on. We only have one previous job, which is precheck, and so that's the only thing that we're going to list here, but you could have more. The next thing we do is here's another expression that says if the version number that is exposed by my previous job, happens to end in a

snapshot, that means I am in an snapshot version of my then the steps are going to be executed. But if your project has already pushed a tag and a commit into a final version, then this whole workflow will be well, at least the precheck job will be run, but the build steps will be a skipped. That is what we want. So the only the reason why I

have done this is so that we can check what is my current state of the project, and if I really need to do a full build or not, cuz your builds will definitely maybe more will have more steps, and you will not like to spend time or waste resources by building something that is not needed given the state of the project. So far so good? Any questions?

Okay. So these are the building blocks, and now we can see that steps can consume information from the outside world, and they also can create outputs that can be read by other jobs. You can define IDs. We can use shell variables, and but the last thing that I haven't shown yet is how we can use environmental variables that you can define in your GitHub repository, or additional

settings that should be private in case of GitHub actions we we call this secrets such as a token to connect or deploy to Amazon S3 or some other kind of secrets or maybe it's a GPC GPG signature or something like Okay, so far we have been running on Ubuntu. But what if you needed to also run on Windows? Say that you have a Java that one perhaps

one of the most common problems that we find is dealing with paths on Windows, isn't it? So we need to test our project on Windows as well. How do we do that? Well, we have to pass additional settings here on the runs on. But we could define perhaps a series of jobs one just for Linux another for Windows and another for Mac blah blah blah. But the

advantage of of OX of GitHub actions is that you can define that in just one single setting. So we start again with this workflow as perhaps into the repository and show you how you can run this manually. So I got here into the tab called actions. And then I'll see the list of all my different workflows that I have defined on my project. So there's a bunch

of here. Some of them have been disabled. So I go here and build number one. I run this a couple of days ago and because it's a workflow dispatch, I have a access to this button right here called run workflow. And I can run it by default on the main branch. If I had other branches, then I could select this here, but it doesn't tell me that

because I don't have any more. Also, I could run it on a particular tag. That's fine. A particular caveat is that in order to run a workflow for the first time, it has to be available on the default branch or the main branch. Once you have it there, then you can select it to run it on a different branch. So, you cannot start a new pull request

with a new workflow and expect that new workflow to be run for the first time. You have to merge it on the default, and then the next iteration of this invocation, you can select it to run it on a whatever branch you want to. Because I have no additional inputs, I can just click this green button, run and this will create um a new run. When we

click here, so if we were to have multiple steps, you will see here a graph of different boxes and one box per And uh the build job here it says, "I'm going to set up the job that is check uh create the runner based on a particular image of Ubuntu." Then this is the part when it check out your project because this is one of the first

things that this is our first Then set up Java with a particular settings that we have. Perfect. Then runs the project, in this case just this Maven verify using the wrapper, the project is fine, and then GitHub actions at least one some actions will have like a post um set of steps. In this case, a set up Java. This is where it caches your local Maven repository.

Uh check out, cleans up uh the credentials and a few other things, and then we're just done. So, when we go back here, we have an invocation of the um of uh of this particular workflow. We don't have any output here, so if we were to put uh put to push artifacts or there would be any warnings coming from the invocations of the actions, they would be

visible here at the bottom of the screen. Um we don't have here anything here. Um uh so, the only thing that you have access is to the log, which by the default I believe will only be accessible for 90 days. Uh you can control this on the settings, whether you want to longer period or shorter period. The same thing for the artifacts that you may produce. You

may want to expire them as soon as possible to reduce the amount of storage that you have in the free plan. It's There are many things that you can configure here. So, because I'm going with the defaults, this is what we have at the moment. If I were to run build number two, this is the one that remember has two jobs, precheck and build. This one also

does not have any inputs. So, I can go here and say run the workflow. And you see the first job here is precheck. This is the one that check that I'm Do I have a snapshot version of my project, which happens to be the case. We can see that here. Check out, set up Java, and eventually it's going to invoke the version number running that from And

then when I go back here, click this here. Now you see that the second job started. If my project was not a snapshot, then you will see this in a different color and will see like a skip. And that will be the end of it. And again, there's no additional logs here. There are not I have anything any other output. That's why this thing remains so simple.

Okay. So, now we go into the matrix. We still have the same precheck step as we saw before. There's nothing new in this regard, the same idea. So, then what is different here is that in the build step, we have this feature called the matrix. And in the matrix, you can define as many parameters as you want. It's pretty much free text. For example, well, the first

thing I'm going to say is the strategy fail fast. That means that if any of the combinations that I'm going to build fails, I want to fail as soon as possible. I don't want to keep running on the others. The default, I believe, is Yeah, I think it's false. You can set it to true. In the matrix object, then you can this thing here OS is free

text. You can define any value that you wanted. In this case, I could have said something like runner maybe or or whatever operating system, whatever it's makes sense to you. And you can define as many as you want. So, this could be a a combination of different properties. And for all these different combinations, um may uh GitHub will create all the different permutations and run uh your

jobs. So, in this case, what I'm saying is I want four different runners to be selected. I put them in And then I use again the expression to say on which runner I want to uh this particular job to be run. So, in my case, this will result in four different runs. On each one of these runners, what I'm going to do? Check out the project, set

up Java, and then just build the project. So, this will ensure that I testing on Linux Intel, OS X Intel, Mac OS or OS X arm, and uh Windows Intel. So, when we click that here in build number three, same deal again, no inputs. we have this pre-check here. And notice that now this looks different as we saw before. It was just a single uh box. Once

this is done, um happens to be successful because we have a snapshot then this box would expand into all the permutations of our matrix, which would four runners. Um here we go. And we also have the names here. Why do we have these names? Because that's what we put here. The name of the um of the of the job. If you have not done that, then it

would be the default with weird identifier. So, now we can have the custom names here. And if you click you see how much time is being spent on each one of the builds. Now, this particular workflow guarantees I can run my project in four different operating systems with the same Java version. And as you saw, it's starting is quite trivial. It's quite simple. You can add more

steps here depending on what you want to do. If you recall that we use an if here for the job, if for whatever reason you need to do something that is specific to Windows, then you could do something like this, for example. If the and you add an expression here, if matrix OS happens to be equals to Windows latest, then this particular block is going to But,

when we're running on Linux or Mac OS, then this step is going to be a skip. So, if you need to do something on Windows, for example, if you're using I don't know, building with GraalVM or something that requires Windows-specific settings to tooling to be installed before building, then you can do things like this. Or if you're in in Mac OS and you need to install something

and you want to use Brew or MacPorts, then you can configure a step like that that will be a skip whenever the other conditions are not met. And because this is your own condition, you can define whatever you want. It could be an output coming from the step. It could be an environmental variable, a secret, anything that can be evaluated during the conditions. Okay? Let's turn into

the next one. This Who here uses GraalVM for generating native images? Okay, just a couple hands. Uh in case that you'll be interested to do that and you would like to do that on CI, here's how one possible way how you could do You see here I have four assemble steps, one for each of the targets that I want to run. And I have the same pre-check

as before. And what I want to do with this particular workflow is build native images for my project using the different platforms and then collect all of those artifacts and push them into a Git release page. You could push it to somewhere else or once you have built the artifacts, you you could collect them and use something else. In this case, I'm just create a GitHub release.

So, first thing first that we saw before, we make sure in this case there is another way to do this and now we can see that we are consuming the what is known as secrets. Uh this particular action will cancel any others of the same name or the same type that are running. I believe this this action I use it like two or three years ago and

then GitHub added an like a native option to cancel similar running projects or workflows, so you don't have to do this with a specific action. I'm I'm old-fashioned, so that's why I keep doing it. The whole reason why this thing is is so that I don't waste more resources when I'm executing the same thing. So, check out the project and do I have a sta- a snapshot

version or not? Same deal before. how do I run on Linux? We depend on pre-check. We check that there's a snapshot, so this is nothing new that we Check out the project. Set up GraalVM with additional setup Then uh this is additional step is specific for this project so that we can provision the different JDKs that can be used to build for uh native image. We change

into the other project which is called Hello World Java GraalVM. We build it with use uh this will create the the native the create the Java jars that we required. Then we use another project called JReleaser in this case that will create the assembly for the native actions and create a zip archive with everything that we need. in case that something went wrong, we capture the logs

the log output of the previous tool in this the crystal will be JReleaser. We want to have these two files, but it could be anything you want to. If you have you're running Maven on verbose mode and you put that into a log file and you want to keep it or is is maybe you're building a Docker image and you want to keep that log. This is

one way you can do it. These are files that exist in your repository and we're going to use another action called upload artifact. We give a custom name. We'll see where this name will be available in the UI. And but the most important thing is this one. We give it a condition. We want this to run every single time. That means that if this step is successful,

we will capture those files. But if this step fails, we also want to That's that's the the important reason why we want to do this because we want look into the failures and figure out how to solve this. In case that for whatever reason these files were may not be available for much longer. then we do the same thing for Intel. You notice there's a lot of

code duplication. We check out, we set up GraalVM, we provision the JDKs, we build, we create the archives, we store the log files, we update we upload the the archive that was created, and so on and so on and so on. So this workflow has a lot of duplication. It's quite big, but it performs almost the same features. And finally, we want to Notice that this job

has lots of dependencies. So he has to ensure that everything that we want to build is ready before we can actually invoke this particular step. And what we do later is check out the code, download all the artifacts that we built then we perform a Git release, and if there were anything that is going wrong, then we're going to capture the logs and we have a access

to that. So, this is going to take a while, perhaps 3 to 4 minutes because we're native image. So, let's go here and let's I'm going to show you this is Yeah, I know why. Notice that this is going to perform a if it's a snapshot. And I think that I didn't run this when the the version was properly set. So, we can we can run this

for a while. Sorry? showing you build forward. Yes, thank There we go. That makes more sense. So, I don't necessarily have to run it, but you here you see the output. So, here's the pre-check. Here are the four nodes. For each one of them, you can see that this one took 5 minutes to run. One particular thing that if you're running on the free tier of GitHub,

you have access to five OS X runner for your whole organization or for your whole set of projects. So, you'll be limited in this regard, regardless if they're Intel or arm. Whereas if it's Linux or if it's Windows, then you can have access to as many runners. So, if you are relying on OS X, note that your your workflows may be a bit slower because you have

to wait for a particular node to become available. So, these things are ready. Uh let's let's look at Linux. This one here. So, here's the uh checkout 0 graal VM. This provisions the JDKs that we're going to run. Uh this runs Maven to create the JAR file. Then, in the assembly step, this one will create a zip file with an executable that contains the uh the native

executable for Linux And here is where we capture the outputs in case that we need them. And then we upload all the artifacts. So, we if we go back to the summary of this action, you notice here we have this graal release a release. This is This contains the logs. But, unfunctionally, if we go back to the configuration here, well, this one does have the names the

different names. The graal release a release, this is the one that expired. This file here is this here. Because I set it to uh to expire very quickly, I can no longer see the logs, but I could click this, download the files, inspect the logs in case that something went wrong. And finally, when we go into release, uh we check out, we download all the artifacts, we

perform the release, and and then we capture it. So, I've actually I'm going to run the next one. Which I will show you this performs kind of the same thing, but removes the duplication. So, I'm going to run this in the background and then explain what's going on. number five, which is refactor. Same deal, the precheck, but in this case, I only have one single assemble. And

this particular assemble says the following thing, I'm going to depend on precheck for the reasons that I explained before, but I'm going to use a reusable workflow. And this is the secret sauce. So, everything that we saw before for the other nodes is going to put in just one single workflow and we can parameterize this. In this case, the only thing that we need to send as

a parameter will be the version number of my project. Where is this file? It's called X reusable native assemble, which is found right here. This one says, I have different inputs. The The version number of my project, which I don't know, has to be a required value. But the versions of GraalVM and the Java version for GraalVM have default settings. So, if I don't provide them, which

is what I did on the invocation, then I'm going to use these different settings. Now, I have also a matrix by default. And you can see that I'm making use of those inputs that are defined on the top of my workflow. And I can also pass in in the secrets for the GitHub token. This is always available. And the rest of the information that you find here

is pretty much the same. It's just that it's parameterized. That is the key difference. And finally, also the name of the artifact that I'm going to upload because otherwise, if they have the same name, then all the runners are going to override the blog that I want to save. So, with this case, I will have four different logs. And this may take a while. Notice that now

one of those actions complains that I'm running an older version of Node.js. This means that one of the actions I'm running is written with TypeScript. And that's kind of a nice segue into the next thing. So, as I said before, you can consume these actions that are ready made for the marketplace. You can build your own localized actions, if you will, by having reusable workflows that live

within your repository or any other repository. Be careful when you consume reusable workflows from a third party. Be really sure to read and understand what that workflow is doing. You don't want some attacker or a hacker to do something bad with your source code. Uh in that case, if you want to consume another workflow from another repository, you would have to pass the full URL of the

repository. So, this thing has to start with HTTPS. So, how do we write our custom in actions? How do we wrap something such that we can invoke we could create our own version of checkout, for example, or our own version to that knows how to do GraalVM native images with Maven and a set of particular settings so that we don't have to repeat everything that we have

here. I have a real-life example that I can show you. It's coming from the JReleaser The thing that we need is an action descriptor, which we can look here. Uh let's make it a bit bigger. Uh well, perhaps that was too big. Uh we have some name, a description, uh some inputs. This thing that says branding, this will appear on the We have some inputs, as we

saw like in the other case for the reusable workflow, we can define the types, default values, and some sort of text to tell people, well, this is what you want to do. So, I have a bunch of settings here. But then the the sauce here, the secret sauce, is this one. composite If you have a composite action, then you can use any programming language. You don't have

to write TypeScript or you don't have to provide a Docker image that contains everything like GitLab CI does. This case, what we're doing is we set up we download a JAR file from the and then we invoke that JAR file with a particular set of arguments. That's it. So, if you want to have your own custom actions written in Java, then the only thing that you have

to do is ensure that you set this setting. And then you can have as many as steps, and you can reference to local files. So, this file here, call uh get JReleaser Java, is right there. This is a very simple Java script that you can or you may or may not run with JBang. This is Java 11. The only thing that it does is given a certain

set of parameters, it's going to locate uh create a URL, download a JAR file if it exists. If it doesn't, they will tell you. Has emojis because everybody loves emojis. And that's what it do. If you want to see this in when we just have to go back where we are here, let's click here Mac OS X, go into assemble, and that's exactly what this custom action

does. Easy as that. This thing is almost done. Um build file, and you can see that now we have additional artifacts here. These are the artifacts uh these are the log files I if I'm not mistaken. And these ones are the native executables created with GraalVM. Once all the four nodes are finished, then the release steps will run, and I will have a GitHub release with some

default settings and all the artifacts that I have created. But now I can move into the next step, which is say that you have all these things already. How do you ensure that you are following the best practices for writing actions? There is an option out there, which is called uh Sisemore. You can run Sisemore on your local environment. It's a command line tool, or you can

also configure it to run every time you're making a push to main if you want to. So, that is found here. I have Sisemore uh configured for this project. Every time that I make a commit to the main branch or there is a pull request for any kind of branch, this will be the trigger. We can also can run it manually. And what this thing does is

set some default permissions for running Sisemore, and then check out my project run sysmore. You've noticed that in the past in the other builds, for example, I'm using a tag. But in here in sysmore I'm using a hash. One of the recommended best practices is to pin actions to hashes. Not to tags because anybody can delete a tag or remove a tag or move it to something

else, point it to where where perhaps an attacker could be. But if you point it to a hash, a well-known hash, hopefully this has not been compromised then this is much better. Now, when you run sysmore in this way if you go to the project into the security tab you notice I have like 109 things that were inspected. These are everything that sysmore found on the configuration

of all my actions. This says You know what? Let's look into this one. You're using upload artifact with version seven instead of pinning to a given hash. This is not a good thing to And then there's a bunch of them like If you could keep moving to here, there is like unpin action reference. Wow, there's a lot of them. Or we have default permissions when running our

actions. Uh or when we check out the project, we have credentials of your Git credentials that could be accessible to to be stolen. So, there are ways to mitigate this. If you go to sysmore into documentation uh which is this, then we see the audit rules. Say pin here. Unpin images, unpin tools, unpin uses. This is one of the complaints that we saw from sysmore. It tells

you what this why this is bad how you can configure this to be skipped And examples how to fix this. For example, here's this thing, you do this. Oh, this is the example in the configuration. How you can fix this, this is the part of the remediation. So, what we had before, let's make this bigger. Oh, that was too big. Uh, how do we fix this? Uh,

you had where where I have it? I almost lost it. here we go. So, you're using uh, tags or branches. The remediation is to use a hash. You could use a command a comment here to tell to figure out well, what is uh, this is just for your information. The tool doesn't do anything with this, so you can keep track of what we're doing you're doing here.

I think we're done running this thing. Uh, the action is ready. Build file is green. We have a bunch of uh, artifacts and the release was successful. So, let's see We got a bunch of files. So, when we go into the project, now there is a tag that wasn't there before. We have a release. And we have some artifacts. Everything that we wanted to publish. And we're

done. obviously, I made use I showcase your release here. You can use any other kind of tool to do these kind of things cuz this is just one of the many tools that you can consume using GitHub Actions. My name is Andres Almiray. I call myself a system sorcerer. I've been doing open source for more than 20 years. Uh, I like to go on stage and talk

about my experiences of open source, share knowledge. And uh, so, if you have any questions regarding open source or anything that we saw today, please let me know. Thank you for your time. I didn't put out the uh the the link for the Slido. Uh do do we have access to the Slido? I don't know. Do you have any questions? Let me know. Approach me. I will

still also be uh outside because we have to make space for the next speaker.

From event

JCON EUROPE

20 Apr 2026 – 23 Apr 2026

All event videos
Back to Watch