<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rob Bos</title>
    <description>The latest articles on DEV Community by Rob Bos (@rob_bos).</description>
    <link>https://dev.to/rob_bos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F767727%2F97f62046-2e00-41df-a083-20eb6f25fe02.jpeg</url>
      <title>DEV Community: Rob Bos</title>
      <link>https://dev.to/rob_bos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rob_bos"/>
    <language>en</language>
    <item>
      <title>Best Blogposts 2023</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Wed, 20 Dec 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/best-blogposts-2023-d8c</link>
      <guid>https://dev.to/rob_bos/best-blogposts-2023-d8c</guid>
      <description>

&lt;p&gt;layout: post title: Best viewed blogposts of 2023 date: 2023-12-20 tags: [Blog, GitHub, Azure DevOps] —&lt;/p&gt;

&lt;p&gt;It’s that time of the year again! Time to look back at the most viewed blogposts of the year. I’m always amazed at the number of views some of these posts get. I’m also amazed at the number of people that find my blogposts useful. I’m glad I can help out!&lt;/p&gt;

&lt;p&gt;Here is the overview:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Title&lt;/th&gt;
&lt;th&gt;Published&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Views&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1.&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/blog/2022/08/12/workflows-not-starting"&gt;GitHub workflows not starting&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;🙀The most viewed for a reason! When your GitHub workflows are not starting up, there can be quite a few things causing this. Read this post to find out more!&lt;/td&gt;
&lt;td&gt;17.2k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/blog/2022/01/03/GitHub-Tokens"&gt;GitHub access tokens explained&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Personal Access Tokens can be a quick an easy way to test things out, but should not be used in production scenarios for a number of reasons 👺. In this post I explain why and what alternatives there are&lt;/td&gt;
&lt;td&gt;6.7k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/blog/2020/04/05/netcore-nested-appsettings-json"&gt;.NET core: nesting appSettings.json in the IDE&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;A three year old post that I jotted down for future reference. Seems like other people still have that same need! 🎉&lt;/td&gt;
&lt;td&gt;4.5k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4.&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/blog/2020/11/24/github-actions-with-private-runner-iis"&gt;GitHub Actions with private runner: deploy to IIS&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;🔍 Using a private runner for GitHub actions unlocks tons of scenario’s to deploy into your private production environment as well. Some folks thing it’s hard to do so on Windows and a classical setup with IIS. In this post I explain the moving parts in making this happen! IIRC I used the same setup to stop, install, and start Windows Services as well. 🦖🌴&lt;/td&gt;
&lt;td&gt;4.2k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.&lt;/td&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;&lt;a href="https://dev.to/blog/2020/11/08/Azure-DevOps-Git-Authenticate-With-PAT"&gt;Authenticate to Azure DevOps with a Personal access token&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Authenticating to Azure DevOps using a personal access token takes a while to figure it out. For future reference I jotted it down. Still helping other folks after 3️⃣ years!&lt;/td&gt;
&lt;td&gt;3.5k&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Looking at these things is always interesting for me. For the last three years I have been blogging mostly on GitHub, Advanced Security, and some Azure DevOps (mostly on Advanced Security on Azure DevOps). The top post is about a typical scenario that I see a lot of folks struggle with, so I am very happy this post gets found a lot to.&lt;/p&gt;

&lt;p&gt;Three of the top five posts are from 2020! That means a lot of folks still have the same need to know this as I did when I wrote the post. This is also the reason why I keep on blogging about these things. It means I can find these things myself, and apparently other folks find them useful as well 🤗.&lt;/p&gt;

&lt;p&gt;My top post from 2023 isn’t even in the top 10 of best viewed posts! It’s the post on &lt;a href="https://dev.to/blog/2023/05/23/GitHub-Advanced-Security-Azure-DevOps"&gt;GitHub Advanced Security on Azure DevOps&lt;/a&gt;, where I explain the new features on Azure DevOps that where announced in the beginning of the year. These security features are available for anyone to use since November 2023 (if you need help with it, let me know!).&lt;/p&gt;

&lt;h1&gt;
  
  
  Blogposts from this year 📝
&lt;/h1&gt;

&lt;p&gt;Looking back at blogging in 2023, I wrote 12 blogposts and shared my lessons learned or how I implemented things for customers. So even though I average a post a month or so, people still are able to find them and use them for their own benefit.&lt;/p&gt;

&lt;p&gt;For me the ones I looked at this year that stand out are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/blog/2023/05/23/GitHub-Advanced-Security-Azure-DevOps"&gt;GitHub Advanced Security on Azure DevOps&lt;/a&gt; - I’m a fan of Advanced Security, so this functionality becoming available for Azure DevOps is a big win for me.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/blog/2023/06/08/GITHUB_STEP_SUMMARY"&gt;How to write to the GITHUB_STEP_SUMMARY&lt;/a&gt; - Very helpful to have a mental image of the moving parts. Instead of looking at the sparse GitHub docs for this, I refer to my own post almost quarterly at the moment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/blog/2023/06/21/GitHub-Container-Action-Cleanup"&gt;GitHub container based action cleanup&lt;/a&gt; - I’m a fan of container based actions, but it can be a bit tricky to clean up after yourself in a container based action.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/blog/2023/09/02/Get-alerts-from-GHAzDo"&gt;Get alerts from GitHub Advanced Security for Azure DevOps&lt;/a&gt; - In the past months I created an extension for Azure DevOps to show &lt;a href="https://marketplace.visualstudio.com/items?itemName=RobBos.GHAzDoWidget"&gt;alert information&lt;/a&gt; in your dashboards, as I was missing that information in the default functionality. This post explains how I you can get those alerts from the REST API yourself (written when the docs were not avaiable yet).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Website stats 📈
&lt;/h2&gt;

&lt;p&gt;For visitor numbers I use &lt;a href="https://plausible.io/"&gt;Plausible.io&lt;/a&gt; and those numbers are publicly available &lt;a href="https://plausible.io/devopsjournal.io"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
A few of the numbers can be found below:&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Dependabot alerts triaging in GitHub</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Sat, 07 Oct 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/dependabot-alerts-triaging-in-github-nc7</link>
      <guid>https://dev.to/rob_bos/dependabot-alerts-triaging-in-github-nc7</guid>
      <description>&lt;p&gt;The GitHub UI displays a couple of helpful tips to use in triaging your Dependabot alerts which are super helpful. Unfortunately the User Interface does not show these filters in the filter bar yet, so I wanted to have a better overview of the filters I could use. I’ve listed them below:&lt;/p&gt;

&lt;h2&gt;
  
  
  Only show alerts where your code is using the vulnerable calls of the dependency
&lt;/h2&gt;

&lt;p&gt;This is very helpful in triaging the open alerts. Currently in limited preview for certain languages and certain package ecosystems. I hope they will expand this to more languages and package ecosystems.&lt;/p&gt;

&lt;p&gt;Instead of wading through all the open alerts where your code might (currently!) not call into the vulnerable part of the dependency code, you can filter down the list of alerts to the things you &lt;strong&gt;are&lt;/strong&gt; calling. Use this filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;is:open has:vulnerable-calls&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Filter on Dependabot auto dismissal
&lt;/h2&gt;

&lt;p&gt;Dependabot now has new functionality to auto dismiss alerts that have low or medium severity. This is a great way to reduce the noise in your alerts list so you can filter on the important issues. You can filter on these alerts with this filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;is:closed resolution:auto-dismissed&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Filter on only runtime dependencies
&lt;/h2&gt;

&lt;p&gt;This is a great way to filter out the development dependencies from the runtime dependencies. This is the case for example when you use NPM as a package manager. You can use this filter to only show the runtime dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;is:open scope:runtime&lt;/code&gt;Do make sure that you are not accidentally publishing to production with development dependencies. This is a common mistake that can lead to security issues, as the files are then still on disk, and could be used as an attack vector.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Filter on vulnerable dependencies where a patch is available
&lt;/h2&gt;

&lt;p&gt;This is helpful to focus on quick wins. Since there is a patch available that fixes the vulnerability, getting these dependencies upgraded can lead to fast results. You can use this filter to only show the alerts where a patch is available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;is:open has:patch&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Get alerts from GitHub Advanced Security for Azure DevOps</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Sat, 02 Sep 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/get-alerts-from-github-advanced-security-for-azure-devops-3pb6</link>
      <guid>https://dev.to/rob_bos/get-alerts-from-github-advanced-security-for-azure-devops-3pb6</guid>
      <description>&lt;p&gt;GitHub Advanced Security for Azure DevOps (GHAzDo) builds on top of the functionality for GitHub Advanced Security and is giving you extra security tools to embed into your developer way of working. It’s a great way to get started with security in your Azure Pipelines and Azure repos and I’ve written about it before in &lt;a href="https://dev.to/blog/2023/05/25/GitHub-Advanced-Security-Azure-DevOps"&gt;this blogpost&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Loading the alerts from the API’s
&lt;/h1&gt;

&lt;p&gt;Before starting with the Advanced Security API’s you’ll need to get the ID for the repository you are working with. You’ll need to have the project name and the repository name itself. With that you can make this API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://dev.azure.com/&amp;lt;PROJECT NAME&amp;gt;//_apis/git/repositories?api-version=7.1-preview.1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will return you the list of repos the token you are using has access to. The repo object will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
            "id": "5e5195e1-1b44-4d4b-9310-5d33ee2c4dc",
            "name": "eShopOnWeb",
            "url": "https://dev.azure.com/raj-bos/3651f6f0-74e5-48d7-8ff9-d62ae2464b1/_apis/git/repositories/5e5195e1-1b44-4d4b-9310-5d33ee2c4dc",
            "project": {
                "id": "3651f6f0-74e5-48d7-8ff9-d62ae2464b1",
                "name": "GHAzDo trial",
                "url": "https://dev.azure.com/raj-bos/_apis/projects/3651f6f0-74e5-48d7-8ff9-d62ae2464b1",
                "state": "wellFormed",
                "revision": 141,
                "visibility": "private",
                "lastUpdateTime": "2023-07-26T18:51:26.227Z"
            },
            "defaultBranch": "refs/heads/main",
            "size": 62610330,
            "remoteUrl": "https://raj-bos@dev.azure.com/raj-bos/GHAzDo%20trial/_git/eShopOnWeb",
            "sshUrl": "git@ssh.dev.azure.com:v3/raj-bos/GHAzDo%20trial/eShopOnWeb",
            "webUrl": "https://dev.azure.com/raj-bos/GHAzDo%20trial/_git/eShopOnWeb",
            "isDisabled": false,
            "isInMaintenance": false
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this you need the “id” field of the response. That can then be injected into the next API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://advsec.dev.azure.com/&amp;lt;PROJECT NAME&amp;gt;/&amp;lt;REPO NAME&amp;gt;/_apis/AdvancedSecurity/repositories/&amp;lt;REPO ID&amp;gt;/alerts?top=50&amp;amp;orderBy=severity&amp;amp;alertType=3&amp;amp;ref=refs/heads/main&amp;amp;states=1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The filtering options determine the response you will get back:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Param&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;top&lt;/td&gt;
&lt;td&gt;The number of alerts you want to get back.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;orderBy&lt;/td&gt;
&lt;td&gt;The field you want to order the results by.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;alertType&lt;/td&gt;
&lt;td&gt;The type of alert you want to get back. 1 = Dependency, 2 = Secrets, 3 = Code scanning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ref&lt;/td&gt;
&lt;td&gt;The branch you want to get the alerts for, only needed when looking at code scanning alerts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;states&lt;/td&gt;
&lt;td&gt;The state of the alerts you want to get back. 1 = Open, 2 = Closed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can also leave the &lt;code&gt;alertType&lt;/code&gt; away from the url to get all alerts in one go. Do be aware that it will result in a different value for the &lt;code&gt;alertType&lt;/code&gt; in the response, instead of the numbers listed in the table above:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;code&lt;/td&gt;
&lt;td&gt;Code scanning alert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;secret&lt;/td&gt;
&lt;td&gt;Secret scanning alert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dependency&lt;/td&gt;
&lt;td&gt;Dependency alert&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Cleaning up files changed by a GitHub Action that runs in a container</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Wed, 21 Jun 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/cleaning-up-files-changed-by-a-github-action-that-runs-in-a-container-57bc</link>
      <guid>https://dev.to/rob_bos/cleaning-up-files-changed-by-a-github-action-that-runs-in-a-container-57bc</guid>
      <description>&lt;p&gt;A common issue we see with self-hosted runners is that they can leave behind files that were created or modified by the action. This is because the action runs in a container and the container is using a &lt;code&gt;root&lt;/code&gt; user to do its work.&lt;/p&gt;

&lt;p&gt;The GitHub documentation says to run the the runner service as &lt;code&gt;root&lt;/code&gt; as well, to have the most compatibility with most runners. This is not a good idea, as it can lead to security issues, so a lot of people run the runner service as a non-root user. This can lead to permission issues when the action touches files in the workspace directory that get’s mounted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vz0VGOsI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230621/aakanksha-panwar-SOOTeA8nL4o-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vz0VGOsI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230621/aakanksha-panwar-SOOTeA8nL4o-unsplash.jpg" alt="Photo of a ray of sun in between the clouds" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Photo by &lt;a href="https://unsplash.com/ko/@aakanksha_panwar?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Aakanksha Panwar&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/SOOTeA8nL4o?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;
&lt;/h5&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;One common example is the &lt;a href="https://github.com/marketplace/actions/super-linter"&gt;super-linter&lt;/a&gt; action. Depending on the checks that run, it can touch files on disc that then get owned by the &lt;code&gt;root&lt;/code&gt; user.&lt;/p&gt;

&lt;p&gt;Another example is running the entire job inside of a container, with using the keyword &lt;code&gt;container&lt;/code&gt; on the job level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    runs-on: self-hosted
    container: ubuntu:22.04
    steps:
      - uses: actions/checkout@v2
      - run: echo "Hello World"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The checkout action will create a &lt;code&gt;.git&lt;/code&gt; directory in the workspace directory with the repo contents, which will be owned by the &lt;code&gt;root&lt;/code&gt; user as the &lt;code&gt;ubuntu-22.04&lt;/code&gt; container runs as &lt;code&gt;root&lt;/code&gt;. The job itself will complete just fine, but the next time you run another job for this repository on the same runner, the checkout action will try to cleanup the $GITHUB_WORKSPACE directory to get a clean starting point, and will fail with a permission error since the job is not running as root, but as the non-root user the runner service is executing under.&lt;/p&gt;

&lt;p&gt;There are multiple ways to tackle this issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prevent it from happening: Run the runner service as &lt;code&gt;root&lt;/code&gt; and run the job as &lt;code&gt;root&lt;/code&gt; as well. This is recommended by GitHub to prevent this from happening, that is how the service has been designed. Most people I talk with do not agree since the user has to much permissions and it can lead to security issues.&lt;/li&gt;
&lt;li&gt;Change the action to not run as root, which is not realistic when using actions from the public marketplace.&lt;/li&gt;
&lt;li&gt;Get the user to cleanup inside of the container, or add a cleanup action in their job.&lt;/li&gt;
&lt;li&gt;Add cleanup configuration on the container level configuration in the runner&lt;/li&gt;
&lt;li&gt;Add cleanup configuration on the runner configuration itself&lt;/li&gt;
&lt;li&gt;Do not run the container with any persistence: run as &lt;code&gt;ephemeral&lt;/code&gt;, where the runner is alive for a single job execution, and then gets completely deleted and cleaned up so there is no reuse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ll go over the last 4 options in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get the user to cleanup inside of the container, or add a cleanup action in their job.
&lt;/h2&gt;

&lt;p&gt;You could hunt for the jobs that cause this issue, and ‘ask’ the user to add a cleanup action in the job itself. There is for example a &lt;a href="https://github.com/asilbek99/action-cleanup"&gt;cleanup action&lt;/a&gt; available in the marketplace that runs in a container that uses root, and that cleans up the workspace directory. This is not a good solution, as it requires a lot of manual work, and you will have to keep track of the jobs that cause this issue. The following options are probably manageable in a better way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add cleanup configuration on the container level configuration in the runner
&lt;/h2&gt;

&lt;p&gt;You can configure the runner with specific customization commands that get executed before and after the job, as well as other options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prepare_job: Called when a job is started.&lt;/li&gt;
&lt;li&gt;cleanup_job: Called at the end of a job.&lt;/li&gt;
&lt;li&gt;run_container_step: Called once for each container action in the job.&lt;/li&gt;
&lt;li&gt;run_script_step: Runs any step that is not a container action. See the entire configuration and examples &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/customizing-the-containers-used-by-jobs"&gt;here&lt;/a&gt;. This is rather complex and more suited for configuring sidecars or other complex scenarios. I prefer to use the next option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add cleanup configuration on the runner configuration itself
&lt;/h2&gt;

&lt;p&gt;By setting 2 environment variables before the job starts, you can run specific scripts before and after the job starts. The completed job can then be a docker run command that mounts the $GITHUB_WORKSPACE and cleans everything up while running as &lt;code&gt;root&lt;/code&gt;. This is the easiest option in my opinion:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ACTIONS_RUNNER_HOOK_JOB_STARTED: The script defined in this environment variable is triggered when a job has been assigned to a runner, but before the job starts running.&lt;/li&gt;
&lt;li&gt;ACTIONS_RUNNER_HOOK_JOB_COMPLETED: The script defined in this environment variable is triggered after the job has finished processing. Find more information in the documentation &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/running-scripts-before-or-after-a-job"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Do not run the container with any persistence
&lt;/h2&gt;

&lt;p&gt;The best advice is to always start runners as &lt;code&gt;ephemeral&lt;/code&gt;, where the runner is alive for a single job execution, and then gets completely deleted and cleaned up so there is no reuse. You will need to provide a mechanism to cleanup the Virtual Machine or Container setup where you execute the runner on. The best method I’ve found is to use &lt;a href="https://github.com/actions/actions-runner-controller"&gt;Actions Runner Controller&lt;/a&gt; where the runner is executing inside of a container that gets deleted after the job is done. This will prevent any data to linger around on the runner as well, and gets you a clean execution environment every time.&lt;/p&gt;

&lt;p&gt;There might be some valid reasons to still have a persistent runner, but I would recommend to use ephemeral runners as much as possible.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Writing to the $GITHUB_STEP_SUMMARY with the core npm package</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Thu, 08 Jun 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/writing-to-the-githubstepsummary-with-the-core-npm-package-9n5</link>
      <guid>https://dev.to/rob_bos/writing-to-the-githubstepsummary-with-the-core-npm-package-9n5</guid>
      <description>&lt;p&gt;Every time I need to write to the GITHUB_STEP_SUMMARY in GitHub Actions from the &lt;a href="https://github.com/actions/github-script"&gt;actions/github-script&lt;/a&gt; action (or from Typescript), I need to search for the &lt;a href="https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/"&gt;blogpost that announced&lt;/a&gt; it’s existence. So I’m writing this blogpost to make it easier for myself to find it a lot easier, including some working examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SFNUxpfc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230608/markus-winkler-aYPtEknQmXE-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SFNUxpfc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230608/markus-winkler-aYPtEknQmXE-unsplash.jpg" alt="Photo of around 20 white puzzle pieces against a white background" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Photo by &lt;a href="https://unsplash.com/@markuswinkler?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Markus Winkler&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/aYPtEknQmXE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;
&lt;/h5&gt;

&lt;p&gt;The code for the summaries lives in the &lt;a href="https://github.com/actions/toolkit/blob/main/packages/core/src/summary.ts"&gt;actions/core&lt;/a&gt; package on npm, but figuring out how to use it can be a bit hard. The only example I’ve seen is in the blogpost I mentioned.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  import * as core from '@actions/core' 

  await core.summary
  .addHeading('Test Results')
  .addCodeBlock(generateTestResults(), "js")
  .addTable([
    [{data: 'File', header: true}, {data: 'Result', header: true}],
    ['foo.js', 'Pass ✅'],
    ['bar.js', 'Fail ❌'],
    ['test.js', 'Pass ✅']
  ])
  .addLink('View staging deployment!', 'https://github.com')
  .write()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does a lot of things at the same time, but we get the general idea that you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add headings&lt;/li&gt;
&lt;li&gt;add code blocks&lt;/li&gt;
&lt;li&gt;add tables&lt;/li&gt;
&lt;li&gt;add links And at the end you need to write the summary itself, which will be added to the file in the GITHUB_STEP_SUMMARY environment variable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Working with the table output
&lt;/h2&gt;

&lt;p&gt;There are no methods to break the table into chunks, like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a header&lt;/li&gt;
&lt;li&gt;Add a row&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The only method there is, is adding the table in one go, with each row as an array of objects, and some configuration in the first row as that will define if the cell is a header or not. So assuming you have an array of results that you want to show, you can convert that array with properties into an array of rows, with each property value being an item in the row array.&lt;/p&gt;

&lt;p&gt;The interesting thing I ran into, is that the row cells &lt;strong&gt;must be a string&lt;/strong&gt;. Sending in integers for example does not work. Take the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await core.summary
            .addHeading('Example')
            .addTable([
                        [{data: 'Topic', header: true}, {data: 'Count', header: true}, {data: 'Public', header: true}],
                        ['foo.js' , "1", "2"],
                        ['bar.js' , '3', '4'],
                        ['test.js', 100, 200]
                      ])
            .write()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, all rows will be added to the summary, and as long as the content is a valid string, it will be shown in the table as well. In this example, the values in the last row are integers, and they will be not visible in the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UGlz7dZ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230608/20230608_ExampleOutput.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UGlz7dZ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230608/20230608_ExampleOutput.png" alt="Screenshot of the table output, with the integer values missing in the last row" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A full example of creating the header array with hardcoded cells, and then adding the rows from an array of objects can be seen below. Here I have an array stored as output in a previous step, so I read that file and map it (as string values!) to an array containing the rows. The next step is to join the two arrays (header + summary) and pass that to the addTable method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Show information in the GITHUB_STEP_SUMMARY
    uses: actions/github-script@v6
    env:
    summaryFile: $
    with: 
    script: see below in other markup for better readability


        const fs = require('fs')
        const summary = fs.readFileSync(process.env.summaryFile, 'utf8')

        // make the heading array for the core.summary method
        const headingArray = [{data: 'Topic', header: true}, {data: 'Count', header: true}, {data: 'Public', header: true},{data: 'Internal', header: true},{data: 'Private', header: true}]

        // convert the summary array into an array that can be passed into the core.summary method
        const summaryArray = JSON.parse(summary).map(t =&amp;gt; [t.name, t.count.toString(), t.public.toString(), t.internal.toString(), t.private.toString()])

        // join the two arrays
        const tableArray = [headingArray, ...summaryArray]

        await core.summary
                .addHeading(`Topics used on repos in the [${process.env.org}] organization`)
                .addTable(tableArray)
                .write()

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>GitHub Advanced Security for Azure DevOps</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Tue, 23 May 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/github-advanced-security-for-azure-devops-45jc</link>
      <guid>https://dev.to/rob_bos/github-advanced-security-for-azure-devops-45jc</guid>
      <description>&lt;p&gt;Microsoft is bringing some of the GitHub Advanced Security tools to Azure DevOps. I have been playing with it for a while and they have presented the latest state at Microsoft Build 2023, which includes a &lt;a href="https://analyticsindiamag.com/microsoft-makes-github-advanced-security-for-azure-devops-available-in-public-preview/"&gt;Public Preview!&lt;/a&gt;. That means you can try it out yourself, and I can finally share my experiences with you! Since I teach a lot people on how to use this on GitHub, you can find some of the differences between the two implementations in this post as well 😉.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b8sOBRLY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/adi-goldstein-EUsVwEOsblE-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b8sOBRLY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/adi-goldstein-EUsVwEOsblE-unsplash.jpg" alt="High tech security image" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Photo by &lt;a href="https://unsplash.com/@adigold1?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Adi Goldstein&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/EUsVwEOsblE?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;
&lt;/h5&gt;

&lt;h2&gt;
  
  
  What is GitHub Advanced Security?
&lt;/h2&gt;

&lt;p&gt;GitHub Advanced Security (GHAS) is a set of tools that help you secure your code and your pipelines. It includes the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code scanning&lt;/li&gt;
&lt;li&gt;Dependabot / Dependency scanning&lt;/li&gt;
&lt;li&gt;Secret scanning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to dive deeper into that functionality, check out my LinkedIn Learning Course &lt;a href="https://devopsjournal.io/blog/2022/10/19/LinkedIn-Learning-GHAS"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependabot / Dependency scanning
&lt;/h3&gt;

&lt;p&gt;Scans you repository for known manifest files, like package.json, and checks if there are any vulnerabilities in the packages you are using. It will then create a pull request to update the package to a newer version that does not have the vulnerability. It can also automate creating pull requests for version updates as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Secret scanning
&lt;/h3&gt;

&lt;p&gt;Scans your repository for known secrets, like passwords, and notifies you if it finds any. It will also notify you if you push a commit that contains a secret. It will also scan your pull requests for secrets and notify you if it finds any.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code scanning
&lt;/h3&gt;

&lt;p&gt;Scans your code for known vulnerabilities using CodeQL (or another Static Application Security Tool, aka SAST). It can also scan your pull requests for vulnerabilities and notify you if it finds any.&lt;/p&gt;

&lt;h1&gt;
  
  
  GitHub Advanced Security for Azure DevOps
&lt;/h1&gt;

&lt;p&gt;Microsoft is bringing the features from GHAS into Azure DevOps as customers have been asking for this for a while. It’s an example of the way they operate both products now, since the new features will get build for GitHub first, and if it makes sense, they might build some of these features into Azure DevOps as well.&lt;/p&gt;

&lt;p&gt;You can see the synergy here as well as of course: any known secret scanning patterns from GHAS can also be used in Azure DevOps, since they can share that between the companies.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get started with GitHub Advanced Security for Azure DevOps
&lt;/h2&gt;

&lt;p&gt;After enabling the feature (can be done on a repo by repo basis), you will get a new ‘Advanced Security’ tab in your repository menu. This will show you the results of the scans that have been done on your repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PXNNfCxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520GHAZDo%2520overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PXNNfCxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520GHAZDo%2520overview.png" alt="Overview of the Advanced Security alerts for a repo in Azure DevOps" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After enabling the feature you will get some extra menu options left and right, as well as extra tasks for your Azure Pipelines.&lt;/p&gt;

&lt;h1&gt;
  
  
  Turning on Secret scanning
&lt;/h1&gt;

&lt;p&gt;Secret scanning is turned on automatically when you turn on Advanced Security. It will start a background job that will scan your repository for secrets. It will also scan you repos entire history: all commits and branches will be checked, for known secret patterns. One additional feature is ‘push protection’. This will prevent you from pushing a commit that contains a secret. This is a great feature to prevent secrets from being pushed to your repository and ‘stop the leak’ of new alerts flowing in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YT9L6iad--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Secret%2520scanning%2520push%2520protection.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YT9L6iad--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Secret%2520scanning%2520push%2520protection.png" alt="UI to enable push protection" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using dependency scanning
&lt;/h1&gt;

&lt;p&gt;To get started with Dependency scanning you need to inject it into a pipeline. This can be done by adding the following task to your pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  - task: AdvancedSecurity-Dependency-Scanning@1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next time this pipeline will run, it will scan you repository for known manifest files, like &lt;code&gt;.csproj&lt;/code&gt; for C# projects, or &lt;code&gt;package.json&lt;/code&gt; for NodeJS projects. From those manifest files it gathers the information about the packages you are pulling in, and can check the underlying ecosystem for the dependencies of those packages as well (libraries build on other libraries as well). It will then check if there are any vulnerabilities in the packages you are using. You can check each package you use, and all of their dependencies as well, with their version numbers against the National Vulnerability Database (&lt;a href="https://nvd.nist.gov/"&gt;NVD&lt;/a&gt; from the NIST institute). Also registered in the NVD is which version is no longer vulnerable (if applicable).&lt;/p&gt;

&lt;p&gt;On GitHub that information is used to create a pull request to update the package to a newer version that does not have the vulnerability. It can also automate creating pull requests for version updates as well. This is not available for GitHub Advanced Security for Azure DevOps. I do expect this will be added later, but for now you will have to create the pull requests yourself.&lt;/p&gt;

&lt;p&gt;In the alert you will get information on the package version that you use, the first non-vulnerable version, as well as the type of vulnerability, so that you can learn on the type of attack vector for this alert.&lt;br&gt;&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IgG8K-TD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Dependency%2520Alert.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IgG8K-TD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Dependency%2520Alert.png" alt="Screenshot of a Dependency alert" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Using Code Scanning
&lt;/h1&gt;

&lt;p&gt;For enabling Code Scanning you need to inject CodeQL into an Azure Pipeline as well (other SAST tools will work as well, as long as they upload a &lt;a href="https://sarifweb.azurewebsites.net/"&gt;SARIF&lt;/a&gt; file):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - task: AdvancedSecurity-Codeql-Init@1
      inputs:
        languages: 'csharp'

    - task: AdvancedSecurity-Codeql-Autobuild@1

    - task: AdvancedSecurity-Codeql-Analyze@1

    - task: AdvancedSecurity-Publish@1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a couple of steps to note here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Init will create a local, empty database that will be filled with all the code paths your code is taking (for example: Method A is calling Method B). You also feed it one of the supported languages (C#, Java, C/C++, Python, JavaScript/TypeScript, Go, or Ruby).&lt;/li&gt;
&lt;li&gt;The auto-build step will try to build you application, based on known patterns for the language you have selected. Sometimes the auto build fails for certain projects, you can then use your own build steps in its place.&lt;/li&gt;
&lt;li&gt;With Analyze you run all the CodeQL queries against the database that was created in step 1. This will also create a SARIF file that contains all the results of the queries (if a query has a result, it will become an alert).&lt;/li&gt;
&lt;li&gt;The Publish step will actually upload the SARIF file to the Advanced Security service, which will then show you the results in the UI.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The queries that will be run can be found in the CodeQL repository on &lt;a href="https://github.com/github/codeql"&gt;github.com&lt;/a&gt;. There is a default set with low noise ratios, but you can also use &lt;a href="https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/customizing-code-scanning#using-queries-in-ql-packs"&gt;extended queries&lt;/a&gt; by configuring them this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - task: AdvancedSecurity-Codeql-Analyze@1
      inputs:
        querysuite: 'security-and-quality'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Note that in Azure DevOps you configure this on the &lt;code&gt;Analyze&lt;/code&gt; task where as you do that in GitHub in the &lt;code&gt;Init&lt;/code&gt; step.
&lt;/h5&gt;

&lt;p&gt;Do be aware that adding more extensive queries will increase the duration of the pipeline, as well as the amount of alerts you will get: the extended queries have a bit more noise and potentially also more false positives. For example from my demo application I went from 4 normal alerts to 7 extra alerts when I added the extended queries from &lt;code&gt;security-and-quality&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The advise is to run these queries at &lt;em&gt;least&lt;/em&gt; on a pull request, as well as on a schedule: the community who builds these queries is super active (150~200 pull requests a month in that repository), so you will get new queries that might find vulnerabilities in your code.&lt;/p&gt;

&lt;p&gt;When a result of the queries is present, you will see those come by in the logs as well:&lt;br&gt;&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--afgcPNBV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Codescanning%2520alerts%2520in%2520logs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--afgcPNBV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Codescanning%2520alerts%2520in%2520logs.png" alt="Screenshot of the log indicating it found two issues" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the upload of the SARIF file you will then get the alerts generated in the Advanced Security overview: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eBtQtc84--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520CodeScanning%2520Alerts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eBtQtc84--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520CodeScanning%2520Alerts.png" alt="Screenshot of the code scanning alerts" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you open up an alert you get more information on the detail page: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TabQmqBt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520CodeScanning%2520Alert%2520detail.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TabQmqBt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520CodeScanning%2520Alert%2520detail.png" alt="Screenshot of the alert detail page" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here you can again learn more about the vulnerability found, with links back to the Common Weakness Enumeration number (CWE) on the &lt;a href="https://cwe.mitre.org"&gt;Mitre site&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Addressing the alerts
&lt;/h1&gt;

&lt;p&gt;To fix the alerts you will need to actually fix the finding it self. There is not yet a way to dismiss the alerts in Azure DevOps (something we do have on the GitHub side).&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing secret scanning alerts
&lt;/h2&gt;

&lt;p&gt;For secret scanning the UI currently shows the warning that you need to treat this secret as a leaked value, and fixing can only be done by revoking the secret.&lt;br&gt;&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gd9DowoP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Secret%2520scanning%2520alert.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gd9DowoP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518%2520Secret%2520scanning%2520alert.png" alt="Screenshot of a secret scanning alert showing you need to revoke the secret" width="800" height="440"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Since there is no way to dismiss this alert through the UI yet, the only way to get rid of this alert is to rewrite the history of the repository so that the commit is no longer in the history. I expect that dismissing alerts will be added in the future, but for now this is the only way to get rid of the alert.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing dependency scanning alerts
&lt;/h2&gt;

&lt;p&gt;To get rid of a dependency scanning alert you will need to create a pull request to upgrade the dependency to a version that is no longer vulnerable. When the detection scan runs again, the alert will get closed. You have a link back to the pipeline that detected that the vulnerable dependency is no longer present: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zoMLfJLF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518_DependencyAlertClosed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zoMLfJLF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230523/20230518_DependencyAlertClosed.png" alt="Screenshot of the closed alert" width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Addressing code scanning alerts
&lt;/h2&gt;

&lt;p&gt;Fixing Code Scanning alerts is a bit more involved, as you will need to actually fix the code that is causing the alert. After fixing the issue, the next scan will close the alert and will link back to the scan that closed the alert. From it, you can find the commit that fixed the issue as well, so you have that end-to-end traceability.&lt;/p&gt;

&lt;p&gt;Note that currently you cannot exclude code from the CodeQL scanning (on GitHub you can). That also means that your unit test suite for example, will get scanned as well, with a good change it finds some issues there as well (I had the same issue with my test project).&lt;/p&gt;

&lt;h2&gt;
  
  
  Dashboarding
&lt;/h2&gt;

&lt;p&gt;For an overall overview of how you are doing across the entire project or organization, you’ll have to look at &lt;a href="https://learn.microsoft.com/en-us/azure/defender-for-cloud/defender-for-devops-introduction"&gt;Microsoft Defender for DevOps&lt;/a&gt;, which is a tool in Microsoft Azure. Since I don’t have Defender integrated yet (I think you need a feature flag to enable that), I don’t have any screenshots yet. I will add them when I have the access!&lt;/p&gt;

&lt;p&gt;The integration does make sense from the Azure perspective and integrate it in the tools folks on Azure Cloud use. But if you only use Azure DevOps, then I would expect an overview to find repeat patterns or dependencies in you Azure DevOps Organization as well. I would not be surprised if they add that overview somewhere in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summarizing
&lt;/h2&gt;

&lt;p&gt;Overall, most of the initial features are already in, with definitely some different choices made comparing it with GitHub’s implementation (for example dashboarding). You can see it is early days, but I expect the rest of the features / finetuning will happen fast, now that the initial part has been integrated (which is often the most work).&lt;/p&gt;

&lt;p&gt;We now have good security features integrated into Azure DevOps, right into the developer experience, which is where this needs to land in my opinion: with the folks who can act on the findings and fix them early on in their process. I hope they integrate the &lt;a href="https://github.com/actions/dependency-review-action"&gt;dependency-review-action&lt;/a&gt; equivalent for Azure DevOps next, so developers will also be enabled to stop the leak (of incoming vulnerable dependencies).&lt;/p&gt;

&lt;p&gt;If you want to know more or have questions, use the comments below!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How Copilot/AI helps me in my daily work</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Mon, 24 Apr 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/how-copilotai-helps-me-in-my-daily-work-5dc6</link>
      <guid>https://dev.to/rob_bos/how-copilotai-helps-me-in-my-daily-work-5dc6</guid>
      <description>&lt;h1&gt;
  
  
  How Copilot and AI helps me in my daily work
&lt;/h1&gt;

&lt;p&gt;During an innovation day at work, I needed to generate extra code and a new application. I wanted to check out the newly released &lt;a href="https://github.blog/2023-04-20-announcing-github-actions-deployment-protection-rules-now-in-public-beta/"&gt;Deployment Protection Rules&lt;/a&gt; that can help you with protecting when a job in GitHub Actions can roll out your application to an environment.&lt;/p&gt;

&lt;p&gt;Deployment protection rules need a new GitHub App that can be triggered when an environment is targeted. That App can then run its own checks and report back the status to GitHub with a callback webhook.&lt;/p&gt;

&lt;p&gt;To get started I needed a new GitHub App that can receive the webhook from GitHub. Since I already have an &lt;a href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview?WT.mc_id=AZ-MVP-5003719"&gt;Azure Function App&lt;/a&gt; up and running, I thought to add another HttpTrigger function to it, so I could log the payload and learn from that (the payload is not documented yet).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fm-60Cfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/craiyon_generating_code.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fm-60Cfz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/craiyon_generating_code.png" alt="AI generated code with the prompt" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;
  
  
  Image generated with &lt;a href="https://www.craiyon.com/"&gt;Craiyon.ai&lt;/a&gt; using the following prompt: &lt;code&gt;sketched photo with some realism of an AI generating code&lt;/code&gt;.
&lt;/h6&gt;

&lt;h1&gt;
  
  
  Usual flow
&lt;/h1&gt;

&lt;p&gt;Normally I would start with searching for the things I need: some documentation for hosting an endpoint to receive the webhook payload, search for creating an app to handle the user login, etc. This can easily take days tinkering around to get things to where it is good enough for a POC. Instead, I used AI tools to help me, and had things up and running in a few hours.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Create a new Azure Function
&lt;/h1&gt;

&lt;p&gt;I knew I needed an HttpTrigger and was about to search for it’s declaration, when I remembered I was already testing out GitHub Copilot for Chat, which is in &lt;a href="https://github.com/features/preview/copilot-x"&gt;technical preview&lt;/a&gt; so I cannot say to much about it. I asked Copilot to write the function definition for me and sure it enough: it proposed the right code, including logging of the incoming payload. Using that code I could publish the function and configure it as a webhook from a new GitHub App.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w9daHSv2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230424_FunctionLog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w9daHSv2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230424_FunctionLog.png" alt="Screenshot of the Azure function log, showing the deployment_callback_url" width="800" height="257"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
The logs show that payload sends in the normal information you would expect, like the context for the trigger (in this case &lt;code&gt;workflow_dispatch&lt;/code&gt; was triggered by my user account) and the callback URL that can be used to report back the status of the check. The callback has the following form: &lt;code&gt;https://api.github.com/repos/{OWNER}/{REPO}/actions/runs/{RUNID}/deployment_protection_rule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means it uses a well defined url, so I can just call that as the GitHub App for testing to see if it works. I’ve configured the Deployment Protection Rule with my new GitHub App based on an existing workflow (Copilot still helped here left and right), and tested it in a workflow to call the callback url.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Create a new node.js app for user configuration
&lt;/h1&gt;

&lt;p&gt;An important part for my setup with the GitHub App will be to have the user configure settings for their environment. So that means I need to have a way to host an app that can do the OAuth flow with GitHub and store the settings in a database.&lt;/p&gt;

&lt;p&gt;I’m not a JavaScript developer who knows exactly how to get started, but I do have AI tools that can help me with that. The easiest option I have and that is free to use, is the &lt;a href="https://www.bing.com/new"&gt;Bing integration in Edge&lt;/a&gt;. Here is my prompt: &lt;code&gt;How can I get started with a simple webapplication based on node that uses GitHub authentication for the user to login and then retrieve information as that user&lt;/code&gt;: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vxJewnde--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_01_prompt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vxJewnde--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_01_prompt.jpg" alt="Screenshot of the prompt and the result" width="800" height="1247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a part of the resulting app:&lt;br&gt;&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wzzh-U6w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_04_app-definition.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wzzh-U6w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_04_app-definition.png" alt="Screenshot of the npm code" width="800" height="524"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It even had the steps in there to store the configuration settings from the GitHub App in the .env file. I could just copy that example and add the code to the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lZGvFILO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_02_prompt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lZGvFILO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_02_prompt.png" alt="Screenshot of the .env setup and the login using the 'passport' library" width="712" height="1824"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There was an error running the app locally, but I could just copy the error message and search for it following the same conversation on Bing. The first result was the right answer, so I could just copy that again (&lt;code&gt;npm install express-session&lt;/code&gt;) and add it to the app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kabtIRIb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_03_error.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kabtIRIb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_03_error.png" alt="Example of the error" width="800" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the working redirect for the user authentication below: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--haPtrrqH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_05_login.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--haPtrrqH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230421_05_login.png" alt="Screenshot showing the authorization of the app using GitHub login for my user and App against my localhost:3000 app." width="800" height="985"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generated code
&lt;/h2&gt;

&lt;p&gt;The generated was not perfect: it picked up some things from the code it was trained on that can be improved. GitHub Copilot should prevent this kind of security issues when generating code, but I used Bing’s AI to generate this part of the code.&lt;/p&gt;

&lt;p&gt;This proves the point that even when using AI to help you generate code, setting up security pipelines is still very important. Luckily GitHub has made Advanced Security features available for free for public repos, allowing me to scan the code using CodeQL:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xbl45ryz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230424_CodeQL_results.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xbl45ryz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://devopsjournal.io/images/2023/20230421/20230424_CodeQL_results.png" alt="Screenshot displaying a CodeQL alert on the cookie for the user being send back to the server in plain text" width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to learn more about GitHub Advanced Security, then check out my LinkedIn Learning Course on it: &lt;a href="https://dev.to/blog/2022/10/19/LinkedIn-Learning-GHAS"&gt;LinkedIn Learning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I could then use the generated code to get started, and improve it to make it more secure using the security tools available as well.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;And with that, most of my setup (the new Azure Function and the new node.js app) was done with me writing minimal amount of code, and still getting everything to work as I wanted.&lt;/p&gt;

&lt;p&gt;Do be aware that I have enough experience with these topics to both know what to look for, and how to spot / find / debug errors in my code. I’m sure that if I was a beginner, I would have had a lot more questions and would have needed to do a lot more research to get to the same result.&lt;/p&gt;

&lt;p&gt;I’m really excited to see what the future holds for Copilot and AI in general. I’m sure it will help me and many others to get more done in less time.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Enabling CodeQL on GitHub Enterprise Server</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Fri, 24 Feb 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/enabling-codeql-on-github-enterprise-server-2829</link>
      <guid>https://dev.to/rob_bos/enabling-codeql-on-github-enterprise-server-2829</guid>
      <description>&lt;p&gt;To enable CodeQL on GitHub Enterprise Server you need to make sure you have GitHub Actions setup and running, including your own set of self-hosted runners. You can read more about that in my previous post &lt;a href="https://dev.to/blog/2022/10/09/Enabling-GitHub-Actions-on-GitHub-Enterprise-Server"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From that point you can get started to enable CodeQL. Of course, you’ll need to have it enabled in your license, and upload that license file to your server as well. Enabling starts at the appliance level, where you need to enable the code scanning and secret scanning features from the management console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2023%2F20230207%2Fbarn-images-t5YUoHW6zRo-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2023%2F20230207%2Fbarn-images-t5YUoHW6zRo-unsplash.jpg" alt="Photo of all sort of tools hanging on a wall, like hammers, saws, etc."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Photo by &lt;a href="https://unsplash.com/@barnimages?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Barn Images&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/t5YUoHW6zRo?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;The default workflow that CodeQL will propose links to the &lt;code&gt;github/codeql-action&lt;/code&gt; action, of which a static copy is installed with each Enterprise Server update. This organization is hidden by default, but you can navigate to it with the direct link. The issue here is that these action repos (github/dependabot-action and all repos in the actions org) only have the source code linked and updated with each Enterprise Server update. Since the CodeQL bundle is stored as a release asset, it is missing from the appliance. The bundle contains all CodeQL queries, including the &lt;code&gt;security-extended&lt;/code&gt; and &lt;code&gt;security-and-quality&lt;/code&gt; query types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncing the CodeQL bundle
&lt;/h2&gt;

&lt;p&gt;Normally we’d use the &lt;a href="https://github.com/actions/actions-sync" rel="noopener noreferrer"&gt;actions-sync&lt;/a&gt; tool to update the actions on the appliance with the latest version on github.com. Unfortunately that tool does not sync any release assets. For syncing the release assets, we need to download the latest release of the &lt;a href="https://github.com/github/codeql-action-sync-tool" rel="noopener noreferrer"&gt;codeql-action-sync-tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After downloading the &lt;code&gt;codeql-action-sync-tool&lt;/code&gt;, you need to make sure you have write access to the &lt;code&gt;github&lt;/code&gt; organization. By default you do not have it, so you cannot &lt;code&gt;write&lt;/code&gt; to the release assets or anything else in this org. That means we need to promote the user that will execute the syncing to an owner of the &lt;code&gt;github&lt;/code&gt; org.&lt;/p&gt;

&lt;p&gt;To do so, you need to call the &lt;a href="https://docs.github.com/en/enterprise-server@3.4/admin/configuration/configuring-your-enterprise/command-line-utilities#ghe-org-admin-promote" rel="noopener noreferrer"&gt;ghe-org-admin-promote&lt;/a&gt; command line utility from a remote shell on the appliance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ghe-org-admin-promote -u USERNAME -o ORGANIZATION

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can call the &lt;code&gt;codeql-action-sync-tool&lt;/code&gt; to download the latest version of the CodeQL bundle and upload it to the &lt;code&gt;github/codeql-action&lt;/code&gt; repo. This tool will also update the &lt;code&gt;github/codeql-action&lt;/code&gt; repo with the latest version of the action code.&lt;br&gt;&lt;br&gt;
You can run it with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;codeql-action-sync-tool sync --force \ 
 --destination-url https://enterprise-server-url.com
 --destination-token &amp;lt;PAT&amp;gt; \
 --source-token &amp;lt;PAT&amp;gt; # prevents ratelimiting 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, the machine that is running this will need to have access to github.com, as well as the Enterprise Server. The &lt;code&gt;--source-token&lt;/code&gt; is optional, but it will prevent you from hitting the rate limit on github.com.&lt;/p&gt;

&lt;h1&gt;
  
  
  Running CodeQL efficiently
&lt;/h1&gt;

&lt;p&gt;Now that we have the CodeQL bundle on the appliance, we can start using it. The first thing you’ll notice is that the CodeQL bundle is quite large. The Linux zip file alone is 500Mb, which is quite a lot for a GitHub Action. The release asset appropriate for the OS of the runner is downloaded for each run. If you are using ephemeral runners (which you should!), this means that the CodeQL bundle is downloaded for each and every run. Given that this workflow is configured by default to run on every push, pull request as well as on a schedule (once a week), it can take up quite the bandwidth and thus hammer your appliance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2023%2F20230207%2Fcodeql-action.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2023%2F20230207%2Fcodeql-action.png" alt="Screenshot showing the different sizes of the release assets, with the Linux tar file being 500Mb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The action follows the normal setup for GitHub Actions to check for the well known folder &lt;code&gt;runner.tool_cache&lt;/code&gt;, which is stored in ‘/opt/hostedtoolcache/’. If it can find the bundle in that folder, it will use that. If it cannot find it, it will download the appropriate release asset.&lt;/p&gt;

&lt;p&gt;That means that we can prep our runners by copying the CodeQL bundle to this location. This will prevent the bundle from being downloaded for each run. The folder is used by including the CodeQL bundle release version and date: &lt;code&gt;/opt/hostedtoolcache/CodeQL/2.12.1-20230120/x64/codeql/codeql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Priming that location will significantly lower the download pressure on your appliance, and speed up the execution of the CodeQL workflow.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Making the case for GitHub's Secret scanning</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Sun, 22 Jan 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/making-the-case-for-githubs-secret-scanning-3nno</link>
      <guid>https://dev.to/rob_bos/making-the-case-for-githubs-secret-scanning-3nno</guid>
      <description>&lt;p&gt;After scanning the GitHub Actions Marketplace for the security of those actions (read that post &lt;a href="https://dev.to/blog/2022/09/18/Analysing-the-GitHub-marketplace"&gt;here&lt;/a&gt;) I was curious to see what happens if I’d enable &lt;a href="https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning" rel="noopener noreferrer"&gt;Secret Scanning&lt;/a&gt; on the forked repositories. I regularly teach classes on using GitHub Advanced Security (where secret scanning is part of) and I always tell my students that they should enable secret scanning on their repositories. I even have a &lt;a href="https://www.linkedin.com/learning/github-advanced-security/github-advanced-security?autoplay=true" rel="noopener noreferrer"&gt;course on LinkedIn Learning about GitHub Advanced Security&lt;/a&gt; in case you want to learn more about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GitHub Secret Scanning?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning" rel="noopener noreferrer"&gt;Secret scanning&lt;/a&gt; is part of the GitHub Advanced Security offering if you have a GitHub Enterprise account, but for public repos it is free to use (and enabled by default). GitHub scans the repository (full history) and issues and pull requests contents to see if it detects a secret. The detection happens based on a set of regular expressions shared by GitHub’s secret scanning partners (over 100 and counting). If a secret is detected, GitHub will notify the repository owner as well as the secret scanning partner. Depending on the context (public repo or not for example), the secret scanning partner can decide to revoke the secret immediately, which I think most partners do.&lt;/p&gt;

&lt;p&gt;This functionality is so good and fast, that I routinely post my GitHub Personal Access Tokens to GitHub issues during my trainings, to show the power of secret scanning. Usually I already have an email and a revoked token before I finish explaining what is happening in the background.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd30shk154ludnukzuwg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd30shk154ludnukzuwg.jpg" alt="Photo of a woman holding her index finger to her mouth in a 'sst' manner" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Photo by &lt;a href="https://unsplash.com/@tinaflour?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Kristina Flour&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/BcjdbyKWquw?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;.
&lt;/h4&gt;

&lt;h2&gt;
  
  
  Analyzing the actions repositories.
&lt;/h2&gt;

&lt;p&gt;In my GitHub Actions marketplace scan, I have the repositories of 14k actions forked into an organization, so I can enable secret scanning and see what I get back from secret scanning. Since all Action repositories on the marketplace are public, any secret that is found has been found before, so I expect all these secrets to already have been revoked before.&lt;/p&gt;

&lt;p&gt;Overall results: Found [1353] secrets for the organization in [1110] repositories (out of 13954 repos scanned). Here is a top 15 of most found secrets to see what is being found:&lt;/p&gt;

&lt;h2&gt;
  
  
  Secret scanning alerts
&lt;/h2&gt;

&lt;p&gt;|Alert type|Count| |—|—:| | GitHub App Installation Access Token | 692 | | Azure Storage Account Access Key | 155 | | GitHub Personal Access Token | 120 | | Amazon AWS Secret Access Key | 50 | | Plivo Auth ID | 40 | | Amazon AWS Access Key ID | 40 | | Google API Key | 34 | | Slack API Token | 31 | | Slack Incoming Webhook URL | 27 | | Atlassian API Token | 22 | | Plivo Auth Token | 16 | | GitHub SSH Private Key | 12 | | Amazon AWS Session Token | 12 | | HashiCorp Vault Service Token | 11 | | PyPI API Token | 10 |&lt;/p&gt;

&lt;p&gt;With all the news recently about credential leaking and malicious actors using these secrets to do bad things, I think it is very important to enable secret scanning on your repositories! Having this data really shows the power of GitHub and its secret scanning partners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing the results
&lt;/h2&gt;

&lt;p&gt;I wanted to get these results to get a feel for the amount of things secret scanning would find. I my opinion, the maintainers of these actions have a high level of understanding Git and GitHub, so you’d expect a relative low number of secrets being found. Still, 1110 repositories out of 13954 repos is 7.9% off all repos where secrets have been found. This shows how easy it is to accidentally commit secrets to a repository. Even in my own repos, a secret was found (a GitHub Personal Access Token even) that I accidentally committed in an environment file! And that while I teach people on these things!&lt;/p&gt;

&lt;p&gt;I think this is a good number to show to my students and customers to make the case for enabling secret scanning on their repositories. Even folks with a high level of understanding, will still make mistakes and &lt;a href="https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning" rel="noopener noreferrer"&gt;secret scanning&lt;/a&gt; will help by finding them for you, every time you make a change to your repository.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Adding OSSF scorecard action to your repo</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Thu, 08 Dec 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/adding-ossf-scorecard-action-to-your-repo-4bhd</link>
      <guid>https://dev.to/rob_bos/adding-ossf-scorecard-action-to-your-repo-4bhd</guid>
      <description>&lt;p&gt;Recently I’ve started to add the &lt;a href="https://github.com/ossf/scorecard-action"&gt;OSSF scorecard action&lt;/a&gt; to my (action) repositories. This is a GitHub action that will run the &lt;a href="https://github.com/ossf/scorecard"&gt;OSSF scorecard&lt;/a&gt; checks against your repository to see if you are following best practices, like having a security policy, using a code scanning tool, etc. Using this badge can give your users a quick overview of the security of your repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scorecard action
&lt;/h2&gt;

&lt;p&gt;The scorecard action will do three things (if you use the default settings):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Analyze your repository for the checks&lt;/li&gt;
&lt;li&gt;Upload the results to the GitHub Security tab (using a SARIF file)&lt;/li&gt;
&lt;li&gt;Upload the results to the OSSF API (A web API that you can even host yourself) With the data uploaded to the OSSF API you can then retrieve a badge with your latest score and show that on your repository:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jVsIYGuJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devopsjournal.io/images/2022/20221208/20221208_00_OSSF_badge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jVsIYGuJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devopsjournal.io/images/2022/20221208/20221208_00_OSSF_badge.png" alt="Screenshot of the OSSF badge in a repo, showing a score of 7.1" width="880" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scoring
&lt;/h2&gt;

&lt;p&gt;The action checks your repository against &lt;a href="https://github.com/ossf/scorecard#scorecard-checks"&gt;several checks&lt;/a&gt; and then calculates a score for each check on a scale of 0 to 10. Based on the risk for that check, the score is then multiplied with a weight. The final score is the average of all the weighted scores. The higher the score, the better.&lt;/p&gt;

&lt;p&gt;Some of the checks that are executed are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Branch-Protection: Is branch protection enabled for the default branch?&lt;/li&gt;
&lt;li&gt;Are GitHub Action versions pinned to SHA hashes, following &lt;a href="https://dev.to/blog/2021/02/06/GitHub-Actions"&gt;best practices&lt;/a&gt;?&lt;/li&gt;
&lt;li&gt;Is the repository using a code scanning tool? Note that this check currently only supports CodeQL and SonarCloud&lt;/li&gt;
&lt;li&gt;Is there a security policy defined?&lt;/li&gt;
&lt;li&gt;Is there a definition file for Dependabot?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting it up
&lt;/h2&gt;

&lt;p&gt;Setting is up is as easy as going to the &lt;a href="https://github.com/ossf/scorecard-action#workflow-example"&gt;OSSF scorecard action&lt;/a&gt; repo and copy the workflow example. Add that to you a new workflow file in your repo and run it from the default branch (usually &lt;code&gt;main&lt;/code&gt;). After the first run, you can add a link to your README.md file to show the badge.&lt;/p&gt;

&lt;p&gt;The result will be a badge showing the latest score:&lt;br&gt;&lt;br&gt;
&lt;a href="https://api.securityscorecards.dev/projects/github.com/devops-actions/load-runner-info"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jx_OuPPG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://api.securityscorecards.dev/projects/github.com/devops-actions/load-runner-info/badge" alt="OpenSSF Scorecard" width="136" height="20"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code scanning alerts
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/ossf/scorecard-action#workflow-example"&gt;default workflow&lt;/a&gt; also uploads the check results as a SARIF file to the Code Scanning Alerts that you can find on the Security tab of your repository. Each check can give one or more results, so you will get an alert for each result. That way you can fix the issues one by one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R33xQaPZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devopsjournal.io/images/2022/20221208/20221208_01_Code_scanning_alert.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R33xQaPZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devopsjournal.io/images/2022/20221208/20221208_01_Code_scanning_alert.png" alt="Screenshot of an alert about dependency pinning that is not followed" width="880" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even better is that most of these alerts will give you actionable suggestions on how to fix the issue. For example, the alert above will give you a link to the &lt;a href="https://app.stepsecurity.io/securerepo/"&gt;Step Security&lt;/a&gt; Application that can analyze your repository and give you a pull request with the changes to fix the issue. They focus on three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restrict permission for the GITHUB_TOKEN&lt;/li&gt;
&lt;li&gt;Add security agent for GitHub hosted runner (Ubuntu only)&lt;/li&gt;
&lt;li&gt;Pin actions to a full SHA hash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MHbCUl5F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devopsjournal.io/images/2022/20221208/20221208_02_ImproveWorkflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MHbCUl5F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://devopsjournal.io/images/2022/20221208/20221208_02_ImproveWorkflow.png" alt="Screenshot of the three options Step Security gives you to improve your workflow" width="880" height="586"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Restrict permission for the GITHUB_TOKEN
&lt;/h3&gt;

&lt;p&gt;One of the best practices is to always indicate what permissions you want to allow for the GitHub token that will be used in your workflow. The default setting is to permissive: it is &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt; for everything in your repo. I’ve been advocating that people always make this read-only at the organization level.&lt;/p&gt;

&lt;p&gt;Since you cannot see what the organization permissions are, it’s a best practice to always specify the rights. You can add it to the top of your workflow file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;permissions: read-all

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now you can override it at the job level if you need to. For example, if you need to push to a branch, you can add &lt;code&gt;write&lt;/code&gt; to the &lt;code&gt;contents&lt;/code&gt; permission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    permissions:
        contents: write
    runs-on: ubuntu-latest
    steps:
     # etc

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add security agent for GitHub hosted runner (Ubuntu only)
&lt;/h3&gt;

&lt;p&gt;This setting is something I want to look into more. It seems that you can add a security agent to your GitHub hosted runner (available only for Ubuntu). It’s an extra product from &lt;a href="https://github.com/step-security/harden-runner"&gt;Step Security&lt;/a&gt; which is available for free. It will analyze the network traffic in the job and log that in their system. After a couple of runs they know what kind of traffic is to be expected, and then you can convert that to basically a firewall rule. Any violations will then be logged and blocked. This can give you a better perimeter defense (as by default all traffic is allowed).&lt;/p&gt;

&lt;p&gt;Definitely something to look into more!&lt;/p&gt;

&lt;h3&gt;
  
  
  Pin actions to a full SHA hash
&lt;/h3&gt;

&lt;p&gt;The last option is to pin your actions to a full SHA hash. This is a best practice that I’ve been &lt;a href="https://dev.to/blog/2021/02/06/GitHub-Actions"&gt;advocating for a while&lt;/a&gt;. It’s a bit more work, but it will make sure that your workflow will not be affected by a malicious actor pushing a new version of an action. What I really like is that this setting will analyze your workflow file (either pasted in or just all workflows in your public repo) and then suggest the SHA hashes of the actions, by looking at their latest version! Even better, they store the latest version in the comment next to the SHA hash, so you can understand where the hash comes from. If only Dependabot understood that comment and would update it in their version update PRs… 🤔!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Examples for calling the GitHub GraphQL API (with ProjectsV2)</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Mon, 28 Nov 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/examples-for-calling-the-github-graphql-api-with-projectsv2-1j3p</link>
      <guid>https://dev.to/rob_bos/examples-for-calling-the-github-graphql-api-with-projectsv2-1j3p</guid>
      <description>&lt;p&gt;Recently we had to call the GitHub GraphQL API for creating a new GitHub Project (with V2). Since this can only be done with the GraphQL API, we had to figure out how to do this. We found little bits and pieces of information, but no complete example. So we decided to write one ourselves. I hope this helps you as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  ProjectsV2 GitHub GraphQL API
&lt;/h2&gt;

&lt;p&gt;The new GitHub Projects simply do not have a REST API at the moment, so you are forced to use the GraphQL API. As an extra challenge, the GraphQL API requires a &lt;a href="https://docs.github.com/en/graphql/guides/migrating-graphql-global-node-ids" rel="noopener noreferrer"&gt;new set of ID’s for these calls&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging in
&lt;/h2&gt;

&lt;p&gt;If you are not careful, then the first hurdle will be to login with the right scopes. I’m going to use the GitHub CLI in this post, but you will need to make sure you have the right scopes for this with manual API calls as well. Logging in with just the normal &lt;code&gt;gh auth login&lt;/code&gt; call is not enough in this case. Add the &lt;code&gt;project&lt;/code&gt; scopes to your call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gh auth login --scopes "project"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting the new ID’s
&lt;/h2&gt;

&lt;p&gt;Now we can start making the calls to the GraphQL API. Since this API with ProjectsV2 needs the new ID’s, make all calls like this to get the new ID’s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# powershell:
$response = $(gh api graphql -H "X-Github-Next-Global-ID: 1" -F query=$query | ConvertFrom-Json)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can call the API with the current login to get the new ID for this login:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$query = "query { viewer { login, id } }"
$response = $(gh api graphql -H "X-Github-Next-Global-ID: 1" -F query=$query | ConvertFrom-Json)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to get the ID from an organization? Use this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$query="query { organization(login: ""$organizationName"") { id, name } }"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Working with ProjectsV2
&lt;/h2&gt;

&lt;p&gt;Now we can start loading the existing projects for an organization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$query="query { organization(login: ""$organizationName"") { projectsV2(first: 100) { edges { node { id } } } } }"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can create a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$query="mutation (`$ownerId: ID!, `$title: String!) { createProjectV2(input: { ownerId: `$ownerId, title: `$title }) { projectV2 { id } } }"    

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see the full script, you can find it &lt;a href="https://github.com/rajbos/github-graphql-examples" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Working with GitHub secrets without admin rights</title>
      <dc:creator>Rob Bos</dc:creator>
      <pubDate>Fri, 11 Nov 2022 00:00:00 +0000</pubDate>
      <link>https://dev.to/rob_bos/working-with-github-secrets-without-admin-rights-353e</link>
      <guid>https://dev.to/rob_bos/working-with-github-secrets-without-admin-rights-353e</guid>
      <description>&lt;p&gt;I was giving a training today on GitHub Actionshttps://github.com/features/actions and learned something new! One of the attendees asked about being able to read and write to Repository Secrets without having admin rights. I had never tried this before, but it turns out it is possible!&lt;/p&gt;

&lt;h2&gt;
  
  
  The premise:
&lt;/h2&gt;

&lt;p&gt;To be able to create actions on the repository you need to have Admin access to the repository: otherwise the UI will not be visible, since it is under the repository settings. For organization level secrets you need Admin access to the &lt;em&gt;organization&lt;/em&gt; level.&lt;/p&gt;

&lt;p&gt;That also means that team members that do not have Admin access, cannot SEE the repository secrets in the UI. They always had to rely on the examples in other workflow files to see what type of secrets were available. Today I learned that any user with &lt;strong&gt;write&lt;/strong&gt; access to the repository can also create, update, and delete a secret. Even if they cannot see it in the UI, they can use the API to manage the secrets. It would be great if GitHub updates the UI to make these kinds of information available to all users that need it (write and maintain). Something similar happens with available GitHub Self-hosted Runners (information is not available for non-admins).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2022%2F20221102%2Fmarkus-winkler-wpOa2i3MUrY-unsplash.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2022%2F20221102%2Fmarkus-winkler-wpOa2i3MUrY-unsplash.jpg" alt="Photo of a smart phone with the thinking emoji displayed on it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Photo by &lt;a href="https://unsplash.com/@markuswinkler?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Markus Winkler&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/think?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/h5&gt;

&lt;h2&gt;
  
  
  The solution:
&lt;/h2&gt;

&lt;p&gt;If you have &lt;strong&gt;write&lt;/strong&gt; access to the repository, you can use the API to create, update, and delete secrets. You can use the &lt;a href="https://cli.github.com/" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt; to do this, or you can use the &lt;a href="https://docs.github.com/en/rest/actions/secrets#list-repository-secrets" rel="noopener noreferrer"&gt;GitHub REST API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is also an API for Environment secrets that work the same way: &lt;a href="https://docs.github.com/en/rest/actions/secrets#list-environment-secrets" rel="noopener noreferrer"&gt;GitHub REST API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The GitHub CLI is a great tool to use, since it is easy to use and it is cross-platform. You can install it on Windows, Linux, and Mac. For maintaining the repository secrets, there is a native call in the CLI that you can use: &lt;a href="https://cli.github.com/manual/gh_secret_list" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # list all secrets for the current repo
  gh secret list

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For environment secrets there is no native call in the CLI, but you can use the REST API to list the secrets. You can use the following command to list the environment secrets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # list the environments on the repository:
    gh api repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments

    # list secrets for that environment:
    gh api repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments/&amp;lt;ENVIRONMENT&amp;gt;/secrets

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output of the CLI calls:&lt;br&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2022%2F20221102%2F20221102_Secret_Listing.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2022%2F20221102%2F20221102_Secret_Listing.png" alt="Screenshot of the output of the CLI calls"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From then you get options to set (create), delete or update the value of the secret. Retrieving the value of the secret is not possible, since there are no API calls for that, which makes sense since they are &lt;em&gt;secrets&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Examples of setting a variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Paste secret value for the current repository in an interactive prompt
$ gh secret set MYSECRET

# Read secret value from an environment variable
$ gh secret set MYSECRET --body "$ENV_VALUE"

# Read secret value from a file
$ gh secret set MYSECRET &amp;lt; myfile.txt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Figuring out environments and secrets
&lt;/h2&gt;

&lt;p&gt;The environment secrets &lt;em&gt;can&lt;/em&gt; be listed by users with write access, and they can &lt;em&gt;create&lt;/em&gt; environments directly with the API.&lt;/p&gt;

&lt;p&gt;For creating an environment you need to have write access to an repo, and the repo needs to be in an Organization. User space repos do not work with this write API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # list secrets for that environment:
    gh api repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments/&amp;lt;ENVIRONMENT&amp;gt;/secrets

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For creating environments in your own user space, you have Admin access so you can use this API call. If you add a body you can the timeout rule, specify protection rules (who needs to approve the job that targets the environment) as well as the deployment branch rule (which branch is allowed to target that environment).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; gh api -X PUT /repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments/NEW_ENVIRONMENT

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Results:&lt;br&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2022%2F20221102%2F20221102_CreateEnvironment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdevopsjournal.io%2Fimages%2F2022%2F20221102%2F20221102_CreateEnvironment.png" alt="Screenshot of the output of 'gh api -X PUT' call to create the environment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are invited as a Collaborator to another user’s repo, you cannot create environments with the API. Trying to make the call you can get two results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;404: Not found (repo is private)&lt;/li&gt;
&lt;li&gt;403: Forbidden (public repo, but you do not have admin access)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As long as you do have &lt;strong&gt;read&lt;/strong&gt; access to the repo, you can list the environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # list the environments on the repository:
    gh api repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 As you have read access to all &lt;em&gt;public repos&lt;/em&gt;, you can list the environments on any public repo as well. Since this information is already available from the workflow files (and they are public), having the name of the environment is not a big deal. Unfortunately the API returns all there is to know about that environment, including the deployment branch and protection rules. The feedback I got from GitHub is that this is ‘by design’. You can get similar information from the &lt;a href="https://docs.github.com/en/rest/branches/branches#list-branches" rel="noopener noreferrer"&gt;branches API&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts:
&lt;/h2&gt;

&lt;p&gt;The only thing that is not available this way is retrieving a list of Organization level secrets: the API calls for that need &lt;code&gt;admin:org&lt;/code&gt; scope, which a user with write access to the repository does not have by default. That is still a big missing feature, since these kinds of secrets are often used to set some large scope (often read-only) secrets for the entire organization, or to have 1 ‘team’ secret that gets added to the repos that team owns.&lt;/p&gt;

&lt;p&gt;So, to list all the Repo secrets you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gh secret list

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for finding the Environments and their secrets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # list the environments on the repository:
    gh api repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments

    # list secrets for that environment:
    gh api repos/&amp;lt;OWNER&amp;gt;/&amp;lt;REPO&amp;gt;/environments/&amp;lt;ENVIRONMENT&amp;gt;/secrets

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
